[interp] Replace frame_objref with a volatile store to local. (#16790)
[mono-project.git] / mono / mini / interp / interp.c
blob2e118f2f0df2011d7fd17e94fd35b7108e01ddfd
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 MONO_NEVER_INLINE MonoException*
1007 ves_array_set (InterpFrame *frame, stackval *sp, MonoMethodSignature *sig)
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, TRUE);
1016 if (pos == -1)
1017 return mono_get_exception_index_out_of_range ();
1019 int val_index = 1 + m_class_get_rank (ac);
1020 if (sp [val_index].data.p && !m_class_is_valuetype (m_class_get_element_class (mono_object_class (o)))) {
1021 ERROR_DECL (error);
1022 MonoObject *isinst = mono_object_isinst_checked (sp [val_index].data.o, m_class_get_element_class (mono_object_class (o)), error);
1023 mono_error_cleanup (error);
1024 if (!isinst)
1025 return mono_get_exception_array_type_mismatch ();
1028 gint32 esize = mono_array_element_size (ac);
1029 gpointer ea = mono_array_addr_with_size_fast (ao, esize, pos);
1031 MonoType *mt = sig->params [m_class_get_rank (ac)];
1032 stackval_to_data (mt, &sp [val_index], ea, FALSE);
1033 return NULL;
1036 static MonoException*
1037 ves_array_get (InterpFrame *frame, stackval *sp, stackval *retval, MonoMethodSignature *sig, gboolean safe)
1039 MonoObject *o = sp->data.o;
1040 MonoArray *ao = (MonoArray *) o;
1041 MonoClass *ac = o->vtable->klass;
1043 g_assert (m_class_get_rank (ac) >= 1);
1045 gint32 pos = ves_array_calculate_index (ao, sp + 1, safe);
1046 if (pos == -1)
1047 return mono_get_exception_index_out_of_range ();
1049 gint32 esize = mono_array_element_size (ac);
1050 gconstpointer ea = mono_array_addr_with_size_fast (ao, esize, pos);
1052 MonoType *mt = sig->ret;
1053 stackval_from_data (mt, retval, ea, FALSE);
1054 return NULL;
1057 static MONO_NEVER_INLINE MonoException*
1058 ves_array_element_address (InterpFrame *frame, MonoClass *required_type, MonoArray *ao, stackval *sp, gboolean needs_typecheck)
1060 MonoClass *ac = ((MonoObject *) ao)->vtable->klass;
1062 g_assert (m_class_get_rank (ac) >= 1);
1064 gint32 pos = ves_array_calculate_index (ao, sp, TRUE);
1065 if (pos == -1)
1066 return mono_get_exception_index_out_of_range ();
1068 if (needs_typecheck && !mono_class_is_assignable_from_internal (m_class_get_element_class (mono_object_class ((MonoObject *) ao)), required_type))
1069 return mono_get_exception_array_type_mismatch ();
1070 gint32 esize = mono_array_element_size (ac);
1071 sp [-1].data.p = mono_array_addr_with_size_fast (ao, esize, pos);
1072 return NULL;
1075 #ifdef MONO_ARCH_HAVE_INTERP_ENTRY_TRAMPOLINE
1076 static MonoFuncV mono_native_to_interp_trampoline = NULL;
1077 #endif
1079 #ifndef MONO_ARCH_HAVE_INTERP_PINVOKE_TRAMP
1080 static InterpMethodArguments* build_args_from_sig (MonoMethodSignature *sig, InterpFrame *frame)
1082 InterpMethodArguments *margs = g_malloc0 (sizeof (InterpMethodArguments));
1084 #ifdef TARGET_ARM
1085 g_assert (mono_arm_eabi_supported ());
1086 int i8_align = mono_arm_i8_align ();
1087 #endif
1089 #ifdef TARGET_WASM
1090 margs->sig = sig;
1091 #endif
1093 if (sig->hasthis)
1094 margs->ilen++;
1096 for (int i = 0; i < sig->param_count; i++) {
1097 guint32 ptype = sig->params [i]->byref ? MONO_TYPE_PTR : sig->params [i]->type;
1098 switch (ptype) {
1099 case MONO_TYPE_BOOLEAN:
1100 case MONO_TYPE_CHAR:
1101 case MONO_TYPE_I1:
1102 case MONO_TYPE_U1:
1103 case MONO_TYPE_I2:
1104 case MONO_TYPE_U2:
1105 case MONO_TYPE_I4:
1106 case MONO_TYPE_U4:
1107 case MONO_TYPE_I:
1108 case MONO_TYPE_U:
1109 case MONO_TYPE_PTR:
1110 case MONO_TYPE_SZARRAY:
1111 case MONO_TYPE_CLASS:
1112 case MONO_TYPE_OBJECT:
1113 case MONO_TYPE_STRING:
1114 case MONO_TYPE_VALUETYPE:
1115 case MONO_TYPE_GENERICINST:
1116 #if SIZEOF_VOID_P == 8
1117 case MONO_TYPE_I8:
1118 case MONO_TYPE_U8:
1119 #endif
1120 margs->ilen++;
1121 break;
1122 #if SIZEOF_VOID_P == 4
1123 case MONO_TYPE_I8:
1124 case MONO_TYPE_U8:
1125 #ifdef TARGET_ARM
1126 /* pairs begin at even registers */
1127 if (i8_align == 8 && margs->ilen & 1)
1128 margs->ilen++;
1129 #endif
1130 margs->ilen += 2;
1131 break;
1132 #endif
1133 case MONO_TYPE_R4:
1134 #if SIZEOF_VOID_P == 8
1135 case MONO_TYPE_R8:
1136 #endif
1137 margs->flen++;
1138 break;
1139 #if SIZEOF_VOID_P == 4
1140 case MONO_TYPE_R8:
1141 margs->flen += 2;
1142 break;
1143 #endif
1144 default:
1145 g_error ("build_args_from_sig: not implemented yet (1): 0x%x\n", ptype);
1149 if (margs->ilen > 0)
1150 margs->iargs = g_malloc0 (sizeof (gpointer) * margs->ilen);
1152 if (margs->flen > 0)
1153 margs->fargs = g_malloc0 (sizeof (double) * margs->flen);
1155 if (margs->ilen > INTERP_ICALL_TRAMP_IARGS)
1156 g_error ("build_args_from_sig: TODO, allocate gregs: %d\n", margs->ilen);
1158 if (margs->flen > INTERP_ICALL_TRAMP_FARGS)
1159 g_error ("build_args_from_sig: TODO, allocate fregs: %d\n", margs->flen);
1162 size_t int_i = 0;
1163 size_t int_f = 0;
1165 if (sig->hasthis) {
1166 margs->iargs [0] = frame->stack_args->data.p;
1167 int_i++;
1170 for (int i = 0; i < sig->param_count; i++) {
1171 guint32 ptype = sig->params [i]->byref ? MONO_TYPE_PTR : sig->params [i]->type;
1172 switch (ptype) {
1173 case MONO_TYPE_BOOLEAN:
1174 case MONO_TYPE_CHAR:
1175 case MONO_TYPE_I1:
1176 case MONO_TYPE_U1:
1177 case MONO_TYPE_I2:
1178 case MONO_TYPE_U2:
1179 case MONO_TYPE_I4:
1180 case MONO_TYPE_U4:
1181 case MONO_TYPE_I:
1182 case MONO_TYPE_U:
1183 case MONO_TYPE_PTR:
1184 case MONO_TYPE_SZARRAY:
1185 case MONO_TYPE_CLASS:
1186 case MONO_TYPE_OBJECT:
1187 case MONO_TYPE_STRING:
1188 case MONO_TYPE_VALUETYPE:
1189 case MONO_TYPE_GENERICINST:
1190 #if SIZEOF_VOID_P == 8
1191 case MONO_TYPE_I8:
1192 case MONO_TYPE_U8:
1193 #endif
1194 margs->iargs [int_i] = frame->stack_args [i].data.p;
1195 #if DEBUG_INTERP
1196 g_print ("build_args_from_sig: margs->iargs [%d]: %p (frame @ %d)\n", int_i, margs->iargs [int_i], i);
1197 #endif
1198 int_i++;
1199 break;
1200 #if SIZEOF_VOID_P == 4
1201 case MONO_TYPE_I8:
1202 case MONO_TYPE_U8: {
1203 stackval *sarg = &frame->stack_args [i];
1204 #ifdef TARGET_ARM
1205 /* pairs begin at even registers */
1206 if (i8_align == 8 && int_i & 1)
1207 int_i++;
1208 #endif
1209 margs->iargs [int_i] = (gpointer) sarg->data.pair.lo;
1210 int_i++;
1211 margs->iargs [int_i] = (gpointer) sarg->data.pair.hi;
1212 #if DEBUG_INTERP
1213 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);
1214 #endif
1215 int_i++;
1216 break;
1218 #endif
1219 case MONO_TYPE_R4:
1220 case MONO_TYPE_R8:
1221 if (ptype == MONO_TYPE_R4)
1222 * (float *) &(margs->fargs [int_f]) = frame->stack_args [i].data.f_r4;
1223 else
1224 margs->fargs [int_f] = frame->stack_args [i].data.f;
1225 #if DEBUG_INTERP
1226 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);
1227 #endif
1228 #if SIZEOF_VOID_P == 4
1229 int_f += 2;
1230 #else
1231 int_f++;
1232 #endif
1233 break;
1234 default:
1235 g_error ("build_args_from_sig: not implemented yet (2): 0x%x\n", ptype);
1239 switch (sig->ret->type) {
1240 case MONO_TYPE_BOOLEAN:
1241 case MONO_TYPE_CHAR:
1242 case MONO_TYPE_I1:
1243 case MONO_TYPE_U1:
1244 case MONO_TYPE_I2:
1245 case MONO_TYPE_U2:
1246 case MONO_TYPE_I4:
1247 case MONO_TYPE_U4:
1248 case MONO_TYPE_I:
1249 case MONO_TYPE_U:
1250 case MONO_TYPE_PTR:
1251 case MONO_TYPE_SZARRAY:
1252 case MONO_TYPE_CLASS:
1253 case MONO_TYPE_OBJECT:
1254 case MONO_TYPE_STRING:
1255 case MONO_TYPE_I8:
1256 case MONO_TYPE_U8:
1257 case MONO_TYPE_VALUETYPE:
1258 case MONO_TYPE_GENERICINST:
1259 margs->retval = &(frame->retval->data.p);
1260 margs->is_float_ret = 0;
1261 break;
1262 case MONO_TYPE_R4:
1263 case MONO_TYPE_R8:
1264 margs->retval = &(frame->retval->data.p);
1265 margs->is_float_ret = 1;
1266 break;
1267 case MONO_TYPE_VOID:
1268 margs->retval = NULL;
1269 break;
1270 default:
1271 g_error ("build_args_from_sig: ret type not implemented yet: 0x%x\n", sig->ret->type);
1274 return margs;
1276 #endif
1278 static void
1279 interp_frame_arg_to_data (MonoInterpFrameHandle frame, MonoMethodSignature *sig, int index, gpointer data)
1281 InterpFrame *iframe = (InterpFrame*)frame;
1283 if (index == -1)
1284 stackval_to_data (sig->ret, iframe->retval, data, sig->pinvoke);
1285 else
1286 stackval_to_data (sig->params [index], &iframe->stack_args [index], data, sig->pinvoke);
1289 static void
1290 interp_data_to_frame_arg (MonoInterpFrameHandle frame, MonoMethodSignature *sig, int index, gconstpointer data)
1292 InterpFrame *iframe = (InterpFrame*)frame;
1294 if (index == -1)
1295 stackval_from_data (sig->ret, iframe->retval, data, sig->pinvoke);
1296 else if (sig->hasthis && index == 0)
1297 iframe->stack_args [index].data.p = *(gpointer*)data;
1298 else
1299 stackval_from_data (sig->params [index - sig->hasthis], &iframe->stack_args [index], data, sig->pinvoke);
1302 static gpointer
1303 interp_frame_arg_to_storage (MonoInterpFrameHandle frame, MonoMethodSignature *sig, int index)
1305 InterpFrame *iframe = (InterpFrame*)frame;
1307 if (index == -1)
1308 return stackval_to_data_addr (sig->ret, iframe->retval);
1309 else
1310 return stackval_to_data_addr (sig->params [index], &iframe->stack_args [index]);
1313 static void
1314 interp_frame_arg_set_storage (MonoInterpFrameHandle frame, MonoMethodSignature *sig, int index, gpointer storage)
1316 InterpFrame *iframe = (InterpFrame*)frame;
1317 stackval *val = (index == -1) ? iframe->retval : &iframe->stack_args [index];
1318 MonoType *type = (index == -1) ? sig->ret : sig->params [index];
1320 switch (type->type) {
1321 case MONO_TYPE_GENERICINST:
1322 if (!MONO_TYPE_IS_REFERENCE (type))
1323 val->data.vt = storage;
1324 break;
1325 case MONO_TYPE_VALUETYPE:
1326 val->data.vt = storage;
1327 break;
1328 default:
1329 g_assert_not_reached ();
1333 static MonoPIFunc
1334 get_interp_to_native_trampoline (void)
1336 static MonoPIFunc trampoline = NULL;
1338 if (!trampoline) {
1339 if (mono_ee_features.use_aot_trampolines) {
1340 trampoline = (MonoPIFunc) mono_aot_get_trampoline ("interp_to_native_trampoline");
1341 } else {
1342 MonoTrampInfo *info;
1343 trampoline = (MonoPIFunc) mono_arch_get_interp_to_native_trampoline (&info);
1344 mono_tramp_info_register (info, NULL);
1346 mono_memory_barrier ();
1348 return trampoline;
1351 static void
1352 interp_to_native_trampoline (gpointer addr, gpointer ccontext)
1354 get_interp_to_native_trampoline () (addr, ccontext);
1357 /* MONO_NO_OPTIMIATION is needed due to usage of INTERP_PUSH_LMF_WITH_CTX. */
1358 #ifdef _MSC_VER
1359 #pragma optimize ("", off)
1360 #endif
1361 static MONO_NO_OPTIMIZATION MONO_NEVER_INLINE void
1362 ves_pinvoke_method (InterpFrame *frame, MonoMethodSignature *sig, MonoFuncV addr, ThreadContext *context, gboolean save_last_error)
1364 MonoLMFExt ext;
1365 gpointer args;
1367 g_assert (!frame->imethod);
1369 static MonoPIFunc entry_func = NULL;
1370 if (!entry_func) {
1371 #ifdef MONO_ARCH_HAS_NO_PROPER_MONOCTX
1372 ERROR_DECL (error);
1373 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);
1374 mono_error_assert_ok (error);
1375 #else
1376 entry_func = get_interp_to_native_trampoline ();
1377 #endif
1378 mono_memory_barrier ();
1381 #ifdef ENABLE_NETCORE
1382 if (save_last_error) {
1383 mono_marshal_clear_last_error ();
1385 #endif
1387 #ifdef MONO_ARCH_HAVE_INTERP_PINVOKE_TRAMP
1388 CallContext ccontext;
1389 mono_arch_set_native_call_context_args (&ccontext, frame, sig);
1390 args = &ccontext;
1391 #else
1392 InterpMethodArguments *margs = build_args_from_sig (sig, frame);
1393 args = margs;
1394 #endif
1396 INTERP_PUSH_LMF_WITH_CTX (frame, ext, exit_pinvoke);
1397 entry_func ((gpointer) addr, args);
1398 if (save_last_error)
1399 mono_marshal_set_last_error ();
1400 interp_pop_lmf (&ext);
1402 #ifdef MONO_ARCH_HAVE_INTERP_PINVOKE_TRAMP
1403 if (!context->has_resume_state)
1404 mono_arch_get_native_call_context_ret (&ccontext, frame, sig);
1406 if (ccontext.stack != NULL)
1407 g_free (ccontext.stack);
1408 #else
1409 if (!context->has_resume_state && !MONO_TYPE_ISSTRUCT (sig->ret))
1410 stackval_from_data (sig->ret, frame->retval, (char*)&frame->retval->data.p, sig->pinvoke);
1412 g_free (margs->iargs);
1413 g_free (margs->fargs);
1414 g_free (margs);
1415 #endif
1416 goto exit_pinvoke; // prevent unused label warning in some configurations
1417 exit_pinvoke:
1418 return;
1420 #ifdef _MSC_VER
1421 #pragma optimize ("", on)
1422 #endif
1425 * interp_init_delegate:
1427 * Initialize del->interp_method.
1429 static void
1430 interp_init_delegate (MonoDelegate *del, MonoError *error)
1432 MonoMethod *method;
1434 if (del->interp_method) {
1435 /* Delegate created by a call to ves_icall_mono_delegate_ctor_interp () */
1436 del->method = ((InterpMethod *)del->interp_method)->method;
1437 } else if (del->method) {
1438 /* Delegate created dynamically */
1439 del->interp_method = mono_interp_get_imethod (del->object.vtable->domain, del->method, error);
1440 } else {
1441 /* Created from JITted code */
1442 g_assert_not_reached ();
1445 method = ((InterpMethod*)del->interp_method)->method;
1446 if (del->target &&
1447 method &&
1448 method->flags & METHOD_ATTRIBUTE_VIRTUAL &&
1449 method->flags & METHOD_ATTRIBUTE_ABSTRACT &&
1450 mono_class_is_abstract (method->klass))
1451 del->interp_method = get_virtual_method ((InterpMethod*)del->interp_method, del->target->vtable);
1453 method = ((InterpMethod*)del->interp_method)->method;
1454 if (method && m_class_get_parent (method->klass) == mono_defaults.multicastdelegate_class) {
1455 const char *name = method->name;
1456 if (*name == 'I' && (strcmp (name, "Invoke") == 0)) {
1458 * When invoking the delegate interp_method is executed directly. If it's an
1459 * invoke make sure we replace it with the appropriate delegate invoke wrapper.
1461 * FIXME We should do this later, when we also know the delegate on which the
1462 * target method is called.
1464 del->interp_method = mono_interp_get_imethod (del->object.vtable->domain, mono_marshal_get_delegate_invoke (method, NULL), error);
1465 mono_error_assert_ok (error);
1469 if (!((InterpMethod *) del->interp_method)->transformed && method_is_dynamic (method)) {
1470 /* Return any errors from method compilation */
1471 mono_interp_transform_method ((InterpMethod *) del->interp_method, get_context (), error);
1472 return_if_nok (error);
1476 static void
1477 interp_delegate_ctor (MonoObjectHandle this_obj, MonoObjectHandle target, gpointer addr, MonoError *error)
1480 * addr is the result of an LDFTN opcode, i.e. an InterpMethod
1482 InterpMethod *imethod = (InterpMethod*)addr;
1484 if (!(imethod->method->flags & METHOD_ATTRIBUTE_STATIC)) {
1485 MonoMethod *invoke = mono_get_delegate_invoke_internal (mono_handle_class (this_obj));
1486 /* virtual invoke delegates must not have null check */
1487 if (mono_method_signature_internal (imethod->method)->param_count == mono_method_signature_internal (invoke)->param_count
1488 && MONO_HANDLE_IS_NULL (target)) {
1489 mono_error_set_argument (error, "this", "Delegate to an instance method cannot have null 'this'");
1490 return;
1494 g_assert (imethod->method);
1495 gpointer entry = mini_get_interp_callbacks ()->create_method_pointer (imethod->method, FALSE, error);
1496 return_if_nok (error);
1498 MONO_HANDLE_SETVAL (MONO_HANDLE_CAST (MonoDelegate, this_obj), interp_method, gpointer, imethod);
1500 mono_delegate_ctor (this_obj, target, entry, error);
1504 * From the spec:
1505 * runtime specifies that the implementation of the method is automatically
1506 * provided by the runtime and is primarily used for the methods of delegates.
1508 static MONO_NEVER_INLINE MonoException*
1509 ves_imethod (InterpFrame *frame, MonoMethod *method, MonoMethodSignature *sig, stackval *sp, stackval *retval)
1511 const char *name = method->name;
1512 mono_class_init_internal (method->klass);
1514 if (method->klass == mono_defaults.array_class) {
1515 if (!strcmp (name, "UnsafeMov")) {
1516 /* TODO: layout checks */
1517 stackval_from_data (sig->ret, retval, (char*) sp, FALSE);
1518 return NULL;
1520 if (!strcmp (name, "UnsafeLoad"))
1521 return ves_array_get (frame, sp, retval, sig, FALSE);
1522 } else if (mini_class_is_system_array (method->klass)) {
1523 MonoObject *obj = (MonoObject*) sp->data.p;
1524 if (!obj)
1525 return mono_get_exception_null_reference ();
1526 if (*name == 'S' && (strcmp (name, "Set") == 0))
1527 return ves_array_set (frame, sp, sig);
1528 if (*name == 'G' && (strcmp (name, "Get") == 0))
1529 return ves_array_get (frame, sp, retval, sig, TRUE);
1532 g_error ("Don't know how to exec runtime method %s.%s::%s",
1533 m_class_get_name_space (method->klass), m_class_get_name (method->klass),
1534 method->name);
1537 #if DEBUG_INTERP
1538 static char*
1539 dump_stack (stackval *stack, stackval *sp)
1541 stackval *s = stack;
1542 GString *str = g_string_new ("");
1544 if (sp == stack)
1545 return g_string_free (str, FALSE);
1547 while (s < sp) {
1548 g_string_append_printf (str, "[%p (%lld)] ", s->data.l, s->data.l);
1549 ++s;
1551 return g_string_free (str, FALSE);
1554 static void
1555 dump_stackval (GString *str, stackval *s, MonoType *type)
1557 switch (type->type) {
1558 case MONO_TYPE_I1:
1559 case MONO_TYPE_U1:
1560 case MONO_TYPE_I2:
1561 case MONO_TYPE_U2:
1562 case MONO_TYPE_I4:
1563 case MONO_TYPE_U4:
1564 case MONO_TYPE_CHAR:
1565 case MONO_TYPE_BOOLEAN:
1566 g_string_append_printf (str, "[%d] ", s->data.i);
1567 break;
1568 case MONO_TYPE_STRING:
1569 case MONO_TYPE_SZARRAY:
1570 case MONO_TYPE_CLASS:
1571 case MONO_TYPE_OBJECT:
1572 case MONO_TYPE_ARRAY:
1573 case MONO_TYPE_PTR:
1574 case MONO_TYPE_I:
1575 case MONO_TYPE_U:
1576 g_string_append_printf (str, "[%p] ", s->data.p);
1577 break;
1578 case MONO_TYPE_VALUETYPE:
1579 if (m_class_is_enumtype (type->data.klass))
1580 g_string_append_printf (str, "[%d] ", s->data.i);
1581 else
1582 g_string_append_printf (str, "[vt:%p] ", s->data.p);
1583 break;
1584 case MONO_TYPE_R4:
1585 g_string_append_printf (str, "[%g] ", s->data.f_r4);
1586 break;
1587 case MONO_TYPE_R8:
1588 g_string_append_printf (str, "[%g] ", s->data.f);
1589 break;
1590 case MONO_TYPE_I8:
1591 case MONO_TYPE_U8:
1592 default: {
1593 GString *res = g_string_new ("");
1594 mono_type_get_desc (res, type, TRUE);
1595 g_string_append_printf (str, "[{%s} %lld/0x%0llx] ", res->str, s->data.l, s->data.l);
1596 g_string_free (res, TRUE);
1597 break;
1602 static char*
1603 dump_retval (InterpFrame *inv)
1605 GString *str = g_string_new ("");
1606 MonoType *ret = mono_method_signature_internal (inv->imethod->method)->ret;
1608 if (ret->type != MONO_TYPE_VOID)
1609 dump_stackval (str, inv->retval, ret);
1611 return g_string_free (str, FALSE);
1614 static char*
1615 dump_args (InterpFrame *inv)
1617 GString *str = g_string_new ("");
1618 int i;
1619 MonoMethodSignature *signature = mono_method_signature_internal (inv->imethod->method);
1621 if (signature->param_count == 0 && !signature->hasthis)
1622 return g_string_free (str, FALSE);
1624 if (signature->hasthis) {
1625 MonoMethod *method = inv->imethod->method;
1626 dump_stackval (str, inv->stack_args, m_class_get_byval_arg (method->klass));
1629 for (i = 0; i < signature->param_count; ++i)
1630 dump_stackval (str, inv->stack_args + (!!signature->hasthis) + i, signature->params [i]);
1632 return g_string_free (str, FALSE);
1634 #endif
1636 #define CHECK_ADD_OVERFLOW(a,b) \
1637 (gint32)(b) >= 0 ? (gint32)(G_MAXINT32) - (gint32)(b) < (gint32)(a) ? -1 : 0 \
1638 : (gint32)(G_MININT32) - (gint32)(b) > (gint32)(a) ? +1 : 0
1640 #define CHECK_SUB_OVERFLOW(a,b) \
1641 (gint32)(b) < 0 ? (gint32)(G_MAXINT32) + (gint32)(b) < (gint32)(a) ? -1 : 0 \
1642 : (gint32)(G_MININT32) + (gint32)(b) > (gint32)(a) ? +1 : 0
1644 #define CHECK_ADD_OVERFLOW_UN(a,b) \
1645 (guint32)(G_MAXUINT32) - (guint32)(b) < (guint32)(a) ? -1 : 0
1647 #define CHECK_SUB_OVERFLOW_UN(a,b) \
1648 (guint32)(a) < (guint32)(b) ? -1 : 0
1650 #define CHECK_ADD_OVERFLOW64(a,b) \
1651 (gint64)(b) >= 0 ? (gint64)(G_MAXINT64) - (gint64)(b) < (gint64)(a) ? -1 : 0 \
1652 : (gint64)(G_MININT64) - (gint64)(b) > (gint64)(a) ? +1 : 0
1654 #define CHECK_SUB_OVERFLOW64(a,b) \
1655 (gint64)(b) < 0 ? (gint64)(G_MAXINT64) + (gint64)(b) < (gint64)(a) ? -1 : 0 \
1656 : (gint64)(G_MININT64) + (gint64)(b) > (gint64)(a) ? +1 : 0
1658 #define CHECK_ADD_OVERFLOW64_UN(a,b) \
1659 (guint64)(G_MAXUINT64) - (guint64)(b) < (guint64)(a) ? -1 : 0
1661 #define CHECK_SUB_OVERFLOW64_UN(a,b) \
1662 (guint64)(a) < (guint64)(b) ? -1 : 0
1664 #if SIZEOF_VOID_P == 4
1665 #define CHECK_ADD_OVERFLOW_NAT(a,b) CHECK_ADD_OVERFLOW(a,b)
1666 #define CHECK_ADD_OVERFLOW_NAT_UN(a,b) CHECK_ADD_OVERFLOW_UN(a,b)
1667 #else
1668 #define CHECK_ADD_OVERFLOW_NAT(a,b) CHECK_ADD_OVERFLOW64(a,b)
1669 #define CHECK_ADD_OVERFLOW_NAT_UN(a,b) CHECK_ADD_OVERFLOW64_UN(a,b)
1670 #endif
1672 /* Resolves to TRUE if the operands would overflow */
1673 #define CHECK_MUL_OVERFLOW(a,b) \
1674 ((gint32)(a) == 0) || ((gint32)(b) == 0) ? 0 : \
1675 (((gint32)(a) > 0) && ((gint32)(b) == -1)) ? FALSE : \
1676 (((gint32)(a) < 0) && ((gint32)(b) == -1)) ? (a == G_MININT32) : \
1677 (((gint32)(a) > 0) && ((gint32)(b) > 0)) ? (gint32)(a) > ((G_MAXINT32) / (gint32)(b)) : \
1678 (((gint32)(a) > 0) && ((gint32)(b) < 0)) ? (gint32)(a) > ((G_MININT32) / (gint32)(b)) : \
1679 (((gint32)(a) < 0) && ((gint32)(b) > 0)) ? (gint32)(a) < ((G_MININT32) / (gint32)(b)) : \
1680 (gint32)(a) < ((G_MAXINT32) / (gint32)(b))
1682 #define CHECK_MUL_OVERFLOW_UN(a,b) \
1683 ((guint32)(a) == 0) || ((guint32)(b) == 0) ? 0 : \
1684 (guint32)(b) > ((G_MAXUINT32) / (guint32)(a))
1686 #define CHECK_MUL_OVERFLOW64(a,b) \
1687 ((gint64)(a) == 0) || ((gint64)(b) == 0) ? 0 : \
1688 (((gint64)(a) > 0) && ((gint64)(b) == -1)) ? FALSE : \
1689 (((gint64)(a) < 0) && ((gint64)(b) == -1)) ? (a == G_MININT64) : \
1690 (((gint64)(a) > 0) && ((gint64)(b) > 0)) ? (gint64)(a) > ((G_MAXINT64) / (gint64)(b)) : \
1691 (((gint64)(a) > 0) && ((gint64)(b) < 0)) ? (gint64)(a) > ((G_MININT64) / (gint64)(b)) : \
1692 (((gint64)(a) < 0) && ((gint64)(b) > 0)) ? (gint64)(a) < ((G_MININT64) / (gint64)(b)) : \
1693 (gint64)(a) < ((G_MAXINT64) / (gint64)(b))
1695 #define CHECK_MUL_OVERFLOW64_UN(a,b) \
1696 ((guint64)(a) == 0) || ((guint64)(b) == 0) ? 0 : \
1697 (guint64)(b) > ((G_MAXUINT64) / (guint64)(a))
1699 #if SIZEOF_VOID_P == 4
1700 #define CHECK_MUL_OVERFLOW_NAT(a,b) CHECK_MUL_OVERFLOW(a,b)
1701 #define CHECK_MUL_OVERFLOW_NAT_UN(a,b) CHECK_MUL_OVERFLOW_UN(a,b)
1702 #else
1703 #define CHECK_MUL_OVERFLOW_NAT(a,b) CHECK_MUL_OVERFLOW64(a,b)
1704 #define CHECK_MUL_OVERFLOW_NAT_UN(a,b) CHECK_MUL_OVERFLOW64_UN(a,b)
1705 #endif
1707 static MonoObject*
1708 interp_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError *error)
1710 InterpFrame frame;
1711 ThreadContext *context = get_context ();
1712 MonoMethodSignature *sig = mono_method_signature_internal (method);
1713 MonoClass *klass = mono_class_from_mono_type_internal (sig->ret);
1714 stackval result;
1715 MonoMethod *target_method = method;
1717 error_init (error);
1718 if (exc)
1719 *exc = NULL;
1721 MonoDomain *domain = mono_domain_get ();
1723 if (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
1724 target_method = mono_marshal_get_native_wrapper (target_method, FALSE, FALSE);
1725 MonoMethod *invoke_wrapper = mono_marshal_get_runtime_invoke_full (target_method, FALSE, TRUE);
1727 //* <code>MonoObject *runtime_invoke (MonoObject *this_obj, void **params, MonoObject **exc, void* method)</code>
1729 result.data.vt = alloca (mono_class_instance_size (klass));
1730 stackval args [4];
1732 if (sig->hasthis)
1733 args [0].data.p = obj;
1734 else
1735 args [0].data.p = NULL;
1736 args [1].data.p = params;
1737 args [2].data.p = exc;
1738 args [3].data.p = target_method;
1740 InterpMethod *imethod = mono_interp_get_imethod (domain, invoke_wrapper, error);
1741 mono_error_assert_ok (error);
1742 init_frame (&frame, NULL, imethod, args, &result);
1744 interp_exec_method (&frame, context, error);
1746 if (context->has_resume_state) {
1747 // This can happen on wasm !?
1748 MonoException *thrown_exc = (MonoException*) mono_gchandle_get_target_internal (context->exc_gchandle);
1749 if (exc)
1750 *exc = (MonoObject*)thrown_exc;
1751 else
1752 mono_error_set_exception_instance (error, thrown_exc);
1753 return NULL;
1755 return (MonoObject*)result.data.p;
1758 typedef struct {
1759 InterpMethod *rmethod;
1760 gpointer this_arg;
1761 gpointer res;
1762 gpointer args [16];
1763 gpointer *many_args;
1764 } InterpEntryData;
1766 /* Main function for entering the interpreter from compiled code */
1767 static void
1768 interp_entry (InterpEntryData *data)
1770 InterpFrame frame;
1771 InterpMethod *rmethod;
1772 ThreadContext *context;
1773 stackval result;
1774 stackval *args;
1775 MonoMethod *method;
1776 MonoMethodSignature *sig;
1777 MonoType *type;
1778 gpointer orig_domain = NULL, attach_cookie;
1779 int i;
1781 if ((gsize)data->rmethod & 1) {
1782 /* Unbox */
1783 data->this_arg = mono_object_unbox_internal ((MonoObject*)data->this_arg);
1784 data->rmethod = (InterpMethod*)(gpointer)((gsize)data->rmethod & ~1);
1786 rmethod = data->rmethod;
1788 if (rmethod->needs_thread_attach)
1789 orig_domain = mono_threads_attach_coop (mono_domain_get (), &attach_cookie);
1791 context = get_context ();
1793 method = rmethod->method;
1794 sig = mono_method_signature_internal (method);
1796 // FIXME: Optimize this
1798 //printf ("%s\n", mono_method_full_name (method, 1));
1800 args = g_newa (stackval, sig->param_count + (sig->hasthis ? 1 : 0));
1801 if (sig->hasthis)
1802 args [0].data.p = data->this_arg;
1804 gpointer *params;
1805 if (data->many_args)
1806 params = data->many_args;
1807 else
1808 params = data->args;
1809 for (i = 0; i < sig->param_count; ++i) {
1810 int a_index = i + (sig->hasthis ? 1 : 0);
1811 if (sig->params [i]->byref) {
1812 args [a_index].data.p = params [i];
1813 continue;
1815 type = rmethod->param_types [i];
1816 switch (type->type) {
1817 case MONO_TYPE_VALUETYPE:
1818 args [a_index].data.p = params [i];
1819 break;
1820 case MONO_TYPE_GENERICINST:
1821 if (MONO_TYPE_IS_REFERENCE (type))
1822 args [a_index].data.p = *(gpointer*)params [i];
1823 else
1824 args [a_index].data.vt = params [i];
1825 break;
1826 default:
1827 stackval_from_data (type, &args [a_index], params [i], FALSE);
1828 break;
1832 memset (&result, 0, sizeof (result));
1833 init_frame (&frame, NULL, data->rmethod, args, &result);
1835 type = rmethod->rtype;
1836 switch (type->type) {
1837 case MONO_TYPE_GENERICINST:
1838 if (!MONO_TYPE_IS_REFERENCE (type))
1839 frame.retval->data.vt = data->res;
1840 break;
1841 case MONO_TYPE_VALUETYPE:
1842 frame.retval->data.vt = data->res;
1843 break;
1844 default:
1845 break;
1848 ERROR_DECL (error);
1849 interp_exec_method (&frame, context, error);
1851 g_assert (!context->has_resume_state);
1853 if (rmethod->needs_thread_attach)
1854 mono_threads_detach_coop (orig_domain, &attach_cookie);
1856 if (mono_llvm_only) {
1857 if (context->has_resume_state)
1858 mono_llvm_reraise_exception ((MonoException*)mono_gchandle_get_target_internal (context->exc_gchandle));
1859 } else {
1860 g_assert (!context->has_resume_state);
1863 type = rmethod->rtype;
1864 switch (type->type) {
1865 case MONO_TYPE_VOID:
1866 break;
1867 case MONO_TYPE_OBJECT:
1868 /* No need for a write barrier */
1869 *(MonoObject**)data->res = (MonoObject*)frame.retval->data.p;
1870 break;
1871 case MONO_TYPE_GENERICINST:
1872 if (MONO_TYPE_IS_REFERENCE (type)) {
1873 *(MonoObject**)data->res = (MonoObject*)frame.retval->data.p;
1874 } else {
1875 /* Already set before the call */
1877 break;
1878 case MONO_TYPE_VALUETYPE:
1879 /* Already set before the call */
1880 break;
1881 default:
1882 stackval_to_data (type, frame.retval, data->res, FALSE);
1883 break;
1887 static stackval *
1888 do_icall (MonoMethodSignature *sig, int op, stackval *sp, gpointer ptr, gboolean save_last_error)
1890 #ifdef ENABLE_NETCORE
1891 if (save_last_error)
1892 mono_marshal_clear_last_error ();
1893 #endif
1895 switch (op) {
1896 case MINT_ICALL_V_V: {
1897 typedef void (*T)(void);
1898 T func = (T)ptr;
1899 func ();
1900 break;
1902 case MINT_ICALL_V_P: {
1903 typedef gpointer (*T)(void);
1904 T func = (T)ptr;
1905 sp++;
1906 sp [-1].data.p = func ();
1907 break;
1909 case MINT_ICALL_P_V: {
1910 typedef void (*T)(gpointer);
1911 T func = (T)ptr;
1912 func (sp [-1].data.p);
1913 sp --;
1914 break;
1916 case MINT_ICALL_P_P: {
1917 typedef gpointer (*T)(gpointer);
1918 T func = (T)ptr;
1919 sp [-1].data.p = func (sp [-1].data.p);
1920 break;
1922 case MINT_ICALL_PP_V: {
1923 typedef void (*T)(gpointer,gpointer);
1924 T func = (T)ptr;
1925 sp -= 2;
1926 func (sp [0].data.p, sp [1].data.p);
1927 break;
1929 case MINT_ICALL_PP_P: {
1930 typedef gpointer (*T)(gpointer,gpointer);
1931 T func = (T)ptr;
1932 --sp;
1933 sp [-1].data.p = func (sp [-1].data.p, sp [0].data.p);
1934 break;
1936 case MINT_ICALL_PPP_V: {
1937 typedef void (*T)(gpointer,gpointer,gpointer);
1938 T func = (T)ptr;
1939 sp -= 3;
1940 func (sp [0].data.p, sp [1].data.p, sp [2].data.p);
1941 break;
1943 case MINT_ICALL_PPP_P: {
1944 typedef gpointer (*T)(gpointer,gpointer,gpointer);
1945 T func = (T)ptr;
1946 sp -= 2;
1947 sp [-1].data.p = func (sp [-1].data.p, sp [0].data.p, sp [1].data.p);
1948 break;
1950 case MINT_ICALL_PPPP_V: {
1951 typedef void (*T)(gpointer,gpointer,gpointer,gpointer);
1952 T func = (T)ptr;
1953 sp -= 4;
1954 func (sp [0].data.p, sp [1].data.p, sp [2].data.p, sp [3].data.p);
1955 break;
1957 case MINT_ICALL_PPPP_P: {
1958 typedef gpointer (*T)(gpointer,gpointer,gpointer,gpointer);
1959 T func = (T)ptr;
1960 sp -= 3;
1961 sp [-1].data.p = func (sp [-1].data.p, sp [0].data.p, sp [1].data.p, sp [2].data.p);
1962 break;
1964 case MINT_ICALL_PPPPP_V: {
1965 typedef void (*T)(gpointer,gpointer,gpointer,gpointer,gpointer);
1966 T func = (T)ptr;
1967 sp -= 5;
1968 func (sp [0].data.p, sp [1].data.p, sp [2].data.p, sp [3].data.p, sp [4].data.p);
1969 break;
1971 case MINT_ICALL_PPPPP_P: {
1972 typedef gpointer (*T)(gpointer,gpointer,gpointer,gpointer,gpointer);
1973 T func = (T)ptr;
1974 sp -= 4;
1975 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);
1976 break;
1978 case MINT_ICALL_PPPPPP_V: {
1979 typedef void (*T)(gpointer,gpointer,gpointer,gpointer,gpointer,gpointer);
1980 T func = (T)ptr;
1981 sp -= 6;
1982 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);
1983 break;
1985 case MINT_ICALL_PPPPPP_P: {
1986 typedef gpointer (*T)(gpointer,gpointer,gpointer,gpointer,gpointer,gpointer);
1987 T func = (T)ptr;
1988 sp -= 5;
1989 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);
1990 break;
1992 default:
1993 g_assert_not_reached ();
1996 if (save_last_error)
1997 mono_marshal_set_last_error ();
1999 /* convert the native representation to the stackval representation */
2000 if (sig)
2001 stackval_from_data (sig->ret, &sp [-1], (char*) &sp [-1].data.p, sig->pinvoke);
2003 return sp;
2006 /* MONO_NO_OPTIMIATION is needed due to usage of INTERP_PUSH_LMF_WITH_CTX. */
2007 #ifdef _MSC_VER
2008 #pragma optimize ("", off)
2009 #endif
2010 static MONO_NO_OPTIMIZATION MONO_NEVER_INLINE stackval *
2011 do_icall_wrapper (InterpFrame *frame, MonoMethodSignature *sig, int op, stackval *sp, gpointer ptr, gboolean save_last_error)
2013 MonoLMFExt ext;
2014 INTERP_PUSH_LMF_WITH_CTX (frame, ext, exit_icall);
2016 sp = do_icall (sig, op, sp, ptr, save_last_error);
2018 interp_pop_lmf (&ext);
2020 goto exit_icall; // prevent unused label warning in some configurations
2021 exit_icall:
2022 return sp;
2024 #ifdef _MSC_VER
2025 #pragma optimize ("", on)
2026 #endif
2028 typedef struct {
2029 int pindex;
2030 gpointer jit_wrapper;
2031 gpointer *args;
2032 MonoFtnDesc *ftndesc;
2033 } JitCallCbData;
2035 static void
2036 jit_call_cb (gpointer arg)
2038 JitCallCbData *cb_data = (JitCallCbData*)arg;
2039 gpointer jit_wrapper = cb_data->jit_wrapper;
2040 int pindex = cb_data->pindex;
2041 gpointer *args = cb_data->args;
2042 MonoFtnDesc ftndesc = *cb_data->ftndesc;
2044 switch (pindex) {
2045 case 0: {
2046 typedef void (*T)(gpointer);
2047 T func = (T)jit_wrapper;
2049 func (&ftndesc);
2050 break;
2052 case 1: {
2053 typedef void (*T)(gpointer, gpointer);
2054 T func = (T)jit_wrapper;
2056 func (args [0], &ftndesc);
2057 break;
2059 case 2: {
2060 typedef void (*T)(gpointer, gpointer, gpointer);
2061 T func = (T)jit_wrapper;
2063 func (args [0], args [1], &ftndesc);
2064 break;
2066 case 3: {
2067 typedef void (*T)(gpointer, gpointer, gpointer, gpointer);
2068 T func = (T)jit_wrapper;
2070 func (args [0], args [1], args [2], &ftndesc);
2071 break;
2073 case 4: {
2074 typedef void (*T)(gpointer, gpointer, gpointer, gpointer, gpointer);
2075 T func = (T)jit_wrapper;
2077 func (args [0], args [1], args [2], args [3], &ftndesc);
2078 break;
2080 case 5: {
2081 typedef void (*T)(gpointer, gpointer, gpointer, gpointer, gpointer, gpointer);
2082 T func = (T)jit_wrapper;
2084 func (args [0], args [1], args [2], args [3], args [4], &ftndesc);
2085 break;
2087 case 6: {
2088 typedef void (*T)(gpointer, gpointer, gpointer, gpointer, gpointer, gpointer, gpointer);
2089 T func = (T)jit_wrapper;
2091 func (args [0], args [1], args [2], args [3], args [4], args [5], &ftndesc);
2092 break;
2094 case 7: {
2095 typedef void (*T)(gpointer, gpointer, gpointer, gpointer, gpointer, gpointer, gpointer, gpointer);
2096 T func = (T)jit_wrapper;
2098 func (args [0], args [1], args [2], args [3], args [4], args [5], args [6], &ftndesc);
2099 break;
2101 case 8: {
2102 typedef void (*T)(gpointer, gpointer, gpointer, gpointer, gpointer, gpointer, gpointer, gpointer, gpointer);
2103 T func = (T)jit_wrapper;
2105 func (args [0], args [1], args [2], args [3], args [4], args [5], args [6], args [7], &ftndesc);
2106 break;
2108 default:
2109 g_assert_not_reached ();
2110 break;
2114 static MONO_NEVER_INLINE stackval *
2115 do_jit_call (stackval *sp, unsigned char *vt_sp, ThreadContext *context, InterpFrame *frame, InterpMethod *rmethod, MonoError *error)
2117 MonoMethodSignature *sig;
2118 MonoFtnDesc ftndesc;
2119 guint8 res_buf [256];
2120 MonoType *type;
2121 MonoLMFExt ext;
2123 //printf ("jit_call: %s\n", mono_method_full_name (rmethod->method, 1));
2126 * Call JITted code through a gsharedvt_out wrapper. These wrappers receive every argument
2127 * by ref and return a return value using an explicit return value argument.
2129 if (!rmethod->jit_wrapper) {
2130 MonoMethod *method = rmethod->method;
2132 sig = mono_method_signature_internal (method);
2133 g_assert (sig);
2135 MonoMethod *wrapper = mini_get_gsharedvt_out_sig_wrapper (sig);
2136 //printf ("J: %s %s\n", mono_method_full_name (method, 1), mono_method_full_name (wrapper, 1));
2138 gpointer jit_wrapper = mono_jit_compile_method_jit_only (wrapper, error);
2139 mono_error_assert_ok (error);
2141 gpointer addr = mono_jit_compile_method_jit_only (method, error);
2142 return_val_if_nok (error, NULL);
2143 g_assert (addr);
2145 rmethod->jit_addr = addr;
2146 rmethod->jit_sig = sig;
2147 mono_memory_barrier ();
2148 rmethod->jit_wrapper = jit_wrapper;
2150 } else {
2151 sig = rmethod->jit_sig;
2154 sp -= sig->param_count;
2155 if (sig->hasthis)
2156 --sp;
2158 ftndesc.addr = rmethod->jit_addr;
2159 ftndesc.arg = NULL;
2161 // FIXME: Optimize this
2163 gpointer args [32];
2164 int pindex = 0;
2165 int stack_index = 0;
2166 if (rmethod->hasthis) {
2167 args [pindex ++] = sp [0].data.p;
2168 stack_index ++;
2170 type = rmethod->rtype;
2171 if (type->type != MONO_TYPE_VOID) {
2172 if (MONO_TYPE_ISSTRUCT (type))
2173 args [pindex ++] = vt_sp;
2174 else
2175 args [pindex ++] = res_buf;
2177 for (int i = 0; i < rmethod->param_count; ++i) {
2178 MonoType *t = rmethod->param_types [i];
2179 stackval *sval = &sp [stack_index + i];
2180 if (sig->params [i]->byref) {
2181 args [pindex ++] = sval->data.p;
2182 } else if (MONO_TYPE_ISSTRUCT (t)) {
2183 args [pindex ++] = sval->data.p;
2184 } else if (MONO_TYPE_IS_REFERENCE (t)) {
2185 args [pindex ++] = &sval->data.p;
2186 } else {
2187 switch (t->type) {
2188 case MONO_TYPE_I1:
2189 case MONO_TYPE_U1:
2190 case MONO_TYPE_I2:
2191 case MONO_TYPE_U2:
2192 case MONO_TYPE_I4:
2193 case MONO_TYPE_U4:
2194 case MONO_TYPE_VALUETYPE:
2195 args [pindex ++] = &sval->data.i;
2196 break;
2197 case MONO_TYPE_PTR:
2198 case MONO_TYPE_FNPTR:
2199 case MONO_TYPE_I:
2200 case MONO_TYPE_U:
2201 case MONO_TYPE_OBJECT:
2202 args [pindex ++] = &sval->data.p;
2203 break;
2204 case MONO_TYPE_I8:
2205 case MONO_TYPE_U8:
2206 args [pindex ++] = &sval->data.l;
2207 break;
2208 case MONO_TYPE_R4:
2209 args [pindex ++] = &sval->data.f_r4;
2210 break;
2211 case MONO_TYPE_R8:
2212 args [pindex ++] = &sval->data.f;
2213 break;
2214 default:
2215 printf ("%s\n", mono_type_full_name (t));
2216 g_assert_not_reached ();
2221 interp_push_lmf (&ext, frame);
2223 JitCallCbData cb_data;
2224 memset (&cb_data, 0, sizeof (cb_data));
2225 cb_data.jit_wrapper = rmethod->jit_wrapper;
2226 cb_data.pindex = pindex;
2227 cb_data.args = args;
2228 cb_data.ftndesc = &ftndesc;
2230 if (mono_aot_mode == MONO_AOT_MODE_LLVMONLY_INTERP) {
2231 /* Catch the exception thrown by the native code using a try-catch */
2232 gboolean thrown = FALSE;
2233 mono_llvm_cpp_catch_exception (jit_call_cb, &cb_data, &thrown);
2234 interp_pop_lmf (&ext);
2235 if (thrown) {
2236 MonoObject *obj = mono_llvm_load_exception ();
2237 g_assert (obj);
2238 mono_error_set_exception_instance (error, (MonoException*)obj);
2239 return sp;
2241 } else {
2242 jit_call_cb (&cb_data);
2243 interp_pop_lmf (&ext);
2246 MonoType *rtype = rmethod->rtype;
2247 switch (rtype->type) {
2248 case MONO_TYPE_VOID:
2249 case MONO_TYPE_OBJECT:
2250 case MONO_TYPE_STRING:
2251 case MONO_TYPE_CLASS:
2252 case MONO_TYPE_ARRAY:
2253 case MONO_TYPE_SZARRAY:
2254 case MONO_TYPE_I:
2255 case MONO_TYPE_U:
2256 case MONO_TYPE_PTR:
2257 sp->data.p = *(gpointer*)res_buf;
2258 break;
2259 case MONO_TYPE_I1:
2260 sp->data.i = *(gint8*)res_buf;
2261 break;
2262 case MONO_TYPE_U1:
2263 sp->data.i = *(guint8*)res_buf;
2264 break;
2265 case MONO_TYPE_I2:
2266 sp->data.i = *(gint16*)res_buf;
2267 break;
2268 case MONO_TYPE_U2:
2269 sp->data.i = *(guint16*)res_buf;
2270 break;
2271 case MONO_TYPE_I4:
2272 sp->data.i = *(gint32*)res_buf;
2273 break;
2274 case MONO_TYPE_U4:
2275 sp->data.i = *(guint32*)res_buf;
2276 break;
2277 case MONO_TYPE_I8:
2278 sp->data.l = *(gint64*)res_buf;
2279 break;
2280 case MONO_TYPE_U8:
2281 sp->data.l = *(guint64*)res_buf;
2282 break;
2283 case MONO_TYPE_R4:
2284 sp->data.f_r4 = *(float*)res_buf;
2285 break;
2286 case MONO_TYPE_R8:
2287 sp->data.f = *(double*)res_buf;
2288 break;
2289 case MONO_TYPE_TYPEDBYREF:
2290 case MONO_TYPE_VALUETYPE:
2291 /* The result was written to vt_sp */
2292 sp->data.p = vt_sp;
2293 break;
2294 case MONO_TYPE_GENERICINST:
2295 if (MONO_TYPE_IS_REFERENCE (rtype)) {
2296 sp->data.p = *(gpointer*)res_buf;
2297 } else {
2298 /* The result was written to vt_sp */
2299 sp->data.p = vt_sp;
2301 break;
2302 default:
2303 g_print ("%s\n", mono_type_full_name (rtype));
2304 g_assert_not_reached ();
2305 break;
2308 return sp;
2311 static MONO_NEVER_INLINE void
2312 do_debugger_tramp (void (*tramp) (void), InterpFrame *frame)
2314 MonoLMFExt ext;
2315 interp_push_lmf (&ext, frame);
2316 tramp ();
2317 interp_pop_lmf (&ext);
2320 static MONO_NEVER_INLINE MonoException*
2321 do_transform_method (InterpFrame *frame, ThreadContext *context)
2323 MonoLMFExt ext;
2324 /* Don't push lmf if we have no interp data */
2325 gboolean push_lmf = frame->parent != NULL;
2326 ERROR_DECL (error);
2328 /* Use the parent frame as the current frame is not complete yet */
2329 if (push_lmf)
2330 interp_push_lmf (&ext, frame->parent);
2332 mono_interp_transform_method (frame->imethod, context, error);
2334 if (push_lmf)
2335 interp_pop_lmf (&ext);
2337 return mono_error_convert_to_exception (error);
2340 static MONO_NEVER_INLINE guchar*
2341 copy_varargs_vtstack (MonoMethodSignature *csig, stackval *sp, guchar *vt_sp_start)
2343 stackval *first_arg = sp - csig->param_count;
2344 guchar *vt_sp = vt_sp_start;
2347 * We need to have the varargs linearly on the stack so the ArgIterator
2348 * can iterate over them. We pass the signature first and then copy them
2349 * one by one on the vtstack. At the end we pass the original vt_stack
2350 * so the callee (MINT_ARGLIST) can find the varargs space.
2352 *(gpointer*)vt_sp = csig;
2353 vt_sp += sizeof (gpointer);
2355 for (int i = csig->sentinelpos; i < csig->param_count; i++) {
2356 int align, arg_size;
2357 arg_size = mono_type_stack_size (csig->params [i], &align);
2358 vt_sp = (guchar*)ALIGN_PTR_TO (vt_sp, align);
2360 stackval_to_data (csig->params [i], &first_arg [i], vt_sp, FALSE);
2361 vt_sp += arg_size;
2364 vt_sp += sizeof (gpointer);
2365 vt_sp = (guchar*)ALIGN_PTR_TO (vt_sp, MINT_VT_ALIGNMENT);
2367 ((gpointer*)vt_sp) [-1] = vt_sp_start;
2369 return vt_sp;
2373 * These functions are the entry points into the interpreter from compiled code.
2374 * They are called by the interp_in wrappers. They have the following signature:
2375 * void (<optional this_arg>, <optional retval pointer>, <arg1>, ..., <argn>, <method ptr>)
2376 * They pack up their arguments into an InterpEntryData structure and call interp_entry ().
2377 * It would be possible for the wrappers to pack up the arguments etc, but that would make them bigger, and there are
2378 * more wrappers then these functions.
2379 * this/static * ret/void * 16 arguments -> 64 functions.
2382 #define MAX_INTERP_ENTRY_ARGS 8
2384 #define INTERP_ENTRY_BASE(_method, _this_arg, _res) \
2385 InterpEntryData data; \
2386 (data).rmethod = (_method); \
2387 (data).res = (_res); \
2388 (data).this_arg = (_this_arg); \
2389 (data).many_args = NULL;
2391 #define INTERP_ENTRY0(_this_arg, _res, _method) { \
2392 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2393 interp_entry (&data); \
2395 #define INTERP_ENTRY1(_this_arg, _res, _method) { \
2396 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2397 (data).args [0] = arg1; \
2398 interp_entry (&data); \
2400 #define INTERP_ENTRY2(_this_arg, _res, _method) { \
2401 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2402 (data).args [0] = arg1; \
2403 (data).args [1] = arg2; \
2404 interp_entry (&data); \
2406 #define INTERP_ENTRY3(_this_arg, _res, _method) { \
2407 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2408 (data).args [0] = arg1; \
2409 (data).args [1] = arg2; \
2410 (data).args [2] = arg3; \
2411 interp_entry (&data); \
2413 #define INTERP_ENTRY4(_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 interp_entry (&data); \
2421 #define INTERP_ENTRY5(_this_arg, _res, _method) { \
2422 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2423 (data).args [0] = arg1; \
2424 (data).args [1] = arg2; \
2425 (data).args [2] = arg3; \
2426 (data).args [3] = arg4; \
2427 (data).args [4] = arg5; \
2428 interp_entry (&data); \
2430 #define INTERP_ENTRY6(_this_arg, _res, _method) { \
2431 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2432 (data).args [0] = arg1; \
2433 (data).args [1] = arg2; \
2434 (data).args [2] = arg3; \
2435 (data).args [3] = arg4; \
2436 (data).args [4] = arg5; \
2437 (data).args [5] = arg6; \
2438 interp_entry (&data); \
2440 #define INTERP_ENTRY7(_this_arg, _res, _method) { \
2441 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2442 (data).args [0] = arg1; \
2443 (data).args [1] = arg2; \
2444 (data).args [2] = arg3; \
2445 (data).args [3] = arg4; \
2446 (data).args [4] = arg5; \
2447 (data).args [5] = arg6; \
2448 (data).args [6] = arg7; \
2449 interp_entry (&data); \
2451 #define INTERP_ENTRY8(_this_arg, _res, _method) { \
2452 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2453 (data).args [0] = arg1; \
2454 (data).args [1] = arg2; \
2455 (data).args [2] = arg3; \
2456 (data).args [3] = arg4; \
2457 (data).args [4] = arg5; \
2458 (data).args [5] = arg6; \
2459 (data).args [6] = arg7; \
2460 (data).args [7] = arg8; \
2461 interp_entry (&data); \
2464 #define ARGLIST0 InterpMethod *rmethod
2465 #define ARGLIST1 gpointer arg1, InterpMethod *rmethod
2466 #define ARGLIST2 gpointer arg1, gpointer arg2, InterpMethod *rmethod
2467 #define ARGLIST3 gpointer arg1, gpointer arg2, gpointer arg3, InterpMethod *rmethod
2468 #define ARGLIST4 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, InterpMethod *rmethod
2469 #define ARGLIST5 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, gpointer arg5, InterpMethod *rmethod
2470 #define ARGLIST6 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, gpointer arg5, gpointer arg6, InterpMethod *rmethod
2471 #define ARGLIST7 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, gpointer arg5, gpointer arg6, gpointer arg7, InterpMethod *rmethod
2472 #define ARGLIST8 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, gpointer arg5, gpointer arg6, gpointer arg7, gpointer arg8, InterpMethod *rmethod
2474 static void interp_entry_static_0 (ARGLIST0) INTERP_ENTRY0 (NULL, NULL, rmethod)
2475 static void interp_entry_static_1 (ARGLIST1) INTERP_ENTRY1 (NULL, NULL, rmethod)
2476 static void interp_entry_static_2 (ARGLIST2) INTERP_ENTRY2 (NULL, NULL, rmethod)
2477 static void interp_entry_static_3 (ARGLIST3) INTERP_ENTRY3 (NULL, NULL, rmethod)
2478 static void interp_entry_static_4 (ARGLIST4) INTERP_ENTRY4 (NULL, NULL, rmethod)
2479 static void interp_entry_static_5 (ARGLIST5) INTERP_ENTRY5 (NULL, NULL, rmethod)
2480 static void interp_entry_static_6 (ARGLIST6) INTERP_ENTRY6 (NULL, NULL, rmethod)
2481 static void interp_entry_static_7 (ARGLIST7) INTERP_ENTRY7 (NULL, NULL, rmethod)
2482 static void interp_entry_static_8 (ARGLIST8) INTERP_ENTRY8 (NULL, NULL, rmethod)
2483 static void interp_entry_static_ret_0 (gpointer res, ARGLIST0) INTERP_ENTRY0 (NULL, res, rmethod)
2484 static void interp_entry_static_ret_1 (gpointer res, ARGLIST1) INTERP_ENTRY1 (NULL, res, rmethod)
2485 static void interp_entry_static_ret_2 (gpointer res, ARGLIST2) INTERP_ENTRY2 (NULL, res, rmethod)
2486 static void interp_entry_static_ret_3 (gpointer res, ARGLIST3) INTERP_ENTRY3 (NULL, res, rmethod)
2487 static void interp_entry_static_ret_4 (gpointer res, ARGLIST4) INTERP_ENTRY4 (NULL, res, rmethod)
2488 static void interp_entry_static_ret_5 (gpointer res, ARGLIST5) INTERP_ENTRY5 (NULL, res, rmethod)
2489 static void interp_entry_static_ret_6 (gpointer res, ARGLIST6) INTERP_ENTRY6 (NULL, res, rmethod)
2490 static void interp_entry_static_ret_7 (gpointer res, ARGLIST7) INTERP_ENTRY7 (NULL, res, rmethod)
2491 static void interp_entry_static_ret_8 (gpointer res, ARGLIST8) INTERP_ENTRY8 (NULL, res, rmethod)
2492 static void interp_entry_instance_0 (gpointer this_arg, ARGLIST0) INTERP_ENTRY0 (this_arg, NULL, rmethod)
2493 static void interp_entry_instance_1 (gpointer this_arg, ARGLIST1) INTERP_ENTRY1 (this_arg, NULL, rmethod)
2494 static void interp_entry_instance_2 (gpointer this_arg, ARGLIST2) INTERP_ENTRY2 (this_arg, NULL, rmethod)
2495 static void interp_entry_instance_3 (gpointer this_arg, ARGLIST3) INTERP_ENTRY3 (this_arg, NULL, rmethod)
2496 static void interp_entry_instance_4 (gpointer this_arg, ARGLIST4) INTERP_ENTRY4 (this_arg, NULL, rmethod)
2497 static void interp_entry_instance_5 (gpointer this_arg, ARGLIST5) INTERP_ENTRY5 (this_arg, NULL, rmethod)
2498 static void interp_entry_instance_6 (gpointer this_arg, ARGLIST6) INTERP_ENTRY6 (this_arg, NULL, rmethod)
2499 static void interp_entry_instance_7 (gpointer this_arg, ARGLIST7) INTERP_ENTRY7 (this_arg, NULL, rmethod)
2500 static void interp_entry_instance_8 (gpointer this_arg, ARGLIST8) INTERP_ENTRY8 (this_arg, NULL, rmethod)
2501 static void interp_entry_instance_ret_0 (gpointer this_arg, gpointer res, ARGLIST0) INTERP_ENTRY0 (this_arg, res, rmethod)
2502 static void interp_entry_instance_ret_1 (gpointer this_arg, gpointer res, ARGLIST1) INTERP_ENTRY1 (this_arg, res, rmethod)
2503 static void interp_entry_instance_ret_2 (gpointer this_arg, gpointer res, ARGLIST2) INTERP_ENTRY2 (this_arg, res, rmethod)
2504 static void interp_entry_instance_ret_3 (gpointer this_arg, gpointer res, ARGLIST3) INTERP_ENTRY3 (this_arg, res, rmethod)
2505 static void interp_entry_instance_ret_4 (gpointer this_arg, gpointer res, ARGLIST4) INTERP_ENTRY4 (this_arg, res, rmethod)
2506 static void interp_entry_instance_ret_5 (gpointer this_arg, gpointer res, ARGLIST5) INTERP_ENTRY5 (this_arg, res, rmethod)
2507 static void interp_entry_instance_ret_6 (gpointer this_arg, gpointer res, ARGLIST6) INTERP_ENTRY6 (this_arg, res, rmethod)
2508 static void interp_entry_instance_ret_7 (gpointer this_arg, gpointer res, ARGLIST7) INTERP_ENTRY7 (this_arg, res, rmethod)
2509 static void interp_entry_instance_ret_8 (gpointer this_arg, gpointer res, ARGLIST8) INTERP_ENTRY8 (this_arg, res, rmethod)
2511 #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
2513 static gpointer entry_funcs_static [MAX_INTERP_ENTRY_ARGS + 1] = { INTERP_ENTRY_FUNCLIST (static) };
2514 static gpointer entry_funcs_static_ret [MAX_INTERP_ENTRY_ARGS + 1] = { INTERP_ENTRY_FUNCLIST (static_ret) };
2515 static gpointer entry_funcs_instance [MAX_INTERP_ENTRY_ARGS + 1] = { INTERP_ENTRY_FUNCLIST (instance) };
2516 static gpointer entry_funcs_instance_ret [MAX_INTERP_ENTRY_ARGS + 1] = { INTERP_ENTRY_FUNCLIST (instance_ret) };
2518 /* General version for methods with more than MAX_INTERP_ENTRY_ARGS arguments */
2519 static void
2520 interp_entry_general (gpointer this_arg, gpointer res, gpointer *args, gpointer rmethod)
2522 INTERP_ENTRY_BASE ((InterpMethod*)rmethod, this_arg, res);
2523 data.many_args = args;
2524 interp_entry (&data);
2527 #ifdef MONO_ARCH_HAVE_INTERP_ENTRY_TRAMPOLINE
2529 // inline so we can alloc on stack
2530 #define alloc_storage_for_stackval(s, t, p) do { \
2531 if ((t)->type == MONO_TYPE_GENERICINST && !MONO_TYPE_IS_REFERENCE (t)) { \
2532 (s)->data.vt = alloca (mono_class_value_size (mono_class_from_mono_type_internal (t), NULL)); \
2533 } else if ((t)->type == MONO_TYPE_VALUETYPE) { \
2534 if (p) \
2535 (s)->data.vt = alloca (mono_class_native_size ((t)->data.klass, NULL)); \
2536 else \
2537 (s)->data.vt = alloca (mono_class_value_size ((t)->data.klass, NULL)); \
2539 } while (0)
2541 static void
2542 interp_entry_from_trampoline (gpointer ccontext_untyped, gpointer rmethod_untyped)
2544 InterpFrame frame;
2545 ThreadContext *context;
2546 stackval result;
2547 stackval *args;
2548 MonoMethod *method;
2549 MonoMethodSignature *sig;
2550 CallContext *ccontext = (CallContext*) ccontext_untyped;
2551 InterpMethod *rmethod = (InterpMethod*) rmethod_untyped;
2552 gpointer orig_domain = NULL, attach_cookie;
2553 int i;
2555 if (rmethod->needs_thread_attach)
2556 orig_domain = mono_threads_attach_coop (mono_domain_get (), &attach_cookie);
2558 context = get_context ();
2560 method = rmethod->method;
2561 sig = mono_method_signature_internal (method);
2563 args = (stackval*)alloca (sizeof (stackval) * (sig->param_count + (sig->hasthis ? 1 : 0)));
2565 init_frame (&frame, NULL, rmethod, args, &result);
2567 /* Allocate storage for value types */
2568 for (i = 0; i < sig->param_count; i++) {
2569 MonoType *type = sig->params [i];
2570 alloc_storage_for_stackval (&frame.stack_args [i + sig->hasthis], type, sig->pinvoke);
2573 if (sig->ret->type != MONO_TYPE_VOID)
2574 alloc_storage_for_stackval (frame.retval, sig->ret, sig->pinvoke);
2576 /* Copy the args saved in the trampoline to the frame stack */
2577 mono_arch_get_native_call_context_args (ccontext, &frame, sig);
2579 ERROR_DECL (error);
2580 interp_exec_method (&frame, context, error);
2582 g_assert (!context->has_resume_state);
2584 if (rmethod->needs_thread_attach)
2585 mono_threads_detach_coop (orig_domain, &attach_cookie);
2587 /* Write back the return value */
2588 mono_arch_set_native_call_context_ret (ccontext, &frame, sig);
2591 #else
2593 static void
2594 interp_entry_from_trampoline (gpointer ccontext_untyped, gpointer rmethod_untyped)
2596 g_assert_not_reached ();
2599 #endif /* MONO_ARCH_HAVE_INTERP_ENTRY_TRAMPOLINE */
2601 static InterpMethod*
2602 lookup_method_pointer (gpointer addr)
2604 MonoDomain *domain = mono_domain_get ();
2605 MonoJitDomainInfo *info = domain_jit_info (domain);
2606 InterpMethod *res = NULL;
2608 mono_domain_lock (domain);
2609 if (info->interp_method_pointer_hash)
2610 res = (InterpMethod*)g_hash_table_lookup (info->interp_method_pointer_hash, addr);
2611 mono_domain_unlock (domain);
2613 return res;
2616 #ifndef MONO_ARCH_HAVE_INTERP_NATIVE_TO_MANAGED
2617 static void
2618 interp_no_native_to_managed (void)
2620 g_error ("interpreter: native-to-managed transition not available on this platform");
2622 #endif
2624 static void
2625 no_llvmonly_interp_method_pointer (void)
2627 g_assert_not_reached ();
2631 * interp_create_method_pointer_llvmonly:
2633 * Return an ftndesc for entering the interpreter and executing METHOD.
2635 static MonoFtnDesc*
2636 interp_create_method_pointer_llvmonly (MonoMethod *method, gboolean unbox, MonoError *error)
2638 MonoDomain *domain = mono_domain_get ();
2639 gpointer addr, entry_func, entry_wrapper;
2640 MonoMethodSignature *sig;
2641 MonoMethod *wrapper;
2642 MonoJitDomainInfo *info;
2643 InterpMethod *imethod;
2645 imethod = mono_interp_get_imethod (domain, method, error);
2646 return_val_if_nok (error, NULL);
2648 if (unbox) {
2649 if (imethod->llvmonly_unbox_entry)
2650 return (MonoFtnDesc*)imethod->llvmonly_unbox_entry;
2651 } else {
2652 if (imethod->jit_entry)
2653 return (MonoFtnDesc*)imethod->jit_entry;
2656 sig = mono_method_signature_internal (method);
2659 * The entry functions need access to the method to call, so we have
2660 * to use a ftndesc. The caller uses a normal signature, while the
2661 * entry functions use a gsharedvt_in signature, so wrap the entry function in
2662 * a gsharedvt_in_sig wrapper.
2664 wrapper = mini_get_gsharedvt_in_sig_wrapper (sig);
2666 entry_wrapper = mono_jit_compile_method_jit_only (wrapper, error);
2667 mono_error_assertf_ok (error, "couldn't compile wrapper \"%s\" for \"%s\"",
2668 mono_method_get_name_full (wrapper, TRUE, TRUE, MONO_TYPE_NAME_FORMAT_IL),
2669 mono_method_get_name_full (method, TRUE, TRUE, MONO_TYPE_NAME_FORMAT_IL));
2671 if (sig->param_count > MAX_INTERP_ENTRY_ARGS) {
2672 g_assert_not_reached ();
2673 //entry_func = (gpointer)interp_entry_general;
2674 } else if (sig->hasthis) {
2675 if (sig->ret->type == MONO_TYPE_VOID)
2676 entry_func = entry_funcs_instance [sig->param_count];
2677 else
2678 entry_func = entry_funcs_instance_ret [sig->param_count];
2679 } else {
2680 if (sig->ret->type == MONO_TYPE_VOID)
2681 entry_func = entry_funcs_static [sig->param_count];
2682 else
2683 entry_func = entry_funcs_static_ret [sig->param_count];
2685 g_assert (entry_func);
2687 /* Encode unbox in the lower bit of imethod */
2688 gpointer entry_arg = imethod;
2689 if (unbox)
2690 entry_arg = (gpointer)(((gsize)entry_arg) | 1);
2691 MonoFtnDesc *entry_ftndesc = mini_llvmonly_create_ftndesc (mono_domain_get (), entry_func, entry_arg);
2693 addr = mini_llvmonly_create_ftndesc (mono_domain_get (), entry_wrapper, entry_ftndesc);
2695 info = domain_jit_info (domain);
2696 mono_domain_lock (domain);
2697 if (!info->interp_method_pointer_hash)
2698 info->interp_method_pointer_hash = g_hash_table_new (NULL, NULL);
2699 g_hash_table_insert (info->interp_method_pointer_hash, addr, imethod);
2700 mono_domain_unlock (domain);
2702 mono_memory_barrier ();
2703 if (unbox)
2704 imethod->llvmonly_unbox_entry = addr;
2705 else
2706 imethod->jit_entry = addr;
2708 return (MonoFtnDesc*)addr;
2712 * interp_create_method_pointer:
2714 * Return a function pointer which can be used to call METHOD using the
2715 * interpreter. Return NULL for methods which are not supported.
2717 static gpointer
2718 interp_create_method_pointer (MonoMethod *method, gboolean compile, MonoError *error)
2720 #ifndef MONO_ARCH_HAVE_INTERP_NATIVE_TO_MANAGED
2721 if (mono_llvm_only)
2722 return (gpointer)no_llvmonly_interp_method_pointer;
2723 return (gpointer)interp_no_native_to_managed;
2724 #else
2725 gpointer addr, entry_func, entry_wrapper = NULL;
2726 MonoDomain *domain = mono_domain_get ();
2727 MonoJitDomainInfo *info;
2728 InterpMethod *imethod = mono_interp_get_imethod (domain, method, error);
2730 if (mono_llvm_only)
2731 return (gpointer)no_llvmonly_interp_method_pointer;
2733 if (imethod->jit_entry)
2734 return imethod->jit_entry;
2736 if (compile && !imethod->transformed) {
2737 /* Return any errors from method compilation */
2738 mono_interp_transform_method (imethod, get_context (), error);
2739 return_val_if_nok (error, NULL);
2742 MonoMethodSignature *sig = mono_method_signature_internal (method);
2744 if (mono_llvm_only)
2745 /* The caller should call interp_create_method_pointer_llvmonly */
2746 g_assert_not_reached ();
2748 if (method->wrapper_type && method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE)
2749 return imethod;
2751 #ifndef MONO_ARCH_HAVE_FTNPTR_ARG_TRAMPOLINE
2753 * Interp in wrappers get the argument in the rgctx register. If
2754 * MONO_ARCH_HAVE_FTNPTR_ARG_TRAMPOLINE is defined it means that
2755 * on that arch the rgctx register is not scratch, so we use a
2756 * separate temp register. We should update the wrappers for this
2757 * if we really care about those architectures (arm).
2759 MonoMethod *wrapper = mini_get_interp_in_wrapper (sig);
2761 entry_wrapper = mono_jit_compile_method_jit_only (wrapper, error);
2762 #endif
2763 if (entry_wrapper) {
2764 if (sig->param_count > MAX_INTERP_ENTRY_ARGS) {
2765 entry_func = (gpointer)interp_entry_general;
2766 } else if (sig->hasthis) {
2767 if (sig->ret->type == MONO_TYPE_VOID)
2768 entry_func = entry_funcs_instance [sig->param_count];
2769 else
2770 entry_func = entry_funcs_instance_ret [sig->param_count];
2771 } else {
2772 if (sig->ret->type == MONO_TYPE_VOID)
2773 entry_func = entry_funcs_static [sig->param_count];
2774 else
2775 entry_func = entry_funcs_static_ret [sig->param_count];
2777 } else {
2778 #ifndef MONO_ARCH_HAVE_INTERP_ENTRY_TRAMPOLINE
2779 mono_error_assertf_ok (error, "couldn't compile wrapper \"%s\" for \"%s\"",
2780 mono_method_get_name_full (wrapper, TRUE, TRUE, MONO_TYPE_NAME_FORMAT_IL),
2781 mono_method_get_name_full (method, TRUE, TRUE, MONO_TYPE_NAME_FORMAT_IL));
2782 #else
2783 mono_error_cleanup (error);
2784 error_init_reuse (error);
2785 if (!mono_native_to_interp_trampoline) {
2786 if (mono_aot_only) {
2787 mono_native_to_interp_trampoline = (MonoFuncV)mono_aot_get_trampoline ("native_to_interp_trampoline");
2788 } else {
2789 MonoTrampInfo *info;
2790 mono_native_to_interp_trampoline = (MonoFuncV)mono_arch_get_native_to_interp_trampoline (&info);
2791 mono_tramp_info_register (info, NULL);
2794 entry_wrapper = (gpointer)mono_native_to_interp_trampoline;
2795 /* We need the lmf wrapper only when being called from mixed mode */
2796 if (sig->pinvoke)
2797 entry_func = (gpointer)interp_entry_from_trampoline;
2798 else {
2799 static gpointer cached_func = NULL;
2800 if (!cached_func) {
2801 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);
2802 mono_memory_barrier ();
2804 entry_func = cached_func;
2806 #endif
2809 g_assert (entry_func);
2810 /* This is the argument passed to the interp_in wrapper by the static rgctx trampoline */
2811 MonoFtnDesc *ftndesc = g_new0 (MonoFtnDesc, 1);
2812 ftndesc->addr = entry_func;
2813 ftndesc->arg = imethod;
2814 mono_error_assert_ok (error);
2817 * The wrapper is called by compiled code, which doesn't pass the extra argument, so we pass it in the
2818 * rgctx register using a trampoline.
2821 addr = mono_create_ftnptr_arg_trampoline (ftndesc, entry_wrapper);
2823 info = domain_jit_info (domain);
2824 mono_domain_lock (domain);
2825 if (!info->interp_method_pointer_hash)
2826 info->interp_method_pointer_hash = g_hash_table_new (NULL, NULL);
2827 g_hash_table_insert (info->interp_method_pointer_hash, addr, imethod);
2828 mono_domain_unlock (domain);
2830 mono_memory_barrier ();
2831 imethod->jit_entry = addr;
2833 return addr;
2834 #endif
2837 #if COUNT_OPS
2838 static long opcode_counts[MINT_LASTOP];
2840 #define COUNT_OP(op) opcode_counts[op]++
2841 #else
2842 #define COUNT_OP(op)
2843 #endif
2845 #if DEBUG_INTERP
2846 #define DUMP_INSTR() \
2847 if (tracing > 1) { \
2848 char *ins; \
2849 if (sp > frame->stack) { \
2850 ins = dump_stack (frame->stack, sp); \
2851 } else { \
2852 ins = g_strdup (""); \
2854 sp->data.l = 0; \
2855 output_indent (); \
2856 char *mn = mono_method_full_name (frame->imethod->method, FALSE); \
2857 char *disasm = mono_interp_dis_mintop (frame->imethod->code, ip); \
2858 g_print ("(%p) %s -> %s\t%d:%s\n", mono_thread_internal_current (), mn, disasm, vt_sp - vtalloc, ins); \
2859 g_free (mn); \
2860 g_free (ins); \
2861 g_free (disasm); \
2863 #else
2864 #define DUMP_INSTR()
2865 #endif
2867 #define INIT_VTABLE(vtable) do { \
2868 if (G_UNLIKELY (!(vtable)->initialized)) { \
2869 mono_runtime_class_init_full ((vtable), error); \
2870 if (!is_ok (error)) \
2871 goto throw_error_label; \
2873 } while (0);
2875 static MONO_NEVER_INLINE MonoObject*
2876 mono_interp_new (MonoDomain* domain, MonoClass* klass)
2878 ERROR_DECL (error);
2879 MonoObject* const object = mono_object_new_checked (domain, klass, error);
2880 mono_error_cleanup (error); // FIXME: do not swallow the error
2881 return object;
2884 static
2885 #ifndef DISABLE_REMOTING
2886 MONO_NEVER_INLINE // To reduce stack.
2887 #endif
2888 void
2889 mono_interp_load_remote_field (
2890 InterpMethod* imethod,
2891 MonoObject* o,
2892 const guint16* ip,
2893 stackval* sp)
2895 g_assert (o); // Caller checks and throws exception properly.
2897 void* addr;
2898 MonoClassField* const field = (MonoClassField*)imethod->data_items[ip [1]];
2900 #ifndef DISABLE_REMOTING
2901 gpointer tmp;
2902 if (mono_object_is_transparent_proxy (o)) {
2903 MonoClass * const klass = ((MonoTransparentProxy*)o)->remote_class->proxy_class;
2904 ERROR_DECL (error);
2905 addr = mono_load_remote_field_checked (o, klass, field, &tmp, error);
2906 mono_error_cleanup (error); /* FIXME: don't swallow the error */
2907 } else
2908 #endif
2909 addr = (char*)o + field->offset;
2910 stackval_from_data (field->type, &sp [-1], addr, FALSE);
2913 static
2914 #ifndef DISABLE_REMOTING
2915 MONO_NEVER_INLINE // To reduce stack.
2916 #endif
2917 guchar* // Return new vt_sp instead of take-address.
2918 mono_interp_load_remote_field_vt (
2919 InterpMethod* imethod,
2920 MonoObject* o,
2921 const guint16* ip,
2922 stackval* sp,
2923 guchar* vt_sp)
2925 g_assert (o); // Caller checks and throws exception properly.
2927 void* addr;
2928 MonoClassField* const field = (MonoClassField*)imethod->data_items[ip [1]];
2929 MonoClass* klass = mono_class_from_mono_type_internal (field->type);
2930 int const i32 = mono_class_value_size (klass, NULL);
2932 #ifndef DISABLE_REMOTING
2933 gpointer tmp;
2934 if (mono_object_is_transparent_proxy (o)) {
2935 klass = ((MonoTransparentProxy*)o)->remote_class->proxy_class;
2936 ERROR_DECL (error);
2937 addr = mono_load_remote_field_checked (o, klass, field, &tmp, error);
2938 mono_error_cleanup (error); /* FIXME: don't swallow the error */
2939 } else
2940 #endif
2941 addr = (char*)o + field->offset;
2942 sp [-1].data.p = vt_sp;
2943 memcpy (vt_sp, addr, i32);
2944 return vt_sp + ALIGN_TO (i32, MINT_VT_ALIGNMENT);
2947 static MONO_NEVER_INLINE gboolean
2948 mono_interp_isinst (MonoObject* object, MonoClass* klass)
2950 ERROR_DECL (error);
2951 const gboolean isinst = mono_object_isinst_checked (object, klass, error) != NULL;
2952 mono_error_cleanup (error); // FIXME: do not swallow the error
2953 return isinst;
2956 // This function is outlined to help save stack in its caller, on the premise
2957 // that it is relatively rarely called. This also lets it use alloca.
2958 static MONO_NEVER_INLINE void
2959 mono_interp_calli_nat_dynamic_pinvoke (
2960 // Parameters are sorted by name.
2961 InterpFrame* child_frame,
2962 guchar* code,
2963 ThreadContext* context,
2964 MonoMethodSignature* csignature,
2965 MonoError* error)
2967 // Recompute to limit parameters, which can also contribute to caller stack.
2968 InterpMethod* const imethod = child_frame->parent->imethod;
2970 g_assert (imethod->method->dynamic && csignature->pinvoke);
2972 /* Pinvoke call is missing the wrapper. See mono_get_native_calli_wrapper */
2973 MonoMarshalSpec** mspecs = g_newa (MonoMarshalSpec*, csignature->param_count + 1);
2974 memset (mspecs, 0, sizeof (MonoMarshalSpec*) * (csignature->param_count + 1));
2976 MonoMethodPInvoke iinfo;
2977 memset (&iinfo, 0, sizeof (iinfo));
2979 MonoMethod* m = mono_marshal_get_native_func_wrapper (m_class_get_image (imethod->method->klass), csignature, &iinfo, mspecs, code);
2981 for (int i = csignature->param_count; i >= 0; i--)
2982 if (mspecs [i])
2983 mono_metadata_free_marshal_spec (mspecs [i]);
2986 ERROR_DECL (error);
2987 child_frame->imethod = mono_interp_get_imethod (imethod->domain, m, error);
2988 mono_error_cleanup (error); /* FIXME: don't swallow the error */
2991 interp_exec_method (child_frame, context, error);
2994 // Leave is split into pieces in order to consume less stack,
2995 // but not have to change how exception handling macros access labels and locals.
2996 static MONO_NEVER_INLINE MonoException*
2997 mono_interp_leave (InterpFrame* child_frame)
2999 stackval tmp_sp;
3001 * We need for mono_thread_get_undeniable_exception to be able to unwind
3002 * to check the abort threshold. For this to work we use child_frame as a
3003 * dummy frame that is stored in the lmf and serves as the transition frame
3005 do_icall_wrapper (child_frame, NULL, MINT_ICALL_V_P, &tmp_sp, (gpointer)mono_thread_get_undeniable_exception, FALSE);
3007 return (MonoException*)tmp_sp.data.p;
3010 static MONO_NEVER_INLINE void
3011 mono_interp_newobj_vt (
3012 // Parameters are sorted by name and parameter list is minimized
3013 // to reduce stack use in caller, on e.g. NT/AMD64 (up to 4 parameters
3014 // use no stack in caller).
3015 InterpFrame* child_frame,
3016 ThreadContext* context,
3017 MonoError* error)
3019 stackval* const sp = child_frame->stack_args;
3021 stackval valuetype_this;
3023 memset (&valuetype_this, 0, sizeof (stackval));
3024 sp->data.p = &valuetype_this;
3026 // FIXME It is unfortunate to outline a recursive case as it
3027 // increases its stack usage. We do this however as it conserves
3028 // stack for all the other recursive cases.
3029 interp_exec_method (child_frame, context, error);
3031 CHECK_RESUME_STATE (context);
3033 *sp = valuetype_this;
3034 resume:
3038 static MONO_NEVER_INLINE MonoException*
3039 mono_interp_newobj (
3040 // Parameters are sorted by name and parameter list is minimized
3041 // to reduce stack use in caller, on e.g. NT/AMD64 (up to 4 parameters
3042 // use no stack in caller).
3043 InterpFrame* child_frame,
3044 ThreadContext* context,
3045 MonoError* error,
3046 guchar* vt_sp)
3048 InterpFrame* const frame = child_frame->parent;
3049 InterpMethod* const imethod = frame->imethod;
3050 stackval* const sp = child_frame->stack_args;
3052 MonoObject* o = NULL; // See the comment about GC safety.
3053 stackval valuetype_this;
3054 stackval retval;
3056 MonoClass * const newobj_class = child_frame->imethod->method->klass;
3057 /*if (profiling_classes) {
3058 guint count = GPOINTER_TO_UINT (g_hash_table_lookup (profiling_classes, newobj_class));
3059 count++;
3060 g_hash_table_insert (profiling_classes, newobj_class, GUINT_TO_POINTER (count));
3064 * First arg is the object.
3066 if (m_class_is_valuetype (newobj_class)) {
3067 MonoType *t = m_class_get_byval_arg (newobj_class);
3068 memset (&valuetype_this, 0, sizeof (stackval));
3069 if (!m_class_is_enumtype (newobj_class) && (t->type == MONO_TYPE_VALUETYPE || (t->type == MONO_TYPE_GENERICINST && mono_type_generic_inst_is_valuetype (t)))) {
3070 sp->data.p = vt_sp;
3071 valuetype_this.data.p = vt_sp;
3072 } else {
3073 sp->data.p = &valuetype_this;
3075 } else {
3076 if (newobj_class != mono_defaults.string_class) {
3077 MonoVTable *vtable = mono_class_vtable_checked (imethod->domain, newobj_class, error);
3078 if (!is_ok (error) || !mono_runtime_class_init_full (vtable, error)) {
3079 MonoException* const exc = mono_error_convert_to_exception (error);
3080 g_assert (exc);
3081 return exc;
3083 ERROR_DECL (error);
3084 OBJREF (o) = mono_object_new_checked (imethod->domain, newobj_class, error);
3085 mono_error_cleanup (error); // FIXME: do not swallow the error
3086 EXCEPTION_CHECKPOINT_IN_HELPER_FUNCTION;
3087 sp->data.o = o;
3088 #ifndef DISABLE_REMOTING
3089 if (mono_object_is_transparent_proxy (o)) {
3090 MonoMethod *remoting_invoke_method = mono_marshal_get_remoting_invoke_with_check (child_frame->imethod->method, error);
3091 mono_error_assert_ok (error);
3092 child_frame->imethod = mono_interp_get_imethod (imethod->domain, remoting_invoke_method, error);
3093 mono_error_assert_ok (error);
3095 #endif
3096 } else {
3097 sp->data.p = NULL;
3098 child_frame->retval = &retval;
3102 interp_exec_method (child_frame, context, error);
3104 CHECK_RESUME_STATE (context);
3107 * a constructor returns void, but we need to return the object we created
3109 if (m_class_is_valuetype (newobj_class) && !m_class_is_enumtype (newobj_class)) {
3110 *sp = valuetype_this;
3111 } else if (newobj_class == mono_defaults.string_class) {
3112 *sp = retval;
3113 } else {
3114 sp->data.o = o;
3116 resume:
3117 return NULL;
3120 static MONO_NEVER_INLINE void
3121 mono_interp_enum_hasflag (stackval* sp, MonoClass* klass)
3123 guint64 a_val = 0, b_val = 0;
3125 stackval_to_data (m_class_get_byval_arg (klass), --sp, &b_val, FALSE);
3126 stackval_to_data (m_class_get_byval_arg (klass), --sp, &a_val, FALSE);
3127 sp->data.i = (a_val & b_val) == b_val;
3130 static MONO_NEVER_INLINE int
3131 mono_interp_box_nullable (InterpFrame* frame, const guint16* ip, stackval* sp, MonoError* error)
3133 InterpMethod* const imethod = frame->imethod;
3134 MonoClass* const c = (MonoClass*)imethod->data_items [ip [1]];
3136 int const size = mono_class_value_size (c, NULL);
3138 guint16 offset = ip [2];
3139 gboolean const pop_vt_sp = !(offset & BOX_NOT_CLEAR_VT_SP);
3140 offset &= ~BOX_NOT_CLEAR_VT_SP;
3142 sp [-1 - offset].data.o = mono_nullable_box (sp [-1 - offset].data.p, c, error);
3143 mono_interp_error_cleanup (error); /* FIXME: don't swallow the error */
3145 return pop_vt_sp ? ALIGN_TO (size, MINT_VT_ALIGNMENT) : 0;
3148 static MONO_NEVER_INLINE int
3149 mono_interp_box_vt (InterpFrame* frame, const guint16* ip, stackval* sp)
3151 InterpMethod* const imethod = frame->imethod;
3153 MonoObject* o; // See the comment about GC safety.
3154 MonoVTable * const vtable = (MonoVTable*)imethod->data_items [ip [1]];
3155 MonoClass* const c = vtable->klass;
3157 int const size = mono_class_value_size (c, NULL);
3159 guint16 offset = ip [2];
3160 gboolean const pop_vt_sp = !(offset & BOX_NOT_CLEAR_VT_SP);
3161 offset &= ~BOX_NOT_CLEAR_VT_SP;
3163 OBJREF (o) = mono_gc_alloc_obj (vtable, m_class_get_instance_size (vtable->klass));
3164 mono_value_copy_internal (mono_object_get_data (o), sp [-1 - offset].data.p, c);
3166 sp [-1 - offset].data.p = o;
3167 return pop_vt_sp ? ALIGN_TO (size, MINT_VT_ALIGNMENT) : 0;
3170 static MONO_NEVER_INLINE void
3171 mono_interp_box (InterpFrame* frame, const guint16* ip, stackval* sp)
3173 MonoObject *o; // See the comment about GC safety.
3174 MonoVTable * const vtable = (MonoVTable*)frame->imethod->data_items [ip [1]];
3176 OBJREF (o) = mono_gc_alloc_obj (vtable, m_class_get_instance_size (vtable->klass));
3178 guint16 const offset = ip [2];
3180 stackval_to_data (m_class_get_byval_arg (vtable->klass), &sp [-1 - offset], mono_object_get_data (o), FALSE);
3182 sp [-1 - offset].data.p = o;
3185 static MONO_NEVER_INLINE int
3186 mono_interp_store_remote_field_vt (InterpFrame* frame, const guint16* ip, stackval* sp, MonoError* error)
3188 InterpMethod* const imethod = frame->imethod;
3189 MonoClassField *field;
3191 MonoObject* const o = sp [-2].data.o;
3193 field = (MonoClassField*)imethod->data_items[ip [1]];
3194 MonoClass *klass = mono_class_from_mono_type_internal (field->type);
3195 int const i32 = mono_class_value_size (klass, NULL);
3197 #ifndef DISABLE_REMOTING
3198 if (mono_object_is_transparent_proxy (o)) {
3199 MonoClass *klass = ((MonoTransparentProxy*)o)->remote_class->proxy_class;
3200 mono_store_remote_field_checked (o, klass, field, sp [-1].data.p, error);
3201 mono_interp_error_cleanup (error); /* FIXME: don't swallow the error */
3202 } else
3203 #endif
3204 mono_value_copy_internal ((char *) o + field->offset, sp [-1].data.p, klass);
3206 return ALIGN_TO (i32, MINT_VT_ALIGNMENT);
3210 * If EXIT_AT_FINALLY is not -1, exit after exiting the finally clause with that index.
3211 * If BASE_FRAME is not NULL, copy arguments/locals from BASE_FRAME.
3212 * The ERROR argument is used to avoid declaring an error object for every interp frame, its not used
3213 * to return error information.
3215 * Currently this method uses 0x88 of stack space on 64bit gcc. Make sure to keep it under control.
3217 static void
3218 interp_exec_method_full (InterpFrame *frame, ThreadContext *context, FrameClauseArgs *clause_args, MonoError *error)
3220 InterpFrame child_frame;
3221 GSList *finally_ips = NULL;
3222 const guint16 *ip = NULL;
3223 stackval *sp;
3224 #if DEBUG_INTERP
3225 gint tracing = global_tracing;
3226 unsigned char *vtalloc;
3227 #endif
3228 unsigned char *vt_sp;
3229 unsigned char *locals = NULL;
3230 #if USE_COMPUTED_GOTO
3231 static void * const in_labels[] = {
3232 #define OPDEF(a,b,c,d,e,f) &&LAB_ ## a,
3233 #include "mintops.def"
3235 #endif
3237 #if DEBUG_INTERP
3238 debug_enter (frame, &tracing);
3239 #endif
3241 if (!frame->imethod->transformed) {
3242 #if DEBUG_INTERP
3243 char *mn = mono_method_full_name (frame->imethod->method, TRUE);
3244 g_print ("(%p) Transforming %s\n", mono_thread_internal_current (), mn);
3245 g_free (mn);
3246 #endif
3248 frame->ip = NULL;
3249 MonoException *ex = do_transform_method (frame, context);
3250 if (ex)
3251 THROW_EX (ex, NULL);
3252 EXCEPTION_CHECKPOINT;
3255 if (!clause_args) {
3256 frame->stack = (stackval*)g_alloca (frame->imethod->alloca_size);
3257 ip = frame->imethod->code;
3258 } else {
3259 ip = clause_args->start_with_ip;
3260 if (clause_args->base_frame) {
3261 frame->stack = (stackval*)g_alloca (frame->imethod->alloca_size);
3262 memcpy (frame->stack, clause_args->base_frame->stack, frame->imethod->alloca_size);
3265 sp = frame->stack;
3266 vt_sp = (unsigned char *) sp + frame->imethod->stack_size;
3267 #if DEBUG_INTERP
3268 vtalloc = vt_sp;
3269 #endif
3270 locals = (unsigned char *) vt_sp + frame->imethod->vt_stack_size;
3271 child_frame.parent = frame;
3273 if (clause_args && clause_args->filter_exception) {
3274 sp->data.p = clause_args->filter_exception;
3275 sp++;
3278 //g_print ("(%p) Call %s\n", mono_thread_internal_current (), mono_method_get_full_name (frame->imethod->method));
3281 * using while (ip < end) may result in a 15% performance drop,
3282 * but it may be useful for debug
3284 while (1) {
3285 main_loop:
3286 /* g_assert (sp >= frame->stack); */
3287 /* g_assert(vt_sp - vtalloc <= frame->imethod->vt_stack_size); */
3288 DUMP_INSTR();
3289 MINT_IN_SWITCH (*ip) {
3290 MINT_IN_CASE(MINT_INITLOCALS)
3291 memset (locals, 0, frame->imethod->locals_size);
3292 ++ip;
3293 MINT_IN_BREAK;
3294 MINT_IN_CASE(MINT_NOP)
3295 MINT_IN_CASE(MINT_NIY)
3296 g_assert_not_reached ();
3297 MINT_IN_BREAK;
3298 MINT_IN_CASE(MINT_BREAK)
3299 ++ip;
3300 do_debugger_tramp (mini_get_dbg_callbacks ()->user_break, frame);
3301 MINT_IN_BREAK;
3302 MINT_IN_CASE(MINT_BREAKPOINT)
3303 ++ip;
3304 mono_break ();
3305 MINT_IN_BREAK;
3306 MINT_IN_CASE(MINT_LDNULL)
3307 sp->data.p = NULL;
3308 ++ip;
3309 ++sp;
3310 MINT_IN_BREAK;
3311 MINT_IN_CASE(MINT_ARGLIST)
3312 sp->data.p = vt_sp;
3313 *(gpointer*)sp->data.p = ((gpointer*)frame->retval->data.p) [-1];
3314 vt_sp += ALIGN_TO (sizeof (gpointer), MINT_VT_ALIGNMENT);
3315 ++ip;
3316 ++sp;
3317 MINT_IN_BREAK;
3318 MINT_IN_CASE(MINT_VTRESULT) {
3319 int ret_size = ip [1];
3320 unsigned char *ret_vt_sp = vt_sp;
3321 vt_sp -= READ32(ip + 2);
3322 if (ret_size > 0) {
3323 memmove (vt_sp, ret_vt_sp, ret_size);
3324 sp [-1].data.p = vt_sp;
3325 vt_sp += ALIGN_TO (ret_size, MINT_VT_ALIGNMENT);
3327 ip += 4;
3328 MINT_IN_BREAK;
3330 #define LDC(n) do { sp->data.i = (n); ++ip; ++sp; } while (0)
3331 MINT_IN_CASE(MINT_LDC_I4_M1)
3332 LDC(-1);
3333 MINT_IN_BREAK;
3334 MINT_IN_CASE(MINT_LDC_I4_0)
3335 LDC(0);
3336 MINT_IN_BREAK;
3337 MINT_IN_CASE(MINT_LDC_I4_1)
3338 LDC(1);
3339 MINT_IN_BREAK;
3340 MINT_IN_CASE(MINT_LDC_I4_2)
3341 LDC(2);
3342 MINT_IN_BREAK;
3343 MINT_IN_CASE(MINT_LDC_I4_3)
3344 LDC(3);
3345 MINT_IN_BREAK;
3346 MINT_IN_CASE(MINT_LDC_I4_4)
3347 LDC(4);
3348 MINT_IN_BREAK;
3349 MINT_IN_CASE(MINT_LDC_I4_5)
3350 LDC(5);
3351 MINT_IN_BREAK;
3352 MINT_IN_CASE(MINT_LDC_I4_6)
3353 LDC(6);
3354 MINT_IN_BREAK;
3355 MINT_IN_CASE(MINT_LDC_I4_7)
3356 LDC(7);
3357 MINT_IN_BREAK;
3358 MINT_IN_CASE(MINT_LDC_I4_8)
3359 LDC(8);
3360 MINT_IN_BREAK;
3361 MINT_IN_CASE(MINT_LDC_I4_S)
3362 sp->data.i = (short)ip [1];
3363 ip += 2;
3364 ++sp;
3365 MINT_IN_BREAK;
3366 MINT_IN_CASE(MINT_LDC_I4)
3367 ++ip;
3368 sp->data.i = READ32 (ip);
3369 ip += 2;
3370 ++sp;
3371 MINT_IN_BREAK;
3372 MINT_IN_CASE(MINT_LDC_I8)
3373 ++ip;
3374 sp->data.l = READ64 (ip);
3375 ip += 4;
3376 ++sp;
3377 MINT_IN_BREAK;
3378 MINT_IN_CASE(MINT_LDC_I8_S)
3379 sp->data.l = (short)ip [1];
3380 ip += 2;
3381 ++sp;
3382 MINT_IN_BREAK;
3383 MINT_IN_CASE(MINT_LDC_R4) {
3384 guint32 val;
3385 ++ip;
3386 val = READ32(ip);
3387 sp->data.f_r4 = * (float *)&val;
3388 ip += 2;
3389 ++sp;
3390 MINT_IN_BREAK;
3392 MINT_IN_CASE(MINT_LDC_R8)
3393 sp->data.l = READ64 (ip + 1); /* note union usage */
3394 ip += 5;
3395 ++sp;
3396 MINT_IN_BREAK;
3397 MINT_IN_CASE(MINT_DUP)
3398 sp [0] = sp[-1];
3399 ++sp;
3400 ++ip;
3401 MINT_IN_BREAK;
3402 MINT_IN_CASE(MINT_DUP_VT) {
3403 int const i32 = READ32 (ip + 1);
3404 sp->data.p = vt_sp;
3405 memcpy(sp->data.p, sp [-1].data.p, i32);
3406 vt_sp += ALIGN_TO (i32, MINT_VT_ALIGNMENT);
3407 ++sp;
3408 ip += 3;
3409 MINT_IN_BREAK;
3411 MINT_IN_CASE(MINT_POP) {
3412 guint16 u16 = (ip [1]) + 1;
3413 if (u16 > 1)
3414 memmove (sp - u16, sp - 1, (u16 - 1) * sizeof (stackval));
3415 sp--;
3416 ip += 2;
3417 MINT_IN_BREAK;
3419 MINT_IN_CASE(MINT_JMP) {
3420 g_assert (sp == frame->stack);
3421 InterpMethod *new_method = (InterpMethod*)frame->imethod->data_items [ip [1]];
3423 if (frame->imethod->prof_flags & MONO_PROFILER_CALL_INSTRUMENTATION_TAIL_CALL)
3424 MONO_PROFILER_RAISE (method_tail_call, (frame->imethod->method, new_method->method));
3426 if (!new_method->transformed) {
3427 MONO_API_ERROR_INIT (error);
3429 frame->ip = ip;
3430 mono_interp_transform_method (new_method, context, error);
3431 MonoException *ex = mono_error_convert_to_exception (error);
3432 if (ex)
3433 THROW_EX (ex, ip);
3435 ip += 2;
3436 const gboolean realloc_frame = new_method->alloca_size > frame->imethod->alloca_size;
3437 frame->imethod = new_method;
3439 * We allocate the stack frame from scratch and store the arguments in the
3440 * locals again since it's possible for the caller stack frame to be smaller
3441 * than the callee stack frame (at the interp level)
3443 if (realloc_frame) {
3444 frame->stack = (stackval*)g_alloca (frame->imethod->alloca_size);
3445 memset (frame->stack, 0, frame->imethod->alloca_size);
3446 sp = frame->stack;
3448 vt_sp = (unsigned char *) sp + frame->imethod->stack_size;
3449 #if DEBUG_INTERP
3450 vtalloc = vt_sp;
3451 #endif
3452 locals = vt_sp + frame->imethod->vt_stack_size;
3453 ip = frame->imethod->code;
3454 MINT_IN_BREAK;
3456 MINT_IN_CASE(MINT_CALLI) {
3457 MonoMethodSignature *csignature;
3459 frame->ip = ip;
3461 csignature = (MonoMethodSignature*)frame->imethod->data_items [ip [1]];
3462 ip += 2;
3463 --sp;
3464 child_frame.imethod = (InterpMethod*)sp->data.p;
3466 sp->data.p = vt_sp;
3467 child_frame.retval = sp;
3468 /* decrement by the actual number of args */
3469 sp -= csignature->param_count;
3470 if (csignature->hasthis)
3471 --sp;
3472 child_frame.stack_args = sp;
3474 if (child_frame.imethod->method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) {
3475 child_frame.imethod = mono_interp_get_imethod (frame->imethod->domain, mono_marshal_get_native_wrapper (child_frame.imethod->method, FALSE, FALSE), error);
3476 mono_interp_error_cleanup (error); /* FIXME: don't swallow the error */
3479 if (csignature->hasthis) {
3480 MonoObject *this_arg = (MonoObject*)sp->data.p;
3482 if (m_class_is_valuetype (this_arg->vtable->klass)) {
3483 gpointer unboxed = mono_object_unbox_internal (this_arg);
3484 sp [0].data.p = unboxed;
3488 interp_exec_method (&child_frame, context, error);
3490 CHECK_RESUME_STATE (context);
3492 /* need to handle typedbyref ... */
3493 if (csignature->ret->type != MONO_TYPE_VOID) {
3494 *sp = *child_frame.retval;
3495 sp++;
3497 MINT_IN_BREAK;
3499 MINT_IN_CASE(MINT_CALLI_NAT_FAST) {
3500 gpointer target_ip = sp [-1].data.p;
3501 MonoMethodSignature *csignature = (MonoMethodSignature*)frame->imethod->data_items [ip [1]];
3502 int opcode = ip [2];
3503 gboolean save_last_error = ip [3];
3505 sp--;
3506 frame->ip = ip;
3508 sp = do_icall_wrapper (frame, csignature, opcode, sp, target_ip, save_last_error);
3509 EXCEPTION_CHECKPOINT;
3510 CHECK_RESUME_STATE (context);
3511 ip += 4;
3512 MINT_IN_BREAK;
3514 MINT_IN_CASE(MINT_CALLI_NAT) {
3516 frame->ip = ip;
3518 MonoMethodSignature* csignature = (MonoMethodSignature*)frame->imethod->data_items [ip [1]];
3520 ip += 3;
3521 --sp;
3522 guchar* const code = (guchar*)sp->data.p;
3523 child_frame.imethod = NULL;
3525 sp->data.p = vt_sp;
3526 child_frame.retval = sp;
3527 /* decrement by the actual number of args */
3528 sp -= csignature->param_count;
3529 if (csignature->hasthis)
3530 --sp;
3531 child_frame.stack_args = sp;
3533 if (frame->imethod->method->dynamic && csignature->pinvoke) {
3534 mono_interp_calli_nat_dynamic_pinvoke (&child_frame, code, context, csignature, error);
3535 } else {
3536 const gboolean save_last_error = ip [-3 + 2];
3537 ves_pinvoke_method (&child_frame, csignature, (MonoFuncV) code, context, save_last_error);
3540 CHECK_RESUME_STATE (context);
3542 /* need to handle typedbyref ... */
3543 if (csignature->ret->type != MONO_TYPE_VOID) {
3544 *sp = *child_frame.retval;
3545 sp++;
3547 MINT_IN_BREAK;
3549 MINT_IN_CASE(MINT_CALLVIRT_FAST)
3550 MINT_IN_CASE(MINT_VCALLVIRT_FAST) {
3551 MonoObject *this_arg;
3552 InterpMethod *target_imethod;
3553 int slot;
3555 // FIXME Have it handle also remoting calls and use a single opcode for virtual calls
3557 frame->ip = ip;
3559 target_imethod = (InterpMethod*)frame->imethod->data_items [ip [1]];
3560 slot = (gint16)ip [2];
3561 ip += 3;
3562 sp->data.p = vt_sp;
3563 child_frame.retval = sp;
3565 /* decrement by the actual number of args */
3566 sp -= target_imethod->param_count + target_imethod->hasthis;
3567 child_frame.stack_args = sp;
3569 this_arg = (MonoObject*)sp->data.p;
3571 child_frame.imethod = get_virtual_method_fast (target_imethod, this_arg->vtable, slot);
3572 if (m_class_is_valuetype (this_arg->vtable->klass) && m_class_is_valuetype (child_frame.imethod->method->klass)) {
3573 /* unbox */
3574 gpointer unboxed = mono_object_unbox_internal (this_arg);
3575 sp [0].data.p = unboxed;
3578 interp_exec_method (&child_frame, context, error);
3580 CHECK_RESUME_STATE (context);
3582 const gboolean is_void = ip [-3] == MINT_VCALLVIRT_FAST;
3583 if (!is_void) {
3584 /* need to handle typedbyref ... */
3585 *sp = *child_frame.retval;
3586 sp++;
3588 MINT_IN_BREAK;
3590 MINT_IN_CASE(MINT_CALL_VARARG) {
3591 int num_varargs = 0;
3592 MonoMethodSignature *csig;
3594 frame->ip = ip;
3596 child_frame.imethod = (InterpMethod*)frame->imethod->data_items [ip [1]];
3597 /* The real signature for vararg calls */
3598 csig = (MonoMethodSignature*) frame->imethod->data_items [ip [2]];
3599 /* Push all vararg arguments from normal sp to vt_sp together with the signature */
3600 num_varargs = csig->param_count - csig->sentinelpos;
3601 vt_sp = copy_varargs_vtstack (csig, sp, vt_sp);
3603 ip += 3;
3604 sp->data.p = vt_sp;
3605 child_frame.retval = sp;
3607 /* decrement by the actual number of args */
3608 sp -= child_frame.imethod->param_count + child_frame.imethod->hasthis + num_varargs;
3609 child_frame.stack_args = sp;
3611 interp_exec_method (&child_frame, context, error);
3613 CHECK_RESUME_STATE (context);
3615 if (csig->ret->type != MONO_TYPE_VOID) {
3616 *sp = *child_frame.retval;
3617 sp++;
3619 MINT_IN_BREAK;
3621 MINT_IN_CASE(MINT_CALL)
3622 MINT_IN_CASE(MINT_VCALL)
3623 MINT_IN_CASE(MINT_CALLVIRT)
3624 MINT_IN_CASE(MINT_VCALLVIRT) {
3626 frame->ip = ip;
3628 child_frame.imethod = (InterpMethod*)frame->imethod->data_items [ip [1]];
3629 ip += 2;
3630 sp->data.p = vt_sp;
3631 child_frame.retval = sp;
3633 /* decrement by the actual number of args */
3634 sp -= child_frame.imethod->param_count + child_frame.imethod->hasthis;
3635 child_frame.stack_args = sp;
3637 const gboolean is_virtual = ip [-2] == MINT_CALLVIRT || ip [-2] == MINT_VCALLVIRT;
3638 if (is_virtual) {
3639 MonoObject *this_arg = (MonoObject*)sp->data.p;
3641 child_frame.imethod = get_virtual_method (child_frame.imethod, this_arg->vtable);
3642 if (m_class_is_valuetype (this_arg->vtable->klass) && m_class_is_valuetype (child_frame.imethod->method->klass)) {
3643 /* unbox */
3644 gpointer unboxed = mono_object_unbox_internal (this_arg);
3645 sp [0].data.p = unboxed;
3649 interp_exec_method (&child_frame, context, error);
3651 CHECK_RESUME_STATE (context);
3653 const gboolean is_void = ip [-2] == MINT_VCALL || ip [-2] == MINT_VCALLVIRT;
3654 if (!is_void) {
3655 /* need to handle typedbyref ... */
3656 *sp = *child_frame.retval;
3657 sp++;
3659 MINT_IN_BREAK;
3661 MINT_IN_CASE(MINT_JIT_CALL) {
3662 InterpMethod *rmethod = (InterpMethod*)frame->imethod->data_items [ip [1]];
3663 MONO_API_ERROR_INIT (error);
3664 frame->ip = ip;
3665 sp = do_jit_call (sp, vt_sp, context, frame, rmethod, error);
3666 if (!is_ok (error)) {
3667 MonoException *ex = mono_error_convert_to_exception (error);
3668 THROW_EX (ex, ip);
3670 ip += 2;
3672 CHECK_RESUME_STATE (context);
3674 if (rmethod->rtype->type != MONO_TYPE_VOID)
3675 sp++;
3677 MINT_IN_BREAK;
3679 MINT_IN_CASE(MINT_CALLRUN) {
3680 MonoMethod *target_method = (MonoMethod*) frame->imethod->data_items [ip [1]];
3681 MonoMethodSignature *sig = (MonoMethodSignature*) frame->imethod->data_items [ip [2]];
3682 stackval *retval;
3684 sp->data.p = vt_sp;
3685 retval = sp;
3687 sp -= sig->param_count;
3688 if (sig->hasthis)
3689 sp--;
3691 MonoException *ex = ves_imethod (frame, target_method, sig, sp, retval);
3692 if (ex)
3693 THROW_EX (ex, ip);
3695 if (sig->ret->type != MONO_TYPE_VOID) {
3696 *sp = *retval;
3697 sp++;
3699 ip += 3;
3700 MINT_IN_BREAK;
3702 MINT_IN_CASE(MINT_RET)
3703 --sp;
3704 *frame->retval = *sp;
3705 if (sp > frame->stack)
3706 g_warning ("ret: more values on stack: %d", sp-frame->stack);
3707 goto exit_frame;
3708 MINT_IN_CASE(MINT_RET_VOID)
3709 if (sp > frame->stack)
3710 g_warning ("ret.void: more values on stack: %d %s", sp-frame->stack, mono_method_full_name (frame->imethod->method, TRUE));
3711 goto exit_frame;
3712 MINT_IN_CASE(MINT_RET_VT) {
3713 int const i32 = READ32 (ip + 1);
3714 --sp;
3715 memcpy(frame->retval->data.p, sp->data.p, i32);
3716 if (sp > frame->stack)
3717 g_warning ("ret.vt: more values on stack: %d", sp-frame->stack);
3718 goto exit_frame;
3720 MINT_IN_CASE(MINT_BR_S)
3721 ip += (short) *(ip + 1);
3722 MINT_IN_BREAK;
3723 MINT_IN_CASE(MINT_BR)
3724 ip += (gint32) READ32(ip + 1);
3725 MINT_IN_BREAK;
3726 #define ZEROP_S(datamem, op) \
3727 --sp; \
3728 if (sp->data.datamem op 0) \
3729 ip += (gint16)ip [1]; \
3730 else \
3731 ip += 2;
3733 #define ZEROP(datamem, op) \
3734 --sp; \
3735 if (sp->data.datamem op 0) \
3736 ip += (gint32)READ32(ip + 1); \
3737 else \
3738 ip += 3;
3740 MINT_IN_CASE(MINT_BRFALSE_I4_S)
3741 ZEROP_S(i, ==);
3742 MINT_IN_BREAK;
3743 MINT_IN_CASE(MINT_BRFALSE_I8_S)
3744 ZEROP_S(l, ==);
3745 MINT_IN_BREAK;
3746 MINT_IN_CASE(MINT_BRFALSE_R4_S)
3747 ZEROP_S(f_r4, ==);
3748 MINT_IN_BREAK;
3749 MINT_IN_CASE(MINT_BRFALSE_R8_S)
3750 ZEROP_S(f, ==);
3751 MINT_IN_BREAK;
3752 MINT_IN_CASE(MINT_BRFALSE_I4)
3753 ZEROP(i, ==);
3754 MINT_IN_BREAK;
3755 MINT_IN_CASE(MINT_BRFALSE_I8)
3756 ZEROP(l, ==);
3757 MINT_IN_BREAK;
3758 MINT_IN_CASE(MINT_BRFALSE_R4)
3759 ZEROP_S(f_r4, ==);
3760 MINT_IN_BREAK;
3761 MINT_IN_CASE(MINT_BRFALSE_R8)
3762 ZEROP_S(f, ==);
3763 MINT_IN_BREAK;
3764 MINT_IN_CASE(MINT_BRTRUE_I4_S)
3765 ZEROP_S(i, !=);
3766 MINT_IN_BREAK;
3767 MINT_IN_CASE(MINT_BRTRUE_I8_S)
3768 ZEROP_S(l, !=);
3769 MINT_IN_BREAK;
3770 MINT_IN_CASE(MINT_BRTRUE_R4_S)
3771 ZEROP_S(f_r4, !=);
3772 MINT_IN_BREAK;
3773 MINT_IN_CASE(MINT_BRTRUE_R8_S)
3774 ZEROP_S(f, !=);
3775 MINT_IN_BREAK;
3776 MINT_IN_CASE(MINT_BRTRUE_I4)
3777 ZEROP(i, !=);
3778 MINT_IN_BREAK;
3779 MINT_IN_CASE(MINT_BRTRUE_I8)
3780 ZEROP(l, !=);
3781 MINT_IN_BREAK;
3782 MINT_IN_CASE(MINT_BRTRUE_R4)
3783 ZEROP(f_r4, !=);
3784 MINT_IN_BREAK;
3785 MINT_IN_CASE(MINT_BRTRUE_R8)
3786 ZEROP(f, !=);
3787 MINT_IN_BREAK;
3788 #define CONDBR_S(cond) \
3789 sp -= 2; \
3790 if (cond) \
3791 ip += (gint16)ip [1]; \
3792 else \
3793 ip += 2;
3794 #define BRELOP_S(datamem, op) \
3795 CONDBR_S(sp[0].data.datamem op sp[1].data.datamem)
3797 #define CONDBR(cond) \
3798 sp -= 2; \
3799 if (cond) \
3800 ip += (gint32)READ32(ip + 1); \
3801 else \
3802 ip += 3;
3804 #define BRELOP(datamem, op) \
3805 CONDBR(sp[0].data.datamem op sp[1].data.datamem)
3807 MINT_IN_CASE(MINT_BEQ_I4_S)
3808 BRELOP_S(i, ==)
3809 MINT_IN_BREAK;
3810 MINT_IN_CASE(MINT_BEQ_I8_S)
3811 BRELOP_S(l, ==)
3812 MINT_IN_BREAK;
3813 MINT_IN_CASE(MINT_BEQ_R4_S)
3814 CONDBR_S(!isunordered (sp [0].data.f_r4, sp [1].data.f_r4) && sp[0].data.f_r4 == sp[1].data.f_r4)
3815 MINT_IN_BREAK;
3816 MINT_IN_CASE(MINT_BEQ_R8_S)
3817 CONDBR_S(!mono_isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f == sp[1].data.f)
3818 MINT_IN_BREAK;
3819 MINT_IN_CASE(MINT_BEQ_I4)
3820 BRELOP(i, ==)
3821 MINT_IN_BREAK;
3822 MINT_IN_CASE(MINT_BEQ_I8)
3823 BRELOP(l, ==)
3824 MINT_IN_BREAK;
3825 MINT_IN_CASE(MINT_BEQ_R4)
3826 CONDBR(!isunordered (sp [0].data.f_r4, sp [1].data.f_r4) && sp[0].data.f_r4 == sp[1].data.f_r4)
3827 MINT_IN_BREAK;
3828 MINT_IN_CASE(MINT_BEQ_R8)
3829 CONDBR(!mono_isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f == sp[1].data.f)
3830 MINT_IN_BREAK;
3831 MINT_IN_CASE(MINT_BGE_I4_S)
3832 BRELOP_S(i, >=)
3833 MINT_IN_BREAK;
3834 MINT_IN_CASE(MINT_BGE_I8_S)
3835 BRELOP_S(l, >=)
3836 MINT_IN_BREAK;
3837 MINT_IN_CASE(MINT_BGE_R4_S)
3838 CONDBR_S(!isunordered (sp [0].data.f_r4, sp [1].data.f_r4) && sp[0].data.f_r4 >= sp[1].data.f_r4)
3839 MINT_IN_BREAK;
3840 MINT_IN_CASE(MINT_BGE_R8_S)
3841 CONDBR_S(!mono_isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f >= sp[1].data.f)
3842 MINT_IN_BREAK;
3843 MINT_IN_CASE(MINT_BGE_I4)
3844 BRELOP(i, >=)
3845 MINT_IN_BREAK;
3846 MINT_IN_CASE(MINT_BGE_I8)
3847 BRELOP(l, >=)
3848 MINT_IN_BREAK;
3849 MINT_IN_CASE(MINT_BGE_R4)
3850 CONDBR(!isunordered (sp [0].data.f_r4, sp [1].data.f_r4) && sp[0].data.f_r4 >= sp[1].data.f_r4)
3851 MINT_IN_BREAK;
3852 MINT_IN_CASE(MINT_BGE_R8)
3853 CONDBR(!mono_isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f >= sp[1].data.f)
3854 MINT_IN_BREAK;
3855 MINT_IN_CASE(MINT_BGT_I4_S)
3856 BRELOP_S(i, >)
3857 MINT_IN_BREAK;
3858 MINT_IN_CASE(MINT_BGT_I8_S)
3859 BRELOP_S(l, >)
3860 MINT_IN_BREAK;
3861 MINT_IN_CASE(MINT_BGT_R4_S)
3862 CONDBR_S(!isunordered (sp [0].data.f_r4, sp [1].data.f_r4) && sp[0].data.f_r4 > sp[1].data.f_r4)
3863 MINT_IN_BREAK;
3864 MINT_IN_CASE(MINT_BGT_R8_S)
3865 CONDBR_S(!mono_isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f > sp[1].data.f)
3866 MINT_IN_BREAK;
3867 MINT_IN_CASE(MINT_BGT_I4)
3868 BRELOP(i, >)
3869 MINT_IN_BREAK;
3870 MINT_IN_CASE(MINT_BGT_I8)
3871 BRELOP(l, >)
3872 MINT_IN_BREAK;
3873 MINT_IN_CASE(MINT_BGT_R4)
3874 CONDBR(!isunordered (sp [0].data.f_r4, sp [1].data.f_r4) && sp[0].data.f_r4 > sp[1].data.f_r4)
3875 MINT_IN_BREAK;
3876 MINT_IN_CASE(MINT_BGT_R8)
3877 CONDBR(!mono_isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f > sp[1].data.f)
3878 MINT_IN_BREAK;
3879 MINT_IN_CASE(MINT_BLT_I4_S)
3880 BRELOP_S(i, <)
3881 MINT_IN_BREAK;
3882 MINT_IN_CASE(MINT_BLT_I8_S)
3883 BRELOP_S(l, <)
3884 MINT_IN_BREAK;
3885 MINT_IN_CASE(MINT_BLT_R4_S)
3886 CONDBR_S(!isunordered (sp [0].data.f_r4, sp [1].data.f_r4) && sp[0].data.f_r4 < sp[1].data.f_r4)
3887 MINT_IN_BREAK;
3888 MINT_IN_CASE(MINT_BLT_R8_S)
3889 CONDBR_S(!mono_isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f < sp[1].data.f)
3890 MINT_IN_BREAK;
3891 MINT_IN_CASE(MINT_BLT_I4)
3892 BRELOP(i, <)
3893 MINT_IN_BREAK;
3894 MINT_IN_CASE(MINT_BLT_I8)
3895 BRELOP(l, <)
3896 MINT_IN_BREAK;
3897 MINT_IN_CASE(MINT_BLT_R4)
3898 CONDBR(!isunordered (sp [0].data.f_r4, sp [1].data.f_r4) && sp[0].data.f_r4 < sp[1].data.f_r4)
3899 MINT_IN_BREAK;
3900 MINT_IN_CASE(MINT_BLT_R8)
3901 CONDBR(!mono_isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f < sp[1].data.f)
3902 MINT_IN_BREAK;
3903 MINT_IN_CASE(MINT_BLE_I4_S)
3904 BRELOP_S(i, <=)
3905 MINT_IN_BREAK;
3906 MINT_IN_CASE(MINT_BLE_I8_S)
3907 BRELOP_S(l, <=)
3908 MINT_IN_BREAK;
3909 MINT_IN_CASE(MINT_BLE_R4_S)
3910 CONDBR_S(!isunordered (sp [0].data.f_r4, sp [1].data.f_r4) && sp[0].data.f_r4 <= sp[1].data.f_r4)
3911 MINT_IN_BREAK;
3912 MINT_IN_CASE(MINT_BLE_R8_S)
3913 CONDBR_S(!mono_isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f <= sp[1].data.f)
3914 MINT_IN_BREAK;
3915 MINT_IN_CASE(MINT_BLE_I4)
3916 BRELOP(i, <=)
3917 MINT_IN_BREAK;
3918 MINT_IN_CASE(MINT_BLE_I8)
3919 BRELOP(l, <=)
3920 MINT_IN_BREAK;
3921 MINT_IN_CASE(MINT_BLE_R4)
3922 CONDBR(!isunordered (sp [0].data.f_r4, sp [1].data.f_r4) && sp[0].data.f_r4 <= sp[1].data.f_r4)
3923 MINT_IN_BREAK;
3924 MINT_IN_CASE(MINT_BLE_R8)
3925 CONDBR(!mono_isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f <= sp[1].data.f)
3926 MINT_IN_BREAK;
3927 MINT_IN_CASE(MINT_BNE_UN_I4_S)
3928 BRELOP_S(i, !=)
3929 MINT_IN_BREAK;
3930 MINT_IN_CASE(MINT_BNE_UN_I8_S)
3931 BRELOP_S(l, !=)
3932 MINT_IN_BREAK;
3933 MINT_IN_CASE(MINT_BNE_UN_R4_S)
3934 CONDBR_S(isunordered (sp [0].data.f_r4, sp [1].data.f_r4) || sp[0].data.f_r4 != sp[1].data.f_r4)
3935 MINT_IN_BREAK;
3936 MINT_IN_CASE(MINT_BNE_UN_R8_S)
3937 CONDBR_S(mono_isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f != sp[1].data.f)
3938 MINT_IN_BREAK;
3939 MINT_IN_CASE(MINT_BNE_UN_I4)
3940 BRELOP(i, !=)
3941 MINT_IN_BREAK;
3942 MINT_IN_CASE(MINT_BNE_UN_I8)
3943 BRELOP(l, !=)
3944 MINT_IN_BREAK;
3945 MINT_IN_CASE(MINT_BNE_UN_R4)
3946 CONDBR(isunordered (sp [0].data.f_r4, sp [1].data.f_r4) || sp[0].data.f_r4 != sp[1].data.f_r4)
3947 MINT_IN_BREAK;
3948 MINT_IN_CASE(MINT_BNE_UN_R8)
3949 CONDBR(mono_isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f != sp[1].data.f)
3950 MINT_IN_BREAK;
3952 #define BRELOP_S_CAST(datamem, op, type) \
3953 sp -= 2; \
3954 if ((type) sp[0].data.datamem op (type) sp[1].data.datamem) \
3955 ip += (gint16)ip [1]; \
3956 else \
3957 ip += 2;
3959 #define BRELOP_CAST(datamem, op, type) \
3960 sp -= 2; \
3961 if ((type) sp[0].data.datamem op (type) sp[1].data.datamem) \
3962 ip += (gint32)READ32(ip + 1); \
3963 else \
3964 ip += 3;
3966 MINT_IN_CASE(MINT_BGE_UN_I4_S)
3967 BRELOP_S_CAST(i, >=, guint32);
3968 MINT_IN_BREAK;
3969 MINT_IN_CASE(MINT_BGE_UN_I8_S)
3970 BRELOP_S_CAST(l, >=, guint64);
3971 MINT_IN_BREAK;
3972 MINT_IN_CASE(MINT_BGE_UN_R4_S)
3973 CONDBR_S(isunordered (sp [0].data.f_r4, sp [1].data.f_r4) || sp[0].data.f_r4 >= sp[1].data.f_r4)
3974 MINT_IN_BREAK;
3975 MINT_IN_CASE(MINT_BGE_UN_R8_S)
3976 CONDBR_S(mono_isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f >= sp[1].data.f)
3977 MINT_IN_BREAK;
3978 MINT_IN_CASE(MINT_BGE_UN_I4)
3979 BRELOP_CAST(i, >=, guint32);
3980 MINT_IN_BREAK;
3981 MINT_IN_CASE(MINT_BGE_UN_I8)
3982 BRELOP_CAST(l, >=, guint64);
3983 MINT_IN_BREAK;
3984 MINT_IN_CASE(MINT_BGE_UN_R4)
3985 CONDBR(isunordered (sp [0].data.f_r4, sp [1].data.f_r4) || sp[0].data.f_r4 >= sp[1].data.f_r4)
3986 MINT_IN_BREAK;
3987 MINT_IN_CASE(MINT_BGE_UN_R8)
3988 CONDBR(mono_isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f >= sp[1].data.f)
3989 MINT_IN_BREAK;
3990 MINT_IN_CASE(MINT_BGT_UN_I4_S)
3991 BRELOP_S_CAST(i, >, guint32);
3992 MINT_IN_BREAK;
3993 MINT_IN_CASE(MINT_BGT_UN_I8_S)
3994 BRELOP_S_CAST(l, >, guint64);
3995 MINT_IN_BREAK;
3996 MINT_IN_CASE(MINT_BGT_UN_R4_S)
3997 CONDBR_S(isunordered (sp [0].data.f_r4, sp [1].data.f_r4) || sp[0].data.f_r4 > sp[1].data.f_r4)
3998 MINT_IN_BREAK;
3999 MINT_IN_CASE(MINT_BGT_UN_R8_S)
4000 CONDBR_S(mono_isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f > sp[1].data.f)
4001 MINT_IN_BREAK;
4002 MINT_IN_CASE(MINT_BGT_UN_I4)
4003 BRELOP_CAST(i, >, guint32);
4004 MINT_IN_BREAK;
4005 MINT_IN_CASE(MINT_BGT_UN_I8)
4006 BRELOP_CAST(l, >, guint64);
4007 MINT_IN_BREAK;
4008 MINT_IN_CASE(MINT_BGT_UN_R4)
4009 CONDBR(isunordered (sp [0].data.f_r4, sp [1].data.f_r4) || sp[0].data.f_r4 > sp[1].data.f_r4)
4010 MINT_IN_BREAK;
4011 MINT_IN_CASE(MINT_BGT_UN_R8)
4012 CONDBR(mono_isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f > sp[1].data.f)
4013 MINT_IN_BREAK;
4014 MINT_IN_CASE(MINT_BLE_UN_I4_S)
4015 BRELOP_S_CAST(i, <=, guint32);
4016 MINT_IN_BREAK;
4017 MINT_IN_CASE(MINT_BLE_UN_I8_S)
4018 BRELOP_S_CAST(l, <=, guint64);
4019 MINT_IN_BREAK;
4020 MINT_IN_CASE(MINT_BLE_UN_R4_S)
4021 CONDBR_S(isunordered (sp [0].data.f_r4, sp [1].data.f_r4) || sp[0].data.f_r4 <= sp[1].data.f_r4)
4022 MINT_IN_BREAK;
4023 MINT_IN_CASE(MINT_BLE_UN_R8_S)
4024 CONDBR_S(mono_isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f <= sp[1].data.f)
4025 MINT_IN_BREAK;
4026 MINT_IN_CASE(MINT_BLE_UN_I4)
4027 BRELOP_CAST(i, <=, guint32);
4028 MINT_IN_BREAK;
4029 MINT_IN_CASE(MINT_BLE_UN_I8)
4030 BRELOP_CAST(l, <=, guint64);
4031 MINT_IN_BREAK;
4032 MINT_IN_CASE(MINT_BLE_UN_R4)
4033 CONDBR(isunordered (sp [0].data.f_r4, sp [1].data.f_r4) || sp[0].data.f_r4 <= sp[1].data.f_r4)
4034 MINT_IN_BREAK;
4035 MINT_IN_CASE(MINT_BLE_UN_R8)
4036 CONDBR(mono_isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f <= sp[1].data.f)
4037 MINT_IN_BREAK;
4038 MINT_IN_CASE(MINT_BLT_UN_I4_S)
4039 BRELOP_S_CAST(i, <, guint32);
4040 MINT_IN_BREAK;
4041 MINT_IN_CASE(MINT_BLT_UN_I8_S)
4042 BRELOP_S_CAST(l, <, guint64);
4043 MINT_IN_BREAK;
4044 MINT_IN_CASE(MINT_BLT_UN_R4_S)
4045 CONDBR_S(isunordered (sp [0].data.f_r4, sp [1].data.f_r4) || sp[0].data.f_r4 < sp[1].data.f_r4)
4046 MINT_IN_BREAK;
4047 MINT_IN_CASE(MINT_BLT_UN_R8_S)
4048 CONDBR_S(mono_isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f < sp[1].data.f)
4049 MINT_IN_BREAK;
4050 MINT_IN_CASE(MINT_BLT_UN_I4)
4051 BRELOP_CAST(i, <, guint32);
4052 MINT_IN_BREAK;
4053 MINT_IN_CASE(MINT_BLT_UN_I8)
4054 BRELOP_CAST(l, <, guint64);
4055 MINT_IN_BREAK;
4056 MINT_IN_CASE(MINT_BLT_UN_R4)
4057 CONDBR(isunordered (sp [0].data.f_r4, sp [1].data.f_r4) || sp[0].data.f_r4 < sp[1].data.f_r4)
4058 MINT_IN_BREAK;
4059 MINT_IN_CASE(MINT_BLT_UN_R8)
4060 CONDBR(mono_isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f < sp[1].data.f)
4061 MINT_IN_BREAK;
4062 MINT_IN_CASE(MINT_SWITCH) {
4063 guint32 n;
4064 const unsigned short *st;
4065 ++ip;
4066 n = READ32 (ip);
4067 ip += 2;
4068 st = ip + 2 * n;
4069 --sp;
4070 if ((guint32)sp->data.i < n) {
4071 gint offset;
4072 ip += 2 * (guint32)sp->data.i;
4073 offset = READ32 (ip);
4074 ip = ip + offset;
4075 } else {
4076 ip = st;
4078 MINT_IN_BREAK;
4080 MINT_IN_CASE(MINT_LDIND_I1_CHECK)
4081 NULL_CHECK (sp [-1].data.p);
4082 ++ip;
4083 sp[-1].data.i = *(gint8*)sp[-1].data.p;
4084 MINT_IN_BREAK;
4085 MINT_IN_CASE(MINT_LDIND_U1_CHECK)
4086 NULL_CHECK (sp [-1].data.p);
4087 ++ip;
4088 sp[-1].data.i = *(guint8*)sp[-1].data.p;
4089 MINT_IN_BREAK;
4090 MINT_IN_CASE(MINT_LDIND_I2_CHECK)
4091 NULL_CHECK (sp [-1].data.p);
4092 ++ip;
4093 sp[-1].data.i = *(gint16*)sp[-1].data.p;
4094 MINT_IN_BREAK;
4095 MINT_IN_CASE(MINT_LDIND_U2_CHECK)
4096 NULL_CHECK (sp [-1].data.p);
4097 ++ip;
4098 sp[-1].data.i = *(guint16*)sp[-1].data.p;
4099 MINT_IN_BREAK;
4100 MINT_IN_CASE(MINT_LDIND_I4_CHECK) /* Fall through */
4101 MINT_IN_CASE(MINT_LDIND_U4_CHECK)
4102 NULL_CHECK (sp [-1].data.p);
4103 ++ip;
4104 sp[-1].data.i = *(gint32*)sp[-1].data.p;
4105 MINT_IN_BREAK;
4106 MINT_IN_CASE(MINT_LDIND_I8_CHECK)
4107 NULL_CHECK (sp [-1].data.p);
4108 ++ip;
4109 #ifdef NO_UNALIGNED_ACCESS
4110 if ((gsize)sp [-1].data.p % SIZEOF_VOID_P)
4111 memcpy (&sp [-1].data.l, sp [-1].data.p, sizeof (gint64));
4112 else
4113 #endif
4114 sp[-1].data.l = *(gint64*)sp[-1].data.p;
4115 MINT_IN_BREAK;
4116 MINT_IN_CASE(MINT_LDIND_I) {
4117 guint16 offset = ip [1];
4118 sp[-1 - offset].data.p = *(gpointer*)sp[-1 - offset].data.p;
4119 ip += 2;
4120 MINT_IN_BREAK;
4122 MINT_IN_CASE(MINT_LDIND_I8) {
4123 guint16 offset = ip [1];
4124 #ifdef NO_UNALIGNED_ACCESS
4125 if ((gsize)sp [-1 - offset].data.p % SIZEOF_VOID_P)
4126 memcpy (&sp [-1 - offset].data.l, sp [-1 - offset].data.p, sizeof (gint64));
4127 else
4128 #endif
4129 sp[-1 - offset].data.l = *(gint64*)sp[-1 - offset].data.p;
4130 ip += 2;
4131 MINT_IN_BREAK;
4133 MINT_IN_CASE(MINT_LDIND_R4_CHECK)
4134 NULL_CHECK (sp [-1].data.p);
4135 ++ip;
4136 sp[-1].data.f_r4 = *(gfloat*)sp[-1].data.p;
4137 MINT_IN_BREAK;
4138 MINT_IN_CASE(MINT_LDIND_R8_CHECK)
4139 NULL_CHECK (sp [-1].data.p);
4140 ++ip;
4141 #ifdef NO_UNALIGNED_ACCESS
4142 if ((gsize)sp [-1].data.p % SIZEOF_VOID_P)
4143 memcpy (&sp [-1].data.f, sp [-1].data.p, sizeof (gdouble));
4144 else
4145 #endif
4146 sp[-1].data.f = *(gdouble*)sp[-1].data.p;
4147 MINT_IN_BREAK;
4148 MINT_IN_CASE(MINT_LDIND_REF)
4149 ++ip;
4150 sp[-1].data.p = *(gpointer*)sp[-1].data.p;
4151 MINT_IN_BREAK;
4152 MINT_IN_CASE(MINT_LDIND_REF_CHECK) {
4153 NULL_CHECK (sp [-1].data.p);
4154 ++ip;
4155 sp [-1].data.p = *(gpointer*)sp [-1].data.p;
4156 MINT_IN_BREAK;
4158 MINT_IN_CASE(MINT_STIND_REF)
4159 ++ip;
4160 sp -= 2;
4161 mono_gc_wbarrier_generic_store_internal (sp->data.p, sp [1].data.o);
4162 MINT_IN_BREAK;
4163 MINT_IN_CASE(MINT_STIND_I1)
4164 ++ip;
4165 sp -= 2;
4166 * (gint8 *) sp->data.p = (gint8)sp[1].data.i;
4167 MINT_IN_BREAK;
4168 MINT_IN_CASE(MINT_STIND_I2)
4169 ++ip;
4170 sp -= 2;
4171 * (gint16 *) sp->data.p = (gint16)sp[1].data.i;
4172 MINT_IN_BREAK;
4173 MINT_IN_CASE(MINT_STIND_I4)
4174 ++ip;
4175 sp -= 2;
4176 * (gint32 *) sp->data.p = sp[1].data.i;
4177 MINT_IN_BREAK;
4178 MINT_IN_CASE(MINT_STIND_I)
4179 ++ip;
4180 sp -= 2;
4181 * (mono_i *) sp->data.p = (mono_i)sp[1].data.p;
4182 MINT_IN_BREAK;
4183 MINT_IN_CASE(MINT_STIND_I8)
4184 ++ip;
4185 sp -= 2;
4186 #ifdef NO_UNALIGNED_ACCESS
4187 if ((gsize)sp->data.p % SIZEOF_VOID_P)
4188 memcpy (sp->data.p, &sp [1].data.l, sizeof (gint64));
4189 else
4190 #endif
4191 * (gint64 *) sp->data.p = sp[1].data.l;
4192 MINT_IN_BREAK;
4193 MINT_IN_CASE(MINT_STIND_R4)
4194 ++ip;
4195 sp -= 2;
4196 * (float *) sp->data.p = sp[1].data.f_r4;
4197 MINT_IN_BREAK;
4198 MINT_IN_CASE(MINT_STIND_R8)
4199 ++ip;
4200 sp -= 2;
4201 #ifdef NO_UNALIGNED_ACCESS
4202 if ((gsize)sp->data.p % SIZEOF_VOID_P)
4203 memcpy (sp->data.p, &sp [1].data.f, sizeof (double));
4204 else
4205 #endif
4206 * (double *) sp->data.p = sp[1].data.f;
4207 MINT_IN_BREAK;
4208 MINT_IN_CASE(MINT_MONO_ATOMIC_STORE_I4)
4209 ++ip;
4210 sp -= 2;
4211 mono_atomic_store_i32 ((gint32 *) sp->data.p, sp [1].data.i);
4212 MINT_IN_BREAK;
4213 #define BINOP(datamem, op) \
4214 --sp; \
4215 sp [-1].data.datamem = sp [-1].data.datamem op sp [0].data.datamem; \
4216 ++ip;
4217 MINT_IN_CASE(MINT_ADD_I4)
4218 BINOP(i, +);
4219 MINT_IN_BREAK;
4220 MINT_IN_CASE(MINT_ADD_I8)
4221 BINOP(l, +);
4222 MINT_IN_BREAK;
4223 MINT_IN_CASE(MINT_ADD_R4)
4224 BINOP(f_r4, +);
4225 MINT_IN_BREAK;
4226 MINT_IN_CASE(MINT_ADD_R8)
4227 BINOP(f, +);
4228 MINT_IN_BREAK;
4229 MINT_IN_CASE(MINT_ADD1_I4)
4230 ++sp [-1].data.i;
4231 ++ip;
4232 MINT_IN_BREAK;
4233 MINT_IN_CASE(MINT_ADD1_I8)
4234 ++sp [-1].data.l;
4235 ++ip;
4236 MINT_IN_BREAK;
4237 MINT_IN_CASE(MINT_SUB_I4)
4238 BINOP(i, -);
4239 MINT_IN_BREAK;
4240 MINT_IN_CASE(MINT_SUB_I8)
4241 BINOP(l, -);
4242 MINT_IN_BREAK;
4243 MINT_IN_CASE(MINT_SUB_R4)
4244 BINOP(f_r4, -);
4245 MINT_IN_BREAK;
4246 MINT_IN_CASE(MINT_SUB_R8)
4247 BINOP(f, -);
4248 MINT_IN_BREAK;
4249 MINT_IN_CASE(MINT_SUB1_I4)
4250 --sp [-1].data.i;
4251 ++ip;
4252 MINT_IN_BREAK;
4253 MINT_IN_CASE(MINT_SUB1_I8)
4254 --sp [-1].data.l;
4255 ++ip;
4256 MINT_IN_BREAK;
4257 MINT_IN_CASE(MINT_MUL_I4)
4258 BINOP(i, *);
4259 MINT_IN_BREAK;
4260 MINT_IN_CASE(MINT_MUL_I8)
4261 BINOP(l, *);
4262 MINT_IN_BREAK;
4263 MINT_IN_CASE(MINT_MUL_R4)
4264 BINOP(f_r4, *);
4265 MINT_IN_BREAK;
4266 MINT_IN_CASE(MINT_MUL_R8)
4267 BINOP(f, *);
4268 MINT_IN_BREAK;
4269 MINT_IN_CASE(MINT_DIV_I4)
4270 if (sp [-1].data.i == 0)
4271 goto div_zero_label;
4272 if (sp [-1].data.i == (-1) && sp [-2].data.i == G_MININT32)
4273 goto overflow_label;
4274 BINOP(i, /);
4275 MINT_IN_BREAK;
4276 MINT_IN_CASE(MINT_DIV_I8)
4277 if (sp [-1].data.l == 0)
4278 goto div_zero_label;
4279 if (sp [-1].data.l == (-1) && sp [-2].data.l == G_MININT64)
4280 goto overflow_label;
4281 BINOP(l, /);
4282 MINT_IN_BREAK;
4283 MINT_IN_CASE(MINT_DIV_R4)
4284 BINOP(f_r4, /);
4285 MINT_IN_BREAK;
4286 MINT_IN_CASE(MINT_DIV_R8)
4287 BINOP(f, /);
4288 MINT_IN_BREAK;
4290 #define BINOP_CAST(datamem, op, type) \
4291 --sp; \
4292 sp [-1].data.datamem = (type)sp [-1].data.datamem op (type)sp [0].data.datamem; \
4293 ++ip;
4294 MINT_IN_CASE(MINT_DIV_UN_I4)
4295 if (sp [-1].data.i == 0)
4296 goto div_zero_label;
4297 BINOP_CAST(i, /, guint32);
4298 MINT_IN_BREAK;
4299 MINT_IN_CASE(MINT_DIV_UN_I8)
4300 if (sp [-1].data.l == 0)
4301 goto div_zero_label;
4302 BINOP_CAST(l, /, guint64);
4303 MINT_IN_BREAK;
4304 MINT_IN_CASE(MINT_REM_I4)
4305 if (sp [-1].data.i == 0)
4306 goto div_zero_label;
4307 if (sp [-1].data.i == (-1) && sp [-2].data.i == G_MININT32)
4308 goto overflow_label;
4309 BINOP(i, %);
4310 MINT_IN_BREAK;
4311 MINT_IN_CASE(MINT_REM_I8)
4312 if (sp [-1].data.l == 0)
4313 goto div_zero_label;
4314 if (sp [-1].data.l == (-1) && sp [-2].data.l == G_MININT64)
4315 goto overflow_label;
4316 BINOP(l, %);
4317 MINT_IN_BREAK;
4318 MINT_IN_CASE(MINT_REM_R4)
4319 /* FIXME: what do we actually do here? */
4320 --sp;
4321 sp [-1].data.f_r4 = fmodf (sp [-1].data.f_r4, sp [0].data.f_r4);
4322 ++ip;
4323 MINT_IN_BREAK;
4324 MINT_IN_CASE(MINT_REM_R8)
4325 /* FIXME: what do we actually do here? */
4326 --sp;
4327 sp [-1].data.f = fmod (sp [-1].data.f, sp [0].data.f);
4328 ++ip;
4329 MINT_IN_BREAK;
4330 MINT_IN_CASE(MINT_REM_UN_I4)
4331 if (sp [-1].data.i == 0)
4332 goto div_zero_label;
4333 BINOP_CAST(i, %, guint32);
4334 MINT_IN_BREAK;
4335 MINT_IN_CASE(MINT_REM_UN_I8)
4336 if (sp [-1].data.l == 0)
4337 goto div_zero_label;
4338 BINOP_CAST(l, %, guint64);
4339 MINT_IN_BREAK;
4340 MINT_IN_CASE(MINT_AND_I4)
4341 BINOP(i, &);
4342 MINT_IN_BREAK;
4343 MINT_IN_CASE(MINT_AND_I8)
4344 BINOP(l, &);
4345 MINT_IN_BREAK;
4346 MINT_IN_CASE(MINT_OR_I4)
4347 BINOP(i, |);
4348 MINT_IN_BREAK;
4349 MINT_IN_CASE(MINT_OR_I8)
4350 BINOP(l, |);
4351 MINT_IN_BREAK;
4352 MINT_IN_CASE(MINT_XOR_I4)
4353 BINOP(i, ^);
4354 MINT_IN_BREAK;
4355 MINT_IN_CASE(MINT_XOR_I8)
4356 BINOP(l, ^);
4357 MINT_IN_BREAK;
4359 #define SHIFTOP(datamem, op) \
4360 --sp; \
4361 sp [-1].data.datamem = sp [-1].data.datamem op sp [0].data.i; \
4362 ++ip;
4364 MINT_IN_CASE(MINT_SHL_I4)
4365 SHIFTOP(i, <<);
4366 MINT_IN_BREAK;
4367 MINT_IN_CASE(MINT_SHL_I8)
4368 SHIFTOP(l, <<);
4369 MINT_IN_BREAK;
4370 MINT_IN_CASE(MINT_SHR_I4)
4371 SHIFTOP(i, >>);
4372 MINT_IN_BREAK;
4373 MINT_IN_CASE(MINT_SHR_I8)
4374 SHIFTOP(l, >>);
4375 MINT_IN_BREAK;
4376 MINT_IN_CASE(MINT_SHR_UN_I4)
4377 --sp;
4378 sp [-1].data.i = (guint32)sp [-1].data.i >> sp [0].data.i;
4379 ++ip;
4380 MINT_IN_BREAK;
4381 MINT_IN_CASE(MINT_SHR_UN_I8)
4382 --sp;
4383 sp [-1].data.l = (guint64)sp [-1].data.l >> sp [0].data.i;
4384 ++ip;
4385 MINT_IN_BREAK;
4386 MINT_IN_CASE(MINT_NEG_I4)
4387 sp [-1].data.i = - sp [-1].data.i;
4388 ++ip;
4389 MINT_IN_BREAK;
4390 MINT_IN_CASE(MINT_NEG_I8)
4391 sp [-1].data.l = - sp [-1].data.l;
4392 ++ip;
4393 MINT_IN_BREAK;
4394 MINT_IN_CASE(MINT_NEG_R4)
4395 sp [-1].data.f_r4 = - sp [-1].data.f_r4;
4396 ++ip;
4397 MINT_IN_BREAK;
4398 MINT_IN_CASE(MINT_NEG_R8)
4399 sp [-1].data.f = - sp [-1].data.f;
4400 ++ip;
4401 MINT_IN_BREAK;
4402 MINT_IN_CASE(MINT_NOT_I4)
4403 sp [-1].data.i = ~ sp [-1].data.i;
4404 ++ip;
4405 MINT_IN_BREAK;
4406 MINT_IN_CASE(MINT_NOT_I8)
4407 sp [-1].data.l = ~ sp [-1].data.l;
4408 ++ip;
4409 MINT_IN_BREAK;
4410 MINT_IN_CASE(MINT_CONV_I1_I4)
4411 sp [-1].data.i = (gint8)sp [-1].data.i;
4412 ++ip;
4413 MINT_IN_BREAK;
4414 MINT_IN_CASE(MINT_CONV_I1_I8)
4415 sp [-1].data.i = (gint8)sp [-1].data.l;
4416 ++ip;
4417 MINT_IN_BREAK;
4418 MINT_IN_CASE(MINT_CONV_I1_R4)
4419 sp [-1].data.i = (gint8) (gint32) sp [-1].data.f_r4;
4420 ++ip;
4421 MINT_IN_BREAK;
4422 MINT_IN_CASE(MINT_CONV_I1_R8)
4423 /* without gint32 cast, C compiler is allowed to use undefined
4424 * behaviour if data.f is bigger than >255. See conv.fpint section
4425 * in C standard:
4426 * > The conversion truncates; that is, the fractional part
4427 * > is discarded. The behavior is undefined if the truncated
4428 * > value cannot be represented in the destination type.
4429 * */
4430 sp [-1].data.i = (gint8) (gint32) sp [-1].data.f;
4431 ++ip;
4432 MINT_IN_BREAK;
4433 MINT_IN_CASE(MINT_CONV_U1_I4)
4434 sp [-1].data.i = (guint8)sp [-1].data.i;
4435 ++ip;
4436 MINT_IN_BREAK;
4437 MINT_IN_CASE(MINT_CONV_U1_I8)
4438 sp [-1].data.i = (guint8)sp [-1].data.l;
4439 ++ip;
4440 MINT_IN_BREAK;
4441 MINT_IN_CASE(MINT_CONV_U1_R4)
4442 sp [-1].data.i = (guint8) (guint32) sp [-1].data.f_r4;
4443 ++ip;
4444 MINT_IN_BREAK;
4445 MINT_IN_CASE(MINT_CONV_U1_R8)
4446 sp [-1].data.i = (guint8) (guint32) sp [-1].data.f;
4447 ++ip;
4448 MINT_IN_BREAK;
4449 MINT_IN_CASE(MINT_CONV_I2_I4)
4450 sp [-1].data.i = (gint16)sp [-1].data.i;
4451 ++ip;
4452 MINT_IN_BREAK;
4453 MINT_IN_CASE(MINT_CONV_I2_I8)
4454 sp [-1].data.i = (gint16)sp [-1].data.l;
4455 ++ip;
4456 MINT_IN_BREAK;
4457 MINT_IN_CASE(MINT_CONV_I2_R4)
4458 sp [-1].data.i = (gint16) (gint32) sp [-1].data.f_r4;
4459 ++ip;
4460 MINT_IN_BREAK;
4461 MINT_IN_CASE(MINT_CONV_I2_R8)
4462 sp [-1].data.i = (gint16) (gint32) sp [-1].data.f;
4463 ++ip;
4464 MINT_IN_BREAK;
4465 MINT_IN_CASE(MINT_CONV_U2_I4)
4466 sp [-1].data.i = (guint16)sp [-1].data.i;
4467 ++ip;
4468 MINT_IN_BREAK;
4469 MINT_IN_CASE(MINT_CONV_U2_I8)
4470 sp [-1].data.i = (guint16)sp [-1].data.l;
4471 ++ip;
4472 MINT_IN_BREAK;
4473 MINT_IN_CASE(MINT_CONV_U2_R4)
4474 sp [-1].data.i = (guint16) (guint32) sp [-1].data.f_r4;
4475 ++ip;
4476 MINT_IN_BREAK;
4477 MINT_IN_CASE(MINT_CONV_U2_R8)
4478 sp [-1].data.i = (guint16) (guint32) sp [-1].data.f;
4479 ++ip;
4480 MINT_IN_BREAK;
4481 MINT_IN_CASE(MINT_CONV_I4_R4)
4482 sp [-1].data.i = (gint32) sp [-1].data.f_r4;
4483 ++ip;
4484 MINT_IN_BREAK;
4485 MINT_IN_CASE(MINT_CONV_I4_R8)
4486 sp [-1].data.i = (gint32)sp [-1].data.f;
4487 ++ip;
4488 MINT_IN_BREAK;
4489 MINT_IN_CASE(MINT_CONV_U4_I8)
4490 MINT_IN_CASE(MINT_CONV_I4_I8)
4491 sp [-1].data.i = (gint32)sp [-1].data.l;
4492 ++ip;
4493 MINT_IN_BREAK;
4494 MINT_IN_CASE(MINT_CONV_I4_I8_SP)
4495 sp [-2].data.i = (gint32)sp [-2].data.l;
4496 ++ip;
4497 MINT_IN_BREAK;
4498 MINT_IN_CASE(MINT_CONV_U4_R4)
4499 #ifdef MONO_ARCH_EMULATE_FCONV_TO_U4
4500 sp [-1].data.i = mono_rconv_u4 (sp [-1].data.f_r4);
4501 #else
4502 sp [-1].data.i = (guint32) sp [-1].data.f_r4;
4503 #endif
4504 ++ip;
4505 MINT_IN_BREAK;
4506 MINT_IN_CASE(MINT_CONV_U4_R8)
4507 #ifdef MONO_ARCH_EMULATE_FCONV_TO_U4
4508 sp [-1].data.i = mono_fconv_u4_2 (sp [-1].data.f);
4509 #else
4510 sp [-1].data.i = (guint32) sp [-1].data.f;
4511 #endif
4512 ++ip;
4513 MINT_IN_BREAK;
4514 MINT_IN_CASE(MINT_CONV_I8_I4)
4515 sp [-1].data.l = sp [-1].data.i;
4516 ++ip;
4517 MINT_IN_BREAK;
4518 MINT_IN_CASE(MINT_CONV_I8_I4_SP)
4519 sp [-2].data.l = sp [-2].data.i;
4520 ++ip;
4521 MINT_IN_BREAK;
4522 MINT_IN_CASE(MINT_CONV_I8_U4)
4523 sp [-1].data.l = (guint32)sp [-1].data.i;
4524 ++ip;
4525 MINT_IN_BREAK;
4526 MINT_IN_CASE(MINT_CONV_I8_R4)
4527 sp [-1].data.l = (gint64) sp [-1].data.f_r4;
4528 ++ip;
4529 MINT_IN_BREAK;
4530 MINT_IN_CASE(MINT_CONV_I8_R8)
4531 sp [-1].data.l = (gint64)sp [-1].data.f;
4532 ++ip;
4533 MINT_IN_BREAK;
4534 MINT_IN_CASE(MINT_CONV_R4_I4)
4535 sp [-1].data.f_r4 = (float)sp [-1].data.i;
4536 ++ip;
4537 MINT_IN_BREAK;
4538 MINT_IN_CASE(MINT_CONV_R4_I8)
4539 sp [-1].data.f_r4 = (float)sp [-1].data.l;
4540 ++ip;
4541 MINT_IN_BREAK;
4542 MINT_IN_CASE(MINT_CONV_R4_R8)
4543 sp [-1].data.f_r4 = (float)sp [-1].data.f;
4544 ++ip;
4545 MINT_IN_BREAK;
4546 MINT_IN_CASE(MINT_CONV_R8_I4)
4547 sp [-1].data.f = (double)sp [-1].data.i;
4548 ++ip;
4549 MINT_IN_BREAK;
4550 MINT_IN_CASE(MINT_CONV_R8_I8)
4551 sp [-1].data.f = (double)sp [-1].data.l;
4552 ++ip;
4553 MINT_IN_BREAK;
4554 MINT_IN_CASE(MINT_CONV_R8_R4)
4555 sp [-1].data.f = (double) sp [-1].data.f_r4;
4556 ++ip;
4557 MINT_IN_BREAK;
4558 MINT_IN_CASE(MINT_CONV_R8_R4_SP)
4559 sp [-2].data.f = (double) sp [-2].data.f_r4;
4560 ++ip;
4561 MINT_IN_BREAK;
4562 MINT_IN_CASE(MINT_CONV_U8_I4)
4563 sp [-1].data.l = sp [-1].data.i & 0xffffffff;
4564 ++ip;
4565 MINT_IN_BREAK;
4566 MINT_IN_CASE(MINT_CONV_U8_R4)
4567 #ifdef MONO_ARCH_EMULATE_FCONV_TO_U8
4568 sp [-1].data.l = mono_rconv_u8 (sp [-1].data.f_r4);
4569 #else
4570 sp [-1].data.l = (guint64) sp [-1].data.f_r4;
4571 #endif
4572 ++ip;
4573 MINT_IN_BREAK;
4574 MINT_IN_CASE(MINT_CONV_U8_R8)
4575 #ifdef MONO_ARCH_EMULATE_FCONV_TO_U8
4576 sp [-1].data.l = mono_fconv_u8_2 (sp [-1].data.f);
4577 #else
4578 sp [-1].data.l = (guint64)sp [-1].data.f;
4579 #endif
4580 ++ip;
4581 MINT_IN_BREAK;
4582 MINT_IN_CASE(MINT_CPOBJ) {
4583 MonoClass* const c = (MonoClass*)frame->imethod->data_items[ip [1]];
4584 g_assert (m_class_is_valuetype (c));
4585 /* if this assertion fails, we need to add a write barrier */
4586 g_assert (!MONO_TYPE_IS_REFERENCE (m_class_get_byval_arg (c)));
4587 stackval_from_data (m_class_get_byval_arg (c), (stackval*)sp [-2].data.p, sp [-1].data.p, FALSE);
4588 ip += 2;
4589 sp -= 2;
4590 MINT_IN_BREAK;
4592 MINT_IN_CASE(MINT_CPOBJ_VT) {
4593 MonoClass* const c = (MonoClass*)frame->imethod->data_items[ip [1]];
4594 mono_value_copy_internal (sp [-2].data.vt, sp [-1].data.vt, c);
4595 ip += 2;
4596 sp -= 2;
4597 MINT_IN_BREAK;
4599 MINT_IN_CASE(MINT_LDOBJ_VT) {
4600 int size = READ32(ip + 1);
4601 ip += 3;
4602 memcpy (vt_sp, sp [-1].data.p, size);
4603 sp [-1].data.p = vt_sp;
4604 vt_sp += ALIGN_TO (size, MINT_VT_ALIGNMENT);
4605 MINT_IN_BREAK;
4607 MINT_IN_CASE(MINT_LDSTR)
4608 sp->data.p = frame->imethod->data_items [ip [1]];
4609 ++sp;
4610 ip += 2;
4611 MINT_IN_BREAK;
4612 MINT_IN_CASE(MINT_LDSTR_TOKEN) {
4613 MonoString *s = NULL;
4614 guint32 strtoken = (guint32)(gsize)frame->imethod->data_items [ip [1]];
4616 MonoMethod *method = frame->imethod->method;
4617 if (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD) {
4618 s = (MonoString*)mono_method_get_wrapper_data (method, strtoken);
4619 } else if (method->wrapper_type != MONO_WRAPPER_NONE) {
4620 s = mono_string_new_wrapper_internal ((const char*)mono_method_get_wrapper_data (method, strtoken));
4621 } else {
4622 g_assert_not_reached ();
4624 sp->data.p = s;
4625 ++sp;
4626 ip += 2;
4627 MINT_IN_BREAK;
4629 MINT_IN_CASE(MINT_NEWOBJ_ARRAY) {
4630 MonoClass *newobj_class;
4631 guint32 token = ip [1];
4632 guint16 param_count = ip [2];
4634 newobj_class = (MonoClass*) frame->imethod->data_items [token];
4636 sp -= param_count;
4637 sp->data.o = ves_array_create (frame->imethod->domain, newobj_class, param_count, sp, error);
4638 if (!is_ok (error))
4639 goto throw_error_label;
4641 ++sp;
4642 ip += 3;
4643 MINT_IN_BREAK;
4645 MINT_IN_CASE(MINT_NEWOBJ_FAST) {
4647 MonoVTable *vtable = (MonoVTable*) frame->imethod->data_items [ip [3]];
4648 INIT_VTABLE (vtable);
4649 MonoObject *o; // See the comment about GC safety.
4650 guint16 param_count;
4651 guint16 imethod_index = ip [1];
4653 const gboolean is_inlined = imethod_index == 0xffff;
4655 param_count = ip [2];
4657 if (param_count) {
4658 sp -= param_count;
4659 memmove (sp + 1 + is_inlined, sp, param_count * sizeof (stackval));
4662 OBJREF (o) = mono_gc_alloc_obj (vtable, m_class_get_instance_size (vtable->klass));
4663 if (G_UNLIKELY (!o)) {
4664 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", m_class_get_instance_size (vtable->klass));
4665 goto throw_error_label;
4668 sp [0].data.o = o;
4669 if (is_inlined) {
4670 sp [1].data.o = o;
4671 sp += param_count + 2;
4672 } else {
4673 InterpMethod *ctor_method = (InterpMethod*) frame->imethod->data_items [imethod_index];
4674 frame->ip = ip;
4676 child_frame.imethod = ctor_method;
4677 child_frame.stack_args = sp;
4679 interp_exec_method (&child_frame, context, error);
4680 CHECK_RESUME_STATE (context);
4681 sp [0].data.o = o;
4682 sp++;
4684 ip += 4;
4686 MINT_IN_BREAK;
4688 MINT_IN_CASE(MINT_NEWOBJ_VT_FAST)
4689 MINT_IN_CASE(MINT_NEWOBJ_VTST_FAST) {
4691 // This is split up to:
4692 // - conserve stack
4693 // - keep exception handling and resume mostly in the main function
4695 frame->ip = ip;
4696 child_frame.imethod = (InterpMethod*) frame->imethod->data_items [ip [1]];
4697 guint16 const param_count = ip [2];
4699 if (param_count) {
4700 sp -= param_count;
4701 memmove (sp + 1, sp, param_count * sizeof (stackval));
4703 child_frame.stack_args = sp;
4704 gboolean const vtst = *ip == MINT_NEWOBJ_VTST_FAST;
4705 if (vtst) {
4706 memset (vt_sp, 0, ip [3]);
4707 sp->data.p = vt_sp;
4708 ip += 4;
4710 interp_exec_method (&child_frame, context, error);
4712 CHECK_RESUME_STATE (context);
4713 sp->data.p = vt_sp;
4715 } else {
4716 ip += 3;
4717 mono_interp_newobj_vt (&child_frame, context, error);
4718 CHECK_RESUME_STATE (context);
4720 ++sp;
4721 MINT_IN_BREAK;
4724 MINT_IN_CASE(MINT_NEWOBJ) {
4726 // This is split up to:
4727 // - conserve stack
4728 // - keep exception handling and resume mostly in the main function
4730 frame->ip = ip;
4732 guint32 const token = ip [1];
4733 ip += 2; // FIXME: Do this after throw?
4735 child_frame.ip = NULL;
4737 child_frame.imethod = (InterpMethod*)frame->imethod->data_items [token];
4738 MonoMethodSignature* const csig = mono_method_signature_internal (child_frame.imethod->method);
4740 g_assert (csig->hasthis);
4741 if (csig->param_count) {
4742 sp -= csig->param_count;
4743 memmove (sp + 1, sp, csig->param_count * sizeof (stackval));
4746 child_frame.stack_args = sp;
4748 MonoException* const exc = mono_interp_newobj (&child_frame, context, error, vt_sp);
4749 if (exc)
4750 THROW_EX (exc, ip);
4751 CHECK_RESUME_STATE (context);
4752 ++sp;
4753 MINT_IN_BREAK;
4755 MINT_IN_CASE(MINT_NEWOBJ_MAGIC) {
4756 frame->ip = ip;
4757 ip += 2;
4759 MINT_IN_BREAK;
4761 MINT_IN_CASE(MINT_INTRINS_BYREFERENCE_CTOR) {
4762 MonoMethodSignature *csig;
4763 guint32 token;
4765 frame->ip = ip;
4766 token = ip [1];
4767 ip += 2;
4769 InterpMethod *cmethod = (InterpMethod*)frame->imethod->data_items [token];
4770 csig = mono_method_signature_internal (cmethod->method);
4772 g_assert (csig->hasthis);
4773 sp -= csig->param_count;
4775 gpointer arg0 = sp [0].data.p;
4777 gpointer *byreference_this = (gpointer*)vt_sp;
4778 *byreference_this = arg0;
4780 /* Followed by a VTRESULT opcode which will push the result on the stack */
4781 ++sp;
4782 MINT_IN_BREAK;
4784 MINT_IN_CASE(MINT_INTRINS_BYREFERENCE_GET_VALUE) {
4785 gpointer *byreference_this = (gpointer*)sp [-1].data.p;
4786 sp [-1].data.p = *byreference_this;
4787 ++ip;
4788 MINT_IN_BREAK;
4790 MINT_IN_CASE(MINT_INTRINS_UNSAFE_ADD_BYTE_OFFSET) {
4791 sp -= 2;
4792 sp [0].data.p = (guint8*)sp [0].data.p + sp [1].data.nati;
4793 sp ++;
4794 ++ip;
4795 MINT_IN_BREAK;
4797 MINT_IN_CASE(MINT_INTRINS_UNSAFE_BYTE_OFFSET) {
4798 sp -= 2;
4799 sp [0].data.nati = (guint8*)sp [1].data.p - (guint8*)sp [0].data.p;
4800 sp ++;
4801 ++ip;
4802 MINT_IN_BREAK;
4804 MINT_IN_CASE(MINT_INTRINS_RUNTIMEHELPERS_OBJECT_HAS_COMPONENT_SIZE) {
4805 MonoObject *obj = sp [-1].data.o;
4806 sp [-1].data.i = (obj->vtable->flags & MONO_VT_FLAG_ARRAY_OR_STRING) != 0;
4807 ++ip;
4808 MINT_IN_BREAK;
4810 MINT_IN_CASE(MINT_CASTCLASS_INTERFACE)
4811 MINT_IN_CASE(MINT_ISINST_INTERFACE) {
4812 MonoObject* const o = sp [-1].data.o;
4813 if (o) {
4814 MonoClass* const c = (MonoClass*)frame->imethod->data_items [ip [1]];
4815 gboolean isinst;
4816 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (o->vtable, m_class_get_interface_id (c))) {
4817 isinst = TRUE;
4818 } else if (m_class_is_array_special_interface (c) || mono_object_is_transparent_proxy (o)) {
4819 /* slow path */
4820 isinst = mono_interp_isinst (o, c); // FIXME: do not swallow the error
4821 } else {
4822 isinst = FALSE;
4825 if (!isinst) {
4826 gboolean const isinst_instr = *ip == MINT_ISINST_INTERFACE;
4827 if (isinst_instr)
4828 sp [-1].data.p = NULL;
4829 else
4830 goto invalid_cast_label;
4833 ip += 2;
4834 MINT_IN_BREAK;
4836 MINT_IN_CASE(MINT_CASTCLASS_COMMON)
4837 MINT_IN_CASE(MINT_ISINST_COMMON) {
4838 MonoObject* const o = sp [-1].data.o;
4839 if (o) {
4840 MonoClass* const c = (MonoClass*)frame->imethod->data_items [ip [1]];
4841 gboolean isinst = mono_class_has_parent_fast (o->vtable->klass, c);
4843 if (!isinst) {
4844 gboolean const isinst_instr = *ip == MINT_ISINST_COMMON;
4845 if (isinst_instr)
4846 sp [-1].data.p = NULL;
4847 else
4848 goto invalid_cast_label;
4851 ip += 2;
4852 MINT_IN_BREAK;
4854 MINT_IN_CASE(MINT_CASTCLASS)
4855 MINT_IN_CASE(MINT_ISINST) {
4856 MonoObject* const o = sp [-1].data.o;
4857 if (o) {
4858 MonoClass* const c = (MonoClass*)frame->imethod->data_items [ip [1]];
4859 if (!mono_interp_isinst (o, c)) { // FIXME: do not swallow the error
4860 gboolean const isinst_instr = *ip == MINT_ISINST;
4861 if (isinst_instr)
4862 sp [-1].data.p = NULL;
4863 else
4864 goto invalid_cast_label;
4867 ip += 2;
4868 MINT_IN_BREAK;
4870 MINT_IN_CASE(MINT_CONV_R_UN_I4)
4871 sp [-1].data.f = (double)(guint32)sp [-1].data.i;
4872 ++ip;
4873 MINT_IN_BREAK;
4874 MINT_IN_CASE(MINT_CONV_R_UN_I8)
4875 sp [-1].data.f = (double)(guint64)sp [-1].data.l;
4876 ++ip;
4877 MINT_IN_BREAK;
4878 MINT_IN_CASE(MINT_UNBOX) {
4879 MonoObject* const o = sp [-1].data.o;
4880 NULL_CHECK (o);
4881 MonoClass* const c = (MonoClass*)frame->imethod->data_items[ip [1]];
4883 if (!(m_class_get_rank (o->vtable->klass) == 0 && m_class_get_element_class (o->vtable->klass) == m_class_get_element_class (c)))
4884 goto invalid_cast_label;
4886 sp [-1].data.p = mono_object_unbox_internal (o);
4887 ip += 2;
4888 MINT_IN_BREAK;
4890 MINT_IN_CASE(MINT_THROW)
4891 --sp;
4892 if (!sp->data.p)
4893 sp->data.p = mono_get_exception_null_reference ();
4895 THROW_EX ((MonoException *)sp->data.p, ip);
4896 MINT_IN_BREAK;
4897 MINT_IN_CASE(MINT_CHECKPOINT)
4898 /* Do synchronous checking of abort requests */
4899 EXCEPTION_CHECKPOINT;
4900 ++ip;
4901 MINT_IN_BREAK;
4902 MINT_IN_CASE(MINT_SAFEPOINT)
4903 /* Do synchronous checking of abort requests */
4904 EXCEPTION_CHECKPOINT;
4905 /* Poll safepoint */
4906 mono_threads_safepoint ();
4907 ++ip;
4908 MINT_IN_BREAK;
4909 MINT_IN_CASE(MINT_LDFLDA_UNSAFE) {
4910 sp[-1].data.p = (char*)sp [-1].data.o + ip [1];
4911 ip += 2;
4912 MINT_IN_BREAK;
4914 MINT_IN_CASE(MINT_LDFLDA) {
4915 MonoObject* const o = sp [-1].data.o;
4916 NULL_CHECK (o);
4917 sp[-1].data.p = (char *)o + ip [1];
4918 ip += 2;
4919 MINT_IN_BREAK;
4921 MINT_IN_CASE(MINT_CKNULL_N) {
4922 /* Same as CKNULL, but further down the stack */
4923 int const n = ip [1];
4924 MonoObject* const o = sp [-n].data.o;
4925 NULL_CHECK (o);
4926 ip += 2;
4927 MINT_IN_BREAK;
4930 #define LDFLD_UNALIGNED(datamem, fieldtype, unaligned) do { \
4931 MonoObject* const o = sp [-1].data.o; \
4932 NULL_CHECK (o); \
4933 if (unaligned) \
4934 memcpy (&sp[-1].data.datamem, (char *)o + ip [1], sizeof (fieldtype)); \
4935 else \
4936 sp[-1].data.datamem = * (fieldtype *)((char *)o + ip [1]) ; \
4937 ip += 2; \
4938 } while (0)
4940 #define LDFLD(datamem, fieldtype) LDFLD_UNALIGNED(datamem, fieldtype, FALSE)
4942 MINT_IN_CASE(MINT_LDFLD_I1) LDFLD(i, gint8); MINT_IN_BREAK;
4943 MINT_IN_CASE(MINT_LDFLD_U1) LDFLD(i, guint8); MINT_IN_BREAK;
4944 MINT_IN_CASE(MINT_LDFLD_I2) LDFLD(i, gint16); MINT_IN_BREAK;
4945 MINT_IN_CASE(MINT_LDFLD_U2) LDFLD(i, guint16); MINT_IN_BREAK;
4946 MINT_IN_CASE(MINT_LDFLD_I4) LDFLD(i, gint32); MINT_IN_BREAK;
4947 MINT_IN_CASE(MINT_LDFLD_I8) LDFLD(l, gint64); MINT_IN_BREAK;
4948 MINT_IN_CASE(MINT_LDFLD_R4) LDFLD(f_r4, float); MINT_IN_BREAK;
4949 MINT_IN_CASE(MINT_LDFLD_R8) LDFLD(f, double); MINT_IN_BREAK;
4950 MINT_IN_CASE(MINT_LDFLD_O) LDFLD(p, gpointer); MINT_IN_BREAK;
4951 MINT_IN_CASE(MINT_LDFLD_P) LDFLD(p, gpointer); MINT_IN_BREAK;
4952 MINT_IN_CASE(MINT_LDFLD_I8_UNALIGNED) LDFLD_UNALIGNED(l, gint64, TRUE); MINT_IN_BREAK;
4953 MINT_IN_CASE(MINT_LDFLD_R8_UNALIGNED) LDFLD_UNALIGNED(f, double, TRUE); MINT_IN_BREAK;
4955 MINT_IN_CASE(MINT_LDFLD_VT) {
4956 MonoObject* const o = sp [-1].data.o;
4957 NULL_CHECK (o);
4959 int size = READ32(ip + 2);
4960 sp [-1].data.p = vt_sp;
4961 memcpy (sp [-1].data.p, (char *)o + ip [1], size);
4962 vt_sp += ALIGN_TO (size, MINT_VT_ALIGNMENT);
4963 ip += 4;
4964 MINT_IN_BREAK;
4967 MINT_IN_CASE(MINT_LDRMFLD) {
4968 MonoObject* const o = sp [-1].data.o;
4969 NULL_CHECK (o);
4970 mono_interp_load_remote_field (frame->imethod, o, ip, sp);
4971 ip += 2;
4972 MINT_IN_BREAK;
4974 MINT_IN_CASE(MINT_LDRMFLD_VT) {
4975 MonoObject* const o = sp [-1].data.o;
4976 NULL_CHECK (o);
4977 vt_sp = mono_interp_load_remote_field_vt (frame->imethod, o, ip, sp, vt_sp);
4978 ip += 2;
4979 MINT_IN_BREAK;
4982 #define STFLD_UNALIGNED(datamem, fieldtype, unaligned) do { \
4983 MonoObject* const o = sp [-2].data.o; \
4984 NULL_CHECK (o); \
4985 sp -= 2; \
4986 if (unaligned) \
4987 memcpy ((char *)o + ip [1], &sp[1].data.datamem, sizeof (fieldtype)); \
4988 else \
4989 * (fieldtype *)((char *)o + ip [1]) = sp[1].data.datamem; \
4990 ip += 2; \
4991 } while (0)
4993 #define STFLD(datamem, fieldtype) STFLD_UNALIGNED(datamem, fieldtype, FALSE)
4995 MINT_IN_CASE(MINT_STFLD_I1) STFLD(i, gint8); MINT_IN_BREAK;
4996 MINT_IN_CASE(MINT_STFLD_U1) STFLD(i, guint8); MINT_IN_BREAK;
4997 MINT_IN_CASE(MINT_STFLD_I2) STFLD(i, gint16); MINT_IN_BREAK;
4998 MINT_IN_CASE(MINT_STFLD_U2) STFLD(i, guint16); MINT_IN_BREAK;
4999 MINT_IN_CASE(MINT_STFLD_I4) STFLD(i, gint32); MINT_IN_BREAK;
5000 MINT_IN_CASE(MINT_STFLD_I8) STFLD(l, gint64); MINT_IN_BREAK;
5001 MINT_IN_CASE(MINT_STFLD_R4) STFLD(f_r4, float); MINT_IN_BREAK;
5002 MINT_IN_CASE(MINT_STFLD_R8) STFLD(f, double); MINT_IN_BREAK;
5003 MINT_IN_CASE(MINT_STFLD_P) STFLD(p, gpointer); MINT_IN_BREAK;
5004 MINT_IN_CASE(MINT_STFLD_O) {
5005 MonoObject* const o = sp [-2].data.o;
5006 NULL_CHECK (o);
5007 sp -= 2;
5008 mono_gc_wbarrier_set_field_internal (o, (char *) o + ip [1], sp [1].data.o);
5009 ip += 2;
5010 MINT_IN_BREAK;
5012 MINT_IN_CASE(MINT_STFLD_I8_UNALIGNED) STFLD_UNALIGNED(l, gint64, TRUE); MINT_IN_BREAK;
5013 MINT_IN_CASE(MINT_STFLD_R8_UNALIGNED) STFLD_UNALIGNED(f, double, TRUE); MINT_IN_BREAK;
5015 MINT_IN_CASE(MINT_STFLD_VT) {
5016 MonoObject* const o = sp [-2].data.o;
5017 NULL_CHECK (o);
5018 sp -= 2;
5020 MonoClass *klass = (MonoClass*)frame->imethod->data_items[ip [2]];
5021 int const i32 = mono_class_value_size (klass, NULL);
5023 guint16 offset = ip [1];
5024 mono_value_copy_internal ((char *) o + offset, sp [1].data.p, klass);
5026 vt_sp -= ALIGN_TO (i32, MINT_VT_ALIGNMENT);
5027 ip += 3;
5028 MINT_IN_BREAK;
5030 MINT_IN_CASE(MINT_STRMFLD) {
5031 MonoClassField *field;
5033 MonoObject* const o = sp [-2].data.o;
5034 NULL_CHECK (o);
5036 field = (MonoClassField*)frame->imethod->data_items[ip [1]];
5037 ip += 2;
5039 #ifndef DISABLE_REMOTING
5040 if (mono_object_is_transparent_proxy (o)) {
5041 MonoClass *klass = ((MonoTransparentProxy*)o)->remote_class->proxy_class;
5042 mono_store_remote_field_checked (o, klass, field, &sp [-1].data, error);
5043 mono_interp_error_cleanup (error); /* FIXME: don't swallow the error */
5044 } else
5045 #endif
5046 stackval_to_data (field->type, &sp [-1], (char*)o + field->offset, FALSE);
5048 sp -= 2;
5049 MINT_IN_BREAK;
5051 MINT_IN_CASE(MINT_STRMFLD_VT)
5053 NULL_CHECK (sp [-2].data.o);
5054 vt_sp -= mono_interp_store_remote_field_vt (frame, ip, sp, error);
5055 ip += 2;
5056 sp -= 2;
5057 MINT_IN_BREAK;
5059 MINT_IN_CASE(MINT_LDSFLDA) {
5060 MonoVTable *vtable = (MonoVTable*) frame->imethod->data_items [ip [1]];
5061 INIT_VTABLE (vtable);
5062 sp->data.p = frame->imethod->data_items [ip [2]];
5063 ip += 3;
5064 ++sp;
5065 MINT_IN_BREAK;
5068 MINT_IN_CASE(MINT_LDSSFLDA) {
5069 guint32 offset = READ32(ip + 1);
5070 sp->data.p = mono_get_special_static_data (offset);
5071 ip += 3;
5072 ++sp;
5073 MINT_IN_BREAK;
5076 /* We init class here to preserve cctor order */
5077 #define LDSFLD(datamem, fieldtype) { \
5078 MonoVTable *vtable = (MonoVTable*) frame->imethod->data_items [ip [1]]; \
5079 INIT_VTABLE (vtable); \
5080 sp[0].data.datamem = * (fieldtype *)(frame->imethod->data_items [ip [2]]) ; \
5081 ip += 3; \
5082 sp++; \
5085 MINT_IN_CASE(MINT_LDSFLD_I1) LDSFLD(i, gint8); MINT_IN_BREAK;
5086 MINT_IN_CASE(MINT_LDSFLD_U1) LDSFLD(i, guint8); MINT_IN_BREAK;
5087 MINT_IN_CASE(MINT_LDSFLD_I2) LDSFLD(i, gint16); MINT_IN_BREAK;
5088 MINT_IN_CASE(MINT_LDSFLD_U2) LDSFLD(i, guint16); MINT_IN_BREAK;
5089 MINT_IN_CASE(MINT_LDSFLD_I4) LDSFLD(i, gint32); MINT_IN_BREAK;
5090 MINT_IN_CASE(MINT_LDSFLD_I8) LDSFLD(l, gint64); MINT_IN_BREAK;
5091 MINT_IN_CASE(MINT_LDSFLD_R4) LDSFLD(f_r4, float); MINT_IN_BREAK;
5092 MINT_IN_CASE(MINT_LDSFLD_R8) LDSFLD(f, double); MINT_IN_BREAK;
5093 MINT_IN_CASE(MINT_LDSFLD_O) LDSFLD(p, gpointer); MINT_IN_BREAK;
5094 MINT_IN_CASE(MINT_LDSFLD_P) LDSFLD(p, gpointer); MINT_IN_BREAK;
5096 MINT_IN_CASE(MINT_LDSFLD_VT) {
5097 MonoVTable *vtable = (MonoVTable*) frame->imethod->data_items [ip [1]];
5098 INIT_VTABLE (vtable);
5099 sp->data.p = vt_sp;
5101 gpointer addr = frame->imethod->data_items [ip [2]];
5102 int const i32 = READ32 (ip + 3);
5103 memcpy (vt_sp, addr, i32);
5104 vt_sp += ALIGN_TO (i32, MINT_VT_ALIGNMENT);
5105 ip += 5;
5106 ++sp;
5107 MINT_IN_BREAK;
5110 #define LDTSFLD(datamem, fieldtype) { \
5111 MonoInternalThread *thread = mono_thread_internal_current (); \
5112 guint32 offset = READ32 (ip + 1); \
5113 gpointer addr = ((char*)thread->static_data [offset & 0x3f]) + (offset >> 6); \
5114 sp[0].data.datamem = *(fieldtype*)addr; \
5115 ip += 3; \
5116 ++sp; \
5118 MINT_IN_CASE(MINT_LDTSFLD_I1) LDTSFLD(i, gint8); MINT_IN_BREAK;
5119 MINT_IN_CASE(MINT_LDTSFLD_U1) LDTSFLD(i, guint8); MINT_IN_BREAK;
5120 MINT_IN_CASE(MINT_LDTSFLD_I2) LDTSFLD(i, gint16); MINT_IN_BREAK;
5121 MINT_IN_CASE(MINT_LDTSFLD_U2) LDTSFLD(i, guint16); MINT_IN_BREAK;
5122 MINT_IN_CASE(MINT_LDTSFLD_I4) LDTSFLD(i, gint32); MINT_IN_BREAK;
5123 MINT_IN_CASE(MINT_LDTSFLD_I8) LDTSFLD(l, gint64); MINT_IN_BREAK;
5124 MINT_IN_CASE(MINT_LDTSFLD_R4) LDTSFLD(f_r4, float); MINT_IN_BREAK;
5125 MINT_IN_CASE(MINT_LDTSFLD_R8) LDTSFLD(f, double); MINT_IN_BREAK;
5126 MINT_IN_CASE(MINT_LDTSFLD_O) LDTSFLD(p, gpointer); MINT_IN_BREAK;
5127 MINT_IN_CASE(MINT_LDTSFLD_P) LDTSFLD(p, gpointer); MINT_IN_BREAK;
5129 MINT_IN_CASE(MINT_LDSSFLD) {
5130 guint32 offset = READ32(ip + 2);
5131 gpointer addr = mono_get_special_static_data (offset);
5132 MonoClassField *field = (MonoClassField*)frame->imethod->data_items [ip [1]];
5133 stackval_from_data (field->type, sp, addr, FALSE);
5134 ip += 4;
5135 ++sp;
5136 MINT_IN_BREAK;
5138 MINT_IN_CASE(MINT_LDSSFLD_VT) {
5139 guint32 offset = READ32(ip + 1);
5140 gpointer addr = mono_get_special_static_data (offset);
5142 int size = READ32 (ip + 3);
5143 memcpy (vt_sp, addr, size);
5144 sp->data.p = vt_sp;
5145 vt_sp += ALIGN_TO (size, MINT_VT_ALIGNMENT);
5146 ip += 5;
5147 ++sp;
5148 MINT_IN_BREAK;
5150 #define STSFLD(datamem, fieldtype) { \
5151 MonoVTable *vtable = (MonoVTable*) frame->imethod->data_items [ip [1]]; \
5152 INIT_VTABLE (vtable); \
5153 sp --; \
5154 * (fieldtype *)(frame->imethod->data_items [ip [2]]) = sp[0].data.datamem; \
5155 ip += 3; \
5158 MINT_IN_CASE(MINT_STSFLD_I1) STSFLD(i, gint8); MINT_IN_BREAK;
5159 MINT_IN_CASE(MINT_STSFLD_U1) STSFLD(i, guint8); MINT_IN_BREAK;
5160 MINT_IN_CASE(MINT_STSFLD_I2) STSFLD(i, gint16); MINT_IN_BREAK;
5161 MINT_IN_CASE(MINT_STSFLD_U2) STSFLD(i, guint16); MINT_IN_BREAK;
5162 MINT_IN_CASE(MINT_STSFLD_I4) STSFLD(i, gint32); MINT_IN_BREAK;
5163 MINT_IN_CASE(MINT_STSFLD_I8) STSFLD(l, gint64); MINT_IN_BREAK;
5164 MINT_IN_CASE(MINT_STSFLD_R4) STSFLD(f_r4, float); MINT_IN_BREAK;
5165 MINT_IN_CASE(MINT_STSFLD_R8) STSFLD(f, double); MINT_IN_BREAK;
5166 MINT_IN_CASE(MINT_STSFLD_P) STSFLD(p, gpointer); MINT_IN_BREAK;
5167 MINT_IN_CASE(MINT_STSFLD_O) STSFLD(p, gpointer); MINT_IN_BREAK;
5169 MINT_IN_CASE(MINT_STSFLD_VT) {
5170 MonoVTable *vtable = (MonoVTable*) frame->imethod->data_items [ip [1]];
5171 INIT_VTABLE (vtable);
5172 int const i32 = READ32 (ip + 3);
5173 gpointer addr = frame->imethod->data_items [ip [2]];
5175 memcpy (addr, sp [-1].data.vt, i32);
5176 vt_sp -= ALIGN_TO (i32, MINT_VT_ALIGNMENT);
5177 ip += 5;
5178 --sp;
5179 MINT_IN_BREAK;
5182 #define STTSFLD(datamem, fieldtype) { \
5183 MonoInternalThread *thread = mono_thread_internal_current (); \
5184 guint32 offset = READ32 (ip + 1); \
5185 gpointer addr = ((char*)thread->static_data [offset & 0x3f]) + (offset >> 6); \
5186 sp--; \
5187 *(fieldtype*)addr = sp[0].data.datamem; \
5188 ip += 3; \
5191 MINT_IN_CASE(MINT_STTSFLD_I1) STTSFLD(i, gint8); MINT_IN_BREAK;
5192 MINT_IN_CASE(MINT_STTSFLD_U1) STTSFLD(i, guint8); MINT_IN_BREAK;
5193 MINT_IN_CASE(MINT_STTSFLD_I2) STTSFLD(i, gint16); MINT_IN_BREAK;
5194 MINT_IN_CASE(MINT_STTSFLD_U2) STTSFLD(i, guint16); MINT_IN_BREAK;
5195 MINT_IN_CASE(MINT_STTSFLD_I4) STTSFLD(i, gint32); MINT_IN_BREAK;
5196 MINT_IN_CASE(MINT_STTSFLD_I8) STTSFLD(l, gint64); MINT_IN_BREAK;
5197 MINT_IN_CASE(MINT_STTSFLD_R4) STTSFLD(f_r4, float); MINT_IN_BREAK;
5198 MINT_IN_CASE(MINT_STTSFLD_R8) STTSFLD(f, double); MINT_IN_BREAK;
5199 MINT_IN_CASE(MINT_STTSFLD_P) STTSFLD(p, gpointer); MINT_IN_BREAK;
5200 MINT_IN_CASE(MINT_STTSFLD_O) STTSFLD(p, gpointer); MINT_IN_BREAK;
5202 MINT_IN_CASE(MINT_STSSFLD) {
5203 guint32 offset = READ32(ip + 2);
5204 gpointer addr = mono_get_special_static_data (offset);
5205 MonoClassField *field = (MonoClassField*)frame->imethod->data_items [ip [1]];
5206 --sp;
5207 stackval_to_data (field->type, sp, addr, FALSE);
5208 ip += 4;
5209 MINT_IN_BREAK;
5211 MINT_IN_CASE(MINT_STSSFLD_VT) {
5212 guint32 offset = READ32(ip + 1);
5213 gpointer addr = mono_get_special_static_data (offset);
5214 --sp;
5215 int size = READ32 (ip + 3);
5216 memcpy (addr, sp->data.vt, size);
5217 vt_sp -= ALIGN_TO (size, MINT_VT_ALIGNMENT);
5218 ip += 5;
5219 MINT_IN_BREAK;
5222 MINT_IN_CASE(MINT_STOBJ_VT) {
5223 int size;
5224 MonoClass* const c = (MonoClass*)frame->imethod->data_items[ip [1]];
5225 ip += 2;
5226 size = mono_class_value_size (c, NULL);
5227 mono_value_copy_internal (sp [-2].data.p, sp [-1].data.p, c);
5228 vt_sp -= ALIGN_TO (size, MINT_VT_ALIGNMENT);
5229 sp -= 2;
5230 MINT_IN_BREAK;
5232 MINT_IN_CASE(MINT_CONV_OVF_I4_UN_R8)
5233 if (sp [-1].data.f < 0 || sp [-1].data.f > G_MAXINT32)
5234 goto overflow_label;
5235 sp [-1].data.i = (gint32)sp [-1].data.f;
5236 ++ip;
5237 MINT_IN_BREAK;
5238 MINT_IN_CASE(MINT_CONV_OVF_U8_I4)
5239 if (sp [-1].data.i < 0)
5240 goto overflow_label;
5241 sp [-1].data.l = sp [-1].data.i;
5242 ++ip;
5243 MINT_IN_BREAK;
5244 MINT_IN_CASE(MINT_CONV_OVF_U8_I8)
5245 if (sp [-1].data.l < 0)
5246 goto overflow_label;
5247 ++ip;
5248 MINT_IN_BREAK;
5249 MINT_IN_CASE(MINT_CONV_OVF_I8_U8)
5250 if ((guint64) sp [-1].data.l > G_MAXINT64)
5251 goto overflow_label;
5252 ++ip;
5253 MINT_IN_BREAK;
5254 MINT_IN_CASE(MINT_CONV_OVF_U8_R4)
5255 if (sp [-1].data.f_r4 < 0 || sp [-1].data.f_r4 > G_MAXUINT64 || isnan (sp [-1].data.f_r4))
5256 goto overflow_label;
5257 sp [-1].data.l = (guint64)sp [-1].data.f_r4;
5258 ++ip;
5259 MINT_IN_BREAK;
5260 MINT_IN_CASE(MINT_CONV_OVF_U8_R8)
5261 if (sp [-1].data.f < 0 || sp [-1].data.f > G_MAXUINT64 || isnan (sp [-1].data.f))
5262 goto overflow_label;
5263 sp [-1].data.l = (guint64)sp [-1].data.f;
5264 ++ip;
5265 MINT_IN_BREAK;
5266 MINT_IN_CASE(MINT_CONV_OVF_I8_UN_R8)
5267 if (sp [-1].data.f < 0 || sp [-1].data.f > G_MAXINT64)
5268 goto overflow_label;
5269 sp [-1].data.l = (gint64)sp [-1].data.f;
5270 ++ip;
5271 MINT_IN_BREAK;
5272 MINT_IN_CASE(MINT_CONV_OVF_I8_UN_R4)
5273 if (sp [-1].data.f_r4 < 0 || sp [-1].data.f_r4 > G_MAXINT64)
5274 goto overflow_label;
5275 sp [-1].data.l = (gint64)sp [-1].data.f_r4;
5276 ++ip;
5277 MINT_IN_BREAK;
5278 MINT_IN_CASE(MINT_CONV_OVF_I8_R4)
5279 if (sp [-1].data.f_r4 < G_MININT64 || sp [-1].data.f_r4 > G_MAXINT64 || isnan (sp [-1].data.f_r4))
5280 goto overflow_label;
5281 sp [-1].data.l = (gint64)sp [-1].data.f_r4;
5282 ++ip;
5283 MINT_IN_BREAK;
5284 MINT_IN_CASE(MINT_CONV_OVF_I8_R8)
5285 if (sp [-1].data.f < G_MININT64 || sp [-1].data.f > G_MAXINT64 || isnan (sp [-1].data.f))
5286 goto overflow_label;
5287 sp [-1].data.l = (gint64)sp [-1].data.f;
5288 ++ip;
5289 MINT_IN_BREAK;
5290 MINT_IN_CASE(MINT_CONV_OVF_I4_UN_I8)
5291 if ((guint64)sp [-1].data.l > G_MAXINT32)
5292 goto overflow_label;
5293 sp [-1].data.i = (gint32)sp [-1].data.l;
5294 ++ip;
5295 MINT_IN_BREAK;
5296 MINT_IN_CASE(MINT_BOX) {
5297 mono_interp_box (frame, ip, sp);
5298 ip += 3;
5299 MINT_IN_BREAK;
5301 MINT_IN_CASE(MINT_BOX_VT) {
5302 vt_sp -= mono_interp_box_vt (frame, ip, sp);
5303 ip += 3;
5304 MINT_IN_BREAK;
5306 MINT_IN_CASE(MINT_BOX_NULLABLE) {
5307 vt_sp -= mono_interp_box_nullable (frame, ip, sp, error);
5308 ip += 3;
5309 MINT_IN_BREAK;
5311 MINT_IN_CASE(MINT_NEWARR) {
5312 MonoVTable *vtable = (MonoVTable*)frame->imethod->data_items[ip [1]];
5313 sp [-1].data.o = (MonoObject*) mono_array_new_specific_checked (vtable, sp [-1].data.i, error);
5314 if (!is_ok (error)) {
5315 goto throw_error_label;
5317 ip += 2;
5318 /*if (profiling_classes) {
5319 guint count = GPOINTER_TO_UINT (g_hash_table_lookup (profiling_classes, o->vtable->klass));
5320 count++;
5321 g_hash_table_insert (profiling_classes, o->vtable->klass, GUINT_TO_POINTER (count));
5324 MINT_IN_BREAK;
5326 MINT_IN_CASE(MINT_LDLEN) {
5327 MonoObject* const o = sp [-1].data.o;
5328 NULL_CHECK (o);
5329 sp [-1].data.nati = mono_array_length_internal ((MonoArray *)o);
5330 ++ip;
5331 MINT_IN_BREAK;
5333 MINT_IN_CASE(MINT_LDLEN_SPAN) {
5334 MonoObject* const o = sp [-1].data.o;
5335 NULL_CHECK (o);
5336 gsize offset_length = (gsize)(gint16)ip [1];
5337 sp [-1].data.nati = *(gint32 *) ((guint8 *) o + offset_length);
5338 ip += 2;
5339 MINT_IN_BREAK;
5341 MINT_IN_CASE(MINT_GETCHR) {
5342 MonoString *s;
5343 s = (MonoString*)sp [-2].data.p;
5344 NULL_CHECK (s);
5345 int const i32 = sp [-1].data.i;
5346 if (i32 < 0 || i32 >= mono_string_length_internal (s))
5347 THROW_EX (mono_get_exception_index_out_of_range (), ip);
5348 --sp;
5349 sp [-1].data.i = mono_string_chars_internal (s)[i32];
5350 ++ip;
5351 MINT_IN_BREAK;
5353 MINT_IN_CASE(MINT_GETITEM_SPAN) {
5354 guint8 * const span = (guint8 *) sp [-2].data.p;
5355 const int index = sp [-1].data.i;
5356 sp--;
5358 NULL_CHECK (span);
5360 const gsize offset_length = (gsize)(gint16)ip [2];
5362 const gint32 length = *(gint32 *) (span + offset_length);
5363 if (index < 0 || index >= length)
5364 THROW_EX (mono_get_exception_index_out_of_range (), ip);
5366 const gsize element_size = (gsize)(gint16)ip [1];
5367 const gsize offset_pointer = (gsize)(gint16)ip [3];
5369 const gpointer pointer = *(gpointer *)(span + offset_pointer);
5370 sp [-1].data.p = (guint8 *) pointer + index * element_size;
5372 ip += 4;
5373 MINT_IN_BREAK;
5375 MINT_IN_CASE(MINT_STRLEN) {
5376 ++ip;
5377 MonoObject* const o = sp [-1].data.o;
5378 NULL_CHECK (o);
5379 sp [-1].data.i = mono_string_length_internal ((MonoString*) o);
5380 MINT_IN_BREAK;
5382 MINT_IN_CASE(MINT_ARRAY_RANK) {
5383 MonoObject* const o = sp [-1].data.o;
5384 NULL_CHECK (o);
5385 sp [-1].data.i = m_class_get_rank (mono_object_class (sp [-1].data.p));
5386 ip++;
5387 MINT_IN_BREAK;
5389 MINT_IN_CASE(MINT_LDELEMA_FAST) {
5390 /* No bounds, one direction */
5391 MonoArray *ao = (MonoArray*)sp [-2].data.o;
5392 NULL_CHECK (ao);
5393 gint32 const index = sp [-1].data.i;
5394 if (index >= ao->max_length)
5395 THROW_EX (mono_get_exception_index_out_of_range (), ip);
5396 gint32 const size = READ32 (ip + 1);
5397 sp [-2].data.p = mono_array_addr_with_size_fast (ao, size, index);
5398 ip += 3;
5399 sp --;
5401 MINT_IN_BREAK;
5403 MINT_IN_CASE(MINT_LDELEMA)
5404 MINT_IN_CASE(MINT_LDELEMA_TC) {
5406 guint16 numargs = ip [2];
5407 ip += 3;
5408 sp -= numargs;
5410 MonoObject* const o = sp [0].data.o;
5411 NULL_CHECK (o);
5413 MonoClass *klass = (MonoClass*)frame->imethod->data_items [ip [-3 + 1]];
5414 const gboolean needs_typecheck = ip [-3] == MINT_LDELEMA_TC;
5415 MonoException *ex = ves_array_element_address (frame, klass, (MonoArray *) o, &sp [1], needs_typecheck);
5416 if (ex)
5417 THROW_EX (ex, ip);
5418 ++sp;
5420 MINT_IN_BREAK;
5422 MINT_IN_CASE(MINT_LDELEM_I1) /* fall through */
5423 MINT_IN_CASE(MINT_LDELEM_U1) /* fall through */
5424 MINT_IN_CASE(MINT_LDELEM_I2) /* fall through */
5425 MINT_IN_CASE(MINT_LDELEM_U2) /* fall through */
5426 MINT_IN_CASE(MINT_LDELEM_I4) /* fall through */
5427 MINT_IN_CASE(MINT_LDELEM_U4) /* fall through */
5428 MINT_IN_CASE(MINT_LDELEM_I8) /* fall through */
5429 MINT_IN_CASE(MINT_LDELEM_I) /* fall through */
5430 MINT_IN_CASE(MINT_LDELEM_R4) /* fall through */
5431 MINT_IN_CASE(MINT_LDELEM_R8) /* fall through */
5432 MINT_IN_CASE(MINT_LDELEM_REF) /* fall through */
5433 MINT_IN_CASE(MINT_LDELEM_VT) {
5434 MonoArray *o;
5435 mono_u aindex;
5437 sp -= 2;
5439 o = (MonoArray*)sp [0].data.p;
5440 NULL_CHECK (o);
5442 aindex = sp [1].data.i;
5443 if (aindex >= mono_array_length_internal (o))
5444 THROW_EX (mono_get_exception_index_out_of_range (), ip);
5447 * FIXME: throw mono_get_exception_array_type_mismatch () if needed
5449 switch (*ip) {
5450 case MINT_LDELEM_I1:
5451 sp [0].data.i = mono_array_get_fast (o, gint8, aindex);
5452 break;
5453 case MINT_LDELEM_U1:
5454 sp [0].data.i = mono_array_get_fast (o, guint8, aindex);
5455 break;
5456 case MINT_LDELEM_I2:
5457 sp [0].data.i = mono_array_get_fast (o, gint16, aindex);
5458 break;
5459 case MINT_LDELEM_U2:
5460 sp [0].data.i = mono_array_get_fast (o, guint16, aindex);
5461 break;
5462 case MINT_LDELEM_I:
5463 sp [0].data.nati = mono_array_get_fast (o, mono_i, aindex);
5464 break;
5465 case MINT_LDELEM_I4:
5466 sp [0].data.i = mono_array_get_fast (o, gint32, aindex);
5467 break;
5468 case MINT_LDELEM_U4:
5469 sp [0].data.i = mono_array_get_fast (o, guint32, aindex);
5470 break;
5471 case MINT_LDELEM_I8:
5472 sp [0].data.l = mono_array_get_fast (o, guint64, aindex);
5473 break;
5474 case MINT_LDELEM_R4:
5475 sp [0].data.f_r4 = mono_array_get_fast (o, float, aindex);
5476 break;
5477 case MINT_LDELEM_R8:
5478 sp [0].data.f = mono_array_get_fast (o, double, aindex);
5479 break;
5480 case MINT_LDELEM_REF:
5481 sp [0].data.p = mono_array_get_fast (o, gpointer, aindex);
5482 break;
5483 case MINT_LDELEM_VT: {
5484 int const i32 = READ32 (ip + 1);
5485 char *src_addr = mono_array_addr_with_size_fast ((MonoArray *) o, i32, aindex);
5486 sp [0].data.vt = vt_sp;
5487 // Copying to vtstack. No wbarrier needed
5488 memcpy (sp [0].data.vt, src_addr, i32);
5489 vt_sp += ALIGN_TO (i32, MINT_VT_ALIGNMENT);
5490 ip += 2;
5491 break;
5493 default:
5494 ves_abort();
5497 ++ip;
5498 ++sp;
5499 MINT_IN_BREAK;
5501 MINT_IN_CASE(MINT_STELEM_I) /* fall through */
5502 MINT_IN_CASE(MINT_STELEM_I1) /* fall through */
5503 MINT_IN_CASE(MINT_STELEM_U1) /* fall through */
5504 MINT_IN_CASE(MINT_STELEM_I2) /* fall through */
5505 MINT_IN_CASE(MINT_STELEM_U2) /* fall through */
5506 MINT_IN_CASE(MINT_STELEM_I4) /* fall through */
5507 MINT_IN_CASE(MINT_STELEM_I8) /* fall through */
5508 MINT_IN_CASE(MINT_STELEM_R4) /* fall through */
5509 MINT_IN_CASE(MINT_STELEM_R8) /* fall through */
5510 MINT_IN_CASE(MINT_STELEM_REF) /* fall through */
5511 MINT_IN_CASE(MINT_STELEM_VT) {
5512 mono_u aindex;
5514 sp -= 3;
5516 MonoObject* const o = sp [0].data.o;
5517 NULL_CHECK (o);
5519 aindex = sp [1].data.i;
5520 if (aindex >= mono_array_length_internal ((MonoArray *)o))
5521 THROW_EX (mono_get_exception_index_out_of_range (), ip);
5523 switch (*ip) {
5524 case MINT_STELEM_I:
5525 mono_array_set_fast ((MonoArray *)o, mono_i, aindex, sp [2].data.nati);
5526 break;
5527 case MINT_STELEM_I1:
5528 mono_array_set_fast ((MonoArray *)o, gint8, aindex, sp [2].data.i);
5529 break;
5530 case MINT_STELEM_U1:
5531 mono_array_set_fast ((MonoArray *) o, guint8, aindex, sp [2].data.i);
5532 break;
5533 case MINT_STELEM_I2:
5534 mono_array_set_fast ((MonoArray *)o, gint16, aindex, sp [2].data.i);
5535 break;
5536 case MINT_STELEM_U2:
5537 mono_array_set_fast ((MonoArray *)o, guint16, aindex, sp [2].data.i);
5538 break;
5539 case MINT_STELEM_I4:
5540 mono_array_set_fast ((MonoArray *)o, gint32, aindex, sp [2].data.i);
5541 break;
5542 case MINT_STELEM_I8:
5543 mono_array_set_fast ((MonoArray *)o, gint64, aindex, sp [2].data.l);
5544 break;
5545 case MINT_STELEM_R4:
5546 mono_array_set_fast ((MonoArray *)o, float, aindex, sp [2].data.f_r4);
5547 break;
5548 case MINT_STELEM_R8:
5549 mono_array_set_fast ((MonoArray *)o, double, aindex, sp [2].data.f);
5550 break;
5551 case MINT_STELEM_REF: {
5552 if (sp [2].data.p) {
5553 MonoObject *isinst_obj = mono_object_isinst_checked (sp [2].data.o, m_class_get_element_class (mono_object_class (o)), error);
5554 mono_interp_error_cleanup (error); /* FIXME: don't swallow the error */
5555 if (!isinst_obj)
5556 THROW_EX (mono_get_exception_array_type_mismatch (), ip);
5558 mono_array_setref_fast ((MonoArray *) o, aindex, sp [2].data.p);
5559 break;
5561 case MINT_STELEM_VT: {
5562 MonoClass *klass_vt = (MonoClass*)frame->imethod->data_items [ip [1]];
5563 int const i32 = READ32 (ip + 2);
5564 char *dst_addr = mono_array_addr_with_size_fast ((MonoArray *) o, i32, aindex);
5566 mono_value_copy_internal (dst_addr, sp [2].data.vt, klass_vt);
5567 vt_sp -= ALIGN_TO (i32, MINT_VT_ALIGNMENT);
5568 ip += 3;
5569 break;
5571 default:
5572 ves_abort();
5575 ++ip;
5576 MINT_IN_BREAK;
5578 MINT_IN_CASE(MINT_CONV_OVF_I4_U4)
5579 if (sp [-1].data.i < 0)
5580 goto overflow_label;
5581 ++ip;
5582 MINT_IN_BREAK;
5583 MINT_IN_CASE(MINT_CONV_OVF_I4_I8)
5584 if (sp [-1].data.l < G_MININT32 || sp [-1].data.l > G_MAXINT32)
5585 goto overflow_label;
5586 sp [-1].data.i = (gint32) sp [-1].data.l;
5587 ++ip;
5588 MINT_IN_BREAK;
5589 MINT_IN_CASE(MINT_CONV_OVF_I4_U8)
5590 if (sp [-1].data.l < 0 || sp [-1].data.l > G_MAXINT32)
5591 goto overflow_label;
5592 sp [-1].data.i = (gint32) sp [-1].data.l;
5593 ++ip;
5594 MINT_IN_BREAK;
5595 MINT_IN_CASE(MINT_CONV_OVF_I4_R4)
5596 if (sp [-1].data.f_r4 < G_MININT32 || sp [-1].data.f_r4 > G_MAXINT32)
5597 goto overflow_label;
5598 sp [-1].data.i = (gint32) sp [-1].data.f_r4;
5599 ++ip;
5600 MINT_IN_BREAK;
5601 MINT_IN_CASE(MINT_CONV_OVF_I4_R8)
5602 if (sp [-1].data.f < G_MININT32 || sp [-1].data.f > G_MAXINT32)
5603 goto overflow_label;
5604 sp [-1].data.i = (gint32) sp [-1].data.f;
5605 ++ip;
5606 MINT_IN_BREAK;
5607 MINT_IN_CASE(MINT_CONV_OVF_U4_I4)
5608 if (sp [-1].data.i < 0)
5609 goto overflow_label;
5610 ++ip;
5611 MINT_IN_BREAK;
5612 MINT_IN_CASE(MINT_CONV_OVF_U4_I8)
5613 if (sp [-1].data.l < 0 || sp [-1].data.l > G_MAXUINT32)
5614 goto overflow_label;
5615 sp [-1].data.i = (guint32) sp [-1].data.l;
5616 ++ip;
5617 MINT_IN_BREAK;
5618 MINT_IN_CASE(MINT_CONV_OVF_U4_R4)
5619 if (sp [-1].data.f_r4 < 0 || sp [-1].data.f_r4 > G_MAXUINT32)
5620 goto overflow_label;
5621 sp [-1].data.i = (guint32) sp [-1].data.f_r4;
5622 ++ip;
5623 MINT_IN_BREAK;
5624 MINT_IN_CASE(MINT_CONV_OVF_U4_R8)
5625 if (sp [-1].data.f < 0 || sp [-1].data.f > G_MAXUINT32)
5626 goto overflow_label;
5627 sp [-1].data.i = (guint32) sp [-1].data.f;
5628 ++ip;
5629 MINT_IN_BREAK;
5630 MINT_IN_CASE(MINT_CONV_OVF_I2_I4)
5631 if (sp [-1].data.i < G_MININT16 || sp [-1].data.i > G_MAXINT16)
5632 goto overflow_label;
5633 ++ip;
5634 MINT_IN_BREAK;
5635 MINT_IN_CASE(MINT_CONV_OVF_I2_U4)
5636 if (sp [-1].data.i < 0 || sp [-1].data.i > G_MAXINT16)
5637 goto overflow_label;
5638 ++ip;
5639 MINT_IN_BREAK;
5640 MINT_IN_CASE(MINT_CONV_OVF_I2_I8)
5641 if (sp [-1].data.l < G_MININT16 || sp [-1].data.l > G_MAXINT16)
5642 goto overflow_label;
5643 sp [-1].data.i = (gint16) sp [-1].data.l;
5644 ++ip;
5645 MINT_IN_BREAK;
5646 MINT_IN_CASE(MINT_CONV_OVF_I2_U8)
5647 if (sp [-1].data.l < 0 || sp [-1].data.l > G_MAXINT16)
5648 goto overflow_label;
5649 sp [-1].data.i = (gint16) sp [-1].data.l;
5650 ++ip;
5651 MINT_IN_BREAK;
5652 MINT_IN_CASE(MINT_CONV_OVF_I2_R8)
5653 if (sp [-1].data.f < G_MININT16 || sp [-1].data.f > G_MAXINT16)
5654 goto overflow_label;
5655 sp [-1].data.i = (gint16) sp [-1].data.f;
5656 ++ip;
5657 MINT_IN_BREAK;
5658 MINT_IN_CASE(MINT_CONV_OVF_I2_UN_R8)
5659 if (sp [-1].data.f < 0 || sp [-1].data.f > G_MAXINT16)
5660 goto overflow_label;
5661 sp [-1].data.i = (gint16) sp [-1].data.f;
5662 ++ip;
5663 MINT_IN_BREAK;
5664 MINT_IN_CASE(MINT_CONV_OVF_U2_I4)
5665 if (sp [-1].data.i < 0 || sp [-1].data.i > G_MAXUINT16)
5666 goto overflow_label;
5667 ++ip;
5668 MINT_IN_BREAK;
5669 MINT_IN_CASE(MINT_CONV_OVF_U2_I8)
5670 if (sp [-1].data.l < 0 || sp [-1].data.l > G_MAXUINT16)
5671 goto overflow_label;
5672 sp [-1].data.i = (guint16) sp [-1].data.l;
5673 ++ip;
5674 MINT_IN_BREAK;
5675 MINT_IN_CASE(MINT_CONV_OVF_U2_R8)
5676 if (sp [-1].data.f < 0 || sp [-1].data.f > G_MAXUINT16)
5677 goto overflow_label;
5678 sp [-1].data.i = (guint16) sp [-1].data.f;
5679 ++ip;
5680 MINT_IN_BREAK;
5681 MINT_IN_CASE(MINT_CONV_OVF_I1_I4)
5682 if (sp [-1].data.i < G_MININT8 || sp [-1].data.i > G_MAXINT8)
5683 goto overflow_label;
5684 ++ip;
5685 MINT_IN_BREAK;
5686 MINT_IN_CASE(MINT_CONV_OVF_I1_U4)
5687 if (sp [-1].data.i < 0 || sp [-1].data.i > G_MAXINT8)
5688 goto overflow_label;
5689 ++ip;
5690 MINT_IN_BREAK;
5691 MINT_IN_CASE(MINT_CONV_OVF_I1_I8)
5692 if (sp [-1].data.l < G_MININT8 || sp [-1].data.l > G_MAXINT8)
5693 goto overflow_label;
5694 sp [-1].data.i = (gint8) sp [-1].data.l;
5695 ++ip;
5696 MINT_IN_BREAK;
5697 MINT_IN_CASE(MINT_CONV_OVF_I1_U8)
5698 if (sp [-1].data.l < 0 || sp [-1].data.l > G_MAXINT8)
5699 goto overflow_label;
5700 sp [-1].data.i = (gint8) sp [-1].data.l;
5701 ++ip;
5702 MINT_IN_BREAK;
5703 MINT_IN_CASE(MINT_CONV_OVF_I1_R8)
5704 if (sp [-1].data.f < G_MININT8 || sp [-1].data.f > G_MAXINT8)
5705 goto overflow_label;
5706 sp [-1].data.i = (gint8) sp [-1].data.f;
5707 ++ip;
5708 MINT_IN_BREAK;
5709 MINT_IN_CASE(MINT_CONV_OVF_I1_UN_R8)
5710 if (sp [-1].data.f < 0 || sp [-1].data.f > G_MAXINT8)
5711 goto overflow_label;
5712 sp [-1].data.i = (gint8) sp [-1].data.f;
5713 ++ip;
5714 MINT_IN_BREAK;
5715 MINT_IN_CASE(MINT_CONV_OVF_U1_I4)
5716 if (sp [-1].data.i < 0 || sp [-1].data.i > G_MAXUINT8)
5717 goto overflow_label;
5718 ++ip;
5719 MINT_IN_BREAK;
5720 MINT_IN_CASE(MINT_CONV_OVF_U1_I8)
5721 if (sp [-1].data.l < 0 || sp [-1].data.l > G_MAXUINT8)
5722 goto overflow_label;
5723 sp [-1].data.i = (guint8) sp [-1].data.l;
5724 ++ip;
5725 MINT_IN_BREAK;
5726 MINT_IN_CASE(MINT_CONV_OVF_U1_R8)
5727 if (sp [-1].data.f < 0 || sp [-1].data.f > G_MAXUINT8)
5728 goto overflow_label;
5729 sp [-1].data.i = (guint8) sp [-1].data.f;
5730 ++ip;
5731 MINT_IN_BREAK;
5732 MINT_IN_CASE(MINT_CKFINITE)
5733 if (!mono_isfinite (sp [-1].data.f))
5734 THROW_EX (mono_get_exception_arithmetic (), ip);
5735 ++ip;
5736 MINT_IN_BREAK;
5737 MINT_IN_CASE(MINT_MKREFANY) {
5738 MonoClass* const c = (MonoClass*)frame->imethod->data_items [ip [1]];
5740 /* The value address is on the stack */
5741 gpointer addr = sp [-1].data.p;
5742 /* Push the typedref value on the stack */
5743 sp [-1].data.p = vt_sp;
5744 vt_sp += ALIGN_TO (sizeof (MonoTypedRef), MINT_VT_ALIGNMENT);
5746 MonoTypedRef *tref = (MonoTypedRef*)sp [-1].data.p;
5747 tref->klass = c;
5748 tref->type = m_class_get_byval_arg (c);
5749 tref->value = addr;
5751 ip += 2;
5752 MINT_IN_BREAK;
5754 MINT_IN_CASE(MINT_REFANYTYPE) {
5755 MonoTypedRef *tref = (MonoTypedRef*)sp [-1].data.p;
5756 MonoType *type = tref->type;
5758 vt_sp -= ALIGN_TO (sizeof (MonoTypedRef), MINT_VT_ALIGNMENT);
5759 sp [-1].data.p = vt_sp;
5760 vt_sp += 8;
5761 *(gpointer*)sp [-1].data.p = type;
5762 ip ++;
5763 MINT_IN_BREAK;
5765 MINT_IN_CASE(MINT_REFANYVAL) {
5766 MonoTypedRef *tref = (MonoTypedRef*)sp [-1].data.p;
5767 gpointer addr = tref->value;
5769 MonoClass* const c = (MonoClass*)frame->imethod->data_items [ip [1]];
5770 if (c != tref->klass)
5771 goto invalid_cast_label;
5773 vt_sp -= ALIGN_TO (sizeof (MonoTypedRef), MINT_VT_ALIGNMENT);
5775 sp [-1].data.p = addr;
5776 ip += 2;
5777 MINT_IN_BREAK;
5779 MINT_IN_CASE(MINT_LDTOKEN)
5780 sp->data.p = vt_sp;
5781 vt_sp += 8;
5782 * (gpointer *)sp->data.p = frame->imethod->data_items[ip [1]];
5783 ip += 2;
5784 ++sp;
5785 MINT_IN_BREAK;
5786 MINT_IN_CASE(MINT_ADD_OVF_I4)
5787 if (CHECK_ADD_OVERFLOW (sp [-2].data.i, sp [-1].data.i))
5788 goto overflow_label;
5789 BINOP(i, +);
5790 MINT_IN_BREAK;
5791 MINT_IN_CASE(MINT_ADD_OVF_I8)
5792 if (CHECK_ADD_OVERFLOW64 (sp [-2].data.l, sp [-1].data.l))
5793 goto overflow_label;
5794 BINOP(l, +);
5795 MINT_IN_BREAK;
5796 MINT_IN_CASE(MINT_ADD_OVF_UN_I4)
5797 if (CHECK_ADD_OVERFLOW_UN (sp [-2].data.i, sp [-1].data.i))
5798 goto overflow_label;
5799 BINOP_CAST(i, +, guint32);
5800 MINT_IN_BREAK;
5801 MINT_IN_CASE(MINT_ADD_OVF_UN_I8)
5802 if (CHECK_ADD_OVERFLOW64_UN (sp [-2].data.l, sp [-1].data.l))
5803 goto overflow_label;
5804 BINOP_CAST(l, +, guint64);
5805 MINT_IN_BREAK;
5806 MINT_IN_CASE(MINT_MUL_OVF_I4)
5807 if (CHECK_MUL_OVERFLOW (sp [-2].data.i, sp [-1].data.i))
5808 goto overflow_label;
5809 BINOP(i, *);
5810 MINT_IN_BREAK;
5811 MINT_IN_CASE(MINT_MUL_OVF_I8)
5812 if (CHECK_MUL_OVERFLOW64 (sp [-2].data.l, sp [-1].data.l))
5813 goto overflow_label;
5814 BINOP(l, *);
5815 MINT_IN_BREAK;
5816 MINT_IN_CASE(MINT_MUL_OVF_UN_I4)
5817 if (CHECK_MUL_OVERFLOW_UN (sp [-2].data.i, sp [-1].data.i))
5818 goto overflow_label;
5819 BINOP_CAST(i, *, guint32);
5820 MINT_IN_BREAK;
5821 MINT_IN_CASE(MINT_MUL_OVF_UN_I8)
5822 if (CHECK_MUL_OVERFLOW64_UN (sp [-2].data.l, sp [-1].data.l))
5823 goto overflow_label;
5824 BINOP_CAST(l, *, guint64);
5825 MINT_IN_BREAK;
5826 MINT_IN_CASE(MINT_SUB_OVF_I4)
5827 if (CHECK_SUB_OVERFLOW (sp [-2].data.i, sp [-1].data.i))
5828 goto overflow_label;
5829 BINOP(i, -);
5830 MINT_IN_BREAK;
5831 MINT_IN_CASE(MINT_SUB_OVF_I8)
5832 if (CHECK_SUB_OVERFLOW64 (sp [-2].data.l, sp [-1].data.l))
5833 goto overflow_label;
5834 BINOP(l, -);
5835 MINT_IN_BREAK;
5836 MINT_IN_CASE(MINT_SUB_OVF_UN_I4)
5837 if (CHECK_SUB_OVERFLOW_UN (sp [-2].data.i, sp [-1].data.i))
5838 goto overflow_label;
5839 BINOP_CAST(i, -, guint32);
5840 MINT_IN_BREAK;
5841 MINT_IN_CASE(MINT_SUB_OVF_UN_I8)
5842 if (CHECK_SUB_OVERFLOW64_UN (sp [-2].data.l, sp [-1].data.l))
5843 goto overflow_label;
5844 BINOP_CAST(l, -, guint64);
5845 MINT_IN_BREAK;
5846 MINT_IN_CASE(MINT_START_ABORT_PROT)
5847 mono_threads_begin_abort_protected_block ();
5848 ip ++;
5849 MINT_IN_BREAK;
5850 MINT_IN_CASE(MINT_ENDFINALLY) {
5851 gboolean pending_abort = mono_threads_end_abort_protected_block ();
5852 ip ++;
5854 // After mono_threads_end_abort_protected_block to conserve stack.
5855 const int clause_index = *ip;
5857 if (clause_args && clause_index == clause_args->exit_clause)
5858 goto exit_frame;
5860 #if DEBUG_INTERP // This assert causes Linux/amd64/clang to use more stack.
5861 g_assert (sp >= frame->stack);
5862 #endif
5863 sp = frame->stack;
5865 if (finally_ips) {
5866 ip = (const guint16*)finally_ips->data;
5867 finally_ips = g_slist_remove (finally_ips, ip);
5868 /* Throw abort after the last finally block to avoid confusing EH */
5869 if (pending_abort && !finally_ips)
5870 EXCEPTION_CHECKPOINT;
5871 // goto main_loop instead of MINT_IN_DISPATCH helps the compiler and therefore conserves stack.
5872 // This is a slow/rare path and conserving stack is preferred over its performance otherwise.
5873 goto main_loop;
5875 ves_abort();
5876 MINT_IN_BREAK;
5879 MINT_IN_CASE(MINT_LEAVE)
5880 MINT_IN_CASE(MINT_LEAVE_S)
5881 MINT_IN_CASE(MINT_LEAVE_CHECK)
5882 MINT_IN_CASE(MINT_LEAVE_S_CHECK) {
5884 // Leave is split into pieces in order to consume less stack,
5885 // but not have to change how exception handling macros access labels and locals.
5887 g_assert (sp >= frame->stack);
5888 sp = frame->stack; /* spec says stack should be empty at endfinally so it should be at the start too */
5889 vt_sp = (unsigned char*)sp + frame->imethod->stack_size;
5891 frame->ip = ip;
5893 int opcode = *ip;
5894 gboolean const check = opcode == MINT_LEAVE_CHECK || opcode == MINT_LEAVE_S_CHECK;
5896 if (check && frame->imethod->method->wrapper_type != MONO_WRAPPER_RUNTIME_INVOKE) {
5897 child_frame.parent = frame;
5898 child_frame.imethod = NULL;
5899 MonoException *abort_exc = mono_interp_leave (&child_frame);
5900 if (abort_exc)
5901 THROW_EX (abort_exc, frame->ip);
5904 opcode = *ip; // Refetch to avoid register/stack pressure.
5905 gboolean const short_offset = opcode == MINT_LEAVE_S || opcode == MINT_LEAVE_S_CHECK;
5906 ip += short_offset ? (short)*(ip + 1) : (gint32)READ32 (ip + 1);
5907 const guint16 *endfinally_ip = ip;
5908 GSList *old_list = finally_ips;
5909 MonoMethod *method = frame->imethod->method;
5910 #if DEBUG_INTERP
5911 if (tracing)
5912 g_print ("* Handle finally IL_%04x\n", endfinally_ip - frame->imethod->code);
5913 #endif
5914 // FIXME Null check for frame->imethod follows deref.
5915 if (frame->imethod == NULL || (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
5916 || (method->iflags & (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL | METHOD_IMPL_ATTRIBUTE_RUNTIME))) {
5917 goto exit_frame;
5919 guint32 const ip_offset = frame->ip - frame->imethod->code;
5921 finally_ips = g_slist_prepend (finally_ips, (void *)endfinally_ip);
5923 for (int i = frame->imethod->num_clauses - 1; i >= 0; i--) {
5924 MonoExceptionClause* const clause = &frame->imethod->clauses [i];
5925 if (MONO_OFFSET_IN_CLAUSE (clause, ip_offset) && !(MONO_OFFSET_IN_CLAUSE (clause, endfinally_ip - frame->imethod->code))) {
5926 if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY) {
5927 ip = frame->imethod->code + clause->handler_offset;
5928 finally_ips = g_slist_prepend (finally_ips, (gpointer) ip);
5929 #if DEBUG_INTERP
5930 if (tracing)
5931 g_print ("* Found finally at IL_%04x with exception: %s\n", clause->handler_offset, context->has_resume_state ? "yes": "no");
5932 #endif
5937 if (old_list != finally_ips && finally_ips) {
5938 ip = (const guint16*)finally_ips->data;
5939 finally_ips = g_slist_remove (finally_ips, ip);
5940 // goto main_loop instead of MINT_IN_DISPATCH helps the compiler and therefore conserves stack.
5941 // This is a slow/rare path and conserving stack is preferred over its performance otherwise.
5942 goto main_loop;
5945 ves_abort();
5946 MINT_IN_BREAK;
5948 MINT_IN_CASE(MINT_ICALL_V_V)
5949 MINT_IN_CASE(MINT_ICALL_V_P)
5950 MINT_IN_CASE(MINT_ICALL_P_V)
5951 MINT_IN_CASE(MINT_ICALL_P_P)
5952 MINT_IN_CASE(MINT_ICALL_PP_V)
5953 MINT_IN_CASE(MINT_ICALL_PP_P)
5954 MINT_IN_CASE(MINT_ICALL_PPP_V)
5955 MINT_IN_CASE(MINT_ICALL_PPP_P)
5956 MINT_IN_CASE(MINT_ICALL_PPPP_V)
5957 MINT_IN_CASE(MINT_ICALL_PPPP_P)
5958 MINT_IN_CASE(MINT_ICALL_PPPPP_V)
5959 MINT_IN_CASE(MINT_ICALL_PPPPP_P)
5960 MINT_IN_CASE(MINT_ICALL_PPPPPP_V)
5961 MINT_IN_CASE(MINT_ICALL_PPPPPP_P)
5962 frame->ip = ip;
5963 sp = do_icall_wrapper (frame, NULL, *ip, sp, frame->imethod->data_items [ip [1]], FALSE);
5964 EXCEPTION_CHECKPOINT;
5965 CHECK_RESUME_STATE (context);
5966 ip += 2;
5967 MINT_IN_BREAK;
5968 MINT_IN_CASE(MINT_MONO_LDPTR)
5969 sp->data.p = frame->imethod->data_items [ip [1]];
5970 ip += 2;
5971 ++sp;
5972 MINT_IN_BREAK;
5973 MINT_IN_CASE(MINT_MONO_NEWOBJ)
5974 sp->data.o = mono_interp_new (frame->imethod->domain, (MonoClass*)frame->imethod->data_items [ip [1]]); // FIXME: do not swallow the error
5975 ip += 2;
5976 sp++;
5977 MINT_IN_BREAK;
5978 MINT_IN_CASE(MINT_MONO_RETOBJ)
5979 ++ip;
5980 sp--;
5981 stackval_from_data (mono_method_signature_internal (frame->imethod->method)->ret, frame->retval, sp->data.p,
5982 mono_method_signature_internal (frame->imethod->method)->pinvoke);
5983 if (sp > frame->stack)
5984 g_warning ("retobj: more values on stack: %d", sp-frame->stack);
5985 goto exit_frame;
5986 MINT_IN_CASE(MINT_MONO_SGEN_THREAD_INFO)
5987 sp->data.p = mono_tls_get_sgen_thread_info ();
5988 sp++;
5989 ++ip;
5990 MINT_IN_BREAK;
5991 MINT_IN_CASE(MINT_MONO_MEMORY_BARRIER) {
5992 ++ip;
5993 mono_memory_barrier ();
5994 MINT_IN_BREAK;
5996 MINT_IN_CASE(MINT_MONO_LDDOMAIN)
5997 sp->data.p = mono_domain_get ();
5998 ++sp;
5999 ++ip;
6000 MINT_IN_BREAK;
6001 MINT_IN_CASE(MINT_SDB_INTR_LOC)
6002 if (G_UNLIKELY (ss_enabled)) {
6003 typedef void (*T) (void);
6004 static T ss_tramp;
6006 if (!ss_tramp) {
6007 void *tramp = mini_get_single_step_trampoline ();
6008 mono_memory_barrier ();
6009 ss_tramp = (T)tramp;
6013 * Make this point to the MINT_SDB_SEQ_POINT instruction which follows this since
6014 * the address of that instruction is stored as the seq point address.
6016 frame->ip = ip + 1;
6019 * Use the same trampoline as the JIT. This ensures that
6020 * the debugger has the context for the last interpreter
6021 * native frame.
6023 do_debugger_tramp (ss_tramp, frame);
6025 CHECK_RESUME_STATE (context);
6027 ++ip;
6028 MINT_IN_BREAK;
6029 MINT_IN_CASE(MINT_SDB_SEQ_POINT)
6030 /* Just a placeholder for a breakpoint */
6031 ++ip;
6032 MINT_IN_BREAK;
6033 MINT_IN_CASE(MINT_SDB_BREAKPOINT) {
6034 typedef void (*T) (void);
6035 static T bp_tramp;
6036 if (!bp_tramp) {
6037 void *tramp = mini_get_breakpoint_trampoline ();
6038 mono_memory_barrier ();
6039 bp_tramp = (T)tramp;
6042 frame->ip = ip;
6044 /* Use the same trampoline as the JIT */
6045 do_debugger_tramp (bp_tramp, frame);
6047 CHECK_RESUME_STATE (context);
6049 ++ip;
6050 MINT_IN_BREAK;
6053 #define RELOP(datamem, op) \
6054 --sp; \
6055 sp [-1].data.i = sp [-1].data.datamem op sp [0].data.datamem; \
6056 ++ip;
6058 #define RELOP_FP(datamem, op, noorder) \
6059 --sp; \
6060 if (mono_isunordered (sp [-1].data.datamem, sp [0].data.datamem)) \
6061 sp [-1].data.i = noorder; \
6062 else \
6063 sp [-1].data.i = sp [-1].data.datamem op sp [0].data.datamem; \
6064 ++ip;
6066 MINT_IN_CASE(MINT_CEQ_I4)
6067 RELOP(i, ==);
6068 MINT_IN_BREAK;
6069 MINT_IN_CASE(MINT_CEQ0_I4)
6070 sp [-1].data.i = (sp [-1].data.i == 0);
6071 ++ip;
6072 MINT_IN_BREAK;
6073 MINT_IN_CASE(MINT_CEQ_I8)
6074 RELOP(l, ==);
6075 MINT_IN_BREAK;
6076 MINT_IN_CASE(MINT_CEQ_R4)
6077 RELOP_FP(f_r4, ==, 0);
6078 MINT_IN_BREAK;
6079 MINT_IN_CASE(MINT_CEQ_R8)
6080 RELOP_FP(f, ==, 0);
6081 MINT_IN_BREAK;
6082 MINT_IN_CASE(MINT_CNE_I4)
6083 RELOP(i, !=);
6084 MINT_IN_BREAK;
6085 MINT_IN_CASE(MINT_CNE_I8)
6086 RELOP(l, !=);
6087 MINT_IN_BREAK;
6088 MINT_IN_CASE(MINT_CNE_R4)
6089 RELOP_FP(f_r4, !=, 1);
6090 MINT_IN_BREAK;
6091 MINT_IN_CASE(MINT_CNE_R8)
6092 RELOP_FP(f, !=, 1);
6093 MINT_IN_BREAK;
6094 MINT_IN_CASE(MINT_CGT_I4)
6095 RELOP(i, >);
6096 MINT_IN_BREAK;
6097 MINT_IN_CASE(MINT_CGT_I8)
6098 RELOP(l, >);
6099 MINT_IN_BREAK;
6100 MINT_IN_CASE(MINT_CGT_R4)
6101 RELOP_FP(f_r4, >, 0);
6102 MINT_IN_BREAK;
6103 MINT_IN_CASE(MINT_CGT_R8)
6104 RELOP_FP(f, >, 0);
6105 MINT_IN_BREAK;
6106 MINT_IN_CASE(MINT_CGE_I4)
6107 RELOP(i, >=);
6108 MINT_IN_BREAK;
6109 MINT_IN_CASE(MINT_CGE_I8)
6110 RELOP(l, >=);
6111 MINT_IN_BREAK;
6112 MINT_IN_CASE(MINT_CGE_R4)
6113 RELOP_FP(f_r4, >=, 0);
6114 MINT_IN_BREAK;
6115 MINT_IN_CASE(MINT_CGE_R8)
6116 RELOP_FP(f, >=, 0);
6117 MINT_IN_BREAK;
6119 #define RELOP_CAST(datamem, op, type) \
6120 --sp; \
6121 sp [-1].data.i = (type)sp [-1].data.datamem op (type)sp [0].data.datamem; \
6122 ++ip;
6124 MINT_IN_CASE(MINT_CGE_UN_I4)
6125 RELOP_CAST(l, >=, guint32);
6126 MINT_IN_BREAK;
6127 MINT_IN_CASE(MINT_CGE_UN_I8)
6128 RELOP_CAST(l, >=, guint64);
6129 MINT_IN_BREAK;
6131 MINT_IN_CASE(MINT_CGT_UN_I4)
6132 RELOP_CAST(i, >, guint32);
6133 MINT_IN_BREAK;
6134 MINT_IN_CASE(MINT_CGT_UN_I8)
6135 RELOP_CAST(l, >, guint64);
6136 MINT_IN_BREAK;
6137 MINT_IN_CASE(MINT_CGT_UN_R4)
6138 RELOP_FP(f_r4, >, 1);
6139 MINT_IN_BREAK;
6140 MINT_IN_CASE(MINT_CGT_UN_R8)
6141 RELOP_FP(f, >, 1);
6142 MINT_IN_BREAK;
6143 MINT_IN_CASE(MINT_CLT_I4)
6144 RELOP(i, <);
6145 MINT_IN_BREAK;
6146 MINT_IN_CASE(MINT_CLT_I8)
6147 RELOP(l, <);
6148 MINT_IN_BREAK;
6149 MINT_IN_CASE(MINT_CLT_R4)
6150 RELOP_FP(f_r4, <, 0);
6151 MINT_IN_BREAK;
6152 MINT_IN_CASE(MINT_CLT_R8)
6153 RELOP_FP(f, <, 0);
6154 MINT_IN_BREAK;
6155 MINT_IN_CASE(MINT_CLT_UN_I4)
6156 RELOP_CAST(i, <, guint32);
6157 MINT_IN_BREAK;
6158 MINT_IN_CASE(MINT_CLT_UN_I8)
6159 RELOP_CAST(l, <, guint64);
6160 MINT_IN_BREAK;
6161 MINT_IN_CASE(MINT_CLT_UN_R4)
6162 RELOP_FP(f_r4, <, 1);
6163 MINT_IN_BREAK;
6164 MINT_IN_CASE(MINT_CLT_UN_R8)
6165 RELOP_FP(f, <, 1);
6166 MINT_IN_BREAK;
6167 MINT_IN_CASE(MINT_CLE_I4)
6168 RELOP(i, <=);
6169 MINT_IN_BREAK;
6170 MINT_IN_CASE(MINT_CLE_I8)
6171 RELOP(l, <=);
6172 MINT_IN_BREAK;
6173 MINT_IN_CASE(MINT_CLE_UN_I4)
6174 RELOP_CAST(l, <=, guint32);
6175 MINT_IN_BREAK;
6176 MINT_IN_CASE(MINT_CLE_UN_I8)
6177 RELOP_CAST(l, <=, guint64);
6178 MINT_IN_BREAK;
6179 MINT_IN_CASE(MINT_CLE_R4)
6180 RELOP_FP(f_r4, <=, 0);
6181 MINT_IN_BREAK;
6182 MINT_IN_CASE(MINT_CLE_R8)
6183 RELOP_FP(f, <=, 0);
6184 MINT_IN_BREAK;
6186 #undef RELOP
6187 #undef RELOP_FP
6188 #undef RELOP_CAST
6190 MINT_IN_CASE(MINT_LDFTN) {
6191 sp->data.p = frame->imethod->data_items [ip [1]];
6192 ++sp;
6193 ip += 2;
6194 MINT_IN_BREAK;
6196 MINT_IN_CASE(MINT_LDVIRTFTN) {
6197 InterpMethod *m = (InterpMethod*)frame->imethod->data_items [ip [1]];
6198 --sp;
6199 NULL_CHECK (sp->data.p);
6201 sp->data.p = get_virtual_method (m, sp->data.o->vtable);
6202 ip += 2;
6203 ++sp;
6204 MINT_IN_BREAK;
6206 MINT_IN_CASE(MINT_LDFTN_DYNAMIC) {
6207 MONO_API_ERROR_INIT (error);
6208 InterpMethod *m = mono_interp_get_imethod (mono_domain_get (), (MonoMethod*) sp [-1].data.p, error);
6209 mono_error_assert_ok (error);
6210 sp [-1].data.p = m;
6211 ip++;
6212 MINT_IN_BREAK;
6215 #define LDARG(datamem, argtype) \
6216 sp->data.datamem = (argtype) frame->stack_args [ip [1]].data.datamem; \
6217 ip += 2; \
6218 ++sp;
6220 MINT_IN_CASE(MINT_LDARG_I1) LDARG(i, gint8); MINT_IN_BREAK;
6221 MINT_IN_CASE(MINT_LDARG_U1) LDARG(i, guint8); MINT_IN_BREAK;
6222 MINT_IN_CASE(MINT_LDARG_I2) LDARG(i, gint16); MINT_IN_BREAK;
6223 MINT_IN_CASE(MINT_LDARG_U2) LDARG(i, guint16); MINT_IN_BREAK;
6224 MINT_IN_CASE(MINT_LDARG_I4) LDARG(i, gint32); MINT_IN_BREAK;
6225 MINT_IN_CASE(MINT_LDARG_I8) LDARG(l, gint64); MINT_IN_BREAK;
6226 MINT_IN_CASE(MINT_LDARG_R4) LDARG(f_r4, float); MINT_IN_BREAK;
6227 MINT_IN_CASE(MINT_LDARG_R8) LDARG(f, double); MINT_IN_BREAK;
6228 MINT_IN_CASE(MINT_LDARG_O) LDARG(p, gpointer); MINT_IN_BREAK;
6229 MINT_IN_CASE(MINT_LDARG_P) LDARG(p, gpointer); MINT_IN_BREAK;
6231 MINT_IN_CASE(MINT_LDARG_VT) {
6232 sp->data.p = vt_sp;
6233 int const i32 = READ32 (ip + 2);
6234 memcpy(sp->data.p, frame->stack_args [ip [1]].data.p, i32);
6235 vt_sp += ALIGN_TO (i32, MINT_VT_ALIGNMENT);
6236 ip += 4;
6237 ++sp;
6238 MINT_IN_BREAK;
6241 #define STARG(datamem, argtype) \
6242 --sp; \
6243 frame->stack_args [ip [1]].data.datamem = (argtype) sp->data.datamem; \
6244 ip += 2; \
6246 MINT_IN_CASE(MINT_STARG_I1) STARG(i, gint8); MINT_IN_BREAK;
6247 MINT_IN_CASE(MINT_STARG_U1) STARG(i, guint8); MINT_IN_BREAK;
6248 MINT_IN_CASE(MINT_STARG_I2) STARG(i, gint16); MINT_IN_BREAK;
6249 MINT_IN_CASE(MINT_STARG_U2) STARG(i, guint16); MINT_IN_BREAK;
6250 MINT_IN_CASE(MINT_STARG_I4) STARG(i, gint32); MINT_IN_BREAK;
6251 MINT_IN_CASE(MINT_STARG_I8) STARG(l, gint64); MINT_IN_BREAK;
6252 MINT_IN_CASE(MINT_STARG_R4) STARG(f_r4, float); MINT_IN_BREAK;
6253 MINT_IN_CASE(MINT_STARG_R8) STARG(f, double); MINT_IN_BREAK;
6254 MINT_IN_CASE(MINT_STARG_O) STARG(p, gpointer); MINT_IN_BREAK;
6255 MINT_IN_CASE(MINT_STARG_P) STARG(p, gpointer); MINT_IN_BREAK;
6257 MINT_IN_CASE(MINT_STARG_VT) {
6258 int const i32 = READ32 (ip + 2);
6259 --sp;
6260 memcpy(frame->stack_args [ip [1]].data.p, sp->data.p, i32);
6261 vt_sp -= ALIGN_TO (i32, MINT_VT_ALIGNMENT);
6262 ip += 4;
6263 MINT_IN_BREAK;
6265 MINT_IN_CASE(MINT_PROF_ENTER) {
6266 ip += 1;
6268 if (MONO_PROFILER_ENABLED (method_enter)) {
6269 MonoProfilerCallContext *prof_ctx = NULL;
6271 if (frame->imethod->prof_flags & MONO_PROFILER_CALL_INSTRUMENTATION_ENTER_CONTEXT) {
6272 prof_ctx = g_new0 (MonoProfilerCallContext, 1);
6273 prof_ctx->interp_frame = frame;
6274 prof_ctx->method = frame->imethod->method;
6277 MONO_PROFILER_RAISE (method_enter, (frame->imethod->method, prof_ctx));
6279 g_free (prof_ctx);
6282 MINT_IN_BREAK;
6285 MINT_IN_CASE(MINT_TRACE_ENTER) {
6286 ip += 1;
6288 MonoProfilerCallContext *prof_ctx = g_alloca (sizeof (MonoProfilerCallContext));
6289 prof_ctx->interp_frame = frame;
6290 prof_ctx->method = frame->imethod->method;
6292 mono_trace_enter_method (frame->imethod->method, prof_ctx);
6293 MINT_IN_BREAK;
6296 MINT_IN_CASE(MINT_TRACE_EXIT) {
6297 // Set retval
6298 int const i32 = READ32 (ip + 1);
6299 --sp;
6300 if (i32 == -1)
6302 else if (i32)
6303 memcpy(frame->retval->data.p, sp->data.p, i32);
6304 else
6305 *frame->retval = *sp;
6307 MonoProfilerCallContext *prof_ctx = g_alloca (sizeof (MonoProfilerCallContext));
6308 prof_ctx->interp_frame = frame;
6309 prof_ctx->method = frame->imethod->method;
6311 mono_trace_leave_method (frame->imethod->method, prof_ctx);
6312 ip += 3;
6313 goto exit_frame;
6316 MINT_IN_CASE(MINT_LDARGA)
6317 sp->data.p = &frame->stack_args [ip [1]];
6318 ip += 2;
6319 ++sp;
6320 MINT_IN_BREAK;
6322 MINT_IN_CASE(MINT_LDARGA_VT)
6323 sp->data.p = frame->stack_args [ip [1]].data.p;
6324 ip += 2;
6325 ++sp;
6326 MINT_IN_BREAK;
6328 #define LDLOC(datamem, argtype) \
6329 sp->data.datamem = * (argtype *)(locals + ip [1]); \
6330 ip += 2; \
6331 ++sp;
6333 MINT_IN_CASE(MINT_LDLOC_I1) LDLOC(i, gint8); MINT_IN_BREAK;
6334 MINT_IN_CASE(MINT_LDLOC_U1) LDLOC(i, guint8); MINT_IN_BREAK;
6335 MINT_IN_CASE(MINT_LDLOC_I2) LDLOC(i, gint16); MINT_IN_BREAK;
6336 MINT_IN_CASE(MINT_LDLOC_U2) LDLOC(i, guint16); MINT_IN_BREAK;
6337 MINT_IN_CASE(MINT_LDLOC_I4) LDLOC(i, gint32); MINT_IN_BREAK;
6338 MINT_IN_CASE(MINT_LDLOC_I8) LDLOC(l, gint64); MINT_IN_BREAK;
6339 MINT_IN_CASE(MINT_LDLOC_R4) LDLOC(f_r4, float); MINT_IN_BREAK;
6340 MINT_IN_CASE(MINT_LDLOC_R8) LDLOC(f, double); MINT_IN_BREAK;
6341 MINT_IN_CASE(MINT_LDLOC_O) LDLOC(p, gpointer); MINT_IN_BREAK;
6342 MINT_IN_CASE(MINT_LDLOC_P) LDLOC(p, gpointer); MINT_IN_BREAK;
6344 MINT_IN_CASE(MINT_LDLOC_VT) {
6345 sp->data.p = vt_sp;
6346 int const i32 = READ32 (ip + 2);
6347 memcpy(sp->data.p, locals + ip [1], i32);
6348 vt_sp += ALIGN_TO (i32, MINT_VT_ALIGNMENT);
6349 ip += 4;
6350 ++sp;
6351 MINT_IN_BREAK;
6353 MINT_IN_CASE(MINT_LDLOCA_S)
6354 sp->data.p = locals + ip [1];
6355 ip += 2;
6356 ++sp;
6357 MINT_IN_BREAK;
6359 #define STLOC(datamem, argtype) \
6360 --sp; \
6361 * (argtype *)(locals + ip [1]) = sp->data.datamem; \
6362 ip += 2;
6364 MINT_IN_CASE(MINT_STLOC_I1) STLOC(i, gint8); MINT_IN_BREAK;
6365 MINT_IN_CASE(MINT_STLOC_U1) STLOC(i, guint8); MINT_IN_BREAK;
6366 MINT_IN_CASE(MINT_STLOC_I2) STLOC(i, gint16); MINT_IN_BREAK;
6367 MINT_IN_CASE(MINT_STLOC_U2) STLOC(i, guint16); MINT_IN_BREAK;
6368 MINT_IN_CASE(MINT_STLOC_I4) STLOC(i, gint32); MINT_IN_BREAK;
6369 MINT_IN_CASE(MINT_STLOC_I8) STLOC(l, gint64); MINT_IN_BREAK;
6370 MINT_IN_CASE(MINT_STLOC_R4) STLOC(f_r4, float); MINT_IN_BREAK;
6371 MINT_IN_CASE(MINT_STLOC_R8) STLOC(f, double); MINT_IN_BREAK;
6372 MINT_IN_CASE(MINT_STLOC_O) STLOC(p, gpointer); MINT_IN_BREAK;
6373 MINT_IN_CASE(MINT_STLOC_P) STLOC(p, gpointer); MINT_IN_BREAK;
6375 #define STLOC_NP(datamem, argtype) \
6376 * (argtype *)(locals + ip [1]) = sp [-1].data.datamem; \
6377 ip += 2;
6379 MINT_IN_CASE(MINT_STLOC_NP_I4) STLOC_NP(i, gint32); MINT_IN_BREAK;
6380 MINT_IN_CASE(MINT_STLOC_NP_O) STLOC_NP(p, gpointer); MINT_IN_BREAK;
6382 MINT_IN_CASE(MINT_STLOC_VT) {
6383 int const i32 = READ32 (ip + 2);
6384 --sp;
6385 memcpy(locals + ip [1], sp->data.p, i32);
6386 vt_sp -= ALIGN_TO (i32, MINT_VT_ALIGNMENT);
6387 ip += 4;
6388 MINT_IN_BREAK;
6391 #define MOVLOC(argtype) \
6392 * (argtype *)(locals + ip [2]) = * (argtype *)(locals + ip [1]); \
6393 ip += 3;
6395 MINT_IN_CASE(MINT_MOVLOC_1) MOVLOC(guint8); MINT_IN_BREAK;
6396 MINT_IN_CASE(MINT_MOVLOC_2) MOVLOC(guint16); MINT_IN_BREAK;
6397 MINT_IN_CASE(MINT_MOVLOC_4) MOVLOC(guint32); MINT_IN_BREAK;
6398 MINT_IN_CASE(MINT_MOVLOC_8) MOVLOC(guint64); MINT_IN_BREAK;
6400 MINT_IN_CASE(MINT_MOVLOC_VT) {
6401 int const i32 = READ32(ip + 3);
6402 memcpy (locals + ip [2], locals + ip [1], i32);
6403 ip += 5;
6404 MINT_IN_BREAK;
6407 MINT_IN_CASE(MINT_LOCALLOC) {
6408 if (sp != frame->stack + 1) /*FIX?*/
6409 goto abort_label;
6411 int len = sp [-1].data.i;
6412 sp [-1].data.p = alloca (len);
6414 if (frame->imethod->init_locals)
6415 memset (sp [-1].data.p, 0, len);
6416 ++ip;
6417 MINT_IN_BREAK;
6419 MINT_IN_CASE(MINT_ENDFILTER)
6420 /* top of stack is result of filter */
6421 frame->retval = &sp [-1];
6422 goto exit_frame;
6423 MINT_IN_CASE(MINT_INITOBJ)
6424 --sp;
6425 memset (sp->data.vt, 0, READ32(ip + 1));
6426 ip += 3;
6427 MINT_IN_BREAK;
6428 MINT_IN_CASE(MINT_CPBLK)
6429 sp -= 3;
6430 if (!sp [0].data.p || !sp [1].data.p)
6431 THROW_EX (mono_get_exception_null_reference(), ip - 1);
6432 ++ip;
6433 /* FIXME: value and size may be int64... */
6434 memcpy (sp [0].data.p, sp [1].data.p, sp [2].data.i);
6435 MINT_IN_BREAK;
6436 #if 0
6437 MINT_IN_CASE(MINT_CONSTRAINED_) {
6438 guint32 token;
6439 /* FIXME: implement */
6440 ++ip;
6441 token = READ32 (ip);
6442 ip += 2;
6443 MINT_IN_BREAK;
6445 #endif
6446 MINT_IN_CASE(MINT_INITBLK)
6447 sp -= 3;
6448 NULL_CHECK (sp [0].data.p);
6449 ++ip;
6450 /* FIXME: value and size may be int64... */
6451 memset (sp [0].data.p, sp [1].data.i, sp [2].data.i);
6452 MINT_IN_BREAK;
6453 #if 0
6454 MINT_IN_CASE(MINT_NO_)
6455 /* FIXME: implement */
6456 ip += 2;
6457 MINT_IN_BREAK;
6458 #endif
6459 MINT_IN_CASE(MINT_RETHROW) {
6460 int exvar_offset = ip [1];
6461 THROW_EX_GENERAL (*(MonoException**)(frame_locals (frame) + exvar_offset), ip, TRUE);
6462 MINT_IN_BREAK;
6464 MINT_IN_CASE(MINT_MONO_RETHROW) {
6466 * need to clarify what this should actually do:
6468 * Takes an exception from the stack and rethrows it.
6469 * This is useful for wrappers that don't want to have to
6470 * use CEE_THROW and lose the exception stacktrace.
6473 --sp;
6474 if (!sp->data.p)
6475 sp->data.p = mono_get_exception_null_reference ();
6477 THROW_EX_GENERAL ((MonoException *)sp->data.p, ip, TRUE);
6478 MINT_IN_BREAK;
6480 MINT_IN_CASE(MINT_LD_DELEGATE_METHOD_PTR) {
6481 MonoDelegate *del;
6483 --sp;
6484 del = (MonoDelegate*)sp->data.p;
6485 if (!del->interp_method) {
6486 /* Not created from interpreted code */
6487 MONO_API_ERROR_INIT (error);
6488 g_assert (del->method);
6489 del->interp_method = mono_interp_get_imethod (del->object.vtable->domain, del->method, error);
6490 mono_error_assert_ok (error);
6492 g_assert (del->interp_method);
6493 sp->data.p = del->interp_method;
6494 ++sp;
6495 ip += 1;
6496 MINT_IN_BREAK;
6498 MINT_IN_CASE(MINT_LD_DELEGATE_INVOKE_IMPL) {
6499 MonoDelegate *del;
6500 int n = ip [1];
6501 del = (MonoDelegate*)sp [-n].data.p;
6502 if (!del->interp_invoke_impl) {
6504 * First time we are called. Set up the invoke wrapper. We might be able to do this
6505 * in ctor but we would need to handle AllocDelegateLike_internal separately
6507 MONO_API_ERROR_INIT (error);
6508 MonoMethod *invoke = mono_get_delegate_invoke_internal (del->object.vtable->klass);
6509 del->interp_invoke_impl = mono_interp_get_imethod (del->object.vtable->domain, mono_marshal_get_delegate_invoke (invoke, del), error);
6510 mono_error_assert_ok (error);
6512 sp ++;
6513 sp [-1].data.p = del->interp_invoke_impl;
6514 ip += 2;
6515 MINT_IN_BREAK;
6518 #define MATH_UNOP(mathfunc) \
6519 sp [-1].data.f = mathfunc (sp [-1].data.f); \
6520 ++ip;
6522 MINT_IN_CASE(MINT_ABS) MATH_UNOP(fabs); MINT_IN_BREAK;
6523 MINT_IN_CASE(MINT_ASIN) MATH_UNOP(asin); MINT_IN_BREAK;
6524 MINT_IN_CASE(MINT_ASINH) MATH_UNOP(asinh); MINT_IN_BREAK;
6525 MINT_IN_CASE(MINT_ACOS) MATH_UNOP(acos); MINT_IN_BREAK;
6526 MINT_IN_CASE(MINT_ACOSH) MATH_UNOP(acosh); MINT_IN_BREAK;
6527 MINT_IN_CASE(MINT_ATAN) MATH_UNOP(atan); MINT_IN_BREAK;
6528 MINT_IN_CASE(MINT_ATANH) MATH_UNOP(atanh); MINT_IN_BREAK;
6529 MINT_IN_CASE(MINT_COS) MATH_UNOP(cos); MINT_IN_BREAK;
6530 MINT_IN_CASE(MINT_CBRT) MATH_UNOP(cbrt); MINT_IN_BREAK;
6531 MINT_IN_CASE(MINT_COSH) MATH_UNOP(cosh); MINT_IN_BREAK;
6532 MINT_IN_CASE(MINT_SIN) MATH_UNOP(sin); MINT_IN_BREAK;
6533 MINT_IN_CASE(MINT_SQRT) MATH_UNOP(sqrt); MINT_IN_BREAK;
6534 MINT_IN_CASE(MINT_SINH) MATH_UNOP(sinh); MINT_IN_BREAK;
6535 MINT_IN_CASE(MINT_TAN) MATH_UNOP(tan); MINT_IN_BREAK;
6536 MINT_IN_CASE(MINT_TANH) MATH_UNOP(tanh); MINT_IN_BREAK;
6538 MINT_IN_CASE(MINT_INTRINS_ENUM_HASFLAG) {
6539 MonoClass *klass = (MonoClass*)frame->imethod->data_items[ip [1]];
6540 mono_interp_enum_hasflag (sp, klass);
6541 sp--;
6542 ip += 2;
6543 MINT_IN_BREAK;
6545 MINT_IN_CASE(MINT_INTRINS_GET_HASHCODE) {
6546 sp [-1].data.i = mono_object_hash_internal (sp [-1].data.o);
6547 ip++;
6548 MINT_IN_BREAK;
6550 MINT_IN_CASE(MINT_INTRINS_GET_TYPE) {
6551 NULL_CHECK (sp [-1].data.p);
6552 sp [-1].data.o = (MonoObject*) sp [-1].data.o->vtable->type;
6553 ip++;
6554 MINT_IN_BREAK;
6557 MINT_IN_DEFAULT
6558 g_error ("Unimplemented opcode: %04x %s at 0x%x\n", *ip, mono_interp_opname (*ip), ip - frame->imethod->code);
6562 g_assert_not_reached ();
6564 abort_label:
6565 THROW_EX (mono_get_exception_execution_engine (NULL), ip);
6566 null_label:
6567 THROW_EX (mono_get_exception_null_reference (), ip);
6568 div_zero_label:
6569 THROW_EX (mono_get_exception_divide_by_zero (), ip);
6570 overflow_label:
6571 THROW_EX (mono_get_exception_overflow (), ip);
6572 throw_error_label:
6573 THROW_EX (mono_error_convert_to_exception (error), ip);
6574 invalid_cast_label:
6575 THROW_EX (mono_get_exception_invalid_cast (), ip);
6576 resume:
6577 g_assert (context->has_resume_state);
6579 if (frame == context->handler_frame && (!clause_args || context->handler_ip < clause_args->end_at_ip)) {
6580 /* Set the current execution state to the resume state in context */
6582 ip = context->handler_ip;
6583 /* spec says stack should be empty at endfinally so it should be at the start too */
6584 sp = frame->stack;
6585 vt_sp = (guchar*)sp + frame->imethod->stack_size;
6586 g_assert (context->exc_gchandle);
6587 sp->data.p = mono_gchandle_get_target_internal (context->exc_gchandle);
6588 ++sp;
6590 finally_ips = clear_resume_state (context, finally_ips);
6591 // goto main_loop instead of MINT_IN_DISPATCH helps the compiler and therefore conserves stack.
6592 // This is a slow/rare path and conserving stack is preferred over its performance otherwise.
6593 goto main_loop;
6595 // fall through
6596 exit_frame:
6597 error_init_reuse (error);
6599 if (clause_args && clause_args->base_frame)
6600 memcpy (clause_args->base_frame->stack, frame->stack, frame->imethod->alloca_size);
6602 if (!context->has_resume_state && MONO_PROFILER_ENABLED (method_leave) &&
6603 frame->imethod->prof_flags & MONO_PROFILER_CALL_INSTRUMENTATION_LEAVE) {
6604 MonoProfilerCallContext *prof_ctx = NULL;
6606 if (frame->imethod->prof_flags & MONO_PROFILER_CALL_INSTRUMENTATION_LEAVE_CONTEXT) {
6607 prof_ctx = g_new0 (MonoProfilerCallContext, 1);
6608 prof_ctx->interp_frame = frame;
6609 prof_ctx->method = frame->imethod->method;
6611 MonoType *rtype = mono_method_signature_internal (frame->imethod->method)->ret;
6613 switch (rtype->type) {
6614 case MONO_TYPE_VOID:
6615 break;
6616 case MONO_TYPE_VALUETYPE:
6617 prof_ctx->return_value = frame->retval->data.p;
6618 break;
6619 default:
6620 prof_ctx->return_value = frame->retval;
6621 break;
6625 MONO_PROFILER_RAISE (method_leave, (frame->imethod->method, prof_ctx));
6627 g_free (prof_ctx);
6628 } else if (context->has_resume_state && frame->imethod->prof_flags & MONO_PROFILER_CALL_INSTRUMENTATION_EXCEPTION_LEAVE)
6629 MONO_PROFILER_RAISE (method_exception_leave, (frame->imethod->method, mono_gchandle_get_target_internal (context->exc_gchandle)));
6631 DEBUG_LEAVE ();
6634 static void
6635 interp_parse_options (const char *options)
6637 char **args, **ptr;
6639 if (!options)
6640 return;
6642 args = g_strsplit (options, ",", -1);
6643 for (ptr = args; ptr && *ptr; ptr ++) {
6644 char *arg = *ptr;
6646 if (strncmp (arg, "jit=", 4) == 0)
6647 mono_interp_jit_classes = g_slist_prepend (mono_interp_jit_classes, arg + 4);
6648 if (strncmp (arg, "interp-only=", strlen ("interp-only=")) == 0)
6649 mono_interp_only_classes = g_slist_prepend (mono_interp_only_classes, arg + strlen ("interp-only="));
6650 if (strncmp (arg, "-inline", 7) == 0)
6651 mono_interp_opt &= ~INTERP_OPT_INLINE;
6652 if (strncmp (arg, "-cprop", 6) == 0)
6653 mono_interp_opt &= ~INTERP_OPT_CPROP;
6658 * interp_set_resume_state:
6660 * Set the state the interpeter will continue to execute from after execution returns to the interpreter.
6662 static void
6663 interp_set_resume_state (MonoJitTlsData *jit_tls, MonoException *ex, MonoJitExceptionInfo *ei, MonoInterpFrameHandle interp_frame, gpointer handler_ip)
6665 ThreadContext *context;
6667 g_assert (jit_tls);
6668 context = (ThreadContext*)jit_tls->interp_context;
6669 g_assert (context);
6671 context->has_resume_state = TRUE;
6672 context->handler_frame = (InterpFrame*)interp_frame;
6673 context->handler_ei = ei;
6674 if (context->exc_gchandle)
6675 mono_gchandle_free_internal (context->exc_gchandle);
6676 context->exc_gchandle = mono_gchandle_new_internal ((MonoObject*)ex, FALSE);
6677 /* Ditto */
6678 if (ei)
6679 *(MonoException**)(frame_locals (context->handler_frame) + ei->exvar_offset) = ex;
6680 context->handler_ip = (const guint16*)handler_ip;
6683 static void
6684 interp_get_resume_state (const MonoJitTlsData *jit_tls, gboolean *has_resume_state, MonoInterpFrameHandle *interp_frame, gpointer *handler_ip)
6686 g_assert (jit_tls);
6687 ThreadContext *context = (ThreadContext*)jit_tls->interp_context;
6688 g_assert (context);
6689 *has_resume_state = context->has_resume_state;
6690 if (context->has_resume_state) {
6691 *interp_frame = context->handler_frame;
6692 *handler_ip = (gpointer)context->handler_ip;
6697 * interp_run_finally:
6699 * Run the finally clause identified by CLAUSE_INDEX in the intepreter frame given by
6700 * frame->interp_frame.
6701 * Return TRUE if the finally clause threw an exception.
6703 static gboolean
6704 interp_run_finally (StackFrameInfo *frame, int clause_index, gpointer handler_ip, gpointer handler_ip_end)
6706 InterpFrame *iframe = (InterpFrame*)frame->interp_frame;
6707 ThreadContext *context = get_context ();
6708 const unsigned short *old_ip = iframe->ip;
6709 FrameClauseArgs clause_args;
6711 memset (&clause_args, 0, sizeof (FrameClauseArgs));
6712 clause_args.start_with_ip = (const guint16*)handler_ip;
6713 clause_args.end_at_ip = (const guint16*)handler_ip_end;
6714 clause_args.exit_clause = clause_index;
6716 ERROR_DECL (error);
6717 interp_exec_method_full (iframe, context, &clause_args, error);
6718 if (context->has_resume_state) {
6719 return TRUE;
6720 } else {
6721 iframe->ip = old_ip;
6722 return FALSE;
6727 * interp_run_filter:
6729 * Run the filter clause identified by CLAUSE_INDEX in the intepreter frame given by
6730 * frame->interp_frame.
6732 static gboolean
6733 interp_run_filter (StackFrameInfo *frame, MonoException *ex, int clause_index, gpointer handler_ip, gpointer handler_ip_end)
6735 InterpFrame *iframe = (InterpFrame*)frame->interp_frame;
6736 ThreadContext *context = get_context ();
6737 InterpFrame child_frame;
6738 stackval retval;
6739 FrameClauseArgs clause_args;
6742 * Have to run the clause in a new frame which is a copy of IFRAME, since
6743 * during debugging, there are two copies of the frame on the stack.
6745 memset (&child_frame, 0, sizeof (InterpFrame));
6746 child_frame.imethod = iframe->imethod;
6747 child_frame.retval = &retval;
6748 child_frame.parent = iframe;
6749 child_frame.stack_args = iframe->stack_args;
6751 memset (&clause_args, 0, sizeof (FrameClauseArgs));
6752 clause_args.start_with_ip = (const guint16*)handler_ip;
6753 clause_args.end_at_ip = (const guint16*)handler_ip_end;
6754 clause_args.filter_exception = ex;
6755 clause_args.base_frame = iframe;
6757 ERROR_DECL (error);
6758 interp_exec_method_full (&child_frame, context, &clause_args, error);
6759 /* ENDFILTER stores the result into child_frame->retval */
6760 return child_frame.retval->data.i ? TRUE : FALSE;
6763 typedef struct {
6764 InterpFrame *current;
6765 } StackIter;
6768 * interp_frame_iter_init:
6770 * Initialize an iterator for iterating through interpreted frames.
6772 static void
6773 interp_frame_iter_init (MonoInterpStackIter *iter, gpointer interp_exit_data)
6775 StackIter *stack_iter = (StackIter*)iter;
6777 stack_iter->current = (InterpFrame*)interp_exit_data;
6781 * interp_frame_iter_next:
6783 * Fill out FRAME with date for the next interpreter frame.
6785 static gboolean
6786 interp_frame_iter_next (MonoInterpStackIter *iter, StackFrameInfo *frame)
6788 StackIter *stack_iter = (StackIter*)iter;
6789 InterpFrame *iframe = stack_iter->current;
6791 memset (frame, 0, sizeof (StackFrameInfo));
6792 /* pinvoke frames doesn't have imethod set */
6793 while (iframe && !(iframe->imethod && iframe->imethod->code && iframe->imethod->jinfo))
6794 iframe = iframe->parent;
6795 if (!iframe)
6796 return FALSE;
6798 MonoMethod *method = iframe->imethod->method;
6799 frame->domain = iframe->imethod->domain;
6800 frame->interp_frame = iframe;
6801 frame->method = method;
6802 frame->actual_method = method;
6803 if (method && ((method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) || (method->iflags & (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL | METHOD_IMPL_ATTRIBUTE_RUNTIME)))) {
6804 frame->native_offset = -1;
6805 frame->type = FRAME_TYPE_MANAGED_TO_NATIVE;
6806 } else {
6807 frame->type = FRAME_TYPE_INTERP;
6808 /* This is the offset in the interpreter IR */
6809 frame->native_offset = (guint8*)iframe->ip - (guint8*)iframe->imethod->code;
6810 if (!method->wrapper_type || method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD)
6811 frame->managed = TRUE;
6813 frame->ji = iframe->imethod->jinfo;
6814 frame->frame_addr = iframe;
6816 stack_iter->current = iframe->parent;
6818 return TRUE;
6821 static MonoJitInfo*
6822 interp_find_jit_info (MonoDomain *domain, MonoMethod *method)
6824 InterpMethod* imethod;
6826 imethod = lookup_imethod (domain, method);
6827 if (imethod)
6828 return imethod->jinfo;
6829 else
6830 return NULL;
6833 static void
6834 interp_set_breakpoint (MonoJitInfo *jinfo, gpointer ip)
6836 guint16 *code = (guint16*)ip;
6837 g_assert (*code == MINT_SDB_SEQ_POINT);
6838 *code = MINT_SDB_BREAKPOINT;
6841 static void
6842 interp_clear_breakpoint (MonoJitInfo *jinfo, gpointer ip)
6844 guint16 *code = (guint16*)ip;
6845 g_assert (*code == MINT_SDB_BREAKPOINT);
6846 *code = MINT_SDB_SEQ_POINT;
6849 static MonoJitInfo*
6850 interp_frame_get_jit_info (MonoInterpFrameHandle frame)
6852 InterpFrame *iframe = (InterpFrame*)frame;
6854 g_assert (iframe->imethod);
6855 return iframe->imethod->jinfo;
6858 static gpointer
6859 interp_frame_get_ip (MonoInterpFrameHandle frame)
6861 InterpFrame *iframe = (InterpFrame*)frame;
6863 g_assert (iframe->imethod);
6864 return (gpointer)iframe->ip;
6867 static gpointer
6868 interp_frame_get_arg (MonoInterpFrameHandle frame, int pos)
6870 InterpFrame *iframe = (InterpFrame*)frame;
6871 MonoMethodSignature *sig;
6873 g_assert (iframe->imethod);
6875 sig = mono_method_signature_internal (iframe->imethod->method);
6876 return stackval_to_data_addr (sig->params [pos], &iframe->stack_args [pos + !!iframe->imethod->hasthis]);
6879 static gpointer
6880 interp_frame_get_local (MonoInterpFrameHandle frame, int pos)
6882 InterpFrame *iframe = (InterpFrame*)frame;
6884 g_assert (iframe->imethod);
6886 return frame_locals (iframe) + iframe->imethod->local_offsets [pos];
6889 static gpointer
6890 interp_frame_get_this (MonoInterpFrameHandle frame)
6892 InterpFrame *iframe = (InterpFrame*)frame;
6894 g_assert (iframe->imethod);
6895 g_assert (iframe->imethod->hasthis);
6896 return &iframe->stack_args [0].data.p;
6899 static MonoInterpFrameHandle
6900 interp_frame_get_parent (MonoInterpFrameHandle frame)
6902 InterpFrame *iframe = (InterpFrame*)frame;
6904 return iframe->parent;
6907 static gpointer
6908 interp_frame_get_res (MonoInterpFrameHandle frame)
6910 InterpFrame *iframe = (InterpFrame*)frame;
6911 MonoMethodSignature *sig;
6913 g_assert (iframe->imethod);
6914 sig = mono_method_signature_internal (iframe->imethod->method);
6915 if (sig->ret->type == MONO_TYPE_VOID)
6916 return NULL;
6917 else
6918 return stackval_to_data_addr (sig->ret, iframe->retval);
6921 static void
6922 interp_start_single_stepping (void)
6924 ss_enabled = TRUE;
6927 static void
6928 interp_stop_single_stepping (void)
6930 ss_enabled = FALSE;
6933 #if COUNT_OPS
6935 static int
6936 opcode_count_comparer (const void * pa, const void * pb)
6938 long counta = opcode_counts [*(int*)pa];
6939 long countb = opcode_counts [*(int*)pb];
6941 if (counta < countb)
6942 return 1;
6943 else if (counta > countb)
6944 return -1;
6945 else
6946 return 0;
6949 static void
6950 interp_print_op_count (void)
6952 int ordered_ops [MINT_LASTOP];
6953 int i;
6954 long total_ops = 0;
6956 for (i = 0; i < MINT_LASTOP; i++) {
6957 ordered_ops [i] = i;
6958 total_ops += opcode_counts [i];
6960 qsort (ordered_ops, MINT_LASTOP, sizeof (int), opcode_count_comparer);
6962 for (i = 0; i < MINT_LASTOP; i++) {
6963 long count = opcode_counts [ordered_ops [i]];
6964 g_print ("%s : %ld (%.2lf%%)\n", mono_interp_opname (ordered_ops [i]), count, (double)count / total_ops * 100);
6967 #endif
6969 static void
6970 interp_cleanup (void)
6972 #if COUNT_OPS
6973 interp_print_op_count ();
6974 #endif
6977 static void
6978 register_interp_stats (void)
6980 mono_counters_init ();
6981 mono_counters_register ("Total transform time", MONO_COUNTER_INTERP | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_interp_stats.transform_time);
6982 mono_counters_register ("Total cprop time", MONO_COUNTER_INTERP | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_interp_stats.cprop_time);
6983 mono_counters_register ("Instructions optimized away", MONO_COUNTER_INTERP | MONO_COUNTER_INT, &mono_interp_stats.killed_instructions);
6984 mono_counters_register ("Methods inlined", MONO_COUNTER_INTERP | MONO_COUNTER_INT, &mono_interp_stats.inlined_methods);
6985 mono_counters_register ("Inline failures", MONO_COUNTER_INTERP | MONO_COUNTER_INT, &mono_interp_stats.inline_failures);
6988 #undef MONO_EE_CALLBACK
6989 #define MONO_EE_CALLBACK(ret, name, sig) interp_ ## name,
6991 static const MonoEECallbacks mono_interp_callbacks = {
6992 MONO_EE_CALLBACKS
6995 void
6996 mono_ee_interp_init (const char *opts)
6998 g_assert (mono_ee_api_version () == MONO_EE_API_VERSION);
6999 g_assert (!interp_init_done);
7000 interp_init_done = TRUE;
7002 mono_native_tls_alloc (&thread_context_id, NULL);
7003 set_context (NULL);
7005 interp_parse_options (opts);
7006 if (mini_get_debug_options ()->mdb_optimizations)
7007 mono_interp_opt &= ~INTERP_OPT_INLINE;
7008 mono_interp_transform_init ();
7010 mini_install_interp_callbacks (&mono_interp_callbacks);
7012 register_interp_stats ();