[interp] Optimize multidimensional array access (#16822)
[mono-project.git] / mono / mini / interp / interp.c
blob848f97a22e3cb6a84c4bc016247173be55014ca6
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>
29 #ifdef HAVE_ALLOCA_H
30 # include <alloca.h>
31 #else
32 # ifdef __CYGWIN__
33 # define alloca __builtin_alloca
34 # endif
35 #endif
37 /* trim excessive headers */
38 #include <mono/metadata/image.h>
39 #include <mono/metadata/assembly-internals.h>
40 #include <mono/metadata/cil-coff.h>
41 #include <mono/metadata/mono-endian.h>
42 #include <mono/metadata/tabledefs.h>
43 #include <mono/metadata/tokentype.h>
44 #include <mono/metadata/loader.h>
45 #include <mono/metadata/threads.h>
46 #include <mono/metadata/threadpool.h>
47 #include <mono/metadata/profiler-private.h>
48 #include <mono/metadata/appdomain.h>
49 #include <mono/metadata/reflection.h>
50 #include <mono/metadata/exception.h>
51 #include <mono/metadata/verify.h>
52 #include <mono/metadata/opcodes.h>
53 #include <mono/metadata/debug-helpers.h>
54 #include <mono/metadata/mono-config.h>
55 #include <mono/metadata/marshal.h>
56 #include <mono/metadata/environment.h>
57 #include <mono/metadata/mono-debug.h>
58 #include <mono/metadata/gc-internals.h>
59 #include <mono/utils/atomic.h>
61 #include "interp.h"
62 #include "interp-internals.h"
63 #include "mintops.h"
65 #include <mono/mini/mini.h>
66 #include <mono/mini/mini-runtime.h>
67 #include <mono/mini/aot-runtime.h>
68 #include <mono/mini/llvm-runtime.h>
69 #include <mono/mini/llvmonly-runtime.h>
70 #include <mono/mini/jit-icalls.h>
71 #include <mono/mini/debugger-agent.h>
72 #include <mono/mini/ee.h>
73 #include <mono/mini/trace.h>
75 #ifdef TARGET_ARM
76 #include <mono/mini/mini-arm.h>
77 #endif
78 #include <mono/metadata/icall-decl.h>
80 #ifdef _MSC_VER
81 #pragma warning(disable:4102) // label' : unreferenced label
82 #endif
84 /* Arguments that are passed when invoking only a finally/filter clause from the frame */
85 typedef struct {
86 /* Where we start the frame execution from */
87 const guint16 *start_with_ip;
89 * End ip of the exit_clause. We need it so we know whether the resume
90 * state is for this frame (which is called from EH) or for the original
91 * frame further down the stack.
93 const guint16 *end_at_ip;
94 /* When exiting this clause we also exit the frame */
95 int exit_clause;
96 /* Exception that we are filtering */
97 MonoException *filter_exception;
98 InterpFrame *base_frame;
99 } FrameClauseArgs;
101 static void
102 init_frame (InterpFrame *frame, InterpFrame *parent_frame, InterpMethod *rmethod, stackval *method_args, stackval *method_retval)
104 frame->parent = parent_frame;
105 frame->stack_args = method_args;
106 frame->retval = method_retval;
107 frame->imethod = rmethod;
108 frame->ip = NULL;
111 #define interp_exec_method(frame, context, error) interp_exec_method_full ((frame), (context), NULL, error)
114 * List of classes whose methods will be executed by transitioning to JITted code.
115 * Used for testing.
117 GSList *mono_interp_jit_classes;
118 /* Optimizations enabled with interpreter */
119 int mono_interp_opt = INTERP_OPT_DEFAULT;
120 /* If TRUE, interpreted code will be interrupted at function entry/backward branches */
121 static gboolean ss_enabled;
123 static gboolean interp_init_done = FALSE;
125 static void interp_exec_method_full (InterpFrame *frame, ThreadContext *context, FrameClauseArgs *clause_args, MonoError *error);
126 static InterpMethod* lookup_method_pointer (gpointer addr);
128 typedef void (*ICallMethod) (InterpFrame *frame);
130 static MonoNativeTlsKey thread_context_id;
132 #define DEBUG_INTERP 0
133 #define COUNT_OPS 0
135 #if DEBUG_INTERP
136 int mono_interp_traceopt = 2;
137 /* If true, then we output the opcodes as we interpret them */
138 static int global_tracing = 2;
140 static int debug_indent_level = 0;
142 static int break_on_method = 0;
143 static int nested_trace = 0;
144 static GList *db_methods = NULL;
145 static char* dump_args (InterpFrame *inv);
147 static void
148 output_indent (void)
150 int h;
152 for (h = 0; h < debug_indent_level; h++)
153 g_print (" ");
156 static void
157 db_match_method (gpointer data, gpointer user_data)
159 MonoMethod *m = (MonoMethod*)user_data;
160 MonoMethodDesc *desc = data;
162 if (mono_method_desc_full_match (desc, m))
163 break_on_method = 1;
166 static void
167 debug_enter (InterpFrame *frame, int *tracing)
169 if (db_methods) {
170 g_list_foreach (db_methods, db_match_method, (gpointer)frame->imethod->method);
171 if (break_on_method)
172 *tracing = nested_trace ? (global_tracing = 2, 3) : 2;
173 break_on_method = 0;
175 if (*tracing) {
176 MonoMethod *method = frame->imethod->method;
177 char *mn, *args = dump_args (frame);
178 debug_indent_level++;
179 output_indent ();
180 mn = mono_method_full_name (method, FALSE);
181 g_print ("(%p) Entering %s (", mono_thread_internal_current (), mn);
182 g_free (mn);
183 g_print ("%s)\n", args);
184 g_free (args);
189 #define DEBUG_LEAVE() \
190 if (tracing) { \
191 char *mn, *args; \
192 args = dump_retval (frame); \
193 output_indent (); \
194 mn = mono_method_full_name (frame->imethod->method, FALSE); \
195 g_print ("(%p) Leaving %s", mono_thread_internal_current (), mn); \
196 g_free (mn); \
197 g_print (" => %s\n", args); \
198 g_free (args); \
199 debug_indent_level--; \
200 if (tracing == 3) global_tracing = 0; \
203 #else
205 int mono_interp_traceopt = 0;
206 #define DEBUG_LEAVE()
208 #endif
210 #if defined(__GNUC__) && !defined(TARGET_WASM) && !COUNT_OPS && !DEBUG_INTERP
211 #define USE_COMPUTED_GOTO 1
212 #endif
214 #if USE_COMPUTED_GOTO
216 #define MINT_IN_SWITCH(op) goto *in_labels[op];
217 #define MINT_IN_CASE(x) LAB_ ## x:
218 #define MINT_IN_DISPATCH(op) goto *in_labels[op];
219 #define MINT_IN_BREAK { goto *in_labels[*ip]; }
220 #define MINT_IN_DEFAULT mint_default: if (0) goto mint_default; /* make gcc shut up */
222 #else
224 #define MINT_IN_SWITCH(op) COUNT_OP(op); switch (op)
225 #define MINT_IN_CASE(x) case x:
226 #define MINT_IN_DISPATCH(op) goto main_loop;
227 #define MINT_IN_BREAK break
228 #define MINT_IN_DEFAULT default:
230 #endif
232 static GSList*
233 clear_resume_state (ThreadContext *context, GSList *finally_ips)
235 /* We have thrown an exception from a finally block. Some of the leave targets were unwound already */
236 while (finally_ips &&
237 finally_ips->data >= context->handler_ei->try_start &&
238 finally_ips->data < context->handler_ei->try_end)
239 finally_ips = g_slist_remove (finally_ips, finally_ips->data);
240 context->has_resume_state = 0;
241 context->handler_frame = NULL;
242 context->handler_ei = NULL;
243 g_assert (context->exc_gchandle);
244 mono_gchandle_free_internal (context->exc_gchandle);
245 context->exc_gchandle = 0;
246 return finally_ips;
250 * If this bit is set, it means the call has thrown the exception, and we
251 * reached this point because the EH code in mono_handle_exception ()
252 * unwound all the JITted frames below us. mono_interp_set_resume_state ()
253 * has set the fields in context to indicate where we have to resume execution.
255 #define CHECK_RESUME_STATE(context) do { \
256 if ((context)->has_resume_state) \
257 goto resume; \
258 } while (0)
260 static void
261 set_context (ThreadContext *context)
263 mono_native_tls_set_value (thread_context_id, context);
265 if (!context)
266 return;
268 MonoJitTlsData *jit_tls = mono_tls_get_jit_tls ();
269 g_assertf (jit_tls, "ThreadContext needs initialized JIT TLS");
271 /* jit_tls assumes ownership of 'context' */
272 jit_tls->interp_context = context;
275 static ThreadContext *
276 get_context (void)
278 ThreadContext *context = (ThreadContext *) mono_native_tls_get_value (thread_context_id);
279 if (context == NULL) {
280 context = g_new0 (ThreadContext, 1);
281 set_context (context);
283 return context;
286 static void
287 mono_interp_error_cleanup (MonoError* error)
289 mono_error_cleanup (error); /* FIXME: don't swallow the error */
290 error_init_reuse (error); // one instruction, so this function is good inline candidate
293 static MONO_NEVER_INLINE void
294 ves_real_abort (int line, MonoMethod *mh,
295 const unsigned short *ip, stackval *stack, stackval *sp)
297 ERROR_DECL (error);
298 MonoMethodHeader *header = mono_method_get_header_checked (mh, error);
299 mono_error_cleanup (error); /* FIXME: don't swallow the error */
300 g_printerr ("Execution aborted in method: %s::%s\n", m_class_get_name (mh->klass), mh->name);
301 g_printerr ("Line=%d IP=0x%04lx, Aborted execution\n", line, ip-(const unsigned short *) header->code);
302 g_printerr ("0x%04x %02x\n", ip-(const unsigned short *) header->code, *ip);
303 mono_metadata_free_mh (header);
306 #define ves_abort() \
307 do {\
308 ves_real_abort(__LINE__, frame->imethod->method, ip, frame->stack, sp); \
309 goto abort_label; \
310 } while (0);
312 static InterpMethod*
313 lookup_imethod (MonoDomain *domain, MonoMethod *method)
315 InterpMethod *imethod;
316 MonoJitDomainInfo *info;
318 info = domain_jit_info (domain);
319 mono_domain_jit_code_hash_lock (domain);
320 imethod = (InterpMethod*)mono_internal_hash_table_lookup (&info->interp_code_hash, method);
321 mono_domain_jit_code_hash_unlock (domain);
322 return imethod;
325 static gpointer
326 interp_get_remoting_invoke (MonoMethod *method, gpointer addr, MonoError *error)
328 #ifndef DISABLE_REMOTING
329 InterpMethod *imethod;
331 if (addr) {
332 imethod = lookup_method_pointer (addr);
333 } else {
334 g_assert (method);
335 imethod = mono_interp_get_imethod (mono_domain_get (), method, error);
336 return_val_if_nok (error, NULL);
338 g_assert (imethod);
339 g_assert (mono_use_interpreter);
341 MonoMethod *remoting_invoke_method = mono_marshal_get_remoting_invoke (imethod->method, error);
342 return_val_if_nok (error, NULL);
343 return mono_interp_get_imethod (mono_domain_get (), remoting_invoke_method, error);
344 #else
345 g_assert_not_reached ();
346 return NULL;
347 #endif
350 InterpMethod*
351 mono_interp_get_imethod (MonoDomain *domain, MonoMethod *method, MonoError *error)
353 InterpMethod *imethod;
354 MonoJitDomainInfo *info;
355 MonoMethodSignature *sig;
356 int i;
358 error_init (error);
360 info = domain_jit_info (domain);
361 mono_domain_jit_code_hash_lock (domain);
362 imethod = (InterpMethod*)mono_internal_hash_table_lookup (&info->interp_code_hash, method);
363 mono_domain_jit_code_hash_unlock (domain);
364 if (imethod)
365 return imethod;
367 sig = mono_method_signature_internal (method);
369 imethod = (InterpMethod*)mono_domain_alloc0 (domain, sizeof (InterpMethod));
370 imethod->method = method;
371 imethod->domain = domain;
372 imethod->param_count = sig->param_count;
373 imethod->hasthis = sig->hasthis;
374 imethod->vararg = sig->call_convention == MONO_CALL_VARARG;
375 imethod->rtype = mini_get_underlying_type (sig->ret);
376 imethod->param_types = (MonoType**)mono_domain_alloc0 (domain, sizeof (MonoType*) * sig->param_count);
377 for (i = 0; i < sig->param_count; ++i)
378 imethod->param_types [i] = mini_get_underlying_type (sig->params [i]);
380 mono_domain_jit_code_hash_lock (domain);
381 if (!mono_internal_hash_table_lookup (&info->interp_code_hash, method))
382 mono_internal_hash_table_insert (&info->interp_code_hash, method, imethod);
383 mono_domain_jit_code_hash_unlock (domain);
385 imethod->prof_flags = mono_profiler_get_call_instrumentation_flags (imethod->method);
387 return imethod;
390 #if defined (MONO_CROSS_COMPILE) || defined (HOST_WASM)
391 #define INTERP_PUSH_LMF_WITH_CTX_BODY(ext, exit_label) \
392 (ext).kind = MONO_LMFEXT_INTERP_EXIT;
394 #elif defined(MONO_ARCH_HAS_NO_PROPER_MONOCTX)
395 /* some platforms, e.g. appleTV, don't provide us a precise MonoContext
396 * (registers are not accurate), thus resuming to the label does not work. */
397 #define INTERP_PUSH_LMF_WITH_CTX_BODY(ext, exit_label) \
398 (ext).kind = MONO_LMFEXT_INTERP_EXIT;
399 #elif defined (_MSC_VER)
400 #define INTERP_PUSH_LMF_WITH_CTX_BODY(ext, exit_label) \
401 (ext).kind = MONO_LMFEXT_INTERP_EXIT_WITH_CTX; \
402 (ext).interp_exit_label_set = FALSE; \
403 MONO_CONTEXT_GET_CURRENT ((ext).ctx); \
404 if ((ext).interp_exit_label_set == FALSE) \
405 mono_arch_do_ip_adjustment (&(ext).ctx); \
406 if ((ext).interp_exit_label_set == TRUE) \
407 goto exit_label; \
408 (ext).interp_exit_label_set = TRUE;
409 #elif defined(MONO_ARCH_HAS_MONO_CONTEXT)
410 #define INTERP_PUSH_LMF_WITH_CTX_BODY(ext, exit_label) \
411 (ext).kind = MONO_LMFEXT_INTERP_EXIT_WITH_CTX; \
412 MONO_CONTEXT_GET_CURRENT ((ext).ctx); \
413 MONO_CONTEXT_SET_IP (&(ext).ctx, (&&exit_label)); \
414 mono_arch_do_ip_adjustment (&(ext).ctx);
415 #else
416 #define INTERP_PUSH_LMF_WITH_CTX_BODY(ext, exit_label) g_error ("requires working mono-context");
417 #endif
419 /* INTERP_PUSH_LMF_WITH_CTX:
421 * same as interp_push_lmf, but retrieving and attaching MonoContext to it.
422 * This is needed to resume into the interp when the exception is thrown from
423 * native code (see ./mono/tests/install_eh_callback.exe).
425 * This must be a macro in order to retrieve the right register values for
426 * MonoContext.
428 #define INTERP_PUSH_LMF_WITH_CTX(frame, ext, exit_label) \
429 memset (&(ext), 0, sizeof (MonoLMFExt)); \
430 (ext).interp_exit_data = (frame); \
431 INTERP_PUSH_LMF_WITH_CTX_BODY ((ext), exit_label); \
432 mono_push_lmf (&(ext));
435 * interp_push_lmf:
437 * Push an LMF frame on the LMF stack
438 * to mark the transition to native code.
439 * This is needed for the native code to
440 * be able to do stack walks.
442 static void
443 interp_push_lmf (MonoLMFExt *ext, InterpFrame *frame)
445 memset (ext, 0, sizeof (MonoLMFExt));
446 ext->kind = MONO_LMFEXT_INTERP_EXIT;
447 ext->interp_exit_data = frame;
449 mono_push_lmf (ext);
452 static void
453 interp_pop_lmf (MonoLMFExt *ext)
455 mono_pop_lmf (&ext->lmf);
458 static MONO_NEVER_INLINE InterpMethod*
459 get_virtual_method (InterpMethod *imethod, MonoVTable *vtable)
461 MonoMethod *m = imethod->method;
462 MonoDomain *domain = imethod->domain;
463 InterpMethod *ret = NULL;
465 #ifndef DISABLE_REMOTING
466 if (mono_class_is_transparent_proxy (vtable->klass)) {
467 ERROR_DECL (error);
468 MonoMethod *remoting_invoke_method = mono_marshal_get_remoting_invoke_with_check (m, error);
469 mono_error_assert_ok (error);
470 ret = mono_interp_get_imethod (domain, remoting_invoke_method, error);
471 mono_error_assert_ok (error);
472 return ret;
474 #endif
476 if ((m->flags & METHOD_ATTRIBUTE_FINAL) || !(m->flags & METHOD_ATTRIBUTE_VIRTUAL)) {
477 if (m->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED) {
478 ERROR_DECL (error);
479 ret = mono_interp_get_imethod (domain, mono_marshal_get_synchronized_wrapper (m), error);
480 mono_error_cleanup (error); /* FIXME: don't swallow the error */
481 } else {
482 ret = imethod;
484 return ret;
487 mono_class_setup_vtable (vtable->klass);
489 int slot = mono_method_get_vtable_slot (m);
490 if (mono_class_is_interface (m->klass)) {
491 g_assert (vtable->klass != m->klass);
492 /* TODO: interface offset lookup is slow, go through IMT instead */
493 gboolean non_exact_match;
494 slot += mono_class_interface_offset_with_variance (vtable->klass, m->klass, &non_exact_match);
497 MonoMethod *virtual_method = m_class_get_vtable (vtable->klass) [slot];
498 if (m->is_inflated && mono_method_get_context (m)->method_inst) {
499 MonoGenericContext context = { NULL, NULL };
501 if (mono_class_is_ginst (virtual_method->klass))
502 context.class_inst = mono_class_get_generic_class (virtual_method->klass)->context.class_inst;
503 else if (mono_class_is_gtd (virtual_method->klass))
504 context.class_inst = mono_class_get_generic_container (virtual_method->klass)->context.class_inst;
505 context.method_inst = mono_method_get_context (m)->method_inst;
507 ERROR_DECL (error);
508 virtual_method = mono_class_inflate_generic_method_checked (virtual_method, &context, error);
509 mono_error_cleanup (error); /* FIXME: don't swallow the error */
512 if (virtual_method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) {
513 virtual_method = mono_marshal_get_native_wrapper (virtual_method, FALSE, FALSE);
516 if (virtual_method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED) {
517 virtual_method = mono_marshal_get_synchronized_wrapper (virtual_method);
520 ERROR_DECL (error);
521 InterpMethod *virtual_imethod = mono_interp_get_imethod (domain, virtual_method, error);
522 mono_error_cleanup (error); /* FIXME: don't swallow the error */
523 return virtual_imethod;
526 typedef struct {
527 InterpMethod *imethod;
528 InterpMethod *target_imethod;
529 } InterpVTableEntry;
531 /* domain lock must be held */
532 static GSList*
533 append_imethod (MonoDomain *domain, GSList *list, InterpMethod *imethod, InterpMethod *target_imethod)
535 GSList *ret;
536 InterpVTableEntry *entry;
538 entry = (InterpVTableEntry*) mono_mempool_alloc (domain->mp, sizeof (InterpVTableEntry));
539 entry->imethod = imethod;
540 entry->target_imethod = target_imethod;
541 ret = g_slist_append_mempool (domain->mp, list, entry);
543 return ret;
546 static InterpMethod*
547 get_target_imethod (GSList *list, InterpMethod *imethod)
549 while (list != NULL) {
550 InterpVTableEntry *entry = (InterpVTableEntry*) list->data;
551 if (entry->imethod == imethod)
552 return entry->target_imethod;
553 list = list->next;
555 return NULL;
558 static gpointer*
559 get_method_table (MonoVTable *vtable, int offset)
561 if (offset >= 0)
562 return vtable->interp_vtable;
563 else
564 return (gpointer*)vtable;
567 static gpointer*
568 alloc_method_table (MonoVTable *vtable, int offset)
570 gpointer *table;
572 if (offset >= 0) {
573 table = mono_domain_alloc0 (vtable->domain, m_class_get_vtable_size (vtable->klass) * sizeof (gpointer));
574 vtable->interp_vtable = table;
575 } else {
576 table = (gpointer*)vtable;
579 return table;
582 static MONO_NEVER_INLINE InterpMethod* // Inlining causes additional stack use in caller.
583 get_virtual_method_fast (InterpMethod *imethod, MonoVTable *vtable, int offset)
585 gpointer *table;
587 #ifndef DISABLE_REMOTING
588 /* FIXME Remoting */
589 if (mono_class_is_transparent_proxy (vtable->klass))
590 return get_virtual_method (imethod, vtable);
591 #endif
593 table = get_method_table (vtable, offset);
595 if (!table) {
596 /* Lazily allocate method table */
597 mono_domain_lock (vtable->domain);
598 table = get_method_table (vtable, offset);
599 if (!table)
600 table = alloc_method_table (vtable, offset);
601 mono_domain_unlock (vtable->domain);
604 if (!table [offset]) {
605 InterpMethod *target_imethod = get_virtual_method (imethod, vtable);
606 /* Lazily initialize the method table slot */
607 mono_domain_lock (vtable->domain);
608 if (!table [offset]) {
609 if (imethod->method->is_inflated || offset < 0)
610 table [offset] = append_imethod (vtable->domain, NULL, imethod, target_imethod);
611 else
612 table [offset] = (gpointer) ((gsize)target_imethod | 0x1);
614 mono_domain_unlock (vtable->domain);
617 if ((gsize)table [offset] & 0x1) {
618 /* Non generic virtual call. Only one method in slot */
619 return (InterpMethod*) ((gsize)table [offset] & ~0x1);
620 } else {
621 /* Virtual generic or interface call. Multiple methods in slot */
622 InterpMethod *target_imethod = get_target_imethod ((GSList*)table [offset], imethod);
624 if (!target_imethod) {
625 target_imethod = get_virtual_method (imethod, vtable);
626 mono_domain_lock (vtable->domain);
627 if (!get_target_imethod ((GSList*)table [offset], imethod))
628 table [offset] = append_imethod (vtable->domain, (GSList*)table [offset], imethod, target_imethod);
629 mono_domain_unlock (vtable->domain);
631 return target_imethod;
635 static void inline
636 stackval_from_data (MonoType *type, stackval *result, const void *data, gboolean pinvoke)
638 type = mini_native_type_replace_type (type);
639 if (type->byref) {
640 switch (type->type) {
641 case MONO_TYPE_OBJECT:
642 case MONO_TYPE_CLASS:
643 case MONO_TYPE_STRING:
644 case MONO_TYPE_ARRAY:
645 case MONO_TYPE_SZARRAY:
646 break;
647 default:
648 break;
650 result->data.p = *(gpointer*)data;
651 return;
653 switch (type->type) {
654 case MONO_TYPE_VOID:
655 return;
656 case MONO_TYPE_I1:
657 result->data.i = *(gint8*)data;
658 return;
659 case MONO_TYPE_U1:
660 case MONO_TYPE_BOOLEAN:
661 result->data.i = *(guint8*)data;
662 return;
663 case MONO_TYPE_I2:
664 result->data.i = *(gint16*)data;
665 return;
666 case MONO_TYPE_U2:
667 case MONO_TYPE_CHAR:
668 result->data.i = *(guint16*)data;
669 return;
670 case MONO_TYPE_I4:
671 result->data.i = *(gint32*)data;
672 return;
673 case MONO_TYPE_U:
674 case MONO_TYPE_I:
675 result->data.nati = *(mono_i*)data;
676 return;
677 case MONO_TYPE_PTR:
678 result->data.p = *(gpointer*)data;
679 return;
680 case MONO_TYPE_U4:
681 result->data.i = *(guint32*)data;
682 return;
683 case MONO_TYPE_R4:
684 /* memmove handles unaligned case */
685 memmove (&result->data.f_r4, data, sizeof (float));
686 return;
687 case MONO_TYPE_I8:
688 case MONO_TYPE_U8:
689 memmove (&result->data.l, data, sizeof (gint64));
690 return;
691 case MONO_TYPE_R8:
692 memmove (&result->data.f, data, sizeof (double));
693 return;
694 case MONO_TYPE_STRING:
695 case MONO_TYPE_SZARRAY:
696 case MONO_TYPE_CLASS:
697 case MONO_TYPE_OBJECT:
698 case MONO_TYPE_ARRAY:
699 result->data.p = *(gpointer*)data;
700 return;
701 case MONO_TYPE_VALUETYPE:
702 if (m_class_is_enumtype (type->data.klass)) {
703 stackval_from_data (mono_class_enum_basetype_internal (type->data.klass), result, data, pinvoke);
704 return;
705 } else if (pinvoke) {
706 memcpy (result->data.vt, data, mono_class_native_size (type->data.klass, NULL));
707 } else {
708 mono_value_copy_internal (result->data.vt, data, type->data.klass);
710 return;
711 case MONO_TYPE_GENERICINST: {
712 if (mono_type_generic_inst_is_valuetype (type)) {
713 mono_value_copy_internal (result->data.vt, data, mono_class_from_mono_type_internal (type));
714 return;
716 stackval_from_data (m_class_get_byval_arg (type->data.generic_class->container_class), result, data, pinvoke);
717 return;
719 default:
720 g_error ("got type 0x%02x", type->type);
724 static void inline
725 stackval_to_data (MonoType *type, stackval *val, void *data, gboolean pinvoke)
727 type = mini_native_type_replace_type (type);
728 if (type->byref) {
729 gpointer *p = (gpointer*)data;
730 *p = val->data.p;
731 return;
733 /* printf ("TODAT0 %p\n", data); */
734 switch (type->type) {
735 case MONO_TYPE_I1:
736 case MONO_TYPE_U1: {
737 guint8 *p = (guint8*)data;
738 *p = val->data.i;
739 return;
741 case MONO_TYPE_BOOLEAN: {
742 guint8 *p = (guint8*)data;
743 *p = (val->data.i != 0);
744 return;
746 case MONO_TYPE_I2:
747 case MONO_TYPE_U2:
748 case MONO_TYPE_CHAR: {
749 guint16 *p = (guint16*)data;
750 *p = val->data.i;
751 return;
753 case MONO_TYPE_I: {
754 mono_i *p = (mono_i*)data;
755 /* In theory the value used by stloc should match the local var type
756 but in practice it sometimes doesn't (a int32 gets dup'd and stloc'd into
757 a native int - both by csc and mcs). Not sure what to do about sign extension
758 as it is outside the spec... doing the obvious */
759 *p = (mono_i)val->data.nati;
760 return;
762 case MONO_TYPE_U: {
763 mono_u *p = (mono_u*)data;
764 /* see above. */
765 *p = (mono_u)val->data.nati;
766 return;
768 case MONO_TYPE_I4:
769 case MONO_TYPE_U4: {
770 gint32 *p = (gint32*)data;
771 *p = val->data.i;
772 return;
774 case MONO_TYPE_I8:
775 case MONO_TYPE_U8: {
776 memmove (data, &val->data.l, sizeof (gint64));
777 return;
779 case MONO_TYPE_R4: {
780 /* memmove handles unaligned case */
781 memmove (data, &val->data.f_r4, sizeof (float));
782 return;
784 case MONO_TYPE_R8: {
785 memmove (data, &val->data.f, sizeof (double));
786 return;
788 case MONO_TYPE_STRING:
789 case MONO_TYPE_SZARRAY:
790 case MONO_TYPE_CLASS:
791 case MONO_TYPE_OBJECT:
792 case MONO_TYPE_ARRAY: {
793 gpointer *p = (gpointer *) data;
794 mono_gc_wbarrier_generic_store_internal (p, val->data.o);
795 return;
797 case MONO_TYPE_PTR: {
798 gpointer *p = (gpointer *) data;
799 *p = val->data.p;
800 return;
802 case MONO_TYPE_VALUETYPE:
803 if (m_class_is_enumtype (type->data.klass)) {
804 stackval_to_data (mono_class_enum_basetype_internal (type->data.klass), val, data, pinvoke);
805 return;
806 } else if (pinvoke) {
807 memcpy (data, val->data.vt, mono_class_native_size (type->data.klass, NULL));
808 } else {
809 mono_value_copy_internal (data, val->data.vt, type->data.klass);
811 return;
812 case MONO_TYPE_GENERICINST: {
813 MonoClass *container_class = type->data.generic_class->container_class;
815 if (m_class_is_valuetype (container_class) && !m_class_is_enumtype (container_class)) {
816 mono_value_copy_internal (data, val->data.vt, mono_class_from_mono_type_internal (type));
817 return;
819 stackval_to_data (m_class_get_byval_arg (type->data.generic_class->container_class), val, data, pinvoke);
820 return;
822 default:
823 g_error ("got type %x", type->type);
828 * Same as stackval_to_data but return address of storage instead
829 * of copying the value.
831 static gpointer
832 stackval_to_data_addr (MonoType *type, stackval *val)
834 type = mini_native_type_replace_type (type);
835 if (type->byref)
836 return &val->data.p;
838 switch (type->type) {
839 case MONO_TYPE_I1:
840 case MONO_TYPE_U1:
841 case MONO_TYPE_BOOLEAN:
842 case MONO_TYPE_I2:
843 case MONO_TYPE_U2:
844 case MONO_TYPE_CHAR:
845 case MONO_TYPE_I4:
846 case MONO_TYPE_U4:
847 return &val->data.i;
848 case MONO_TYPE_I:
849 case MONO_TYPE_U:
850 return &val->data.nati;
851 case MONO_TYPE_I8:
852 case MONO_TYPE_U8:
853 return &val->data.l;
854 case MONO_TYPE_R4:
855 return &val->data.f_r4;
856 case MONO_TYPE_R8:
857 return &val->data.f;
858 case MONO_TYPE_STRING:
859 case MONO_TYPE_SZARRAY:
860 case MONO_TYPE_CLASS:
861 case MONO_TYPE_OBJECT:
862 case MONO_TYPE_ARRAY:
863 case MONO_TYPE_PTR:
864 return &val->data.p;
865 case MONO_TYPE_VALUETYPE:
866 if (m_class_is_enumtype (type->data.klass))
867 return stackval_to_data_addr (mono_class_enum_basetype_internal (type->data.klass), val);
868 else
869 return val->data.vt;
870 case MONO_TYPE_TYPEDBYREF:
871 return val->data.vt;
872 case MONO_TYPE_GENERICINST: {
873 MonoClass *container_class = type->data.generic_class->container_class;
875 if (m_class_is_valuetype (container_class) && !m_class_is_enumtype (container_class))
876 return val->data.vt;
877 return stackval_to_data_addr (m_class_get_byval_arg (type->data.generic_class->container_class), val);
879 default:
880 g_error ("got type %x", type->type);
885 * interp_throw:
886 * Throw an exception from the interpreter.
888 static MONO_NEVER_INLINE void
889 interp_throw (ThreadContext *context, MonoException *ex, InterpFrame *frame, const guint16* ip, gboolean rethrow)
891 ERROR_DECL (error);
892 MonoLMFExt ext;
894 interp_push_lmf (&ext, frame);
895 frame->ip = ip;
897 if (mono_object_isinst_checked ((MonoObject *) ex, mono_defaults.exception_class, error)) {
898 MonoException *mono_ex = ex;
899 if (!rethrow) {
900 mono_ex->stack_trace = NULL;
901 mono_ex->trace_ips = NULL;
904 mono_error_assert_ok (error);
906 MonoContext ctx;
907 memset (&ctx, 0, sizeof (MonoContext));
908 MONO_CONTEXT_SET_SP (&ctx, frame);
911 * Call the JIT EH code. The EH code will call back to us using:
912 * - mono_interp_set_resume_state ()/run_finally ()/run_filter ().
913 * Since ctx.ip is 0, this will start unwinding from the LMF frame
914 * pushed above, which points to our frames.
916 mono_handle_exception (&ctx, (MonoObject*)ex);
917 if (MONO_CONTEXT_GET_IP (&ctx) != 0) {
918 /* We need to unwind into non-interpreter code */
919 mono_restore_context (&ctx);
920 g_assert_not_reached ();
923 interp_pop_lmf (&ext);
925 g_assert (context->has_resume_state);
928 #define THROW_EX_GENERAL(exception,ex_ip, rethrow) \
929 do { \
930 interp_throw (context, (exception), (frame), (ex_ip), (rethrow)); \
931 goto resume; \
932 } while (0)
934 #define THROW_EX(exception,ex_ip) THROW_EX_GENERAL ((exception), (ex_ip), FALSE)
936 #define NULL_CHECK(o) do { \
937 if (G_UNLIKELY (!(o))) \
938 goto null_label; \
939 } while (0)
941 #define EXCEPTION_CHECKPOINT \
942 do { \
943 if (*mono_thread_interruption_request_flag () && !mono_threads_is_critical_method (frame->imethod->method)) { \
944 MonoException *exc = mono_thread_interruption_checkpoint (); \
945 if (exc) \
946 THROW_EX (exc, ip); \
948 } while (0)
951 #define EXCEPTION_CHECKPOINT_IN_HELPER_FUNCTION \
952 do { \
953 if (*mono_thread_interruption_request_flag () && !mono_threads_is_critical_method (frame->imethod->method)) { \
954 MonoException *exc = mono_thread_interruption_checkpoint (); \
955 if (exc) \
956 return exc; \
958 } while (0)
960 static MonoObject*
961 ves_array_create (MonoDomain *domain, MonoClass *klass, int param_count, stackval *values, MonoError *error)
963 uintptr_t *lengths;
964 intptr_t *lower_bounds;
965 int i;
967 lengths = g_newa (uintptr_t, m_class_get_rank (klass) * 2);
968 for (i = 0; i < param_count; ++i) {
969 lengths [i] = values->data.i;
970 values ++;
972 if (m_class_get_rank (klass) == param_count) {
973 /* Only lengths provided. */
974 lower_bounds = NULL;
975 } else {
976 /* lower bounds are first. */
977 lower_bounds = (intptr_t *) lengths;
978 lengths += m_class_get_rank (klass);
980 return (MonoObject*) mono_array_new_full_checked (domain, klass, lengths, lower_bounds, error);
983 static gint32
984 ves_array_calculate_index (MonoArray *ao, stackval *sp, gboolean safe)
986 MonoClass *ac = ((MonoObject *) ao)->vtable->klass;
988 guint32 pos = 0;
989 if (ao->bounds) {
990 for (gint32 i = 0; i < m_class_get_rank (ac); i++) {
991 guint32 idx = sp [i].data.i;
992 guint32 lower = ao->bounds [i].lower_bound;
993 guint32 len = ao->bounds [i].length;
994 if (safe && (idx < lower || (idx - lower) >= len))
995 return -1;
996 pos = (pos * len) + idx - lower;
998 } else {
999 pos = sp [0].data.i;
1000 if (safe && pos >= ao->max_length)
1001 return -1;
1003 return pos;
1006 static MonoException*
1007 ves_array_get (InterpFrame *frame, stackval *sp, stackval *retval, MonoMethodSignature *sig, gboolean safe)
1009 MonoObject *o = sp->data.o;
1010 MonoArray *ao = (MonoArray *) o;
1011 MonoClass *ac = o->vtable->klass;
1013 g_assert (m_class_get_rank (ac) >= 1);
1015 gint32 pos = ves_array_calculate_index (ao, sp + 1, safe);
1016 if (pos == -1)
1017 return mono_get_exception_index_out_of_range ();
1019 gint32 esize = mono_array_element_size (ac);
1020 gconstpointer ea = mono_array_addr_with_size_fast (ao, esize, pos);
1022 MonoType *mt = sig->ret;
1023 stackval_from_data (mt, retval, ea, FALSE);
1024 return NULL;
1027 static MONO_NEVER_INLINE MonoException*
1028 ves_array_element_address (InterpFrame *frame, MonoClass *required_type, MonoArray *ao, stackval *sp, gboolean needs_typecheck)
1030 MonoClass *ac = ((MonoObject *) ao)->vtable->klass;
1032 g_assert (m_class_get_rank (ac) >= 1);
1034 gint32 pos = ves_array_calculate_index (ao, sp, TRUE);
1035 if (pos == -1)
1036 return mono_get_exception_index_out_of_range ();
1038 if (needs_typecheck && !mono_class_is_assignable_from_internal (m_class_get_element_class (mono_object_class ((MonoObject *) ao)), required_type))
1039 return mono_get_exception_array_type_mismatch ();
1040 gint32 esize = mono_array_element_size (ac);
1041 sp [-1].data.p = mono_array_addr_with_size_fast (ao, esize, pos);
1042 return NULL;
1045 #ifdef MONO_ARCH_HAVE_INTERP_ENTRY_TRAMPOLINE
1046 static MonoFuncV mono_native_to_interp_trampoline = NULL;
1047 #endif
1049 #ifndef MONO_ARCH_HAVE_INTERP_PINVOKE_TRAMP
1050 static InterpMethodArguments* build_args_from_sig (MonoMethodSignature *sig, InterpFrame *frame)
1052 InterpMethodArguments *margs = g_malloc0 (sizeof (InterpMethodArguments));
1054 #ifdef TARGET_ARM
1055 g_assert (mono_arm_eabi_supported ());
1056 int i8_align = mono_arm_i8_align ();
1057 #endif
1059 #ifdef TARGET_WASM
1060 margs->sig = sig;
1061 #endif
1063 if (sig->hasthis)
1064 margs->ilen++;
1066 for (int i = 0; i < sig->param_count; i++) {
1067 guint32 ptype = sig->params [i]->byref ? MONO_TYPE_PTR : sig->params [i]->type;
1068 switch (ptype) {
1069 case MONO_TYPE_BOOLEAN:
1070 case MONO_TYPE_CHAR:
1071 case MONO_TYPE_I1:
1072 case MONO_TYPE_U1:
1073 case MONO_TYPE_I2:
1074 case MONO_TYPE_U2:
1075 case MONO_TYPE_I4:
1076 case MONO_TYPE_U4:
1077 case MONO_TYPE_I:
1078 case MONO_TYPE_U:
1079 case MONO_TYPE_PTR:
1080 case MONO_TYPE_SZARRAY:
1081 case MONO_TYPE_CLASS:
1082 case MONO_TYPE_OBJECT:
1083 case MONO_TYPE_STRING:
1084 case MONO_TYPE_VALUETYPE:
1085 case MONO_TYPE_GENERICINST:
1086 #if SIZEOF_VOID_P == 8
1087 case MONO_TYPE_I8:
1088 case MONO_TYPE_U8:
1089 #endif
1090 margs->ilen++;
1091 break;
1092 #if SIZEOF_VOID_P == 4
1093 case MONO_TYPE_I8:
1094 case MONO_TYPE_U8:
1095 #ifdef TARGET_ARM
1096 /* pairs begin at even registers */
1097 if (i8_align == 8 && margs->ilen & 1)
1098 margs->ilen++;
1099 #endif
1100 margs->ilen += 2;
1101 break;
1102 #endif
1103 case MONO_TYPE_R4:
1104 #if SIZEOF_VOID_P == 8
1105 case MONO_TYPE_R8:
1106 #endif
1107 margs->flen++;
1108 break;
1109 #if SIZEOF_VOID_P == 4
1110 case MONO_TYPE_R8:
1111 margs->flen += 2;
1112 break;
1113 #endif
1114 default:
1115 g_error ("build_args_from_sig: not implemented yet (1): 0x%x\n", ptype);
1119 if (margs->ilen > 0)
1120 margs->iargs = g_malloc0 (sizeof (gpointer) * margs->ilen);
1122 if (margs->flen > 0)
1123 margs->fargs = g_malloc0 (sizeof (double) * margs->flen);
1125 if (margs->ilen > INTERP_ICALL_TRAMP_IARGS)
1126 g_error ("build_args_from_sig: TODO, allocate gregs: %d\n", margs->ilen);
1128 if (margs->flen > INTERP_ICALL_TRAMP_FARGS)
1129 g_error ("build_args_from_sig: TODO, allocate fregs: %d\n", margs->flen);
1132 size_t int_i = 0;
1133 size_t int_f = 0;
1135 if (sig->hasthis) {
1136 margs->iargs [0] = frame->stack_args->data.p;
1137 int_i++;
1140 for (int i = 0; i < sig->param_count; i++) {
1141 guint32 ptype = sig->params [i]->byref ? MONO_TYPE_PTR : sig->params [i]->type;
1142 switch (ptype) {
1143 case MONO_TYPE_BOOLEAN:
1144 case MONO_TYPE_CHAR:
1145 case MONO_TYPE_I1:
1146 case MONO_TYPE_U1:
1147 case MONO_TYPE_I2:
1148 case MONO_TYPE_U2:
1149 case MONO_TYPE_I4:
1150 case MONO_TYPE_U4:
1151 case MONO_TYPE_I:
1152 case MONO_TYPE_U:
1153 case MONO_TYPE_PTR:
1154 case MONO_TYPE_SZARRAY:
1155 case MONO_TYPE_CLASS:
1156 case MONO_TYPE_OBJECT:
1157 case MONO_TYPE_STRING:
1158 case MONO_TYPE_VALUETYPE:
1159 case MONO_TYPE_GENERICINST:
1160 #if SIZEOF_VOID_P == 8
1161 case MONO_TYPE_I8:
1162 case MONO_TYPE_U8:
1163 #endif
1164 margs->iargs [int_i] = frame->stack_args [i].data.p;
1165 #if DEBUG_INTERP
1166 g_print ("build_args_from_sig: margs->iargs [%d]: %p (frame @ %d)\n", int_i, margs->iargs [int_i], i);
1167 #endif
1168 int_i++;
1169 break;
1170 #if SIZEOF_VOID_P == 4
1171 case MONO_TYPE_I8:
1172 case MONO_TYPE_U8: {
1173 stackval *sarg = &frame->stack_args [i];
1174 #ifdef TARGET_ARM
1175 /* pairs begin at even registers */
1176 if (i8_align == 8 && int_i & 1)
1177 int_i++;
1178 #endif
1179 margs->iargs [int_i] = (gpointer) sarg->data.pair.lo;
1180 int_i++;
1181 margs->iargs [int_i] = (gpointer) sarg->data.pair.hi;
1182 #if DEBUG_INTERP
1183 g_print ("build_args_from_sig: margs->iargs [%d/%d]: 0x%016llx, hi=0x%08x lo=0x%08x (frame @ %d)\n", int_i - 1, int_i, *((guint64 *) &margs->iargs [int_i - 1]), sarg->data.pair.hi, sarg->data.pair.lo, i);
1184 #endif
1185 int_i++;
1186 break;
1188 #endif
1189 case MONO_TYPE_R4:
1190 case MONO_TYPE_R8:
1191 if (ptype == MONO_TYPE_R4)
1192 * (float *) &(margs->fargs [int_f]) = frame->stack_args [i].data.f_r4;
1193 else
1194 margs->fargs [int_f] = frame->stack_args [i].data.f;
1195 #if DEBUG_INTERP
1196 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);
1197 #endif
1198 #if SIZEOF_VOID_P == 4
1199 int_f += 2;
1200 #else
1201 int_f++;
1202 #endif
1203 break;
1204 default:
1205 g_error ("build_args_from_sig: not implemented yet (2): 0x%x\n", ptype);
1209 switch (sig->ret->type) {
1210 case MONO_TYPE_BOOLEAN:
1211 case MONO_TYPE_CHAR:
1212 case MONO_TYPE_I1:
1213 case MONO_TYPE_U1:
1214 case MONO_TYPE_I2:
1215 case MONO_TYPE_U2:
1216 case MONO_TYPE_I4:
1217 case MONO_TYPE_U4:
1218 case MONO_TYPE_I:
1219 case MONO_TYPE_U:
1220 case MONO_TYPE_PTR:
1221 case MONO_TYPE_SZARRAY:
1222 case MONO_TYPE_CLASS:
1223 case MONO_TYPE_OBJECT:
1224 case MONO_TYPE_STRING:
1225 case MONO_TYPE_I8:
1226 case MONO_TYPE_U8:
1227 case MONO_TYPE_VALUETYPE:
1228 case MONO_TYPE_GENERICINST:
1229 margs->retval = &(frame->retval->data.p);
1230 margs->is_float_ret = 0;
1231 break;
1232 case MONO_TYPE_R4:
1233 case MONO_TYPE_R8:
1234 margs->retval = &(frame->retval->data.p);
1235 margs->is_float_ret = 1;
1236 break;
1237 case MONO_TYPE_VOID:
1238 margs->retval = NULL;
1239 break;
1240 default:
1241 g_error ("build_args_from_sig: ret type not implemented yet: 0x%x\n", sig->ret->type);
1244 return margs;
1246 #endif
1248 static void
1249 interp_frame_arg_to_data (MonoInterpFrameHandle frame, MonoMethodSignature *sig, int index, gpointer data)
1251 InterpFrame *iframe = (InterpFrame*)frame;
1253 if (index == -1)
1254 stackval_to_data (sig->ret, iframe->retval, data, sig->pinvoke);
1255 else
1256 stackval_to_data (sig->params [index], &iframe->stack_args [index], data, sig->pinvoke);
1259 static void
1260 interp_data_to_frame_arg (MonoInterpFrameHandle frame, MonoMethodSignature *sig, int index, gconstpointer data)
1262 InterpFrame *iframe = (InterpFrame*)frame;
1264 if (index == -1)
1265 stackval_from_data (sig->ret, iframe->retval, data, sig->pinvoke);
1266 else if (sig->hasthis && index == 0)
1267 iframe->stack_args [index].data.p = *(gpointer*)data;
1268 else
1269 stackval_from_data (sig->params [index - sig->hasthis], &iframe->stack_args [index], data, sig->pinvoke);
1272 static gpointer
1273 interp_frame_arg_to_storage (MonoInterpFrameHandle frame, MonoMethodSignature *sig, int index)
1275 InterpFrame *iframe = (InterpFrame*)frame;
1277 if (index == -1)
1278 return stackval_to_data_addr (sig->ret, iframe->retval);
1279 else
1280 return stackval_to_data_addr (sig->params [index], &iframe->stack_args [index]);
1283 static void
1284 interp_frame_arg_set_storage (MonoInterpFrameHandle frame, MonoMethodSignature *sig, int index, gpointer storage)
1286 InterpFrame *iframe = (InterpFrame*)frame;
1287 stackval *val = (index == -1) ? iframe->retval : &iframe->stack_args [index];
1288 MonoType *type = (index == -1) ? sig->ret : sig->params [index];
1290 switch (type->type) {
1291 case MONO_TYPE_GENERICINST:
1292 if (!MONO_TYPE_IS_REFERENCE (type))
1293 val->data.vt = storage;
1294 break;
1295 case MONO_TYPE_VALUETYPE:
1296 val->data.vt = storage;
1297 break;
1298 default:
1299 g_assert_not_reached ();
1303 static MonoPIFunc
1304 get_interp_to_native_trampoline (void)
1306 static MonoPIFunc trampoline = NULL;
1308 if (!trampoline) {
1309 if (mono_ee_features.use_aot_trampolines) {
1310 trampoline = (MonoPIFunc) mono_aot_get_trampoline ("interp_to_native_trampoline");
1311 } else {
1312 MonoTrampInfo *info;
1313 trampoline = (MonoPIFunc) mono_arch_get_interp_to_native_trampoline (&info);
1314 mono_tramp_info_register (info, NULL);
1316 mono_memory_barrier ();
1318 return trampoline;
1321 static void
1322 interp_to_native_trampoline (gpointer addr, gpointer ccontext)
1324 get_interp_to_native_trampoline () (addr, ccontext);
1327 /* MONO_NO_OPTIMIATION is needed due to usage of INTERP_PUSH_LMF_WITH_CTX. */
1328 #ifdef _MSC_VER
1329 #pragma optimize ("", off)
1330 #endif
1331 static MONO_NO_OPTIMIZATION MONO_NEVER_INLINE void
1332 ves_pinvoke_method (InterpFrame *frame, MonoMethodSignature *sig, MonoFuncV addr, ThreadContext *context, gboolean save_last_error)
1334 MonoLMFExt ext;
1335 gpointer args;
1337 g_assert (!frame->imethod);
1339 static MonoPIFunc entry_func = NULL;
1340 if (!entry_func) {
1341 #ifdef MONO_ARCH_HAS_NO_PROPER_MONOCTX
1342 ERROR_DECL (error);
1343 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);
1344 mono_error_assert_ok (error);
1345 #else
1346 entry_func = get_interp_to_native_trampoline ();
1347 #endif
1348 mono_memory_barrier ();
1351 #ifdef ENABLE_NETCORE
1352 if (save_last_error) {
1353 mono_marshal_clear_last_error ();
1355 #endif
1357 #ifdef MONO_ARCH_HAVE_INTERP_PINVOKE_TRAMP
1358 CallContext ccontext;
1359 mono_arch_set_native_call_context_args (&ccontext, frame, sig);
1360 args = &ccontext;
1361 #else
1362 InterpMethodArguments *margs = build_args_from_sig (sig, frame);
1363 args = margs;
1364 #endif
1366 INTERP_PUSH_LMF_WITH_CTX (frame, ext, exit_pinvoke);
1367 entry_func ((gpointer) addr, args);
1368 if (save_last_error)
1369 mono_marshal_set_last_error ();
1370 interp_pop_lmf (&ext);
1372 #ifdef MONO_ARCH_HAVE_INTERP_PINVOKE_TRAMP
1373 if (!context->has_resume_state)
1374 mono_arch_get_native_call_context_ret (&ccontext, frame, sig);
1376 if (ccontext.stack != NULL)
1377 g_free (ccontext.stack);
1378 #else
1379 if (!context->has_resume_state && !MONO_TYPE_ISSTRUCT (sig->ret))
1380 stackval_from_data (sig->ret, frame->retval, (char*)&frame->retval->data.p, sig->pinvoke);
1382 g_free (margs->iargs);
1383 g_free (margs->fargs);
1384 g_free (margs);
1385 #endif
1386 goto exit_pinvoke; // prevent unused label warning in some configurations
1387 exit_pinvoke:
1388 return;
1390 #ifdef _MSC_VER
1391 #pragma optimize ("", on)
1392 #endif
1395 * interp_init_delegate:
1397 * Initialize del->interp_method.
1399 static void
1400 interp_init_delegate (MonoDelegate *del, MonoError *error)
1402 MonoMethod *method;
1404 if (del->interp_method) {
1405 /* Delegate created by a call to ves_icall_mono_delegate_ctor_interp () */
1406 del->method = ((InterpMethod *)del->interp_method)->method;
1407 } else if (del->method) {
1408 /* Delegate created dynamically */
1409 del->interp_method = mono_interp_get_imethod (del->object.vtable->domain, del->method, error);
1410 } else {
1411 /* Created from JITted code */
1412 g_assert_not_reached ();
1415 method = ((InterpMethod*)del->interp_method)->method;
1416 if (del->target &&
1417 method &&
1418 method->flags & METHOD_ATTRIBUTE_VIRTUAL &&
1419 method->flags & METHOD_ATTRIBUTE_ABSTRACT &&
1420 mono_class_is_abstract (method->klass))
1421 del->interp_method = get_virtual_method ((InterpMethod*)del->interp_method, del->target->vtable);
1423 method = ((InterpMethod*)del->interp_method)->method;
1424 if (method && m_class_get_parent (method->klass) == mono_defaults.multicastdelegate_class) {
1425 const char *name = method->name;
1426 if (*name == 'I' && (strcmp (name, "Invoke") == 0)) {
1428 * When invoking the delegate interp_method is executed directly. If it's an
1429 * invoke make sure we replace it with the appropriate delegate invoke wrapper.
1431 * FIXME We should do this later, when we also know the delegate on which the
1432 * target method is called.
1434 del->interp_method = mono_interp_get_imethod (del->object.vtable->domain, mono_marshal_get_delegate_invoke (method, NULL), error);
1435 mono_error_assert_ok (error);
1439 if (!((InterpMethod *) del->interp_method)->transformed && method_is_dynamic (method)) {
1440 /* Return any errors from method compilation */
1441 mono_interp_transform_method ((InterpMethod *) del->interp_method, get_context (), error);
1442 return_if_nok (error);
1446 static void
1447 interp_delegate_ctor (MonoObjectHandle this_obj, MonoObjectHandle target, gpointer addr, MonoError *error)
1450 * addr is the result of an LDFTN opcode, i.e. an InterpMethod
1452 InterpMethod *imethod = (InterpMethod*)addr;
1454 if (!(imethod->method->flags & METHOD_ATTRIBUTE_STATIC)) {
1455 MonoMethod *invoke = mono_get_delegate_invoke_internal (mono_handle_class (this_obj));
1456 /* virtual invoke delegates must not have null check */
1457 if (mono_method_signature_internal (imethod->method)->param_count == mono_method_signature_internal (invoke)->param_count
1458 && MONO_HANDLE_IS_NULL (target)) {
1459 mono_error_set_argument (error, "this", "Delegate to an instance method cannot have null 'this'");
1460 return;
1464 g_assert (imethod->method);
1465 gpointer entry = mini_get_interp_callbacks ()->create_method_pointer (imethod->method, FALSE, error);
1466 return_if_nok (error);
1468 MONO_HANDLE_SETVAL (MONO_HANDLE_CAST (MonoDelegate, this_obj), interp_method, gpointer, imethod);
1470 mono_delegate_ctor (this_obj, target, entry, error);
1474 * From the spec:
1475 * runtime specifies that the implementation of the method is automatically
1476 * provided by the runtime and is primarily used for the methods of delegates.
1478 static MONO_NEVER_INLINE MonoException*
1479 ves_imethod (InterpFrame *frame, MonoMethod *method, MonoMethodSignature *sig, stackval *sp, stackval *retval)
1481 const char *name = method->name;
1482 mono_class_init_internal (method->klass);
1484 if (method->klass == mono_defaults.array_class) {
1485 if (!strcmp (name, "UnsafeMov")) {
1486 /* TODO: layout checks */
1487 stackval_from_data (sig->ret, retval, (char*) sp, FALSE);
1488 return NULL;
1490 if (!strcmp (name, "UnsafeLoad"))
1491 return ves_array_get (frame, sp, retval, sig, FALSE);
1494 g_error ("Don't know how to exec runtime method %s.%s::%s",
1495 m_class_get_name_space (method->klass), m_class_get_name (method->klass),
1496 method->name);
1499 #if DEBUG_INTERP
1500 static char*
1501 dump_stack (stackval *stack, stackval *sp)
1503 stackval *s = stack;
1504 GString *str = g_string_new ("");
1506 if (sp == stack)
1507 return g_string_free (str, FALSE);
1509 while (s < sp) {
1510 g_string_append_printf (str, "[%p (%lld)] ", s->data.l, s->data.l);
1511 ++s;
1513 return g_string_free (str, FALSE);
1516 static void
1517 dump_stackval (GString *str, stackval *s, MonoType *type)
1519 switch (type->type) {
1520 case MONO_TYPE_I1:
1521 case MONO_TYPE_U1:
1522 case MONO_TYPE_I2:
1523 case MONO_TYPE_U2:
1524 case MONO_TYPE_I4:
1525 case MONO_TYPE_U4:
1526 case MONO_TYPE_CHAR:
1527 case MONO_TYPE_BOOLEAN:
1528 g_string_append_printf (str, "[%d] ", s->data.i);
1529 break;
1530 case MONO_TYPE_STRING:
1531 case MONO_TYPE_SZARRAY:
1532 case MONO_TYPE_CLASS:
1533 case MONO_TYPE_OBJECT:
1534 case MONO_TYPE_ARRAY:
1535 case MONO_TYPE_PTR:
1536 case MONO_TYPE_I:
1537 case MONO_TYPE_U:
1538 g_string_append_printf (str, "[%p] ", s->data.p);
1539 break;
1540 case MONO_TYPE_VALUETYPE:
1541 if (m_class_is_enumtype (type->data.klass))
1542 g_string_append_printf (str, "[%d] ", s->data.i);
1543 else
1544 g_string_append_printf (str, "[vt:%p] ", s->data.p);
1545 break;
1546 case MONO_TYPE_R4:
1547 g_string_append_printf (str, "[%g] ", s->data.f_r4);
1548 break;
1549 case MONO_TYPE_R8:
1550 g_string_append_printf (str, "[%g] ", s->data.f);
1551 break;
1552 case MONO_TYPE_I8:
1553 case MONO_TYPE_U8:
1554 default: {
1555 GString *res = g_string_new ("");
1556 mono_type_get_desc (res, type, TRUE);
1557 g_string_append_printf (str, "[{%s} %lld/0x%0llx] ", res->str, s->data.l, s->data.l);
1558 g_string_free (res, TRUE);
1559 break;
1564 static char*
1565 dump_retval (InterpFrame *inv)
1567 GString *str = g_string_new ("");
1568 MonoType *ret = mono_method_signature_internal (inv->imethod->method)->ret;
1570 if (ret->type != MONO_TYPE_VOID)
1571 dump_stackval (str, inv->retval, ret);
1573 return g_string_free (str, FALSE);
1576 static char*
1577 dump_args (InterpFrame *inv)
1579 GString *str = g_string_new ("");
1580 int i;
1581 MonoMethodSignature *signature = mono_method_signature_internal (inv->imethod->method);
1583 if (signature->param_count == 0 && !signature->hasthis)
1584 return g_string_free (str, FALSE);
1586 if (signature->hasthis) {
1587 MonoMethod *method = inv->imethod->method;
1588 dump_stackval (str, inv->stack_args, m_class_get_byval_arg (method->klass));
1591 for (i = 0; i < signature->param_count; ++i)
1592 dump_stackval (str, inv->stack_args + (!!signature->hasthis) + i, signature->params [i]);
1594 return g_string_free (str, FALSE);
1596 #endif
1598 #define CHECK_ADD_OVERFLOW(a,b) \
1599 (gint32)(b) >= 0 ? (gint32)(G_MAXINT32) - (gint32)(b) < (gint32)(a) ? -1 : 0 \
1600 : (gint32)(G_MININT32) - (gint32)(b) > (gint32)(a) ? +1 : 0
1602 #define CHECK_SUB_OVERFLOW(a,b) \
1603 (gint32)(b) < 0 ? (gint32)(G_MAXINT32) + (gint32)(b) < (gint32)(a) ? -1 : 0 \
1604 : (gint32)(G_MININT32) + (gint32)(b) > (gint32)(a) ? +1 : 0
1606 #define CHECK_ADD_OVERFLOW_UN(a,b) \
1607 (guint32)(G_MAXUINT32) - (guint32)(b) < (guint32)(a) ? -1 : 0
1609 #define CHECK_SUB_OVERFLOW_UN(a,b) \
1610 (guint32)(a) < (guint32)(b) ? -1 : 0
1612 #define CHECK_ADD_OVERFLOW64(a,b) \
1613 (gint64)(b) >= 0 ? (gint64)(G_MAXINT64) - (gint64)(b) < (gint64)(a) ? -1 : 0 \
1614 : (gint64)(G_MININT64) - (gint64)(b) > (gint64)(a) ? +1 : 0
1616 #define CHECK_SUB_OVERFLOW64(a,b) \
1617 (gint64)(b) < 0 ? (gint64)(G_MAXINT64) + (gint64)(b) < (gint64)(a) ? -1 : 0 \
1618 : (gint64)(G_MININT64) + (gint64)(b) > (gint64)(a) ? +1 : 0
1620 #define CHECK_ADD_OVERFLOW64_UN(a,b) \
1621 (guint64)(G_MAXUINT64) - (guint64)(b) < (guint64)(a) ? -1 : 0
1623 #define CHECK_SUB_OVERFLOW64_UN(a,b) \
1624 (guint64)(a) < (guint64)(b) ? -1 : 0
1626 #if SIZEOF_VOID_P == 4
1627 #define CHECK_ADD_OVERFLOW_NAT(a,b) CHECK_ADD_OVERFLOW(a,b)
1628 #define CHECK_ADD_OVERFLOW_NAT_UN(a,b) CHECK_ADD_OVERFLOW_UN(a,b)
1629 #else
1630 #define CHECK_ADD_OVERFLOW_NAT(a,b) CHECK_ADD_OVERFLOW64(a,b)
1631 #define CHECK_ADD_OVERFLOW_NAT_UN(a,b) CHECK_ADD_OVERFLOW64_UN(a,b)
1632 #endif
1634 /* Resolves to TRUE if the operands would overflow */
1635 #define CHECK_MUL_OVERFLOW(a,b) \
1636 ((gint32)(a) == 0) || ((gint32)(b) == 0) ? 0 : \
1637 (((gint32)(a) > 0) && ((gint32)(b) == -1)) ? FALSE : \
1638 (((gint32)(a) < 0) && ((gint32)(b) == -1)) ? (a == G_MININT32) : \
1639 (((gint32)(a) > 0) && ((gint32)(b) > 0)) ? (gint32)(a) > ((G_MAXINT32) / (gint32)(b)) : \
1640 (((gint32)(a) > 0) && ((gint32)(b) < 0)) ? (gint32)(a) > ((G_MININT32) / (gint32)(b)) : \
1641 (((gint32)(a) < 0) && ((gint32)(b) > 0)) ? (gint32)(a) < ((G_MININT32) / (gint32)(b)) : \
1642 (gint32)(a) < ((G_MAXINT32) / (gint32)(b))
1644 #define CHECK_MUL_OVERFLOW_UN(a,b) \
1645 ((guint32)(a) == 0) || ((guint32)(b) == 0) ? 0 : \
1646 (guint32)(b) > ((G_MAXUINT32) / (guint32)(a))
1648 #define CHECK_MUL_OVERFLOW64(a,b) \
1649 ((gint64)(a) == 0) || ((gint64)(b) == 0) ? 0 : \
1650 (((gint64)(a) > 0) && ((gint64)(b) == -1)) ? FALSE : \
1651 (((gint64)(a) < 0) && ((gint64)(b) == -1)) ? (a == G_MININT64) : \
1652 (((gint64)(a) > 0) && ((gint64)(b) > 0)) ? (gint64)(a) > ((G_MAXINT64) / (gint64)(b)) : \
1653 (((gint64)(a) > 0) && ((gint64)(b) < 0)) ? (gint64)(a) > ((G_MININT64) / (gint64)(b)) : \
1654 (((gint64)(a) < 0) && ((gint64)(b) > 0)) ? (gint64)(a) < ((G_MININT64) / (gint64)(b)) : \
1655 (gint64)(a) < ((G_MAXINT64) / (gint64)(b))
1657 #define CHECK_MUL_OVERFLOW64_UN(a,b) \
1658 ((guint64)(a) == 0) || ((guint64)(b) == 0) ? 0 : \
1659 (guint64)(b) > ((G_MAXUINT64) / (guint64)(a))
1661 #if SIZEOF_VOID_P == 4
1662 #define CHECK_MUL_OVERFLOW_NAT(a,b) CHECK_MUL_OVERFLOW(a,b)
1663 #define CHECK_MUL_OVERFLOW_NAT_UN(a,b) CHECK_MUL_OVERFLOW_UN(a,b)
1664 #else
1665 #define CHECK_MUL_OVERFLOW_NAT(a,b) CHECK_MUL_OVERFLOW64(a,b)
1666 #define CHECK_MUL_OVERFLOW_NAT_UN(a,b) CHECK_MUL_OVERFLOW64_UN(a,b)
1667 #endif
1669 static MonoObject*
1670 interp_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError *error)
1672 InterpFrame frame;
1673 ThreadContext *context = get_context ();
1674 MonoMethodSignature *sig = mono_method_signature_internal (method);
1675 MonoClass *klass = mono_class_from_mono_type_internal (sig->ret);
1676 stackval result;
1677 MonoMethod *target_method = method;
1679 error_init (error);
1680 if (exc)
1681 *exc = NULL;
1683 MonoDomain *domain = mono_domain_get ();
1685 if (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
1686 target_method = mono_marshal_get_native_wrapper (target_method, FALSE, FALSE);
1687 MonoMethod *invoke_wrapper = mono_marshal_get_runtime_invoke_full (target_method, FALSE, TRUE);
1689 //* <code>MonoObject *runtime_invoke (MonoObject *this_obj, void **params, MonoObject **exc, void* method)</code>
1691 result.data.vt = alloca (mono_class_instance_size (klass));
1692 stackval args [4];
1694 if (sig->hasthis)
1695 args [0].data.p = obj;
1696 else
1697 args [0].data.p = NULL;
1698 args [1].data.p = params;
1699 args [2].data.p = exc;
1700 args [3].data.p = target_method;
1702 InterpMethod *imethod = mono_interp_get_imethod (domain, invoke_wrapper, error);
1703 mono_error_assert_ok (error);
1704 init_frame (&frame, NULL, imethod, args, &result);
1706 interp_exec_method (&frame, context, error);
1708 if (context->has_resume_state) {
1709 // This can happen on wasm !?
1710 MonoException *thrown_exc = (MonoException*) mono_gchandle_get_target_internal (context->exc_gchandle);
1711 if (exc)
1712 *exc = (MonoObject*)thrown_exc;
1713 else
1714 mono_error_set_exception_instance (error, thrown_exc);
1715 return NULL;
1717 return (MonoObject*)result.data.p;
1720 typedef struct {
1721 InterpMethod *rmethod;
1722 gpointer this_arg;
1723 gpointer res;
1724 gpointer args [16];
1725 gpointer *many_args;
1726 } InterpEntryData;
1728 /* Main function for entering the interpreter from compiled code */
1729 static void
1730 interp_entry (InterpEntryData *data)
1732 InterpFrame frame;
1733 InterpMethod *rmethod;
1734 ThreadContext *context;
1735 stackval result;
1736 stackval *args;
1737 MonoMethod *method;
1738 MonoMethodSignature *sig;
1739 MonoType *type;
1740 gpointer orig_domain = NULL, attach_cookie;
1741 int i;
1743 if ((gsize)data->rmethod & 1) {
1744 /* Unbox */
1745 data->this_arg = mono_object_unbox_internal ((MonoObject*)data->this_arg);
1746 data->rmethod = (InterpMethod*)(gpointer)((gsize)data->rmethod & ~1);
1748 rmethod = data->rmethod;
1750 if (rmethod->needs_thread_attach)
1751 orig_domain = mono_threads_attach_coop (mono_domain_get (), &attach_cookie);
1753 context = get_context ();
1755 method = rmethod->method;
1756 sig = mono_method_signature_internal (method);
1758 // FIXME: Optimize this
1760 //printf ("%s\n", mono_method_full_name (method, 1));
1762 args = g_newa (stackval, sig->param_count + (sig->hasthis ? 1 : 0));
1763 if (sig->hasthis)
1764 args [0].data.p = data->this_arg;
1766 gpointer *params;
1767 if (data->many_args)
1768 params = data->many_args;
1769 else
1770 params = data->args;
1771 for (i = 0; i < sig->param_count; ++i) {
1772 int a_index = i + (sig->hasthis ? 1 : 0);
1773 if (sig->params [i]->byref) {
1774 args [a_index].data.p = params [i];
1775 continue;
1777 type = rmethod->param_types [i];
1778 switch (type->type) {
1779 case MONO_TYPE_VALUETYPE:
1780 args [a_index].data.p = params [i];
1781 break;
1782 case MONO_TYPE_GENERICINST:
1783 if (MONO_TYPE_IS_REFERENCE (type))
1784 args [a_index].data.p = *(gpointer*)params [i];
1785 else
1786 args [a_index].data.vt = params [i];
1787 break;
1788 default:
1789 stackval_from_data (type, &args [a_index], params [i], FALSE);
1790 break;
1794 memset (&result, 0, sizeof (result));
1795 init_frame (&frame, NULL, data->rmethod, args, &result);
1797 type = rmethod->rtype;
1798 switch (type->type) {
1799 case MONO_TYPE_GENERICINST:
1800 if (!MONO_TYPE_IS_REFERENCE (type))
1801 frame.retval->data.vt = data->res;
1802 break;
1803 case MONO_TYPE_VALUETYPE:
1804 frame.retval->data.vt = data->res;
1805 break;
1806 default:
1807 break;
1810 ERROR_DECL (error);
1811 interp_exec_method (&frame, context, error);
1813 g_assert (!context->has_resume_state);
1815 if (rmethod->needs_thread_attach)
1816 mono_threads_detach_coop (orig_domain, &attach_cookie);
1818 if (mono_llvm_only) {
1819 if (context->has_resume_state)
1820 mono_llvm_reraise_exception ((MonoException*)mono_gchandle_get_target_internal (context->exc_gchandle));
1821 } else {
1822 g_assert (!context->has_resume_state);
1825 type = rmethod->rtype;
1826 switch (type->type) {
1827 case MONO_TYPE_VOID:
1828 break;
1829 case MONO_TYPE_OBJECT:
1830 /* No need for a write barrier */
1831 *(MonoObject**)data->res = (MonoObject*)frame.retval->data.p;
1832 break;
1833 case MONO_TYPE_GENERICINST:
1834 if (MONO_TYPE_IS_REFERENCE (type)) {
1835 *(MonoObject**)data->res = (MonoObject*)frame.retval->data.p;
1836 } else {
1837 /* Already set before the call */
1839 break;
1840 case MONO_TYPE_VALUETYPE:
1841 /* Already set before the call */
1842 break;
1843 default:
1844 stackval_to_data (type, frame.retval, data->res, FALSE);
1845 break;
1849 static stackval *
1850 do_icall (MonoMethodSignature *sig, int op, stackval *sp, gpointer ptr, gboolean save_last_error)
1852 #ifdef ENABLE_NETCORE
1853 if (save_last_error)
1854 mono_marshal_clear_last_error ();
1855 #endif
1857 switch (op) {
1858 case MINT_ICALL_V_V: {
1859 typedef void (*T)(void);
1860 T func = (T)ptr;
1861 func ();
1862 break;
1864 case MINT_ICALL_V_P: {
1865 typedef gpointer (*T)(void);
1866 T func = (T)ptr;
1867 sp++;
1868 sp [-1].data.p = func ();
1869 break;
1871 case MINT_ICALL_P_V: {
1872 typedef void (*T)(gpointer);
1873 T func = (T)ptr;
1874 func (sp [-1].data.p);
1875 sp --;
1876 break;
1878 case MINT_ICALL_P_P: {
1879 typedef gpointer (*T)(gpointer);
1880 T func = (T)ptr;
1881 sp [-1].data.p = func (sp [-1].data.p);
1882 break;
1884 case MINT_ICALL_PP_V: {
1885 typedef void (*T)(gpointer,gpointer);
1886 T func = (T)ptr;
1887 sp -= 2;
1888 func (sp [0].data.p, sp [1].data.p);
1889 break;
1891 case MINT_ICALL_PP_P: {
1892 typedef gpointer (*T)(gpointer,gpointer);
1893 T func = (T)ptr;
1894 --sp;
1895 sp [-1].data.p = func (sp [-1].data.p, sp [0].data.p);
1896 break;
1898 case MINT_ICALL_PPP_V: {
1899 typedef void (*T)(gpointer,gpointer,gpointer);
1900 T func = (T)ptr;
1901 sp -= 3;
1902 func (sp [0].data.p, sp [1].data.p, sp [2].data.p);
1903 break;
1905 case MINT_ICALL_PPP_P: {
1906 typedef gpointer (*T)(gpointer,gpointer,gpointer);
1907 T func = (T)ptr;
1908 sp -= 2;
1909 sp [-1].data.p = func (sp [-1].data.p, sp [0].data.p, sp [1].data.p);
1910 break;
1912 case MINT_ICALL_PPPP_V: {
1913 typedef void (*T)(gpointer,gpointer,gpointer,gpointer);
1914 T func = (T)ptr;
1915 sp -= 4;
1916 func (sp [0].data.p, sp [1].data.p, sp [2].data.p, sp [3].data.p);
1917 break;
1919 case MINT_ICALL_PPPP_P: {
1920 typedef gpointer (*T)(gpointer,gpointer,gpointer,gpointer);
1921 T func = (T)ptr;
1922 sp -= 3;
1923 sp [-1].data.p = func (sp [-1].data.p, sp [0].data.p, sp [1].data.p, sp [2].data.p);
1924 break;
1926 case MINT_ICALL_PPPPP_V: {
1927 typedef void (*T)(gpointer,gpointer,gpointer,gpointer,gpointer);
1928 T func = (T)ptr;
1929 sp -= 5;
1930 func (sp [0].data.p, sp [1].data.p, sp [2].data.p, sp [3].data.p, sp [4].data.p);
1931 break;
1933 case MINT_ICALL_PPPPP_P: {
1934 typedef gpointer (*T)(gpointer,gpointer,gpointer,gpointer,gpointer);
1935 T func = (T)ptr;
1936 sp -= 4;
1937 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);
1938 break;
1940 case MINT_ICALL_PPPPPP_V: {
1941 typedef void (*T)(gpointer,gpointer,gpointer,gpointer,gpointer,gpointer);
1942 T func = (T)ptr;
1943 sp -= 6;
1944 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);
1945 break;
1947 case MINT_ICALL_PPPPPP_P: {
1948 typedef gpointer (*T)(gpointer,gpointer,gpointer,gpointer,gpointer,gpointer);
1949 T func = (T)ptr;
1950 sp -= 5;
1951 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);
1952 break;
1954 default:
1955 g_assert_not_reached ();
1958 if (save_last_error)
1959 mono_marshal_set_last_error ();
1961 /* convert the native representation to the stackval representation */
1962 if (sig)
1963 stackval_from_data (sig->ret, &sp [-1], (char*) &sp [-1].data.p, sig->pinvoke);
1965 return sp;
1968 /* MONO_NO_OPTIMIATION is needed due to usage of INTERP_PUSH_LMF_WITH_CTX. */
1969 #ifdef _MSC_VER
1970 #pragma optimize ("", off)
1971 #endif
1972 static MONO_NO_OPTIMIZATION MONO_NEVER_INLINE stackval *
1973 do_icall_wrapper (InterpFrame *frame, MonoMethodSignature *sig, int op, stackval *sp, gpointer ptr, gboolean save_last_error)
1975 MonoLMFExt ext;
1976 INTERP_PUSH_LMF_WITH_CTX (frame, ext, exit_icall);
1978 sp = do_icall (sig, op, sp, ptr, save_last_error);
1980 interp_pop_lmf (&ext);
1982 goto exit_icall; // prevent unused label warning in some configurations
1983 exit_icall:
1984 return sp;
1986 #ifdef _MSC_VER
1987 #pragma optimize ("", on)
1988 #endif
1990 typedef struct {
1991 int pindex;
1992 gpointer jit_wrapper;
1993 gpointer *args;
1994 MonoFtnDesc *ftndesc;
1995 } JitCallCbData;
1997 static void
1998 jit_call_cb (gpointer arg)
2000 JitCallCbData *cb_data = (JitCallCbData*)arg;
2001 gpointer jit_wrapper = cb_data->jit_wrapper;
2002 int pindex = cb_data->pindex;
2003 gpointer *args = cb_data->args;
2004 MonoFtnDesc ftndesc = *cb_data->ftndesc;
2006 switch (pindex) {
2007 case 0: {
2008 typedef void (*T)(gpointer);
2009 T func = (T)jit_wrapper;
2011 func (&ftndesc);
2012 break;
2014 case 1: {
2015 typedef void (*T)(gpointer, gpointer);
2016 T func = (T)jit_wrapper;
2018 func (args [0], &ftndesc);
2019 break;
2021 case 2: {
2022 typedef void (*T)(gpointer, gpointer, gpointer);
2023 T func = (T)jit_wrapper;
2025 func (args [0], args [1], &ftndesc);
2026 break;
2028 case 3: {
2029 typedef void (*T)(gpointer, gpointer, gpointer, gpointer);
2030 T func = (T)jit_wrapper;
2032 func (args [0], args [1], args [2], &ftndesc);
2033 break;
2035 case 4: {
2036 typedef void (*T)(gpointer, gpointer, gpointer, gpointer, gpointer);
2037 T func = (T)jit_wrapper;
2039 func (args [0], args [1], args [2], args [3], &ftndesc);
2040 break;
2042 case 5: {
2043 typedef void (*T)(gpointer, gpointer, gpointer, gpointer, gpointer, gpointer);
2044 T func = (T)jit_wrapper;
2046 func (args [0], args [1], args [2], args [3], args [4], &ftndesc);
2047 break;
2049 case 6: {
2050 typedef void (*T)(gpointer, gpointer, gpointer, gpointer, gpointer, gpointer, gpointer);
2051 T func = (T)jit_wrapper;
2053 func (args [0], args [1], args [2], args [3], args [4], args [5], &ftndesc);
2054 break;
2056 case 7: {
2057 typedef void (*T)(gpointer, gpointer, gpointer, gpointer, gpointer, gpointer, gpointer, gpointer);
2058 T func = (T)jit_wrapper;
2060 func (args [0], args [1], args [2], args [3], args [4], args [5], args [6], &ftndesc);
2061 break;
2063 case 8: {
2064 typedef void (*T)(gpointer, gpointer, gpointer, gpointer, gpointer, gpointer, gpointer, gpointer, gpointer);
2065 T func = (T)jit_wrapper;
2067 func (args [0], args [1], args [2], args [3], args [4], args [5], args [6], args [7], &ftndesc);
2068 break;
2070 default:
2071 g_assert_not_reached ();
2072 break;
2076 static MONO_NEVER_INLINE stackval *
2077 do_jit_call (stackval *sp, unsigned char *vt_sp, ThreadContext *context, InterpFrame *frame, InterpMethod *rmethod, MonoError *error)
2079 MonoMethodSignature *sig;
2080 MonoFtnDesc ftndesc;
2081 guint8 res_buf [256];
2082 MonoType *type;
2083 MonoLMFExt ext;
2085 //printf ("jit_call: %s\n", mono_method_full_name (rmethod->method, 1));
2088 * Call JITted code through a gsharedvt_out wrapper. These wrappers receive every argument
2089 * by ref and return a return value using an explicit return value argument.
2091 if (!rmethod->jit_wrapper) {
2092 MonoMethod *method = rmethod->method;
2094 sig = mono_method_signature_internal (method);
2095 g_assert (sig);
2097 MonoMethod *wrapper = mini_get_gsharedvt_out_sig_wrapper (sig);
2098 //printf ("J: %s %s\n", mono_method_full_name (method, 1), mono_method_full_name (wrapper, 1));
2100 gpointer jit_wrapper = mono_jit_compile_method_jit_only (wrapper, error);
2101 mono_error_assert_ok (error);
2103 gpointer addr = mono_jit_compile_method_jit_only (method, error);
2104 return_val_if_nok (error, NULL);
2105 g_assert (addr);
2107 rmethod->jit_addr = addr;
2108 rmethod->jit_sig = sig;
2109 mono_memory_barrier ();
2110 rmethod->jit_wrapper = jit_wrapper;
2112 } else {
2113 sig = rmethod->jit_sig;
2116 sp -= sig->param_count;
2117 if (sig->hasthis)
2118 --sp;
2120 ftndesc.addr = rmethod->jit_addr;
2121 ftndesc.arg = NULL;
2123 // FIXME: Optimize this
2125 gpointer args [32];
2126 int pindex = 0;
2127 int stack_index = 0;
2128 if (rmethod->hasthis) {
2129 args [pindex ++] = sp [0].data.p;
2130 stack_index ++;
2132 type = rmethod->rtype;
2133 if (type->type != MONO_TYPE_VOID) {
2134 if (MONO_TYPE_ISSTRUCT (type))
2135 args [pindex ++] = vt_sp;
2136 else
2137 args [pindex ++] = res_buf;
2139 for (int i = 0; i < rmethod->param_count; ++i) {
2140 MonoType *t = rmethod->param_types [i];
2141 stackval *sval = &sp [stack_index + i];
2142 if (sig->params [i]->byref) {
2143 args [pindex ++] = sval->data.p;
2144 } else if (MONO_TYPE_ISSTRUCT (t)) {
2145 args [pindex ++] = sval->data.p;
2146 } else if (MONO_TYPE_IS_REFERENCE (t)) {
2147 args [pindex ++] = &sval->data.p;
2148 } else {
2149 switch (t->type) {
2150 case MONO_TYPE_I1:
2151 case MONO_TYPE_U1:
2152 case MONO_TYPE_I2:
2153 case MONO_TYPE_U2:
2154 case MONO_TYPE_I4:
2155 case MONO_TYPE_U4:
2156 case MONO_TYPE_VALUETYPE:
2157 args [pindex ++] = &sval->data.i;
2158 break;
2159 case MONO_TYPE_PTR:
2160 case MONO_TYPE_FNPTR:
2161 case MONO_TYPE_I:
2162 case MONO_TYPE_U:
2163 case MONO_TYPE_OBJECT:
2164 args [pindex ++] = &sval->data.p;
2165 break;
2166 case MONO_TYPE_I8:
2167 case MONO_TYPE_U8:
2168 args [pindex ++] = &sval->data.l;
2169 break;
2170 case MONO_TYPE_R4:
2171 args [pindex ++] = &sval->data.f_r4;
2172 break;
2173 case MONO_TYPE_R8:
2174 args [pindex ++] = &sval->data.f;
2175 break;
2176 default:
2177 printf ("%s\n", mono_type_full_name (t));
2178 g_assert_not_reached ();
2183 interp_push_lmf (&ext, frame);
2185 JitCallCbData cb_data;
2186 memset (&cb_data, 0, sizeof (cb_data));
2187 cb_data.jit_wrapper = rmethod->jit_wrapper;
2188 cb_data.pindex = pindex;
2189 cb_data.args = args;
2190 cb_data.ftndesc = &ftndesc;
2192 if (mono_aot_mode == MONO_AOT_MODE_LLVMONLY_INTERP) {
2193 /* Catch the exception thrown by the native code using a try-catch */
2194 gboolean thrown = FALSE;
2195 mono_llvm_cpp_catch_exception (jit_call_cb, &cb_data, &thrown);
2196 interp_pop_lmf (&ext);
2197 if (thrown) {
2198 MonoObject *obj = mono_llvm_load_exception ();
2199 g_assert (obj);
2200 mono_error_set_exception_instance (error, (MonoException*)obj);
2201 return sp;
2203 } else {
2204 jit_call_cb (&cb_data);
2205 interp_pop_lmf (&ext);
2208 MonoType *rtype = rmethod->rtype;
2209 switch (rtype->type) {
2210 case MONO_TYPE_VOID:
2211 case MONO_TYPE_OBJECT:
2212 case MONO_TYPE_STRING:
2213 case MONO_TYPE_CLASS:
2214 case MONO_TYPE_ARRAY:
2215 case MONO_TYPE_SZARRAY:
2216 case MONO_TYPE_I:
2217 case MONO_TYPE_U:
2218 case MONO_TYPE_PTR:
2219 sp->data.p = *(gpointer*)res_buf;
2220 break;
2221 case MONO_TYPE_I1:
2222 sp->data.i = *(gint8*)res_buf;
2223 break;
2224 case MONO_TYPE_U1:
2225 sp->data.i = *(guint8*)res_buf;
2226 break;
2227 case MONO_TYPE_I2:
2228 sp->data.i = *(gint16*)res_buf;
2229 break;
2230 case MONO_TYPE_U2:
2231 sp->data.i = *(guint16*)res_buf;
2232 break;
2233 case MONO_TYPE_I4:
2234 sp->data.i = *(gint32*)res_buf;
2235 break;
2236 case MONO_TYPE_U4:
2237 sp->data.i = *(guint32*)res_buf;
2238 break;
2239 case MONO_TYPE_I8:
2240 sp->data.l = *(gint64*)res_buf;
2241 break;
2242 case MONO_TYPE_U8:
2243 sp->data.l = *(guint64*)res_buf;
2244 break;
2245 case MONO_TYPE_R4:
2246 sp->data.f_r4 = *(float*)res_buf;
2247 break;
2248 case MONO_TYPE_R8:
2249 sp->data.f = *(double*)res_buf;
2250 break;
2251 case MONO_TYPE_TYPEDBYREF:
2252 case MONO_TYPE_VALUETYPE:
2253 /* The result was written to vt_sp */
2254 sp->data.p = vt_sp;
2255 break;
2256 case MONO_TYPE_GENERICINST:
2257 if (MONO_TYPE_IS_REFERENCE (rtype)) {
2258 sp->data.p = *(gpointer*)res_buf;
2259 } else {
2260 /* The result was written to vt_sp */
2261 sp->data.p = vt_sp;
2263 break;
2264 default:
2265 g_print ("%s\n", mono_type_full_name (rtype));
2266 g_assert_not_reached ();
2267 break;
2270 return sp;
2273 static MONO_NEVER_INLINE void
2274 do_debugger_tramp (void (*tramp) (void), InterpFrame *frame)
2276 MonoLMFExt ext;
2277 interp_push_lmf (&ext, frame);
2278 tramp ();
2279 interp_pop_lmf (&ext);
2282 static MONO_NEVER_INLINE MonoException*
2283 do_transform_method (InterpFrame *frame, ThreadContext *context)
2285 MonoLMFExt ext;
2286 /* Don't push lmf if we have no interp data */
2287 gboolean push_lmf = frame->parent != NULL;
2288 ERROR_DECL (error);
2290 /* Use the parent frame as the current frame is not complete yet */
2291 if (push_lmf)
2292 interp_push_lmf (&ext, frame->parent);
2294 mono_interp_transform_method (frame->imethod, context, error);
2296 if (push_lmf)
2297 interp_pop_lmf (&ext);
2299 return mono_error_convert_to_exception (error);
2302 static MONO_NEVER_INLINE guchar*
2303 copy_varargs_vtstack (MonoMethodSignature *csig, stackval *sp, guchar *vt_sp_start)
2305 stackval *first_arg = sp - csig->param_count;
2306 guchar *vt_sp = vt_sp_start;
2309 * We need to have the varargs linearly on the stack so the ArgIterator
2310 * can iterate over them. We pass the signature first and then copy them
2311 * one by one on the vtstack. At the end we pass the original vt_stack
2312 * so the callee (MINT_ARGLIST) can find the varargs space.
2314 *(gpointer*)vt_sp = csig;
2315 vt_sp += sizeof (gpointer);
2317 for (int i = csig->sentinelpos; i < csig->param_count; i++) {
2318 int align, arg_size;
2319 arg_size = mono_type_stack_size (csig->params [i], &align);
2320 vt_sp = (guchar*)ALIGN_PTR_TO (vt_sp, align);
2322 stackval_to_data (csig->params [i], &first_arg [i], vt_sp, FALSE);
2323 vt_sp += arg_size;
2326 vt_sp += sizeof (gpointer);
2327 vt_sp = (guchar*)ALIGN_PTR_TO (vt_sp, MINT_VT_ALIGNMENT);
2329 ((gpointer*)vt_sp) [-1] = vt_sp_start;
2331 return vt_sp;
2335 * These functions are the entry points into the interpreter from compiled code.
2336 * They are called by the interp_in wrappers. They have the following signature:
2337 * void (<optional this_arg>, <optional retval pointer>, <arg1>, ..., <argn>, <method ptr>)
2338 * They pack up their arguments into an InterpEntryData structure and call interp_entry ().
2339 * It would be possible for the wrappers to pack up the arguments etc, but that would make them bigger, and there are
2340 * more wrappers then these functions.
2341 * this/static * ret/void * 16 arguments -> 64 functions.
2344 #define MAX_INTERP_ENTRY_ARGS 8
2346 #define INTERP_ENTRY_BASE(_method, _this_arg, _res) \
2347 InterpEntryData data; \
2348 (data).rmethod = (_method); \
2349 (data).res = (_res); \
2350 (data).this_arg = (_this_arg); \
2351 (data).many_args = NULL;
2353 #define INTERP_ENTRY0(_this_arg, _res, _method) { \
2354 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2355 interp_entry (&data); \
2357 #define INTERP_ENTRY1(_this_arg, _res, _method) { \
2358 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2359 (data).args [0] = arg1; \
2360 interp_entry (&data); \
2362 #define INTERP_ENTRY2(_this_arg, _res, _method) { \
2363 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2364 (data).args [0] = arg1; \
2365 (data).args [1] = arg2; \
2366 interp_entry (&data); \
2368 #define INTERP_ENTRY3(_this_arg, _res, _method) { \
2369 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2370 (data).args [0] = arg1; \
2371 (data).args [1] = arg2; \
2372 (data).args [2] = arg3; \
2373 interp_entry (&data); \
2375 #define INTERP_ENTRY4(_this_arg, _res, _method) { \
2376 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2377 (data).args [0] = arg1; \
2378 (data).args [1] = arg2; \
2379 (data).args [2] = arg3; \
2380 (data).args [3] = arg4; \
2381 interp_entry (&data); \
2383 #define INTERP_ENTRY5(_this_arg, _res, _method) { \
2384 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2385 (data).args [0] = arg1; \
2386 (data).args [1] = arg2; \
2387 (data).args [2] = arg3; \
2388 (data).args [3] = arg4; \
2389 (data).args [4] = arg5; \
2390 interp_entry (&data); \
2392 #define INTERP_ENTRY6(_this_arg, _res, _method) { \
2393 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2394 (data).args [0] = arg1; \
2395 (data).args [1] = arg2; \
2396 (data).args [2] = arg3; \
2397 (data).args [3] = arg4; \
2398 (data).args [4] = arg5; \
2399 (data).args [5] = arg6; \
2400 interp_entry (&data); \
2402 #define INTERP_ENTRY7(_this_arg, _res, _method) { \
2403 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2404 (data).args [0] = arg1; \
2405 (data).args [1] = arg2; \
2406 (data).args [2] = arg3; \
2407 (data).args [3] = arg4; \
2408 (data).args [4] = arg5; \
2409 (data).args [5] = arg6; \
2410 (data).args [6] = arg7; \
2411 interp_entry (&data); \
2413 #define INTERP_ENTRY8(_this_arg, _res, _method) { \
2414 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2415 (data).args [0] = arg1; \
2416 (data).args [1] = arg2; \
2417 (data).args [2] = arg3; \
2418 (data).args [3] = arg4; \
2419 (data).args [4] = arg5; \
2420 (data).args [5] = arg6; \
2421 (data).args [6] = arg7; \
2422 (data).args [7] = arg8; \
2423 interp_entry (&data); \
2426 #define ARGLIST0 InterpMethod *rmethod
2427 #define ARGLIST1 gpointer arg1, InterpMethod *rmethod
2428 #define ARGLIST2 gpointer arg1, gpointer arg2, InterpMethod *rmethod
2429 #define ARGLIST3 gpointer arg1, gpointer arg2, gpointer arg3, InterpMethod *rmethod
2430 #define ARGLIST4 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, InterpMethod *rmethod
2431 #define ARGLIST5 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, gpointer arg5, InterpMethod *rmethod
2432 #define ARGLIST6 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, gpointer arg5, gpointer arg6, InterpMethod *rmethod
2433 #define ARGLIST7 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, gpointer arg5, gpointer arg6, gpointer arg7, InterpMethod *rmethod
2434 #define ARGLIST8 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, gpointer arg5, gpointer arg6, gpointer arg7, gpointer arg8, InterpMethod *rmethod
2436 static void interp_entry_static_0 (ARGLIST0) INTERP_ENTRY0 (NULL, NULL, rmethod)
2437 static void interp_entry_static_1 (ARGLIST1) INTERP_ENTRY1 (NULL, NULL, rmethod)
2438 static void interp_entry_static_2 (ARGLIST2) INTERP_ENTRY2 (NULL, NULL, rmethod)
2439 static void interp_entry_static_3 (ARGLIST3) INTERP_ENTRY3 (NULL, NULL, rmethod)
2440 static void interp_entry_static_4 (ARGLIST4) INTERP_ENTRY4 (NULL, NULL, rmethod)
2441 static void interp_entry_static_5 (ARGLIST5) INTERP_ENTRY5 (NULL, NULL, rmethod)
2442 static void interp_entry_static_6 (ARGLIST6) INTERP_ENTRY6 (NULL, NULL, rmethod)
2443 static void interp_entry_static_7 (ARGLIST7) INTERP_ENTRY7 (NULL, NULL, rmethod)
2444 static void interp_entry_static_8 (ARGLIST8) INTERP_ENTRY8 (NULL, NULL, rmethod)
2445 static void interp_entry_static_ret_0 (gpointer res, ARGLIST0) INTERP_ENTRY0 (NULL, res, rmethod)
2446 static void interp_entry_static_ret_1 (gpointer res, ARGLIST1) INTERP_ENTRY1 (NULL, res, rmethod)
2447 static void interp_entry_static_ret_2 (gpointer res, ARGLIST2) INTERP_ENTRY2 (NULL, res, rmethod)
2448 static void interp_entry_static_ret_3 (gpointer res, ARGLIST3) INTERP_ENTRY3 (NULL, res, rmethod)
2449 static void interp_entry_static_ret_4 (gpointer res, ARGLIST4) INTERP_ENTRY4 (NULL, res, rmethod)
2450 static void interp_entry_static_ret_5 (gpointer res, ARGLIST5) INTERP_ENTRY5 (NULL, res, rmethod)
2451 static void interp_entry_static_ret_6 (gpointer res, ARGLIST6) INTERP_ENTRY6 (NULL, res, rmethod)
2452 static void interp_entry_static_ret_7 (gpointer res, ARGLIST7) INTERP_ENTRY7 (NULL, res, rmethod)
2453 static void interp_entry_static_ret_8 (gpointer res, ARGLIST8) INTERP_ENTRY8 (NULL, res, rmethod)
2454 static void interp_entry_instance_0 (gpointer this_arg, ARGLIST0) INTERP_ENTRY0 (this_arg, NULL, rmethod)
2455 static void interp_entry_instance_1 (gpointer this_arg, ARGLIST1) INTERP_ENTRY1 (this_arg, NULL, rmethod)
2456 static void interp_entry_instance_2 (gpointer this_arg, ARGLIST2) INTERP_ENTRY2 (this_arg, NULL, rmethod)
2457 static void interp_entry_instance_3 (gpointer this_arg, ARGLIST3) INTERP_ENTRY3 (this_arg, NULL, rmethod)
2458 static void interp_entry_instance_4 (gpointer this_arg, ARGLIST4) INTERP_ENTRY4 (this_arg, NULL, rmethod)
2459 static void interp_entry_instance_5 (gpointer this_arg, ARGLIST5) INTERP_ENTRY5 (this_arg, NULL, rmethod)
2460 static void interp_entry_instance_6 (gpointer this_arg, ARGLIST6) INTERP_ENTRY6 (this_arg, NULL, rmethod)
2461 static void interp_entry_instance_7 (gpointer this_arg, ARGLIST7) INTERP_ENTRY7 (this_arg, NULL, rmethod)
2462 static void interp_entry_instance_8 (gpointer this_arg, ARGLIST8) INTERP_ENTRY8 (this_arg, NULL, rmethod)
2463 static void interp_entry_instance_ret_0 (gpointer this_arg, gpointer res, ARGLIST0) INTERP_ENTRY0 (this_arg, res, rmethod)
2464 static void interp_entry_instance_ret_1 (gpointer this_arg, gpointer res, ARGLIST1) INTERP_ENTRY1 (this_arg, res, rmethod)
2465 static void interp_entry_instance_ret_2 (gpointer this_arg, gpointer res, ARGLIST2) INTERP_ENTRY2 (this_arg, res, rmethod)
2466 static void interp_entry_instance_ret_3 (gpointer this_arg, gpointer res, ARGLIST3) INTERP_ENTRY3 (this_arg, res, rmethod)
2467 static void interp_entry_instance_ret_4 (gpointer this_arg, gpointer res, ARGLIST4) INTERP_ENTRY4 (this_arg, res, rmethod)
2468 static void interp_entry_instance_ret_5 (gpointer this_arg, gpointer res, ARGLIST5) INTERP_ENTRY5 (this_arg, res, rmethod)
2469 static void interp_entry_instance_ret_6 (gpointer this_arg, gpointer res, ARGLIST6) INTERP_ENTRY6 (this_arg, res, rmethod)
2470 static void interp_entry_instance_ret_7 (gpointer this_arg, gpointer res, ARGLIST7) INTERP_ENTRY7 (this_arg, res, rmethod)
2471 static void interp_entry_instance_ret_8 (gpointer this_arg, gpointer res, ARGLIST8) INTERP_ENTRY8 (this_arg, res, rmethod)
2473 #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
2475 static gpointer entry_funcs_static [MAX_INTERP_ENTRY_ARGS + 1] = { INTERP_ENTRY_FUNCLIST (static) };
2476 static gpointer entry_funcs_static_ret [MAX_INTERP_ENTRY_ARGS + 1] = { INTERP_ENTRY_FUNCLIST (static_ret) };
2477 static gpointer entry_funcs_instance [MAX_INTERP_ENTRY_ARGS + 1] = { INTERP_ENTRY_FUNCLIST (instance) };
2478 static gpointer entry_funcs_instance_ret [MAX_INTERP_ENTRY_ARGS + 1] = { INTERP_ENTRY_FUNCLIST (instance_ret) };
2480 /* General version for methods with more than MAX_INTERP_ENTRY_ARGS arguments */
2481 static void
2482 interp_entry_general (gpointer this_arg, gpointer res, gpointer *args, gpointer rmethod)
2484 INTERP_ENTRY_BASE ((InterpMethod*)rmethod, this_arg, res);
2485 data.many_args = args;
2486 interp_entry (&data);
2489 #ifdef MONO_ARCH_HAVE_INTERP_ENTRY_TRAMPOLINE
2491 // inline so we can alloc on stack
2492 #define alloc_storage_for_stackval(s, t, p) do { \
2493 if ((t)->type == MONO_TYPE_GENERICINST && !MONO_TYPE_IS_REFERENCE (t)) { \
2494 (s)->data.vt = alloca (mono_class_value_size (mono_class_from_mono_type_internal (t), NULL)); \
2495 } else if ((t)->type == MONO_TYPE_VALUETYPE) { \
2496 if (p) \
2497 (s)->data.vt = alloca (mono_class_native_size ((t)->data.klass, NULL)); \
2498 else \
2499 (s)->data.vt = alloca (mono_class_value_size ((t)->data.klass, NULL)); \
2501 } while (0)
2503 static void
2504 interp_entry_from_trampoline (gpointer ccontext_untyped, gpointer rmethod_untyped)
2506 InterpFrame frame;
2507 ThreadContext *context;
2508 stackval result;
2509 stackval *args;
2510 MonoMethod *method;
2511 MonoMethodSignature *sig;
2512 CallContext *ccontext = (CallContext*) ccontext_untyped;
2513 InterpMethod *rmethod = (InterpMethod*) rmethod_untyped;
2514 gpointer orig_domain = NULL, attach_cookie;
2515 int i;
2517 if (rmethod->needs_thread_attach)
2518 orig_domain = mono_threads_attach_coop (mono_domain_get (), &attach_cookie);
2520 context = get_context ();
2522 method = rmethod->method;
2523 sig = mono_method_signature_internal (method);
2525 args = (stackval*)alloca (sizeof (stackval) * (sig->param_count + (sig->hasthis ? 1 : 0)));
2527 init_frame (&frame, NULL, rmethod, args, &result);
2529 /* Allocate storage for value types */
2530 for (i = 0; i < sig->param_count; i++) {
2531 MonoType *type = sig->params [i];
2532 alloc_storage_for_stackval (&frame.stack_args [i + sig->hasthis], type, sig->pinvoke);
2535 if (sig->ret->type != MONO_TYPE_VOID)
2536 alloc_storage_for_stackval (frame.retval, sig->ret, sig->pinvoke);
2538 /* Copy the args saved in the trampoline to the frame stack */
2539 mono_arch_get_native_call_context_args (ccontext, &frame, sig);
2541 ERROR_DECL (error);
2542 interp_exec_method (&frame, context, error);
2544 g_assert (!context->has_resume_state);
2546 if (rmethod->needs_thread_attach)
2547 mono_threads_detach_coop (orig_domain, &attach_cookie);
2549 /* Write back the return value */
2550 mono_arch_set_native_call_context_ret (ccontext, &frame, sig);
2553 #else
2555 static void
2556 interp_entry_from_trampoline (gpointer ccontext_untyped, gpointer rmethod_untyped)
2558 g_assert_not_reached ();
2561 #endif /* MONO_ARCH_HAVE_INTERP_ENTRY_TRAMPOLINE */
2563 static InterpMethod*
2564 lookup_method_pointer (gpointer addr)
2566 MonoDomain *domain = mono_domain_get ();
2567 MonoJitDomainInfo *info = domain_jit_info (domain);
2568 InterpMethod *res = NULL;
2570 mono_domain_lock (domain);
2571 if (info->interp_method_pointer_hash)
2572 res = (InterpMethod*)g_hash_table_lookup (info->interp_method_pointer_hash, addr);
2573 mono_domain_unlock (domain);
2575 return res;
2578 #ifndef MONO_ARCH_HAVE_INTERP_NATIVE_TO_MANAGED
2579 static void
2580 interp_no_native_to_managed (void)
2582 g_error ("interpreter: native-to-managed transition not available on this platform");
2584 #endif
2586 static void
2587 no_llvmonly_interp_method_pointer (void)
2589 g_assert_not_reached ();
2593 * interp_create_method_pointer_llvmonly:
2595 * Return an ftndesc for entering the interpreter and executing METHOD.
2597 static MonoFtnDesc*
2598 interp_create_method_pointer_llvmonly (MonoMethod *method, gboolean unbox, MonoError *error)
2600 MonoDomain *domain = mono_domain_get ();
2601 gpointer addr, entry_func, entry_wrapper;
2602 MonoMethodSignature *sig;
2603 MonoMethod *wrapper;
2604 MonoJitDomainInfo *info;
2605 InterpMethod *imethod;
2607 imethod = mono_interp_get_imethod (domain, method, error);
2608 return_val_if_nok (error, NULL);
2610 if (unbox) {
2611 if (imethod->llvmonly_unbox_entry)
2612 return (MonoFtnDesc*)imethod->llvmonly_unbox_entry;
2613 } else {
2614 if (imethod->jit_entry)
2615 return (MonoFtnDesc*)imethod->jit_entry;
2618 sig = mono_method_signature_internal (method);
2621 * The entry functions need access to the method to call, so we have
2622 * to use a ftndesc. The caller uses a normal signature, while the
2623 * entry functions use a gsharedvt_in signature, so wrap the entry function in
2624 * a gsharedvt_in_sig wrapper.
2626 wrapper = mini_get_gsharedvt_in_sig_wrapper (sig);
2628 entry_wrapper = mono_jit_compile_method_jit_only (wrapper, error);
2629 mono_error_assertf_ok (error, "couldn't compile wrapper \"%s\" for \"%s\"",
2630 mono_method_get_name_full (wrapper, TRUE, TRUE, MONO_TYPE_NAME_FORMAT_IL),
2631 mono_method_get_name_full (method, TRUE, TRUE, MONO_TYPE_NAME_FORMAT_IL));
2633 if (sig->param_count > MAX_INTERP_ENTRY_ARGS) {
2634 g_assert_not_reached ();
2635 //entry_func = (gpointer)interp_entry_general;
2636 } else if (sig->hasthis) {
2637 if (sig->ret->type == MONO_TYPE_VOID)
2638 entry_func = entry_funcs_instance [sig->param_count];
2639 else
2640 entry_func = entry_funcs_instance_ret [sig->param_count];
2641 } else {
2642 if (sig->ret->type == MONO_TYPE_VOID)
2643 entry_func = entry_funcs_static [sig->param_count];
2644 else
2645 entry_func = entry_funcs_static_ret [sig->param_count];
2647 g_assert (entry_func);
2649 /* Encode unbox in the lower bit of imethod */
2650 gpointer entry_arg = imethod;
2651 if (unbox)
2652 entry_arg = (gpointer)(((gsize)entry_arg) | 1);
2653 MonoFtnDesc *entry_ftndesc = mini_llvmonly_create_ftndesc (mono_domain_get (), entry_func, entry_arg);
2655 addr = mini_llvmonly_create_ftndesc (mono_domain_get (), entry_wrapper, entry_ftndesc);
2657 info = domain_jit_info (domain);
2658 mono_domain_lock (domain);
2659 if (!info->interp_method_pointer_hash)
2660 info->interp_method_pointer_hash = g_hash_table_new (NULL, NULL);
2661 g_hash_table_insert (info->interp_method_pointer_hash, addr, imethod);
2662 mono_domain_unlock (domain);
2664 mono_memory_barrier ();
2665 if (unbox)
2666 imethod->llvmonly_unbox_entry = addr;
2667 else
2668 imethod->jit_entry = addr;
2670 return (MonoFtnDesc*)addr;
2674 * interp_create_method_pointer:
2676 * Return a function pointer which can be used to call METHOD using the
2677 * interpreter. Return NULL for methods which are not supported.
2679 static gpointer
2680 interp_create_method_pointer (MonoMethod *method, gboolean compile, MonoError *error)
2682 #ifndef MONO_ARCH_HAVE_INTERP_NATIVE_TO_MANAGED
2683 if (mono_llvm_only)
2684 return (gpointer)no_llvmonly_interp_method_pointer;
2685 return (gpointer)interp_no_native_to_managed;
2686 #else
2687 gpointer addr, entry_func, entry_wrapper = NULL;
2688 MonoDomain *domain = mono_domain_get ();
2689 MonoJitDomainInfo *info;
2690 InterpMethod *imethod = mono_interp_get_imethod (domain, method, error);
2692 if (mono_llvm_only)
2693 return (gpointer)no_llvmonly_interp_method_pointer;
2695 if (imethod->jit_entry)
2696 return imethod->jit_entry;
2698 if (compile && !imethod->transformed) {
2699 /* Return any errors from method compilation */
2700 mono_interp_transform_method (imethod, get_context (), error);
2701 return_val_if_nok (error, NULL);
2704 MonoMethodSignature *sig = mono_method_signature_internal (method);
2706 if (mono_llvm_only)
2707 /* The caller should call interp_create_method_pointer_llvmonly */
2708 g_assert_not_reached ();
2710 if (method->wrapper_type && method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE)
2711 return imethod;
2713 #ifndef MONO_ARCH_HAVE_FTNPTR_ARG_TRAMPOLINE
2715 * Interp in wrappers get the argument in the rgctx register. If
2716 * MONO_ARCH_HAVE_FTNPTR_ARG_TRAMPOLINE is defined it means that
2717 * on that arch the rgctx register is not scratch, so we use a
2718 * separate temp register. We should update the wrappers for this
2719 * if we really care about those architectures (arm).
2721 MonoMethod *wrapper = mini_get_interp_in_wrapper (sig);
2723 entry_wrapper = mono_jit_compile_method_jit_only (wrapper, error);
2724 #endif
2725 if (entry_wrapper) {
2726 if (sig->param_count > MAX_INTERP_ENTRY_ARGS) {
2727 entry_func = (gpointer)interp_entry_general;
2728 } else if (sig->hasthis) {
2729 if (sig->ret->type == MONO_TYPE_VOID)
2730 entry_func = entry_funcs_instance [sig->param_count];
2731 else
2732 entry_func = entry_funcs_instance_ret [sig->param_count];
2733 } else {
2734 if (sig->ret->type == MONO_TYPE_VOID)
2735 entry_func = entry_funcs_static [sig->param_count];
2736 else
2737 entry_func = entry_funcs_static_ret [sig->param_count];
2739 } else {
2740 #ifndef MONO_ARCH_HAVE_INTERP_ENTRY_TRAMPOLINE
2741 mono_error_assertf_ok (error, "couldn't compile wrapper \"%s\" for \"%s\"",
2742 mono_method_get_name_full (wrapper, TRUE, TRUE, MONO_TYPE_NAME_FORMAT_IL),
2743 mono_method_get_name_full (method, TRUE, TRUE, MONO_TYPE_NAME_FORMAT_IL));
2744 #else
2745 mono_error_cleanup (error);
2746 error_init_reuse (error);
2747 if (!mono_native_to_interp_trampoline) {
2748 if (mono_aot_only) {
2749 mono_native_to_interp_trampoline = (MonoFuncV)mono_aot_get_trampoline ("native_to_interp_trampoline");
2750 } else {
2751 MonoTrampInfo *info;
2752 mono_native_to_interp_trampoline = (MonoFuncV)mono_arch_get_native_to_interp_trampoline (&info);
2753 mono_tramp_info_register (info, NULL);
2756 entry_wrapper = (gpointer)mono_native_to_interp_trampoline;
2757 /* We need the lmf wrapper only when being called from mixed mode */
2758 if (sig->pinvoke)
2759 entry_func = (gpointer)interp_entry_from_trampoline;
2760 else {
2761 static gpointer cached_func = NULL;
2762 if (!cached_func) {
2763 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);
2764 mono_memory_barrier ();
2766 entry_func = cached_func;
2768 #endif
2771 g_assert (entry_func);
2772 /* This is the argument passed to the interp_in wrapper by the static rgctx trampoline */
2773 MonoFtnDesc *ftndesc = g_new0 (MonoFtnDesc, 1);
2774 ftndesc->addr = entry_func;
2775 ftndesc->arg = imethod;
2776 mono_error_assert_ok (error);
2779 * The wrapper is called by compiled code, which doesn't pass the extra argument, so we pass it in the
2780 * rgctx register using a trampoline.
2783 addr = mono_create_ftnptr_arg_trampoline (ftndesc, entry_wrapper);
2785 info = domain_jit_info (domain);
2786 mono_domain_lock (domain);
2787 if (!info->interp_method_pointer_hash)
2788 info->interp_method_pointer_hash = g_hash_table_new (NULL, NULL);
2789 g_hash_table_insert (info->interp_method_pointer_hash, addr, imethod);
2790 mono_domain_unlock (domain);
2792 mono_memory_barrier ();
2793 imethod->jit_entry = addr;
2795 return addr;
2796 #endif
2799 #if COUNT_OPS
2800 static long opcode_counts[MINT_LASTOP];
2802 #define COUNT_OP(op) opcode_counts[op]++
2803 #else
2804 #define COUNT_OP(op)
2805 #endif
2807 #if DEBUG_INTERP
2808 #define DUMP_INSTR() \
2809 if (tracing > 1) { \
2810 char *ins; \
2811 if (sp > frame->stack) { \
2812 ins = dump_stack (frame->stack, sp); \
2813 } else { \
2814 ins = g_strdup (""); \
2816 sp->data.l = 0; \
2817 output_indent (); \
2818 char *mn = mono_method_full_name (frame->imethod->method, FALSE); \
2819 char *disasm = mono_interp_dis_mintop (frame->imethod->code, ip); \
2820 g_print ("(%p) %s -> %s\t%d:%s\n", mono_thread_internal_current (), mn, disasm, vt_sp - vtalloc, ins); \
2821 g_free (mn); \
2822 g_free (ins); \
2823 g_free (disasm); \
2825 #else
2826 #define DUMP_INSTR()
2827 #endif
2829 #define INIT_VTABLE(vtable) do { \
2830 if (G_UNLIKELY (!(vtable)->initialized)) { \
2831 mono_runtime_class_init_full ((vtable), error); \
2832 if (!is_ok (error)) \
2833 goto throw_error_label; \
2835 } while (0);
2837 static MONO_NEVER_INLINE MonoObject*
2838 mono_interp_new (MonoDomain* domain, MonoClass* klass)
2840 ERROR_DECL (error);
2841 MonoObject* const object = mono_object_new_checked (domain, klass, error);
2842 mono_error_cleanup (error); // FIXME: do not swallow the error
2843 return object;
2846 static
2847 #ifndef DISABLE_REMOTING
2848 MONO_NEVER_INLINE // To reduce stack.
2849 #endif
2850 void
2851 mono_interp_load_remote_field (
2852 InterpMethod* imethod,
2853 MonoObject* o,
2854 const guint16* ip,
2855 stackval* sp)
2857 g_assert (o); // Caller checks and throws exception properly.
2859 void* addr;
2860 MonoClassField* const field = (MonoClassField*)imethod->data_items[ip [1]];
2862 #ifndef DISABLE_REMOTING
2863 gpointer tmp;
2864 if (mono_object_is_transparent_proxy (o)) {
2865 MonoClass * const klass = ((MonoTransparentProxy*)o)->remote_class->proxy_class;
2866 ERROR_DECL (error);
2867 addr = mono_load_remote_field_checked (o, klass, field, &tmp, error);
2868 mono_error_cleanup (error); /* FIXME: don't swallow the error */
2869 } else
2870 #endif
2871 addr = (char*)o + field->offset;
2872 stackval_from_data (field->type, &sp [-1], addr, FALSE);
2875 static
2876 #ifndef DISABLE_REMOTING
2877 MONO_NEVER_INLINE // To reduce stack.
2878 #endif
2879 guchar* // Return new vt_sp instead of take-address.
2880 mono_interp_load_remote_field_vt (
2881 InterpMethod* imethod,
2882 MonoObject* o,
2883 const guint16* ip,
2884 stackval* sp,
2885 guchar* vt_sp)
2887 g_assert (o); // Caller checks and throws exception properly.
2889 void* addr;
2890 MonoClassField* const field = (MonoClassField*)imethod->data_items[ip [1]];
2891 MonoClass* klass = mono_class_from_mono_type_internal (field->type);
2892 int const i32 = mono_class_value_size (klass, NULL);
2894 #ifndef DISABLE_REMOTING
2895 gpointer tmp;
2896 if (mono_object_is_transparent_proxy (o)) {
2897 klass = ((MonoTransparentProxy*)o)->remote_class->proxy_class;
2898 ERROR_DECL (error);
2899 addr = mono_load_remote_field_checked (o, klass, field, &tmp, error);
2900 mono_error_cleanup (error); /* FIXME: don't swallow the error */
2901 } else
2902 #endif
2903 addr = (char*)o + field->offset;
2904 sp [-1].data.p = vt_sp;
2905 memcpy (vt_sp, addr, i32);
2906 return vt_sp + ALIGN_TO (i32, MINT_VT_ALIGNMENT);
2909 static MONO_NEVER_INLINE gboolean
2910 mono_interp_isinst (MonoObject* object, MonoClass* klass)
2912 ERROR_DECL (error);
2913 const gboolean isinst = mono_object_isinst_checked (object, klass, error) != NULL;
2914 mono_error_cleanup (error); // FIXME: do not swallow the error
2915 return isinst;
2918 // This function is outlined to help save stack in its caller, on the premise
2919 // that it is relatively rarely called. This also lets it use alloca.
2920 static MONO_NEVER_INLINE void
2921 mono_interp_calli_nat_dynamic_pinvoke (
2922 // Parameters are sorted by name.
2923 InterpFrame* child_frame,
2924 guchar* code,
2925 ThreadContext* context,
2926 MonoMethodSignature* csignature,
2927 MonoError* error)
2929 // Recompute to limit parameters, which can also contribute to caller stack.
2930 InterpMethod* const imethod = child_frame->parent->imethod;
2932 g_assert (imethod->method->dynamic && csignature->pinvoke);
2934 /* Pinvoke call is missing the wrapper. See mono_get_native_calli_wrapper */
2935 MonoMarshalSpec** mspecs = g_newa (MonoMarshalSpec*, csignature->param_count + 1);
2936 memset (mspecs, 0, sizeof (MonoMarshalSpec*) * (csignature->param_count + 1));
2938 MonoMethodPInvoke iinfo;
2939 memset (&iinfo, 0, sizeof (iinfo));
2941 MonoMethod* m = mono_marshal_get_native_func_wrapper (m_class_get_image (imethod->method->klass), csignature, &iinfo, mspecs, code);
2943 for (int i = csignature->param_count; i >= 0; i--)
2944 if (mspecs [i])
2945 mono_metadata_free_marshal_spec (mspecs [i]);
2948 ERROR_DECL (error);
2949 child_frame->imethod = mono_interp_get_imethod (imethod->domain, m, error);
2950 mono_error_cleanup (error); /* FIXME: don't swallow the error */
2953 interp_exec_method (child_frame, context, error);
2956 // Leave is split into pieces in order to consume less stack,
2957 // but not have to change how exception handling macros access labels and locals.
2958 static MONO_NEVER_INLINE MonoException*
2959 mono_interp_leave (InterpFrame* child_frame)
2961 stackval tmp_sp;
2963 * We need for mono_thread_get_undeniable_exception to be able to unwind
2964 * to check the abort threshold. For this to work we use child_frame as a
2965 * dummy frame that is stored in the lmf and serves as the transition frame
2967 do_icall_wrapper (child_frame, NULL, MINT_ICALL_V_P, &tmp_sp, (gpointer)mono_thread_get_undeniable_exception, FALSE);
2969 return (MonoException*)tmp_sp.data.p;
2972 static MONO_NEVER_INLINE void
2973 mono_interp_newobj_vt (
2974 // Parameters are sorted by name and parameter list is minimized
2975 // to reduce stack use in caller, on e.g. NT/AMD64 (up to 4 parameters
2976 // use no stack in caller).
2977 InterpFrame* child_frame,
2978 ThreadContext* context,
2979 MonoError* error)
2981 stackval* const sp = child_frame->stack_args;
2983 stackval valuetype_this;
2985 memset (&valuetype_this, 0, sizeof (stackval));
2986 sp->data.p = &valuetype_this;
2988 // FIXME It is unfortunate to outline a recursive case as it
2989 // increases its stack usage. We do this however as it conserves
2990 // stack for all the other recursive cases.
2991 interp_exec_method (child_frame, context, error);
2993 CHECK_RESUME_STATE (context);
2995 *sp = valuetype_this;
2996 resume:
3000 static MONO_NEVER_INLINE MonoException*
3001 mono_interp_newobj (
3002 // Parameters are sorted by name and parameter list is minimized
3003 // to reduce stack use in caller, on e.g. NT/AMD64 (up to 4 parameters
3004 // use no stack in caller).
3005 InterpFrame* child_frame,
3006 ThreadContext* context,
3007 MonoError* error,
3008 guchar* vt_sp)
3010 InterpFrame* const frame = child_frame->parent;
3011 InterpMethod* const imethod = frame->imethod;
3012 stackval* const sp = child_frame->stack_args;
3014 MonoObject* o = NULL; // See the comment about GC safety.
3015 stackval valuetype_this;
3016 stackval retval;
3018 MonoClass * const newobj_class = child_frame->imethod->method->klass;
3019 /*if (profiling_classes) {
3020 guint count = GPOINTER_TO_UINT (g_hash_table_lookup (profiling_classes, newobj_class));
3021 count++;
3022 g_hash_table_insert (profiling_classes, newobj_class, GUINT_TO_POINTER (count));
3026 * First arg is the object.
3028 if (m_class_is_valuetype (newobj_class)) {
3029 MonoType *t = m_class_get_byval_arg (newobj_class);
3030 memset (&valuetype_this, 0, sizeof (stackval));
3031 if (!m_class_is_enumtype (newobj_class) && (t->type == MONO_TYPE_VALUETYPE || (t->type == MONO_TYPE_GENERICINST && mono_type_generic_inst_is_valuetype (t)))) {
3032 sp->data.p = vt_sp;
3033 valuetype_this.data.p = vt_sp;
3034 } else {
3035 sp->data.p = &valuetype_this;
3037 } else {
3038 if (newobj_class != mono_defaults.string_class) {
3039 MonoVTable *vtable = mono_class_vtable_checked (imethod->domain, newobj_class, error);
3040 if (!is_ok (error) || !mono_runtime_class_init_full (vtable, error)) {
3041 MonoException* const exc = mono_error_convert_to_exception (error);
3042 g_assert (exc);
3043 return exc;
3045 ERROR_DECL (error);
3046 OBJREF (o) = mono_object_new_checked (imethod->domain, newobj_class, error);
3047 mono_error_cleanup (error); // FIXME: do not swallow the error
3048 EXCEPTION_CHECKPOINT_IN_HELPER_FUNCTION;
3049 sp->data.o = o;
3050 #ifndef DISABLE_REMOTING
3051 if (mono_object_is_transparent_proxy (o)) {
3052 MonoMethod *remoting_invoke_method = mono_marshal_get_remoting_invoke_with_check (child_frame->imethod->method, error);
3053 mono_error_assert_ok (error);
3054 child_frame->imethod = mono_interp_get_imethod (imethod->domain, remoting_invoke_method, error);
3055 mono_error_assert_ok (error);
3057 #endif
3058 } else {
3059 sp->data.p = NULL;
3060 child_frame->retval = &retval;
3064 interp_exec_method (child_frame, context, error);
3066 CHECK_RESUME_STATE (context);
3069 * a constructor returns void, but we need to return the object we created
3071 if (m_class_is_valuetype (newobj_class) && !m_class_is_enumtype (newobj_class)) {
3072 *sp = valuetype_this;
3073 } else if (newobj_class == mono_defaults.string_class) {
3074 *sp = retval;
3075 } else {
3076 sp->data.o = o;
3078 resume:
3079 return NULL;
3082 static MONO_NEVER_INLINE void
3083 mono_interp_enum_hasflag (stackval* sp, MonoClass* klass)
3085 guint64 a_val = 0, b_val = 0;
3087 stackval_to_data (m_class_get_byval_arg (klass), --sp, &b_val, FALSE);
3088 stackval_to_data (m_class_get_byval_arg (klass), --sp, &a_val, FALSE);
3089 sp->data.i = (a_val & b_val) == b_val;
3092 static MONO_NEVER_INLINE int
3093 mono_interp_box_nullable (InterpFrame* frame, const guint16* ip, stackval* sp, MonoError* error)
3095 InterpMethod* const imethod = frame->imethod;
3096 MonoClass* const c = (MonoClass*)imethod->data_items [ip [1]];
3098 int const size = mono_class_value_size (c, NULL);
3100 guint16 offset = ip [2];
3101 gboolean const pop_vt_sp = !(offset & BOX_NOT_CLEAR_VT_SP);
3102 offset &= ~BOX_NOT_CLEAR_VT_SP;
3104 sp [-1 - offset].data.o = mono_nullable_box (sp [-1 - offset].data.p, c, error);
3105 mono_interp_error_cleanup (error); /* FIXME: don't swallow the error */
3107 return pop_vt_sp ? ALIGN_TO (size, MINT_VT_ALIGNMENT) : 0;
3110 static MONO_NEVER_INLINE int
3111 mono_interp_box_vt (InterpFrame* frame, const guint16* ip, stackval* sp)
3113 InterpMethod* const imethod = frame->imethod;
3115 MonoObject* o; // See the comment about GC safety.
3116 MonoVTable * const vtable = (MonoVTable*)imethod->data_items [ip [1]];
3117 MonoClass* const c = vtable->klass;
3119 int const size = mono_class_value_size (c, NULL);
3121 guint16 offset = ip [2];
3122 gboolean const pop_vt_sp = !(offset & BOX_NOT_CLEAR_VT_SP);
3123 offset &= ~BOX_NOT_CLEAR_VT_SP;
3125 OBJREF (o) = mono_gc_alloc_obj (vtable, m_class_get_instance_size (vtable->klass));
3126 mono_value_copy_internal (mono_object_get_data (o), sp [-1 - offset].data.p, c);
3128 sp [-1 - offset].data.p = o;
3129 return pop_vt_sp ? ALIGN_TO (size, MINT_VT_ALIGNMENT) : 0;
3132 static MONO_NEVER_INLINE void
3133 mono_interp_box (InterpFrame* frame, const guint16* ip, stackval* sp)
3135 MonoObject *o; // See the comment about GC safety.
3136 MonoVTable * const vtable = (MonoVTable*)frame->imethod->data_items [ip [1]];
3138 OBJREF (o) = mono_gc_alloc_obj (vtable, m_class_get_instance_size (vtable->klass));
3140 guint16 const offset = ip [2];
3142 stackval_to_data (m_class_get_byval_arg (vtable->klass), &sp [-1 - offset], mono_object_get_data (o), FALSE);
3144 sp [-1 - offset].data.p = o;
3147 static MONO_NEVER_INLINE int
3148 mono_interp_store_remote_field_vt (InterpFrame* frame, const guint16* ip, stackval* sp, MonoError* error)
3150 InterpMethod* const imethod = frame->imethod;
3151 MonoClassField *field;
3153 MonoObject* const o = sp [-2].data.o;
3155 field = (MonoClassField*)imethod->data_items[ip [1]];
3156 MonoClass *klass = mono_class_from_mono_type_internal (field->type);
3157 int const i32 = mono_class_value_size (klass, NULL);
3159 #ifndef DISABLE_REMOTING
3160 if (mono_object_is_transparent_proxy (o)) {
3161 MonoClass *klass = ((MonoTransparentProxy*)o)->remote_class->proxy_class;
3162 mono_store_remote_field_checked (o, klass, field, sp [-1].data.p, error);
3163 mono_interp_error_cleanup (error); /* FIXME: don't swallow the error */
3164 } else
3165 #endif
3166 mono_value_copy_internal ((char *) o + field->offset, sp [-1].data.p, klass);
3168 return ALIGN_TO (i32, MINT_VT_ALIGNMENT);
3171 static MONO_ALWAYS_INLINE stackval*
3172 mono_interp_call (InterpFrame *frame, ThreadContext *context, InterpFrame *child_frame, const guint16 *ip, stackval *sp, guchar *vt_sp, gboolean is_virtual)
3174 frame->ip = ip;
3176 child_frame->imethod = (InterpMethod*)frame->imethod->data_items [ip [1]];
3177 ip += 2;
3178 sp->data.p = vt_sp;
3179 child_frame->retval = sp;
3181 /* decrement by the actual number of args */
3182 sp -= child_frame->imethod->param_count + child_frame->imethod->hasthis;
3184 if (is_virtual) {
3185 MonoObject *this_arg = (MonoObject*)sp->data.p;
3187 child_frame->imethod = get_virtual_method (child_frame->imethod, this_arg->vtable);
3188 if (m_class_is_valuetype (this_arg->vtable->klass) && m_class_is_valuetype (child_frame->imethod->method->klass)) {
3189 /* unbox */
3190 gpointer unboxed = mono_object_unbox_internal (this_arg);
3191 sp [0].data.p = unboxed;
3194 return sp;
3198 * If EXIT_AT_FINALLY is not -1, exit after exiting the finally clause with that index.
3199 * If BASE_FRAME is not NULL, copy arguments/locals from BASE_FRAME.
3200 * The ERROR argument is used to avoid declaring an error object for every interp frame, its not used
3201 * to return error information.
3203 * Currently this method uses 0x88 of stack space on 64bit gcc. Make sure to keep it under control.
3205 static void
3206 interp_exec_method_full (InterpFrame *frame, ThreadContext *context, FrameClauseArgs *clause_args, MonoError *error)
3208 InterpFrame child_frame;
3209 GSList *finally_ips = NULL;
3210 const guint16 *ip = NULL;
3211 stackval *sp;
3212 #if DEBUG_INTERP
3213 gint tracing = global_tracing;
3214 unsigned char *vtalloc;
3215 #endif
3216 unsigned char *vt_sp;
3217 unsigned char *locals = NULL;
3218 #if USE_COMPUTED_GOTO
3219 static void * const in_labels[] = {
3220 #define OPDEF(a,b,c,d,e,f) &&LAB_ ## a,
3221 #include "mintops.def"
3223 #endif
3225 #if DEBUG_INTERP
3226 debug_enter (frame, &tracing);
3227 #endif
3229 if (!frame->imethod->transformed) {
3230 #if DEBUG_INTERP
3231 char *mn = mono_method_full_name (frame->imethod->method, TRUE);
3232 g_print ("(%p) Transforming %s\n", mono_thread_internal_current (), mn);
3233 g_free (mn);
3234 #endif
3236 frame->ip = NULL;
3237 MonoException *ex = do_transform_method (frame, context);
3238 if (ex)
3239 THROW_EX (ex, NULL);
3240 EXCEPTION_CHECKPOINT;
3243 if (!clause_args) {
3244 frame->stack = (stackval*)g_alloca (frame->imethod->alloca_size);
3245 ip = frame->imethod->code;
3246 } else {
3247 ip = clause_args->start_with_ip;
3248 if (clause_args->base_frame) {
3249 frame->stack = (stackval*)g_alloca (frame->imethod->alloca_size);
3250 memcpy (frame->stack, clause_args->base_frame->stack, frame->imethod->alloca_size);
3253 sp = frame->stack;
3254 vt_sp = (unsigned char *) sp + frame->imethod->stack_size;
3255 #if DEBUG_INTERP
3256 vtalloc = vt_sp;
3257 #endif
3258 locals = (unsigned char *) vt_sp + frame->imethod->vt_stack_size;
3259 child_frame.parent = frame;
3261 if (clause_args && clause_args->filter_exception) {
3262 sp->data.p = clause_args->filter_exception;
3263 sp++;
3266 //g_print ("(%p) Call %s\n", mono_thread_internal_current (), mono_method_get_full_name (frame->imethod->method));
3269 * using while (ip < end) may result in a 15% performance drop,
3270 * but it may be useful for debug
3272 while (1) {
3273 main_loop:
3274 /* g_assert (sp >= frame->stack); */
3275 /* g_assert(vt_sp - vtalloc <= frame->imethod->vt_stack_size); */
3276 DUMP_INSTR();
3277 MINT_IN_SWITCH (*ip) {
3278 MINT_IN_CASE(MINT_INITLOCALS)
3279 memset (locals, 0, frame->imethod->locals_size);
3280 ++ip;
3281 MINT_IN_BREAK;
3282 MINT_IN_CASE(MINT_NOP)
3283 MINT_IN_CASE(MINT_NIY)
3284 g_assert_not_reached ();
3285 MINT_IN_BREAK;
3286 MINT_IN_CASE(MINT_BREAK)
3287 ++ip;
3288 do_debugger_tramp (mini_get_dbg_callbacks ()->user_break, frame);
3289 MINT_IN_BREAK;
3290 MINT_IN_CASE(MINT_BREAKPOINT)
3291 ++ip;
3292 mono_break ();
3293 MINT_IN_BREAK;
3294 MINT_IN_CASE(MINT_LDNULL)
3295 sp->data.p = NULL;
3296 ++ip;
3297 ++sp;
3298 MINT_IN_BREAK;
3299 MINT_IN_CASE(MINT_ARGLIST)
3300 sp->data.p = vt_sp;
3301 *(gpointer*)sp->data.p = ((gpointer*)frame->retval->data.p) [-1];
3302 vt_sp += ALIGN_TO (sizeof (gpointer), MINT_VT_ALIGNMENT);
3303 ++ip;
3304 ++sp;
3305 MINT_IN_BREAK;
3306 MINT_IN_CASE(MINT_VTRESULT) {
3307 int ret_size = ip [1];
3308 unsigned char *ret_vt_sp = vt_sp;
3309 vt_sp -= READ32(ip + 2);
3310 if (ret_size > 0) {
3311 memmove (vt_sp, ret_vt_sp, ret_size);
3312 sp [-1].data.p = vt_sp;
3313 vt_sp += ALIGN_TO (ret_size, MINT_VT_ALIGNMENT);
3315 ip += 4;
3316 MINT_IN_BREAK;
3318 #define LDC(n) do { sp->data.i = (n); ++ip; ++sp; } while (0)
3319 MINT_IN_CASE(MINT_LDC_I4_M1)
3320 LDC(-1);
3321 MINT_IN_BREAK;
3322 MINT_IN_CASE(MINT_LDC_I4_0)
3323 LDC(0);
3324 MINT_IN_BREAK;
3325 MINT_IN_CASE(MINT_LDC_I4_1)
3326 LDC(1);
3327 MINT_IN_BREAK;
3328 MINT_IN_CASE(MINT_LDC_I4_2)
3329 LDC(2);
3330 MINT_IN_BREAK;
3331 MINT_IN_CASE(MINT_LDC_I4_3)
3332 LDC(3);
3333 MINT_IN_BREAK;
3334 MINT_IN_CASE(MINT_LDC_I4_4)
3335 LDC(4);
3336 MINT_IN_BREAK;
3337 MINT_IN_CASE(MINT_LDC_I4_5)
3338 LDC(5);
3339 MINT_IN_BREAK;
3340 MINT_IN_CASE(MINT_LDC_I4_6)
3341 LDC(6);
3342 MINT_IN_BREAK;
3343 MINT_IN_CASE(MINT_LDC_I4_7)
3344 LDC(7);
3345 MINT_IN_BREAK;
3346 MINT_IN_CASE(MINT_LDC_I4_8)
3347 LDC(8);
3348 MINT_IN_BREAK;
3349 MINT_IN_CASE(MINT_LDC_I4_S)
3350 sp->data.i = (short)ip [1];
3351 ip += 2;
3352 ++sp;
3353 MINT_IN_BREAK;
3354 MINT_IN_CASE(MINT_LDC_I4)
3355 ++ip;
3356 sp->data.i = READ32 (ip);
3357 ip += 2;
3358 ++sp;
3359 MINT_IN_BREAK;
3360 MINT_IN_CASE(MINT_LDC_I8)
3361 ++ip;
3362 sp->data.l = READ64 (ip);
3363 ip += 4;
3364 ++sp;
3365 MINT_IN_BREAK;
3366 MINT_IN_CASE(MINT_LDC_I8_S)
3367 sp->data.l = (short)ip [1];
3368 ip += 2;
3369 ++sp;
3370 MINT_IN_BREAK;
3371 MINT_IN_CASE(MINT_LDC_R4) {
3372 guint32 val;
3373 ++ip;
3374 val = READ32(ip);
3375 sp->data.f_r4 = * (float *)&val;
3376 ip += 2;
3377 ++sp;
3378 MINT_IN_BREAK;
3380 MINT_IN_CASE(MINT_LDC_R8)
3381 sp->data.l = READ64 (ip + 1); /* note union usage */
3382 ip += 5;
3383 ++sp;
3384 MINT_IN_BREAK;
3385 MINT_IN_CASE(MINT_DUP)
3386 sp [0] = sp[-1];
3387 ++sp;
3388 ++ip;
3389 MINT_IN_BREAK;
3390 MINT_IN_CASE(MINT_DUP_VT) {
3391 int const i32 = READ32 (ip + 1);
3392 sp->data.p = vt_sp;
3393 memcpy(sp->data.p, sp [-1].data.p, i32);
3394 vt_sp += ALIGN_TO (i32, MINT_VT_ALIGNMENT);
3395 ++sp;
3396 ip += 3;
3397 MINT_IN_BREAK;
3399 MINT_IN_CASE(MINT_POP) {
3400 guint16 u16 = (ip [1]) + 1;
3401 if (u16 > 1)
3402 memmove (sp - u16, sp - 1, (u16 - 1) * sizeof (stackval));
3403 sp--;
3404 ip += 2;
3405 MINT_IN_BREAK;
3407 MINT_IN_CASE(MINT_JMP) {
3408 g_assert (sp == frame->stack);
3409 InterpMethod *new_method = (InterpMethod*)frame->imethod->data_items [ip [1]];
3411 if (frame->imethod->prof_flags & MONO_PROFILER_CALL_INSTRUMENTATION_TAIL_CALL)
3412 MONO_PROFILER_RAISE (method_tail_call, (frame->imethod->method, new_method->method));
3414 if (!new_method->transformed) {
3415 MONO_API_ERROR_INIT (error);
3417 frame->ip = ip;
3418 mono_interp_transform_method (new_method, context, error);
3419 MonoException *ex = mono_error_convert_to_exception (error);
3420 if (ex)
3421 THROW_EX (ex, ip);
3423 ip += 2;
3424 const gboolean realloc_frame = new_method->alloca_size > frame->imethod->alloca_size;
3425 frame->imethod = new_method;
3427 * We allocate the stack frame from scratch and store the arguments in the
3428 * locals again since it's possible for the caller stack frame to be smaller
3429 * than the callee stack frame (at the interp level)
3431 if (realloc_frame) {
3432 frame->stack = (stackval*)g_alloca (frame->imethod->alloca_size);
3433 memset (frame->stack, 0, frame->imethod->alloca_size);
3434 sp = frame->stack;
3436 vt_sp = (unsigned char *) sp + frame->imethod->stack_size;
3437 #if DEBUG_INTERP
3438 vtalloc = vt_sp;
3439 #endif
3440 locals = vt_sp + frame->imethod->vt_stack_size;
3441 ip = frame->imethod->code;
3442 MINT_IN_BREAK;
3444 MINT_IN_CASE(MINT_CALLI) {
3445 MonoMethodSignature *csignature;
3447 frame->ip = ip;
3449 csignature = (MonoMethodSignature*)frame->imethod->data_items [ip [1]];
3450 ip += 2;
3451 --sp;
3452 child_frame.imethod = (InterpMethod*)sp->data.p;
3454 sp->data.p = vt_sp;
3455 child_frame.retval = sp;
3456 /* decrement by the actual number of args */
3457 sp -= csignature->param_count;
3458 if (csignature->hasthis)
3459 --sp;
3461 if (child_frame.imethod->method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) {
3462 child_frame.imethod = mono_interp_get_imethod (frame->imethod->domain, mono_marshal_get_native_wrapper (child_frame.imethod->method, FALSE, FALSE), error);
3463 mono_interp_error_cleanup (error); /* FIXME: don't swallow the error */
3466 if (csignature->hasthis) {
3467 MonoObject *this_arg = (MonoObject*)sp->data.p;
3469 if (m_class_is_valuetype (this_arg->vtable->klass)) {
3470 gpointer unboxed = mono_object_unbox_internal (this_arg);
3471 sp [0].data.p = unboxed;
3475 if (csignature->ret->type != MONO_TYPE_VOID)
3476 goto common_call;
3477 goto common_vcall;
3479 MINT_IN_CASE(MINT_CALLI_NAT_FAST) {
3480 gpointer target_ip = sp [-1].data.p;
3481 MonoMethodSignature *csignature = (MonoMethodSignature*)frame->imethod->data_items [ip [1]];
3482 int opcode = ip [2];
3483 gboolean save_last_error = ip [3];
3485 sp--;
3486 frame->ip = ip;
3488 sp = do_icall_wrapper (frame, csignature, opcode, sp, target_ip, save_last_error);
3489 EXCEPTION_CHECKPOINT;
3490 CHECK_RESUME_STATE (context);
3491 ip += 4;
3492 MINT_IN_BREAK;
3494 MINT_IN_CASE(MINT_CALLI_NAT) {
3496 frame->ip = ip;
3498 MonoMethodSignature* csignature = (MonoMethodSignature*)frame->imethod->data_items [ip [1]];
3500 ip += 3;
3501 --sp;
3502 guchar* const code = (guchar*)sp->data.p;
3503 child_frame.imethod = NULL;
3505 sp->data.p = vt_sp;
3506 child_frame.retval = sp;
3507 /* decrement by the actual number of args */
3508 sp -= csignature->param_count;
3509 if (csignature->hasthis)
3510 --sp;
3511 child_frame.stack_args = sp;
3513 if (frame->imethod->method->dynamic && csignature->pinvoke) {
3514 mono_interp_calli_nat_dynamic_pinvoke (&child_frame, code, context, csignature, error);
3515 } else {
3516 const gboolean save_last_error = ip [-3 + 2];
3517 ves_pinvoke_method (&child_frame, csignature, (MonoFuncV) code, context, save_last_error);
3520 /* need to handle typedbyref ... */
3521 if (csignature->ret->type != MONO_TYPE_VOID)
3522 goto call_return;
3523 goto vcall_return;
3525 MINT_IN_CASE(MINT_CALLVIRT_FAST)
3526 MINT_IN_CASE(MINT_VCALLVIRT_FAST) {
3527 MonoObject *this_arg;
3528 InterpMethod *target_imethod;
3529 int slot;
3531 // FIXME Have it handle also remoting calls and use a single opcode for virtual calls
3533 frame->ip = ip;
3535 target_imethod = (InterpMethod*)frame->imethod->data_items [ip [1]];
3536 slot = (gint16)ip [2];
3537 ip += 3;
3538 sp->data.p = vt_sp;
3539 child_frame.retval = sp;
3541 /* decrement by the actual number of args */
3542 sp -= target_imethod->param_count + target_imethod->hasthis;
3544 this_arg = (MonoObject*)sp->data.p;
3546 child_frame.imethod = get_virtual_method_fast (target_imethod, this_arg->vtable, slot);
3547 if (m_class_is_valuetype (this_arg->vtable->klass) && m_class_is_valuetype (child_frame.imethod->method->klass)) {
3548 /* unbox */
3549 gpointer unboxed = mono_object_unbox_internal (this_arg);
3550 sp [0].data.p = unboxed;
3552 const gboolean is_void = ip [-3] == MINT_VCALLVIRT_FAST;
3553 if (!is_void)
3554 goto common_call;
3555 goto common_vcall;
3557 MINT_IN_CASE(MINT_CALL_VARARG) {
3558 int num_varargs = 0;
3559 MonoMethodSignature *csig;
3561 frame->ip = ip;
3563 child_frame.imethod = (InterpMethod*)frame->imethod->data_items [ip [1]];
3564 /* The real signature for vararg calls */
3565 csig = (MonoMethodSignature*) frame->imethod->data_items [ip [2]];
3566 /* Push all vararg arguments from normal sp to vt_sp together with the signature */
3567 num_varargs = csig->param_count - csig->sentinelpos;
3568 vt_sp = copy_varargs_vtstack (csig, sp, vt_sp);
3570 ip += 3;
3571 sp->data.p = vt_sp;
3572 child_frame.retval = sp;
3574 /* decrement by the actual number of args */
3575 sp -= child_frame.imethod->param_count + child_frame.imethod->hasthis + num_varargs;
3577 if (csig->ret->type != MONO_TYPE_VOID)
3578 goto common_call;
3579 goto common_vcall;
3581 MINT_IN_CASE(MINT_CALL)
3582 sp = mono_interp_call (frame, context, &child_frame, (ip += 2) - 2, sp, vt_sp, FALSE);
3583 common_call:
3584 child_frame.stack_args = sp;
3585 interp_exec_method (&child_frame, context, error);
3586 call_return:
3587 /* need to handle typedbyref ... */
3588 *sp = *child_frame.retval;
3589 sp++;
3590 vcall_return:
3591 CHECK_RESUME_STATE (context);
3592 MINT_IN_BREAK;
3594 MINT_IN_CASE(MINT_VCALL)
3595 sp = mono_interp_call (frame, context, &child_frame, (ip += 2) - 2, sp, vt_sp, FALSE);
3596 common_vcall:
3597 child_frame.stack_args = sp;
3598 interp_exec_method (&child_frame, context, error);
3599 goto vcall_return;
3601 MINT_IN_CASE(MINT_CALLVIRT)
3602 sp = mono_interp_call (frame, context, &child_frame, (ip += 2) - 2, sp, vt_sp, TRUE);
3603 goto common_call;
3605 MINT_IN_CASE(MINT_VCALLVIRT)
3606 sp = mono_interp_call (frame, context, &child_frame, (ip += 2) - 2, sp, vt_sp, TRUE);
3607 goto common_vcall;
3609 MINT_IN_CASE(MINT_JIT_CALL) {
3610 InterpMethod *rmethod = (InterpMethod*)frame->imethod->data_items [ip [1]];
3611 MONO_API_ERROR_INIT (error);
3612 frame->ip = ip;
3613 sp = do_jit_call (sp, vt_sp, context, frame, rmethod, error);
3614 if (!is_ok (error)) {
3615 MonoException *ex = mono_error_convert_to_exception (error);
3616 THROW_EX (ex, ip);
3618 ip += 2;
3620 CHECK_RESUME_STATE (context);
3622 if (rmethod->rtype->type != MONO_TYPE_VOID)
3623 sp++;
3625 MINT_IN_BREAK;
3627 MINT_IN_CASE(MINT_CALLRUN) {
3628 MonoMethod *target_method = (MonoMethod*) frame->imethod->data_items [ip [1]];
3629 MonoMethodSignature *sig = (MonoMethodSignature*) frame->imethod->data_items [ip [2]];
3630 stackval *retval;
3632 sp->data.p = vt_sp;
3633 retval = sp;
3635 sp -= sig->param_count;
3636 if (sig->hasthis)
3637 sp--;
3639 MonoException *ex = ves_imethod (frame, target_method, sig, sp, retval);
3640 if (ex)
3641 THROW_EX (ex, ip);
3643 if (sig->ret->type != MONO_TYPE_VOID) {
3644 *sp = *retval;
3645 sp++;
3647 ip += 3;
3648 MINT_IN_BREAK;
3650 MINT_IN_CASE(MINT_RET)
3651 --sp;
3652 *frame->retval = *sp;
3653 if (sp > frame->stack)
3654 g_warning ("ret: more values on stack: %d", sp-frame->stack);
3655 goto exit_frame;
3656 MINT_IN_CASE(MINT_RET_VOID)
3657 if (sp > frame->stack)
3658 g_warning ("ret.void: more values on stack: %d %s", sp-frame->stack, mono_method_full_name (frame->imethod->method, TRUE));
3659 goto exit_frame;
3660 MINT_IN_CASE(MINT_RET_VT) {
3661 int const i32 = READ32 (ip + 1);
3662 --sp;
3663 memcpy(frame->retval->data.p, sp->data.p, i32);
3664 if (sp > frame->stack)
3665 g_warning ("ret.vt: more values on stack: %d", sp-frame->stack);
3666 goto exit_frame;
3668 MINT_IN_CASE(MINT_BR_S)
3669 ip += (short) *(ip + 1);
3670 MINT_IN_BREAK;
3671 MINT_IN_CASE(MINT_BR)
3672 ip += (gint32) READ32(ip + 1);
3673 MINT_IN_BREAK;
3674 #define ZEROP_S(datamem, op) \
3675 --sp; \
3676 if (sp->data.datamem op 0) \
3677 ip += (gint16)ip [1]; \
3678 else \
3679 ip += 2;
3681 #define ZEROP(datamem, op) \
3682 --sp; \
3683 if (sp->data.datamem op 0) \
3684 ip += (gint32)READ32(ip + 1); \
3685 else \
3686 ip += 3;
3688 MINT_IN_CASE(MINT_BRFALSE_I4_S)
3689 ZEROP_S(i, ==);
3690 MINT_IN_BREAK;
3691 MINT_IN_CASE(MINT_BRFALSE_I8_S)
3692 ZEROP_S(l, ==);
3693 MINT_IN_BREAK;
3694 MINT_IN_CASE(MINT_BRFALSE_R4_S)
3695 ZEROP_S(f_r4, ==);
3696 MINT_IN_BREAK;
3697 MINT_IN_CASE(MINT_BRFALSE_R8_S)
3698 ZEROP_S(f, ==);
3699 MINT_IN_BREAK;
3700 MINT_IN_CASE(MINT_BRFALSE_I4)
3701 ZEROP(i, ==);
3702 MINT_IN_BREAK;
3703 MINT_IN_CASE(MINT_BRFALSE_I8)
3704 ZEROP(l, ==);
3705 MINT_IN_BREAK;
3706 MINT_IN_CASE(MINT_BRFALSE_R4)
3707 ZEROP_S(f_r4, ==);
3708 MINT_IN_BREAK;
3709 MINT_IN_CASE(MINT_BRFALSE_R8)
3710 ZEROP_S(f, ==);
3711 MINT_IN_BREAK;
3712 MINT_IN_CASE(MINT_BRTRUE_I4_S)
3713 ZEROP_S(i, !=);
3714 MINT_IN_BREAK;
3715 MINT_IN_CASE(MINT_BRTRUE_I8_S)
3716 ZEROP_S(l, !=);
3717 MINT_IN_BREAK;
3718 MINT_IN_CASE(MINT_BRTRUE_R4_S)
3719 ZEROP_S(f_r4, !=);
3720 MINT_IN_BREAK;
3721 MINT_IN_CASE(MINT_BRTRUE_R8_S)
3722 ZEROP_S(f, !=);
3723 MINT_IN_BREAK;
3724 MINT_IN_CASE(MINT_BRTRUE_I4)
3725 ZEROP(i, !=);
3726 MINT_IN_BREAK;
3727 MINT_IN_CASE(MINT_BRTRUE_I8)
3728 ZEROP(l, !=);
3729 MINT_IN_BREAK;
3730 MINT_IN_CASE(MINT_BRTRUE_R4)
3731 ZEROP(f_r4, !=);
3732 MINT_IN_BREAK;
3733 MINT_IN_CASE(MINT_BRTRUE_R8)
3734 ZEROP(f, !=);
3735 MINT_IN_BREAK;
3736 #define CONDBR_S(cond) \
3737 sp -= 2; \
3738 if (cond) \
3739 ip += (gint16)ip [1]; \
3740 else \
3741 ip += 2;
3742 #define BRELOP_S(datamem, op) \
3743 CONDBR_S(sp[0].data.datamem op sp[1].data.datamem)
3745 #define CONDBR(cond) \
3746 sp -= 2; \
3747 if (cond) \
3748 ip += (gint32)READ32(ip + 1); \
3749 else \
3750 ip += 3;
3752 #define BRELOP(datamem, op) \
3753 CONDBR(sp[0].data.datamem op sp[1].data.datamem)
3755 MINT_IN_CASE(MINT_BEQ_I4_S)
3756 BRELOP_S(i, ==)
3757 MINT_IN_BREAK;
3758 MINT_IN_CASE(MINT_BEQ_I8_S)
3759 BRELOP_S(l, ==)
3760 MINT_IN_BREAK;
3761 MINT_IN_CASE(MINT_BEQ_R4_S)
3762 CONDBR_S(!isunordered (sp [0].data.f_r4, sp [1].data.f_r4) && sp[0].data.f_r4 == sp[1].data.f_r4)
3763 MINT_IN_BREAK;
3764 MINT_IN_CASE(MINT_BEQ_R8_S)
3765 CONDBR_S(!mono_isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f == sp[1].data.f)
3766 MINT_IN_BREAK;
3767 MINT_IN_CASE(MINT_BEQ_I4)
3768 BRELOP(i, ==)
3769 MINT_IN_BREAK;
3770 MINT_IN_CASE(MINT_BEQ_I8)
3771 BRELOP(l, ==)
3772 MINT_IN_BREAK;
3773 MINT_IN_CASE(MINT_BEQ_R4)
3774 CONDBR(!isunordered (sp [0].data.f_r4, sp [1].data.f_r4) && sp[0].data.f_r4 == sp[1].data.f_r4)
3775 MINT_IN_BREAK;
3776 MINT_IN_CASE(MINT_BEQ_R8)
3777 CONDBR(!mono_isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f == sp[1].data.f)
3778 MINT_IN_BREAK;
3779 MINT_IN_CASE(MINT_BGE_I4_S)
3780 BRELOP_S(i, >=)
3781 MINT_IN_BREAK;
3782 MINT_IN_CASE(MINT_BGE_I8_S)
3783 BRELOP_S(l, >=)
3784 MINT_IN_BREAK;
3785 MINT_IN_CASE(MINT_BGE_R4_S)
3786 CONDBR_S(!isunordered (sp [0].data.f_r4, sp [1].data.f_r4) && sp[0].data.f_r4 >= sp[1].data.f_r4)
3787 MINT_IN_BREAK;
3788 MINT_IN_CASE(MINT_BGE_R8_S)
3789 CONDBR_S(!mono_isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f >= sp[1].data.f)
3790 MINT_IN_BREAK;
3791 MINT_IN_CASE(MINT_BGE_I4)
3792 BRELOP(i, >=)
3793 MINT_IN_BREAK;
3794 MINT_IN_CASE(MINT_BGE_I8)
3795 BRELOP(l, >=)
3796 MINT_IN_BREAK;
3797 MINT_IN_CASE(MINT_BGE_R4)
3798 CONDBR(!isunordered (sp [0].data.f_r4, sp [1].data.f_r4) && sp[0].data.f_r4 >= sp[1].data.f_r4)
3799 MINT_IN_BREAK;
3800 MINT_IN_CASE(MINT_BGE_R8)
3801 CONDBR(!mono_isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f >= sp[1].data.f)
3802 MINT_IN_BREAK;
3803 MINT_IN_CASE(MINT_BGT_I4_S)
3804 BRELOP_S(i, >)
3805 MINT_IN_BREAK;
3806 MINT_IN_CASE(MINT_BGT_I8_S)
3807 BRELOP_S(l, >)
3808 MINT_IN_BREAK;
3809 MINT_IN_CASE(MINT_BGT_R4_S)
3810 CONDBR_S(!isunordered (sp [0].data.f_r4, sp [1].data.f_r4) && sp[0].data.f_r4 > sp[1].data.f_r4)
3811 MINT_IN_BREAK;
3812 MINT_IN_CASE(MINT_BGT_R8_S)
3813 CONDBR_S(!mono_isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f > sp[1].data.f)
3814 MINT_IN_BREAK;
3815 MINT_IN_CASE(MINT_BGT_I4)
3816 BRELOP(i, >)
3817 MINT_IN_BREAK;
3818 MINT_IN_CASE(MINT_BGT_I8)
3819 BRELOP(l, >)
3820 MINT_IN_BREAK;
3821 MINT_IN_CASE(MINT_BGT_R4)
3822 CONDBR(!isunordered (sp [0].data.f_r4, sp [1].data.f_r4) && sp[0].data.f_r4 > sp[1].data.f_r4)
3823 MINT_IN_BREAK;
3824 MINT_IN_CASE(MINT_BGT_R8)
3825 CONDBR(!mono_isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f > sp[1].data.f)
3826 MINT_IN_BREAK;
3827 MINT_IN_CASE(MINT_BLT_I4_S)
3828 BRELOP_S(i, <)
3829 MINT_IN_BREAK;
3830 MINT_IN_CASE(MINT_BLT_I8_S)
3831 BRELOP_S(l, <)
3832 MINT_IN_BREAK;
3833 MINT_IN_CASE(MINT_BLT_R4_S)
3834 CONDBR_S(!isunordered (sp [0].data.f_r4, sp [1].data.f_r4) && sp[0].data.f_r4 < sp[1].data.f_r4)
3835 MINT_IN_BREAK;
3836 MINT_IN_CASE(MINT_BLT_R8_S)
3837 CONDBR_S(!mono_isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f < sp[1].data.f)
3838 MINT_IN_BREAK;
3839 MINT_IN_CASE(MINT_BLT_I4)
3840 BRELOP(i, <)
3841 MINT_IN_BREAK;
3842 MINT_IN_CASE(MINT_BLT_I8)
3843 BRELOP(l, <)
3844 MINT_IN_BREAK;
3845 MINT_IN_CASE(MINT_BLT_R4)
3846 CONDBR(!isunordered (sp [0].data.f_r4, sp [1].data.f_r4) && sp[0].data.f_r4 < sp[1].data.f_r4)
3847 MINT_IN_BREAK;
3848 MINT_IN_CASE(MINT_BLT_R8)
3849 CONDBR(!mono_isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f < sp[1].data.f)
3850 MINT_IN_BREAK;
3851 MINT_IN_CASE(MINT_BLE_I4_S)
3852 BRELOP_S(i, <=)
3853 MINT_IN_BREAK;
3854 MINT_IN_CASE(MINT_BLE_I8_S)
3855 BRELOP_S(l, <=)
3856 MINT_IN_BREAK;
3857 MINT_IN_CASE(MINT_BLE_R4_S)
3858 CONDBR_S(!isunordered (sp [0].data.f_r4, sp [1].data.f_r4) && sp[0].data.f_r4 <= sp[1].data.f_r4)
3859 MINT_IN_BREAK;
3860 MINT_IN_CASE(MINT_BLE_R8_S)
3861 CONDBR_S(!mono_isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f <= sp[1].data.f)
3862 MINT_IN_BREAK;
3863 MINT_IN_CASE(MINT_BLE_I4)
3864 BRELOP(i, <=)
3865 MINT_IN_BREAK;
3866 MINT_IN_CASE(MINT_BLE_I8)
3867 BRELOP(l, <=)
3868 MINT_IN_BREAK;
3869 MINT_IN_CASE(MINT_BLE_R4)
3870 CONDBR(!isunordered (sp [0].data.f_r4, sp [1].data.f_r4) && sp[0].data.f_r4 <= sp[1].data.f_r4)
3871 MINT_IN_BREAK;
3872 MINT_IN_CASE(MINT_BLE_R8)
3873 CONDBR(!mono_isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f <= sp[1].data.f)
3874 MINT_IN_BREAK;
3875 MINT_IN_CASE(MINT_BNE_UN_I4_S)
3876 BRELOP_S(i, !=)
3877 MINT_IN_BREAK;
3878 MINT_IN_CASE(MINT_BNE_UN_I8_S)
3879 BRELOP_S(l, !=)
3880 MINT_IN_BREAK;
3881 MINT_IN_CASE(MINT_BNE_UN_R4_S)
3882 CONDBR_S(isunordered (sp [0].data.f_r4, sp [1].data.f_r4) || sp[0].data.f_r4 != sp[1].data.f_r4)
3883 MINT_IN_BREAK;
3884 MINT_IN_CASE(MINT_BNE_UN_R8_S)
3885 CONDBR_S(mono_isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f != sp[1].data.f)
3886 MINT_IN_BREAK;
3887 MINT_IN_CASE(MINT_BNE_UN_I4)
3888 BRELOP(i, !=)
3889 MINT_IN_BREAK;
3890 MINT_IN_CASE(MINT_BNE_UN_I8)
3891 BRELOP(l, !=)
3892 MINT_IN_BREAK;
3893 MINT_IN_CASE(MINT_BNE_UN_R4)
3894 CONDBR(isunordered (sp [0].data.f_r4, sp [1].data.f_r4) || sp[0].data.f_r4 != sp[1].data.f_r4)
3895 MINT_IN_BREAK;
3896 MINT_IN_CASE(MINT_BNE_UN_R8)
3897 CONDBR(mono_isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f != sp[1].data.f)
3898 MINT_IN_BREAK;
3900 #define BRELOP_S_CAST(datamem, op, type) \
3901 sp -= 2; \
3902 if ((type) sp[0].data.datamem op (type) sp[1].data.datamem) \
3903 ip += (gint16)ip [1]; \
3904 else \
3905 ip += 2;
3907 #define BRELOP_CAST(datamem, op, type) \
3908 sp -= 2; \
3909 if ((type) sp[0].data.datamem op (type) sp[1].data.datamem) \
3910 ip += (gint32)READ32(ip + 1); \
3911 else \
3912 ip += 3;
3914 MINT_IN_CASE(MINT_BGE_UN_I4_S)
3915 BRELOP_S_CAST(i, >=, guint32);
3916 MINT_IN_BREAK;
3917 MINT_IN_CASE(MINT_BGE_UN_I8_S)
3918 BRELOP_S_CAST(l, >=, guint64);
3919 MINT_IN_BREAK;
3920 MINT_IN_CASE(MINT_BGE_UN_R4_S)
3921 CONDBR_S(isunordered (sp [0].data.f_r4, sp [1].data.f_r4) || sp[0].data.f_r4 >= sp[1].data.f_r4)
3922 MINT_IN_BREAK;
3923 MINT_IN_CASE(MINT_BGE_UN_R8_S)
3924 CONDBR_S(mono_isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f >= sp[1].data.f)
3925 MINT_IN_BREAK;
3926 MINT_IN_CASE(MINT_BGE_UN_I4)
3927 BRELOP_CAST(i, >=, guint32);
3928 MINT_IN_BREAK;
3929 MINT_IN_CASE(MINT_BGE_UN_I8)
3930 BRELOP_CAST(l, >=, guint64);
3931 MINT_IN_BREAK;
3932 MINT_IN_CASE(MINT_BGE_UN_R4)
3933 CONDBR(isunordered (sp [0].data.f_r4, sp [1].data.f_r4) || sp[0].data.f_r4 >= sp[1].data.f_r4)
3934 MINT_IN_BREAK;
3935 MINT_IN_CASE(MINT_BGE_UN_R8)
3936 CONDBR(mono_isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f >= sp[1].data.f)
3937 MINT_IN_BREAK;
3938 MINT_IN_CASE(MINT_BGT_UN_I4_S)
3939 BRELOP_S_CAST(i, >, guint32);
3940 MINT_IN_BREAK;
3941 MINT_IN_CASE(MINT_BGT_UN_I8_S)
3942 BRELOP_S_CAST(l, >, guint64);
3943 MINT_IN_BREAK;
3944 MINT_IN_CASE(MINT_BGT_UN_R4_S)
3945 CONDBR_S(isunordered (sp [0].data.f_r4, sp [1].data.f_r4) || sp[0].data.f_r4 > sp[1].data.f_r4)
3946 MINT_IN_BREAK;
3947 MINT_IN_CASE(MINT_BGT_UN_R8_S)
3948 CONDBR_S(mono_isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f > sp[1].data.f)
3949 MINT_IN_BREAK;
3950 MINT_IN_CASE(MINT_BGT_UN_I4)
3951 BRELOP_CAST(i, >, guint32);
3952 MINT_IN_BREAK;
3953 MINT_IN_CASE(MINT_BGT_UN_I8)
3954 BRELOP_CAST(l, >, guint64);
3955 MINT_IN_BREAK;
3956 MINT_IN_CASE(MINT_BGT_UN_R4)
3957 CONDBR(isunordered (sp [0].data.f_r4, sp [1].data.f_r4) || sp[0].data.f_r4 > sp[1].data.f_r4)
3958 MINT_IN_BREAK;
3959 MINT_IN_CASE(MINT_BGT_UN_R8)
3960 CONDBR(mono_isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f > sp[1].data.f)
3961 MINT_IN_BREAK;
3962 MINT_IN_CASE(MINT_BLE_UN_I4_S)
3963 BRELOP_S_CAST(i, <=, guint32);
3964 MINT_IN_BREAK;
3965 MINT_IN_CASE(MINT_BLE_UN_I8_S)
3966 BRELOP_S_CAST(l, <=, guint64);
3967 MINT_IN_BREAK;
3968 MINT_IN_CASE(MINT_BLE_UN_R4_S)
3969 CONDBR_S(isunordered (sp [0].data.f_r4, sp [1].data.f_r4) || sp[0].data.f_r4 <= sp[1].data.f_r4)
3970 MINT_IN_BREAK;
3971 MINT_IN_CASE(MINT_BLE_UN_R8_S)
3972 CONDBR_S(mono_isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f <= sp[1].data.f)
3973 MINT_IN_BREAK;
3974 MINT_IN_CASE(MINT_BLE_UN_I4)
3975 BRELOP_CAST(i, <=, guint32);
3976 MINT_IN_BREAK;
3977 MINT_IN_CASE(MINT_BLE_UN_I8)
3978 BRELOP_CAST(l, <=, guint64);
3979 MINT_IN_BREAK;
3980 MINT_IN_CASE(MINT_BLE_UN_R4)
3981 CONDBR(isunordered (sp [0].data.f_r4, sp [1].data.f_r4) || sp[0].data.f_r4 <= sp[1].data.f_r4)
3982 MINT_IN_BREAK;
3983 MINT_IN_CASE(MINT_BLE_UN_R8)
3984 CONDBR(mono_isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f <= sp[1].data.f)
3985 MINT_IN_BREAK;
3986 MINT_IN_CASE(MINT_BLT_UN_I4_S)
3987 BRELOP_S_CAST(i, <, guint32);
3988 MINT_IN_BREAK;
3989 MINT_IN_CASE(MINT_BLT_UN_I8_S)
3990 BRELOP_S_CAST(l, <, guint64);
3991 MINT_IN_BREAK;
3992 MINT_IN_CASE(MINT_BLT_UN_R4_S)
3993 CONDBR_S(isunordered (sp [0].data.f_r4, sp [1].data.f_r4) || sp[0].data.f_r4 < sp[1].data.f_r4)
3994 MINT_IN_BREAK;
3995 MINT_IN_CASE(MINT_BLT_UN_R8_S)
3996 CONDBR_S(mono_isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f < sp[1].data.f)
3997 MINT_IN_BREAK;
3998 MINT_IN_CASE(MINT_BLT_UN_I4)
3999 BRELOP_CAST(i, <, guint32);
4000 MINT_IN_BREAK;
4001 MINT_IN_CASE(MINT_BLT_UN_I8)
4002 BRELOP_CAST(l, <, guint64);
4003 MINT_IN_BREAK;
4004 MINT_IN_CASE(MINT_BLT_UN_R4)
4005 CONDBR(isunordered (sp [0].data.f_r4, sp [1].data.f_r4) || sp[0].data.f_r4 < sp[1].data.f_r4)
4006 MINT_IN_BREAK;
4007 MINT_IN_CASE(MINT_BLT_UN_R8)
4008 CONDBR(mono_isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f < sp[1].data.f)
4009 MINT_IN_BREAK;
4010 MINT_IN_CASE(MINT_SWITCH) {
4011 guint32 n;
4012 const unsigned short *st;
4013 ++ip;
4014 n = READ32 (ip);
4015 ip += 2;
4016 st = ip + 2 * n;
4017 --sp;
4018 if ((guint32)sp->data.i < n) {
4019 gint offset;
4020 ip += 2 * (guint32)sp->data.i;
4021 offset = READ32 (ip);
4022 ip = ip + offset;
4023 } else {
4024 ip = st;
4026 MINT_IN_BREAK;
4028 MINT_IN_CASE(MINT_LDIND_I1_CHECK)
4029 NULL_CHECK (sp [-1].data.p);
4030 ++ip;
4031 sp[-1].data.i = *(gint8*)sp[-1].data.p;
4032 MINT_IN_BREAK;
4033 MINT_IN_CASE(MINT_LDIND_U1_CHECK)
4034 NULL_CHECK (sp [-1].data.p);
4035 ++ip;
4036 sp[-1].data.i = *(guint8*)sp[-1].data.p;
4037 MINT_IN_BREAK;
4038 MINT_IN_CASE(MINT_LDIND_I2_CHECK)
4039 NULL_CHECK (sp [-1].data.p);
4040 ++ip;
4041 sp[-1].data.i = *(gint16*)sp[-1].data.p;
4042 MINT_IN_BREAK;
4043 MINT_IN_CASE(MINT_LDIND_U2_CHECK)
4044 NULL_CHECK (sp [-1].data.p);
4045 ++ip;
4046 sp[-1].data.i = *(guint16*)sp[-1].data.p;
4047 MINT_IN_BREAK;
4048 MINT_IN_CASE(MINT_LDIND_I4_CHECK) /* Fall through */
4049 MINT_IN_CASE(MINT_LDIND_U4_CHECK)
4050 NULL_CHECK (sp [-1].data.p);
4051 ++ip;
4052 sp[-1].data.i = *(gint32*)sp[-1].data.p;
4053 MINT_IN_BREAK;
4054 MINT_IN_CASE(MINT_LDIND_I8_CHECK)
4055 NULL_CHECK (sp [-1].data.p);
4056 ++ip;
4057 #ifdef NO_UNALIGNED_ACCESS
4058 if ((gsize)sp [-1].data.p % SIZEOF_VOID_P)
4059 memcpy (&sp [-1].data.l, sp [-1].data.p, sizeof (gint64));
4060 else
4061 #endif
4062 sp[-1].data.l = *(gint64*)sp[-1].data.p;
4063 MINT_IN_BREAK;
4064 MINT_IN_CASE(MINT_LDIND_I) {
4065 guint16 offset = ip [1];
4066 sp[-1 - offset].data.p = *(gpointer*)sp[-1 - offset].data.p;
4067 ip += 2;
4068 MINT_IN_BREAK;
4070 MINT_IN_CASE(MINT_LDIND_I8) {
4071 guint16 offset = ip [1];
4072 #ifdef NO_UNALIGNED_ACCESS
4073 if ((gsize)sp [-1 - offset].data.p % SIZEOF_VOID_P)
4074 memcpy (&sp [-1 - offset].data.l, sp [-1 - offset].data.p, sizeof (gint64));
4075 else
4076 #endif
4077 sp[-1 - offset].data.l = *(gint64*)sp[-1 - offset].data.p;
4078 ip += 2;
4079 MINT_IN_BREAK;
4081 MINT_IN_CASE(MINT_LDIND_R4_CHECK)
4082 NULL_CHECK (sp [-1].data.p);
4083 ++ip;
4084 sp[-1].data.f_r4 = *(gfloat*)sp[-1].data.p;
4085 MINT_IN_BREAK;
4086 MINT_IN_CASE(MINT_LDIND_R8_CHECK)
4087 NULL_CHECK (sp [-1].data.p);
4088 ++ip;
4089 #ifdef NO_UNALIGNED_ACCESS
4090 if ((gsize)sp [-1].data.p % SIZEOF_VOID_P)
4091 memcpy (&sp [-1].data.f, sp [-1].data.p, sizeof (gdouble));
4092 else
4093 #endif
4094 sp[-1].data.f = *(gdouble*)sp[-1].data.p;
4095 MINT_IN_BREAK;
4096 MINT_IN_CASE(MINT_LDIND_REF)
4097 ++ip;
4098 sp[-1].data.p = *(gpointer*)sp[-1].data.p;
4099 MINT_IN_BREAK;
4100 MINT_IN_CASE(MINT_LDIND_REF_CHECK) {
4101 NULL_CHECK (sp [-1].data.p);
4102 ++ip;
4103 sp [-1].data.p = *(gpointer*)sp [-1].data.p;
4104 MINT_IN_BREAK;
4106 MINT_IN_CASE(MINT_STIND_REF)
4107 ++ip;
4108 sp -= 2;
4109 mono_gc_wbarrier_generic_store_internal (sp->data.p, sp [1].data.o);
4110 MINT_IN_BREAK;
4111 MINT_IN_CASE(MINT_STIND_I1)
4112 ++ip;
4113 sp -= 2;
4114 * (gint8 *) sp->data.p = (gint8)sp[1].data.i;
4115 MINT_IN_BREAK;
4116 MINT_IN_CASE(MINT_STIND_I2)
4117 ++ip;
4118 sp -= 2;
4119 * (gint16 *) sp->data.p = (gint16)sp[1].data.i;
4120 MINT_IN_BREAK;
4121 MINT_IN_CASE(MINT_STIND_I4)
4122 ++ip;
4123 sp -= 2;
4124 * (gint32 *) sp->data.p = sp[1].data.i;
4125 MINT_IN_BREAK;
4126 MINT_IN_CASE(MINT_STIND_I)
4127 ++ip;
4128 sp -= 2;
4129 * (mono_i *) sp->data.p = (mono_i)sp[1].data.p;
4130 MINT_IN_BREAK;
4131 MINT_IN_CASE(MINT_STIND_I8)
4132 ++ip;
4133 sp -= 2;
4134 #ifdef NO_UNALIGNED_ACCESS
4135 if ((gsize)sp->data.p % SIZEOF_VOID_P)
4136 memcpy (sp->data.p, &sp [1].data.l, sizeof (gint64));
4137 else
4138 #endif
4139 * (gint64 *) sp->data.p = sp[1].data.l;
4140 MINT_IN_BREAK;
4141 MINT_IN_CASE(MINT_STIND_R4)
4142 ++ip;
4143 sp -= 2;
4144 * (float *) sp->data.p = sp[1].data.f_r4;
4145 MINT_IN_BREAK;
4146 MINT_IN_CASE(MINT_STIND_R8)
4147 ++ip;
4148 sp -= 2;
4149 #ifdef NO_UNALIGNED_ACCESS
4150 if ((gsize)sp->data.p % SIZEOF_VOID_P)
4151 memcpy (sp->data.p, &sp [1].data.f, sizeof (double));
4152 else
4153 #endif
4154 * (double *) sp->data.p = sp[1].data.f;
4155 MINT_IN_BREAK;
4156 MINT_IN_CASE(MINT_MONO_ATOMIC_STORE_I4)
4157 ++ip;
4158 sp -= 2;
4159 mono_atomic_store_i32 ((gint32 *) sp->data.p, sp [1].data.i);
4160 MINT_IN_BREAK;
4161 #define BINOP(datamem, op) \
4162 --sp; \
4163 sp [-1].data.datamem = sp [-1].data.datamem op sp [0].data.datamem; \
4164 ++ip;
4165 MINT_IN_CASE(MINT_ADD_I4)
4166 BINOP(i, +);
4167 MINT_IN_BREAK;
4168 MINT_IN_CASE(MINT_ADD_I8)
4169 BINOP(l, +);
4170 MINT_IN_BREAK;
4171 MINT_IN_CASE(MINT_ADD_R4)
4172 BINOP(f_r4, +);
4173 MINT_IN_BREAK;
4174 MINT_IN_CASE(MINT_ADD_R8)
4175 BINOP(f, +);
4176 MINT_IN_BREAK;
4177 MINT_IN_CASE(MINT_ADD1_I4)
4178 ++sp [-1].data.i;
4179 ++ip;
4180 MINT_IN_BREAK;
4181 MINT_IN_CASE(MINT_ADD1_I8)
4182 ++sp [-1].data.l;
4183 ++ip;
4184 MINT_IN_BREAK;
4185 MINT_IN_CASE(MINT_SUB_I4)
4186 BINOP(i, -);
4187 MINT_IN_BREAK;
4188 MINT_IN_CASE(MINT_SUB_I8)
4189 BINOP(l, -);
4190 MINT_IN_BREAK;
4191 MINT_IN_CASE(MINT_SUB_R4)
4192 BINOP(f_r4, -);
4193 MINT_IN_BREAK;
4194 MINT_IN_CASE(MINT_SUB_R8)
4195 BINOP(f, -);
4196 MINT_IN_BREAK;
4197 MINT_IN_CASE(MINT_SUB1_I4)
4198 --sp [-1].data.i;
4199 ++ip;
4200 MINT_IN_BREAK;
4201 MINT_IN_CASE(MINT_SUB1_I8)
4202 --sp [-1].data.l;
4203 ++ip;
4204 MINT_IN_BREAK;
4205 MINT_IN_CASE(MINT_MUL_I4)
4206 BINOP(i, *);
4207 MINT_IN_BREAK;
4208 MINT_IN_CASE(MINT_MUL_I8)
4209 BINOP(l, *);
4210 MINT_IN_BREAK;
4211 MINT_IN_CASE(MINT_MUL_R4)
4212 BINOP(f_r4, *);
4213 MINT_IN_BREAK;
4214 MINT_IN_CASE(MINT_MUL_R8)
4215 BINOP(f, *);
4216 MINT_IN_BREAK;
4217 MINT_IN_CASE(MINT_DIV_I4)
4218 if (sp [-1].data.i == 0)
4219 goto div_zero_label;
4220 if (sp [-1].data.i == (-1) && sp [-2].data.i == G_MININT32)
4221 goto overflow_label;
4222 BINOP(i, /);
4223 MINT_IN_BREAK;
4224 MINT_IN_CASE(MINT_DIV_I8)
4225 if (sp [-1].data.l == 0)
4226 goto div_zero_label;
4227 if (sp [-1].data.l == (-1) && sp [-2].data.l == G_MININT64)
4228 goto overflow_label;
4229 BINOP(l, /);
4230 MINT_IN_BREAK;
4231 MINT_IN_CASE(MINT_DIV_R4)
4232 BINOP(f_r4, /);
4233 MINT_IN_BREAK;
4234 MINT_IN_CASE(MINT_DIV_R8)
4235 BINOP(f, /);
4236 MINT_IN_BREAK;
4238 #define BINOP_CAST(datamem, op, type) \
4239 --sp; \
4240 sp [-1].data.datamem = (type)sp [-1].data.datamem op (type)sp [0].data.datamem; \
4241 ++ip;
4242 MINT_IN_CASE(MINT_DIV_UN_I4)
4243 if (sp [-1].data.i == 0)
4244 goto div_zero_label;
4245 BINOP_CAST(i, /, guint32);
4246 MINT_IN_BREAK;
4247 MINT_IN_CASE(MINT_DIV_UN_I8)
4248 if (sp [-1].data.l == 0)
4249 goto div_zero_label;
4250 BINOP_CAST(l, /, guint64);
4251 MINT_IN_BREAK;
4252 MINT_IN_CASE(MINT_REM_I4)
4253 if (sp [-1].data.i == 0)
4254 goto div_zero_label;
4255 if (sp [-1].data.i == (-1) && sp [-2].data.i == G_MININT32)
4256 goto overflow_label;
4257 BINOP(i, %);
4258 MINT_IN_BREAK;
4259 MINT_IN_CASE(MINT_REM_I8)
4260 if (sp [-1].data.l == 0)
4261 goto div_zero_label;
4262 if (sp [-1].data.l == (-1) && sp [-2].data.l == G_MININT64)
4263 goto overflow_label;
4264 BINOP(l, %);
4265 MINT_IN_BREAK;
4266 MINT_IN_CASE(MINT_REM_R4)
4267 /* FIXME: what do we actually do here? */
4268 --sp;
4269 sp [-1].data.f_r4 = fmodf (sp [-1].data.f_r4, sp [0].data.f_r4);
4270 ++ip;
4271 MINT_IN_BREAK;
4272 MINT_IN_CASE(MINT_REM_R8)
4273 /* FIXME: what do we actually do here? */
4274 --sp;
4275 sp [-1].data.f = fmod (sp [-1].data.f, sp [0].data.f);
4276 ++ip;
4277 MINT_IN_BREAK;
4278 MINT_IN_CASE(MINT_REM_UN_I4)
4279 if (sp [-1].data.i == 0)
4280 goto div_zero_label;
4281 BINOP_CAST(i, %, guint32);
4282 MINT_IN_BREAK;
4283 MINT_IN_CASE(MINT_REM_UN_I8)
4284 if (sp [-1].data.l == 0)
4285 goto div_zero_label;
4286 BINOP_CAST(l, %, guint64);
4287 MINT_IN_BREAK;
4288 MINT_IN_CASE(MINT_AND_I4)
4289 BINOP(i, &);
4290 MINT_IN_BREAK;
4291 MINT_IN_CASE(MINT_AND_I8)
4292 BINOP(l, &);
4293 MINT_IN_BREAK;
4294 MINT_IN_CASE(MINT_OR_I4)
4295 BINOP(i, |);
4296 MINT_IN_BREAK;
4297 MINT_IN_CASE(MINT_OR_I8)
4298 BINOP(l, |);
4299 MINT_IN_BREAK;
4300 MINT_IN_CASE(MINT_XOR_I4)
4301 BINOP(i, ^);
4302 MINT_IN_BREAK;
4303 MINT_IN_CASE(MINT_XOR_I8)
4304 BINOP(l, ^);
4305 MINT_IN_BREAK;
4307 #define SHIFTOP(datamem, op) \
4308 --sp; \
4309 sp [-1].data.datamem = sp [-1].data.datamem op sp [0].data.i; \
4310 ++ip;
4312 MINT_IN_CASE(MINT_SHL_I4)
4313 SHIFTOP(i, <<);
4314 MINT_IN_BREAK;
4315 MINT_IN_CASE(MINT_SHL_I8)
4316 SHIFTOP(l, <<);
4317 MINT_IN_BREAK;
4318 MINT_IN_CASE(MINT_SHR_I4)
4319 SHIFTOP(i, >>);
4320 MINT_IN_BREAK;
4321 MINT_IN_CASE(MINT_SHR_I8)
4322 SHIFTOP(l, >>);
4323 MINT_IN_BREAK;
4324 MINT_IN_CASE(MINT_SHR_UN_I4)
4325 --sp;
4326 sp [-1].data.i = (guint32)sp [-1].data.i >> sp [0].data.i;
4327 ++ip;
4328 MINT_IN_BREAK;
4329 MINT_IN_CASE(MINT_SHR_UN_I8)
4330 --sp;
4331 sp [-1].data.l = (guint64)sp [-1].data.l >> sp [0].data.i;
4332 ++ip;
4333 MINT_IN_BREAK;
4334 MINT_IN_CASE(MINT_NEG_I4)
4335 sp [-1].data.i = - sp [-1].data.i;
4336 ++ip;
4337 MINT_IN_BREAK;
4338 MINT_IN_CASE(MINT_NEG_I8)
4339 sp [-1].data.l = - sp [-1].data.l;
4340 ++ip;
4341 MINT_IN_BREAK;
4342 MINT_IN_CASE(MINT_NEG_R4)
4343 sp [-1].data.f_r4 = - sp [-1].data.f_r4;
4344 ++ip;
4345 MINT_IN_BREAK;
4346 MINT_IN_CASE(MINT_NEG_R8)
4347 sp [-1].data.f = - sp [-1].data.f;
4348 ++ip;
4349 MINT_IN_BREAK;
4350 MINT_IN_CASE(MINT_NOT_I4)
4351 sp [-1].data.i = ~ sp [-1].data.i;
4352 ++ip;
4353 MINT_IN_BREAK;
4354 MINT_IN_CASE(MINT_NOT_I8)
4355 sp [-1].data.l = ~ sp [-1].data.l;
4356 ++ip;
4357 MINT_IN_BREAK;
4358 MINT_IN_CASE(MINT_CONV_I1_I4)
4359 sp [-1].data.i = (gint8)sp [-1].data.i;
4360 ++ip;
4361 MINT_IN_BREAK;
4362 MINT_IN_CASE(MINT_CONV_I1_I8)
4363 sp [-1].data.i = (gint8)sp [-1].data.l;
4364 ++ip;
4365 MINT_IN_BREAK;
4366 MINT_IN_CASE(MINT_CONV_I1_R4)
4367 sp [-1].data.i = (gint8) (gint32) sp [-1].data.f_r4;
4368 ++ip;
4369 MINT_IN_BREAK;
4370 MINT_IN_CASE(MINT_CONV_I1_R8)
4371 /* without gint32 cast, C compiler is allowed to use undefined
4372 * behaviour if data.f is bigger than >255. See conv.fpint section
4373 * in C standard:
4374 * > The conversion truncates; that is, the fractional part
4375 * > is discarded. The behavior is undefined if the truncated
4376 * > value cannot be represented in the destination type.
4377 * */
4378 sp [-1].data.i = (gint8) (gint32) sp [-1].data.f;
4379 ++ip;
4380 MINT_IN_BREAK;
4381 MINT_IN_CASE(MINT_CONV_U1_I4)
4382 sp [-1].data.i = (guint8)sp [-1].data.i;
4383 ++ip;
4384 MINT_IN_BREAK;
4385 MINT_IN_CASE(MINT_CONV_U1_I8)
4386 sp [-1].data.i = (guint8)sp [-1].data.l;
4387 ++ip;
4388 MINT_IN_BREAK;
4389 MINT_IN_CASE(MINT_CONV_U1_R4)
4390 sp [-1].data.i = (guint8) (guint32) sp [-1].data.f_r4;
4391 ++ip;
4392 MINT_IN_BREAK;
4393 MINT_IN_CASE(MINT_CONV_U1_R8)
4394 sp [-1].data.i = (guint8) (guint32) sp [-1].data.f;
4395 ++ip;
4396 MINT_IN_BREAK;
4397 MINT_IN_CASE(MINT_CONV_I2_I4)
4398 sp [-1].data.i = (gint16)sp [-1].data.i;
4399 ++ip;
4400 MINT_IN_BREAK;
4401 MINT_IN_CASE(MINT_CONV_I2_I8)
4402 sp [-1].data.i = (gint16)sp [-1].data.l;
4403 ++ip;
4404 MINT_IN_BREAK;
4405 MINT_IN_CASE(MINT_CONV_I2_R4)
4406 sp [-1].data.i = (gint16) (gint32) sp [-1].data.f_r4;
4407 ++ip;
4408 MINT_IN_BREAK;
4409 MINT_IN_CASE(MINT_CONV_I2_R8)
4410 sp [-1].data.i = (gint16) (gint32) sp [-1].data.f;
4411 ++ip;
4412 MINT_IN_BREAK;
4413 MINT_IN_CASE(MINT_CONV_U2_I4)
4414 sp [-1].data.i = (guint16)sp [-1].data.i;
4415 ++ip;
4416 MINT_IN_BREAK;
4417 MINT_IN_CASE(MINT_CONV_U2_I8)
4418 sp [-1].data.i = (guint16)sp [-1].data.l;
4419 ++ip;
4420 MINT_IN_BREAK;
4421 MINT_IN_CASE(MINT_CONV_U2_R4)
4422 sp [-1].data.i = (guint16) (guint32) sp [-1].data.f_r4;
4423 ++ip;
4424 MINT_IN_BREAK;
4425 MINT_IN_CASE(MINT_CONV_U2_R8)
4426 sp [-1].data.i = (guint16) (guint32) sp [-1].data.f;
4427 ++ip;
4428 MINT_IN_BREAK;
4429 MINT_IN_CASE(MINT_CONV_I4_R4)
4430 sp [-1].data.i = (gint32) sp [-1].data.f_r4;
4431 ++ip;
4432 MINT_IN_BREAK;
4433 MINT_IN_CASE(MINT_CONV_I4_R8)
4434 sp [-1].data.i = (gint32)sp [-1].data.f;
4435 ++ip;
4436 MINT_IN_BREAK;
4437 MINT_IN_CASE(MINT_CONV_U4_I8)
4438 MINT_IN_CASE(MINT_CONV_I4_I8)
4439 sp [-1].data.i = (gint32)sp [-1].data.l;
4440 ++ip;
4441 MINT_IN_BREAK;
4442 MINT_IN_CASE(MINT_CONV_I4_I8_SP)
4443 sp [-2].data.i = (gint32)sp [-2].data.l;
4444 ++ip;
4445 MINT_IN_BREAK;
4446 MINT_IN_CASE(MINT_CONV_U4_R4)
4447 #ifdef MONO_ARCH_EMULATE_FCONV_TO_U4
4448 sp [-1].data.i = mono_rconv_u4 (sp [-1].data.f_r4);
4449 #else
4450 sp [-1].data.i = (guint32) sp [-1].data.f_r4;
4451 #endif
4452 ++ip;
4453 MINT_IN_BREAK;
4454 MINT_IN_CASE(MINT_CONV_U4_R8)
4455 #ifdef MONO_ARCH_EMULATE_FCONV_TO_U4
4456 sp [-1].data.i = mono_fconv_u4_2 (sp [-1].data.f);
4457 #else
4458 sp [-1].data.i = (guint32) sp [-1].data.f;
4459 #endif
4460 ++ip;
4461 MINT_IN_BREAK;
4462 MINT_IN_CASE(MINT_CONV_I8_I4)
4463 sp [-1].data.l = sp [-1].data.i;
4464 ++ip;
4465 MINT_IN_BREAK;
4466 MINT_IN_CASE(MINT_CONV_I8_I4_SP)
4467 sp [-2].data.l = sp [-2].data.i;
4468 ++ip;
4469 MINT_IN_BREAK;
4470 MINT_IN_CASE(MINT_CONV_I8_U4)
4471 sp [-1].data.l = (guint32)sp [-1].data.i;
4472 ++ip;
4473 MINT_IN_BREAK;
4474 MINT_IN_CASE(MINT_CONV_I8_R4)
4475 sp [-1].data.l = (gint64) sp [-1].data.f_r4;
4476 ++ip;
4477 MINT_IN_BREAK;
4478 MINT_IN_CASE(MINT_CONV_I8_R8)
4479 sp [-1].data.l = (gint64)sp [-1].data.f;
4480 ++ip;
4481 MINT_IN_BREAK;
4482 MINT_IN_CASE(MINT_CONV_R4_I4)
4483 sp [-1].data.f_r4 = (float)sp [-1].data.i;
4484 ++ip;
4485 MINT_IN_BREAK;
4486 MINT_IN_CASE(MINT_CONV_R4_I8)
4487 sp [-1].data.f_r4 = (float)sp [-1].data.l;
4488 ++ip;
4489 MINT_IN_BREAK;
4490 MINT_IN_CASE(MINT_CONV_R4_R8)
4491 sp [-1].data.f_r4 = (float)sp [-1].data.f;
4492 ++ip;
4493 MINT_IN_BREAK;
4494 MINT_IN_CASE(MINT_CONV_R8_I4)
4495 sp [-1].data.f = (double)sp [-1].data.i;
4496 ++ip;
4497 MINT_IN_BREAK;
4498 MINT_IN_CASE(MINT_CONV_R8_I8)
4499 sp [-1].data.f = (double)sp [-1].data.l;
4500 ++ip;
4501 MINT_IN_BREAK;
4502 MINT_IN_CASE(MINT_CONV_R8_R4)
4503 sp [-1].data.f = (double) sp [-1].data.f_r4;
4504 ++ip;
4505 MINT_IN_BREAK;
4506 MINT_IN_CASE(MINT_CONV_R8_R4_SP)
4507 sp [-2].data.f = (double) sp [-2].data.f_r4;
4508 ++ip;
4509 MINT_IN_BREAK;
4510 MINT_IN_CASE(MINT_CONV_U8_I4)
4511 sp [-1].data.l = sp [-1].data.i & 0xffffffff;
4512 ++ip;
4513 MINT_IN_BREAK;
4514 MINT_IN_CASE(MINT_CONV_U8_R4)
4515 #ifdef MONO_ARCH_EMULATE_FCONV_TO_U8
4516 sp [-1].data.l = mono_rconv_u8 (sp [-1].data.f_r4);
4517 #else
4518 sp [-1].data.l = (guint64) sp [-1].data.f_r4;
4519 #endif
4520 ++ip;
4521 MINT_IN_BREAK;
4522 MINT_IN_CASE(MINT_CONV_U8_R8)
4523 #ifdef MONO_ARCH_EMULATE_FCONV_TO_U8
4524 sp [-1].data.l = mono_fconv_u8_2 (sp [-1].data.f);
4525 #else
4526 sp [-1].data.l = (guint64)sp [-1].data.f;
4527 #endif
4528 ++ip;
4529 MINT_IN_BREAK;
4530 MINT_IN_CASE(MINT_CPOBJ) {
4531 MonoClass* const c = (MonoClass*)frame->imethod->data_items[ip [1]];
4532 g_assert (m_class_is_valuetype (c));
4533 /* if this assertion fails, we need to add a write barrier */
4534 g_assert (!MONO_TYPE_IS_REFERENCE (m_class_get_byval_arg (c)));
4535 stackval_from_data (m_class_get_byval_arg (c), (stackval*)sp [-2].data.p, sp [-1].data.p, FALSE);
4536 ip += 2;
4537 sp -= 2;
4538 MINT_IN_BREAK;
4540 MINT_IN_CASE(MINT_CPOBJ_VT) {
4541 MonoClass* const c = (MonoClass*)frame->imethod->data_items[ip [1]];
4542 mono_value_copy_internal (sp [-2].data.vt, sp [-1].data.vt, c);
4543 ip += 2;
4544 sp -= 2;
4545 MINT_IN_BREAK;
4547 MINT_IN_CASE(MINT_LDOBJ_VT) {
4548 int size = READ32(ip + 1);
4549 ip += 3;
4550 memcpy (vt_sp, sp [-1].data.p, size);
4551 sp [-1].data.p = vt_sp;
4552 vt_sp += ALIGN_TO (size, MINT_VT_ALIGNMENT);
4553 MINT_IN_BREAK;
4555 MINT_IN_CASE(MINT_LDSTR)
4556 sp->data.p = frame->imethod->data_items [ip [1]];
4557 ++sp;
4558 ip += 2;
4559 MINT_IN_BREAK;
4560 MINT_IN_CASE(MINT_LDSTR_TOKEN) {
4561 MonoString *s = NULL;
4562 guint32 strtoken = (guint32)(gsize)frame->imethod->data_items [ip [1]];
4564 MonoMethod *method = frame->imethod->method;
4565 if (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD) {
4566 s = (MonoString*)mono_method_get_wrapper_data (method, strtoken);
4567 } else if (method->wrapper_type != MONO_WRAPPER_NONE) {
4568 s = mono_string_new_wrapper_internal ((const char*)mono_method_get_wrapper_data (method, strtoken));
4569 } else {
4570 g_assert_not_reached ();
4572 sp->data.p = s;
4573 ++sp;
4574 ip += 2;
4575 MINT_IN_BREAK;
4577 MINT_IN_CASE(MINT_NEWOBJ_ARRAY) {
4578 MonoClass *newobj_class;
4579 guint32 token = ip [1];
4580 guint16 param_count = ip [2];
4582 newobj_class = (MonoClass*) frame->imethod->data_items [token];
4584 sp -= param_count;
4585 sp->data.o = ves_array_create (frame->imethod->domain, newobj_class, param_count, sp, error);
4586 if (!is_ok (error))
4587 goto throw_error_label;
4589 ++sp;
4590 ip += 3;
4591 MINT_IN_BREAK;
4593 MINT_IN_CASE(MINT_NEWOBJ_FAST) {
4595 MonoVTable *vtable = (MonoVTable*) frame->imethod->data_items [ip [3]];
4596 INIT_VTABLE (vtable);
4597 MonoObject *o; // See the comment about GC safety.
4598 guint16 param_count;
4599 guint16 imethod_index = ip [1];
4601 const gboolean is_inlined = imethod_index == 0xffff;
4603 param_count = ip [2];
4605 if (param_count) {
4606 sp -= param_count;
4607 memmove (sp + 1 + is_inlined, sp, param_count * sizeof (stackval));
4610 OBJREF (o) = mono_gc_alloc_obj (vtable, m_class_get_instance_size (vtable->klass));
4611 if (G_UNLIKELY (!o)) {
4612 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", m_class_get_instance_size (vtable->klass));
4613 goto throw_error_label;
4616 sp [0].data.o = o;
4617 if (is_inlined) {
4618 sp [1].data.o = o;
4619 sp += param_count + 2;
4620 } else {
4621 InterpMethod *ctor_method = (InterpMethod*) frame->imethod->data_items [imethod_index];
4622 frame->ip = ip;
4624 child_frame.imethod = ctor_method;
4625 child_frame.stack_args = sp;
4627 interp_exec_method (&child_frame, context, error);
4628 CHECK_RESUME_STATE (context);
4629 sp [0].data.o = o;
4630 sp++;
4632 ip += 4;
4634 MINT_IN_BREAK;
4636 MINT_IN_CASE(MINT_NEWOBJ_VT_FAST)
4637 MINT_IN_CASE(MINT_NEWOBJ_VTST_FAST) {
4639 // This is split up to:
4640 // - conserve stack
4641 // - keep exception handling and resume mostly in the main function
4643 frame->ip = ip;
4644 child_frame.imethod = (InterpMethod*) frame->imethod->data_items [ip [1]];
4645 guint16 const param_count = ip [2];
4647 if (param_count) {
4648 sp -= param_count;
4649 memmove (sp + 1, sp, param_count * sizeof (stackval));
4651 child_frame.stack_args = sp;
4652 gboolean const vtst = *ip == MINT_NEWOBJ_VTST_FAST;
4653 if (vtst) {
4654 memset (vt_sp, 0, ip [3]);
4655 sp->data.p = vt_sp;
4656 ip += 4;
4658 interp_exec_method (&child_frame, context, error);
4660 CHECK_RESUME_STATE (context);
4661 sp->data.p = vt_sp;
4663 } else {
4664 ip += 3;
4665 mono_interp_newobj_vt (&child_frame, context, error);
4666 CHECK_RESUME_STATE (context);
4668 ++sp;
4669 MINT_IN_BREAK;
4672 MINT_IN_CASE(MINT_NEWOBJ) {
4674 // This is split up to:
4675 // - conserve stack
4676 // - keep exception handling and resume mostly in the main function
4678 frame->ip = ip;
4680 guint32 const token = ip [1];
4681 ip += 2; // FIXME: Do this after throw?
4683 child_frame.ip = NULL;
4685 child_frame.imethod = (InterpMethod*)frame->imethod->data_items [token];
4686 MonoMethodSignature* const csig = mono_method_signature_internal (child_frame.imethod->method);
4688 g_assert (csig->hasthis);
4689 if (csig->param_count) {
4690 sp -= csig->param_count;
4691 memmove (sp + 1, sp, csig->param_count * sizeof (stackval));
4694 child_frame.stack_args = sp;
4696 MonoException* const exc = mono_interp_newobj (&child_frame, context, error, vt_sp);
4697 if (exc)
4698 THROW_EX (exc, ip);
4699 CHECK_RESUME_STATE (context);
4700 ++sp;
4701 MINT_IN_BREAK;
4703 MINT_IN_CASE(MINT_NEWOBJ_MAGIC) {
4704 frame->ip = ip;
4705 ip += 2;
4707 MINT_IN_BREAK;
4709 MINT_IN_CASE(MINT_INTRINS_BYREFERENCE_CTOR) {
4710 MonoMethodSignature *csig;
4711 guint32 token;
4713 frame->ip = ip;
4714 token = ip [1];
4715 ip += 2;
4717 InterpMethod *cmethod = (InterpMethod*)frame->imethod->data_items [token];
4718 csig = mono_method_signature_internal (cmethod->method);
4720 g_assert (csig->hasthis);
4721 sp -= csig->param_count;
4723 gpointer arg0 = sp [0].data.p;
4725 gpointer *byreference_this = (gpointer*)vt_sp;
4726 *byreference_this = arg0;
4728 /* Followed by a VTRESULT opcode which will push the result on the stack */
4729 ++sp;
4730 MINT_IN_BREAK;
4732 MINT_IN_CASE(MINT_INTRINS_BYREFERENCE_GET_VALUE) {
4733 gpointer *byreference_this = (gpointer*)sp [-1].data.p;
4734 sp [-1].data.p = *byreference_this;
4735 ++ip;
4736 MINT_IN_BREAK;
4738 MINT_IN_CASE(MINT_INTRINS_UNSAFE_ADD_BYTE_OFFSET) {
4739 sp -= 2;
4740 sp [0].data.p = (guint8*)sp [0].data.p + sp [1].data.nati;
4741 sp ++;
4742 ++ip;
4743 MINT_IN_BREAK;
4745 MINT_IN_CASE(MINT_INTRINS_UNSAFE_BYTE_OFFSET) {
4746 sp -= 2;
4747 sp [0].data.nati = (guint8*)sp [1].data.p - (guint8*)sp [0].data.p;
4748 sp ++;
4749 ++ip;
4750 MINT_IN_BREAK;
4752 MINT_IN_CASE(MINT_INTRINS_RUNTIMEHELPERS_OBJECT_HAS_COMPONENT_SIZE) {
4753 MonoObject *obj = sp [-1].data.o;
4754 sp [-1].data.i = (obj->vtable->flags & MONO_VT_FLAG_ARRAY_OR_STRING) != 0;
4755 ++ip;
4756 MINT_IN_BREAK;
4758 MINT_IN_CASE(MINT_CASTCLASS_INTERFACE)
4759 MINT_IN_CASE(MINT_ISINST_INTERFACE) {
4760 MonoObject* const o = sp [-1].data.o;
4761 if (o) {
4762 MonoClass* const c = (MonoClass*)frame->imethod->data_items [ip [1]];
4763 gboolean isinst;
4764 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (o->vtable, m_class_get_interface_id (c))) {
4765 isinst = TRUE;
4766 } else if (m_class_is_array_special_interface (c) || mono_object_is_transparent_proxy (o)) {
4767 /* slow path */
4768 isinst = mono_interp_isinst (o, c); // FIXME: do not swallow the error
4769 } else {
4770 isinst = FALSE;
4773 if (!isinst) {
4774 gboolean const isinst_instr = *ip == MINT_ISINST_INTERFACE;
4775 if (isinst_instr)
4776 sp [-1].data.p = NULL;
4777 else
4778 goto invalid_cast_label;
4781 ip += 2;
4782 MINT_IN_BREAK;
4784 MINT_IN_CASE(MINT_CASTCLASS_COMMON)
4785 MINT_IN_CASE(MINT_ISINST_COMMON) {
4786 MonoObject* const o = sp [-1].data.o;
4787 if (o) {
4788 MonoClass* const c = (MonoClass*)frame->imethod->data_items [ip [1]];
4789 gboolean isinst = mono_class_has_parent_fast (o->vtable->klass, c);
4791 if (!isinst) {
4792 gboolean const isinst_instr = *ip == MINT_ISINST_COMMON;
4793 if (isinst_instr)
4794 sp [-1].data.p = NULL;
4795 else
4796 goto invalid_cast_label;
4799 ip += 2;
4800 MINT_IN_BREAK;
4802 MINT_IN_CASE(MINT_CASTCLASS)
4803 MINT_IN_CASE(MINT_ISINST) {
4804 MonoObject* const o = sp [-1].data.o;
4805 if (o) {
4806 MonoClass* const c = (MonoClass*)frame->imethod->data_items [ip [1]];
4807 if (!mono_interp_isinst (o, c)) { // FIXME: do not swallow the error
4808 gboolean const isinst_instr = *ip == MINT_ISINST;
4809 if (isinst_instr)
4810 sp [-1].data.p = NULL;
4811 else
4812 goto invalid_cast_label;
4815 ip += 2;
4816 MINT_IN_BREAK;
4818 MINT_IN_CASE(MINT_CONV_R_UN_I4)
4819 sp [-1].data.f = (double)(guint32)sp [-1].data.i;
4820 ++ip;
4821 MINT_IN_BREAK;
4822 MINT_IN_CASE(MINT_CONV_R_UN_I8)
4823 sp [-1].data.f = (double)(guint64)sp [-1].data.l;
4824 ++ip;
4825 MINT_IN_BREAK;
4826 MINT_IN_CASE(MINT_UNBOX) {
4827 MonoObject* const o = sp [-1].data.o;
4828 NULL_CHECK (o);
4829 MonoClass* const c = (MonoClass*)frame->imethod->data_items[ip [1]];
4831 if (!(m_class_get_rank (o->vtable->klass) == 0 && m_class_get_element_class (o->vtable->klass) == m_class_get_element_class (c)))
4832 goto invalid_cast_label;
4834 sp [-1].data.p = mono_object_unbox_internal (o);
4835 ip += 2;
4836 MINT_IN_BREAK;
4838 MINT_IN_CASE(MINT_THROW)
4839 --sp;
4840 if (!sp->data.p)
4841 sp->data.p = mono_get_exception_null_reference ();
4843 THROW_EX ((MonoException *)sp->data.p, ip);
4844 MINT_IN_BREAK;
4845 MINT_IN_CASE(MINT_CHECKPOINT)
4846 /* Do synchronous checking of abort requests */
4847 EXCEPTION_CHECKPOINT;
4848 ++ip;
4849 MINT_IN_BREAK;
4850 MINT_IN_CASE(MINT_SAFEPOINT)
4851 /* Do synchronous checking of abort requests */
4852 EXCEPTION_CHECKPOINT;
4853 /* Poll safepoint */
4854 mono_threads_safepoint ();
4855 ++ip;
4856 MINT_IN_BREAK;
4857 MINT_IN_CASE(MINT_LDFLDA_UNSAFE) {
4858 sp[-1].data.p = (char*)sp [-1].data.o + ip [1];
4859 ip += 2;
4860 MINT_IN_BREAK;
4862 MINT_IN_CASE(MINT_LDFLDA) {
4863 MonoObject* const o = sp [-1].data.o;
4864 NULL_CHECK (o);
4865 sp[-1].data.p = (char *)o + ip [1];
4866 ip += 2;
4867 MINT_IN_BREAK;
4869 MINT_IN_CASE(MINT_CKNULL_N) {
4870 /* Same as CKNULL, but further down the stack */
4871 int const n = ip [1];
4872 MonoObject* const o = sp [-n].data.o;
4873 NULL_CHECK (o);
4874 ip += 2;
4875 MINT_IN_BREAK;
4878 #define LDFLD_UNALIGNED(datamem, fieldtype, unaligned) do { \
4879 MonoObject* const o = sp [-1].data.o; \
4880 NULL_CHECK (o); \
4881 if (unaligned) \
4882 memcpy (&sp[-1].data.datamem, (char *)o + ip [1], sizeof (fieldtype)); \
4883 else \
4884 sp[-1].data.datamem = * (fieldtype *)((char *)o + ip [1]) ; \
4885 ip += 2; \
4886 } while (0)
4888 #define LDFLD(datamem, fieldtype) LDFLD_UNALIGNED(datamem, fieldtype, FALSE)
4890 MINT_IN_CASE(MINT_LDFLD_I1) LDFLD(i, gint8); MINT_IN_BREAK;
4891 MINT_IN_CASE(MINT_LDFLD_U1) LDFLD(i, guint8); MINT_IN_BREAK;
4892 MINT_IN_CASE(MINT_LDFLD_I2) LDFLD(i, gint16); MINT_IN_BREAK;
4893 MINT_IN_CASE(MINT_LDFLD_U2) LDFLD(i, guint16); MINT_IN_BREAK;
4894 MINT_IN_CASE(MINT_LDFLD_I4) LDFLD(i, gint32); MINT_IN_BREAK;
4895 MINT_IN_CASE(MINT_LDFLD_I8) LDFLD(l, gint64); MINT_IN_BREAK;
4896 MINT_IN_CASE(MINT_LDFLD_R4) LDFLD(f_r4, float); MINT_IN_BREAK;
4897 MINT_IN_CASE(MINT_LDFLD_R8) LDFLD(f, double); MINT_IN_BREAK;
4898 MINT_IN_CASE(MINT_LDFLD_O) LDFLD(p, gpointer); MINT_IN_BREAK;
4899 MINT_IN_CASE(MINT_LDFLD_P) LDFLD(p, gpointer); MINT_IN_BREAK;
4900 MINT_IN_CASE(MINT_LDFLD_I8_UNALIGNED) LDFLD_UNALIGNED(l, gint64, TRUE); MINT_IN_BREAK;
4901 MINT_IN_CASE(MINT_LDFLD_R8_UNALIGNED) LDFLD_UNALIGNED(f, double, TRUE); MINT_IN_BREAK;
4903 MINT_IN_CASE(MINT_LDFLD_VT) {
4904 MonoObject* const o = sp [-1].data.o;
4905 NULL_CHECK (o);
4907 int size = READ32(ip + 2);
4908 sp [-1].data.p = vt_sp;
4909 memcpy (sp [-1].data.p, (char *)o + ip [1], size);
4910 vt_sp += ALIGN_TO (size, MINT_VT_ALIGNMENT);
4911 ip += 4;
4912 MINT_IN_BREAK;
4915 MINT_IN_CASE(MINT_LDRMFLD) {
4916 MonoObject* const o = sp [-1].data.o;
4917 NULL_CHECK (o);
4918 mono_interp_load_remote_field (frame->imethod, o, ip, sp);
4919 ip += 2;
4920 MINT_IN_BREAK;
4922 MINT_IN_CASE(MINT_LDRMFLD_VT) {
4923 MonoObject* const o = sp [-1].data.o;
4924 NULL_CHECK (o);
4925 vt_sp = mono_interp_load_remote_field_vt (frame->imethod, o, ip, sp, vt_sp);
4926 ip += 2;
4927 MINT_IN_BREAK;
4930 #define STFLD_UNALIGNED(datamem, fieldtype, unaligned) do { \
4931 MonoObject* const o = sp [-2].data.o; \
4932 NULL_CHECK (o); \
4933 sp -= 2; \
4934 if (unaligned) \
4935 memcpy ((char *)o + ip [1], &sp[1].data.datamem, sizeof (fieldtype)); \
4936 else \
4937 * (fieldtype *)((char *)o + ip [1]) = sp[1].data.datamem; \
4938 ip += 2; \
4939 } while (0)
4941 #define STFLD(datamem, fieldtype) STFLD_UNALIGNED(datamem, fieldtype, FALSE)
4943 MINT_IN_CASE(MINT_STFLD_I1) STFLD(i, gint8); MINT_IN_BREAK;
4944 MINT_IN_CASE(MINT_STFLD_U1) STFLD(i, guint8); MINT_IN_BREAK;
4945 MINT_IN_CASE(MINT_STFLD_I2) STFLD(i, gint16); MINT_IN_BREAK;
4946 MINT_IN_CASE(MINT_STFLD_U2) STFLD(i, guint16); MINT_IN_BREAK;
4947 MINT_IN_CASE(MINT_STFLD_I4) STFLD(i, gint32); MINT_IN_BREAK;
4948 MINT_IN_CASE(MINT_STFLD_I8) STFLD(l, gint64); MINT_IN_BREAK;
4949 MINT_IN_CASE(MINT_STFLD_R4) STFLD(f_r4, float); MINT_IN_BREAK;
4950 MINT_IN_CASE(MINT_STFLD_R8) STFLD(f, double); MINT_IN_BREAK;
4951 MINT_IN_CASE(MINT_STFLD_P) STFLD(p, gpointer); MINT_IN_BREAK;
4952 MINT_IN_CASE(MINT_STFLD_O) {
4953 MonoObject* const o = sp [-2].data.o;
4954 NULL_CHECK (o);
4955 sp -= 2;
4956 mono_gc_wbarrier_set_field_internal (o, (char *) o + ip [1], sp [1].data.o);
4957 ip += 2;
4958 MINT_IN_BREAK;
4960 MINT_IN_CASE(MINT_STFLD_I8_UNALIGNED) STFLD_UNALIGNED(l, gint64, TRUE); MINT_IN_BREAK;
4961 MINT_IN_CASE(MINT_STFLD_R8_UNALIGNED) STFLD_UNALIGNED(f, double, TRUE); MINT_IN_BREAK;
4963 MINT_IN_CASE(MINT_STFLD_VT) {
4964 MonoObject* const o = sp [-2].data.o;
4965 NULL_CHECK (o);
4966 sp -= 2;
4968 MonoClass *klass = (MonoClass*)frame->imethod->data_items[ip [2]];
4969 int const i32 = mono_class_value_size (klass, NULL);
4971 guint16 offset = ip [1];
4972 mono_value_copy_internal ((char *) o + offset, sp [1].data.p, klass);
4974 vt_sp -= ALIGN_TO (i32, MINT_VT_ALIGNMENT);
4975 ip += 3;
4976 MINT_IN_BREAK;
4978 MINT_IN_CASE(MINT_STRMFLD) {
4979 MonoClassField *field;
4981 MonoObject* const o = sp [-2].data.o;
4982 NULL_CHECK (o);
4984 field = (MonoClassField*)frame->imethod->data_items[ip [1]];
4985 ip += 2;
4987 #ifndef DISABLE_REMOTING
4988 if (mono_object_is_transparent_proxy (o)) {
4989 MonoClass *klass = ((MonoTransparentProxy*)o)->remote_class->proxy_class;
4990 mono_store_remote_field_checked (o, klass, field, &sp [-1].data, error);
4991 mono_interp_error_cleanup (error); /* FIXME: don't swallow the error */
4992 } else
4993 #endif
4994 stackval_to_data (field->type, &sp [-1], (char*)o + field->offset, FALSE);
4996 sp -= 2;
4997 MINT_IN_BREAK;
4999 MINT_IN_CASE(MINT_STRMFLD_VT)
5001 NULL_CHECK (sp [-2].data.o);
5002 vt_sp -= mono_interp_store_remote_field_vt (frame, ip, sp, error);
5003 ip += 2;
5004 sp -= 2;
5005 MINT_IN_BREAK;
5007 MINT_IN_CASE(MINT_LDSFLDA) {
5008 MonoVTable *vtable = (MonoVTable*) frame->imethod->data_items [ip [1]];
5009 INIT_VTABLE (vtable);
5010 sp->data.p = frame->imethod->data_items [ip [2]];
5011 ip += 3;
5012 ++sp;
5013 MINT_IN_BREAK;
5016 MINT_IN_CASE(MINT_LDSSFLDA) {
5017 guint32 offset = READ32(ip + 1);
5018 sp->data.p = mono_get_special_static_data (offset);
5019 ip += 3;
5020 ++sp;
5021 MINT_IN_BREAK;
5024 /* We init class here to preserve cctor order */
5025 #define LDSFLD(datamem, fieldtype) { \
5026 MonoVTable *vtable = (MonoVTable*) frame->imethod->data_items [ip [1]]; \
5027 INIT_VTABLE (vtable); \
5028 sp[0].data.datamem = * (fieldtype *)(frame->imethod->data_items [ip [2]]) ; \
5029 ip += 3; \
5030 sp++; \
5033 MINT_IN_CASE(MINT_LDSFLD_I1) LDSFLD(i, gint8); MINT_IN_BREAK;
5034 MINT_IN_CASE(MINT_LDSFLD_U1) LDSFLD(i, guint8); MINT_IN_BREAK;
5035 MINT_IN_CASE(MINT_LDSFLD_I2) LDSFLD(i, gint16); MINT_IN_BREAK;
5036 MINT_IN_CASE(MINT_LDSFLD_U2) LDSFLD(i, guint16); MINT_IN_BREAK;
5037 MINT_IN_CASE(MINT_LDSFLD_I4) LDSFLD(i, gint32); MINT_IN_BREAK;
5038 MINT_IN_CASE(MINT_LDSFLD_I8) LDSFLD(l, gint64); MINT_IN_BREAK;
5039 MINT_IN_CASE(MINT_LDSFLD_R4) LDSFLD(f_r4, float); MINT_IN_BREAK;
5040 MINT_IN_CASE(MINT_LDSFLD_R8) LDSFLD(f, double); MINT_IN_BREAK;
5041 MINT_IN_CASE(MINT_LDSFLD_O) LDSFLD(p, gpointer); MINT_IN_BREAK;
5042 MINT_IN_CASE(MINT_LDSFLD_P) LDSFLD(p, gpointer); MINT_IN_BREAK;
5044 MINT_IN_CASE(MINT_LDSFLD_VT) {
5045 MonoVTable *vtable = (MonoVTable*) frame->imethod->data_items [ip [1]];
5046 INIT_VTABLE (vtable);
5047 sp->data.p = vt_sp;
5049 gpointer addr = frame->imethod->data_items [ip [2]];
5050 int const i32 = READ32 (ip + 3);
5051 memcpy (vt_sp, addr, i32);
5052 vt_sp += ALIGN_TO (i32, MINT_VT_ALIGNMENT);
5053 ip += 5;
5054 ++sp;
5055 MINT_IN_BREAK;
5058 #define LDTSFLD(datamem, fieldtype) { \
5059 MonoInternalThread *thread = mono_thread_internal_current (); \
5060 guint32 offset = READ32 (ip + 1); \
5061 gpointer addr = ((char*)thread->static_data [offset & 0x3f]) + (offset >> 6); \
5062 sp[0].data.datamem = *(fieldtype*)addr; \
5063 ip += 3; \
5064 ++sp; \
5066 MINT_IN_CASE(MINT_LDTSFLD_I1) LDTSFLD(i, gint8); MINT_IN_BREAK;
5067 MINT_IN_CASE(MINT_LDTSFLD_U1) LDTSFLD(i, guint8); MINT_IN_BREAK;
5068 MINT_IN_CASE(MINT_LDTSFLD_I2) LDTSFLD(i, gint16); MINT_IN_BREAK;
5069 MINT_IN_CASE(MINT_LDTSFLD_U2) LDTSFLD(i, guint16); MINT_IN_BREAK;
5070 MINT_IN_CASE(MINT_LDTSFLD_I4) LDTSFLD(i, gint32); MINT_IN_BREAK;
5071 MINT_IN_CASE(MINT_LDTSFLD_I8) LDTSFLD(l, gint64); MINT_IN_BREAK;
5072 MINT_IN_CASE(MINT_LDTSFLD_R4) LDTSFLD(f_r4, float); MINT_IN_BREAK;
5073 MINT_IN_CASE(MINT_LDTSFLD_R8) LDTSFLD(f, double); MINT_IN_BREAK;
5074 MINT_IN_CASE(MINT_LDTSFLD_O) LDTSFLD(p, gpointer); MINT_IN_BREAK;
5075 MINT_IN_CASE(MINT_LDTSFLD_P) LDTSFLD(p, gpointer); MINT_IN_BREAK;
5077 MINT_IN_CASE(MINT_LDSSFLD) {
5078 guint32 offset = READ32(ip + 2);
5079 gpointer addr = mono_get_special_static_data (offset);
5080 MonoClassField *field = (MonoClassField*)frame->imethod->data_items [ip [1]];
5081 stackval_from_data (field->type, sp, addr, FALSE);
5082 ip += 4;
5083 ++sp;
5084 MINT_IN_BREAK;
5086 MINT_IN_CASE(MINT_LDSSFLD_VT) {
5087 guint32 offset = READ32(ip + 1);
5088 gpointer addr = mono_get_special_static_data (offset);
5090 int size = READ32 (ip + 3);
5091 memcpy (vt_sp, addr, size);
5092 sp->data.p = vt_sp;
5093 vt_sp += ALIGN_TO (size, MINT_VT_ALIGNMENT);
5094 ip += 5;
5095 ++sp;
5096 MINT_IN_BREAK;
5098 #define STSFLD(datamem, fieldtype) { \
5099 MonoVTable *vtable = (MonoVTable*) frame->imethod->data_items [ip [1]]; \
5100 INIT_VTABLE (vtable); \
5101 sp --; \
5102 * (fieldtype *)(frame->imethod->data_items [ip [2]]) = sp[0].data.datamem; \
5103 ip += 3; \
5106 MINT_IN_CASE(MINT_STSFLD_I1) STSFLD(i, gint8); MINT_IN_BREAK;
5107 MINT_IN_CASE(MINT_STSFLD_U1) STSFLD(i, guint8); MINT_IN_BREAK;
5108 MINT_IN_CASE(MINT_STSFLD_I2) STSFLD(i, gint16); MINT_IN_BREAK;
5109 MINT_IN_CASE(MINT_STSFLD_U2) STSFLD(i, guint16); MINT_IN_BREAK;
5110 MINT_IN_CASE(MINT_STSFLD_I4) STSFLD(i, gint32); MINT_IN_BREAK;
5111 MINT_IN_CASE(MINT_STSFLD_I8) STSFLD(l, gint64); MINT_IN_BREAK;
5112 MINT_IN_CASE(MINT_STSFLD_R4) STSFLD(f_r4, float); MINT_IN_BREAK;
5113 MINT_IN_CASE(MINT_STSFLD_R8) STSFLD(f, double); MINT_IN_BREAK;
5114 MINT_IN_CASE(MINT_STSFLD_P) STSFLD(p, gpointer); MINT_IN_BREAK;
5115 MINT_IN_CASE(MINT_STSFLD_O) STSFLD(p, gpointer); MINT_IN_BREAK;
5117 MINT_IN_CASE(MINT_STSFLD_VT) {
5118 MonoVTable *vtable = (MonoVTable*) frame->imethod->data_items [ip [1]];
5119 INIT_VTABLE (vtable);
5120 int const i32 = READ32 (ip + 3);
5121 gpointer addr = frame->imethod->data_items [ip [2]];
5123 memcpy (addr, sp [-1].data.vt, i32);
5124 vt_sp -= ALIGN_TO (i32, MINT_VT_ALIGNMENT);
5125 ip += 5;
5126 --sp;
5127 MINT_IN_BREAK;
5130 #define STTSFLD(datamem, fieldtype) { \
5131 MonoInternalThread *thread = mono_thread_internal_current (); \
5132 guint32 offset = READ32 (ip + 1); \
5133 gpointer addr = ((char*)thread->static_data [offset & 0x3f]) + (offset >> 6); \
5134 sp--; \
5135 *(fieldtype*)addr = sp[0].data.datamem; \
5136 ip += 3; \
5139 MINT_IN_CASE(MINT_STTSFLD_I1) STTSFLD(i, gint8); MINT_IN_BREAK;
5140 MINT_IN_CASE(MINT_STTSFLD_U1) STTSFLD(i, guint8); MINT_IN_BREAK;
5141 MINT_IN_CASE(MINT_STTSFLD_I2) STTSFLD(i, gint16); MINT_IN_BREAK;
5142 MINT_IN_CASE(MINT_STTSFLD_U2) STTSFLD(i, guint16); MINT_IN_BREAK;
5143 MINT_IN_CASE(MINT_STTSFLD_I4) STTSFLD(i, gint32); MINT_IN_BREAK;
5144 MINT_IN_CASE(MINT_STTSFLD_I8) STTSFLD(l, gint64); MINT_IN_BREAK;
5145 MINT_IN_CASE(MINT_STTSFLD_R4) STTSFLD(f_r4, float); MINT_IN_BREAK;
5146 MINT_IN_CASE(MINT_STTSFLD_R8) STTSFLD(f, double); MINT_IN_BREAK;
5147 MINT_IN_CASE(MINT_STTSFLD_P) STTSFLD(p, gpointer); MINT_IN_BREAK;
5148 MINT_IN_CASE(MINT_STTSFLD_O) STTSFLD(p, gpointer); MINT_IN_BREAK;
5150 MINT_IN_CASE(MINT_STSSFLD) {
5151 guint32 offset = READ32(ip + 2);
5152 gpointer addr = mono_get_special_static_data (offset);
5153 MonoClassField *field = (MonoClassField*)frame->imethod->data_items [ip [1]];
5154 --sp;
5155 stackval_to_data (field->type, sp, addr, FALSE);
5156 ip += 4;
5157 MINT_IN_BREAK;
5159 MINT_IN_CASE(MINT_STSSFLD_VT) {
5160 guint32 offset = READ32(ip + 1);
5161 gpointer addr = mono_get_special_static_data (offset);
5162 --sp;
5163 int size = READ32 (ip + 3);
5164 memcpy (addr, sp->data.vt, size);
5165 vt_sp -= ALIGN_TO (size, MINT_VT_ALIGNMENT);
5166 ip += 5;
5167 MINT_IN_BREAK;
5170 MINT_IN_CASE(MINT_STOBJ_VT) {
5171 int size;
5172 MonoClass* const c = (MonoClass*)frame->imethod->data_items[ip [1]];
5173 ip += 2;
5174 size = mono_class_value_size (c, NULL);
5175 mono_value_copy_internal (sp [-2].data.p, sp [-1].data.p, c);
5176 vt_sp -= ALIGN_TO (size, MINT_VT_ALIGNMENT);
5177 sp -= 2;
5178 MINT_IN_BREAK;
5180 MINT_IN_CASE(MINT_CONV_OVF_I4_UN_R8)
5181 if (sp [-1].data.f < 0 || sp [-1].data.f > G_MAXINT32)
5182 goto overflow_label;
5183 sp [-1].data.i = (gint32)sp [-1].data.f;
5184 ++ip;
5185 MINT_IN_BREAK;
5186 MINT_IN_CASE(MINT_CONV_OVF_U8_I4)
5187 if (sp [-1].data.i < 0)
5188 goto overflow_label;
5189 sp [-1].data.l = sp [-1].data.i;
5190 ++ip;
5191 MINT_IN_BREAK;
5192 MINT_IN_CASE(MINT_CONV_OVF_U8_I8)
5193 if (sp [-1].data.l < 0)
5194 goto overflow_label;
5195 ++ip;
5196 MINT_IN_BREAK;
5197 MINT_IN_CASE(MINT_CONV_OVF_I8_U8)
5198 if ((guint64) sp [-1].data.l > G_MAXINT64)
5199 goto overflow_label;
5200 ++ip;
5201 MINT_IN_BREAK;
5202 MINT_IN_CASE(MINT_CONV_OVF_U8_R4)
5203 if (sp [-1].data.f_r4 < 0 || sp [-1].data.f_r4 > G_MAXUINT64 || isnan (sp [-1].data.f_r4))
5204 goto overflow_label;
5205 sp [-1].data.l = (guint64)sp [-1].data.f_r4;
5206 ++ip;
5207 MINT_IN_BREAK;
5208 MINT_IN_CASE(MINT_CONV_OVF_U8_R8)
5209 if (sp [-1].data.f < 0 || sp [-1].data.f > G_MAXUINT64 || isnan (sp [-1].data.f))
5210 goto overflow_label;
5211 sp [-1].data.l = (guint64)sp [-1].data.f;
5212 ++ip;
5213 MINT_IN_BREAK;
5214 MINT_IN_CASE(MINT_CONV_OVF_I8_UN_R8)
5215 if (sp [-1].data.f < 0 || sp [-1].data.f > G_MAXINT64)
5216 goto overflow_label;
5217 sp [-1].data.l = (gint64)sp [-1].data.f;
5218 ++ip;
5219 MINT_IN_BREAK;
5220 MINT_IN_CASE(MINT_CONV_OVF_I8_UN_R4)
5221 if (sp [-1].data.f_r4 < 0 || sp [-1].data.f_r4 > G_MAXINT64)
5222 goto overflow_label;
5223 sp [-1].data.l = (gint64)sp [-1].data.f_r4;
5224 ++ip;
5225 MINT_IN_BREAK;
5226 MINT_IN_CASE(MINT_CONV_OVF_I8_R4)
5227 if (sp [-1].data.f_r4 < G_MININT64 || sp [-1].data.f_r4 > G_MAXINT64 || isnan (sp [-1].data.f_r4))
5228 goto overflow_label;
5229 sp [-1].data.l = (gint64)sp [-1].data.f_r4;
5230 ++ip;
5231 MINT_IN_BREAK;
5232 MINT_IN_CASE(MINT_CONV_OVF_I8_R8)
5233 if (sp [-1].data.f < G_MININT64 || sp [-1].data.f > G_MAXINT64 || isnan (sp [-1].data.f))
5234 goto overflow_label;
5235 sp [-1].data.l = (gint64)sp [-1].data.f;
5236 ++ip;
5237 MINT_IN_BREAK;
5238 MINT_IN_CASE(MINT_CONV_OVF_I4_UN_I8)
5239 if ((guint64)sp [-1].data.l > G_MAXINT32)
5240 goto overflow_label;
5241 sp [-1].data.i = (gint32)sp [-1].data.l;
5242 ++ip;
5243 MINT_IN_BREAK;
5244 MINT_IN_CASE(MINT_BOX) {
5245 mono_interp_box (frame, ip, sp);
5246 ip += 3;
5247 MINT_IN_BREAK;
5249 MINT_IN_CASE(MINT_BOX_VT) {
5250 vt_sp -= mono_interp_box_vt (frame, ip, sp);
5251 ip += 3;
5252 MINT_IN_BREAK;
5254 MINT_IN_CASE(MINT_BOX_NULLABLE) {
5255 vt_sp -= mono_interp_box_nullable (frame, ip, sp, error);
5256 ip += 3;
5257 MINT_IN_BREAK;
5259 MINT_IN_CASE(MINT_NEWARR) {
5260 MonoVTable *vtable = (MonoVTable*)frame->imethod->data_items[ip [1]];
5261 sp [-1].data.o = (MonoObject*) mono_array_new_specific_checked (vtable, sp [-1].data.i, error);
5262 if (!is_ok (error)) {
5263 goto throw_error_label;
5265 ip += 2;
5266 /*if (profiling_classes) {
5267 guint count = GPOINTER_TO_UINT (g_hash_table_lookup (profiling_classes, o->vtable->klass));
5268 count++;
5269 g_hash_table_insert (profiling_classes, o->vtable->klass, GUINT_TO_POINTER (count));
5272 MINT_IN_BREAK;
5274 MINT_IN_CASE(MINT_LDLEN) {
5275 MonoObject* const o = sp [-1].data.o;
5276 NULL_CHECK (o);
5277 sp [-1].data.nati = mono_array_length_internal ((MonoArray *)o);
5278 ++ip;
5279 MINT_IN_BREAK;
5281 MINT_IN_CASE(MINT_LDLEN_SPAN) {
5282 MonoObject* const o = sp [-1].data.o;
5283 NULL_CHECK (o);
5284 gsize offset_length = (gsize)(gint16)ip [1];
5285 sp [-1].data.nati = *(gint32 *) ((guint8 *) o + offset_length);
5286 ip += 2;
5287 MINT_IN_BREAK;
5289 MINT_IN_CASE(MINT_GETCHR) {
5290 MonoString *s;
5291 s = (MonoString*)sp [-2].data.p;
5292 NULL_CHECK (s);
5293 int const i32 = sp [-1].data.i;
5294 if (i32 < 0 || i32 >= mono_string_length_internal (s))
5295 THROW_EX (mono_get_exception_index_out_of_range (), ip);
5296 --sp;
5297 sp [-1].data.i = mono_string_chars_internal (s)[i32];
5298 ++ip;
5299 MINT_IN_BREAK;
5301 MINT_IN_CASE(MINT_GETITEM_SPAN) {
5302 guint8 * const span = (guint8 *) sp [-2].data.p;
5303 const int index = sp [-1].data.i;
5304 sp--;
5306 NULL_CHECK (span);
5308 const gsize offset_length = (gsize)(gint16)ip [2];
5310 const gint32 length = *(gint32 *) (span + offset_length);
5311 if (index < 0 || index >= length)
5312 THROW_EX (mono_get_exception_index_out_of_range (), ip);
5314 const gsize element_size = (gsize)(gint16)ip [1];
5315 const gsize offset_pointer = (gsize)(gint16)ip [3];
5317 const gpointer pointer = *(gpointer *)(span + offset_pointer);
5318 sp [-1].data.p = (guint8 *) pointer + index * element_size;
5320 ip += 4;
5321 MINT_IN_BREAK;
5323 MINT_IN_CASE(MINT_STRLEN) {
5324 ++ip;
5325 MonoObject* const o = sp [-1].data.o;
5326 NULL_CHECK (o);
5327 sp [-1].data.i = mono_string_length_internal ((MonoString*) o);
5328 MINT_IN_BREAK;
5330 MINT_IN_CASE(MINT_ARRAY_RANK) {
5331 MonoObject* const o = sp [-1].data.o;
5332 NULL_CHECK (o);
5333 sp [-1].data.i = m_class_get_rank (mono_object_class (sp [-1].data.p));
5334 ip++;
5335 MINT_IN_BREAK;
5337 MINT_IN_CASE(MINT_LDELEMA1) {
5338 /* No bounds, one direction */
5339 MonoArray *ao = (MonoArray*)sp [-2].data.o;
5340 NULL_CHECK (ao);
5341 gint32 const index = sp [-1].data.i;
5342 if (index >= ao->max_length)
5343 THROW_EX (mono_get_exception_index_out_of_range (), ip);
5344 gint32 const size = READ32 (ip + 1);
5345 sp [-2].data.p = mono_array_addr_with_size_fast (ao, size, index);
5346 ip += 3;
5347 sp --;
5349 MINT_IN_BREAK;
5351 MINT_IN_CASE(MINT_LDELEMA) {
5352 guint16 rank = ip [1];
5353 gint32 const esize = READ32 (ip + 2);
5354 ip += 4;
5355 sp -= rank;
5357 MonoArray* const ao = (MonoArray*) sp [-1].data.o;
5358 NULL_CHECK (ao);
5360 g_assert (ao->bounds);
5361 guint32 pos = 0;
5362 for (int i = 0; i < rank; i++) {
5363 guint32 idx = sp [i].data.i;
5364 guint32 lower = ao->bounds [i].lower_bound;
5365 guint32 len = ao->bounds [i].length;
5366 if (idx < lower || (idx - lower) >= len)
5367 THROW_EX (mono_get_exception_index_out_of_range (), ip);
5368 pos = (pos * len) + idx - lower;
5371 sp [-1].data.p = mono_array_addr_with_size_fast (ao, esize, pos);
5372 MINT_IN_BREAK;
5374 MINT_IN_CASE(MINT_LDELEMA_TC) {
5375 guint16 rank = ip [1];
5376 ip += 3;
5377 sp -= rank;
5379 MonoObject* const o = sp [-1].data.o;
5380 NULL_CHECK (o);
5382 MonoClass *klass = (MonoClass*)frame->imethod->data_items [ip [-3 + 2]];
5383 const gboolean needs_typecheck = ip [-3] == MINT_LDELEMA_TC;
5384 MonoException *ex = ves_array_element_address (frame, klass, (MonoArray *) o, sp, needs_typecheck);
5385 if (ex)
5386 THROW_EX (ex, ip);
5387 MINT_IN_BREAK;
5389 MINT_IN_CASE(MINT_LDELEM_I1) /* fall through */
5390 MINT_IN_CASE(MINT_LDELEM_U1) /* fall through */
5391 MINT_IN_CASE(MINT_LDELEM_I2) /* fall through */
5392 MINT_IN_CASE(MINT_LDELEM_U2) /* fall through */
5393 MINT_IN_CASE(MINT_LDELEM_I4) /* fall through */
5394 MINT_IN_CASE(MINT_LDELEM_U4) /* fall through */
5395 MINT_IN_CASE(MINT_LDELEM_I8) /* fall through */
5396 MINT_IN_CASE(MINT_LDELEM_I) /* fall through */
5397 MINT_IN_CASE(MINT_LDELEM_R4) /* fall through */
5398 MINT_IN_CASE(MINT_LDELEM_R8) /* fall through */
5399 MINT_IN_CASE(MINT_LDELEM_REF) /* fall through */
5400 MINT_IN_CASE(MINT_LDELEM_VT) {
5401 MonoArray *o;
5402 mono_u aindex;
5404 sp -= 2;
5406 o = (MonoArray*)sp [0].data.p;
5407 NULL_CHECK (o);
5409 aindex = sp [1].data.i;
5410 if (aindex >= mono_array_length_internal (o))
5411 THROW_EX (mono_get_exception_index_out_of_range (), ip);
5414 * FIXME: throw mono_get_exception_array_type_mismatch () if needed
5416 switch (*ip) {
5417 case MINT_LDELEM_I1:
5418 sp [0].data.i = mono_array_get_fast (o, gint8, aindex);
5419 break;
5420 case MINT_LDELEM_U1:
5421 sp [0].data.i = mono_array_get_fast (o, guint8, aindex);
5422 break;
5423 case MINT_LDELEM_I2:
5424 sp [0].data.i = mono_array_get_fast (o, gint16, aindex);
5425 break;
5426 case MINT_LDELEM_U2:
5427 sp [0].data.i = mono_array_get_fast (o, guint16, aindex);
5428 break;
5429 case MINT_LDELEM_I:
5430 sp [0].data.nati = mono_array_get_fast (o, mono_i, aindex);
5431 break;
5432 case MINT_LDELEM_I4:
5433 sp [0].data.i = mono_array_get_fast (o, gint32, aindex);
5434 break;
5435 case MINT_LDELEM_U4:
5436 sp [0].data.i = mono_array_get_fast (o, guint32, aindex);
5437 break;
5438 case MINT_LDELEM_I8:
5439 sp [0].data.l = mono_array_get_fast (o, guint64, aindex);
5440 break;
5441 case MINT_LDELEM_R4:
5442 sp [0].data.f_r4 = mono_array_get_fast (o, float, aindex);
5443 break;
5444 case MINT_LDELEM_R8:
5445 sp [0].data.f = mono_array_get_fast (o, double, aindex);
5446 break;
5447 case MINT_LDELEM_REF:
5448 sp [0].data.p = mono_array_get_fast (o, gpointer, aindex);
5449 break;
5450 case MINT_LDELEM_VT: {
5451 int const i32 = READ32 (ip + 1);
5452 char *src_addr = mono_array_addr_with_size_fast ((MonoArray *) o, i32, aindex);
5453 sp [0].data.vt = vt_sp;
5454 // Copying to vtstack. No wbarrier needed
5455 memcpy (sp [0].data.vt, src_addr, i32);
5456 vt_sp += ALIGN_TO (i32, MINT_VT_ALIGNMENT);
5457 ip += 2;
5458 break;
5460 default:
5461 ves_abort();
5464 ++ip;
5465 ++sp;
5466 MINT_IN_BREAK;
5468 MINT_IN_CASE(MINT_STELEM_I) /* fall through */
5469 MINT_IN_CASE(MINT_STELEM_I1) /* fall through */
5470 MINT_IN_CASE(MINT_STELEM_U1) /* fall through */
5471 MINT_IN_CASE(MINT_STELEM_I2) /* fall through */
5472 MINT_IN_CASE(MINT_STELEM_U2) /* fall through */
5473 MINT_IN_CASE(MINT_STELEM_I4) /* fall through */
5474 MINT_IN_CASE(MINT_STELEM_I8) /* fall through */
5475 MINT_IN_CASE(MINT_STELEM_R4) /* fall through */
5476 MINT_IN_CASE(MINT_STELEM_R8) /* fall through */
5477 MINT_IN_CASE(MINT_STELEM_REF) /* fall through */
5478 MINT_IN_CASE(MINT_STELEM_VT) {
5479 mono_u aindex;
5481 sp -= 3;
5483 MonoObject* const o = sp [0].data.o;
5484 NULL_CHECK (o);
5486 aindex = sp [1].data.i;
5487 if (aindex >= mono_array_length_internal ((MonoArray *)o))
5488 THROW_EX (mono_get_exception_index_out_of_range (), ip);
5490 switch (*ip) {
5491 case MINT_STELEM_I:
5492 mono_array_set_fast ((MonoArray *)o, mono_i, aindex, sp [2].data.nati);
5493 break;
5494 case MINT_STELEM_I1:
5495 mono_array_set_fast ((MonoArray *)o, gint8, aindex, sp [2].data.i);
5496 break;
5497 case MINT_STELEM_U1:
5498 mono_array_set_fast ((MonoArray *) o, guint8, aindex, sp [2].data.i);
5499 break;
5500 case MINT_STELEM_I2:
5501 mono_array_set_fast ((MonoArray *)o, gint16, aindex, sp [2].data.i);
5502 break;
5503 case MINT_STELEM_U2:
5504 mono_array_set_fast ((MonoArray *)o, guint16, aindex, sp [2].data.i);
5505 break;
5506 case MINT_STELEM_I4:
5507 mono_array_set_fast ((MonoArray *)o, gint32, aindex, sp [2].data.i);
5508 break;
5509 case MINT_STELEM_I8:
5510 mono_array_set_fast ((MonoArray *)o, gint64, aindex, sp [2].data.l);
5511 break;
5512 case MINT_STELEM_R4:
5513 mono_array_set_fast ((MonoArray *)o, float, aindex, sp [2].data.f_r4);
5514 break;
5515 case MINT_STELEM_R8:
5516 mono_array_set_fast ((MonoArray *)o, double, aindex, sp [2].data.f);
5517 break;
5518 case MINT_STELEM_REF: {
5519 if (sp [2].data.p) {
5520 MonoObject *isinst_obj = mono_object_isinst_checked (sp [2].data.o, m_class_get_element_class (mono_object_class (o)), error);
5521 mono_interp_error_cleanup (error); /* FIXME: don't swallow the error */
5522 if (!isinst_obj)
5523 THROW_EX (mono_get_exception_array_type_mismatch (), ip);
5525 mono_array_setref_fast ((MonoArray *) o, aindex, sp [2].data.p);
5526 break;
5528 case MINT_STELEM_VT: {
5529 MonoClass *klass_vt = (MonoClass*)frame->imethod->data_items [ip [1]];
5530 int const i32 = READ32 (ip + 2);
5531 char *dst_addr = mono_array_addr_with_size_fast ((MonoArray *) o, i32, aindex);
5533 mono_value_copy_internal (dst_addr, sp [2].data.vt, klass_vt);
5534 vt_sp -= ALIGN_TO (i32, MINT_VT_ALIGNMENT);
5535 ip += 3;
5536 break;
5538 default:
5539 ves_abort();
5542 ++ip;
5543 MINT_IN_BREAK;
5545 MINT_IN_CASE(MINT_CONV_OVF_I4_U4)
5546 if (sp [-1].data.i < 0)
5547 goto overflow_label;
5548 ++ip;
5549 MINT_IN_BREAK;
5550 MINT_IN_CASE(MINT_CONV_OVF_I4_I8)
5551 if (sp [-1].data.l < G_MININT32 || sp [-1].data.l > G_MAXINT32)
5552 goto overflow_label;
5553 sp [-1].data.i = (gint32) sp [-1].data.l;
5554 ++ip;
5555 MINT_IN_BREAK;
5556 MINT_IN_CASE(MINT_CONV_OVF_I4_U8)
5557 if (sp [-1].data.l < 0 || sp [-1].data.l > G_MAXINT32)
5558 goto overflow_label;
5559 sp [-1].data.i = (gint32) sp [-1].data.l;
5560 ++ip;
5561 MINT_IN_BREAK;
5562 MINT_IN_CASE(MINT_CONV_OVF_I4_R4)
5563 if (sp [-1].data.f_r4 < G_MININT32 || sp [-1].data.f_r4 > G_MAXINT32)
5564 goto overflow_label;
5565 sp [-1].data.i = (gint32) sp [-1].data.f_r4;
5566 ++ip;
5567 MINT_IN_BREAK;
5568 MINT_IN_CASE(MINT_CONV_OVF_I4_R8)
5569 if (sp [-1].data.f < G_MININT32 || sp [-1].data.f > G_MAXINT32)
5570 goto overflow_label;
5571 sp [-1].data.i = (gint32) sp [-1].data.f;
5572 ++ip;
5573 MINT_IN_BREAK;
5574 MINT_IN_CASE(MINT_CONV_OVF_U4_I4)
5575 if (sp [-1].data.i < 0)
5576 goto overflow_label;
5577 ++ip;
5578 MINT_IN_BREAK;
5579 MINT_IN_CASE(MINT_CONV_OVF_U4_I8)
5580 if (sp [-1].data.l < 0 || sp [-1].data.l > G_MAXUINT32)
5581 goto overflow_label;
5582 sp [-1].data.i = (guint32) sp [-1].data.l;
5583 ++ip;
5584 MINT_IN_BREAK;
5585 MINT_IN_CASE(MINT_CONV_OVF_U4_R4)
5586 if (sp [-1].data.f_r4 < 0 || sp [-1].data.f_r4 > G_MAXUINT32)
5587 goto overflow_label;
5588 sp [-1].data.i = (guint32) sp [-1].data.f_r4;
5589 ++ip;
5590 MINT_IN_BREAK;
5591 MINT_IN_CASE(MINT_CONV_OVF_U4_R8)
5592 if (sp [-1].data.f < 0 || sp [-1].data.f > G_MAXUINT32)
5593 goto overflow_label;
5594 sp [-1].data.i = (guint32) sp [-1].data.f;
5595 ++ip;
5596 MINT_IN_BREAK;
5597 MINT_IN_CASE(MINT_CONV_OVF_I2_I4)
5598 if (sp [-1].data.i < G_MININT16 || sp [-1].data.i > G_MAXINT16)
5599 goto overflow_label;
5600 ++ip;
5601 MINT_IN_BREAK;
5602 MINT_IN_CASE(MINT_CONV_OVF_I2_U4)
5603 if (sp [-1].data.i < 0 || sp [-1].data.i > G_MAXINT16)
5604 goto overflow_label;
5605 ++ip;
5606 MINT_IN_BREAK;
5607 MINT_IN_CASE(MINT_CONV_OVF_I2_I8)
5608 if (sp [-1].data.l < G_MININT16 || sp [-1].data.l > G_MAXINT16)
5609 goto overflow_label;
5610 sp [-1].data.i = (gint16) sp [-1].data.l;
5611 ++ip;
5612 MINT_IN_BREAK;
5613 MINT_IN_CASE(MINT_CONV_OVF_I2_U8)
5614 if (sp [-1].data.l < 0 || sp [-1].data.l > G_MAXINT16)
5615 goto overflow_label;
5616 sp [-1].data.i = (gint16) sp [-1].data.l;
5617 ++ip;
5618 MINT_IN_BREAK;
5619 MINT_IN_CASE(MINT_CONV_OVF_I2_R8)
5620 if (sp [-1].data.f < G_MININT16 || sp [-1].data.f > G_MAXINT16)
5621 goto overflow_label;
5622 sp [-1].data.i = (gint16) sp [-1].data.f;
5623 ++ip;
5624 MINT_IN_BREAK;
5625 MINT_IN_CASE(MINT_CONV_OVF_I2_UN_R8)
5626 if (sp [-1].data.f < 0 || sp [-1].data.f > G_MAXINT16)
5627 goto overflow_label;
5628 sp [-1].data.i = (gint16) sp [-1].data.f;
5629 ++ip;
5630 MINT_IN_BREAK;
5631 MINT_IN_CASE(MINT_CONV_OVF_U2_I4)
5632 if (sp [-1].data.i < 0 || sp [-1].data.i > G_MAXUINT16)
5633 goto overflow_label;
5634 ++ip;
5635 MINT_IN_BREAK;
5636 MINT_IN_CASE(MINT_CONV_OVF_U2_I8)
5637 if (sp [-1].data.l < 0 || sp [-1].data.l > G_MAXUINT16)
5638 goto overflow_label;
5639 sp [-1].data.i = (guint16) sp [-1].data.l;
5640 ++ip;
5641 MINT_IN_BREAK;
5642 MINT_IN_CASE(MINT_CONV_OVF_U2_R8)
5643 if (sp [-1].data.f < 0 || sp [-1].data.f > G_MAXUINT16)
5644 goto overflow_label;
5645 sp [-1].data.i = (guint16) sp [-1].data.f;
5646 ++ip;
5647 MINT_IN_BREAK;
5648 MINT_IN_CASE(MINT_CONV_OVF_I1_I4)
5649 if (sp [-1].data.i < G_MININT8 || sp [-1].data.i > G_MAXINT8)
5650 goto overflow_label;
5651 ++ip;
5652 MINT_IN_BREAK;
5653 MINT_IN_CASE(MINT_CONV_OVF_I1_U4)
5654 if (sp [-1].data.i < 0 || sp [-1].data.i > G_MAXINT8)
5655 goto overflow_label;
5656 ++ip;
5657 MINT_IN_BREAK;
5658 MINT_IN_CASE(MINT_CONV_OVF_I1_I8)
5659 if (sp [-1].data.l < G_MININT8 || sp [-1].data.l > G_MAXINT8)
5660 goto overflow_label;
5661 sp [-1].data.i = (gint8) sp [-1].data.l;
5662 ++ip;
5663 MINT_IN_BREAK;
5664 MINT_IN_CASE(MINT_CONV_OVF_I1_U8)
5665 if (sp [-1].data.l < 0 || sp [-1].data.l > G_MAXINT8)
5666 goto overflow_label;
5667 sp [-1].data.i = (gint8) sp [-1].data.l;
5668 ++ip;
5669 MINT_IN_BREAK;
5670 MINT_IN_CASE(MINT_CONV_OVF_I1_R8)
5671 if (sp [-1].data.f < G_MININT8 || sp [-1].data.f > G_MAXINT8)
5672 goto overflow_label;
5673 sp [-1].data.i = (gint8) sp [-1].data.f;
5674 ++ip;
5675 MINT_IN_BREAK;
5676 MINT_IN_CASE(MINT_CONV_OVF_I1_UN_R8)
5677 if (sp [-1].data.f < 0 || sp [-1].data.f > G_MAXINT8)
5678 goto overflow_label;
5679 sp [-1].data.i = (gint8) sp [-1].data.f;
5680 ++ip;
5681 MINT_IN_BREAK;
5682 MINT_IN_CASE(MINT_CONV_OVF_U1_I4)
5683 if (sp [-1].data.i < 0 || sp [-1].data.i > G_MAXUINT8)
5684 goto overflow_label;
5685 ++ip;
5686 MINT_IN_BREAK;
5687 MINT_IN_CASE(MINT_CONV_OVF_U1_I8)
5688 if (sp [-1].data.l < 0 || sp [-1].data.l > G_MAXUINT8)
5689 goto overflow_label;
5690 sp [-1].data.i = (guint8) sp [-1].data.l;
5691 ++ip;
5692 MINT_IN_BREAK;
5693 MINT_IN_CASE(MINT_CONV_OVF_U1_R8)
5694 if (sp [-1].data.f < 0 || sp [-1].data.f > G_MAXUINT8)
5695 goto overflow_label;
5696 sp [-1].data.i = (guint8) sp [-1].data.f;
5697 ++ip;
5698 MINT_IN_BREAK;
5699 MINT_IN_CASE(MINT_CKFINITE)
5700 if (!mono_isfinite (sp [-1].data.f))
5701 THROW_EX (mono_get_exception_arithmetic (), ip);
5702 ++ip;
5703 MINT_IN_BREAK;
5704 MINT_IN_CASE(MINT_MKREFANY) {
5705 MonoClass* const c = (MonoClass*)frame->imethod->data_items [ip [1]];
5707 /* The value address is on the stack */
5708 gpointer addr = sp [-1].data.p;
5709 /* Push the typedref value on the stack */
5710 sp [-1].data.p = vt_sp;
5711 vt_sp += ALIGN_TO (sizeof (MonoTypedRef), MINT_VT_ALIGNMENT);
5713 MonoTypedRef *tref = (MonoTypedRef*)sp [-1].data.p;
5714 tref->klass = c;
5715 tref->type = m_class_get_byval_arg (c);
5716 tref->value = addr;
5718 ip += 2;
5719 MINT_IN_BREAK;
5721 MINT_IN_CASE(MINT_REFANYTYPE) {
5722 MonoTypedRef *tref = (MonoTypedRef*)sp [-1].data.p;
5723 MonoType *type = tref->type;
5725 vt_sp -= ALIGN_TO (sizeof (MonoTypedRef), MINT_VT_ALIGNMENT);
5726 sp [-1].data.p = vt_sp;
5727 vt_sp += 8;
5728 *(gpointer*)sp [-1].data.p = type;
5729 ip ++;
5730 MINT_IN_BREAK;
5732 MINT_IN_CASE(MINT_REFANYVAL) {
5733 MonoTypedRef *tref = (MonoTypedRef*)sp [-1].data.p;
5734 gpointer addr = tref->value;
5736 MonoClass* const c = (MonoClass*)frame->imethod->data_items [ip [1]];
5737 if (c != tref->klass)
5738 goto invalid_cast_label;
5740 vt_sp -= ALIGN_TO (sizeof (MonoTypedRef), MINT_VT_ALIGNMENT);
5742 sp [-1].data.p = addr;
5743 ip += 2;
5744 MINT_IN_BREAK;
5746 MINT_IN_CASE(MINT_LDTOKEN)
5747 sp->data.p = vt_sp;
5748 vt_sp += 8;
5749 * (gpointer *)sp->data.p = frame->imethod->data_items[ip [1]];
5750 ip += 2;
5751 ++sp;
5752 MINT_IN_BREAK;
5753 MINT_IN_CASE(MINT_ADD_OVF_I4)
5754 if (CHECK_ADD_OVERFLOW (sp [-2].data.i, sp [-1].data.i))
5755 goto overflow_label;
5756 BINOP(i, +);
5757 MINT_IN_BREAK;
5758 MINT_IN_CASE(MINT_ADD_OVF_I8)
5759 if (CHECK_ADD_OVERFLOW64 (sp [-2].data.l, sp [-1].data.l))
5760 goto overflow_label;
5761 BINOP(l, +);
5762 MINT_IN_BREAK;
5763 MINT_IN_CASE(MINT_ADD_OVF_UN_I4)
5764 if (CHECK_ADD_OVERFLOW_UN (sp [-2].data.i, sp [-1].data.i))
5765 goto overflow_label;
5766 BINOP_CAST(i, +, guint32);
5767 MINT_IN_BREAK;
5768 MINT_IN_CASE(MINT_ADD_OVF_UN_I8)
5769 if (CHECK_ADD_OVERFLOW64_UN (sp [-2].data.l, sp [-1].data.l))
5770 goto overflow_label;
5771 BINOP_CAST(l, +, guint64);
5772 MINT_IN_BREAK;
5773 MINT_IN_CASE(MINT_MUL_OVF_I4)
5774 if (CHECK_MUL_OVERFLOW (sp [-2].data.i, sp [-1].data.i))
5775 goto overflow_label;
5776 BINOP(i, *);
5777 MINT_IN_BREAK;
5778 MINT_IN_CASE(MINT_MUL_OVF_I8)
5779 if (CHECK_MUL_OVERFLOW64 (sp [-2].data.l, sp [-1].data.l))
5780 goto overflow_label;
5781 BINOP(l, *);
5782 MINT_IN_BREAK;
5783 MINT_IN_CASE(MINT_MUL_OVF_UN_I4)
5784 if (CHECK_MUL_OVERFLOW_UN (sp [-2].data.i, sp [-1].data.i))
5785 goto overflow_label;
5786 BINOP_CAST(i, *, guint32);
5787 MINT_IN_BREAK;
5788 MINT_IN_CASE(MINT_MUL_OVF_UN_I8)
5789 if (CHECK_MUL_OVERFLOW64_UN (sp [-2].data.l, sp [-1].data.l))
5790 goto overflow_label;
5791 BINOP_CAST(l, *, guint64);
5792 MINT_IN_BREAK;
5793 MINT_IN_CASE(MINT_SUB_OVF_I4)
5794 if (CHECK_SUB_OVERFLOW (sp [-2].data.i, sp [-1].data.i))
5795 goto overflow_label;
5796 BINOP(i, -);
5797 MINT_IN_BREAK;
5798 MINT_IN_CASE(MINT_SUB_OVF_I8)
5799 if (CHECK_SUB_OVERFLOW64 (sp [-2].data.l, sp [-1].data.l))
5800 goto overflow_label;
5801 BINOP(l, -);
5802 MINT_IN_BREAK;
5803 MINT_IN_CASE(MINT_SUB_OVF_UN_I4)
5804 if (CHECK_SUB_OVERFLOW_UN (sp [-2].data.i, sp [-1].data.i))
5805 goto overflow_label;
5806 BINOP_CAST(i, -, guint32);
5807 MINT_IN_BREAK;
5808 MINT_IN_CASE(MINT_SUB_OVF_UN_I8)
5809 if (CHECK_SUB_OVERFLOW64_UN (sp [-2].data.l, sp [-1].data.l))
5810 goto overflow_label;
5811 BINOP_CAST(l, -, guint64);
5812 MINT_IN_BREAK;
5813 MINT_IN_CASE(MINT_START_ABORT_PROT)
5814 mono_threads_begin_abort_protected_block ();
5815 ip ++;
5816 MINT_IN_BREAK;
5817 MINT_IN_CASE(MINT_ENDFINALLY) {
5818 gboolean pending_abort = mono_threads_end_abort_protected_block ();
5819 ip ++;
5821 // After mono_threads_end_abort_protected_block to conserve stack.
5822 const int clause_index = *ip;
5824 if (clause_args && clause_index == clause_args->exit_clause)
5825 goto exit_frame;
5827 #if DEBUG_INTERP // This assert causes Linux/amd64/clang to use more stack.
5828 g_assert (sp >= frame->stack);
5829 #endif
5830 sp = frame->stack;
5832 if (finally_ips) {
5833 ip = (const guint16*)finally_ips->data;
5834 finally_ips = g_slist_remove (finally_ips, ip);
5835 /* Throw abort after the last finally block to avoid confusing EH */
5836 if (pending_abort && !finally_ips)
5837 EXCEPTION_CHECKPOINT;
5838 // goto main_loop instead of MINT_IN_DISPATCH helps the compiler and therefore conserves stack.
5839 // This is a slow/rare path and conserving stack is preferred over its performance otherwise.
5840 goto main_loop;
5842 ves_abort();
5843 MINT_IN_BREAK;
5846 MINT_IN_CASE(MINT_LEAVE)
5847 MINT_IN_CASE(MINT_LEAVE_S)
5848 MINT_IN_CASE(MINT_LEAVE_CHECK)
5849 MINT_IN_CASE(MINT_LEAVE_S_CHECK) {
5851 // Leave is split into pieces in order to consume less stack,
5852 // but not have to change how exception handling macros access labels and locals.
5854 g_assert (sp >= frame->stack);
5855 sp = frame->stack; /* spec says stack should be empty at endfinally so it should be at the start too */
5856 vt_sp = (unsigned char*)sp + frame->imethod->stack_size;
5858 frame->ip = ip;
5860 int opcode = *ip;
5861 gboolean const check = opcode == MINT_LEAVE_CHECK || opcode == MINT_LEAVE_S_CHECK;
5863 if (check && frame->imethod->method->wrapper_type != MONO_WRAPPER_RUNTIME_INVOKE) {
5864 child_frame.parent = frame;
5865 child_frame.imethod = NULL;
5866 MonoException *abort_exc = mono_interp_leave (&child_frame);
5867 if (abort_exc)
5868 THROW_EX (abort_exc, frame->ip);
5871 opcode = *ip; // Refetch to avoid register/stack pressure.
5872 gboolean const short_offset = opcode == MINT_LEAVE_S || opcode == MINT_LEAVE_S_CHECK;
5873 ip += short_offset ? (short)*(ip + 1) : (gint32)READ32 (ip + 1);
5874 const guint16 *endfinally_ip = ip;
5875 GSList *old_list = finally_ips;
5876 MonoMethod *method = frame->imethod->method;
5877 #if DEBUG_INTERP
5878 if (tracing)
5879 g_print ("* Handle finally IL_%04x\n", endfinally_ip - frame->imethod->code);
5880 #endif
5881 // FIXME Null check for frame->imethod follows deref.
5882 if (frame->imethod == NULL || (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
5883 || (method->iflags & (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL | METHOD_IMPL_ATTRIBUTE_RUNTIME))) {
5884 goto exit_frame;
5886 guint32 const ip_offset = frame->ip - frame->imethod->code;
5888 finally_ips = g_slist_prepend (finally_ips, (void *)endfinally_ip);
5890 for (int i = frame->imethod->num_clauses - 1; i >= 0; i--) {
5891 MonoExceptionClause* const clause = &frame->imethod->clauses [i];
5892 if (MONO_OFFSET_IN_CLAUSE (clause, ip_offset) && !(MONO_OFFSET_IN_CLAUSE (clause, endfinally_ip - frame->imethod->code))) {
5893 if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY) {
5894 ip = frame->imethod->code + clause->handler_offset;
5895 finally_ips = g_slist_prepend (finally_ips, (gpointer) ip);
5896 #if DEBUG_INTERP
5897 if (tracing)
5898 g_print ("* Found finally at IL_%04x with exception: %s\n", clause->handler_offset, context->has_resume_state ? "yes": "no");
5899 #endif
5904 if (old_list != finally_ips && finally_ips) {
5905 ip = (const guint16*)finally_ips->data;
5906 finally_ips = g_slist_remove (finally_ips, ip);
5907 // goto main_loop instead of MINT_IN_DISPATCH helps the compiler and therefore conserves stack.
5908 // This is a slow/rare path and conserving stack is preferred over its performance otherwise.
5909 goto main_loop;
5912 ves_abort();
5913 MINT_IN_BREAK;
5915 MINT_IN_CASE(MINT_ICALL_V_V)
5916 MINT_IN_CASE(MINT_ICALL_V_P)
5917 MINT_IN_CASE(MINT_ICALL_P_V)
5918 MINT_IN_CASE(MINT_ICALL_P_P)
5919 MINT_IN_CASE(MINT_ICALL_PP_V)
5920 MINT_IN_CASE(MINT_ICALL_PP_P)
5921 MINT_IN_CASE(MINT_ICALL_PPP_V)
5922 MINT_IN_CASE(MINT_ICALL_PPP_P)
5923 MINT_IN_CASE(MINT_ICALL_PPPP_V)
5924 MINT_IN_CASE(MINT_ICALL_PPPP_P)
5925 MINT_IN_CASE(MINT_ICALL_PPPPP_V)
5926 MINT_IN_CASE(MINT_ICALL_PPPPP_P)
5927 MINT_IN_CASE(MINT_ICALL_PPPPPP_V)
5928 MINT_IN_CASE(MINT_ICALL_PPPPPP_P)
5929 frame->ip = ip;
5930 sp = do_icall_wrapper (frame, NULL, *ip, sp, frame->imethod->data_items [ip [1]], FALSE);
5931 EXCEPTION_CHECKPOINT;
5932 CHECK_RESUME_STATE (context);
5933 ip += 2;
5934 MINT_IN_BREAK;
5935 MINT_IN_CASE(MINT_MONO_LDPTR)
5936 sp->data.p = frame->imethod->data_items [ip [1]];
5937 ip += 2;
5938 ++sp;
5939 MINT_IN_BREAK;
5940 MINT_IN_CASE(MINT_MONO_NEWOBJ)
5941 sp->data.o = mono_interp_new (frame->imethod->domain, (MonoClass*)frame->imethod->data_items [ip [1]]); // FIXME: do not swallow the error
5942 ip += 2;
5943 sp++;
5944 MINT_IN_BREAK;
5945 MINT_IN_CASE(MINT_MONO_RETOBJ)
5946 ++ip;
5947 sp--;
5948 stackval_from_data (mono_method_signature_internal (frame->imethod->method)->ret, frame->retval, sp->data.p,
5949 mono_method_signature_internal (frame->imethod->method)->pinvoke);
5950 if (sp > frame->stack)
5951 g_warning ("retobj: more values on stack: %d", sp-frame->stack);
5952 goto exit_frame;
5953 MINT_IN_CASE(MINT_MONO_SGEN_THREAD_INFO)
5954 sp->data.p = mono_tls_get_sgen_thread_info ();
5955 sp++;
5956 ++ip;
5957 MINT_IN_BREAK;
5958 MINT_IN_CASE(MINT_MONO_MEMORY_BARRIER) {
5959 ++ip;
5960 mono_memory_barrier ();
5961 MINT_IN_BREAK;
5963 MINT_IN_CASE(MINT_MONO_LDDOMAIN)
5964 sp->data.p = mono_domain_get ();
5965 ++sp;
5966 ++ip;
5967 MINT_IN_BREAK;
5968 MINT_IN_CASE(MINT_SDB_INTR_LOC)
5969 if (G_UNLIKELY (ss_enabled)) {
5970 typedef void (*T) (void);
5971 static T ss_tramp;
5973 if (!ss_tramp) {
5974 void *tramp = mini_get_single_step_trampoline ();
5975 mono_memory_barrier ();
5976 ss_tramp = (T)tramp;
5980 * Make this point to the MINT_SDB_SEQ_POINT instruction which follows this since
5981 * the address of that instruction is stored as the seq point address.
5983 frame->ip = ip + 1;
5986 * Use the same trampoline as the JIT. This ensures that
5987 * the debugger has the context for the last interpreter
5988 * native frame.
5990 do_debugger_tramp (ss_tramp, frame);
5992 CHECK_RESUME_STATE (context);
5994 ++ip;
5995 MINT_IN_BREAK;
5996 MINT_IN_CASE(MINT_SDB_SEQ_POINT)
5997 /* Just a placeholder for a breakpoint */
5998 ++ip;
5999 MINT_IN_BREAK;
6000 MINT_IN_CASE(MINT_SDB_BREAKPOINT) {
6001 typedef void (*T) (void);
6002 static T bp_tramp;
6003 if (!bp_tramp) {
6004 void *tramp = mini_get_breakpoint_trampoline ();
6005 mono_memory_barrier ();
6006 bp_tramp = (T)tramp;
6009 frame->ip = ip;
6011 /* Use the same trampoline as the JIT */
6012 do_debugger_tramp (bp_tramp, frame);
6014 CHECK_RESUME_STATE (context);
6016 ++ip;
6017 MINT_IN_BREAK;
6020 #define RELOP(datamem, op) \
6021 --sp; \
6022 sp [-1].data.i = sp [-1].data.datamem op sp [0].data.datamem; \
6023 ++ip;
6025 #define RELOP_FP(datamem, op, noorder) \
6026 --sp; \
6027 if (mono_isunordered (sp [-1].data.datamem, sp [0].data.datamem)) \
6028 sp [-1].data.i = noorder; \
6029 else \
6030 sp [-1].data.i = sp [-1].data.datamem op sp [0].data.datamem; \
6031 ++ip;
6033 MINT_IN_CASE(MINT_CEQ_I4)
6034 RELOP(i, ==);
6035 MINT_IN_BREAK;
6036 MINT_IN_CASE(MINT_CEQ0_I4)
6037 sp [-1].data.i = (sp [-1].data.i == 0);
6038 ++ip;
6039 MINT_IN_BREAK;
6040 MINT_IN_CASE(MINT_CEQ_I8)
6041 RELOP(l, ==);
6042 MINT_IN_BREAK;
6043 MINT_IN_CASE(MINT_CEQ_R4)
6044 RELOP_FP(f_r4, ==, 0);
6045 MINT_IN_BREAK;
6046 MINT_IN_CASE(MINT_CEQ_R8)
6047 RELOP_FP(f, ==, 0);
6048 MINT_IN_BREAK;
6049 MINT_IN_CASE(MINT_CNE_I4)
6050 RELOP(i, !=);
6051 MINT_IN_BREAK;
6052 MINT_IN_CASE(MINT_CNE_I8)
6053 RELOP(l, !=);
6054 MINT_IN_BREAK;
6055 MINT_IN_CASE(MINT_CNE_R4)
6056 RELOP_FP(f_r4, !=, 1);
6057 MINT_IN_BREAK;
6058 MINT_IN_CASE(MINT_CNE_R8)
6059 RELOP_FP(f, !=, 1);
6060 MINT_IN_BREAK;
6061 MINT_IN_CASE(MINT_CGT_I4)
6062 RELOP(i, >);
6063 MINT_IN_BREAK;
6064 MINT_IN_CASE(MINT_CGT_I8)
6065 RELOP(l, >);
6066 MINT_IN_BREAK;
6067 MINT_IN_CASE(MINT_CGT_R4)
6068 RELOP_FP(f_r4, >, 0);
6069 MINT_IN_BREAK;
6070 MINT_IN_CASE(MINT_CGT_R8)
6071 RELOP_FP(f, >, 0);
6072 MINT_IN_BREAK;
6073 MINT_IN_CASE(MINT_CGE_I4)
6074 RELOP(i, >=);
6075 MINT_IN_BREAK;
6076 MINT_IN_CASE(MINT_CGE_I8)
6077 RELOP(l, >=);
6078 MINT_IN_BREAK;
6079 MINT_IN_CASE(MINT_CGE_R4)
6080 RELOP_FP(f_r4, >=, 0);
6081 MINT_IN_BREAK;
6082 MINT_IN_CASE(MINT_CGE_R8)
6083 RELOP_FP(f, >=, 0);
6084 MINT_IN_BREAK;
6086 #define RELOP_CAST(datamem, op, type) \
6087 --sp; \
6088 sp [-1].data.i = (type)sp [-1].data.datamem op (type)sp [0].data.datamem; \
6089 ++ip;
6091 MINT_IN_CASE(MINT_CGE_UN_I4)
6092 RELOP_CAST(l, >=, guint32);
6093 MINT_IN_BREAK;
6094 MINT_IN_CASE(MINT_CGE_UN_I8)
6095 RELOP_CAST(l, >=, guint64);
6096 MINT_IN_BREAK;
6098 MINT_IN_CASE(MINT_CGT_UN_I4)
6099 RELOP_CAST(i, >, guint32);
6100 MINT_IN_BREAK;
6101 MINT_IN_CASE(MINT_CGT_UN_I8)
6102 RELOP_CAST(l, >, guint64);
6103 MINT_IN_BREAK;
6104 MINT_IN_CASE(MINT_CGT_UN_R4)
6105 RELOP_FP(f_r4, >, 1);
6106 MINT_IN_BREAK;
6107 MINT_IN_CASE(MINT_CGT_UN_R8)
6108 RELOP_FP(f, >, 1);
6109 MINT_IN_BREAK;
6110 MINT_IN_CASE(MINT_CLT_I4)
6111 RELOP(i, <);
6112 MINT_IN_BREAK;
6113 MINT_IN_CASE(MINT_CLT_I8)
6114 RELOP(l, <);
6115 MINT_IN_BREAK;
6116 MINT_IN_CASE(MINT_CLT_R4)
6117 RELOP_FP(f_r4, <, 0);
6118 MINT_IN_BREAK;
6119 MINT_IN_CASE(MINT_CLT_R8)
6120 RELOP_FP(f, <, 0);
6121 MINT_IN_BREAK;
6122 MINT_IN_CASE(MINT_CLT_UN_I4)
6123 RELOP_CAST(i, <, guint32);
6124 MINT_IN_BREAK;
6125 MINT_IN_CASE(MINT_CLT_UN_I8)
6126 RELOP_CAST(l, <, guint64);
6127 MINT_IN_BREAK;
6128 MINT_IN_CASE(MINT_CLT_UN_R4)
6129 RELOP_FP(f_r4, <, 1);
6130 MINT_IN_BREAK;
6131 MINT_IN_CASE(MINT_CLT_UN_R8)
6132 RELOP_FP(f, <, 1);
6133 MINT_IN_BREAK;
6134 MINT_IN_CASE(MINT_CLE_I4)
6135 RELOP(i, <=);
6136 MINT_IN_BREAK;
6137 MINT_IN_CASE(MINT_CLE_I8)
6138 RELOP(l, <=);
6139 MINT_IN_BREAK;
6140 MINT_IN_CASE(MINT_CLE_UN_I4)
6141 RELOP_CAST(l, <=, guint32);
6142 MINT_IN_BREAK;
6143 MINT_IN_CASE(MINT_CLE_UN_I8)
6144 RELOP_CAST(l, <=, guint64);
6145 MINT_IN_BREAK;
6146 MINT_IN_CASE(MINT_CLE_R4)
6147 RELOP_FP(f_r4, <=, 0);
6148 MINT_IN_BREAK;
6149 MINT_IN_CASE(MINT_CLE_R8)
6150 RELOP_FP(f, <=, 0);
6151 MINT_IN_BREAK;
6153 #undef RELOP
6154 #undef RELOP_FP
6155 #undef RELOP_CAST
6157 MINT_IN_CASE(MINT_LDFTN) {
6158 sp->data.p = frame->imethod->data_items [ip [1]];
6159 ++sp;
6160 ip += 2;
6161 MINT_IN_BREAK;
6163 MINT_IN_CASE(MINT_LDVIRTFTN) {
6164 InterpMethod *m = (InterpMethod*)frame->imethod->data_items [ip [1]];
6165 --sp;
6166 NULL_CHECK (sp->data.p);
6168 sp->data.p = get_virtual_method (m, sp->data.o->vtable);
6169 ip += 2;
6170 ++sp;
6171 MINT_IN_BREAK;
6173 MINT_IN_CASE(MINT_LDFTN_DYNAMIC) {
6174 MONO_API_ERROR_INIT (error);
6175 InterpMethod *m = mono_interp_get_imethod (mono_domain_get (), (MonoMethod*) sp [-1].data.p, error);
6176 mono_error_assert_ok (error);
6177 sp [-1].data.p = m;
6178 ip++;
6179 MINT_IN_BREAK;
6182 #define LDARG(datamem, argtype) \
6183 sp->data.datamem = (argtype) frame->stack_args [ip [1]].data.datamem; \
6184 ip += 2; \
6185 ++sp;
6187 #define LDARGn(datamem, argtype, n) \
6188 sp->data.datamem = (argtype) frame->stack_args [n].data.datamem; \
6189 ++ip; \
6190 ++sp;
6192 MINT_IN_CASE(MINT_LDARG_I1) LDARG(i, gint8); MINT_IN_BREAK;
6193 MINT_IN_CASE(MINT_LDARG_U1) LDARG(i, guint8); MINT_IN_BREAK;
6194 MINT_IN_CASE(MINT_LDARG_I2) LDARG(i, gint16); MINT_IN_BREAK;
6195 MINT_IN_CASE(MINT_LDARG_U2) LDARG(i, guint16); MINT_IN_BREAK;
6196 MINT_IN_CASE(MINT_LDARG_I4) LDARG(i, gint32); MINT_IN_BREAK;
6197 MINT_IN_CASE(MINT_LDARG_I8) LDARG(l, gint64); MINT_IN_BREAK;
6198 MINT_IN_CASE(MINT_LDARG_R4) LDARG(f_r4, float); MINT_IN_BREAK;
6199 MINT_IN_CASE(MINT_LDARG_R8) LDARG(f, double); MINT_IN_BREAK;
6200 MINT_IN_CASE(MINT_LDARG_O) LDARG(p, gpointer); MINT_IN_BREAK;
6201 MINT_IN_CASE(MINT_LDARG_P) LDARG(p, gpointer); MINT_IN_BREAK;
6203 MINT_IN_CASE(MINT_LDARG_P0) LDARGn(p, gpointer, 0); MINT_IN_BREAK;
6205 MINT_IN_CASE(MINT_LDARG_VT) {
6206 sp->data.p = vt_sp;
6207 int const i32 = READ32 (ip + 2);
6208 memcpy(sp->data.p, frame->stack_args [ip [1]].data.p, i32);
6209 vt_sp += ALIGN_TO (i32, MINT_VT_ALIGNMENT);
6210 ip += 4;
6211 ++sp;
6212 MINT_IN_BREAK;
6215 #define STARG(datamem, argtype) \
6216 --sp; \
6217 frame->stack_args [ip [1]].data.datamem = (argtype) sp->data.datamem; \
6218 ip += 2; \
6220 MINT_IN_CASE(MINT_STARG_I1) STARG(i, gint8); MINT_IN_BREAK;
6221 MINT_IN_CASE(MINT_STARG_U1) STARG(i, guint8); MINT_IN_BREAK;
6222 MINT_IN_CASE(MINT_STARG_I2) STARG(i, gint16); MINT_IN_BREAK;
6223 MINT_IN_CASE(MINT_STARG_U2) STARG(i, guint16); MINT_IN_BREAK;
6224 MINT_IN_CASE(MINT_STARG_I4) STARG(i, gint32); MINT_IN_BREAK;
6225 MINT_IN_CASE(MINT_STARG_I8) STARG(l, gint64); MINT_IN_BREAK;
6226 MINT_IN_CASE(MINT_STARG_R4) STARG(f_r4, float); MINT_IN_BREAK;
6227 MINT_IN_CASE(MINT_STARG_R8) STARG(f, double); MINT_IN_BREAK;
6228 MINT_IN_CASE(MINT_STARG_O) STARG(p, gpointer); MINT_IN_BREAK;
6229 MINT_IN_CASE(MINT_STARG_P) STARG(p, gpointer); MINT_IN_BREAK;
6231 MINT_IN_CASE(MINT_STARG_VT) {
6232 int const i32 = READ32 (ip + 2);
6233 --sp;
6234 memcpy(frame->stack_args [ip [1]].data.p, sp->data.p, i32);
6235 vt_sp -= ALIGN_TO (i32, MINT_VT_ALIGNMENT);
6236 ip += 4;
6237 MINT_IN_BREAK;
6239 MINT_IN_CASE(MINT_PROF_ENTER) {
6240 ip += 1;
6242 if (MONO_PROFILER_ENABLED (method_enter)) {
6243 MonoProfilerCallContext *prof_ctx = NULL;
6245 if (frame->imethod->prof_flags & MONO_PROFILER_CALL_INSTRUMENTATION_ENTER_CONTEXT) {
6246 prof_ctx = g_new0 (MonoProfilerCallContext, 1);
6247 prof_ctx->interp_frame = frame;
6248 prof_ctx->method = frame->imethod->method;
6251 MONO_PROFILER_RAISE (method_enter, (frame->imethod->method, prof_ctx));
6253 g_free (prof_ctx);
6256 MINT_IN_BREAK;
6259 MINT_IN_CASE(MINT_TRACE_ENTER) {
6260 ip += 1;
6262 MonoProfilerCallContext *prof_ctx = g_alloca (sizeof (MonoProfilerCallContext));
6263 prof_ctx->interp_frame = frame;
6264 prof_ctx->method = frame->imethod->method;
6266 mono_trace_enter_method (frame->imethod->method, prof_ctx);
6267 MINT_IN_BREAK;
6270 MINT_IN_CASE(MINT_TRACE_EXIT) {
6271 // Set retval
6272 int const i32 = READ32 (ip + 1);
6273 --sp;
6274 if (i32 == -1)
6276 else if (i32)
6277 memcpy(frame->retval->data.p, sp->data.p, i32);
6278 else
6279 *frame->retval = *sp;
6281 MonoProfilerCallContext *prof_ctx = g_alloca (sizeof (MonoProfilerCallContext));
6282 prof_ctx->interp_frame = frame;
6283 prof_ctx->method = frame->imethod->method;
6285 mono_trace_leave_method (frame->imethod->method, prof_ctx);
6286 ip += 3;
6287 goto exit_frame;
6290 MINT_IN_CASE(MINT_LDARGA)
6291 sp->data.p = &frame->stack_args [ip [1]];
6292 ip += 2;
6293 ++sp;
6294 MINT_IN_BREAK;
6296 MINT_IN_CASE(MINT_LDARGA_VT)
6297 sp->data.p = frame->stack_args [ip [1]].data.p;
6298 ip += 2;
6299 ++sp;
6300 MINT_IN_BREAK;
6302 #define LDLOC(datamem, argtype) \
6303 sp->data.datamem = * (argtype *)(locals + ip [1]); \
6304 ip += 2; \
6305 ++sp;
6307 MINT_IN_CASE(MINT_LDLOC_I1) LDLOC(i, gint8); MINT_IN_BREAK;
6308 MINT_IN_CASE(MINT_LDLOC_U1) LDLOC(i, guint8); MINT_IN_BREAK;
6309 MINT_IN_CASE(MINT_LDLOC_I2) LDLOC(i, gint16); MINT_IN_BREAK;
6310 MINT_IN_CASE(MINT_LDLOC_U2) LDLOC(i, guint16); MINT_IN_BREAK;
6311 MINT_IN_CASE(MINT_LDLOC_I4) LDLOC(i, gint32); MINT_IN_BREAK;
6312 MINT_IN_CASE(MINT_LDLOC_I8) LDLOC(l, gint64); MINT_IN_BREAK;
6313 MINT_IN_CASE(MINT_LDLOC_R4) LDLOC(f_r4, float); MINT_IN_BREAK;
6314 MINT_IN_CASE(MINT_LDLOC_R8) LDLOC(f, double); MINT_IN_BREAK;
6315 MINT_IN_CASE(MINT_LDLOC_O) LDLOC(p, gpointer); MINT_IN_BREAK;
6316 MINT_IN_CASE(MINT_LDLOC_P) LDLOC(p, gpointer); MINT_IN_BREAK;
6318 MINT_IN_CASE(MINT_LDLOC_VT) {
6319 sp->data.p = vt_sp;
6320 int const i32 = READ32 (ip + 2);
6321 memcpy(sp->data.p, locals + ip [1], i32);
6322 vt_sp += ALIGN_TO (i32, MINT_VT_ALIGNMENT);
6323 ip += 4;
6324 ++sp;
6325 MINT_IN_BREAK;
6327 MINT_IN_CASE(MINT_LDLOCA_S)
6328 sp->data.p = locals + ip [1];
6329 ip += 2;
6330 ++sp;
6331 MINT_IN_BREAK;
6333 #define STLOC(datamem, argtype) \
6334 --sp; \
6335 * (argtype *)(locals + ip [1]) = sp->data.datamem; \
6336 ip += 2;
6338 MINT_IN_CASE(MINT_STLOC_I1) STLOC(i, gint8); MINT_IN_BREAK;
6339 MINT_IN_CASE(MINT_STLOC_U1) STLOC(i, guint8); MINT_IN_BREAK;
6340 MINT_IN_CASE(MINT_STLOC_I2) STLOC(i, gint16); MINT_IN_BREAK;
6341 MINT_IN_CASE(MINT_STLOC_U2) STLOC(i, guint16); MINT_IN_BREAK;
6342 MINT_IN_CASE(MINT_STLOC_I4) STLOC(i, gint32); MINT_IN_BREAK;
6343 MINT_IN_CASE(MINT_STLOC_I8) STLOC(l, gint64); MINT_IN_BREAK;
6344 MINT_IN_CASE(MINT_STLOC_R4) STLOC(f_r4, float); MINT_IN_BREAK;
6345 MINT_IN_CASE(MINT_STLOC_R8) STLOC(f, double); MINT_IN_BREAK;
6346 MINT_IN_CASE(MINT_STLOC_O) STLOC(p, gpointer); MINT_IN_BREAK;
6347 MINT_IN_CASE(MINT_STLOC_P) STLOC(p, gpointer); MINT_IN_BREAK;
6349 #define STLOC_NP(datamem, argtype) \
6350 * (argtype *)(locals + ip [1]) = sp [-1].data.datamem; \
6351 ip += 2;
6353 MINT_IN_CASE(MINT_STLOC_NP_I4) STLOC_NP(i, gint32); MINT_IN_BREAK;
6354 MINT_IN_CASE(MINT_STLOC_NP_O) STLOC_NP(p, gpointer); MINT_IN_BREAK;
6356 MINT_IN_CASE(MINT_STLOC_VT) {
6357 int const i32 = READ32 (ip + 2);
6358 --sp;
6359 memcpy(locals + ip [1], sp->data.p, i32);
6360 vt_sp -= ALIGN_TO (i32, MINT_VT_ALIGNMENT);
6361 ip += 4;
6362 MINT_IN_BREAK;
6365 #define MOVLOC(argtype) \
6366 * (argtype *)(locals + ip [2]) = * (argtype *)(locals + ip [1]); \
6367 ip += 3;
6369 MINT_IN_CASE(MINT_MOVLOC_1) MOVLOC(guint8); MINT_IN_BREAK;
6370 MINT_IN_CASE(MINT_MOVLOC_2) MOVLOC(guint16); MINT_IN_BREAK;
6371 MINT_IN_CASE(MINT_MOVLOC_4) MOVLOC(guint32); MINT_IN_BREAK;
6372 MINT_IN_CASE(MINT_MOVLOC_8) MOVLOC(guint64); MINT_IN_BREAK;
6374 MINT_IN_CASE(MINT_MOVLOC_VT) {
6375 int const i32 = READ32(ip + 3);
6376 memcpy (locals + ip [2], locals + ip [1], i32);
6377 ip += 5;
6378 MINT_IN_BREAK;
6381 MINT_IN_CASE(MINT_LOCALLOC) {
6382 if (sp != frame->stack + 1) /*FIX?*/
6383 goto abort_label;
6385 int len = sp [-1].data.i;
6386 sp [-1].data.p = alloca (len);
6388 if (frame->imethod->init_locals)
6389 memset (sp [-1].data.p, 0, len);
6390 ++ip;
6391 MINT_IN_BREAK;
6393 MINT_IN_CASE(MINT_ENDFILTER)
6394 /* top of stack is result of filter */
6395 frame->retval = &sp [-1];
6396 goto exit_frame;
6397 MINT_IN_CASE(MINT_INITOBJ)
6398 --sp;
6399 memset (sp->data.vt, 0, READ32(ip + 1));
6400 ip += 3;
6401 MINT_IN_BREAK;
6402 MINT_IN_CASE(MINT_CPBLK)
6403 sp -= 3;
6404 if (!sp [0].data.p || !sp [1].data.p)
6405 THROW_EX (mono_get_exception_null_reference(), ip - 1);
6406 ++ip;
6407 /* FIXME: value and size may be int64... */
6408 memcpy (sp [0].data.p, sp [1].data.p, sp [2].data.i);
6409 MINT_IN_BREAK;
6410 #if 0
6411 MINT_IN_CASE(MINT_CONSTRAINED_) {
6412 guint32 token;
6413 /* FIXME: implement */
6414 ++ip;
6415 token = READ32 (ip);
6416 ip += 2;
6417 MINT_IN_BREAK;
6419 #endif
6420 MINT_IN_CASE(MINT_INITBLK)
6421 sp -= 3;
6422 NULL_CHECK (sp [0].data.p);
6423 ++ip;
6424 /* FIXME: value and size may be int64... */
6425 memset (sp [0].data.p, sp [1].data.i, sp [2].data.i);
6426 MINT_IN_BREAK;
6427 #if 0
6428 MINT_IN_CASE(MINT_NO_)
6429 /* FIXME: implement */
6430 ip += 2;
6431 MINT_IN_BREAK;
6432 #endif
6433 MINT_IN_CASE(MINT_RETHROW) {
6434 int exvar_offset = ip [1];
6435 THROW_EX_GENERAL (*(MonoException**)(frame_locals (frame) + exvar_offset), ip, TRUE);
6436 MINT_IN_BREAK;
6438 MINT_IN_CASE(MINT_MONO_RETHROW) {
6440 * need to clarify what this should actually do:
6442 * Takes an exception from the stack and rethrows it.
6443 * This is useful for wrappers that don't want to have to
6444 * use CEE_THROW and lose the exception stacktrace.
6447 --sp;
6448 if (!sp->data.p)
6449 sp->data.p = mono_get_exception_null_reference ();
6451 THROW_EX_GENERAL ((MonoException *)sp->data.p, ip, TRUE);
6452 MINT_IN_BREAK;
6454 MINT_IN_CASE(MINT_LD_DELEGATE_METHOD_PTR) {
6455 MonoDelegate *del;
6457 --sp;
6458 del = (MonoDelegate*)sp->data.p;
6459 if (!del->interp_method) {
6460 /* Not created from interpreted code */
6461 MONO_API_ERROR_INIT (error);
6462 g_assert (del->method);
6463 del->interp_method = mono_interp_get_imethod (del->object.vtable->domain, del->method, error);
6464 mono_error_assert_ok (error);
6466 g_assert (del->interp_method);
6467 sp->data.p = del->interp_method;
6468 ++sp;
6469 ip += 1;
6470 MINT_IN_BREAK;
6472 MINT_IN_CASE(MINT_LD_DELEGATE_INVOKE_IMPL) {
6473 MonoDelegate *del;
6474 int n = ip [1];
6475 del = (MonoDelegate*)sp [-n].data.p;
6476 if (!del->interp_invoke_impl) {
6478 * First time we are called. Set up the invoke wrapper. We might be able to do this
6479 * in ctor but we would need to handle AllocDelegateLike_internal separately
6481 MONO_API_ERROR_INIT (error);
6482 MonoMethod *invoke = mono_get_delegate_invoke_internal (del->object.vtable->klass);
6483 del->interp_invoke_impl = mono_interp_get_imethod (del->object.vtable->domain, mono_marshal_get_delegate_invoke (invoke, del), error);
6484 mono_error_assert_ok (error);
6486 sp ++;
6487 sp [-1].data.p = del->interp_invoke_impl;
6488 ip += 2;
6489 MINT_IN_BREAK;
6492 #define MATH_UNOP(mathfunc) \
6493 sp [-1].data.f = mathfunc (sp [-1].data.f); \
6494 ++ip;
6496 MINT_IN_CASE(MINT_ABS) MATH_UNOP(fabs); MINT_IN_BREAK;
6497 MINT_IN_CASE(MINT_ASIN) MATH_UNOP(asin); MINT_IN_BREAK;
6498 MINT_IN_CASE(MINT_ASINH) MATH_UNOP(asinh); MINT_IN_BREAK;
6499 MINT_IN_CASE(MINT_ACOS) MATH_UNOP(acos); MINT_IN_BREAK;
6500 MINT_IN_CASE(MINT_ACOSH) MATH_UNOP(acosh); MINT_IN_BREAK;
6501 MINT_IN_CASE(MINT_ATAN) MATH_UNOP(atan); MINT_IN_BREAK;
6502 MINT_IN_CASE(MINT_ATANH) MATH_UNOP(atanh); MINT_IN_BREAK;
6503 MINT_IN_CASE(MINT_COS) MATH_UNOP(cos); MINT_IN_BREAK;
6504 MINT_IN_CASE(MINT_CBRT) MATH_UNOP(cbrt); MINT_IN_BREAK;
6505 MINT_IN_CASE(MINT_COSH) MATH_UNOP(cosh); MINT_IN_BREAK;
6506 MINT_IN_CASE(MINT_SIN) MATH_UNOP(sin); MINT_IN_BREAK;
6507 MINT_IN_CASE(MINT_SQRT) MATH_UNOP(sqrt); MINT_IN_BREAK;
6508 MINT_IN_CASE(MINT_SINH) MATH_UNOP(sinh); MINT_IN_BREAK;
6509 MINT_IN_CASE(MINT_TAN) MATH_UNOP(tan); MINT_IN_BREAK;
6510 MINT_IN_CASE(MINT_TANH) MATH_UNOP(tanh); MINT_IN_BREAK;
6512 MINT_IN_CASE(MINT_INTRINS_ENUM_HASFLAG) {
6513 MonoClass *klass = (MonoClass*)frame->imethod->data_items[ip [1]];
6514 mono_interp_enum_hasflag (sp, klass);
6515 sp--;
6516 ip += 2;
6517 MINT_IN_BREAK;
6519 MINT_IN_CASE(MINT_INTRINS_GET_HASHCODE) {
6520 sp [-1].data.i = mono_object_hash_internal (sp [-1].data.o);
6521 ip++;
6522 MINT_IN_BREAK;
6524 MINT_IN_CASE(MINT_INTRINS_GET_TYPE) {
6525 NULL_CHECK (sp [-1].data.p);
6526 sp [-1].data.o = (MonoObject*) sp [-1].data.o->vtable->type;
6527 ip++;
6528 MINT_IN_BREAK;
6531 MINT_IN_DEFAULT
6532 g_error ("Unimplemented opcode: %04x %s at 0x%x\n", *ip, mono_interp_opname (*ip), ip - frame->imethod->code);
6536 g_assert_not_reached ();
6538 abort_label:
6539 THROW_EX (mono_get_exception_execution_engine (NULL), ip);
6540 null_label:
6541 THROW_EX (mono_get_exception_null_reference (), ip);
6542 div_zero_label:
6543 THROW_EX (mono_get_exception_divide_by_zero (), ip);
6544 overflow_label:
6545 THROW_EX (mono_get_exception_overflow (), ip);
6546 throw_error_label:
6547 THROW_EX (mono_error_convert_to_exception (error), ip);
6548 invalid_cast_label:
6549 THROW_EX (mono_get_exception_invalid_cast (), ip);
6550 resume:
6551 g_assert (context->has_resume_state);
6553 if (frame == context->handler_frame && (!clause_args || context->handler_ip < clause_args->end_at_ip)) {
6554 /* Set the current execution state to the resume state in context */
6556 ip = context->handler_ip;
6557 /* spec says stack should be empty at endfinally so it should be at the start too */
6558 sp = frame->stack;
6559 vt_sp = (guchar*)sp + frame->imethod->stack_size;
6560 g_assert (context->exc_gchandle);
6561 sp->data.p = mono_gchandle_get_target_internal (context->exc_gchandle);
6562 ++sp;
6564 finally_ips = clear_resume_state (context, finally_ips);
6565 // goto main_loop instead of MINT_IN_DISPATCH helps the compiler and therefore conserves stack.
6566 // This is a slow/rare path and conserving stack is preferred over its performance otherwise.
6567 goto main_loop;
6569 // fall through
6570 exit_frame:
6571 error_init_reuse (error);
6573 if (clause_args && clause_args->base_frame)
6574 memcpy (clause_args->base_frame->stack, frame->stack, frame->imethod->alloca_size);
6576 if (!context->has_resume_state && MONO_PROFILER_ENABLED (method_leave) &&
6577 frame->imethod->prof_flags & MONO_PROFILER_CALL_INSTRUMENTATION_LEAVE) {
6578 MonoProfilerCallContext *prof_ctx = NULL;
6580 if (frame->imethod->prof_flags & MONO_PROFILER_CALL_INSTRUMENTATION_LEAVE_CONTEXT) {
6581 prof_ctx = g_new0 (MonoProfilerCallContext, 1);
6582 prof_ctx->interp_frame = frame;
6583 prof_ctx->method = frame->imethod->method;
6585 MonoType *rtype = mono_method_signature_internal (frame->imethod->method)->ret;
6587 switch (rtype->type) {
6588 case MONO_TYPE_VOID:
6589 break;
6590 case MONO_TYPE_VALUETYPE:
6591 prof_ctx->return_value = frame->retval->data.p;
6592 break;
6593 default:
6594 prof_ctx->return_value = frame->retval;
6595 break;
6599 MONO_PROFILER_RAISE (method_leave, (frame->imethod->method, prof_ctx));
6601 g_free (prof_ctx);
6602 } else if (context->has_resume_state && frame->imethod->prof_flags & MONO_PROFILER_CALL_INSTRUMENTATION_EXCEPTION_LEAVE)
6603 MONO_PROFILER_RAISE (method_exception_leave, (frame->imethod->method, mono_gchandle_get_target_internal (context->exc_gchandle)));
6605 DEBUG_LEAVE ();
6608 static void
6609 interp_parse_options (const char *options)
6611 char **args, **ptr;
6613 if (!options)
6614 return;
6616 args = g_strsplit (options, ",", -1);
6617 for (ptr = args; ptr && *ptr; ptr ++) {
6618 char *arg = *ptr;
6620 if (strncmp (arg, "jit=", 4) == 0)
6621 mono_interp_jit_classes = g_slist_prepend (mono_interp_jit_classes, arg + 4);
6622 if (strncmp (arg, "interp-only=", strlen ("interp-only=")) == 0)
6623 mono_interp_only_classes = g_slist_prepend (mono_interp_only_classes, arg + strlen ("interp-only="));
6624 if (strncmp (arg, "-inline", 7) == 0)
6625 mono_interp_opt &= ~INTERP_OPT_INLINE;
6626 if (strncmp (arg, "-cprop", 6) == 0)
6627 mono_interp_opt &= ~INTERP_OPT_CPROP;
6632 * interp_set_resume_state:
6634 * Set the state the interpeter will continue to execute from after execution returns to the interpreter.
6636 static void
6637 interp_set_resume_state (MonoJitTlsData *jit_tls, MonoException *ex, MonoJitExceptionInfo *ei, MonoInterpFrameHandle interp_frame, gpointer handler_ip)
6639 ThreadContext *context;
6641 g_assert (jit_tls);
6642 context = (ThreadContext*)jit_tls->interp_context;
6643 g_assert (context);
6645 context->has_resume_state = TRUE;
6646 context->handler_frame = (InterpFrame*)interp_frame;
6647 context->handler_ei = ei;
6648 if (context->exc_gchandle)
6649 mono_gchandle_free_internal (context->exc_gchandle);
6650 context->exc_gchandle = mono_gchandle_new_internal ((MonoObject*)ex, FALSE);
6651 /* Ditto */
6652 if (ei)
6653 *(MonoException**)(frame_locals (context->handler_frame) + ei->exvar_offset) = ex;
6654 context->handler_ip = (const guint16*)handler_ip;
6657 static void
6658 interp_get_resume_state (const MonoJitTlsData *jit_tls, gboolean *has_resume_state, MonoInterpFrameHandle *interp_frame, gpointer *handler_ip)
6660 g_assert (jit_tls);
6661 ThreadContext *context = (ThreadContext*)jit_tls->interp_context;
6662 g_assert (context);
6663 *has_resume_state = context->has_resume_state;
6664 if (context->has_resume_state) {
6665 *interp_frame = context->handler_frame;
6666 *handler_ip = (gpointer)context->handler_ip;
6671 * interp_run_finally:
6673 * Run the finally clause identified by CLAUSE_INDEX in the intepreter frame given by
6674 * frame->interp_frame.
6675 * Return TRUE if the finally clause threw an exception.
6677 static gboolean
6678 interp_run_finally (StackFrameInfo *frame, int clause_index, gpointer handler_ip, gpointer handler_ip_end)
6680 InterpFrame *iframe = (InterpFrame*)frame->interp_frame;
6681 ThreadContext *context = get_context ();
6682 const unsigned short *old_ip = iframe->ip;
6683 FrameClauseArgs clause_args;
6685 memset (&clause_args, 0, sizeof (FrameClauseArgs));
6686 clause_args.start_with_ip = (const guint16*)handler_ip;
6687 clause_args.end_at_ip = (const guint16*)handler_ip_end;
6688 clause_args.exit_clause = clause_index;
6690 ERROR_DECL (error);
6691 interp_exec_method_full (iframe, context, &clause_args, error);
6692 if (context->has_resume_state) {
6693 return TRUE;
6694 } else {
6695 iframe->ip = old_ip;
6696 return FALSE;
6701 * interp_run_filter:
6703 * Run the filter clause identified by CLAUSE_INDEX in the intepreter frame given by
6704 * frame->interp_frame.
6706 static gboolean
6707 interp_run_filter (StackFrameInfo *frame, MonoException *ex, int clause_index, gpointer handler_ip, gpointer handler_ip_end)
6709 InterpFrame *iframe = (InterpFrame*)frame->interp_frame;
6710 ThreadContext *context = get_context ();
6711 InterpFrame child_frame;
6712 stackval retval;
6713 FrameClauseArgs clause_args;
6716 * Have to run the clause in a new frame which is a copy of IFRAME, since
6717 * during debugging, there are two copies of the frame on the stack.
6719 memset (&child_frame, 0, sizeof (InterpFrame));
6720 child_frame.imethod = iframe->imethod;
6721 child_frame.retval = &retval;
6722 child_frame.parent = iframe;
6723 child_frame.stack_args = iframe->stack_args;
6725 memset (&clause_args, 0, sizeof (FrameClauseArgs));
6726 clause_args.start_with_ip = (const guint16*)handler_ip;
6727 clause_args.end_at_ip = (const guint16*)handler_ip_end;
6728 clause_args.filter_exception = ex;
6729 clause_args.base_frame = iframe;
6731 ERROR_DECL (error);
6732 interp_exec_method_full (&child_frame, context, &clause_args, error);
6733 /* ENDFILTER stores the result into child_frame->retval */
6734 return child_frame.retval->data.i ? TRUE : FALSE;
6737 typedef struct {
6738 InterpFrame *current;
6739 } StackIter;
6742 * interp_frame_iter_init:
6744 * Initialize an iterator for iterating through interpreted frames.
6746 static void
6747 interp_frame_iter_init (MonoInterpStackIter *iter, gpointer interp_exit_data)
6749 StackIter *stack_iter = (StackIter*)iter;
6751 stack_iter->current = (InterpFrame*)interp_exit_data;
6755 * interp_frame_iter_next:
6757 * Fill out FRAME with date for the next interpreter frame.
6759 static gboolean
6760 interp_frame_iter_next (MonoInterpStackIter *iter, StackFrameInfo *frame)
6762 StackIter *stack_iter = (StackIter*)iter;
6763 InterpFrame *iframe = stack_iter->current;
6765 memset (frame, 0, sizeof (StackFrameInfo));
6766 /* pinvoke frames doesn't have imethod set */
6767 while (iframe && !(iframe->imethod && iframe->imethod->code && iframe->imethod->jinfo))
6768 iframe = iframe->parent;
6769 if (!iframe)
6770 return FALSE;
6772 MonoMethod *method = iframe->imethod->method;
6773 frame->domain = iframe->imethod->domain;
6774 frame->interp_frame = iframe;
6775 frame->method = method;
6776 frame->actual_method = method;
6777 if (method && ((method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) || (method->iflags & (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL | METHOD_IMPL_ATTRIBUTE_RUNTIME)))) {
6778 frame->native_offset = -1;
6779 frame->type = FRAME_TYPE_MANAGED_TO_NATIVE;
6780 } else {
6781 frame->type = FRAME_TYPE_INTERP;
6782 /* This is the offset in the interpreter IR */
6783 frame->native_offset = (guint8*)iframe->ip - (guint8*)iframe->imethod->code;
6784 if (!method->wrapper_type || method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD)
6785 frame->managed = TRUE;
6787 frame->ji = iframe->imethod->jinfo;
6788 frame->frame_addr = iframe;
6790 stack_iter->current = iframe->parent;
6792 return TRUE;
6795 static MonoJitInfo*
6796 interp_find_jit_info (MonoDomain *domain, MonoMethod *method)
6798 InterpMethod* imethod;
6800 imethod = lookup_imethod (domain, method);
6801 if (imethod)
6802 return imethod->jinfo;
6803 else
6804 return NULL;
6807 static void
6808 interp_set_breakpoint (MonoJitInfo *jinfo, gpointer ip)
6810 guint16 *code = (guint16*)ip;
6811 g_assert (*code == MINT_SDB_SEQ_POINT);
6812 *code = MINT_SDB_BREAKPOINT;
6815 static void
6816 interp_clear_breakpoint (MonoJitInfo *jinfo, gpointer ip)
6818 guint16 *code = (guint16*)ip;
6819 g_assert (*code == MINT_SDB_BREAKPOINT);
6820 *code = MINT_SDB_SEQ_POINT;
6823 static MonoJitInfo*
6824 interp_frame_get_jit_info (MonoInterpFrameHandle frame)
6826 InterpFrame *iframe = (InterpFrame*)frame;
6828 g_assert (iframe->imethod);
6829 return iframe->imethod->jinfo;
6832 static gpointer
6833 interp_frame_get_ip (MonoInterpFrameHandle frame)
6835 InterpFrame *iframe = (InterpFrame*)frame;
6837 g_assert (iframe->imethod);
6838 return (gpointer)iframe->ip;
6841 static gpointer
6842 interp_frame_get_arg (MonoInterpFrameHandle frame, int pos)
6844 InterpFrame *iframe = (InterpFrame*)frame;
6845 MonoMethodSignature *sig;
6847 g_assert (iframe->imethod);
6849 sig = mono_method_signature_internal (iframe->imethod->method);
6850 return stackval_to_data_addr (sig->params [pos], &iframe->stack_args [pos + !!iframe->imethod->hasthis]);
6853 static gpointer
6854 interp_frame_get_local (MonoInterpFrameHandle frame, int pos)
6856 InterpFrame *iframe = (InterpFrame*)frame;
6858 g_assert (iframe->imethod);
6860 return frame_locals (iframe) + iframe->imethod->local_offsets [pos];
6863 static gpointer
6864 interp_frame_get_this (MonoInterpFrameHandle frame)
6866 InterpFrame *iframe = (InterpFrame*)frame;
6868 g_assert (iframe->imethod);
6869 g_assert (iframe->imethod->hasthis);
6870 return &iframe->stack_args [0].data.p;
6873 static MonoInterpFrameHandle
6874 interp_frame_get_parent (MonoInterpFrameHandle frame)
6876 InterpFrame *iframe = (InterpFrame*)frame;
6878 return iframe->parent;
6881 static gpointer
6882 interp_frame_get_res (MonoInterpFrameHandle frame)
6884 InterpFrame *iframe = (InterpFrame*)frame;
6885 MonoMethodSignature *sig;
6887 g_assert (iframe->imethod);
6888 sig = mono_method_signature_internal (iframe->imethod->method);
6889 if (sig->ret->type == MONO_TYPE_VOID)
6890 return NULL;
6891 else
6892 return stackval_to_data_addr (sig->ret, iframe->retval);
6895 static void
6896 interp_start_single_stepping (void)
6898 ss_enabled = TRUE;
6901 static void
6902 interp_stop_single_stepping (void)
6904 ss_enabled = FALSE;
6907 #if COUNT_OPS
6909 static int
6910 opcode_count_comparer (const void * pa, const void * pb)
6912 long counta = opcode_counts [*(int*)pa];
6913 long countb = opcode_counts [*(int*)pb];
6915 if (counta < countb)
6916 return 1;
6917 else if (counta > countb)
6918 return -1;
6919 else
6920 return 0;
6923 static void
6924 interp_print_op_count (void)
6926 int ordered_ops [MINT_LASTOP];
6927 int i;
6928 long total_ops = 0;
6930 for (i = 0; i < MINT_LASTOP; i++) {
6931 ordered_ops [i] = i;
6932 total_ops += opcode_counts [i];
6934 qsort (ordered_ops, MINT_LASTOP, sizeof (int), opcode_count_comparer);
6936 for (i = 0; i < MINT_LASTOP; i++) {
6937 long count = opcode_counts [ordered_ops [i]];
6938 g_print ("%s : %ld (%.2lf%%)\n", mono_interp_opname (ordered_ops [i]), count, (double)count / total_ops * 100);
6941 #endif
6943 static void
6944 interp_cleanup (void)
6946 #if COUNT_OPS
6947 interp_print_op_count ();
6948 #endif
6951 static void
6952 register_interp_stats (void)
6954 mono_counters_init ();
6955 mono_counters_register ("Total transform time", MONO_COUNTER_INTERP | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_interp_stats.transform_time);
6956 mono_counters_register ("Total cprop time", MONO_COUNTER_INTERP | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_interp_stats.cprop_time);
6957 mono_counters_register ("STLOC_NP count", MONO_COUNTER_INTERP | MONO_COUNTER_INT, &mono_interp_stats.stloc_nps);
6958 mono_counters_register ("MOVLOC count", MONO_COUNTER_INTERP | MONO_COUNTER_INT, &mono_interp_stats.movlocs);
6959 mono_counters_register ("Copy propagations", MONO_COUNTER_INTERP | MONO_COUNTER_INT, &mono_interp_stats.copy_propagations);
6960 mono_counters_register ("Killed instructions", MONO_COUNTER_INTERP | MONO_COUNTER_INT, &mono_interp_stats.killed_instructions);
6961 mono_counters_register ("Methods inlined", MONO_COUNTER_INTERP | MONO_COUNTER_INT, &mono_interp_stats.inlined_methods);
6962 mono_counters_register ("Inline failures", MONO_COUNTER_INTERP | MONO_COUNTER_INT, &mono_interp_stats.inline_failures);
6965 #undef MONO_EE_CALLBACK
6966 #define MONO_EE_CALLBACK(ret, name, sig) interp_ ## name,
6968 static const MonoEECallbacks mono_interp_callbacks = {
6969 MONO_EE_CALLBACKS
6972 void
6973 mono_ee_interp_init (const char *opts)
6975 g_assert (mono_ee_api_version () == MONO_EE_API_VERSION);
6976 g_assert (!interp_init_done);
6977 interp_init_done = TRUE;
6979 mono_native_tls_alloc (&thread_context_id, NULL);
6980 set_context (NULL);
6982 interp_parse_options (opts);
6983 /* Don't do any optimizations if running under debugger */
6984 if (mini_get_debug_options ()->mdb_optimizations)
6985 mono_interp_opt = 0;
6986 mono_interp_transform_init ();
6988 mini_install_interp_callbacks (&mono_interp_callbacks);
6990 register_interp_stats ();