[interp] Remove varargs from InterpFrame and recompute it instead (#16598)
[mono-project.git] / mono / mini / interp / interp.c
blobbe7429639173003b3cbef402d028c94b5b16d241
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->ex = NULL;
109 frame->ip = NULL;
112 #define interp_exec_method(frame, context, error) interp_exec_method_full ((frame), (context), NULL, error)
115 * List of classes whose methods will be executed by transitioning to JITted code.
116 * Used for testing.
118 GSList *mono_interp_jit_classes;
119 /* Optimizations enabled with interpreter */
120 int mono_interp_opt = INTERP_OPT_INLINE;
121 /* If TRUE, interpreted code will be interrupted at function entry/backward branches */
122 static gboolean ss_enabled;
124 static gboolean interp_init_done = FALSE;
126 static void interp_exec_method_full (InterpFrame *frame, ThreadContext *context, FrameClauseArgs *clause_args, MonoError *error);
127 static InterpMethod* lookup_method_pointer (gpointer addr);
129 typedef void (*ICallMethod) (InterpFrame *frame);
131 static MonoNativeTlsKey thread_context_id;
133 #define DEBUG_INTERP 0
134 #define COUNT_OPS 0
136 #if DEBUG_INTERP
137 int mono_interp_traceopt = 2;
138 /* If true, then we output the opcodes as we interpret them */
139 static int global_tracing = 2;
141 static int debug_indent_level = 0;
143 static int break_on_method = 0;
144 static int nested_trace = 0;
145 static GList *db_methods = NULL;
146 static char* dump_args (InterpFrame *inv);
148 static void
149 output_indent (void)
151 int h;
153 for (h = 0; h < debug_indent_level; h++)
154 g_print (" ");
157 static void
158 db_match_method (gpointer data, gpointer user_data)
160 MonoMethod *m = (MonoMethod*)user_data;
161 MonoMethodDesc *desc = data;
163 if (mono_method_desc_full_match (desc, m))
164 break_on_method = 1;
167 static void
168 debug_enter (InterpFrame *frame, int *tracing)
170 if (db_methods) {
171 g_list_foreach (db_methods, db_match_method, (gpointer)frame->imethod->method);
172 if (break_on_method)
173 *tracing = nested_trace ? (global_tracing = 2, 3) : 2;
174 break_on_method = 0;
176 if (*tracing) {
177 MonoMethod *method = frame->imethod->method;
178 char *mn, *args = dump_args (frame);
179 debug_indent_level++;
180 output_indent ();
181 mn = mono_method_full_name (method, FALSE);
182 g_print ("(%p) Entering %s (", mono_thread_internal_current (), mn);
183 g_free (mn);
184 g_print ("%s)\n", args);
185 g_free (args);
190 #define DEBUG_LEAVE() \
191 if (tracing) { \
192 char *mn, *args; \
193 args = dump_retval (frame); \
194 output_indent (); \
195 mn = mono_method_full_name (frame->imethod->method, FALSE); \
196 g_print ("(%p) Leaving %s", mono_thread_internal_current (), mn); \
197 g_free (mn); \
198 g_print (" => %s\n", args); \
199 g_free (args); \
200 debug_indent_level--; \
201 if (tracing == 3) global_tracing = 0; \
204 #else
206 int mono_interp_traceopt = 0;
207 #define DEBUG_LEAVE()
209 #endif
211 #if defined(__GNUC__) && !defined(TARGET_WASM)
212 #define USE_COMPUTED_GOTO 1
213 #endif
214 #if USE_COMPUTED_GOTO
215 #define MINT_IN_SWITCH(op) COUNT_OP(op); goto *in_labels[op];
216 #define MINT_IN_CASE(x) LAB_ ## x:
217 #define MINT_IN_DISPATCH(op) goto *in_labels[op];
218 #if DEBUG_INTERP
219 #define MINT_IN_BREAK if (tracing > 1) { MINT_IN_DISPATCH(*ip); } else { COUNT_OP(*ip); goto *in_labels[*ip]; }
220 #else
221 #define MINT_IN_BREAK { COUNT_OP(*ip); goto *in_labels[*ip]; }
222 #endif
223 #define MINT_IN_DEFAULT mint_default: if (0) goto mint_default; /* make gcc shut up */
224 #else
225 #define MINT_IN_SWITCH(op) switch (op)
226 #define MINT_IN_CASE(x) case x:
227 #define MINT_IN_DISPATCH(op) goto main_loop;
228 #define MINT_IN_BREAK break
229 #define MINT_IN_DEFAULT default:
230 #endif
232 // FIXME The inlining of this needs to be reevaluated in the context of later changes.
233 // Also there is now only one caller, so consider inlining it manually.
234 static MONO_NEVER_INLINE GSList* // Inlining this causes caller to use more stack.
235 set_resume_state (ThreadContext *context, InterpFrame *frame, GSList* finally_ips)
237 /* We have thrown an exception from a finally block. Some of the leave targets were unwound already */
238 while (finally_ips &&
239 finally_ips->data >= context->handler_ei->try_start &&
240 finally_ips->data < context->handler_ei->try_end)
241 finally_ips = g_slist_remove (finally_ips, finally_ips->data);
242 frame->ex = NULL;
243 context->has_resume_state = 0;
244 context->handler_frame = NULL;
245 context->handler_ei = NULL;
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;
896 frame->ex = ex;
898 if (mono_object_isinst_checked ((MonoObject *) ex, mono_defaults.exception_class, error)) {
899 MonoException *mono_ex = ex;
900 if (!rethrow) {
901 mono_ex->stack_trace = NULL;
902 mono_ex->trace_ips = NULL;
905 mono_error_assert_ok (error);
907 MonoContext ctx;
908 memset (&ctx, 0, sizeof (MonoContext));
909 MONO_CONTEXT_SET_SP (&ctx, frame);
912 * Call the JIT EH code. The EH code will call back to us using:
913 * - mono_interp_set_resume_state ()/run_finally ()/run_filter ().
914 * Since ctx.ip is 0, this will start unwinding from the LMF frame
915 * pushed above, which points to our frames.
917 mono_handle_exception (&ctx, (MonoObject*)ex);
918 if (MONO_CONTEXT_GET_IP (&ctx) != 0) {
919 /* We need to unwind into non-interpreter code */
920 mono_restore_context (&ctx);
921 g_assert_not_reached ();
924 interp_pop_lmf (&ext);
926 g_assert (context->has_resume_state);
929 #define THROW_EX_GENERAL(exception,ex_ip, rethrow) \
930 do { \
931 interp_throw (context, (exception), (frame), (ex_ip), (rethrow)); \
932 goto resume; \
933 } while (0)
935 #define THROW_EX(exception,ex_ip) THROW_EX_GENERAL ((exception), (ex_ip), FALSE)
937 #define NULL_CHECK(o) do { \
938 if (G_UNLIKELY (!(o))) \
939 goto null_label; \
940 } while (0)
942 #define EXCEPTION_CHECKPOINT \
943 do { \
944 if (*mono_thread_interruption_request_flag () && !mono_threads_is_critical_method (frame->imethod->method)) { \
945 MonoException *exc = mono_thread_interruption_checkpoint (); \
946 if (exc) \
947 THROW_EX (exc, ip); \
949 } while (0)
952 #define EXCEPTION_CHECKPOINT_IN_HELPER_FUNCTION \
953 do { \
954 if (*mono_thread_interruption_request_flag () && !mono_threads_is_critical_method (frame->imethod->method)) { \
955 MonoException *exc = mono_thread_interruption_checkpoint (); \
956 if (exc) \
957 return exc; \
959 } while (0)
961 static MonoObject*
962 ves_array_create (MonoDomain *domain, MonoClass *klass, int param_count, stackval *values, MonoError *error)
964 uintptr_t *lengths;
965 intptr_t *lower_bounds;
966 int i;
968 lengths = g_newa (uintptr_t, m_class_get_rank (klass) * 2);
969 for (i = 0; i < param_count; ++i) {
970 lengths [i] = values->data.i;
971 values ++;
973 if (m_class_get_rank (klass) == param_count) {
974 /* Only lengths provided. */
975 lower_bounds = NULL;
976 } else {
977 /* lower bounds are first. */
978 lower_bounds = (intptr_t *) lengths;
979 lengths += m_class_get_rank (klass);
981 return (MonoObject*) mono_array_new_full_checked (domain, klass, lengths, lower_bounds, error);
984 static gint32
985 ves_array_calculate_index (MonoArray *ao, stackval *sp, InterpFrame *frame, gboolean safe)
987 g_assert (!frame->ex);
988 MonoClass *ac = ((MonoObject *) ao)->vtable->klass;
990 guint32 pos = 0;
991 if (ao->bounds) {
992 for (gint32 i = 0; i < m_class_get_rank (ac); i++) {
993 guint32 idx = sp [i].data.i;
994 guint32 lower = ao->bounds [i].lower_bound;
995 guint32 len = ao->bounds [i].length;
996 if (safe && (idx < lower || (idx - lower) >= len)) {
997 frame->ex = mono_get_exception_index_out_of_range ();
998 return -1;
1000 pos = (pos * len) + idx - lower;
1002 } else {
1003 pos = sp [0].data.i;
1004 if (safe && pos >= ao->max_length) {
1005 frame->ex = mono_get_exception_index_out_of_range ();
1006 return -1;
1009 return pos;
1012 static MONO_NEVER_INLINE void
1013 ves_array_set (InterpFrame *frame, stackval *sp, MonoMethodSignature *sig)
1015 MonoObject *o = sp->data.o;
1016 MonoArray *ao = (MonoArray *) o;
1017 MonoClass *ac = o->vtable->klass;
1019 g_assert (m_class_get_rank (ac) >= 1);
1021 gint32 pos = ves_array_calculate_index (ao, sp + 1, frame, TRUE);
1022 if (frame->ex)
1023 return;
1025 int val_index = 1 + m_class_get_rank (ac);
1026 if (sp [val_index].data.p && !m_class_is_valuetype (m_class_get_element_class (mono_object_class (o)))) {
1027 ERROR_DECL (error);
1028 MonoObject *isinst = mono_object_isinst_checked (sp [val_index].data.o, m_class_get_element_class (mono_object_class (o)), error);
1029 mono_error_cleanup (error);
1030 if (!isinst) {
1031 frame->ex = mono_get_exception_array_type_mismatch ();
1032 return;
1036 gint32 esize = mono_array_element_size (ac);
1037 gpointer ea = mono_array_addr_with_size_fast (ao, esize, pos);
1039 MonoType *mt = sig->params [m_class_get_rank (ac)];
1040 stackval_to_data (mt, &sp [val_index], ea, FALSE);
1043 static void
1044 ves_array_get (InterpFrame *frame, stackval *sp, stackval *retval, MonoMethodSignature *sig, gboolean safe)
1046 MonoObject *o = sp->data.o;
1047 MonoArray *ao = (MonoArray *) o;
1048 MonoClass *ac = o->vtable->klass;
1050 g_assert (m_class_get_rank (ac) >= 1);
1052 gint32 pos = ves_array_calculate_index (ao, sp + 1, frame, safe);
1053 if (frame->ex)
1054 return;
1056 gint32 esize = mono_array_element_size (ac);
1057 gconstpointer ea = mono_array_addr_with_size_fast (ao, esize, pos);
1059 MonoType *mt = sig->ret;
1060 stackval_from_data (mt, retval, ea, FALSE);
1063 static MONO_NEVER_INLINE gpointer
1064 ves_array_element_address (InterpFrame *frame, MonoClass *required_type, MonoArray *ao, stackval *sp, gboolean needs_typecheck)
1066 MonoClass *ac = ((MonoObject *) ao)->vtable->klass;
1068 g_assert (m_class_get_rank (ac) >= 1);
1070 gint32 pos = ves_array_calculate_index (ao, sp, frame, TRUE);
1071 if (frame->ex)
1072 return NULL;
1074 if (needs_typecheck && !mono_class_is_assignable_from_internal (m_class_get_element_class (mono_object_class ((MonoObject *) ao)), required_type)) {
1075 frame->ex = mono_get_exception_array_type_mismatch ();
1076 return NULL;
1078 gint32 esize = mono_array_element_size (ac);
1079 return mono_array_addr_with_size_fast (ao, esize, pos);
1082 #ifdef MONO_ARCH_HAVE_INTERP_ENTRY_TRAMPOLINE
1083 static MonoFuncV mono_native_to_interp_trampoline = NULL;
1084 #endif
1086 #ifndef MONO_ARCH_HAVE_INTERP_PINVOKE_TRAMP
1087 static InterpMethodArguments* build_args_from_sig (MonoMethodSignature *sig, InterpFrame *frame)
1089 InterpMethodArguments *margs = g_malloc0 (sizeof (InterpMethodArguments));
1091 #ifdef TARGET_ARM
1092 g_assert (mono_arm_eabi_supported ());
1093 int i8_align = mono_arm_i8_align ();
1094 #endif
1096 #ifdef TARGET_WASM
1097 margs->sig = sig;
1098 #endif
1100 if (sig->hasthis)
1101 margs->ilen++;
1103 for (int i = 0; i < sig->param_count; i++) {
1104 guint32 ptype = sig->params [i]->byref ? MONO_TYPE_PTR : sig->params [i]->type;
1105 switch (ptype) {
1106 case MONO_TYPE_BOOLEAN:
1107 case MONO_TYPE_CHAR:
1108 case MONO_TYPE_I1:
1109 case MONO_TYPE_U1:
1110 case MONO_TYPE_I2:
1111 case MONO_TYPE_U2:
1112 case MONO_TYPE_I4:
1113 case MONO_TYPE_U4:
1114 case MONO_TYPE_I:
1115 case MONO_TYPE_U:
1116 case MONO_TYPE_PTR:
1117 case MONO_TYPE_SZARRAY:
1118 case MONO_TYPE_CLASS:
1119 case MONO_TYPE_OBJECT:
1120 case MONO_TYPE_STRING:
1121 case MONO_TYPE_VALUETYPE:
1122 case MONO_TYPE_GENERICINST:
1123 #if SIZEOF_VOID_P == 8
1124 case MONO_TYPE_I8:
1125 case MONO_TYPE_U8:
1126 #endif
1127 margs->ilen++;
1128 break;
1129 #if SIZEOF_VOID_P == 4
1130 case MONO_TYPE_I8:
1131 case MONO_TYPE_U8:
1132 #ifdef TARGET_ARM
1133 /* pairs begin at even registers */
1134 if (i8_align == 8 && margs->ilen & 1)
1135 margs->ilen++;
1136 #endif
1137 margs->ilen += 2;
1138 break;
1139 #endif
1140 case MONO_TYPE_R4:
1141 #if SIZEOF_VOID_P == 8
1142 case MONO_TYPE_R8:
1143 #endif
1144 margs->flen++;
1145 break;
1146 #if SIZEOF_VOID_P == 4
1147 case MONO_TYPE_R8:
1148 margs->flen += 2;
1149 break;
1150 #endif
1151 default:
1152 g_error ("build_args_from_sig: not implemented yet (1): 0x%x\n", ptype);
1156 if (margs->ilen > 0)
1157 margs->iargs = g_malloc0 (sizeof (gpointer) * margs->ilen);
1159 if (margs->flen > 0)
1160 margs->fargs = g_malloc0 (sizeof (double) * margs->flen);
1162 if (margs->ilen > INTERP_ICALL_TRAMP_IARGS)
1163 g_error ("build_args_from_sig: TODO, allocate gregs: %d\n", margs->ilen);
1165 if (margs->flen > INTERP_ICALL_TRAMP_FARGS)
1166 g_error ("build_args_from_sig: TODO, allocate fregs: %d\n", margs->flen);
1169 size_t int_i = 0;
1170 size_t int_f = 0;
1172 if (sig->hasthis) {
1173 margs->iargs [0] = frame->stack_args->data.p;
1174 int_i++;
1177 for (int i = 0; i < sig->param_count; i++) {
1178 guint32 ptype = sig->params [i]->byref ? MONO_TYPE_PTR : sig->params [i]->type;
1179 switch (ptype) {
1180 case MONO_TYPE_BOOLEAN:
1181 case MONO_TYPE_CHAR:
1182 case MONO_TYPE_I1:
1183 case MONO_TYPE_U1:
1184 case MONO_TYPE_I2:
1185 case MONO_TYPE_U2:
1186 case MONO_TYPE_I4:
1187 case MONO_TYPE_U4:
1188 case MONO_TYPE_I:
1189 case MONO_TYPE_U:
1190 case MONO_TYPE_PTR:
1191 case MONO_TYPE_SZARRAY:
1192 case MONO_TYPE_CLASS:
1193 case MONO_TYPE_OBJECT:
1194 case MONO_TYPE_STRING:
1195 case MONO_TYPE_VALUETYPE:
1196 case MONO_TYPE_GENERICINST:
1197 #if SIZEOF_VOID_P == 8
1198 case MONO_TYPE_I8:
1199 case MONO_TYPE_U8:
1200 #endif
1201 margs->iargs [int_i] = frame->stack_args [i].data.p;
1202 #if DEBUG_INTERP
1203 g_print ("build_args_from_sig: margs->iargs [%d]: %p (frame @ %d)\n", int_i, margs->iargs [int_i], i);
1204 #endif
1205 int_i++;
1206 break;
1207 #if SIZEOF_VOID_P == 4
1208 case MONO_TYPE_I8:
1209 case MONO_TYPE_U8: {
1210 stackval *sarg = &frame->stack_args [i];
1211 #ifdef TARGET_ARM
1212 /* pairs begin at even registers */
1213 if (i8_align == 8 && int_i & 1)
1214 int_i++;
1215 #endif
1216 margs->iargs [int_i] = (gpointer) sarg->data.pair.lo;
1217 int_i++;
1218 margs->iargs [int_i] = (gpointer) sarg->data.pair.hi;
1219 #if DEBUG_INTERP
1220 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);
1221 #endif
1222 int_i++;
1223 break;
1225 #endif
1226 case MONO_TYPE_R4:
1227 case MONO_TYPE_R8:
1228 if (ptype == MONO_TYPE_R4)
1229 * (float *) &(margs->fargs [int_f]) = frame->stack_args [i].data.f_r4;
1230 else
1231 margs->fargs [int_f] = frame->stack_args [i].data.f;
1232 #if DEBUG_INTERP
1233 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);
1234 #endif
1235 #if SIZEOF_VOID_P == 4
1236 int_f += 2;
1237 #else
1238 int_f++;
1239 #endif
1240 break;
1241 default:
1242 g_error ("build_args_from_sig: not implemented yet (2): 0x%x\n", ptype);
1246 switch (sig->ret->type) {
1247 case MONO_TYPE_BOOLEAN:
1248 case MONO_TYPE_CHAR:
1249 case MONO_TYPE_I1:
1250 case MONO_TYPE_U1:
1251 case MONO_TYPE_I2:
1252 case MONO_TYPE_U2:
1253 case MONO_TYPE_I4:
1254 case MONO_TYPE_U4:
1255 case MONO_TYPE_I:
1256 case MONO_TYPE_U:
1257 case MONO_TYPE_PTR:
1258 case MONO_TYPE_SZARRAY:
1259 case MONO_TYPE_CLASS:
1260 case MONO_TYPE_OBJECT:
1261 case MONO_TYPE_STRING:
1262 case MONO_TYPE_I8:
1263 case MONO_TYPE_U8:
1264 case MONO_TYPE_VALUETYPE:
1265 case MONO_TYPE_GENERICINST:
1266 margs->retval = &(frame->retval->data.p);
1267 margs->is_float_ret = 0;
1268 break;
1269 case MONO_TYPE_R4:
1270 case MONO_TYPE_R8:
1271 margs->retval = &(frame->retval->data.p);
1272 margs->is_float_ret = 1;
1273 break;
1274 case MONO_TYPE_VOID:
1275 margs->retval = NULL;
1276 break;
1277 default:
1278 g_error ("build_args_from_sig: ret type not implemented yet: 0x%x\n", sig->ret->type);
1281 return margs;
1283 #endif
1285 static void
1286 interp_frame_arg_to_data (MonoInterpFrameHandle frame, MonoMethodSignature *sig, int index, gpointer data)
1288 InterpFrame *iframe = (InterpFrame*)frame;
1290 if (index == -1)
1291 stackval_to_data (sig->ret, iframe->retval, data, sig->pinvoke);
1292 else
1293 stackval_to_data (sig->params [index], &iframe->stack_args [index], data, sig->pinvoke);
1296 static void
1297 interp_data_to_frame_arg (MonoInterpFrameHandle frame, MonoMethodSignature *sig, int index, gconstpointer data)
1299 InterpFrame *iframe = (InterpFrame*)frame;
1301 if (index == -1)
1302 stackval_from_data (sig->ret, iframe->retval, data, sig->pinvoke);
1303 else if (sig->hasthis && index == 0)
1304 iframe->stack_args [index].data.p = *(gpointer*)data;
1305 else
1306 stackval_from_data (sig->params [index - sig->hasthis], &iframe->stack_args [index], data, sig->pinvoke);
1309 static gpointer
1310 interp_frame_arg_to_storage (MonoInterpFrameHandle frame, MonoMethodSignature *sig, int index)
1312 InterpFrame *iframe = (InterpFrame*)frame;
1314 if (index == -1)
1315 return stackval_to_data_addr (sig->ret, iframe->retval);
1316 else
1317 return stackval_to_data_addr (sig->params [index], &iframe->stack_args [index]);
1320 static void
1321 interp_frame_arg_set_storage (MonoInterpFrameHandle frame, MonoMethodSignature *sig, int index, gpointer storage)
1323 InterpFrame *iframe = (InterpFrame*)frame;
1324 stackval *val = (index == -1) ? iframe->retval : &iframe->stack_args [index];
1325 MonoType *type = (index == -1) ? sig->ret : sig->params [index];
1327 switch (type->type) {
1328 case MONO_TYPE_GENERICINST:
1329 if (!MONO_TYPE_IS_REFERENCE (type))
1330 val->data.vt = storage;
1331 break;
1332 case MONO_TYPE_VALUETYPE:
1333 val->data.vt = storage;
1334 break;
1335 default:
1336 g_assert_not_reached ();
1340 static MonoPIFunc
1341 get_interp_to_native_trampoline (void)
1343 static MonoPIFunc trampoline = NULL;
1345 if (!trampoline) {
1346 if (mono_ee_features.use_aot_trampolines) {
1347 trampoline = (MonoPIFunc) mono_aot_get_trampoline ("interp_to_native_trampoline");
1348 } else {
1349 MonoTrampInfo *info;
1350 trampoline = (MonoPIFunc) mono_arch_get_interp_to_native_trampoline (&info);
1351 mono_tramp_info_register (info, NULL);
1353 mono_memory_barrier ();
1355 return trampoline;
1358 static void
1359 interp_to_native_trampoline (gpointer addr, gpointer ccontext)
1361 get_interp_to_native_trampoline () (addr, ccontext);
1364 /* MONO_NO_OPTIMIATION is needed due to usage of INTERP_PUSH_LMF_WITH_CTX. */
1365 #ifdef _MSC_VER
1366 #pragma optimize ("", off)
1367 #endif
1368 static MONO_NO_OPTIMIZATION MONO_NEVER_INLINE void
1369 ves_pinvoke_method (InterpFrame *frame, MonoMethodSignature *sig, MonoFuncV addr, gboolean string_ctor, ThreadContext *context, gboolean save_last_error)
1371 MonoLMFExt ext;
1372 gpointer args;
1374 frame->ex = NULL;
1376 g_assert (!frame->imethod);
1378 static MonoPIFunc entry_func = NULL;
1379 if (!entry_func) {
1380 #ifdef MONO_ARCH_HAS_NO_PROPER_MONOCTX
1381 ERROR_DECL (error);
1382 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);
1383 mono_error_assert_ok (error);
1384 #else
1385 entry_func = get_interp_to_native_trampoline ();
1386 #endif
1387 mono_memory_barrier ();
1390 #ifdef ENABLE_NETCORE
1391 if (save_last_error) {
1392 mono_marshal_clear_last_error ();
1394 #endif
1396 #ifdef MONO_ARCH_HAVE_INTERP_PINVOKE_TRAMP
1397 CallContext ccontext;
1398 mono_arch_set_native_call_context_args (&ccontext, frame, sig);
1399 args = &ccontext;
1400 #else
1401 InterpMethodArguments *margs = build_args_from_sig (sig, frame);
1402 args = margs;
1403 #endif
1405 INTERP_PUSH_LMF_WITH_CTX (frame, ext, exit_pinvoke);
1406 entry_func ((gpointer) addr, args);
1407 if (save_last_error)
1408 mono_marshal_set_last_error ();
1409 interp_pop_lmf (&ext);
1411 #ifdef MONO_ARCH_HAVE_INTERP_PINVOKE_TRAMP
1412 if (!frame->ex)
1413 mono_arch_get_native_call_context_ret (&ccontext, frame, sig);
1415 if (ccontext.stack != NULL)
1416 g_free (ccontext.stack);
1417 #else
1418 if (!frame->ex && !MONO_TYPE_ISSTRUCT (sig->ret))
1419 stackval_from_data (sig->ret, frame->retval, (char*)&frame->retval->data.p, sig->pinvoke);
1421 g_free (margs->iargs);
1422 g_free (margs->fargs);
1423 g_free (margs);
1424 #endif
1425 goto exit_pinvoke; // prevent unused label warning in some configurations
1426 exit_pinvoke:
1427 return;
1429 #ifdef _MSC_VER
1430 #pragma optimize ("", on)
1431 #endif
1434 * interp_init_delegate:
1436 * Initialize del->interp_method.
1438 static void
1439 interp_init_delegate (MonoDelegate *del, MonoError *error)
1441 MonoMethod *method;
1443 if (del->interp_method) {
1444 /* Delegate created by a call to ves_icall_mono_delegate_ctor_interp () */
1445 del->method = ((InterpMethod *)del->interp_method)->method;
1446 } else if (del->method) {
1447 /* Delegate created dynamically */
1448 del->interp_method = mono_interp_get_imethod (del->object.vtable->domain, del->method, error);
1449 } else {
1450 /* Created from JITted code */
1451 g_assert_not_reached ();
1454 method = ((InterpMethod*)del->interp_method)->method;
1455 if (del->target &&
1456 method &&
1457 method->flags & METHOD_ATTRIBUTE_VIRTUAL &&
1458 method->flags & METHOD_ATTRIBUTE_ABSTRACT &&
1459 mono_class_is_abstract (method->klass))
1460 del->interp_method = get_virtual_method ((InterpMethod*)del->interp_method, del->target->vtable);
1462 method = ((InterpMethod*)del->interp_method)->method;
1463 if (method && m_class_get_parent (method->klass) == mono_defaults.multicastdelegate_class) {
1464 const char *name = method->name;
1465 if (*name == 'I' && (strcmp (name, "Invoke") == 0)) {
1467 * When invoking the delegate interp_method is executed directly. If it's an
1468 * invoke make sure we replace it with the appropriate delegate invoke wrapper.
1470 * FIXME We should do this later, when we also know the delegate on which the
1471 * target method is called.
1473 del->interp_method = mono_interp_get_imethod (del->object.vtable->domain, mono_marshal_get_delegate_invoke (method, NULL), error);
1474 mono_error_assert_ok (error);
1478 if (!((InterpMethod *) del->interp_method)->transformed && method_is_dynamic (method)) {
1479 /* Return any errors from method compilation */
1480 mono_interp_transform_method ((InterpMethod *) del->interp_method, get_context (), error);
1481 return_if_nok (error);
1485 static void
1486 interp_delegate_ctor (MonoObjectHandle this_obj, MonoObjectHandle target, gpointer addr, MonoError *error)
1489 * addr is the result of an LDFTN opcode, i.e. an InterpMethod
1491 InterpMethod *imethod = (InterpMethod*)addr;
1493 if (!(imethod->method->flags & METHOD_ATTRIBUTE_STATIC)) {
1494 MonoMethod *invoke = mono_get_delegate_invoke_internal (mono_handle_class (this_obj));
1495 /* virtual invoke delegates must not have null check */
1496 if (mono_method_signature_internal (imethod->method)->param_count == mono_method_signature_internal (invoke)->param_count
1497 && MONO_HANDLE_IS_NULL (target)) {
1498 mono_error_set_argument (error, "this", "Delegate to an instance method cannot have null 'this'");
1499 return;
1503 g_assert (imethod->method);
1504 gpointer entry = mini_get_interp_callbacks ()->create_method_pointer (imethod->method, FALSE, error);
1505 return_if_nok (error);
1507 MONO_HANDLE_SETVAL (MONO_HANDLE_CAST (MonoDelegate, this_obj), interp_method, gpointer, imethod);
1509 mono_delegate_ctor (this_obj, target, entry, error);
1513 * From the spec:
1514 * runtime specifies that the implementation of the method is automatically
1515 * provided by the runtime and is primarily used for the methods of delegates.
1517 static MONO_NEVER_INLINE void
1518 ves_imethod (InterpFrame *frame, MonoMethod *method, MonoMethodSignature *sig, stackval *sp, stackval *retval)
1520 const char *name = method->name;
1521 mono_class_init_internal (method->klass);
1523 if (method->klass == mono_defaults.array_class) {
1524 if (!strcmp (name, "UnsafeMov")) {
1525 /* TODO: layout checks */
1526 stackval_from_data (sig->ret, retval, (char*) sp, FALSE);
1527 return;
1529 if (!strcmp (name, "UnsafeLoad")) {
1530 ves_array_get (frame, sp, retval, sig, FALSE);
1531 return;
1533 } else if (mini_class_is_system_array (method->klass)) {
1534 MonoObject *obj = (MonoObject*) sp->data.p;
1535 if (!obj) {
1536 frame->ex = mono_get_exception_null_reference ();
1537 return;
1539 if (*name == 'S' && (strcmp (name, "Set") == 0)) {
1540 ves_array_set (frame, sp, sig);
1541 return;
1543 if (*name == 'G' && (strcmp (name, "Get") == 0)) {
1544 ves_array_get (frame, sp, retval, sig, TRUE);
1545 return;
1549 g_error ("Don't know how to exec runtime method %s.%s::%s",
1550 m_class_get_name_space (method->klass), m_class_get_name (method->klass),
1551 method->name);
1554 #if DEBUG_INTERP
1555 static char*
1556 dump_stack (stackval *stack, stackval *sp)
1558 stackval *s = stack;
1559 GString *str = g_string_new ("");
1561 if (sp == stack)
1562 return g_string_free (str, FALSE);
1564 while (s < sp) {
1565 g_string_append_printf (str, "[%p (%lld)] ", s->data.l, s->data.l);
1566 ++s;
1568 return g_string_free (str, FALSE);
1571 static void
1572 dump_stackval (GString *str, stackval *s, MonoType *type)
1574 switch (type->type) {
1575 case MONO_TYPE_I1:
1576 case MONO_TYPE_U1:
1577 case MONO_TYPE_I2:
1578 case MONO_TYPE_U2:
1579 case MONO_TYPE_I4:
1580 case MONO_TYPE_U4:
1581 case MONO_TYPE_CHAR:
1582 case MONO_TYPE_BOOLEAN:
1583 g_string_append_printf (str, "[%d] ", s->data.i);
1584 break;
1585 case MONO_TYPE_STRING:
1586 case MONO_TYPE_SZARRAY:
1587 case MONO_TYPE_CLASS:
1588 case MONO_TYPE_OBJECT:
1589 case MONO_TYPE_ARRAY:
1590 case MONO_TYPE_PTR:
1591 case MONO_TYPE_I:
1592 case MONO_TYPE_U:
1593 g_string_append_printf (str, "[%p] ", s->data.p);
1594 break;
1595 case MONO_TYPE_VALUETYPE:
1596 if (m_class_is_enumtype (type->data.klass))
1597 g_string_append_printf (str, "[%d] ", s->data.i);
1598 else
1599 g_string_append_printf (str, "[vt:%p] ", s->data.p);
1600 break;
1601 case MONO_TYPE_R4:
1602 g_string_append_printf (str, "[%g] ", s->data.f_r4);
1603 break;
1604 case MONO_TYPE_R8:
1605 g_string_append_printf (str, "[%g] ", s->data.f);
1606 break;
1607 case MONO_TYPE_I8:
1608 case MONO_TYPE_U8:
1609 default: {
1610 GString *res = g_string_new ("");
1611 mono_type_get_desc (res, type, TRUE);
1612 g_string_append_printf (str, "[{%s} %lld/0x%0llx] ", res->str, s->data.l, s->data.l);
1613 g_string_free (res, TRUE);
1614 break;
1619 static char*
1620 dump_retval (InterpFrame *inv)
1622 GString *str = g_string_new ("");
1623 MonoType *ret = mono_method_signature_internal (inv->imethod->method)->ret;
1625 if (ret->type != MONO_TYPE_VOID)
1626 dump_stackval (str, inv->retval, ret);
1628 return g_string_free (str, FALSE);
1631 static char*
1632 dump_args (InterpFrame *inv)
1634 GString *str = g_string_new ("");
1635 int i;
1636 MonoMethodSignature *signature = mono_method_signature_internal (inv->imethod->method);
1638 if (signature->param_count == 0 && !signature->hasthis)
1639 return g_string_free (str, FALSE);
1641 if (signature->hasthis) {
1642 MonoMethod *method = inv->imethod->method;
1643 dump_stackval (str, inv->stack_args, m_class_get_byval_arg (method->klass));
1646 for (i = 0; i < signature->param_count; ++i)
1647 dump_stackval (str, inv->stack_args + (!!signature->hasthis) + i, signature->params [i]);
1649 return g_string_free (str, FALSE);
1651 #endif
1653 #define CHECK_ADD_OVERFLOW(a,b) \
1654 (gint32)(b) >= 0 ? (gint32)(G_MAXINT32) - (gint32)(b) < (gint32)(a) ? -1 : 0 \
1655 : (gint32)(G_MININT32) - (gint32)(b) > (gint32)(a) ? +1 : 0
1657 #define CHECK_SUB_OVERFLOW(a,b) \
1658 (gint32)(b) < 0 ? (gint32)(G_MAXINT32) + (gint32)(b) < (gint32)(a) ? -1 : 0 \
1659 : (gint32)(G_MININT32) + (gint32)(b) > (gint32)(a) ? +1 : 0
1661 #define CHECK_ADD_OVERFLOW_UN(a,b) \
1662 (guint32)(G_MAXUINT32) - (guint32)(b) < (guint32)(a) ? -1 : 0
1664 #define CHECK_SUB_OVERFLOW_UN(a,b) \
1665 (guint32)(a) < (guint32)(b) ? -1 : 0
1667 #define CHECK_ADD_OVERFLOW64(a,b) \
1668 (gint64)(b) >= 0 ? (gint64)(G_MAXINT64) - (gint64)(b) < (gint64)(a) ? -1 : 0 \
1669 : (gint64)(G_MININT64) - (gint64)(b) > (gint64)(a) ? +1 : 0
1671 #define CHECK_SUB_OVERFLOW64(a,b) \
1672 (gint64)(b) < 0 ? (gint64)(G_MAXINT64) + (gint64)(b) < (gint64)(a) ? -1 : 0 \
1673 : (gint64)(G_MININT64) + (gint64)(b) > (gint64)(a) ? +1 : 0
1675 #define CHECK_ADD_OVERFLOW64_UN(a,b) \
1676 (guint64)(G_MAXUINT64) - (guint64)(b) < (guint64)(a) ? -1 : 0
1678 #define CHECK_SUB_OVERFLOW64_UN(a,b) \
1679 (guint64)(a) < (guint64)(b) ? -1 : 0
1681 #if SIZEOF_VOID_P == 4
1682 #define CHECK_ADD_OVERFLOW_NAT(a,b) CHECK_ADD_OVERFLOW(a,b)
1683 #define CHECK_ADD_OVERFLOW_NAT_UN(a,b) CHECK_ADD_OVERFLOW_UN(a,b)
1684 #else
1685 #define CHECK_ADD_OVERFLOW_NAT(a,b) CHECK_ADD_OVERFLOW64(a,b)
1686 #define CHECK_ADD_OVERFLOW_NAT_UN(a,b) CHECK_ADD_OVERFLOW64_UN(a,b)
1687 #endif
1689 /* Resolves to TRUE if the operands would overflow */
1690 #define CHECK_MUL_OVERFLOW(a,b) \
1691 ((gint32)(a) == 0) || ((gint32)(b) == 0) ? 0 : \
1692 (((gint32)(a) > 0) && ((gint32)(b) == -1)) ? FALSE : \
1693 (((gint32)(a) < 0) && ((gint32)(b) == -1)) ? (a == G_MININT32) : \
1694 (((gint32)(a) > 0) && ((gint32)(b) > 0)) ? (gint32)(a) > ((G_MAXINT32) / (gint32)(b)) : \
1695 (((gint32)(a) > 0) && ((gint32)(b) < 0)) ? (gint32)(a) > ((G_MININT32) / (gint32)(b)) : \
1696 (((gint32)(a) < 0) && ((gint32)(b) > 0)) ? (gint32)(a) < ((G_MININT32) / (gint32)(b)) : \
1697 (gint32)(a) < ((G_MAXINT32) / (gint32)(b))
1699 #define CHECK_MUL_OVERFLOW_UN(a,b) \
1700 ((guint32)(a) == 0) || ((guint32)(b) == 0) ? 0 : \
1701 (guint32)(b) > ((G_MAXUINT32) / (guint32)(a))
1703 #define CHECK_MUL_OVERFLOW64(a,b) \
1704 ((gint64)(a) == 0) || ((gint64)(b) == 0) ? 0 : \
1705 (((gint64)(a) > 0) && ((gint64)(b) == -1)) ? FALSE : \
1706 (((gint64)(a) < 0) && ((gint64)(b) == -1)) ? (a == G_MININT64) : \
1707 (((gint64)(a) > 0) && ((gint64)(b) > 0)) ? (gint64)(a) > ((G_MAXINT64) / (gint64)(b)) : \
1708 (((gint64)(a) > 0) && ((gint64)(b) < 0)) ? (gint64)(a) > ((G_MININT64) / (gint64)(b)) : \
1709 (((gint64)(a) < 0) && ((gint64)(b) > 0)) ? (gint64)(a) < ((G_MININT64) / (gint64)(b)) : \
1710 (gint64)(a) < ((G_MAXINT64) / (gint64)(b))
1712 #define CHECK_MUL_OVERFLOW64_UN(a,b) \
1713 ((guint64)(a) == 0) || ((guint64)(b) == 0) ? 0 : \
1714 (guint64)(b) > ((G_MAXUINT64) / (guint64)(a))
1716 #if SIZEOF_VOID_P == 4
1717 #define CHECK_MUL_OVERFLOW_NAT(a,b) CHECK_MUL_OVERFLOW(a,b)
1718 #define CHECK_MUL_OVERFLOW_NAT_UN(a,b) CHECK_MUL_OVERFLOW_UN(a,b)
1719 #else
1720 #define CHECK_MUL_OVERFLOW_NAT(a,b) CHECK_MUL_OVERFLOW64(a,b)
1721 #define CHECK_MUL_OVERFLOW_NAT_UN(a,b) CHECK_MUL_OVERFLOW64_UN(a,b)
1722 #endif
1724 static MonoObject*
1725 interp_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError *error)
1727 InterpFrame frame;
1728 ThreadContext *context = get_context ();
1729 MonoMethodSignature *sig = mono_method_signature_internal (method);
1730 MonoClass *klass = mono_class_from_mono_type_internal (sig->ret);
1731 stackval result;
1732 MonoMethod *target_method = method;
1734 error_init (error);
1735 if (exc)
1736 *exc = NULL;
1738 frame.ex = NULL;
1740 MonoDomain *domain = mono_domain_get ();
1742 if (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
1743 target_method = mono_marshal_get_native_wrapper (target_method, FALSE, FALSE);
1744 MonoMethod *invoke_wrapper = mono_marshal_get_runtime_invoke_full (target_method, FALSE, TRUE);
1746 //* <code>MonoObject *runtime_invoke (MonoObject *this_obj, void **params, MonoObject **exc, void* method)</code>
1748 result.data.vt = alloca (mono_class_instance_size (klass));
1749 stackval args [4];
1751 if (sig->hasthis)
1752 args [0].data.p = obj;
1753 else
1754 args [0].data.p = NULL;
1755 args [1].data.p = params;
1756 args [2].data.p = exc;
1757 args [3].data.p = target_method;
1759 InterpMethod *imethod = mono_interp_get_imethod (domain, invoke_wrapper, error);
1760 mono_error_assert_ok (error);
1761 init_frame (&frame, NULL, imethod, args, &result);
1763 interp_exec_method (&frame, context, error);
1765 if (frame.ex) {
1766 if (exc) {
1767 *exc = (MonoObject*) frame.ex;
1768 return NULL;
1770 mono_error_set_exception_instance (error, frame.ex);
1771 return NULL;
1773 return (MonoObject*)result.data.p;
1776 typedef struct {
1777 InterpMethod *rmethod;
1778 gpointer this_arg;
1779 gpointer res;
1780 gpointer args [16];
1781 gpointer *many_args;
1782 } InterpEntryData;
1784 /* Main function for entering the interpreter from compiled code */
1785 static void
1786 interp_entry (InterpEntryData *data)
1788 InterpFrame frame;
1789 InterpMethod *rmethod;
1790 ThreadContext *context;
1791 stackval result;
1792 stackval *args;
1793 MonoMethod *method;
1794 MonoMethodSignature *sig;
1795 MonoType *type;
1796 gpointer orig_domain = NULL, attach_cookie;
1797 int i;
1799 if ((gsize)data->rmethod & 1) {
1800 /* Unbox */
1801 data->this_arg = mono_object_unbox_internal ((MonoObject*)data->this_arg);
1802 data->rmethod = (InterpMethod*)(gpointer)((gsize)data->rmethod & ~1);
1804 rmethod = data->rmethod;
1806 if (rmethod->needs_thread_attach)
1807 orig_domain = mono_threads_attach_coop (mono_domain_get (), &attach_cookie);
1809 context = get_context ();
1811 method = rmethod->method;
1812 sig = mono_method_signature_internal (method);
1814 // FIXME: Optimize this
1816 //printf ("%s\n", mono_method_full_name (method, 1));
1818 frame.ex = NULL;
1820 args = g_newa (stackval, sig->param_count + (sig->hasthis ? 1 : 0));
1821 if (sig->hasthis)
1822 args [0].data.p = data->this_arg;
1824 gpointer *params;
1825 if (data->many_args)
1826 params = data->many_args;
1827 else
1828 params = data->args;
1829 for (i = 0; i < sig->param_count; ++i) {
1830 int a_index = i + (sig->hasthis ? 1 : 0);
1831 if (sig->params [i]->byref) {
1832 args [a_index].data.p = params [i];
1833 continue;
1835 type = rmethod->param_types [i];
1836 switch (type->type) {
1837 case MONO_TYPE_VALUETYPE:
1838 args [a_index].data.p = params [i];
1839 break;
1840 case MONO_TYPE_GENERICINST:
1841 if (MONO_TYPE_IS_REFERENCE (type))
1842 args [a_index].data.p = *(gpointer*)params [i];
1843 else
1844 args [a_index].data.vt = params [i];
1845 break;
1846 default:
1847 stackval_from_data (type, &args [a_index], params [i], FALSE);
1848 break;
1852 memset (&result, 0, sizeof (result));
1853 init_frame (&frame, NULL, data->rmethod, args, &result);
1855 type = rmethod->rtype;
1856 switch (type->type) {
1857 case MONO_TYPE_GENERICINST:
1858 if (!MONO_TYPE_IS_REFERENCE (type))
1859 frame.retval->data.vt = data->res;
1860 break;
1861 case MONO_TYPE_VALUETYPE:
1862 frame.retval->data.vt = data->res;
1863 break;
1864 default:
1865 break;
1868 ERROR_DECL (error);
1869 interp_exec_method (&frame, context, error);
1871 if (rmethod->needs_thread_attach)
1872 mono_threads_detach_coop (orig_domain, &attach_cookie);
1874 if (mono_llvm_only) {
1875 if (frame.ex)
1876 mono_llvm_reraise_exception (frame.ex);
1877 } else {
1878 g_assert (frame.ex == NULL);
1881 type = rmethod->rtype;
1882 switch (type->type) {
1883 case MONO_TYPE_VOID:
1884 break;
1885 case MONO_TYPE_OBJECT:
1886 /* No need for a write barrier */
1887 *(MonoObject**)data->res = (MonoObject*)frame.retval->data.p;
1888 break;
1889 case MONO_TYPE_GENERICINST:
1890 if (MONO_TYPE_IS_REFERENCE (type)) {
1891 *(MonoObject**)data->res = (MonoObject*)frame.retval->data.p;
1892 } else {
1893 /* Already set before the call */
1895 break;
1896 case MONO_TYPE_VALUETYPE:
1897 /* Already set before the call */
1898 break;
1899 default:
1900 stackval_to_data (type, frame.retval, data->res, FALSE);
1901 break;
1905 static stackval *
1906 do_icall (InterpFrame *frame, MonoMethodSignature *sig, int op, stackval *sp, gpointer ptr, gboolean save_last_error)
1908 #ifdef ENABLE_NETCORE
1909 if (save_last_error)
1910 mono_marshal_clear_last_error ();
1911 #endif
1913 switch (op) {
1914 case MINT_ICALL_V_V: {
1915 typedef void (*T)(void);
1916 T func = (T)ptr;
1917 func ();
1918 break;
1920 case MINT_ICALL_V_P: {
1921 typedef gpointer (*T)(void);
1922 T func = (T)ptr;
1923 sp++;
1924 sp [-1].data.p = func ();
1925 break;
1927 case MINT_ICALL_P_V: {
1928 typedef void (*T)(gpointer);
1929 T func = (T)ptr;
1930 func (sp [-1].data.p);
1931 sp --;
1932 break;
1934 case MINT_ICALL_P_P: {
1935 typedef gpointer (*T)(gpointer);
1936 T func = (T)ptr;
1937 sp [-1].data.p = func (sp [-1].data.p);
1938 break;
1940 case MINT_ICALL_PP_V: {
1941 typedef void (*T)(gpointer,gpointer);
1942 T func = (T)ptr;
1943 sp -= 2;
1944 func (sp [0].data.p, sp [1].data.p);
1945 break;
1947 case MINT_ICALL_PP_P: {
1948 typedef gpointer (*T)(gpointer,gpointer);
1949 T func = (T)ptr;
1950 --sp;
1951 sp [-1].data.p = func (sp [-1].data.p, sp [0].data.p);
1952 break;
1954 case MINT_ICALL_PPP_V: {
1955 typedef void (*T)(gpointer,gpointer,gpointer);
1956 T func = (T)ptr;
1957 sp -= 3;
1958 func (sp [0].data.p, sp [1].data.p, sp [2].data.p);
1959 break;
1961 case MINT_ICALL_PPP_P: {
1962 typedef gpointer (*T)(gpointer,gpointer,gpointer);
1963 T func = (T)ptr;
1964 sp -= 2;
1965 sp [-1].data.p = func (sp [-1].data.p, sp [0].data.p, sp [1].data.p);
1966 break;
1968 case MINT_ICALL_PPPP_V: {
1969 typedef void (*T)(gpointer,gpointer,gpointer,gpointer);
1970 T func = (T)ptr;
1971 sp -= 4;
1972 func (sp [0].data.p, sp [1].data.p, sp [2].data.p, sp [3].data.p);
1973 break;
1975 case MINT_ICALL_PPPP_P: {
1976 typedef gpointer (*T)(gpointer,gpointer,gpointer,gpointer);
1977 T func = (T)ptr;
1978 sp -= 3;
1979 sp [-1].data.p = func (sp [-1].data.p, sp [0].data.p, sp [1].data.p, sp [2].data.p);
1980 break;
1982 case MINT_ICALL_PPPPP_V: {
1983 typedef void (*T)(gpointer,gpointer,gpointer,gpointer,gpointer);
1984 T func = (T)ptr;
1985 sp -= 5;
1986 func (sp [0].data.p, sp [1].data.p, sp [2].data.p, sp [3].data.p, sp [4].data.p);
1987 break;
1989 case MINT_ICALL_PPPPP_P: {
1990 typedef gpointer (*T)(gpointer,gpointer,gpointer,gpointer,gpointer);
1991 T func = (T)ptr;
1992 sp -= 4;
1993 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);
1994 break;
1996 case MINT_ICALL_PPPPPP_V: {
1997 typedef void (*T)(gpointer,gpointer,gpointer,gpointer,gpointer,gpointer);
1998 T func = (T)ptr;
1999 sp -= 6;
2000 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);
2001 break;
2003 case MINT_ICALL_PPPPPP_P: {
2004 typedef gpointer (*T)(gpointer,gpointer,gpointer,gpointer,gpointer,gpointer);
2005 T func = (T)ptr;
2006 sp -= 5;
2007 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);
2008 break;
2010 default:
2011 g_assert_not_reached ();
2014 if (save_last_error)
2015 mono_marshal_set_last_error ();
2017 /* convert the native representation to the stackval representation */
2018 if (sig)
2019 stackval_from_data (sig->ret, &sp [-1], (char*) &sp [-1].data.p, sig->pinvoke);
2021 return sp;
2024 /* MONO_NO_OPTIMIATION is needed due to usage of INTERP_PUSH_LMF_WITH_CTX. */
2025 #ifdef _MSC_VER
2026 #pragma optimize ("", off)
2027 #endif
2028 static MONO_NO_OPTIMIZATION MONO_NEVER_INLINE stackval *
2029 do_icall_wrapper (InterpFrame *frame, MonoMethodSignature *sig, int op, stackval *sp, gpointer ptr, gboolean save_last_error)
2031 MonoLMFExt ext;
2032 INTERP_PUSH_LMF_WITH_CTX (frame, ext, exit_icall);
2034 sp = do_icall (frame, sig, op, sp, ptr, save_last_error);
2036 interp_pop_lmf (&ext);
2038 goto exit_icall; // prevent unused label warning in some configurations
2039 exit_icall:
2040 return sp;
2042 #ifdef _MSC_VER
2043 #pragma optimize ("", on)
2044 #endif
2046 typedef struct {
2047 int pindex;
2048 gpointer jit_wrapper;
2049 gpointer *args;
2050 MonoFtnDesc *ftndesc;
2051 } JitCallCbData;
2053 static void
2054 jit_call_cb (gpointer arg)
2056 JitCallCbData *cb_data = (JitCallCbData*)arg;
2057 gpointer jit_wrapper = cb_data->jit_wrapper;
2058 int pindex = cb_data->pindex;
2059 gpointer *args = cb_data->args;
2060 MonoFtnDesc ftndesc = *cb_data->ftndesc;
2062 switch (pindex) {
2063 case 0: {
2064 typedef void (*T)(gpointer);
2065 T func = (T)jit_wrapper;
2067 func (&ftndesc);
2068 break;
2070 case 1: {
2071 typedef void (*T)(gpointer, gpointer);
2072 T func = (T)jit_wrapper;
2074 func (args [0], &ftndesc);
2075 break;
2077 case 2: {
2078 typedef void (*T)(gpointer, gpointer, gpointer);
2079 T func = (T)jit_wrapper;
2081 func (args [0], args [1], &ftndesc);
2082 break;
2084 case 3: {
2085 typedef void (*T)(gpointer, gpointer, gpointer, gpointer);
2086 T func = (T)jit_wrapper;
2088 func (args [0], args [1], args [2], &ftndesc);
2089 break;
2091 case 4: {
2092 typedef void (*T)(gpointer, gpointer, gpointer, gpointer, gpointer);
2093 T func = (T)jit_wrapper;
2095 func (args [0], args [1], args [2], args [3], &ftndesc);
2096 break;
2098 case 5: {
2099 typedef void (*T)(gpointer, gpointer, gpointer, gpointer, gpointer, gpointer);
2100 T func = (T)jit_wrapper;
2102 func (args [0], args [1], args [2], args [3], args [4], &ftndesc);
2103 break;
2105 case 6: {
2106 typedef void (*T)(gpointer, gpointer, gpointer, gpointer, gpointer, gpointer, gpointer);
2107 T func = (T)jit_wrapper;
2109 func (args [0], args [1], args [2], args [3], args [4], args [5], &ftndesc);
2110 break;
2112 case 7: {
2113 typedef void (*T)(gpointer, gpointer, gpointer, gpointer, gpointer, gpointer, gpointer, gpointer);
2114 T func = (T)jit_wrapper;
2116 func (args [0], args [1], args [2], args [3], args [4], args [5], args [6], &ftndesc);
2117 break;
2119 case 8: {
2120 typedef void (*T)(gpointer, gpointer, gpointer, gpointer, gpointer, gpointer, gpointer, gpointer, gpointer);
2121 T func = (T)jit_wrapper;
2123 func (args [0], args [1], args [2], args [3], args [4], args [5], args [6], args [7], &ftndesc);
2124 break;
2126 default:
2127 g_assert_not_reached ();
2128 break;
2132 static MONO_NEVER_INLINE stackval *
2133 do_jit_call (stackval *sp, unsigned char *vt_sp, ThreadContext *context, InterpFrame *frame, InterpMethod *rmethod, MonoError *error)
2135 MonoMethodSignature *sig;
2136 MonoFtnDesc ftndesc;
2137 guint8 res_buf [256];
2138 MonoType *type;
2139 MonoLMFExt ext;
2141 //printf ("jit_call: %s\n", mono_method_full_name (rmethod->method, 1));
2144 * Call JITted code through a gsharedvt_out wrapper. These wrappers receive every argument
2145 * by ref and return a return value using an explicit return value argument.
2147 if (!rmethod->jit_wrapper) {
2148 MonoMethod *method = rmethod->method;
2150 sig = mono_method_signature_internal (method);
2151 g_assert (sig);
2153 MonoMethod *wrapper = mini_get_gsharedvt_out_sig_wrapper (sig);
2154 //printf ("J: %s %s\n", mono_method_full_name (method, 1), mono_method_full_name (wrapper, 1));
2156 gpointer jit_wrapper = mono_jit_compile_method_jit_only (wrapper, error);
2157 mono_error_assert_ok (error);
2159 gpointer addr = mono_jit_compile_method_jit_only (method, error);
2160 return_val_if_nok (error, NULL);
2161 g_assert (addr);
2163 rmethod->jit_addr = addr;
2164 rmethod->jit_sig = sig;
2165 mono_memory_barrier ();
2166 rmethod->jit_wrapper = jit_wrapper;
2168 } else {
2169 sig = rmethod->jit_sig;
2172 sp -= sig->param_count;
2173 if (sig->hasthis)
2174 --sp;
2176 ftndesc.addr = rmethod->jit_addr;
2177 ftndesc.arg = NULL;
2179 // FIXME: Optimize this
2181 gpointer args [32];
2182 int pindex = 0;
2183 int stack_index = 0;
2184 if (rmethod->hasthis) {
2185 args [pindex ++] = sp [0].data.p;
2186 stack_index ++;
2188 type = rmethod->rtype;
2189 if (type->type != MONO_TYPE_VOID) {
2190 if (MONO_TYPE_ISSTRUCT (type))
2191 args [pindex ++] = vt_sp;
2192 else
2193 args [pindex ++] = res_buf;
2195 for (int i = 0; i < rmethod->param_count; ++i) {
2196 MonoType *t = rmethod->param_types [i];
2197 stackval *sval = &sp [stack_index + i];
2198 if (sig->params [i]->byref) {
2199 args [pindex ++] = sval->data.p;
2200 } else if (MONO_TYPE_ISSTRUCT (t)) {
2201 args [pindex ++] = sval->data.p;
2202 } else if (MONO_TYPE_IS_REFERENCE (t)) {
2203 args [pindex ++] = &sval->data.p;
2204 } else {
2205 switch (t->type) {
2206 case MONO_TYPE_I1:
2207 case MONO_TYPE_U1:
2208 case MONO_TYPE_I2:
2209 case MONO_TYPE_U2:
2210 case MONO_TYPE_I4:
2211 case MONO_TYPE_U4:
2212 case MONO_TYPE_VALUETYPE:
2213 args [pindex ++] = &sval->data.i;
2214 break;
2215 case MONO_TYPE_PTR:
2216 case MONO_TYPE_FNPTR:
2217 case MONO_TYPE_I:
2218 case MONO_TYPE_U:
2219 case MONO_TYPE_OBJECT:
2220 args [pindex ++] = &sval->data.p;
2221 break;
2222 case MONO_TYPE_I8:
2223 case MONO_TYPE_U8:
2224 args [pindex ++] = &sval->data.l;
2225 break;
2226 case MONO_TYPE_R4:
2227 args [pindex ++] = &sval->data.f_r4;
2228 break;
2229 case MONO_TYPE_R8:
2230 args [pindex ++] = &sval->data.f;
2231 break;
2232 default:
2233 printf ("%s\n", mono_type_full_name (t));
2234 g_assert_not_reached ();
2239 interp_push_lmf (&ext, frame);
2241 JitCallCbData cb_data;
2242 memset (&cb_data, 0, sizeof (cb_data));
2243 cb_data.jit_wrapper = rmethod->jit_wrapper;
2244 cb_data.pindex = pindex;
2245 cb_data.args = args;
2246 cb_data.ftndesc = &ftndesc;
2248 if (mono_aot_mode == MONO_AOT_MODE_LLVMONLY_INTERP) {
2249 /* Catch the exception thrown by the native code using a try-catch */
2250 gboolean thrown = FALSE;
2251 mono_llvm_cpp_catch_exception (jit_call_cb, &cb_data, &thrown);
2252 interp_pop_lmf (&ext);
2253 if (thrown) {
2254 MonoObject *obj = mono_llvm_load_exception ();
2255 g_assert (obj);
2256 mono_error_set_exception_instance (error, (MonoException*)obj);
2257 return sp;
2259 } else {
2260 jit_call_cb (&cb_data);
2261 interp_pop_lmf (&ext);
2264 MonoType *rtype = rmethod->rtype;
2265 switch (rtype->type) {
2266 case MONO_TYPE_VOID:
2267 case MONO_TYPE_OBJECT:
2268 case MONO_TYPE_STRING:
2269 case MONO_TYPE_CLASS:
2270 case MONO_TYPE_ARRAY:
2271 case MONO_TYPE_SZARRAY:
2272 case MONO_TYPE_I:
2273 case MONO_TYPE_U:
2274 case MONO_TYPE_PTR:
2275 sp->data.p = *(gpointer*)res_buf;
2276 break;
2277 case MONO_TYPE_I1:
2278 sp->data.i = *(gint8*)res_buf;
2279 break;
2280 case MONO_TYPE_U1:
2281 sp->data.i = *(guint8*)res_buf;
2282 break;
2283 case MONO_TYPE_I2:
2284 sp->data.i = *(gint16*)res_buf;
2285 break;
2286 case MONO_TYPE_U2:
2287 sp->data.i = *(guint16*)res_buf;
2288 break;
2289 case MONO_TYPE_I4:
2290 sp->data.i = *(gint32*)res_buf;
2291 break;
2292 case MONO_TYPE_U4:
2293 sp->data.i = *(guint32*)res_buf;
2294 break;
2295 case MONO_TYPE_I8:
2296 sp->data.l = *(gint64*)res_buf;
2297 break;
2298 case MONO_TYPE_U8:
2299 sp->data.l = *(guint64*)res_buf;
2300 break;
2301 case MONO_TYPE_R4:
2302 sp->data.f_r4 = *(float*)res_buf;
2303 break;
2304 case MONO_TYPE_R8:
2305 sp->data.f = *(double*)res_buf;
2306 break;
2307 case MONO_TYPE_TYPEDBYREF:
2308 case MONO_TYPE_VALUETYPE:
2309 /* The result was written to vt_sp */
2310 sp->data.p = vt_sp;
2311 break;
2312 case MONO_TYPE_GENERICINST:
2313 if (MONO_TYPE_IS_REFERENCE (rtype)) {
2314 sp->data.p = *(gpointer*)res_buf;
2315 } else {
2316 /* The result was written to vt_sp */
2317 sp->data.p = vt_sp;
2319 break;
2320 default:
2321 g_print ("%s\n", mono_type_full_name (rtype));
2322 g_assert_not_reached ();
2323 break;
2326 return sp;
2329 static MONO_NEVER_INLINE void
2330 do_debugger_tramp (void (*tramp) (void), InterpFrame *frame)
2332 MonoLMFExt ext;
2333 interp_push_lmf (&ext, frame);
2334 tramp ();
2335 interp_pop_lmf (&ext);
2338 static MONO_NEVER_INLINE void
2339 do_transform_method (InterpFrame *frame, ThreadContext *context)
2341 MonoLMFExt ext;
2342 /* Don't push lmf if we have no interp data */
2343 gboolean push_lmf = frame->parent != NULL;
2344 ERROR_DECL (error);
2346 /* Use the parent frame as the current frame is not complete yet */
2347 if (push_lmf)
2348 interp_push_lmf (&ext, frame->parent);
2350 mono_interp_transform_method (frame->imethod, context, error);
2351 frame->ex = mono_error_convert_to_exception (error);
2353 if (push_lmf)
2354 interp_pop_lmf (&ext);
2357 static MONO_NEVER_INLINE guchar*
2358 copy_varargs_vtstack (MonoMethodSignature *csig, stackval *sp, guchar *vt_sp_start)
2360 stackval *first_arg = sp - csig->param_count;
2361 guchar *vt_sp = vt_sp_start;
2364 * We need to have the varargs linearly on the stack so the ArgIterator
2365 * can iterate over them. We pass the signature first and then copy them
2366 * one by one on the vtstack. At the end we pass the original vt_stack
2367 * so the callee (MINT_ARGLIST) can find the varargs space.
2369 *(gpointer*)vt_sp = csig;
2370 vt_sp += sizeof (gpointer);
2372 for (int i = csig->sentinelpos; i < csig->param_count; i++) {
2373 int align, arg_size;
2374 arg_size = mono_type_stack_size (csig->params [i], &align);
2375 vt_sp = (guchar*)ALIGN_PTR_TO (vt_sp, align);
2377 stackval_to_data (csig->params [i], &first_arg [i], vt_sp, FALSE);
2378 vt_sp += arg_size;
2381 vt_sp += sizeof (gpointer);
2382 vt_sp = (guchar*)ALIGN_PTR_TO (vt_sp, MINT_VT_ALIGNMENT);
2384 ((gpointer*)vt_sp) [-1] = vt_sp_start;
2386 return vt_sp;
2390 * These functions are the entry points into the interpreter from compiled code.
2391 * They are called by the interp_in wrappers. They have the following signature:
2392 * void (<optional this_arg>, <optional retval pointer>, <arg1>, ..., <argn>, <method ptr>)
2393 * They pack up their arguments into an InterpEntryData structure and call interp_entry ().
2394 * It would be possible for the wrappers to pack up the arguments etc, but that would make them bigger, and there are
2395 * more wrappers then these functions.
2396 * this/static * ret/void * 16 arguments -> 64 functions.
2399 #define MAX_INTERP_ENTRY_ARGS 8
2401 #define INTERP_ENTRY_BASE(_method, _this_arg, _res) \
2402 InterpEntryData data; \
2403 (data).rmethod = (_method); \
2404 (data).res = (_res); \
2405 (data).this_arg = (_this_arg); \
2406 (data).many_args = NULL;
2408 #define INTERP_ENTRY0(_this_arg, _res, _method) { \
2409 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2410 interp_entry (&data); \
2412 #define INTERP_ENTRY1(_this_arg, _res, _method) { \
2413 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2414 (data).args [0] = arg1; \
2415 interp_entry (&data); \
2417 #define INTERP_ENTRY2(_this_arg, _res, _method) { \
2418 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2419 (data).args [0] = arg1; \
2420 (data).args [1] = arg2; \
2421 interp_entry (&data); \
2423 #define INTERP_ENTRY3(_this_arg, _res, _method) { \
2424 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2425 (data).args [0] = arg1; \
2426 (data).args [1] = arg2; \
2427 (data).args [2] = arg3; \
2428 interp_entry (&data); \
2430 #define INTERP_ENTRY4(_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 interp_entry (&data); \
2438 #define INTERP_ENTRY5(_this_arg, _res, _method) { \
2439 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2440 (data).args [0] = arg1; \
2441 (data).args [1] = arg2; \
2442 (data).args [2] = arg3; \
2443 (data).args [3] = arg4; \
2444 (data).args [4] = arg5; \
2445 interp_entry (&data); \
2447 #define INTERP_ENTRY6(_this_arg, _res, _method) { \
2448 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2449 (data).args [0] = arg1; \
2450 (data).args [1] = arg2; \
2451 (data).args [2] = arg3; \
2452 (data).args [3] = arg4; \
2453 (data).args [4] = arg5; \
2454 (data).args [5] = arg6; \
2455 interp_entry (&data); \
2457 #define INTERP_ENTRY7(_this_arg, _res, _method) { \
2458 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2459 (data).args [0] = arg1; \
2460 (data).args [1] = arg2; \
2461 (data).args [2] = arg3; \
2462 (data).args [3] = arg4; \
2463 (data).args [4] = arg5; \
2464 (data).args [5] = arg6; \
2465 (data).args [6] = arg7; \
2466 interp_entry (&data); \
2468 #define INTERP_ENTRY8(_this_arg, _res, _method) { \
2469 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2470 (data).args [0] = arg1; \
2471 (data).args [1] = arg2; \
2472 (data).args [2] = arg3; \
2473 (data).args [3] = arg4; \
2474 (data).args [4] = arg5; \
2475 (data).args [5] = arg6; \
2476 (data).args [6] = arg7; \
2477 (data).args [7] = arg8; \
2478 interp_entry (&data); \
2481 #define ARGLIST0 InterpMethod *rmethod
2482 #define ARGLIST1 gpointer arg1, InterpMethod *rmethod
2483 #define ARGLIST2 gpointer arg1, gpointer arg2, InterpMethod *rmethod
2484 #define ARGLIST3 gpointer arg1, gpointer arg2, gpointer arg3, InterpMethod *rmethod
2485 #define ARGLIST4 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, InterpMethod *rmethod
2486 #define ARGLIST5 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, gpointer arg5, InterpMethod *rmethod
2487 #define ARGLIST6 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, gpointer arg5, gpointer arg6, InterpMethod *rmethod
2488 #define ARGLIST7 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, gpointer arg5, gpointer arg6, gpointer arg7, InterpMethod *rmethod
2489 #define ARGLIST8 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, gpointer arg5, gpointer arg6, gpointer arg7, gpointer arg8, InterpMethod *rmethod
2491 static void interp_entry_static_0 (ARGLIST0) INTERP_ENTRY0 (NULL, NULL, rmethod)
2492 static void interp_entry_static_1 (ARGLIST1) INTERP_ENTRY1 (NULL, NULL, rmethod)
2493 static void interp_entry_static_2 (ARGLIST2) INTERP_ENTRY2 (NULL, NULL, rmethod)
2494 static void interp_entry_static_3 (ARGLIST3) INTERP_ENTRY3 (NULL, NULL, rmethod)
2495 static void interp_entry_static_4 (ARGLIST4) INTERP_ENTRY4 (NULL, NULL, rmethod)
2496 static void interp_entry_static_5 (ARGLIST5) INTERP_ENTRY5 (NULL, NULL, rmethod)
2497 static void interp_entry_static_6 (ARGLIST6) INTERP_ENTRY6 (NULL, NULL, rmethod)
2498 static void interp_entry_static_7 (ARGLIST7) INTERP_ENTRY7 (NULL, NULL, rmethod)
2499 static void interp_entry_static_8 (ARGLIST8) INTERP_ENTRY8 (NULL, NULL, rmethod)
2500 static void interp_entry_static_ret_0 (gpointer res, ARGLIST0) INTERP_ENTRY0 (NULL, res, rmethod)
2501 static void interp_entry_static_ret_1 (gpointer res, ARGLIST1) INTERP_ENTRY1 (NULL, res, rmethod)
2502 static void interp_entry_static_ret_2 (gpointer res, ARGLIST2) INTERP_ENTRY2 (NULL, res, rmethod)
2503 static void interp_entry_static_ret_3 (gpointer res, ARGLIST3) INTERP_ENTRY3 (NULL, res, rmethod)
2504 static void interp_entry_static_ret_4 (gpointer res, ARGLIST4) INTERP_ENTRY4 (NULL, res, rmethod)
2505 static void interp_entry_static_ret_5 (gpointer res, ARGLIST5) INTERP_ENTRY5 (NULL, res, rmethod)
2506 static void interp_entry_static_ret_6 (gpointer res, ARGLIST6) INTERP_ENTRY6 (NULL, res, rmethod)
2507 static void interp_entry_static_ret_7 (gpointer res, ARGLIST7) INTERP_ENTRY7 (NULL, res, rmethod)
2508 static void interp_entry_static_ret_8 (gpointer res, ARGLIST8) INTERP_ENTRY8 (NULL, res, rmethod)
2509 static void interp_entry_instance_0 (gpointer this_arg, ARGLIST0) INTERP_ENTRY0 (this_arg, NULL, rmethod)
2510 static void interp_entry_instance_1 (gpointer this_arg, ARGLIST1) INTERP_ENTRY1 (this_arg, NULL, rmethod)
2511 static void interp_entry_instance_2 (gpointer this_arg, ARGLIST2) INTERP_ENTRY2 (this_arg, NULL, rmethod)
2512 static void interp_entry_instance_3 (gpointer this_arg, ARGLIST3) INTERP_ENTRY3 (this_arg, NULL, rmethod)
2513 static void interp_entry_instance_4 (gpointer this_arg, ARGLIST4) INTERP_ENTRY4 (this_arg, NULL, rmethod)
2514 static void interp_entry_instance_5 (gpointer this_arg, ARGLIST5) INTERP_ENTRY5 (this_arg, NULL, rmethod)
2515 static void interp_entry_instance_6 (gpointer this_arg, ARGLIST6) INTERP_ENTRY6 (this_arg, NULL, rmethod)
2516 static void interp_entry_instance_7 (gpointer this_arg, ARGLIST7) INTERP_ENTRY7 (this_arg, NULL, rmethod)
2517 static void interp_entry_instance_8 (gpointer this_arg, ARGLIST8) INTERP_ENTRY8 (this_arg, NULL, rmethod)
2518 static void interp_entry_instance_ret_0 (gpointer this_arg, gpointer res, ARGLIST0) INTERP_ENTRY0 (this_arg, res, rmethod)
2519 static void interp_entry_instance_ret_1 (gpointer this_arg, gpointer res, ARGLIST1) INTERP_ENTRY1 (this_arg, res, rmethod)
2520 static void interp_entry_instance_ret_2 (gpointer this_arg, gpointer res, ARGLIST2) INTERP_ENTRY2 (this_arg, res, rmethod)
2521 static void interp_entry_instance_ret_3 (gpointer this_arg, gpointer res, ARGLIST3) INTERP_ENTRY3 (this_arg, res, rmethod)
2522 static void interp_entry_instance_ret_4 (gpointer this_arg, gpointer res, ARGLIST4) INTERP_ENTRY4 (this_arg, res, rmethod)
2523 static void interp_entry_instance_ret_5 (gpointer this_arg, gpointer res, ARGLIST5) INTERP_ENTRY5 (this_arg, res, rmethod)
2524 static void interp_entry_instance_ret_6 (gpointer this_arg, gpointer res, ARGLIST6) INTERP_ENTRY6 (this_arg, res, rmethod)
2525 static void interp_entry_instance_ret_7 (gpointer this_arg, gpointer res, ARGLIST7) INTERP_ENTRY7 (this_arg, res, rmethod)
2526 static void interp_entry_instance_ret_8 (gpointer this_arg, gpointer res, ARGLIST8) INTERP_ENTRY8 (this_arg, res, rmethod)
2528 #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
2530 static gpointer entry_funcs_static [MAX_INTERP_ENTRY_ARGS + 1] = { INTERP_ENTRY_FUNCLIST (static) };
2531 static gpointer entry_funcs_static_ret [MAX_INTERP_ENTRY_ARGS + 1] = { INTERP_ENTRY_FUNCLIST (static_ret) };
2532 static gpointer entry_funcs_instance [MAX_INTERP_ENTRY_ARGS + 1] = { INTERP_ENTRY_FUNCLIST (instance) };
2533 static gpointer entry_funcs_instance_ret [MAX_INTERP_ENTRY_ARGS + 1] = { INTERP_ENTRY_FUNCLIST (instance_ret) };
2535 /* General version for methods with more than MAX_INTERP_ENTRY_ARGS arguments */
2536 static void
2537 interp_entry_general (gpointer this_arg, gpointer res, gpointer *args, gpointer rmethod)
2539 INTERP_ENTRY_BASE ((InterpMethod*)rmethod, this_arg, res);
2540 data.many_args = args;
2541 interp_entry (&data);
2544 #ifdef MONO_ARCH_HAVE_INTERP_ENTRY_TRAMPOLINE
2546 // inline so we can alloc on stack
2547 #define alloc_storage_for_stackval(s, t, p) do { \
2548 if ((t)->type == MONO_TYPE_GENERICINST && !MONO_TYPE_IS_REFERENCE (t)) { \
2549 (s)->data.vt = alloca (mono_class_value_size (mono_class_from_mono_type_internal (t), NULL)); \
2550 } else if ((t)->type == MONO_TYPE_VALUETYPE) { \
2551 if (p) \
2552 (s)->data.vt = alloca (mono_class_native_size ((t)->data.klass, NULL)); \
2553 else \
2554 (s)->data.vt = alloca (mono_class_value_size ((t)->data.klass, NULL)); \
2556 } while (0)
2558 static void
2559 interp_entry_from_trampoline (gpointer ccontext_untyped, gpointer rmethod_untyped)
2561 InterpFrame frame;
2562 ThreadContext *context;
2563 stackval result;
2564 stackval *args;
2565 MonoMethod *method;
2566 MonoMethodSignature *sig;
2567 CallContext *ccontext = (CallContext*) ccontext_untyped;
2568 InterpMethod *rmethod = (InterpMethod*) rmethod_untyped;
2569 gpointer orig_domain = NULL, attach_cookie;
2570 int i;
2572 if (rmethod->needs_thread_attach)
2573 orig_domain = mono_threads_attach_coop (mono_domain_get (), &attach_cookie);
2575 context = get_context ();
2577 method = rmethod->method;
2578 sig = mono_method_signature_internal (method);
2580 frame.ex = NULL;
2582 args = (stackval*)alloca (sizeof (stackval) * (sig->param_count + (sig->hasthis ? 1 : 0)));
2584 init_frame (&frame, NULL, rmethod, args, &result);
2586 /* Allocate storage for value types */
2587 for (i = 0; i < sig->param_count; i++) {
2588 MonoType *type = sig->params [i];
2589 alloc_storage_for_stackval (&frame.stack_args [i + sig->hasthis], type, sig->pinvoke);
2592 if (sig->ret->type != MONO_TYPE_VOID)
2593 alloc_storage_for_stackval (frame.retval, sig->ret, sig->pinvoke);
2595 /* Copy the args saved in the trampoline to the frame stack */
2596 mono_arch_get_native_call_context_args (ccontext, &frame, sig);
2598 ERROR_DECL (error);
2599 interp_exec_method (&frame, context, error);
2601 if (rmethod->needs_thread_attach)
2602 mono_threads_detach_coop (orig_domain, &attach_cookie);
2604 // FIXME:
2605 g_assert (frame.ex == NULL);
2607 /* Write back the return value */
2608 mono_arch_set_native_call_context_ret (ccontext, &frame, sig);
2611 #else
2613 static void
2614 interp_entry_from_trampoline (gpointer ccontext_untyped, gpointer rmethod_untyped)
2616 g_assert_not_reached ();
2619 #endif /* MONO_ARCH_HAVE_INTERP_ENTRY_TRAMPOLINE */
2621 static InterpMethod*
2622 lookup_method_pointer (gpointer addr)
2624 MonoDomain *domain = mono_domain_get ();
2625 MonoJitDomainInfo *info = domain_jit_info (domain);
2626 InterpMethod *res = NULL;
2628 mono_domain_lock (domain);
2629 if (info->interp_method_pointer_hash)
2630 res = (InterpMethod*)g_hash_table_lookup (info->interp_method_pointer_hash, addr);
2631 mono_domain_unlock (domain);
2633 return res;
2636 #ifndef MONO_ARCH_HAVE_INTERP_NATIVE_TO_MANAGED
2637 static void
2638 interp_no_native_to_managed (void)
2640 g_error ("interpreter: native-to-managed transition not available on this platform");
2642 #endif
2644 static void
2645 no_llvmonly_interp_method_pointer (void)
2647 g_assert_not_reached ();
2651 * interp_create_method_pointer_llvmonly:
2653 * Return an ftndesc for entering the interpreter and executing METHOD.
2655 static MonoFtnDesc*
2656 interp_create_method_pointer_llvmonly (MonoMethod *method, gboolean unbox, MonoError *error)
2658 MonoDomain *domain = mono_domain_get ();
2659 gpointer addr, entry_func, entry_wrapper;
2660 MonoMethodSignature *sig;
2661 MonoMethod *wrapper;
2662 MonoJitDomainInfo *info;
2663 InterpMethod *imethod;
2665 imethod = mono_interp_get_imethod (domain, method, error);
2666 return_val_if_nok (error, NULL);
2668 if (unbox) {
2669 if (imethod->llvmonly_unbox_entry)
2670 return (MonoFtnDesc*)imethod->llvmonly_unbox_entry;
2671 } else {
2672 if (imethod->jit_entry)
2673 return (MonoFtnDesc*)imethod->jit_entry;
2676 sig = mono_method_signature_internal (method);
2679 * The entry functions need access to the method to call, so we have
2680 * to use a ftndesc. The caller uses a normal signature, while the
2681 * entry functions use a gsharedvt_in signature, so wrap the entry function in
2682 * a gsharedvt_in_sig wrapper.
2684 wrapper = mini_get_gsharedvt_in_sig_wrapper (sig);
2686 entry_wrapper = mono_jit_compile_method_jit_only (wrapper, error);
2687 mono_error_assertf_ok (error, "couldn't compile wrapper \"%s\" for \"%s\"",
2688 mono_method_get_name_full (wrapper, TRUE, TRUE, MONO_TYPE_NAME_FORMAT_IL),
2689 mono_method_get_name_full (method, TRUE, TRUE, MONO_TYPE_NAME_FORMAT_IL));
2691 if (sig->param_count > MAX_INTERP_ENTRY_ARGS) {
2692 g_assert_not_reached ();
2693 //entry_func = (gpointer)interp_entry_general;
2694 } else if (sig->hasthis) {
2695 if (sig->ret->type == MONO_TYPE_VOID)
2696 entry_func = entry_funcs_instance [sig->param_count];
2697 else
2698 entry_func = entry_funcs_instance_ret [sig->param_count];
2699 } else {
2700 if (sig->ret->type == MONO_TYPE_VOID)
2701 entry_func = entry_funcs_static [sig->param_count];
2702 else
2703 entry_func = entry_funcs_static_ret [sig->param_count];
2705 g_assert (entry_func);
2707 /* Encode unbox in the lower bit of imethod */
2708 gpointer entry_arg = imethod;
2709 if (unbox)
2710 entry_arg = (gpointer)(((gsize)entry_arg) | 1);
2711 MonoFtnDesc *entry_ftndesc = mini_llvmonly_create_ftndesc (mono_domain_get (), entry_func, entry_arg);
2713 addr = mini_llvmonly_create_ftndesc (mono_domain_get (), entry_wrapper, entry_ftndesc);
2715 info = domain_jit_info (domain);
2716 mono_domain_lock (domain);
2717 if (!info->interp_method_pointer_hash)
2718 info->interp_method_pointer_hash = g_hash_table_new (NULL, NULL);
2719 g_hash_table_insert (info->interp_method_pointer_hash, addr, imethod);
2720 mono_domain_unlock (domain);
2722 mono_memory_barrier ();
2723 if (unbox)
2724 imethod->llvmonly_unbox_entry = addr;
2725 else
2726 imethod->jit_entry = addr;
2728 return (MonoFtnDesc*)addr;
2732 * interp_create_method_pointer:
2734 * Return a function pointer which can be used to call METHOD using the
2735 * interpreter. Return NULL for methods which are not supported.
2737 static gpointer
2738 interp_create_method_pointer (MonoMethod *method, gboolean compile, MonoError *error)
2740 #ifndef MONO_ARCH_HAVE_INTERP_NATIVE_TO_MANAGED
2741 if (mono_llvm_only)
2742 return (gpointer)no_llvmonly_interp_method_pointer;
2743 return (gpointer)interp_no_native_to_managed;
2744 #else
2745 gpointer addr, entry_func, entry_wrapper = NULL;
2746 MonoDomain *domain = mono_domain_get ();
2747 MonoJitDomainInfo *info;
2748 InterpMethod *imethod = mono_interp_get_imethod (domain, method, error);
2750 if (mono_llvm_only)
2751 return (gpointer)no_llvmonly_interp_method_pointer;
2753 if (imethod->jit_entry)
2754 return imethod->jit_entry;
2756 if (compile && !imethod->transformed) {
2757 /* Return any errors from method compilation */
2758 mono_interp_transform_method (imethod, get_context (), error);
2759 return_val_if_nok (error, NULL);
2762 MonoMethodSignature *sig = mono_method_signature_internal (method);
2764 if (mono_llvm_only)
2765 /* The caller should call interp_create_method_pointer_llvmonly */
2766 g_assert_not_reached ();
2768 if (method->wrapper_type && method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE)
2769 return imethod;
2771 #ifndef MONO_ARCH_HAVE_FTNPTR_ARG_TRAMPOLINE
2773 * Interp in wrappers get the argument in the rgctx register. If
2774 * MONO_ARCH_HAVE_FTNPTR_ARG_TRAMPOLINE is defined it means that
2775 * on that arch the rgctx register is not scratch, so we use a
2776 * separate temp register. We should update the wrappers for this
2777 * if we really care about those architectures (arm).
2779 MonoMethod *wrapper = mini_get_interp_in_wrapper (sig);
2781 entry_wrapper = mono_jit_compile_method_jit_only (wrapper, error);
2782 #endif
2783 if (entry_wrapper) {
2784 if (sig->param_count > MAX_INTERP_ENTRY_ARGS) {
2785 entry_func = (gpointer)interp_entry_general;
2786 } else if (sig->hasthis) {
2787 if (sig->ret->type == MONO_TYPE_VOID)
2788 entry_func = entry_funcs_instance [sig->param_count];
2789 else
2790 entry_func = entry_funcs_instance_ret [sig->param_count];
2791 } else {
2792 if (sig->ret->type == MONO_TYPE_VOID)
2793 entry_func = entry_funcs_static [sig->param_count];
2794 else
2795 entry_func = entry_funcs_static_ret [sig->param_count];
2797 } else {
2798 #ifndef MONO_ARCH_HAVE_INTERP_ENTRY_TRAMPOLINE
2799 mono_error_assertf_ok (error, "couldn't compile wrapper \"%s\" for \"%s\"",
2800 mono_method_get_name_full (wrapper, TRUE, TRUE, MONO_TYPE_NAME_FORMAT_IL),
2801 mono_method_get_name_full (method, TRUE, TRUE, MONO_TYPE_NAME_FORMAT_IL));
2802 #else
2803 mono_error_cleanup (error);
2804 error_init_reuse (error);
2805 if (!mono_native_to_interp_trampoline) {
2806 if (mono_aot_only) {
2807 mono_native_to_interp_trampoline = (MonoFuncV)mono_aot_get_trampoline ("native_to_interp_trampoline");
2808 } else {
2809 MonoTrampInfo *info;
2810 mono_native_to_interp_trampoline = (MonoFuncV)mono_arch_get_native_to_interp_trampoline (&info);
2811 mono_tramp_info_register (info, NULL);
2814 entry_wrapper = (gpointer)mono_native_to_interp_trampoline;
2815 /* We need the lmf wrapper only when being called from mixed mode */
2816 if (sig->pinvoke)
2817 entry_func = (gpointer)interp_entry_from_trampoline;
2818 else {
2819 static gpointer cached_func = NULL;
2820 if (!cached_func) {
2821 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);
2822 mono_memory_barrier ();
2824 entry_func = cached_func;
2826 #endif
2829 g_assert (entry_func);
2830 /* This is the argument passed to the interp_in wrapper by the static rgctx trampoline */
2831 MonoFtnDesc *ftndesc = g_new0 (MonoFtnDesc, 1);
2832 ftndesc->addr = entry_func;
2833 ftndesc->arg = imethod;
2834 mono_error_assert_ok (error);
2837 * The wrapper is called by compiled code, which doesn't pass the extra argument, so we pass it in the
2838 * rgctx register using a trampoline.
2841 addr = mono_create_ftnptr_arg_trampoline (ftndesc, entry_wrapper);
2843 info = domain_jit_info (domain);
2844 mono_domain_lock (domain);
2845 if (!info->interp_method_pointer_hash)
2846 info->interp_method_pointer_hash = g_hash_table_new (NULL, NULL);
2847 g_hash_table_insert (info->interp_method_pointer_hash, addr, imethod);
2848 mono_domain_unlock (domain);
2850 mono_memory_barrier ();
2851 imethod->jit_entry = addr;
2853 return addr;
2854 #endif
2857 #if COUNT_OPS
2858 static int opcode_counts[512];
2860 #define COUNT_OP(op) opcode_counts[op]++
2861 #else
2862 #define COUNT_OP(op)
2863 #endif
2865 #if DEBUG_INTERP
2866 #define DUMP_INSTR() \
2867 if (tracing > 1) { \
2868 char *ins; \
2869 if (sp > frame->stack) { \
2870 ins = dump_stack (frame->stack, sp); \
2871 } else { \
2872 ins = g_strdup (""); \
2874 sp->data.l = 0; \
2875 output_indent (); \
2876 char *mn = mono_method_full_name (frame->imethod->method, FALSE); \
2877 char *disasm = mono_interp_dis_mintop(imethod->code, ip); \
2878 g_print ("(%p) %s -> %s\t%d:%s\n", mono_thread_internal_current (), mn, disasm, vt_sp - vtalloc, ins); \
2879 g_free (mn); \
2880 g_free (ins); \
2881 g_free (disasm); \
2883 #else
2884 #define DUMP_INSTR()
2885 #endif
2887 #define INIT_VTABLE(vtable) do { \
2888 if (G_UNLIKELY (!(vtable)->initialized)) { \
2889 mono_runtime_class_init_full ((vtable), error); \
2890 if (!is_ok (error)) \
2891 goto throw_error_label; \
2893 } while (0);
2895 static MONO_NEVER_INLINE MonoObject*
2896 mono_interp_new (MonoDomain* domain, MonoClass* klass)
2898 ERROR_DECL (error);
2899 MonoObject* const object = mono_object_new_checked (domain, klass, error);
2900 mono_error_cleanup (error); // FIXME: do not swallow the error
2901 return object;
2904 static
2905 #ifndef DISABLE_REMOTING
2906 MONO_NEVER_INLINE // To reduce stack.
2907 #endif
2908 void
2909 mono_interp_load_remote_field (
2910 InterpMethod* imethod,
2911 MonoObject* o,
2912 const guint16* ip,
2913 stackval* sp)
2915 g_assert (o); // Caller checks and throws exception properly.
2917 void* addr;
2918 MonoClassField* const field = (MonoClassField*)imethod->data_items[* (guint16 *)(ip + 1)];
2920 #ifndef DISABLE_REMOTING
2921 gpointer tmp;
2922 if (mono_object_is_transparent_proxy (o)) {
2923 MonoClass * const klass = ((MonoTransparentProxy*)o)->remote_class->proxy_class;
2924 ERROR_DECL (error);
2925 addr = mono_load_remote_field_checked (o, klass, field, &tmp, error);
2926 mono_error_cleanup (error); /* FIXME: don't swallow the error */
2927 } else
2928 #endif
2929 addr = (char*)o + field->offset;
2930 stackval_from_data (field->type, &sp [-1], addr, FALSE);
2933 static
2934 #ifndef DISABLE_REMOTING
2935 MONO_NEVER_INLINE // To reduce stack.
2936 #endif
2937 guchar* // Return new vt_sp instead of take-address.
2938 mono_interp_load_remote_field_vt (
2939 InterpMethod* imethod,
2940 MonoObject* o,
2941 const guint16* ip,
2942 stackval* sp,
2943 guchar* vt_sp)
2945 g_assert (o); // Caller checks and throws exception properly.
2947 void* addr;
2948 MonoClassField* const field = (MonoClassField*)imethod->data_items[* (guint16 *)(ip + 1)];
2949 MonoClass* klass = mono_class_from_mono_type_internal (field->type);
2950 int const i32 = mono_class_value_size (klass, NULL);
2952 #ifndef DISABLE_REMOTING
2953 gpointer tmp;
2954 if (mono_object_is_transparent_proxy (o)) {
2955 klass = ((MonoTransparentProxy*)o)->remote_class->proxy_class;
2956 ERROR_DECL (error);
2957 addr = mono_load_remote_field_checked (o, klass, field, &tmp, error);
2958 mono_error_cleanup (error); /* FIXME: don't swallow the error */
2959 } else
2960 #endif
2961 addr = (char*)o + field->offset;
2962 sp [-1].data.p = vt_sp;
2963 memcpy (vt_sp, addr, i32);
2964 return vt_sp + ALIGN_TO (i32, MINT_VT_ALIGNMENT);
2967 static MONO_NEVER_INLINE gboolean
2968 mono_interp_isinst (MonoObject* object, MonoClass* klass)
2970 ERROR_DECL (error);
2971 const gboolean isinst = mono_object_isinst_checked (object, klass, error) != NULL;
2972 mono_error_cleanup (error); // FIXME: do not swallow the error
2973 return isinst;
2977 * GC SAFETY:
2979 * The interpreter executes in gc unsafe (non-preempt) mode. On wasm, the C stack is
2980 * scannable but the wasm stack is not, so to make the code GC safe, the following rules
2981 * should be followed:
2982 * - every objref handled by the code needs to have a copy stored inside InterpFrame,
2983 * in stackval->data.o. For objrefs which are not yet on the IL stack, they can be stored
2984 * in frame->o. This will ensure the objects are pinned. The 'frame' local is assumed
2985 * to be allocated to the C stack and not to registers.
2986 * - minimalize the number of MonoObject* locals/arguments.
2989 #ifdef TARGET_WASM
2990 #define frame_objref(frame) (frame)->o
2991 #else
2992 #define frame_objref(frame) o
2993 #endif
2995 // This function is outlined to help save stack in its caller, on the premise
2996 // that it is relatively rarely called. This also lets it use alloca.
2997 static MONO_NEVER_INLINE void
2998 mono_interp_calli_nat_dynamic_pinvoke (
2999 // Parameters are sorted by name.
3000 InterpFrame* child_frame,
3001 guchar* code,
3002 ThreadContext* context,
3003 MonoMethodSignature* csignature,
3004 MonoError* error)
3006 // Recompute to limit parameters, which can also contribute to caller stack.
3007 InterpMethod* const imethod = child_frame->parent->imethod;
3009 g_assert (imethod->method->dynamic && csignature->pinvoke);
3011 /* Pinvoke call is missing the wrapper. See mono_get_native_calli_wrapper */
3012 MonoMarshalSpec** mspecs = g_newa (MonoMarshalSpec*, csignature->param_count + 1);
3013 memset (mspecs, 0, sizeof (MonoMarshalSpec*) * (csignature->param_count + 1));
3015 MonoMethodPInvoke iinfo;
3016 memset (&iinfo, 0, sizeof (iinfo));
3018 MonoMethod* m = mono_marshal_get_native_func_wrapper (m_class_get_image (imethod->method->klass), csignature, &iinfo, mspecs, code);
3020 for (int i = csignature->param_count; i >= 0; i--)
3021 if (mspecs [i])
3022 mono_metadata_free_marshal_spec (mspecs [i]);
3025 ERROR_DECL (error);
3026 child_frame->imethod = mono_interp_get_imethod (imethod->domain, m, error);
3027 mono_error_cleanup (error); /* FIXME: don't swallow the error */
3030 interp_exec_method (child_frame, context, error);
3033 // Leave is split into pieces in order to consume less stack,
3034 // but not have to change how exception handling macros access labels and locals.
3035 static MONO_NEVER_INLINE MonoException*
3036 mono_interp_leave (InterpFrame* child_frame)
3038 stackval tmp_sp;
3040 * We need for mono_thread_get_undeniable_exception to be able to unwind
3041 * to check the abort threshold. For this to work we use child_frame as a
3042 * dummy frame that is stored in the lmf and serves as the transition frame
3044 do_icall_wrapper (child_frame, NULL, MINT_ICALL_V_P, &tmp_sp, (gpointer)mono_thread_get_undeniable_exception, FALSE);
3046 return (MonoException*)tmp_sp.data.p;
3049 static MONO_NEVER_INLINE void
3050 mono_interp_newobj_vt (
3051 // Parameters are sorted by name and parameter list is minimized
3052 // to reduce stack use in caller, on e.g. NT/AMD64 (up to 4 parameters
3053 // use no stack in caller).
3054 InterpFrame* child_frame,
3055 ThreadContext* context,
3056 MonoError* error)
3058 stackval* const sp = child_frame->stack_args;
3060 stackval valuetype_this;
3062 memset (&valuetype_this, 0, sizeof (stackval));
3063 sp->data.p = &valuetype_this;
3065 // FIXME It is unfortunate to outline a recursive case as it
3066 // increases its stack usage. We do this however as it conserves
3067 // stack for all the other recursive cases.
3068 interp_exec_method (child_frame, context, error);
3070 CHECK_RESUME_STATE (context);
3072 *sp = valuetype_this;
3073 resume:
3077 static MONO_NEVER_INLINE MonoException*
3078 mono_interp_newobj (
3079 // Parameters are sorted by name and parameter list is minimized
3080 // to reduce stack use in caller, on e.g. NT/AMD64 (up to 4 parameters
3081 // use no stack in caller).
3082 InterpFrame* child_frame,
3083 ThreadContext* context,
3084 MonoError* error,
3085 guchar* vt_sp)
3087 InterpFrame* const frame = child_frame->parent;
3088 InterpMethod* const imethod = frame->imethod;
3089 stackval* const sp = child_frame->stack_args;
3091 MonoObject* o = NULL; // See the comment about GC safety above.
3092 stackval valuetype_this;
3093 stackval retval;
3095 MonoClass * const newobj_class = child_frame->imethod->method->klass;
3096 /*if (profiling_classes) {
3097 guint count = GPOINTER_TO_UINT (g_hash_table_lookup (profiling_classes, newobj_class));
3098 count++;
3099 g_hash_table_insert (profiling_classes, newobj_class, GUINT_TO_POINTER (count));
3103 * First arg is the object.
3105 if (m_class_is_valuetype (newobj_class)) {
3106 MonoType *t = m_class_get_byval_arg (newobj_class);
3107 memset (&valuetype_this, 0, sizeof (stackval));
3108 if (!m_class_is_enumtype (newobj_class) && (t->type == MONO_TYPE_VALUETYPE || (t->type == MONO_TYPE_GENERICINST && mono_type_generic_inst_is_valuetype (t)))) {
3109 sp->data.p = vt_sp;
3110 valuetype_this.data.p = vt_sp;
3111 } else {
3112 sp->data.p = &valuetype_this;
3114 } else {
3115 if (newobj_class != mono_defaults.string_class) {
3116 MonoVTable *vtable = mono_class_vtable_checked (imethod->domain, newobj_class, error);
3117 if (!is_ok (error) || !mono_runtime_class_init_full (vtable, error)) {
3118 MonoException* const exc = mono_error_convert_to_exception (error);
3119 g_assert (exc);
3120 return exc;
3122 ERROR_DECL (error);
3123 frame_objref (frame) = mono_object_new_checked (imethod->domain, newobj_class, error);
3124 mono_error_cleanup (error); // FIXME: do not swallow the error
3125 EXCEPTION_CHECKPOINT_IN_HELPER_FUNCTION;
3126 sp->data.o = frame_objref (frame);
3127 #ifndef DISABLE_REMOTING
3128 if (mono_object_is_transparent_proxy (frame_objref (frame))) {
3129 MonoMethod *remoting_invoke_method = mono_marshal_get_remoting_invoke_with_check (child_frame->imethod->method, error);
3130 mono_error_assert_ok (error);
3131 child_frame->imethod = mono_interp_get_imethod (imethod->domain, remoting_invoke_method, error);
3132 mono_error_assert_ok (error);
3134 #endif
3135 } else {
3136 sp->data.p = NULL;
3137 child_frame->retval = &retval;
3141 interp_exec_method (child_frame, context, error);
3143 CHECK_RESUME_STATE (context);
3146 * a constructor returns void, but we need to return the object we created
3148 if (m_class_is_valuetype (newobj_class) && !m_class_is_enumtype (newobj_class)) {
3149 *sp = valuetype_this;
3150 } else if (newobj_class == mono_defaults.string_class) {
3151 *sp = retval;
3152 } else {
3153 sp->data.o = frame_objref (frame);
3155 resume:
3156 return NULL;
3159 static MONO_NEVER_INLINE void
3160 mono_interp_enum_hasflag (stackval* sp, MonoClass* klass)
3162 guint64 a_val = 0, b_val = 0;
3164 stackval_to_data (m_class_get_byval_arg (klass), --sp, &b_val, FALSE);
3165 stackval_to_data (m_class_get_byval_arg (klass), --sp, &a_val, FALSE);
3166 sp->data.i = (a_val & b_val) == b_val;
3169 static MONO_NEVER_INLINE int
3170 mono_interp_box_nullable (InterpFrame* frame, const guint16* ip, stackval* sp, MonoError* error)
3172 InterpMethod* const imethod = frame->imethod;
3173 MonoClass* const c = (MonoClass*)imethod->data_items [*(const guint16*)(ip + 1)];
3175 int const size = mono_class_value_size (c, NULL);
3177 guint16 offset = *(const guint16*)(ip + 2);
3178 gboolean const pop_vt_sp = !(offset & BOX_NOT_CLEAR_VT_SP);
3179 offset &= ~BOX_NOT_CLEAR_VT_SP;
3181 sp [-1 - offset].data.o = mono_nullable_box (sp [-1 - offset].data.p, c, error);
3182 mono_interp_error_cleanup (error); /* FIXME: don't swallow the error */
3184 return pop_vt_sp ? ALIGN_TO (size, MINT_VT_ALIGNMENT) : 0;
3187 static MONO_NEVER_INLINE int
3188 mono_interp_box_vt (InterpFrame* frame, const guint16* ip, stackval* sp)
3190 InterpMethod* const imethod = frame->imethod;
3192 MonoObject* o; // See the comment about GC safety.
3193 MonoVTable * const vtable = (MonoVTable*)imethod->data_items [*(const guint16*)(ip + 1)];
3194 MonoClass* const c = vtable->klass;
3196 int const size = mono_class_value_size (c, NULL);
3198 guint16 offset = *(const guint16*)(ip + 2);
3199 gboolean const pop_vt_sp = !(offset & BOX_NOT_CLEAR_VT_SP);
3200 offset &= ~BOX_NOT_CLEAR_VT_SP;
3202 frame_objref (frame) = mono_gc_alloc_obj (vtable, m_class_get_instance_size (vtable->klass));
3203 mono_value_copy_internal (mono_object_get_data (frame_objref (frame)), sp [-1 - offset].data.p, c);
3205 sp [-1 - offset].data.p = frame_objref (frame);
3206 return pop_vt_sp ? ALIGN_TO (size, MINT_VT_ALIGNMENT) : 0;
3209 static MONO_NEVER_INLINE void
3210 mono_interp_box (InterpFrame* frame, const guint16* ip, stackval* sp)
3212 MonoObject* o; // See the comment about GC safety.
3213 MonoVTable * const vtable = (MonoVTable*)frame->imethod->data_items [*(const guint16*)(ip + 1)];
3215 frame_objref (frame) = mono_gc_alloc_obj (vtable, m_class_get_instance_size (vtable->klass));
3217 guint16 const offset = *(const guint16*)(ip + 2);
3219 stackval_to_data (m_class_get_byval_arg (vtable->klass), &sp [-1 - offset], mono_object_get_data (frame_objref (frame)), FALSE);
3221 sp [-1 - offset].data.p = frame_objref (frame);
3224 static MONO_NEVER_INLINE int
3225 mono_interp_store_remote_field_vt (InterpFrame* frame, const guint16* ip, stackval* sp, MonoError* error)
3227 InterpMethod* const imethod = frame->imethod;
3228 MonoClassField *field;
3230 MonoObject* const o = sp [-2].data.o;
3232 field = (MonoClassField*)imethod->data_items[* (guint16 *)(ip + 1)];
3233 MonoClass *klass = mono_class_from_mono_type_internal (field->type);
3234 int const i32 = mono_class_value_size (klass, NULL);
3236 #ifndef DISABLE_REMOTING
3237 if (mono_object_is_transparent_proxy (o)) {
3238 MonoClass *klass = ((MonoTransparentProxy*)o)->remote_class->proxy_class;
3239 mono_store_remote_field_checked (o, klass, field, sp [-1].data.p, error);
3240 mono_interp_error_cleanup (error); /* FIXME: don't swallow the error */
3241 } else
3242 #endif
3243 mono_value_copy_internal ((char *) o + field->offset, sp [-1].data.p, klass);
3245 return ALIGN_TO (i32, MINT_VT_ALIGNMENT);
3249 * If EXIT_AT_FINALLY is not -1, exit after exiting the finally clause with that index.
3250 * If BASE_FRAME is not NULL, copy arguments/locals from BASE_FRAME.
3251 * The ERROR argument is used to avoid declaring an error object for every interp frame, its not used
3252 * to return error information.
3254 * Currently this method uses 0x88 of stack space on 64bit gcc. Make sure to keep it under control.
3256 static void
3257 interp_exec_method_full (InterpFrame *frame, ThreadContext *context, FrameClauseArgs *clause_args, MonoError *error)
3259 InterpFrame child_frame;
3260 GSList *finally_ips = NULL;
3261 const guint16 *endfinally_ip = NULL;
3262 const guint16 *ip = NULL;
3263 stackval *sp;
3264 #if DEBUG_INTERP
3265 gint tracing = global_tracing;
3266 unsigned char *vtalloc;
3267 #endif
3268 unsigned char *vt_sp;
3269 unsigned char *locals = NULL;
3270 #if USE_COMPUTED_GOTO
3271 static void * const in_labels[] = {
3272 #define OPDEF(a,b,c,d) &&LAB_ ## a,
3273 #include "mintops.def"
3275 #endif
3277 frame->ex = NULL;
3278 #if DEBUG_INTERP
3279 debug_enter (frame, &tracing);
3280 #endif
3282 if (!frame->imethod->transformed) {
3283 #if DEBUG_INTERP
3284 char *mn = mono_method_full_name (frame->imethod->method, TRUE);
3285 g_print ("(%p) Transforming %s\n", mono_thread_internal_current (), mn);
3286 g_free (mn);
3287 #endif
3289 frame->ip = NULL;
3290 do_transform_method (frame, context);
3291 if (frame->ex)
3292 THROW_EX (frame->ex, NULL);
3293 EXCEPTION_CHECKPOINT;
3296 if (!clause_args) {
3297 frame->stack = (stackval*)g_alloca (frame->imethod->alloca_size);
3298 ip = frame->imethod->code;
3299 } else {
3300 ip = clause_args->start_with_ip;
3301 if (clause_args->base_frame) {
3302 frame->stack = (stackval*)g_alloca (frame->imethod->alloca_size);
3303 memcpy (frame->stack, clause_args->base_frame->stack, frame->imethod->alloca_size);
3306 sp = frame->stack;
3307 vt_sp = (unsigned char *) sp + frame->imethod->stack_size;
3308 #if DEBUG_INTERP
3309 vtalloc = vt_sp;
3310 #endif
3311 locals = (unsigned char *) vt_sp + frame->imethod->vt_stack_size;
3312 child_frame.parent = frame;
3314 if (clause_args && clause_args->filter_exception) {
3315 sp->data.p = clause_args->filter_exception;
3316 sp++;
3319 //g_print ("(%p) Call %s\n", mono_thread_internal_current (), mono_method_get_full_name (frame->imethod->method));
3322 * using while (ip < end) may result in a 15% performance drop,
3323 * but it may be useful for debug
3325 while (1) {
3326 main_loop:
3327 /* g_assert (sp >= frame->stack); */
3328 /* g_assert(vt_sp - vtalloc <= frame->imethod->vt_stack_size); */
3329 DUMP_INSTR();
3330 MINT_IN_SWITCH (*ip) {
3331 MINT_IN_CASE(MINT_INITLOCALS)
3332 memset (locals, 0, frame->imethod->locals_size);
3333 ++ip;
3334 MINT_IN_BREAK;
3335 MINT_IN_CASE(MINT_NOP)
3336 MINT_IN_CASE(MINT_NIY)
3337 g_assert_not_reached ();
3338 MINT_IN_BREAK;
3339 MINT_IN_CASE(MINT_BREAK)
3340 ++ip;
3341 do_debugger_tramp (mini_get_dbg_callbacks ()->user_break, frame);
3342 MINT_IN_BREAK;
3343 MINT_IN_CASE(MINT_BREAKPOINT)
3344 ++ip;
3345 mono_break ();
3346 MINT_IN_BREAK;
3347 MINT_IN_CASE(MINT_LDNULL)
3348 sp->data.p = NULL;
3349 ++ip;
3350 ++sp;
3351 MINT_IN_BREAK;
3352 MINT_IN_CASE(MINT_ARGLIST)
3353 sp->data.p = vt_sp;
3354 *(gpointer*)sp->data.p = ((gpointer*)frame->retval->data.p) [-1];
3355 vt_sp += ALIGN_TO (sizeof (gpointer), MINT_VT_ALIGNMENT);
3356 ++ip;
3357 ++sp;
3358 MINT_IN_BREAK;
3359 MINT_IN_CASE(MINT_VTRESULT) {
3360 int ret_size = * (guint16 *)(ip + 1);
3361 unsigned char *ret_vt_sp = vt_sp;
3362 vt_sp -= READ32(ip + 2);
3363 if (ret_size > 0) {
3364 memmove (vt_sp, ret_vt_sp, ret_size);
3365 sp [-1].data.p = vt_sp;
3366 vt_sp += ALIGN_TO (ret_size, MINT_VT_ALIGNMENT);
3368 ip += 4;
3369 MINT_IN_BREAK;
3371 #define LDC(n) do { sp->data.i = (n); ++ip; ++sp; } while (0)
3372 MINT_IN_CASE(MINT_LDC_I4_M1)
3373 LDC(-1);
3374 MINT_IN_BREAK;
3375 MINT_IN_CASE(MINT_LDC_I4_0)
3376 LDC(0);
3377 MINT_IN_BREAK;
3378 MINT_IN_CASE(MINT_LDC_I4_1)
3379 LDC(1);
3380 MINT_IN_BREAK;
3381 MINT_IN_CASE(MINT_LDC_I4_2)
3382 LDC(2);
3383 MINT_IN_BREAK;
3384 MINT_IN_CASE(MINT_LDC_I4_3)
3385 LDC(3);
3386 MINT_IN_BREAK;
3387 MINT_IN_CASE(MINT_LDC_I4_4)
3388 LDC(4);
3389 MINT_IN_BREAK;
3390 MINT_IN_CASE(MINT_LDC_I4_5)
3391 LDC(5);
3392 MINT_IN_BREAK;
3393 MINT_IN_CASE(MINT_LDC_I4_6)
3394 LDC(6);
3395 MINT_IN_BREAK;
3396 MINT_IN_CASE(MINT_LDC_I4_7)
3397 LDC(7);
3398 MINT_IN_BREAK;
3399 MINT_IN_CASE(MINT_LDC_I4_8)
3400 LDC(8);
3401 MINT_IN_BREAK;
3402 MINT_IN_CASE(MINT_LDC_I4_S)
3403 sp->data.i = *(const short *)(ip + 1);
3404 ip += 2;
3405 ++sp;
3406 MINT_IN_BREAK;
3407 MINT_IN_CASE(MINT_LDC_I4)
3408 ++ip;
3409 sp->data.i = READ32 (ip);
3410 ip += 2;
3411 ++sp;
3412 MINT_IN_BREAK;
3413 MINT_IN_CASE(MINT_LDC_I8)
3414 ++ip;
3415 sp->data.l = READ64 (ip);
3416 ip += 4;
3417 ++sp;
3418 MINT_IN_BREAK;
3419 MINT_IN_CASE(MINT_LDC_I8_S)
3420 sp->data.l = *(const short *)(ip + 1);
3421 ip += 2;
3422 ++sp;
3423 MINT_IN_BREAK;
3424 MINT_IN_CASE(MINT_LDC_R4) {
3425 guint32 val;
3426 ++ip;
3427 val = READ32(ip);
3428 sp->data.f_r4 = * (float *)&val;
3429 ip += 2;
3430 ++sp;
3431 MINT_IN_BREAK;
3433 MINT_IN_CASE(MINT_LDC_R8)
3434 sp->data.l = READ64 (ip + 1); /* note union usage */
3435 ip += 5;
3436 ++sp;
3437 MINT_IN_BREAK;
3438 MINT_IN_CASE(MINT_DUP)
3439 sp [0] = sp[-1];
3440 ++sp;
3441 ++ip;
3442 MINT_IN_BREAK;
3443 MINT_IN_CASE(MINT_DUP_VT) {
3444 int const i32 = READ32 (ip + 1);
3445 sp->data.p = vt_sp;
3446 memcpy(sp->data.p, sp [-1].data.p, i32);
3447 vt_sp += ALIGN_TO (i32, MINT_VT_ALIGNMENT);
3448 ++sp;
3449 ip += 3;
3450 MINT_IN_BREAK;
3452 MINT_IN_CASE(MINT_POP) {
3453 guint16 u16 = (* (guint16 *)(ip + 1)) + 1;
3454 if (u16 > 1)
3455 memmove (sp - u16, sp - 1, (u16 - 1) * sizeof (stackval));
3456 sp--;
3457 ip += 2;
3458 MINT_IN_BREAK;
3460 MINT_IN_CASE(MINT_JMP) {
3461 InterpMethod *new_method = (InterpMethod*)frame->imethod->data_items [* (guint16 *)(ip + 1)];
3463 if (frame->imethod->prof_flags & MONO_PROFILER_CALL_INSTRUMENTATION_TAIL_CALL)
3464 MONO_PROFILER_RAISE (method_tail_call, (frame->imethod->method, new_method->method));
3466 if (!new_method->transformed) {
3467 MONO_API_ERROR_INIT (error);
3469 frame->ip = ip;
3470 mono_interp_transform_method (new_method, context, error);
3471 frame->ex = mono_error_convert_to_exception (error);
3472 if (frame->ex)
3473 goto exit_frame;
3475 ip += 2;
3476 const gboolean realloc_frame = new_method->alloca_size > frame->imethod->alloca_size;
3477 frame->imethod = new_method;
3479 * We allocate the stack frame from scratch and store the arguments in the
3480 * locals again since it's possible for the caller stack frame to be smaller
3481 * than the callee stack frame (at the interp level)
3483 if (realloc_frame) {
3484 frame->stack = (stackval*)g_alloca (frame->imethod->alloca_size);
3485 memset (frame->stack, 0, frame->imethod->alloca_size);
3486 sp = frame->stack;
3488 vt_sp = (unsigned char *) sp + frame->imethod->stack_size;
3489 #if DEBUG_INTERP
3490 vtalloc = vt_sp;
3491 #endif
3492 locals = vt_sp + frame->imethod->vt_stack_size;
3493 ip = frame->imethod->code;
3494 MINT_IN_BREAK;
3496 MINT_IN_CASE(MINT_CALLI) {
3497 MonoMethodSignature *csignature;
3499 frame->ip = ip;
3501 csignature = (MonoMethodSignature*)frame->imethod->data_items [* (guint16 *)(ip + 1)];
3502 ip += 2;
3503 --sp;
3504 child_frame.imethod = (InterpMethod*)sp->data.p;
3506 sp->data.p = vt_sp;
3507 child_frame.retval = sp;
3508 /* decrement by the actual number of args */
3509 sp -= csignature->param_count;
3510 if (csignature->hasthis)
3511 --sp;
3512 child_frame.stack_args = sp;
3514 if (child_frame.imethod->method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) {
3515 child_frame.imethod = mono_interp_get_imethod (frame->imethod->domain, mono_marshal_get_native_wrapper (child_frame.imethod->method, FALSE, FALSE), error);
3516 mono_interp_error_cleanup (error); /* FIXME: don't swallow the error */
3519 if (csignature->hasthis) {
3520 MonoObject *this_arg = (MonoObject*)sp->data.p;
3522 if (m_class_is_valuetype (this_arg->vtable->klass)) {
3523 gpointer unboxed = mono_object_unbox_internal (this_arg);
3524 sp [0].data.p = unboxed;
3528 interp_exec_method (&child_frame, context, error);
3530 CHECK_RESUME_STATE (context);
3532 /* need to handle typedbyref ... */
3533 if (csignature->ret->type != MONO_TYPE_VOID) {
3534 *sp = *child_frame.retval;
3535 sp++;
3537 MINT_IN_BREAK;
3539 MINT_IN_CASE(MINT_CALLI_NAT_FAST) {
3540 gpointer target_ip = sp [-1].data.p;
3541 MonoMethodSignature *csignature = (MonoMethodSignature*)frame->imethod->data_items [* (guint16 *)(ip + 1)];
3542 int opcode = *(guint16 *)(ip + 2);
3543 gboolean save_last_error = *(guint16 *)(ip + 3);
3545 sp--;
3546 frame->ip = ip;
3548 sp = do_icall_wrapper (frame, csignature, opcode, sp, target_ip, save_last_error);
3549 EXCEPTION_CHECKPOINT;
3550 CHECK_RESUME_STATE (context);
3551 ip += 4;
3552 MINT_IN_BREAK;
3554 MINT_IN_CASE(MINT_CALLI_NAT) {
3556 frame->ip = ip;
3558 MonoMethodSignature* csignature = (MonoMethodSignature*)frame->imethod->data_items [* (guint16 *)(ip + 1)];
3560 ip += 3;
3561 --sp;
3562 guchar* const code = (guchar*)sp->data.p;
3563 child_frame.imethod = NULL;
3565 sp->data.p = vt_sp;
3566 child_frame.retval = sp;
3567 /* decrement by the actual number of args */
3568 sp -= csignature->param_count;
3569 if (csignature->hasthis)
3570 --sp;
3571 child_frame.stack_args = sp;
3573 if (frame->imethod->method->dynamic && csignature->pinvoke) {
3574 mono_interp_calli_nat_dynamic_pinvoke (&child_frame, code, context, csignature, error);
3575 } else {
3576 const gboolean save_last_error = *(guint16 *)(ip - 3 + 2);
3577 ves_pinvoke_method (&child_frame, csignature, (MonoFuncV) code, FALSE, context, save_last_error);
3580 CHECK_RESUME_STATE (context);
3582 /* need to handle typedbyref ... */
3583 if (csignature->ret->type != MONO_TYPE_VOID) {
3584 *sp = *child_frame.retval;
3585 sp++;
3587 MINT_IN_BREAK;
3589 MINT_IN_CASE(MINT_CALLVIRT_FAST)
3590 MINT_IN_CASE(MINT_VCALLVIRT_FAST) {
3591 MonoObject *this_arg;
3592 InterpMethod *target_imethod;
3593 int slot;
3595 // FIXME Have it handle also remoting calls and use a single opcode for virtual calls
3597 frame->ip = ip;
3599 target_imethod = (InterpMethod*)frame->imethod->data_items [* (guint16 *)(ip + 1)];
3600 slot = *(gint16*)(ip + 2);
3601 ip += 3;
3602 sp->data.p = vt_sp;
3603 child_frame.retval = sp;
3605 /* decrement by the actual number of args */
3606 sp -= target_imethod->param_count + target_imethod->hasthis;
3607 child_frame.stack_args = sp;
3609 this_arg = (MonoObject*)sp->data.p;
3611 child_frame.imethod = get_virtual_method_fast (target_imethod, this_arg->vtable, slot);
3612 if (m_class_is_valuetype (this_arg->vtable->klass) && m_class_is_valuetype (child_frame.imethod->method->klass)) {
3613 /* unbox */
3614 gpointer unboxed = mono_object_unbox_internal (this_arg);
3615 sp [0].data.p = unboxed;
3618 interp_exec_method (&child_frame, context, error);
3620 CHECK_RESUME_STATE (context);
3622 const gboolean is_void = ip [-3] == MINT_VCALLVIRT_FAST;
3623 if (!is_void) {
3624 /* need to handle typedbyref ... */
3625 *sp = *child_frame.retval;
3626 sp++;
3628 MINT_IN_BREAK;
3630 MINT_IN_CASE(MINT_CALL_VARARG) {
3631 int num_varargs = 0;
3632 MonoMethodSignature *csig;
3634 frame->ip = ip;
3636 child_frame.imethod = (InterpMethod*)frame->imethod->data_items [* (guint16 *)(ip + 1)];
3637 /* The real signature for vararg calls */
3638 csig = (MonoMethodSignature*) frame->imethod->data_items [* (guint16*) (ip + 2)];
3639 /* Push all vararg arguments from normal sp to vt_sp together with the signature */
3640 num_varargs = csig->param_count - csig->sentinelpos;
3641 vt_sp = copy_varargs_vtstack (csig, sp, vt_sp);
3643 ip += 3;
3644 sp->data.p = vt_sp;
3645 child_frame.retval = sp;
3647 /* decrement by the actual number of args */
3648 sp -= child_frame.imethod->param_count + child_frame.imethod->hasthis + num_varargs;
3649 child_frame.stack_args = sp;
3651 interp_exec_method (&child_frame, context, error);
3653 CHECK_RESUME_STATE (context);
3655 if (csig->ret->type != MONO_TYPE_VOID) {
3656 *sp = *child_frame.retval;
3657 sp++;
3659 MINT_IN_BREAK;
3661 MINT_IN_CASE(MINT_CALL)
3662 MINT_IN_CASE(MINT_VCALL)
3663 MINT_IN_CASE(MINT_CALLVIRT)
3664 MINT_IN_CASE(MINT_VCALLVIRT) {
3666 frame->ip = ip;
3668 child_frame.imethod = (InterpMethod*)frame->imethod->data_items [* (guint16 *)(ip + 1)];
3669 ip += 2;
3670 sp->data.p = vt_sp;
3671 child_frame.retval = sp;
3673 /* decrement by the actual number of args */
3674 sp -= child_frame.imethod->param_count + child_frame.imethod->hasthis;
3675 child_frame.stack_args = sp;
3677 const gboolean is_virtual = ip [-2] == MINT_CALLVIRT || ip [-2] == MINT_VCALLVIRT;
3678 if (is_virtual) {
3679 MonoObject *this_arg = (MonoObject*)sp->data.p;
3681 child_frame.imethod = get_virtual_method (child_frame.imethod, this_arg->vtable);
3682 if (m_class_is_valuetype (this_arg->vtable->klass) && m_class_is_valuetype (child_frame.imethod->method->klass)) {
3683 /* unbox */
3684 gpointer unboxed = mono_object_unbox_internal (this_arg);
3685 sp [0].data.p = unboxed;
3689 interp_exec_method (&child_frame, context, error);
3691 CHECK_RESUME_STATE (context);
3693 const gboolean is_void = ip [-2] == MINT_VCALL || ip [-2] == MINT_VCALLVIRT;
3694 if (!is_void) {
3695 /* need to handle typedbyref ... */
3696 *sp = *child_frame.retval;
3697 sp++;
3699 MINT_IN_BREAK;
3701 MINT_IN_CASE(MINT_JIT_CALL) {
3702 InterpMethod *rmethod = (InterpMethod*)frame->imethod->data_items [* (guint16 *)(ip + 1)];
3703 MONO_API_ERROR_INIT (error);
3704 frame->ip = ip;
3705 sp = do_jit_call (sp, vt_sp, context, frame, rmethod, error);
3706 if (!is_ok (error)) {
3707 MonoException *ex = mono_error_convert_to_exception (error);
3708 THROW_EX (ex, ip);
3710 ip += 2;
3712 CHECK_RESUME_STATE (context);
3714 if (rmethod->rtype->type != MONO_TYPE_VOID)
3715 sp++;
3717 MINT_IN_BREAK;
3719 MINT_IN_CASE(MINT_CALLRUN) {
3720 MonoMethod *target_method = (MonoMethod*) frame->imethod->data_items [* (guint16 *)(ip + 1)];
3721 MonoMethodSignature *sig = (MonoMethodSignature*) frame->imethod->data_items [* (guint16 *)(ip + 2)];
3722 stackval *retval;
3724 sp->data.p = vt_sp;
3725 retval = sp;
3727 sp -= sig->param_count;
3728 if (sig->hasthis)
3729 sp--;
3731 ves_imethod (frame, target_method, sig, sp, retval);
3732 if (frame->ex)
3733 THROW_EX (frame->ex, ip);
3735 if (sig->ret->type != MONO_TYPE_VOID) {
3736 *sp = *retval;
3737 sp++;
3739 ip += 3;
3740 MINT_IN_BREAK;
3742 MINT_IN_CASE(MINT_RET)
3743 --sp;
3744 *frame->retval = *sp;
3745 if (sp > frame->stack)
3746 g_warning ("ret: more values on stack: %d", sp-frame->stack);
3747 goto exit_frame;
3748 MINT_IN_CASE(MINT_RET_VOID)
3749 if (sp > frame->stack)
3750 g_warning ("ret.void: more values on stack: %d %s", sp-frame->stack, mono_method_full_name (frame->imethod->method, TRUE));
3751 goto exit_frame;
3752 MINT_IN_CASE(MINT_RET_VT) {
3753 int const i32 = READ32 (ip + 1);
3754 --sp;
3755 memcpy(frame->retval->data.p, sp->data.p, i32);
3756 if (sp > frame->stack)
3757 g_warning ("ret.vt: more values on stack: %d", sp-frame->stack);
3758 goto exit_frame;
3760 MINT_IN_CASE(MINT_BR_S)
3761 ip += (short) *(ip + 1);
3762 MINT_IN_BREAK;
3763 MINT_IN_CASE(MINT_BR)
3764 ip += (gint32) READ32(ip + 1);
3765 MINT_IN_BREAK;
3766 #define ZEROP_S(datamem, op) \
3767 --sp; \
3768 if (sp->data.datamem op 0) \
3769 ip += * (gint16 *)(ip + 1); \
3770 else \
3771 ip += 2;
3773 #define ZEROP(datamem, op) \
3774 --sp; \
3775 if (sp->data.datamem op 0) \
3776 ip += (gint32)READ32(ip + 1); \
3777 else \
3778 ip += 3;
3780 MINT_IN_CASE(MINT_BRFALSE_I4_S)
3781 ZEROP_S(i, ==);
3782 MINT_IN_BREAK;
3783 MINT_IN_CASE(MINT_BRFALSE_I8_S)
3784 ZEROP_S(l, ==);
3785 MINT_IN_BREAK;
3786 MINT_IN_CASE(MINT_BRFALSE_R4_S)
3787 ZEROP_S(f_r4, ==);
3788 MINT_IN_BREAK;
3789 MINT_IN_CASE(MINT_BRFALSE_R8_S)
3790 ZEROP_S(f, ==);
3791 MINT_IN_BREAK;
3792 MINT_IN_CASE(MINT_BRFALSE_I4)
3793 ZEROP(i, ==);
3794 MINT_IN_BREAK;
3795 MINT_IN_CASE(MINT_BRFALSE_I8)
3796 ZEROP(l, ==);
3797 MINT_IN_BREAK;
3798 MINT_IN_CASE(MINT_BRFALSE_R4)
3799 ZEROP_S(f_r4, ==);
3800 MINT_IN_BREAK;
3801 MINT_IN_CASE(MINT_BRFALSE_R8)
3802 ZEROP_S(f, ==);
3803 MINT_IN_BREAK;
3804 MINT_IN_CASE(MINT_BRTRUE_I4_S)
3805 ZEROP_S(i, !=);
3806 MINT_IN_BREAK;
3807 MINT_IN_CASE(MINT_BRTRUE_I8_S)
3808 ZEROP_S(l, !=);
3809 MINT_IN_BREAK;
3810 MINT_IN_CASE(MINT_BRTRUE_R4_S)
3811 ZEROP_S(f_r4, !=);
3812 MINT_IN_BREAK;
3813 MINT_IN_CASE(MINT_BRTRUE_R8_S)
3814 ZEROP_S(f, !=);
3815 MINT_IN_BREAK;
3816 MINT_IN_CASE(MINT_BRTRUE_I4)
3817 ZEROP(i, !=);
3818 MINT_IN_BREAK;
3819 MINT_IN_CASE(MINT_BRTRUE_I8)
3820 ZEROP(l, !=);
3821 MINT_IN_BREAK;
3822 MINT_IN_CASE(MINT_BRTRUE_R4)
3823 ZEROP(f_r4, !=);
3824 MINT_IN_BREAK;
3825 MINT_IN_CASE(MINT_BRTRUE_R8)
3826 ZEROP(f, !=);
3827 MINT_IN_BREAK;
3828 #define CONDBR_S(cond) \
3829 sp -= 2; \
3830 if (cond) \
3831 ip += * (gint16 *)(ip + 1); \
3832 else \
3833 ip += 2;
3834 #define BRELOP_S(datamem, op) \
3835 CONDBR_S(sp[0].data.datamem op sp[1].data.datamem)
3837 #define CONDBR(cond) \
3838 sp -= 2; \
3839 if (cond) \
3840 ip += (gint32)READ32(ip + 1); \
3841 else \
3842 ip += 3;
3844 #define BRELOP(datamem, op) \
3845 CONDBR(sp[0].data.datamem op sp[1].data.datamem)
3847 MINT_IN_CASE(MINT_BEQ_I4_S)
3848 BRELOP_S(i, ==)
3849 MINT_IN_BREAK;
3850 MINT_IN_CASE(MINT_BEQ_I8_S)
3851 BRELOP_S(l, ==)
3852 MINT_IN_BREAK;
3853 MINT_IN_CASE(MINT_BEQ_R4_S)
3854 CONDBR_S(!isunordered (sp [0].data.f_r4, sp [1].data.f_r4) && sp[0].data.f_r4 == sp[1].data.f_r4)
3855 MINT_IN_BREAK;
3856 MINT_IN_CASE(MINT_BEQ_R8_S)
3857 CONDBR_S(!mono_isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f == sp[1].data.f)
3858 MINT_IN_BREAK;
3859 MINT_IN_CASE(MINT_BEQ_I4)
3860 BRELOP(i, ==)
3861 MINT_IN_BREAK;
3862 MINT_IN_CASE(MINT_BEQ_I8)
3863 BRELOP(l, ==)
3864 MINT_IN_BREAK;
3865 MINT_IN_CASE(MINT_BEQ_R4)
3866 CONDBR(!isunordered (sp [0].data.f_r4, sp [1].data.f_r4) && sp[0].data.f_r4 == sp[1].data.f_r4)
3867 MINT_IN_BREAK;
3868 MINT_IN_CASE(MINT_BEQ_R8)
3869 CONDBR(!mono_isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f == sp[1].data.f)
3870 MINT_IN_BREAK;
3871 MINT_IN_CASE(MINT_BGE_I4_S)
3872 BRELOP_S(i, >=)
3873 MINT_IN_BREAK;
3874 MINT_IN_CASE(MINT_BGE_I8_S)
3875 BRELOP_S(l, >=)
3876 MINT_IN_BREAK;
3877 MINT_IN_CASE(MINT_BGE_R4_S)
3878 CONDBR_S(!isunordered (sp [0].data.f_r4, sp [1].data.f_r4) && sp[0].data.f_r4 >= sp[1].data.f_r4)
3879 MINT_IN_BREAK;
3880 MINT_IN_CASE(MINT_BGE_R8_S)
3881 CONDBR_S(!mono_isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f >= sp[1].data.f)
3882 MINT_IN_BREAK;
3883 MINT_IN_CASE(MINT_BGE_I4)
3884 BRELOP(i, >=)
3885 MINT_IN_BREAK;
3886 MINT_IN_CASE(MINT_BGE_I8)
3887 BRELOP(l, >=)
3888 MINT_IN_BREAK;
3889 MINT_IN_CASE(MINT_BGE_R4)
3890 CONDBR(!isunordered (sp [0].data.f_r4, sp [1].data.f_r4) && sp[0].data.f_r4 >= sp[1].data.f_r4)
3891 MINT_IN_BREAK;
3892 MINT_IN_CASE(MINT_BGE_R8)
3893 CONDBR(!mono_isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f >= sp[1].data.f)
3894 MINT_IN_BREAK;
3895 MINT_IN_CASE(MINT_BGT_I4_S)
3896 BRELOP_S(i, >)
3897 MINT_IN_BREAK;
3898 MINT_IN_CASE(MINT_BGT_I8_S)
3899 BRELOP_S(l, >)
3900 MINT_IN_BREAK;
3901 MINT_IN_CASE(MINT_BGT_R4_S)
3902 CONDBR_S(!isunordered (sp [0].data.f_r4, sp [1].data.f_r4) && sp[0].data.f_r4 > sp[1].data.f_r4)
3903 MINT_IN_BREAK;
3904 MINT_IN_CASE(MINT_BGT_R8_S)
3905 CONDBR_S(!mono_isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f > sp[1].data.f)
3906 MINT_IN_BREAK;
3907 MINT_IN_CASE(MINT_BGT_I4)
3908 BRELOP(i, >)
3909 MINT_IN_BREAK;
3910 MINT_IN_CASE(MINT_BGT_I8)
3911 BRELOP(l, >)
3912 MINT_IN_BREAK;
3913 MINT_IN_CASE(MINT_BGT_R4)
3914 CONDBR(!isunordered (sp [0].data.f_r4, sp [1].data.f_r4) && sp[0].data.f_r4 > sp[1].data.f_r4)
3915 MINT_IN_BREAK;
3916 MINT_IN_CASE(MINT_BGT_R8)
3917 CONDBR(!mono_isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f > sp[1].data.f)
3918 MINT_IN_BREAK;
3919 MINT_IN_CASE(MINT_BLT_I4_S)
3920 BRELOP_S(i, <)
3921 MINT_IN_BREAK;
3922 MINT_IN_CASE(MINT_BLT_I8_S)
3923 BRELOP_S(l, <)
3924 MINT_IN_BREAK;
3925 MINT_IN_CASE(MINT_BLT_R4_S)
3926 CONDBR_S(!isunordered (sp [0].data.f_r4, sp [1].data.f_r4) && sp[0].data.f_r4 < sp[1].data.f_r4)
3927 MINT_IN_BREAK;
3928 MINT_IN_CASE(MINT_BLT_R8_S)
3929 CONDBR_S(!mono_isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f < sp[1].data.f)
3930 MINT_IN_BREAK;
3931 MINT_IN_CASE(MINT_BLT_I4)
3932 BRELOP(i, <)
3933 MINT_IN_BREAK;
3934 MINT_IN_CASE(MINT_BLT_I8)
3935 BRELOP(l, <)
3936 MINT_IN_BREAK;
3937 MINT_IN_CASE(MINT_BLT_R4)
3938 CONDBR(!isunordered (sp [0].data.f_r4, sp [1].data.f_r4) && sp[0].data.f_r4 < sp[1].data.f_r4)
3939 MINT_IN_BREAK;
3940 MINT_IN_CASE(MINT_BLT_R8)
3941 CONDBR(!mono_isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f < sp[1].data.f)
3942 MINT_IN_BREAK;
3943 MINT_IN_CASE(MINT_BLE_I4_S)
3944 BRELOP_S(i, <=)
3945 MINT_IN_BREAK;
3946 MINT_IN_CASE(MINT_BLE_I8_S)
3947 BRELOP_S(l, <=)
3948 MINT_IN_BREAK;
3949 MINT_IN_CASE(MINT_BLE_R4_S)
3950 CONDBR_S(!isunordered (sp [0].data.f_r4, sp [1].data.f_r4) && sp[0].data.f_r4 <= sp[1].data.f_r4)
3951 MINT_IN_BREAK;
3952 MINT_IN_CASE(MINT_BLE_R8_S)
3953 CONDBR_S(!mono_isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f <= sp[1].data.f)
3954 MINT_IN_BREAK;
3955 MINT_IN_CASE(MINT_BLE_I4)
3956 BRELOP(i, <=)
3957 MINT_IN_BREAK;
3958 MINT_IN_CASE(MINT_BLE_I8)
3959 BRELOP(l, <=)
3960 MINT_IN_BREAK;
3961 MINT_IN_CASE(MINT_BLE_R4)
3962 CONDBR(!isunordered (sp [0].data.f_r4, sp [1].data.f_r4) && sp[0].data.f_r4 <= sp[1].data.f_r4)
3963 MINT_IN_BREAK;
3964 MINT_IN_CASE(MINT_BLE_R8)
3965 CONDBR(!mono_isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f <= sp[1].data.f)
3966 MINT_IN_BREAK;
3967 MINT_IN_CASE(MINT_BNE_UN_I4_S)
3968 BRELOP_S(i, !=)
3969 MINT_IN_BREAK;
3970 MINT_IN_CASE(MINT_BNE_UN_I8_S)
3971 BRELOP_S(l, !=)
3972 MINT_IN_BREAK;
3973 MINT_IN_CASE(MINT_BNE_UN_R4_S)
3974 CONDBR_S(isunordered (sp [0].data.f_r4, sp [1].data.f_r4) || sp[0].data.f_r4 != sp[1].data.f_r4)
3975 MINT_IN_BREAK;
3976 MINT_IN_CASE(MINT_BNE_UN_R8_S)
3977 CONDBR_S(mono_isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f != sp[1].data.f)
3978 MINT_IN_BREAK;
3979 MINT_IN_CASE(MINT_BNE_UN_I4)
3980 BRELOP(i, !=)
3981 MINT_IN_BREAK;
3982 MINT_IN_CASE(MINT_BNE_UN_I8)
3983 BRELOP(l, !=)
3984 MINT_IN_BREAK;
3985 MINT_IN_CASE(MINT_BNE_UN_R4)
3986 CONDBR(isunordered (sp [0].data.f_r4, sp [1].data.f_r4) || sp[0].data.f_r4 != sp[1].data.f_r4)
3987 MINT_IN_BREAK;
3988 MINT_IN_CASE(MINT_BNE_UN_R8)
3989 CONDBR(mono_isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f != sp[1].data.f)
3990 MINT_IN_BREAK;
3992 #define BRELOP_S_CAST(datamem, op, type) \
3993 sp -= 2; \
3994 if ((type) sp[0].data.datamem op (type) sp[1].data.datamem) \
3995 ip += * (gint16 *)(ip + 1); \
3996 else \
3997 ip += 2;
3999 #define BRELOP_CAST(datamem, op, type) \
4000 sp -= 2; \
4001 if ((type) sp[0].data.datamem op (type) sp[1].data.datamem) \
4002 ip += (gint32)READ32(ip + 1); \
4003 else \
4004 ip += 3;
4006 MINT_IN_CASE(MINT_BGE_UN_I4_S)
4007 BRELOP_S_CAST(i, >=, guint32);
4008 MINT_IN_BREAK;
4009 MINT_IN_CASE(MINT_BGE_UN_I8_S)
4010 BRELOP_S_CAST(l, >=, guint64);
4011 MINT_IN_BREAK;
4012 MINT_IN_CASE(MINT_BGE_UN_R4_S)
4013 CONDBR_S(isunordered (sp [0].data.f_r4, sp [1].data.f_r4) || sp[0].data.f_r4 >= sp[1].data.f_r4)
4014 MINT_IN_BREAK;
4015 MINT_IN_CASE(MINT_BGE_UN_R8_S)
4016 CONDBR_S(mono_isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f >= sp[1].data.f)
4017 MINT_IN_BREAK;
4018 MINT_IN_CASE(MINT_BGE_UN_I4)
4019 BRELOP_CAST(i, >=, guint32);
4020 MINT_IN_BREAK;
4021 MINT_IN_CASE(MINT_BGE_UN_I8)
4022 BRELOP_CAST(l, >=, guint64);
4023 MINT_IN_BREAK;
4024 MINT_IN_CASE(MINT_BGE_UN_R4)
4025 CONDBR(isunordered (sp [0].data.f_r4, sp [1].data.f_r4) || sp[0].data.f_r4 >= sp[1].data.f_r4)
4026 MINT_IN_BREAK;
4027 MINT_IN_CASE(MINT_BGE_UN_R8)
4028 CONDBR(mono_isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f >= sp[1].data.f)
4029 MINT_IN_BREAK;
4030 MINT_IN_CASE(MINT_BGT_UN_I4_S)
4031 BRELOP_S_CAST(i, >, guint32);
4032 MINT_IN_BREAK;
4033 MINT_IN_CASE(MINT_BGT_UN_I8_S)
4034 BRELOP_S_CAST(l, >, guint64);
4035 MINT_IN_BREAK;
4036 MINT_IN_CASE(MINT_BGT_UN_R4_S)
4037 CONDBR_S(isunordered (sp [0].data.f_r4, sp [1].data.f_r4) || sp[0].data.f_r4 > sp[1].data.f_r4)
4038 MINT_IN_BREAK;
4039 MINT_IN_CASE(MINT_BGT_UN_R8_S)
4040 CONDBR_S(mono_isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f > sp[1].data.f)
4041 MINT_IN_BREAK;
4042 MINT_IN_CASE(MINT_BGT_UN_I4)
4043 BRELOP_CAST(i, >, guint32);
4044 MINT_IN_BREAK;
4045 MINT_IN_CASE(MINT_BGT_UN_I8)
4046 BRELOP_CAST(l, >, guint64);
4047 MINT_IN_BREAK;
4048 MINT_IN_CASE(MINT_BGT_UN_R4)
4049 CONDBR(isunordered (sp [0].data.f_r4, sp [1].data.f_r4) || sp[0].data.f_r4 > sp[1].data.f_r4)
4050 MINT_IN_BREAK;
4051 MINT_IN_CASE(MINT_BGT_UN_R8)
4052 CONDBR(mono_isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f > sp[1].data.f)
4053 MINT_IN_BREAK;
4054 MINT_IN_CASE(MINT_BLE_UN_I4_S)
4055 BRELOP_S_CAST(i, <=, guint32);
4056 MINT_IN_BREAK;
4057 MINT_IN_CASE(MINT_BLE_UN_I8_S)
4058 BRELOP_S_CAST(l, <=, guint64);
4059 MINT_IN_BREAK;
4060 MINT_IN_CASE(MINT_BLE_UN_R4_S)
4061 CONDBR_S(isunordered (sp [0].data.f_r4, sp [1].data.f_r4) || sp[0].data.f_r4 <= sp[1].data.f_r4)
4062 MINT_IN_BREAK;
4063 MINT_IN_CASE(MINT_BLE_UN_R8_S)
4064 CONDBR_S(mono_isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f <= sp[1].data.f)
4065 MINT_IN_BREAK;
4066 MINT_IN_CASE(MINT_BLE_UN_I4)
4067 BRELOP_CAST(i, <=, guint32);
4068 MINT_IN_BREAK;
4069 MINT_IN_CASE(MINT_BLE_UN_I8)
4070 BRELOP_CAST(l, <=, guint64);
4071 MINT_IN_BREAK;
4072 MINT_IN_CASE(MINT_BLE_UN_R4)
4073 CONDBR(isunordered (sp [0].data.f_r4, sp [1].data.f_r4) || sp[0].data.f_r4 <= sp[1].data.f_r4)
4074 MINT_IN_BREAK;
4075 MINT_IN_CASE(MINT_BLE_UN_R8)
4076 CONDBR(mono_isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f <= sp[1].data.f)
4077 MINT_IN_BREAK;
4078 MINT_IN_CASE(MINT_BLT_UN_I4_S)
4079 BRELOP_S_CAST(i, <, guint32);
4080 MINT_IN_BREAK;
4081 MINT_IN_CASE(MINT_BLT_UN_I8_S)
4082 BRELOP_S_CAST(l, <, guint64);
4083 MINT_IN_BREAK;
4084 MINT_IN_CASE(MINT_BLT_UN_R4_S)
4085 CONDBR_S(isunordered (sp [0].data.f_r4, sp [1].data.f_r4) || sp[0].data.f_r4 < sp[1].data.f_r4)
4086 MINT_IN_BREAK;
4087 MINT_IN_CASE(MINT_BLT_UN_R8_S)
4088 CONDBR_S(mono_isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f < sp[1].data.f)
4089 MINT_IN_BREAK;
4090 MINT_IN_CASE(MINT_BLT_UN_I4)
4091 BRELOP_CAST(i, <, guint32);
4092 MINT_IN_BREAK;
4093 MINT_IN_CASE(MINT_BLT_UN_I8)
4094 BRELOP_CAST(l, <, guint64);
4095 MINT_IN_BREAK;
4096 MINT_IN_CASE(MINT_BLT_UN_R4)
4097 CONDBR(isunordered (sp [0].data.f_r4, sp [1].data.f_r4) || sp[0].data.f_r4 < sp[1].data.f_r4)
4098 MINT_IN_BREAK;
4099 MINT_IN_CASE(MINT_BLT_UN_R8)
4100 CONDBR(mono_isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f < sp[1].data.f)
4101 MINT_IN_BREAK;
4102 MINT_IN_CASE(MINT_SWITCH) {
4103 guint32 n;
4104 const unsigned short *st;
4105 ++ip;
4106 n = READ32 (ip);
4107 ip += 2;
4108 st = ip + 2 * n;
4109 --sp;
4110 if ((guint32)sp->data.i < n) {
4111 gint offset;
4112 ip += 2 * (guint32)sp->data.i;
4113 offset = READ32 (ip);
4114 ip = ip + offset;
4115 } else {
4116 ip = st;
4118 MINT_IN_BREAK;
4120 MINT_IN_CASE(MINT_LDIND_I1_CHECK)
4121 NULL_CHECK (sp [-1].data.p);
4122 ++ip;
4123 sp[-1].data.i = *(gint8*)sp[-1].data.p;
4124 MINT_IN_BREAK;
4125 MINT_IN_CASE(MINT_LDIND_U1_CHECK)
4126 NULL_CHECK (sp [-1].data.p);
4127 ++ip;
4128 sp[-1].data.i = *(guint8*)sp[-1].data.p;
4129 MINT_IN_BREAK;
4130 MINT_IN_CASE(MINT_LDIND_I2_CHECK)
4131 NULL_CHECK (sp [-1].data.p);
4132 ++ip;
4133 sp[-1].data.i = *(gint16*)sp[-1].data.p;
4134 MINT_IN_BREAK;
4135 MINT_IN_CASE(MINT_LDIND_U2_CHECK)
4136 NULL_CHECK (sp [-1].data.p);
4137 ++ip;
4138 sp[-1].data.i = *(guint16*)sp[-1].data.p;
4139 MINT_IN_BREAK;
4140 MINT_IN_CASE(MINT_LDIND_I4_CHECK) /* Fall through */
4141 MINT_IN_CASE(MINT_LDIND_U4_CHECK)
4142 NULL_CHECK (sp [-1].data.p);
4143 ++ip;
4144 sp[-1].data.i = *(gint32*)sp[-1].data.p;
4145 MINT_IN_BREAK;
4146 MINT_IN_CASE(MINT_LDIND_I8_CHECK)
4147 NULL_CHECK (sp [-1].data.p);
4148 ++ip;
4149 #ifdef NO_UNALIGNED_ACCESS
4150 if ((gsize)sp [-1].data.p % SIZEOF_VOID_P)
4151 memcpy (&sp [-1].data.l, sp [-1].data.p, sizeof (gint64));
4152 else
4153 #endif
4154 sp[-1].data.l = *(gint64*)sp[-1].data.p;
4155 MINT_IN_BREAK;
4156 MINT_IN_CASE(MINT_LDIND_I) {
4157 guint16 offset = * (guint16 *)(ip + 1);
4158 sp[-1 - offset].data.p = *(gpointer*)sp[-1 - offset].data.p;
4159 ip += 2;
4160 MINT_IN_BREAK;
4162 MINT_IN_CASE(MINT_LDIND_I8) {
4163 guint16 offset = * (guint16 *)(ip + 1);
4164 #ifdef NO_UNALIGNED_ACCESS
4165 if ((gsize)sp [-1 - offset].data.p % SIZEOF_VOID_P)
4166 memcpy (&sp [-1 - offset].data.l, sp [-1 - offset].data.p, sizeof (gint64));
4167 else
4168 #endif
4169 sp[-1 - offset].data.l = *(gint64*)sp[-1 - offset].data.p;
4170 ip += 2;
4171 MINT_IN_BREAK;
4173 MINT_IN_CASE(MINT_LDIND_R4_CHECK)
4174 NULL_CHECK (sp [-1].data.p);
4175 ++ip;
4176 sp[-1].data.f_r4 = *(gfloat*)sp[-1].data.p;
4177 MINT_IN_BREAK;
4178 MINT_IN_CASE(MINT_LDIND_R8_CHECK)
4179 NULL_CHECK (sp [-1].data.p);
4180 ++ip;
4181 #ifdef NO_UNALIGNED_ACCESS
4182 if ((gsize)sp [-1].data.p % SIZEOF_VOID_P)
4183 memcpy (&sp [-1].data.f, sp [-1].data.p, sizeof (gdouble));
4184 else
4185 #endif
4186 sp[-1].data.f = *(gdouble*)sp[-1].data.p;
4187 MINT_IN_BREAK;
4188 MINT_IN_CASE(MINT_LDIND_REF)
4189 ++ip;
4190 sp[-1].data.p = *(gpointer*)sp[-1].data.p;
4191 MINT_IN_BREAK;
4192 MINT_IN_CASE(MINT_LDIND_REF_CHECK) {
4193 NULL_CHECK (sp [-1].data.p);
4194 ++ip;
4195 sp [-1].data.p = *(gpointer*)sp [-1].data.p;
4196 MINT_IN_BREAK;
4198 MINT_IN_CASE(MINT_STIND_REF)
4199 ++ip;
4200 sp -= 2;
4201 mono_gc_wbarrier_generic_store_internal (sp->data.p, sp [1].data.o);
4202 MINT_IN_BREAK;
4203 MINT_IN_CASE(MINT_STIND_I1)
4204 ++ip;
4205 sp -= 2;
4206 * (gint8 *) sp->data.p = (gint8)sp[1].data.i;
4207 MINT_IN_BREAK;
4208 MINT_IN_CASE(MINT_STIND_I2)
4209 ++ip;
4210 sp -= 2;
4211 * (gint16 *) sp->data.p = (gint16)sp[1].data.i;
4212 MINT_IN_BREAK;
4213 MINT_IN_CASE(MINT_STIND_I4)
4214 ++ip;
4215 sp -= 2;
4216 * (gint32 *) sp->data.p = sp[1].data.i;
4217 MINT_IN_BREAK;
4218 MINT_IN_CASE(MINT_STIND_I)
4219 ++ip;
4220 sp -= 2;
4221 * (mono_i *) sp->data.p = (mono_i)sp[1].data.p;
4222 MINT_IN_BREAK;
4223 MINT_IN_CASE(MINT_STIND_I8)
4224 ++ip;
4225 sp -= 2;
4226 #ifdef NO_UNALIGNED_ACCESS
4227 if ((gsize)sp->data.p % SIZEOF_VOID_P)
4228 memcpy (sp->data.p, &sp [1].data.l, sizeof (gint64));
4229 else
4230 #endif
4231 * (gint64 *) sp->data.p = sp[1].data.l;
4232 MINT_IN_BREAK;
4233 MINT_IN_CASE(MINT_STIND_R4)
4234 ++ip;
4235 sp -= 2;
4236 * (float *) sp->data.p = sp[1].data.f_r4;
4237 MINT_IN_BREAK;
4238 MINT_IN_CASE(MINT_STIND_R8)
4239 ++ip;
4240 sp -= 2;
4241 #ifdef NO_UNALIGNED_ACCESS
4242 if ((gsize)sp->data.p % SIZEOF_VOID_P)
4243 memcpy (sp->data.p, &sp [1].data.f, sizeof (double));
4244 else
4245 #endif
4246 * (double *) sp->data.p = sp[1].data.f;
4247 MINT_IN_BREAK;
4248 MINT_IN_CASE(MINT_MONO_ATOMIC_STORE_I4)
4249 ++ip;
4250 sp -= 2;
4251 mono_atomic_store_i32 ((gint32 *) sp->data.p, sp [1].data.i);
4252 MINT_IN_BREAK;
4253 #define BINOP(datamem, op) \
4254 --sp; \
4255 sp [-1].data.datamem = sp [-1].data.datamem op sp [0].data.datamem; \
4256 ++ip;
4257 MINT_IN_CASE(MINT_ADD_I4)
4258 BINOP(i, +);
4259 MINT_IN_BREAK;
4260 MINT_IN_CASE(MINT_ADD_I8)
4261 BINOP(l, +);
4262 MINT_IN_BREAK;
4263 MINT_IN_CASE(MINT_ADD_R4)
4264 BINOP(f_r4, +);
4265 MINT_IN_BREAK;
4266 MINT_IN_CASE(MINT_ADD_R8)
4267 BINOP(f, +);
4268 MINT_IN_BREAK;
4269 MINT_IN_CASE(MINT_ADD1_I4)
4270 ++sp [-1].data.i;
4271 ++ip;
4272 MINT_IN_BREAK;
4273 MINT_IN_CASE(MINT_ADD1_I8)
4274 ++sp [-1].data.l;
4275 ++ip;
4276 MINT_IN_BREAK;
4277 MINT_IN_CASE(MINT_SUB_I4)
4278 BINOP(i, -);
4279 MINT_IN_BREAK;
4280 MINT_IN_CASE(MINT_SUB_I8)
4281 BINOP(l, -);
4282 MINT_IN_BREAK;
4283 MINT_IN_CASE(MINT_SUB_R4)
4284 BINOP(f_r4, -);
4285 MINT_IN_BREAK;
4286 MINT_IN_CASE(MINT_SUB_R8)
4287 BINOP(f, -);
4288 MINT_IN_BREAK;
4289 MINT_IN_CASE(MINT_SUB1_I4)
4290 --sp [-1].data.i;
4291 ++ip;
4292 MINT_IN_BREAK;
4293 MINT_IN_CASE(MINT_SUB1_I8)
4294 --sp [-1].data.l;
4295 ++ip;
4296 MINT_IN_BREAK;
4297 MINT_IN_CASE(MINT_MUL_I4)
4298 BINOP(i, *);
4299 MINT_IN_BREAK;
4300 MINT_IN_CASE(MINT_MUL_I8)
4301 BINOP(l, *);
4302 MINT_IN_BREAK;
4303 MINT_IN_CASE(MINT_MUL_R4)
4304 BINOP(f_r4, *);
4305 MINT_IN_BREAK;
4306 MINT_IN_CASE(MINT_MUL_R8)
4307 BINOP(f, *);
4308 MINT_IN_BREAK;
4309 MINT_IN_CASE(MINT_DIV_I4)
4310 if (sp [-1].data.i == 0)
4311 goto div_zero_label;
4312 if (sp [-1].data.i == (-1) && sp [-2].data.i == G_MININT32)
4313 goto overflow_label;
4314 BINOP(i, /);
4315 MINT_IN_BREAK;
4316 MINT_IN_CASE(MINT_DIV_I8)
4317 if (sp [-1].data.l == 0)
4318 goto div_zero_label;
4319 if (sp [-1].data.l == (-1) && sp [-2].data.l == G_MININT64)
4320 goto overflow_label;
4321 BINOP(l, /);
4322 MINT_IN_BREAK;
4323 MINT_IN_CASE(MINT_DIV_R4)
4324 BINOP(f_r4, /);
4325 MINT_IN_BREAK;
4326 MINT_IN_CASE(MINT_DIV_R8)
4327 BINOP(f, /);
4328 MINT_IN_BREAK;
4330 #define BINOP_CAST(datamem, op, type) \
4331 --sp; \
4332 sp [-1].data.datamem = (type)sp [-1].data.datamem op (type)sp [0].data.datamem; \
4333 ++ip;
4334 MINT_IN_CASE(MINT_DIV_UN_I4)
4335 if (sp [-1].data.i == 0)
4336 goto div_zero_label;
4337 BINOP_CAST(i, /, guint32);
4338 MINT_IN_BREAK;
4339 MINT_IN_CASE(MINT_DIV_UN_I8)
4340 if (sp [-1].data.l == 0)
4341 goto div_zero_label;
4342 BINOP_CAST(l, /, guint64);
4343 MINT_IN_BREAK;
4344 MINT_IN_CASE(MINT_REM_I4)
4345 if (sp [-1].data.i == 0)
4346 goto div_zero_label;
4347 if (sp [-1].data.i == (-1) && sp [-2].data.i == G_MININT32)
4348 goto overflow_label;
4349 BINOP(i, %);
4350 MINT_IN_BREAK;
4351 MINT_IN_CASE(MINT_REM_I8)
4352 if (sp [-1].data.l == 0)
4353 goto div_zero_label;
4354 if (sp [-1].data.l == (-1) && sp [-2].data.l == G_MININT64)
4355 goto overflow_label;
4356 BINOP(l, %);
4357 MINT_IN_BREAK;
4358 MINT_IN_CASE(MINT_REM_R4)
4359 /* FIXME: what do we actually do here? */
4360 --sp;
4361 sp [-1].data.f_r4 = fmodf (sp [-1].data.f_r4, sp [0].data.f_r4);
4362 ++ip;
4363 MINT_IN_BREAK;
4364 MINT_IN_CASE(MINT_REM_R8)
4365 /* FIXME: what do we actually do here? */
4366 --sp;
4367 sp [-1].data.f = fmod (sp [-1].data.f, sp [0].data.f);
4368 ++ip;
4369 MINT_IN_BREAK;
4370 MINT_IN_CASE(MINT_REM_UN_I4)
4371 if (sp [-1].data.i == 0)
4372 goto div_zero_label;
4373 BINOP_CAST(i, %, guint32);
4374 MINT_IN_BREAK;
4375 MINT_IN_CASE(MINT_REM_UN_I8)
4376 if (sp [-1].data.l == 0)
4377 goto div_zero_label;
4378 BINOP_CAST(l, %, guint64);
4379 MINT_IN_BREAK;
4380 MINT_IN_CASE(MINT_AND_I4)
4381 BINOP(i, &);
4382 MINT_IN_BREAK;
4383 MINT_IN_CASE(MINT_AND_I8)
4384 BINOP(l, &);
4385 MINT_IN_BREAK;
4386 MINT_IN_CASE(MINT_OR_I4)
4387 BINOP(i, |);
4388 MINT_IN_BREAK;
4389 MINT_IN_CASE(MINT_OR_I8)
4390 BINOP(l, |);
4391 MINT_IN_BREAK;
4392 MINT_IN_CASE(MINT_XOR_I4)
4393 BINOP(i, ^);
4394 MINT_IN_BREAK;
4395 MINT_IN_CASE(MINT_XOR_I8)
4396 BINOP(l, ^);
4397 MINT_IN_BREAK;
4399 #define SHIFTOP(datamem, op) \
4400 --sp; \
4401 sp [-1].data.datamem = sp [-1].data.datamem op sp [0].data.i; \
4402 ++ip;
4404 MINT_IN_CASE(MINT_SHL_I4)
4405 SHIFTOP(i, <<);
4406 MINT_IN_BREAK;
4407 MINT_IN_CASE(MINT_SHL_I8)
4408 SHIFTOP(l, <<);
4409 MINT_IN_BREAK;
4410 MINT_IN_CASE(MINT_SHR_I4)
4411 SHIFTOP(i, >>);
4412 MINT_IN_BREAK;
4413 MINT_IN_CASE(MINT_SHR_I8)
4414 SHIFTOP(l, >>);
4415 MINT_IN_BREAK;
4416 MINT_IN_CASE(MINT_SHR_UN_I4)
4417 --sp;
4418 sp [-1].data.i = (guint32)sp [-1].data.i >> sp [0].data.i;
4419 ++ip;
4420 MINT_IN_BREAK;
4421 MINT_IN_CASE(MINT_SHR_UN_I8)
4422 --sp;
4423 sp [-1].data.l = (guint64)sp [-1].data.l >> sp [0].data.i;
4424 ++ip;
4425 MINT_IN_BREAK;
4426 MINT_IN_CASE(MINT_NEG_I4)
4427 sp [-1].data.i = - sp [-1].data.i;
4428 ++ip;
4429 MINT_IN_BREAK;
4430 MINT_IN_CASE(MINT_NEG_I8)
4431 sp [-1].data.l = - sp [-1].data.l;
4432 ++ip;
4433 MINT_IN_BREAK;
4434 MINT_IN_CASE(MINT_NEG_R4)
4435 sp [-1].data.f_r4 = - sp [-1].data.f_r4;
4436 ++ip;
4437 MINT_IN_BREAK;
4438 MINT_IN_CASE(MINT_NEG_R8)
4439 sp [-1].data.f = - sp [-1].data.f;
4440 ++ip;
4441 MINT_IN_BREAK;
4442 MINT_IN_CASE(MINT_NOT_I4)
4443 sp [-1].data.i = ~ sp [-1].data.i;
4444 ++ip;
4445 MINT_IN_BREAK;
4446 MINT_IN_CASE(MINT_NOT_I8)
4447 sp [-1].data.l = ~ sp [-1].data.l;
4448 ++ip;
4449 MINT_IN_BREAK;
4450 MINT_IN_CASE(MINT_CONV_I1_I4)
4451 sp [-1].data.i = (gint8)sp [-1].data.i;
4452 ++ip;
4453 MINT_IN_BREAK;
4454 MINT_IN_CASE(MINT_CONV_I1_I8)
4455 sp [-1].data.i = (gint8)sp [-1].data.l;
4456 ++ip;
4457 MINT_IN_BREAK;
4458 MINT_IN_CASE(MINT_CONV_I1_R4)
4459 sp [-1].data.i = (gint8) (gint32) sp [-1].data.f_r4;
4460 ++ip;
4461 MINT_IN_BREAK;
4462 MINT_IN_CASE(MINT_CONV_I1_R8)
4463 /* without gint32 cast, C compiler is allowed to use undefined
4464 * behaviour if data.f is bigger than >255. See conv.fpint section
4465 * in C standard:
4466 * > The conversion truncates; that is, the fractional part
4467 * > is discarded. The behavior is undefined if the truncated
4468 * > value cannot be represented in the destination type.
4469 * */
4470 sp [-1].data.i = (gint8) (gint32) sp [-1].data.f;
4471 ++ip;
4472 MINT_IN_BREAK;
4473 MINT_IN_CASE(MINT_CONV_U1_I4)
4474 sp [-1].data.i = (guint8)sp [-1].data.i;
4475 ++ip;
4476 MINT_IN_BREAK;
4477 MINT_IN_CASE(MINT_CONV_U1_I8)
4478 sp [-1].data.i = (guint8)sp [-1].data.l;
4479 ++ip;
4480 MINT_IN_BREAK;
4481 MINT_IN_CASE(MINT_CONV_U1_R4)
4482 sp [-1].data.i = (guint8) (guint32) sp [-1].data.f_r4;
4483 ++ip;
4484 MINT_IN_BREAK;
4485 MINT_IN_CASE(MINT_CONV_U1_R8)
4486 sp [-1].data.i = (guint8) (guint32) sp [-1].data.f;
4487 ++ip;
4488 MINT_IN_BREAK;
4489 MINT_IN_CASE(MINT_CONV_I2_I4)
4490 sp [-1].data.i = (gint16)sp [-1].data.i;
4491 ++ip;
4492 MINT_IN_BREAK;
4493 MINT_IN_CASE(MINT_CONV_I2_I8)
4494 sp [-1].data.i = (gint16)sp [-1].data.l;
4495 ++ip;
4496 MINT_IN_BREAK;
4497 MINT_IN_CASE(MINT_CONV_I2_R4)
4498 sp [-1].data.i = (gint16) (gint32) sp [-1].data.f_r4;
4499 ++ip;
4500 MINT_IN_BREAK;
4501 MINT_IN_CASE(MINT_CONV_I2_R8)
4502 sp [-1].data.i = (gint16) (gint32) sp [-1].data.f;
4503 ++ip;
4504 MINT_IN_BREAK;
4505 MINT_IN_CASE(MINT_CONV_U2_I4)
4506 sp [-1].data.i = (guint16)sp [-1].data.i;
4507 ++ip;
4508 MINT_IN_BREAK;
4509 MINT_IN_CASE(MINT_CONV_U2_I8)
4510 sp [-1].data.i = (guint16)sp [-1].data.l;
4511 ++ip;
4512 MINT_IN_BREAK;
4513 MINT_IN_CASE(MINT_CONV_U2_R4)
4514 sp [-1].data.i = (guint16) (guint32) sp [-1].data.f_r4;
4515 ++ip;
4516 MINT_IN_BREAK;
4517 MINT_IN_CASE(MINT_CONV_U2_R8)
4518 sp [-1].data.i = (guint16) (guint32) sp [-1].data.f;
4519 ++ip;
4520 MINT_IN_BREAK;
4521 MINT_IN_CASE(MINT_CONV_I4_R4)
4522 sp [-1].data.i = (gint32) sp [-1].data.f_r4;
4523 ++ip;
4524 MINT_IN_BREAK;
4525 MINT_IN_CASE(MINT_CONV_I4_R8)
4526 sp [-1].data.i = (gint32)sp [-1].data.f;
4527 ++ip;
4528 MINT_IN_BREAK;
4529 MINT_IN_CASE(MINT_CONV_U4_I8)
4530 MINT_IN_CASE(MINT_CONV_I4_I8)
4531 sp [-1].data.i = (gint32)sp [-1].data.l;
4532 ++ip;
4533 MINT_IN_BREAK;
4534 MINT_IN_CASE(MINT_CONV_I4_I8_SP)
4535 sp [-2].data.i = (gint32)sp [-2].data.l;
4536 ++ip;
4537 MINT_IN_BREAK;
4538 MINT_IN_CASE(MINT_CONV_U4_R4)
4539 #ifdef MONO_ARCH_EMULATE_FCONV_TO_U4
4540 sp [-1].data.i = mono_rconv_u4 (sp [-1].data.f_r4);
4541 #else
4542 sp [-1].data.i = (guint32) sp [-1].data.f_r4;
4543 #endif
4544 ++ip;
4545 MINT_IN_BREAK;
4546 MINT_IN_CASE(MINT_CONV_U4_R8)
4547 #ifdef MONO_ARCH_EMULATE_FCONV_TO_U4
4548 sp [-1].data.i = mono_fconv_u4_2 (sp [-1].data.f);
4549 #else
4550 sp [-1].data.i = (guint32) sp [-1].data.f;
4551 #endif
4552 ++ip;
4553 MINT_IN_BREAK;
4554 MINT_IN_CASE(MINT_CONV_I8_I4)
4555 sp [-1].data.l = sp [-1].data.i;
4556 ++ip;
4557 MINT_IN_BREAK;
4558 MINT_IN_CASE(MINT_CONV_I8_I4_SP)
4559 sp [-2].data.l = sp [-2].data.i;
4560 ++ip;
4561 MINT_IN_BREAK;
4562 MINT_IN_CASE(MINT_CONV_I8_U4)
4563 sp [-1].data.l = (guint32)sp [-1].data.i;
4564 ++ip;
4565 MINT_IN_BREAK;
4566 MINT_IN_CASE(MINT_CONV_I8_R4)
4567 sp [-1].data.l = (gint64) sp [-1].data.f_r4;
4568 ++ip;
4569 MINT_IN_BREAK;
4570 MINT_IN_CASE(MINT_CONV_I8_R8)
4571 sp [-1].data.l = (gint64)sp [-1].data.f;
4572 ++ip;
4573 MINT_IN_BREAK;
4574 MINT_IN_CASE(MINT_CONV_R4_I4)
4575 sp [-1].data.f_r4 = (float)sp [-1].data.i;
4576 ++ip;
4577 MINT_IN_BREAK;
4578 MINT_IN_CASE(MINT_CONV_R4_I8)
4579 sp [-1].data.f_r4 = (float)sp [-1].data.l;
4580 ++ip;
4581 MINT_IN_BREAK;
4582 MINT_IN_CASE(MINT_CONV_R4_R8)
4583 sp [-1].data.f_r4 = (float)sp [-1].data.f;
4584 ++ip;
4585 MINT_IN_BREAK;
4586 MINT_IN_CASE(MINT_CONV_R8_I4)
4587 sp [-1].data.f = (double)sp [-1].data.i;
4588 ++ip;
4589 MINT_IN_BREAK;
4590 MINT_IN_CASE(MINT_CONV_R8_I8)
4591 sp [-1].data.f = (double)sp [-1].data.l;
4592 ++ip;
4593 MINT_IN_BREAK;
4594 MINT_IN_CASE(MINT_CONV_R8_R4)
4595 sp [-1].data.f = (double) sp [-1].data.f_r4;
4596 ++ip;
4597 MINT_IN_BREAK;
4598 MINT_IN_CASE(MINT_CONV_R8_R4_SP)
4599 sp [-2].data.f = (double) sp [-2].data.f_r4;
4600 ++ip;
4601 MINT_IN_BREAK;
4602 MINT_IN_CASE(MINT_CONV_U8_I4)
4603 sp [-1].data.l = sp [-1].data.i & 0xffffffff;
4604 ++ip;
4605 MINT_IN_BREAK;
4606 MINT_IN_CASE(MINT_CONV_U8_R4)
4607 #ifdef MONO_ARCH_EMULATE_FCONV_TO_U8
4608 sp [-1].data.l = mono_rconv_u8 (sp [-1].data.f_r4);
4609 #else
4610 sp [-1].data.l = (guint64) sp [-1].data.f_r4;
4611 #endif
4612 ++ip;
4613 MINT_IN_BREAK;
4614 MINT_IN_CASE(MINT_CONV_U8_R8)
4615 #ifdef MONO_ARCH_EMULATE_FCONV_TO_U8
4616 sp [-1].data.l = mono_fconv_u8_2 (sp [-1].data.f);
4617 #else
4618 sp [-1].data.l = (guint64)sp [-1].data.f;
4619 #endif
4620 ++ip;
4621 MINT_IN_BREAK;
4622 MINT_IN_CASE(MINT_CPOBJ) {
4623 MonoClass* const c = (MonoClass*)frame->imethod->data_items[* (guint16 *)(ip + 1)];
4624 g_assert (m_class_is_valuetype (c));
4625 /* if this assertion fails, we need to add a write barrier */
4626 g_assert (!MONO_TYPE_IS_REFERENCE (m_class_get_byval_arg (c)));
4627 stackval_from_data (m_class_get_byval_arg (c), (stackval*)sp [-2].data.p, sp [-1].data.p, FALSE);
4628 ip += 2;
4629 sp -= 2;
4630 MINT_IN_BREAK;
4632 MINT_IN_CASE(MINT_CPOBJ_VT) {
4633 MonoClass* const c = (MonoClass*)frame->imethod->data_items[* (guint16 *)(ip + 1)];
4634 mono_value_copy_internal (sp [-2].data.vt, sp [-1].data.vt, c);
4635 ip += 2;
4636 sp -= 2;
4637 MINT_IN_BREAK;
4639 MINT_IN_CASE(MINT_LDOBJ_VT) {
4640 int size = READ32(ip + 1);
4641 ip += 3;
4642 memcpy (vt_sp, sp [-1].data.p, size);
4643 sp [-1].data.p = vt_sp;
4644 vt_sp += ALIGN_TO (size, MINT_VT_ALIGNMENT);
4645 MINT_IN_BREAK;
4647 MINT_IN_CASE(MINT_LDSTR)
4648 sp->data.p = frame->imethod->data_items [* (guint16 *)(ip + 1)];
4649 ++sp;
4650 ip += 2;
4651 MINT_IN_BREAK;
4652 MINT_IN_CASE(MINT_LDSTR_TOKEN) {
4653 MonoString *s = NULL;
4654 guint32 strtoken = (guint32)(gsize)frame->imethod->data_items [* (guint16 *)(ip + 1)];
4656 MonoMethod *method = frame->imethod->method;
4657 if (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD) {
4658 s = (MonoString*)mono_method_get_wrapper_data (method, strtoken);
4659 } else if (method->wrapper_type != MONO_WRAPPER_NONE) {
4660 s = mono_string_new_wrapper_internal ((const char*)mono_method_get_wrapper_data (method, strtoken));
4661 } else {
4662 g_assert_not_reached ();
4664 sp->data.p = s;
4665 ++sp;
4666 ip += 2;
4667 MINT_IN_BREAK;
4669 MINT_IN_CASE(MINT_NEWOBJ_ARRAY) {
4670 MonoClass *newobj_class;
4671 guint32 token = * (guint16 *)(ip + 1);
4672 guint16 param_count = * (guint16 *)(ip + 2);
4674 newobj_class = (MonoClass*) frame->imethod->data_items [token];
4676 sp -= param_count;
4677 sp->data.o = ves_array_create (frame->imethod->domain, newobj_class, param_count, sp, error);
4678 if (!is_ok (error))
4679 goto throw_error_label;
4681 ++sp;
4682 ip += 3;
4683 MINT_IN_BREAK;
4685 MINT_IN_CASE(MINT_NEWOBJ_FAST) {
4687 MonoVTable *vtable = (MonoVTable*) frame->imethod->data_items [*(guint16*)(ip + 3)];
4688 INIT_VTABLE (vtable);
4690 MonoObject* o = NULL; // See the comment about GC safety above.
4691 guint16 param_count;
4692 guint16 imethod_index = *(guint16*) (ip + 1);
4694 const gboolean is_inlined = imethod_index == 0xffff;
4696 param_count = *(guint16*)(ip + 2);
4698 if (param_count) {
4699 sp -= param_count;
4700 memmove (sp + 1 + is_inlined, sp, param_count * sizeof (stackval));
4703 frame_objref (frame) = mono_gc_alloc_obj (vtable, m_class_get_instance_size (vtable->klass));
4704 if (G_UNLIKELY (!frame_objref (frame))) {
4705 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", m_class_get_instance_size (vtable->klass));
4706 goto throw_error_label;
4709 sp [0].data.o = frame_objref (frame);
4710 if (is_inlined) {
4711 sp [1].data.o = frame_objref (frame);
4712 sp += param_count + 2;
4713 } else {
4714 InterpMethod *ctor_method = (InterpMethod*) frame->imethod->data_items [imethod_index];
4715 frame->ip = ip;
4717 child_frame.imethod = ctor_method;
4718 child_frame.stack_args = sp;
4720 interp_exec_method (&child_frame, context, error);
4721 CHECK_RESUME_STATE (context);
4722 sp [0].data.o = frame_objref (frame);
4723 sp++;
4725 ip += 4;
4727 MINT_IN_BREAK;
4729 MINT_IN_CASE(MINT_NEWOBJ_VT_FAST)
4730 MINT_IN_CASE(MINT_NEWOBJ_VTST_FAST) {
4732 // This is split up to:
4733 // - conserve stack
4734 // - keep exception handling and resume mostly in the main function
4736 frame->ip = ip;
4737 child_frame.imethod = (InterpMethod*) frame->imethod->data_items [*(guint16*)(ip + 1)];
4738 guint16 const param_count = *(guint16*)(ip + 2);
4740 if (param_count) {
4741 sp -= param_count;
4742 memmove (sp + 1, sp, param_count * sizeof (stackval));
4744 child_frame.stack_args = sp;
4745 gboolean const vtst = *ip == MINT_NEWOBJ_VTST_FAST;
4746 if (vtst) {
4747 memset (vt_sp, 0, *(guint16*)(ip + 3));
4748 sp->data.p = vt_sp;
4749 ip += 4;
4751 interp_exec_method (&child_frame, context, error);
4753 CHECK_RESUME_STATE (context);
4754 sp->data.p = vt_sp;
4756 } else {
4757 ip += 3;
4758 mono_interp_newobj_vt (&child_frame, context, error);
4759 CHECK_RESUME_STATE (context);
4761 ++sp;
4762 MINT_IN_BREAK;
4765 MINT_IN_CASE(MINT_NEWOBJ) {
4767 // This is split up to:
4768 // - conserve stack
4769 // - keep exception handling and resume mostly in the main function
4771 frame->ip = ip;
4773 guint32 const token = * (guint16 *)(ip + 1);
4774 ip += 2; // FIXME: Do this after throw?
4776 child_frame.ip = NULL;
4777 child_frame.ex = NULL;
4779 child_frame.imethod = (InterpMethod*)frame->imethod->data_items [token];
4780 MonoMethodSignature* const csig = mono_method_signature_internal (child_frame.imethod->method);
4782 g_assert (csig->hasthis);
4783 if (csig->param_count) {
4784 sp -= csig->param_count;
4785 memmove (sp + 1, sp, csig->param_count * sizeof (stackval));
4788 child_frame.stack_args = sp;
4790 MonoException* const exc = mono_interp_newobj (&child_frame, context, error, vt_sp);
4791 if (exc)
4792 THROW_EX (exc, ip);
4793 CHECK_RESUME_STATE (context);
4794 ++sp;
4795 MINT_IN_BREAK;
4797 MINT_IN_CASE(MINT_NEWOBJ_MAGIC) {
4798 frame->ip = ip;
4799 ip += 2;
4801 MINT_IN_BREAK;
4803 MINT_IN_CASE(MINT_INTRINS_BYREFERENCE_CTOR) {
4804 MonoMethodSignature *csig;
4805 guint32 token;
4807 frame->ip = ip;
4808 token = * (guint16 *)(ip + 1);
4809 ip += 2;
4811 InterpMethod *cmethod = (InterpMethod*)frame->imethod->data_items [token];
4812 csig = mono_method_signature_internal (cmethod->method);
4814 g_assert (csig->hasthis);
4815 sp -= csig->param_count;
4817 gpointer arg0 = sp [0].data.p;
4819 gpointer *byreference_this = (gpointer*)vt_sp;
4820 *byreference_this = arg0;
4822 /* Followed by a VTRESULT opcode which will push the result on the stack */
4823 ++sp;
4824 MINT_IN_BREAK;
4826 MINT_IN_CASE(MINT_INTRINS_BYREFERENCE_GET_VALUE) {
4827 gpointer *byreference_this = (gpointer*)sp [-1].data.p;
4828 sp [-1].data.p = *byreference_this;
4829 ++ip;
4830 MINT_IN_BREAK;
4832 MINT_IN_CASE(MINT_INTRINS_UNSAFE_ADD_BYTE_OFFSET) {
4833 sp -= 2;
4834 sp [0].data.p = (guint8*)sp [0].data.p + sp [1].data.nati;
4835 sp ++;
4836 ++ip;
4837 MINT_IN_BREAK;
4839 MINT_IN_CASE(MINT_INTRINS_UNSAFE_BYTE_OFFSET) {
4840 sp -= 2;
4841 sp [0].data.nati = (guint8*)sp [1].data.p - (guint8*)sp [0].data.p;
4842 sp ++;
4843 ++ip;
4844 MINT_IN_BREAK;
4846 MINT_IN_CASE(MINT_INTRINS_RUNTIMEHELPERS_OBJECT_HAS_COMPONENT_SIZE) {
4847 sp -= 1;
4848 MonoObject *obj = sp [0].data.o;
4849 sp [0].data.i = (obj->vtable->flags & MONO_VT_FLAG_ARRAY_OR_STRING) != 0;
4850 sp ++;
4851 ++ip;
4852 MINT_IN_BREAK;
4854 MINT_IN_CASE(MINT_CASTCLASS_INTERFACE)
4855 MINT_IN_CASE(MINT_ISINST_INTERFACE) {
4856 MonoObject* const o = sp [-1].data.o; // See the comment about GC safety above.
4857 if (o) {
4858 MonoClass* const c = (MonoClass*)frame->imethod->data_items [*(guint16 *)(ip + 1)];
4859 gboolean isinst;
4860 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (o->vtable, m_class_get_interface_id (c))) {
4861 isinst = TRUE;
4862 } else if (m_class_is_array_special_interface (c) || mono_object_is_transparent_proxy (o)) {
4863 /* slow path */
4864 isinst = mono_interp_isinst (o, c); // FIXME: do not swallow the error
4865 } else {
4866 isinst = FALSE;
4869 if (!isinst) {
4870 gboolean const isinst_instr = *ip == MINT_ISINST_INTERFACE;
4871 if (isinst_instr)
4872 sp [-1].data.p = NULL;
4873 else
4874 goto invalid_cast_label;
4877 ip += 2;
4878 MINT_IN_BREAK;
4880 MINT_IN_CASE(MINT_CASTCLASS_COMMON)
4881 MINT_IN_CASE(MINT_ISINST_COMMON) {
4882 MonoObject* const o = sp [-1].data.o; // See the comment about GC safety above
4883 if (o) {
4884 MonoClass* const c = (MonoClass*)frame->imethod->data_items [*(guint16 *)(ip + 1)];
4885 gboolean isinst = mono_class_has_parent_fast (o->vtable->klass, c);
4887 if (!isinst) {
4888 gboolean const isinst_instr = *ip == MINT_ISINST_COMMON;
4889 if (isinst_instr)
4890 sp [-1].data.p = NULL;
4891 else
4892 goto invalid_cast_label;
4895 ip += 2;
4896 MINT_IN_BREAK;
4898 MINT_IN_CASE(MINT_CASTCLASS)
4899 MINT_IN_CASE(MINT_ISINST) {
4900 MonoObject* const o = sp [-1].data.o; // See the comment about GC safety above
4901 if (o) {
4902 MonoClass* const c = (MonoClass*)frame->imethod->data_items [*(guint16 *)(ip + 1)];
4903 if (!mono_interp_isinst (o, c)) { // FIXME: do not swallow the error
4904 gboolean const isinst_instr = *ip == MINT_ISINST;
4905 if (isinst_instr)
4906 sp [-1].data.p = NULL;
4907 else
4908 goto invalid_cast_label;
4911 ip += 2;
4912 MINT_IN_BREAK;
4914 MINT_IN_CASE(MINT_CONV_R_UN_I4)
4915 sp [-1].data.f = (double)(guint32)sp [-1].data.i;
4916 ++ip;
4917 MINT_IN_BREAK;
4918 MINT_IN_CASE(MINT_CONV_R_UN_I8)
4919 sp [-1].data.f = (double)(guint64)sp [-1].data.l;
4920 ++ip;
4921 MINT_IN_BREAK;
4922 MINT_IN_CASE(MINT_UNBOX) {
4923 MonoObject* const o = sp [-1].data.o; // See the comment about GC safety above
4924 NULL_CHECK (o);
4925 MonoClass* const c = (MonoClass*)frame->imethod->data_items[*(guint16 *)(ip + 1)];
4927 if (!(m_class_get_rank (o->vtable->klass) == 0 && m_class_get_element_class (o->vtable->klass) == m_class_get_element_class (c)))
4928 goto invalid_cast_label;
4930 sp [-1].data.p = mono_object_unbox_internal (o);
4931 ip += 2;
4932 MINT_IN_BREAK;
4934 MINT_IN_CASE(MINT_THROW)
4935 --sp;
4936 if (!sp->data.p)
4937 sp->data.p = mono_get_exception_null_reference ();
4939 THROW_EX ((MonoException *)sp->data.p, ip);
4940 MINT_IN_BREAK;
4941 MINT_IN_CASE(MINT_CHECKPOINT)
4942 /* Do synchronous checking of abort requests */
4943 EXCEPTION_CHECKPOINT;
4944 ++ip;
4945 MINT_IN_BREAK;
4946 MINT_IN_CASE(MINT_SAFEPOINT)
4947 /* Do synchronous checking of abort requests */
4948 EXCEPTION_CHECKPOINT;
4949 /* Poll safepoint */
4950 mono_threads_safepoint ();
4951 ++ip;
4952 MINT_IN_BREAK;
4953 MINT_IN_CASE(MINT_LDFLDA_UNSAFE) {
4954 sp[-1].data.p = (char*)sp [-1].data.o + * (guint16 *)(ip + 1);
4955 ip += 2;
4956 MINT_IN_BREAK;
4958 MINT_IN_CASE(MINT_LDFLDA) {
4959 MonoObject* const o = sp [-1].data.o; // See the comment about GC safety above.
4960 NULL_CHECK (o);
4961 sp[-1].data.p = (char *)o + * (guint16 *)(ip + 1);
4962 ip += 2;
4963 MINT_IN_BREAK;
4965 MINT_IN_CASE(MINT_CKNULL_N) {
4966 /* Same as CKNULL, but further down the stack */
4967 int const n = *(guint16*)(ip + 1);
4968 MonoObject* const o = sp [-n].data.o; // See the comment about GC safety above.
4969 NULL_CHECK (o);
4970 ip += 2;
4971 MINT_IN_BREAK;
4974 #define LDFLD_UNALIGNED(datamem, fieldtype, unaligned) do { \
4975 MonoObject* const o = sp [-1].data.o; \
4976 NULL_CHECK (o); \
4977 if (unaligned) \
4978 memcpy (&sp[-1].data.datamem, (char *)o + * (guint16 *)(ip + 1), sizeof (fieldtype)); \
4979 else \
4980 sp[-1].data.datamem = * (fieldtype *)((char *)o + * (guint16 *)(ip + 1)) ; \
4981 ip += 2; \
4982 } while (0)
4984 #define LDFLD(datamem, fieldtype) LDFLD_UNALIGNED(datamem, fieldtype, FALSE)
4986 MINT_IN_CASE(MINT_LDFLD_I1) LDFLD(i, gint8); MINT_IN_BREAK;
4987 MINT_IN_CASE(MINT_LDFLD_U1) LDFLD(i, guint8); MINT_IN_BREAK;
4988 MINT_IN_CASE(MINT_LDFLD_I2) LDFLD(i, gint16); MINT_IN_BREAK;
4989 MINT_IN_CASE(MINT_LDFLD_U2) LDFLD(i, guint16); MINT_IN_BREAK;
4990 MINT_IN_CASE(MINT_LDFLD_I4) LDFLD(i, gint32); MINT_IN_BREAK;
4991 MINT_IN_CASE(MINT_LDFLD_I8) LDFLD(l, gint64); MINT_IN_BREAK;
4992 MINT_IN_CASE(MINT_LDFLD_R4) LDFLD(f_r4, float); MINT_IN_BREAK;
4993 MINT_IN_CASE(MINT_LDFLD_R8) LDFLD(f, double); MINT_IN_BREAK;
4994 MINT_IN_CASE(MINT_LDFLD_O) LDFLD(p, gpointer); MINT_IN_BREAK;
4995 MINT_IN_CASE(MINT_LDFLD_P) LDFLD(p, gpointer); MINT_IN_BREAK;
4996 MINT_IN_CASE(MINT_LDFLD_I8_UNALIGNED) LDFLD_UNALIGNED(l, gint64, TRUE); MINT_IN_BREAK;
4997 MINT_IN_CASE(MINT_LDFLD_R8_UNALIGNED) LDFLD_UNALIGNED(f, double, TRUE); MINT_IN_BREAK;
4999 MINT_IN_CASE(MINT_LDFLD_VT) {
5000 MonoObject* const o = sp [-1].data.o; // See the comment about GC safety above.
5001 NULL_CHECK (o);
5003 int size = READ32(ip + 2);
5004 sp [-1].data.p = vt_sp;
5005 memcpy (sp [-1].data.p, (char *)o + * (guint16 *)(ip + 1), size);
5006 vt_sp += ALIGN_TO (size, MINT_VT_ALIGNMENT);
5007 ip += 4;
5008 MINT_IN_BREAK;
5011 MINT_IN_CASE(MINT_LDRMFLD) {
5012 MonoObject* const o = sp [-1].data.o; // See the comment about GC safety above.
5013 NULL_CHECK (o);
5014 mono_interp_load_remote_field (frame->imethod, o, ip, sp);
5015 ip += 2;
5016 MINT_IN_BREAK;
5018 MINT_IN_CASE(MINT_LDRMFLD_VT) {
5019 MonoObject* const o = sp [-1].data.o; // See the comment about GC safety above.
5020 NULL_CHECK (o);
5021 vt_sp = mono_interp_load_remote_field_vt (frame->imethod, o, ip, sp, vt_sp);
5022 ip += 2;
5023 MINT_IN_BREAK;
5026 #define STFLD_UNALIGNED(datamem, fieldtype, unaligned) do { \
5027 MonoObject* const o = sp [-2].data.o; /* See the comment about GC safety above. */ \
5028 NULL_CHECK (o); \
5029 sp -= 2; \
5030 if (unaligned) \
5031 memcpy ((char *)o + * (guint16 *)(ip + 1), &sp[1].data.datamem, sizeof (fieldtype)); \
5032 else \
5033 * (fieldtype *)((char *)o + * (guint16 *)(ip + 1)) = sp[1].data.datamem; \
5034 ip += 2; \
5035 } while (0)
5037 #define STFLD(datamem, fieldtype) STFLD_UNALIGNED(datamem, fieldtype, FALSE)
5039 MINT_IN_CASE(MINT_STFLD_I1) STFLD(i, gint8); MINT_IN_BREAK;
5040 MINT_IN_CASE(MINT_STFLD_U1) STFLD(i, guint8); MINT_IN_BREAK;
5041 MINT_IN_CASE(MINT_STFLD_I2) STFLD(i, gint16); MINT_IN_BREAK;
5042 MINT_IN_CASE(MINT_STFLD_U2) STFLD(i, guint16); MINT_IN_BREAK;
5043 MINT_IN_CASE(MINT_STFLD_I4) STFLD(i, gint32); MINT_IN_BREAK;
5044 MINT_IN_CASE(MINT_STFLD_I8) STFLD(l, gint64); MINT_IN_BREAK;
5045 MINT_IN_CASE(MINT_STFLD_R4) STFLD(f_r4, float); MINT_IN_BREAK;
5046 MINT_IN_CASE(MINT_STFLD_R8) STFLD(f, double); MINT_IN_BREAK;
5047 MINT_IN_CASE(MINT_STFLD_P) STFLD(p, gpointer); MINT_IN_BREAK;
5048 MINT_IN_CASE(MINT_STFLD_O) {
5049 MonoObject* const o = sp [-2].data.o; // See the comment about GC safety above.
5050 NULL_CHECK (o);
5051 sp -= 2;
5052 mono_gc_wbarrier_set_field_internal (o, (char *) o + * (guint16 *)(ip + 1), sp [1].data.o);
5053 ip += 2;
5054 MINT_IN_BREAK;
5056 MINT_IN_CASE(MINT_STFLD_I8_UNALIGNED) STFLD_UNALIGNED(l, gint64, TRUE); MINT_IN_BREAK;
5057 MINT_IN_CASE(MINT_STFLD_R8_UNALIGNED) STFLD_UNALIGNED(f, double, TRUE); MINT_IN_BREAK;
5059 MINT_IN_CASE(MINT_STFLD_VT) {
5060 MonoObject* const o = sp [-2].data.o; // See the comment about GC safety above.
5061 NULL_CHECK (o);
5062 sp -= 2;
5064 MonoClass *klass = (MonoClass*)frame->imethod->data_items[* (guint16 *)(ip + 2)];
5065 int const i32 = mono_class_value_size (klass, NULL);
5067 guint16 offset = * (guint16 *)(ip + 1);
5068 mono_value_copy_internal ((char *) o + offset, sp [1].data.p, klass);
5070 vt_sp -= ALIGN_TO (i32, MINT_VT_ALIGNMENT);
5071 ip += 3;
5072 MINT_IN_BREAK;
5074 MINT_IN_CASE(MINT_STRMFLD) {
5075 MonoClassField *field;
5077 MonoObject* const o = sp [-2].data.o; // See the comment about GC safety above.
5078 NULL_CHECK (o);
5080 field = (MonoClassField*)frame->imethod->data_items[* (guint16 *)(ip + 1)];
5081 ip += 2;
5083 #ifndef DISABLE_REMOTING
5084 if (mono_object_is_transparent_proxy (o)) {
5085 MonoClass *klass = ((MonoTransparentProxy*)o)->remote_class->proxy_class;
5086 mono_store_remote_field_checked (o, klass, field, &sp [-1].data, error);
5087 mono_interp_error_cleanup (error); /* FIXME: don't swallow the error */
5088 } else
5089 #endif
5090 stackval_to_data (field->type, &sp [-1], (char*)o + field->offset, FALSE);
5092 sp -= 2;
5093 MINT_IN_BREAK;
5095 MINT_IN_CASE(MINT_STRMFLD_VT)
5097 NULL_CHECK (sp [-2].data.o);
5098 vt_sp -= mono_interp_store_remote_field_vt (frame, ip, sp, error);
5099 ip += 2;
5100 sp -= 2;
5101 MINT_IN_BREAK;
5103 MINT_IN_CASE(MINT_LDSFLDA) {
5104 MonoVTable *vtable = (MonoVTable*) frame->imethod->data_items [*(guint16*)(ip + 1)];
5105 INIT_VTABLE (vtable);
5106 sp->data.p = frame->imethod->data_items [*(guint16*)(ip + 2)];
5107 ip += 3;
5108 ++sp;
5109 MINT_IN_BREAK;
5112 MINT_IN_CASE(MINT_LDSSFLDA) {
5113 guint32 offset = READ32(ip + 1);
5114 sp->data.p = mono_get_special_static_data (offset);
5115 ip += 3;
5116 ++sp;
5117 MINT_IN_BREAK;
5120 /* We init class here to preserve cctor order */
5121 #define LDSFLD(datamem, fieldtype) { \
5122 MonoVTable *vtable = (MonoVTable*) frame->imethod->data_items [*(guint16*)(ip + 1)]; \
5123 INIT_VTABLE (vtable); \
5124 sp[0].data.datamem = * (fieldtype *)(frame->imethod->data_items [* (guint16 *)(ip + 2)]) ; \
5125 ip += 3; \
5126 sp++; \
5129 MINT_IN_CASE(MINT_LDSFLD_I1) LDSFLD(i, gint8); MINT_IN_BREAK;
5130 MINT_IN_CASE(MINT_LDSFLD_U1) LDSFLD(i, guint8); MINT_IN_BREAK;
5131 MINT_IN_CASE(MINT_LDSFLD_I2) LDSFLD(i, gint16); MINT_IN_BREAK;
5132 MINT_IN_CASE(MINT_LDSFLD_U2) LDSFLD(i, guint16); MINT_IN_BREAK;
5133 MINT_IN_CASE(MINT_LDSFLD_I4) LDSFLD(i, gint32); MINT_IN_BREAK;
5134 MINT_IN_CASE(MINT_LDSFLD_I8) LDSFLD(l, gint64); MINT_IN_BREAK;
5135 MINT_IN_CASE(MINT_LDSFLD_R4) LDSFLD(f_r4, float); MINT_IN_BREAK;
5136 MINT_IN_CASE(MINT_LDSFLD_R8) LDSFLD(f, double); MINT_IN_BREAK;
5137 MINT_IN_CASE(MINT_LDSFLD_O) LDSFLD(p, gpointer); MINT_IN_BREAK;
5138 MINT_IN_CASE(MINT_LDSFLD_P) LDSFLD(p, gpointer); MINT_IN_BREAK;
5140 MINT_IN_CASE(MINT_LDSFLD_VT) {
5141 MonoVTable *vtable = (MonoVTable*) frame->imethod->data_items [*(guint16*)(ip + 1)];
5142 INIT_VTABLE (vtable);
5143 sp->data.p = vt_sp;
5145 gpointer addr = frame->imethod->data_items [*(guint16*)(ip + 2)];
5146 int const i32 = READ32 (ip + 3);
5147 memcpy (vt_sp, addr, i32);
5148 vt_sp += ALIGN_TO (i32, MINT_VT_ALIGNMENT);
5149 ip += 5;
5150 ++sp;
5151 MINT_IN_BREAK;
5154 #define LDTSFLD(datamem, fieldtype) { \
5155 MonoInternalThread *thread = mono_thread_internal_current (); \
5156 guint32 offset = READ32 (ip + 1); \
5157 gpointer addr = ((char*)thread->static_data [offset & 0x3f]) + (offset >> 6); \
5158 sp[0].data.datamem = *(fieldtype*)addr; \
5159 ip += 3; \
5160 ++sp; \
5162 MINT_IN_CASE(MINT_LDTSFLD_I1) LDTSFLD(i, gint8); MINT_IN_BREAK;
5163 MINT_IN_CASE(MINT_LDTSFLD_U1) LDTSFLD(i, guint8); MINT_IN_BREAK;
5164 MINT_IN_CASE(MINT_LDTSFLD_I2) LDTSFLD(i, gint16); MINT_IN_BREAK;
5165 MINT_IN_CASE(MINT_LDTSFLD_U2) LDTSFLD(i, guint16); MINT_IN_BREAK;
5166 MINT_IN_CASE(MINT_LDTSFLD_I4) LDTSFLD(i, gint32); MINT_IN_BREAK;
5167 MINT_IN_CASE(MINT_LDTSFLD_I8) LDTSFLD(l, gint64); MINT_IN_BREAK;
5168 MINT_IN_CASE(MINT_LDTSFLD_R4) LDTSFLD(f_r4, float); MINT_IN_BREAK;
5169 MINT_IN_CASE(MINT_LDTSFLD_R8) LDTSFLD(f, double); MINT_IN_BREAK;
5170 MINT_IN_CASE(MINT_LDTSFLD_O) LDTSFLD(p, gpointer); MINT_IN_BREAK;
5171 MINT_IN_CASE(MINT_LDTSFLD_P) LDTSFLD(p, gpointer); MINT_IN_BREAK;
5173 MINT_IN_CASE(MINT_LDSSFLD) {
5174 guint32 offset = READ32(ip + 2);
5175 gpointer addr = mono_get_special_static_data (offset);
5176 MonoClassField *field = (MonoClassField*)frame->imethod->data_items [* (guint16 *)(ip + 1)];
5177 stackval_from_data (field->type, sp, addr, FALSE);
5178 ip += 4;
5179 ++sp;
5180 MINT_IN_BREAK;
5182 MINT_IN_CASE(MINT_LDSSFLD_VT) {
5183 guint32 offset = READ32(ip + 1);
5184 gpointer addr = mono_get_special_static_data (offset);
5186 int size = READ32 (ip + 3);
5187 memcpy (vt_sp, addr, size);
5188 sp->data.p = vt_sp;
5189 vt_sp += ALIGN_TO (size, MINT_VT_ALIGNMENT);
5190 ip += 5;
5191 ++sp;
5192 MINT_IN_BREAK;
5194 #define STSFLD(datamem, fieldtype) { \
5195 MonoVTable *vtable = (MonoVTable*) frame->imethod->data_items [*(guint16*)(ip + 1)]; \
5196 INIT_VTABLE (vtable); \
5197 sp --; \
5198 * (fieldtype *)(frame->imethod->data_items [* (guint16 *)(ip + 2)]) = sp[0].data.datamem; \
5199 ip += 3; \
5202 MINT_IN_CASE(MINT_STSFLD_I1) STSFLD(i, gint8); MINT_IN_BREAK;
5203 MINT_IN_CASE(MINT_STSFLD_U1) STSFLD(i, guint8); MINT_IN_BREAK;
5204 MINT_IN_CASE(MINT_STSFLD_I2) STSFLD(i, gint16); MINT_IN_BREAK;
5205 MINT_IN_CASE(MINT_STSFLD_U2) STSFLD(i, guint16); MINT_IN_BREAK;
5206 MINT_IN_CASE(MINT_STSFLD_I4) STSFLD(i, gint32); MINT_IN_BREAK;
5207 MINT_IN_CASE(MINT_STSFLD_I8) STSFLD(l, gint64); MINT_IN_BREAK;
5208 MINT_IN_CASE(MINT_STSFLD_R4) STSFLD(f_r4, float); MINT_IN_BREAK;
5209 MINT_IN_CASE(MINT_STSFLD_R8) STSFLD(f, double); MINT_IN_BREAK;
5210 MINT_IN_CASE(MINT_STSFLD_P) STSFLD(p, gpointer); MINT_IN_BREAK;
5211 MINT_IN_CASE(MINT_STSFLD_O) STSFLD(p, gpointer); MINT_IN_BREAK;
5213 MINT_IN_CASE(MINT_STSFLD_VT) {
5214 MonoVTable *vtable = (MonoVTable*) frame->imethod->data_items [*(guint16*)(ip + 1)];
5215 INIT_VTABLE (vtable);
5216 int const i32 = READ32 (ip + 3);
5217 gpointer addr = frame->imethod->data_items [*(guint16*)(ip + 2)];
5219 memcpy (addr, sp [-1].data.vt, i32);
5220 vt_sp -= ALIGN_TO (i32, MINT_VT_ALIGNMENT);
5221 ip += 5;
5222 --sp;
5223 MINT_IN_BREAK;
5226 #define STTSFLD(datamem, fieldtype) { \
5227 MonoInternalThread *thread = mono_thread_internal_current (); \
5228 guint32 offset = READ32 (ip + 1); \
5229 gpointer addr = ((char*)thread->static_data [offset & 0x3f]) + (offset >> 6); \
5230 sp--; \
5231 *(fieldtype*)addr = sp[0].data.datamem; \
5232 ip += 3; \
5235 MINT_IN_CASE(MINT_STTSFLD_I1) STTSFLD(i, gint8); MINT_IN_BREAK;
5236 MINT_IN_CASE(MINT_STTSFLD_U1) STTSFLD(i, guint8); MINT_IN_BREAK;
5237 MINT_IN_CASE(MINT_STTSFLD_I2) STTSFLD(i, gint16); MINT_IN_BREAK;
5238 MINT_IN_CASE(MINT_STTSFLD_U2) STTSFLD(i, guint16); MINT_IN_BREAK;
5239 MINT_IN_CASE(MINT_STTSFLD_I4) STTSFLD(i, gint32); MINT_IN_BREAK;
5240 MINT_IN_CASE(MINT_STTSFLD_I8) STTSFLD(l, gint64); MINT_IN_BREAK;
5241 MINT_IN_CASE(MINT_STTSFLD_R4) STTSFLD(f_r4, float); MINT_IN_BREAK;
5242 MINT_IN_CASE(MINT_STTSFLD_R8) STTSFLD(f, double); MINT_IN_BREAK;
5243 MINT_IN_CASE(MINT_STTSFLD_P) STTSFLD(p, gpointer); MINT_IN_BREAK;
5244 MINT_IN_CASE(MINT_STTSFLD_O) STTSFLD(p, gpointer); MINT_IN_BREAK;
5246 MINT_IN_CASE(MINT_STSSFLD) {
5247 guint32 offset = READ32(ip + 2);
5248 gpointer addr = mono_get_special_static_data (offset);
5249 MonoClassField *field = (MonoClassField*)frame->imethod->data_items [* (guint16 *)(ip + 1)];
5250 --sp;
5251 stackval_to_data (field->type, sp, addr, FALSE);
5252 ip += 4;
5253 MINT_IN_BREAK;
5255 MINT_IN_CASE(MINT_STSSFLD_VT) {
5256 guint32 offset = READ32(ip + 1);
5257 gpointer addr = mono_get_special_static_data (offset);
5258 --sp;
5259 int size = READ32 (ip + 3);
5260 memcpy (addr, sp->data.vt, size);
5261 vt_sp -= ALIGN_TO (size, MINT_VT_ALIGNMENT);
5262 ip += 5;
5263 MINT_IN_BREAK;
5266 MINT_IN_CASE(MINT_STOBJ_VT) {
5267 int size;
5268 MonoClass* const c = (MonoClass*)frame->imethod->data_items[* (guint16 *)(ip + 1)];
5269 ip += 2;
5270 size = mono_class_value_size (c, NULL);
5271 mono_value_copy_internal (sp [-2].data.p, sp [-1].data.p, c);
5272 vt_sp -= ALIGN_TO (size, MINT_VT_ALIGNMENT);
5273 sp -= 2;
5274 MINT_IN_BREAK;
5276 MINT_IN_CASE(MINT_CONV_OVF_I4_UN_R8)
5277 if (sp [-1].data.f < 0 || sp [-1].data.f > G_MAXINT32)
5278 goto overflow_label;
5279 sp [-1].data.i = (gint32)sp [-1].data.f;
5280 ++ip;
5281 MINT_IN_BREAK;
5282 MINT_IN_CASE(MINT_CONV_OVF_U8_I4)
5283 if (sp [-1].data.i < 0)
5284 goto overflow_label;
5285 sp [-1].data.l = sp [-1].data.i;
5286 ++ip;
5287 MINT_IN_BREAK;
5288 MINT_IN_CASE(MINT_CONV_OVF_U8_I8)
5289 if (sp [-1].data.l < 0)
5290 goto overflow_label;
5291 ++ip;
5292 MINT_IN_BREAK;
5293 MINT_IN_CASE(MINT_CONV_OVF_I8_U8)
5294 if ((guint64) sp [-1].data.l > G_MAXINT64)
5295 goto overflow_label;
5296 ++ip;
5297 MINT_IN_BREAK;
5298 MINT_IN_CASE(MINT_CONV_OVF_U8_R4)
5299 if (sp [-1].data.f_r4 < 0 || sp [-1].data.f_r4 > G_MAXUINT64 || isnan (sp [-1].data.f_r4))
5300 goto overflow_label;
5301 sp [-1].data.l = (guint64)sp [-1].data.f_r4;
5302 ++ip;
5303 MINT_IN_BREAK;
5304 MINT_IN_CASE(MINT_CONV_OVF_U8_R8)
5305 if (sp [-1].data.f < 0 || sp [-1].data.f > G_MAXUINT64 || isnan (sp [-1].data.f))
5306 goto overflow_label;
5307 sp [-1].data.l = (guint64)sp [-1].data.f;
5308 ++ip;
5309 MINT_IN_BREAK;
5310 MINT_IN_CASE(MINT_CONV_OVF_I8_UN_R8)
5311 if (sp [-1].data.f < 0 || sp [-1].data.f > G_MAXINT64)
5312 goto overflow_label;
5313 sp [-1].data.l = (gint64)sp [-1].data.f;
5314 ++ip;
5315 MINT_IN_BREAK;
5316 MINT_IN_CASE(MINT_CONV_OVF_I8_UN_R4)
5317 if (sp [-1].data.f_r4 < 0 || sp [-1].data.f_r4 > G_MAXINT64)
5318 goto overflow_label;
5319 sp [-1].data.l = (gint64)sp [-1].data.f_r4;
5320 ++ip;
5321 MINT_IN_BREAK;
5322 MINT_IN_CASE(MINT_CONV_OVF_I8_R4)
5323 if (sp [-1].data.f_r4 < G_MININT64 || sp [-1].data.f_r4 > G_MAXINT64 || isnan (sp [-1].data.f_r4))
5324 goto overflow_label;
5325 sp [-1].data.l = (gint64)sp [-1].data.f_r4;
5326 ++ip;
5327 MINT_IN_BREAK;
5328 MINT_IN_CASE(MINT_CONV_OVF_I8_R8)
5329 if (sp [-1].data.f < G_MININT64 || sp [-1].data.f > G_MAXINT64 || isnan (sp [-1].data.f))
5330 goto overflow_label;
5331 sp [-1].data.l = (gint64)sp [-1].data.f;
5332 ++ip;
5333 MINT_IN_BREAK;
5334 MINT_IN_CASE(MINT_CONV_OVF_I4_UN_I8)
5335 if ((guint64)sp [-1].data.l > G_MAXINT32)
5336 goto overflow_label;
5337 sp [-1].data.i = (gint32)sp [-1].data.l;
5338 ++ip;
5339 MINT_IN_BREAK;
5340 MINT_IN_CASE(MINT_BOX) {
5341 mono_interp_box (frame, ip, sp);
5342 ip += 3;
5343 MINT_IN_BREAK;
5345 MINT_IN_CASE(MINT_BOX_VT) {
5346 vt_sp -= mono_interp_box_vt (frame, ip, sp);
5347 ip += 3;
5348 MINT_IN_BREAK;
5350 MINT_IN_CASE(MINT_BOX_NULLABLE) {
5351 vt_sp -= mono_interp_box_nullable (frame, ip, sp, error);
5352 ip += 3;
5353 MINT_IN_BREAK;
5355 MINT_IN_CASE(MINT_NEWARR) {
5356 MonoVTable *vtable = (MonoVTable*)frame->imethod->data_items[*(guint16 *)(ip + 1)];
5357 sp [-1].data.o = (MonoObject*) mono_array_new_specific_checked (vtable, sp [-1].data.i, error);
5358 if (!is_ok (error)) {
5359 goto throw_error_label;
5361 ip += 2;
5362 /*if (profiling_classes) {
5363 guint count = GPOINTER_TO_UINT (g_hash_table_lookup (profiling_classes, o->vtable->klass));
5364 count++;
5365 g_hash_table_insert (profiling_classes, o->vtable->klass, GUINT_TO_POINTER (count));
5368 MINT_IN_BREAK;
5370 MINT_IN_CASE(MINT_LDLEN) {
5371 MonoObject* const o = sp [-1].data.o; // See the comment about GC safety above.
5372 NULL_CHECK (o);
5373 sp [-1].data.nati = mono_array_length_internal ((MonoArray *)o);
5374 ++ip;
5375 MINT_IN_BREAK;
5377 MINT_IN_CASE(MINT_LDLEN_SPAN) {
5378 MonoObject* const o = sp [-1].data.o; // See the comment about GC safety above.
5379 NULL_CHECK (o);
5380 gsize offset_length = (gsize) *(gint16 *) (ip + 1);
5381 sp [-1].data.nati = *(gint32 *) ((guint8 *) o + offset_length);
5382 ip += 2;
5383 MINT_IN_BREAK;
5385 MINT_IN_CASE(MINT_GETCHR) {
5386 MonoString *s;
5387 s = (MonoString*)sp [-2].data.p;
5388 NULL_CHECK (s);
5389 int const i32 = sp [-1].data.i;
5390 if (i32 < 0 || i32 >= mono_string_length_internal (s))
5391 THROW_EX (mono_get_exception_index_out_of_range (), ip);
5392 --sp;
5393 sp [-1].data.i = mono_string_chars_internal (s)[i32];
5394 ++ip;
5395 MINT_IN_BREAK;
5397 MINT_IN_CASE(MINT_GETITEM_SPAN) {
5398 guint8 * const span = (guint8 *) sp [-2].data.p;
5399 const int index = sp [-1].data.i;
5400 sp--;
5402 NULL_CHECK (span);
5404 const gsize offset_length = (gsize) *(gint16 *) (ip + 2);
5406 const gint32 length = *(gint32 *) (span + offset_length);
5407 if (index < 0 || index >= length)
5408 THROW_EX (mono_get_exception_index_out_of_range (), ip);
5410 const gsize element_size = (gsize) *(gint16 *) (ip + 1);
5411 const gsize offset_pointer = (gsize) *(gint16 *) (ip + 3);
5413 const gpointer pointer = *(gpointer *)(span + offset_pointer);
5414 sp [-1].data.p = (guint8 *) pointer + index * element_size;
5416 ip += 4;
5417 MINT_IN_BREAK;
5419 MINT_IN_CASE(MINT_STRLEN) {
5420 ++ip;
5421 MonoObject* const o = sp [-1].data.o; // See the comment about GC safety above.
5422 NULL_CHECK (o);
5423 sp [-1].data.i = mono_string_length_internal ((MonoString*) o);
5424 MINT_IN_BREAK;
5426 MINT_IN_CASE(MINT_ARRAY_RANK) {
5427 MonoObject* const o = sp [-1].data.o; // See the comment about GC safety above.
5428 NULL_CHECK (o);
5429 sp [-1].data.i = m_class_get_rank (mono_object_class (sp [-1].data.p));
5430 ip++;
5431 MINT_IN_BREAK;
5433 MINT_IN_CASE(MINT_LDELEMA_FAST) {
5434 /* No bounds, one direction */
5435 MonoArray *ao = (MonoArray*)sp [-2].data.o;
5436 NULL_CHECK (ao);
5437 gint32 const index = sp [-1].data.i;
5438 if (index >= ao->max_length)
5439 THROW_EX (mono_get_exception_index_out_of_range (), ip);
5440 gint32 const size = READ32 (ip + 1);
5441 sp [-2].data.p = mono_array_addr_with_size_fast (ao, size, index);
5442 ip += 3;
5443 sp --;
5445 MINT_IN_BREAK;
5447 MINT_IN_CASE(MINT_LDELEMA)
5448 MINT_IN_CASE(MINT_LDELEMA_TC) {
5450 guint16 numargs = *(guint16 *) (ip + 2);
5451 ip += 3;
5452 sp -= numargs;
5454 MonoObject* const o = sp [0].data.o; // See the comment about GC safety above.
5455 NULL_CHECK (o);
5457 MonoClass *klass = (MonoClass*)frame->imethod->data_items [*(guint16 *) (ip - 3 + 1)];
5458 const gboolean needs_typecheck = ip [-3] == MINT_LDELEMA_TC;
5459 sp->data.p = ves_array_element_address (frame, klass, (MonoArray *) o, &sp [1], needs_typecheck);
5460 if (frame->ex)
5461 THROW_EX (frame->ex, ip);
5462 ++sp;
5464 MINT_IN_BREAK;
5466 MINT_IN_CASE(MINT_LDELEM_I1) /* fall through */
5467 MINT_IN_CASE(MINT_LDELEM_U1) /* fall through */
5468 MINT_IN_CASE(MINT_LDELEM_I2) /* fall through */
5469 MINT_IN_CASE(MINT_LDELEM_U2) /* fall through */
5470 MINT_IN_CASE(MINT_LDELEM_I4) /* fall through */
5471 MINT_IN_CASE(MINT_LDELEM_U4) /* fall through */
5472 MINT_IN_CASE(MINT_LDELEM_I8) /* fall through */
5473 MINT_IN_CASE(MINT_LDELEM_I) /* fall through */
5474 MINT_IN_CASE(MINT_LDELEM_R4) /* fall through */
5475 MINT_IN_CASE(MINT_LDELEM_R8) /* fall through */
5476 MINT_IN_CASE(MINT_LDELEM_REF) /* fall through */
5477 MINT_IN_CASE(MINT_LDELEM_VT) {
5478 MonoArray *o;
5479 mono_u aindex;
5481 sp -= 2;
5483 o = (MonoArray*)sp [0].data.p;
5484 NULL_CHECK (o);
5486 aindex = sp [1].data.i;
5487 if (aindex >= mono_array_length_internal (o))
5488 THROW_EX (mono_get_exception_index_out_of_range (), ip);
5491 * FIXME: throw mono_get_exception_array_type_mismatch () if needed
5493 switch (*ip) {
5494 case MINT_LDELEM_I1:
5495 sp [0].data.i = mono_array_get_fast (o, gint8, aindex);
5496 break;
5497 case MINT_LDELEM_U1:
5498 sp [0].data.i = mono_array_get_fast (o, guint8, aindex);
5499 break;
5500 case MINT_LDELEM_I2:
5501 sp [0].data.i = mono_array_get_fast (o, gint16, aindex);
5502 break;
5503 case MINT_LDELEM_U2:
5504 sp [0].data.i = mono_array_get_fast (o, guint16, aindex);
5505 break;
5506 case MINT_LDELEM_I:
5507 sp [0].data.nati = mono_array_get_fast (o, mono_i, aindex);
5508 break;
5509 case MINT_LDELEM_I4:
5510 sp [0].data.i = mono_array_get_fast (o, gint32, aindex);
5511 break;
5512 case MINT_LDELEM_U4:
5513 sp [0].data.i = mono_array_get_fast (o, guint32, aindex);
5514 break;
5515 case MINT_LDELEM_I8:
5516 sp [0].data.l = mono_array_get_fast (o, guint64, aindex);
5517 break;
5518 case MINT_LDELEM_R4:
5519 sp [0].data.f_r4 = mono_array_get_fast (o, float, aindex);
5520 break;
5521 case MINT_LDELEM_R8:
5522 sp [0].data.f = mono_array_get_fast (o, double, aindex);
5523 break;
5524 case MINT_LDELEM_REF:
5525 sp [0].data.p = mono_array_get_fast (o, gpointer, aindex);
5526 break;
5527 case MINT_LDELEM_VT: {
5528 int const i32 = READ32 (ip + 1);
5529 char *src_addr = mono_array_addr_with_size_fast ((MonoArray *) o, i32, aindex);
5530 sp [0].data.vt = vt_sp;
5531 // Copying to vtstack. No wbarrier needed
5532 memcpy (sp [0].data.vt, src_addr, i32);
5533 vt_sp += ALIGN_TO (i32, MINT_VT_ALIGNMENT);
5534 ip += 2;
5535 break;
5537 default:
5538 ves_abort();
5541 ++ip;
5542 ++sp;
5543 MINT_IN_BREAK;
5545 MINT_IN_CASE(MINT_STELEM_I) /* fall through */
5546 MINT_IN_CASE(MINT_STELEM_I1) /* fall through */
5547 MINT_IN_CASE(MINT_STELEM_U1) /* fall through */
5548 MINT_IN_CASE(MINT_STELEM_I2) /* fall through */
5549 MINT_IN_CASE(MINT_STELEM_U2) /* fall through */
5550 MINT_IN_CASE(MINT_STELEM_I4) /* fall through */
5551 MINT_IN_CASE(MINT_STELEM_I8) /* fall through */
5552 MINT_IN_CASE(MINT_STELEM_R4) /* fall through */
5553 MINT_IN_CASE(MINT_STELEM_R8) /* fall through */
5554 MINT_IN_CASE(MINT_STELEM_REF) /* fall through */
5555 MINT_IN_CASE(MINT_STELEM_VT) {
5556 mono_u aindex;
5558 sp -= 3;
5560 MonoObject* const o = sp [0].data.o; // See the comment about GC safety above.
5561 NULL_CHECK (o);
5563 aindex = sp [1].data.i;
5564 if (aindex >= mono_array_length_internal ((MonoArray *)o))
5565 THROW_EX (mono_get_exception_index_out_of_range (), ip);
5567 switch (*ip) {
5568 case MINT_STELEM_I:
5569 mono_array_set_fast ((MonoArray *)o, mono_i, aindex, sp [2].data.nati);
5570 break;
5571 case MINT_STELEM_I1:
5572 mono_array_set_fast ((MonoArray *)o, gint8, aindex, sp [2].data.i);
5573 break;
5574 case MINT_STELEM_U1:
5575 mono_array_set_fast ((MonoArray *) o, guint8, aindex, sp [2].data.i);
5576 break;
5577 case MINT_STELEM_I2:
5578 mono_array_set_fast ((MonoArray *)o, gint16, aindex, sp [2].data.i);
5579 break;
5580 case MINT_STELEM_U2:
5581 mono_array_set_fast ((MonoArray *)o, guint16, aindex, sp [2].data.i);
5582 break;
5583 case MINT_STELEM_I4:
5584 mono_array_set_fast ((MonoArray *)o, gint32, aindex, sp [2].data.i);
5585 break;
5586 case MINT_STELEM_I8:
5587 mono_array_set_fast ((MonoArray *)o, gint64, aindex, sp [2].data.l);
5588 break;
5589 case MINT_STELEM_R4:
5590 mono_array_set_fast ((MonoArray *)o, float, aindex, sp [2].data.f_r4);
5591 break;
5592 case MINT_STELEM_R8:
5593 mono_array_set_fast ((MonoArray *)o, double, aindex, sp [2].data.f);
5594 break;
5595 case MINT_STELEM_REF: {
5596 if (sp [2].data.p) {
5597 MonoObject *isinst_obj = mono_object_isinst_checked (sp [2].data.o, m_class_get_element_class (mono_object_class (o)), error);
5598 mono_interp_error_cleanup (error); /* FIXME: don't swallow the error */
5599 if (!isinst_obj)
5600 THROW_EX (mono_get_exception_array_type_mismatch (), ip);
5602 mono_array_setref_fast ((MonoArray *) o, aindex, sp [2].data.p);
5603 break;
5605 case MINT_STELEM_VT: {
5606 MonoClass *klass_vt = (MonoClass*)frame->imethod->data_items [*(guint16 *) (ip + 1)];
5607 int const i32 = READ32 (ip + 2);
5608 char *dst_addr = mono_array_addr_with_size_fast ((MonoArray *) o, i32, aindex);
5610 mono_value_copy_internal (dst_addr, sp [2].data.vt, klass_vt);
5611 vt_sp -= ALIGN_TO (i32, MINT_VT_ALIGNMENT);
5612 ip += 3;
5613 break;
5615 default:
5616 ves_abort();
5619 ++ip;
5620 MINT_IN_BREAK;
5622 MINT_IN_CASE(MINT_CONV_OVF_I4_U4)
5623 if (sp [-1].data.i < 0)
5624 goto overflow_label;
5625 ++ip;
5626 MINT_IN_BREAK;
5627 MINT_IN_CASE(MINT_CONV_OVF_I4_I8)
5628 if (sp [-1].data.l < G_MININT32 || sp [-1].data.l > G_MAXINT32)
5629 goto overflow_label;
5630 sp [-1].data.i = (gint32) sp [-1].data.l;
5631 ++ip;
5632 MINT_IN_BREAK;
5633 MINT_IN_CASE(MINT_CONV_OVF_I4_U8)
5634 if (sp [-1].data.l < 0 || sp [-1].data.l > G_MAXINT32)
5635 goto overflow_label;
5636 sp [-1].data.i = (gint32) sp [-1].data.l;
5637 ++ip;
5638 MINT_IN_BREAK;
5639 MINT_IN_CASE(MINT_CONV_OVF_I4_R4)
5640 if (sp [-1].data.f_r4 < G_MININT32 || sp [-1].data.f_r4 > G_MAXINT32)
5641 goto overflow_label;
5642 sp [-1].data.i = (gint32) sp [-1].data.f_r4;
5643 ++ip;
5644 MINT_IN_BREAK;
5645 MINT_IN_CASE(MINT_CONV_OVF_I4_R8)
5646 if (sp [-1].data.f < G_MININT32 || sp [-1].data.f > G_MAXINT32)
5647 goto overflow_label;
5648 sp [-1].data.i = (gint32) sp [-1].data.f;
5649 ++ip;
5650 MINT_IN_BREAK;
5651 MINT_IN_CASE(MINT_CONV_OVF_U4_I4)
5652 if (sp [-1].data.i < 0)
5653 goto overflow_label;
5654 ++ip;
5655 MINT_IN_BREAK;
5656 MINT_IN_CASE(MINT_CONV_OVF_U4_I8)
5657 if (sp [-1].data.l < 0 || sp [-1].data.l > G_MAXUINT32)
5658 goto overflow_label;
5659 sp [-1].data.i = (guint32) sp [-1].data.l;
5660 ++ip;
5661 MINT_IN_BREAK;
5662 MINT_IN_CASE(MINT_CONV_OVF_U4_R4)
5663 if (sp [-1].data.f_r4 < 0 || sp [-1].data.f_r4 > G_MAXUINT32)
5664 goto overflow_label;
5665 sp [-1].data.i = (guint32) sp [-1].data.f_r4;
5666 ++ip;
5667 MINT_IN_BREAK;
5668 MINT_IN_CASE(MINT_CONV_OVF_U4_R8)
5669 if (sp [-1].data.f < 0 || sp [-1].data.f > G_MAXUINT32)
5670 goto overflow_label;
5671 sp [-1].data.i = (guint32) sp [-1].data.f;
5672 ++ip;
5673 MINT_IN_BREAK;
5674 MINT_IN_CASE(MINT_CONV_OVF_I2_I4)
5675 if (sp [-1].data.i < G_MININT16 || sp [-1].data.i > G_MAXINT16)
5676 goto overflow_label;
5677 ++ip;
5678 MINT_IN_BREAK;
5679 MINT_IN_CASE(MINT_CONV_OVF_I2_U4)
5680 if (sp [-1].data.i < 0 || sp [-1].data.i > G_MAXINT16)
5681 goto overflow_label;
5682 ++ip;
5683 MINT_IN_BREAK;
5684 MINT_IN_CASE(MINT_CONV_OVF_I2_I8)
5685 if (sp [-1].data.l < G_MININT16 || sp [-1].data.l > G_MAXINT16)
5686 goto overflow_label;
5687 sp [-1].data.i = (gint16) sp [-1].data.l;
5688 ++ip;
5689 MINT_IN_BREAK;
5690 MINT_IN_CASE(MINT_CONV_OVF_I2_U8)
5691 if (sp [-1].data.l < 0 || sp [-1].data.l > G_MAXINT16)
5692 goto overflow_label;
5693 sp [-1].data.i = (gint16) sp [-1].data.l;
5694 ++ip;
5695 MINT_IN_BREAK;
5696 MINT_IN_CASE(MINT_CONV_OVF_I2_R8)
5697 if (sp [-1].data.f < G_MININT16 || sp [-1].data.f > G_MAXINT16)
5698 goto overflow_label;
5699 sp [-1].data.i = (gint16) sp [-1].data.f;
5700 ++ip;
5701 MINT_IN_BREAK;
5702 MINT_IN_CASE(MINT_CONV_OVF_I2_UN_R8)
5703 if (sp [-1].data.f < 0 || sp [-1].data.f > G_MAXINT16)
5704 goto overflow_label;
5705 sp [-1].data.i = (gint16) sp [-1].data.f;
5706 ++ip;
5707 MINT_IN_BREAK;
5708 MINT_IN_CASE(MINT_CONV_OVF_U2_I4)
5709 if (sp [-1].data.i < 0 || sp [-1].data.i > G_MAXUINT16)
5710 goto overflow_label;
5711 ++ip;
5712 MINT_IN_BREAK;
5713 MINT_IN_CASE(MINT_CONV_OVF_U2_I8)
5714 if (sp [-1].data.l < 0 || sp [-1].data.l > G_MAXUINT16)
5715 goto overflow_label;
5716 sp [-1].data.i = (guint16) sp [-1].data.l;
5717 ++ip;
5718 MINT_IN_BREAK;
5719 MINT_IN_CASE(MINT_CONV_OVF_U2_R8)
5720 if (sp [-1].data.f < 0 || sp [-1].data.f > G_MAXUINT16)
5721 goto overflow_label;
5722 sp [-1].data.i = (guint16) sp [-1].data.f;
5723 ++ip;
5724 MINT_IN_BREAK;
5725 MINT_IN_CASE(MINT_CONV_OVF_I1_I4)
5726 if (sp [-1].data.i < G_MININT8 || sp [-1].data.i > G_MAXINT8)
5727 goto overflow_label;
5728 ++ip;
5729 MINT_IN_BREAK;
5730 MINT_IN_CASE(MINT_CONV_OVF_I1_U4)
5731 if (sp [-1].data.i < 0 || sp [-1].data.i > G_MAXINT8)
5732 goto overflow_label;
5733 ++ip;
5734 MINT_IN_BREAK;
5735 MINT_IN_CASE(MINT_CONV_OVF_I1_I8)
5736 if (sp [-1].data.l < G_MININT8 || sp [-1].data.l > G_MAXINT8)
5737 goto overflow_label;
5738 sp [-1].data.i = (gint8) sp [-1].data.l;
5739 ++ip;
5740 MINT_IN_BREAK;
5741 MINT_IN_CASE(MINT_CONV_OVF_I1_U8)
5742 if (sp [-1].data.l < 0 || sp [-1].data.l > G_MAXINT8)
5743 goto overflow_label;
5744 sp [-1].data.i = (gint8) sp [-1].data.l;
5745 ++ip;
5746 MINT_IN_BREAK;
5747 MINT_IN_CASE(MINT_CONV_OVF_I1_R8)
5748 if (sp [-1].data.f < G_MININT8 || sp [-1].data.f > G_MAXINT8)
5749 goto overflow_label;
5750 sp [-1].data.i = (gint8) sp [-1].data.f;
5751 ++ip;
5752 MINT_IN_BREAK;
5753 MINT_IN_CASE(MINT_CONV_OVF_I1_UN_R8)
5754 if (sp [-1].data.f < 0 || sp [-1].data.f > G_MAXINT8)
5755 goto overflow_label;
5756 sp [-1].data.i = (gint8) sp [-1].data.f;
5757 ++ip;
5758 MINT_IN_BREAK;
5759 MINT_IN_CASE(MINT_CONV_OVF_U1_I4)
5760 if (sp [-1].data.i < 0 || sp [-1].data.i > G_MAXUINT8)
5761 goto overflow_label;
5762 ++ip;
5763 MINT_IN_BREAK;
5764 MINT_IN_CASE(MINT_CONV_OVF_U1_I8)
5765 if (sp [-1].data.l < 0 || sp [-1].data.l > G_MAXUINT8)
5766 goto overflow_label;
5767 sp [-1].data.i = (guint8) sp [-1].data.l;
5768 ++ip;
5769 MINT_IN_BREAK;
5770 MINT_IN_CASE(MINT_CONV_OVF_U1_R8)
5771 if (sp [-1].data.f < 0 || sp [-1].data.f > G_MAXUINT8)
5772 goto overflow_label;
5773 sp [-1].data.i = (guint8) sp [-1].data.f;
5774 ++ip;
5775 MINT_IN_BREAK;
5776 MINT_IN_CASE(MINT_CKFINITE)
5777 if (!mono_isfinite (sp [-1].data.f))
5778 THROW_EX (mono_get_exception_arithmetic (), ip);
5779 ++ip;
5780 MINT_IN_BREAK;
5781 MINT_IN_CASE(MINT_MKREFANY) {
5782 MonoClass* const c = (MonoClass*)frame->imethod->data_items [*(guint16 *)(ip + 1)];
5784 /* The value address is on the stack */
5785 gpointer addr = sp [-1].data.p;
5786 /* Push the typedref value on the stack */
5787 sp [-1].data.p = vt_sp;
5788 vt_sp += ALIGN_TO (sizeof (MonoTypedRef), MINT_VT_ALIGNMENT);
5790 MonoTypedRef *tref = (MonoTypedRef*)sp [-1].data.p;
5791 tref->klass = c;
5792 tref->type = m_class_get_byval_arg (c);
5793 tref->value = addr;
5795 ip += 2;
5796 MINT_IN_BREAK;
5798 MINT_IN_CASE(MINT_REFANYTYPE) {
5799 MonoTypedRef *tref = (MonoTypedRef*)sp [-1].data.p;
5800 MonoType *type = tref->type;
5802 vt_sp -= ALIGN_TO (sizeof (MonoTypedRef), MINT_VT_ALIGNMENT);
5803 sp [-1].data.p = vt_sp;
5804 vt_sp += 8;
5805 *(gpointer*)sp [-1].data.p = type;
5806 ip ++;
5807 MINT_IN_BREAK;
5809 MINT_IN_CASE(MINT_REFANYVAL) {
5810 MonoTypedRef *tref = (MonoTypedRef*)sp [-1].data.p;
5811 gpointer addr = tref->value;
5813 MonoClass* const c = (MonoClass*)frame->imethod->data_items [*(guint16 *)(ip + 1)];
5814 if (c != tref->klass)
5815 goto invalid_cast_label;
5817 vt_sp -= ALIGN_TO (sizeof (MonoTypedRef), MINT_VT_ALIGNMENT);
5819 sp [-1].data.p = addr;
5820 ip += 2;
5821 MINT_IN_BREAK;
5823 MINT_IN_CASE(MINT_LDTOKEN)
5824 sp->data.p = vt_sp;
5825 vt_sp += 8;
5826 * (gpointer *)sp->data.p = frame->imethod->data_items[*(guint16 *)(ip + 1)];
5827 ip += 2;
5828 ++sp;
5829 MINT_IN_BREAK;
5830 MINT_IN_CASE(MINT_ADD_OVF_I4)
5831 if (CHECK_ADD_OVERFLOW (sp [-2].data.i, sp [-1].data.i))
5832 goto overflow_label;
5833 BINOP(i, +);
5834 MINT_IN_BREAK;
5835 MINT_IN_CASE(MINT_ADD_OVF_I8)
5836 if (CHECK_ADD_OVERFLOW64 (sp [-2].data.l, sp [-1].data.l))
5837 goto overflow_label;
5838 BINOP(l, +);
5839 MINT_IN_BREAK;
5840 MINT_IN_CASE(MINT_ADD_OVF_UN_I4)
5841 if (CHECK_ADD_OVERFLOW_UN (sp [-2].data.i, sp [-1].data.i))
5842 goto overflow_label;
5843 BINOP_CAST(i, +, guint32);
5844 MINT_IN_BREAK;
5845 MINT_IN_CASE(MINT_ADD_OVF_UN_I8)
5846 if (CHECK_ADD_OVERFLOW64_UN (sp [-2].data.l, sp [-1].data.l))
5847 goto overflow_label;
5848 BINOP_CAST(l, +, guint64);
5849 MINT_IN_BREAK;
5850 MINT_IN_CASE(MINT_MUL_OVF_I4)
5851 if (CHECK_MUL_OVERFLOW (sp [-2].data.i, sp [-1].data.i))
5852 goto overflow_label;
5853 BINOP(i, *);
5854 MINT_IN_BREAK;
5855 MINT_IN_CASE(MINT_MUL_OVF_I8)
5856 if (CHECK_MUL_OVERFLOW64 (sp [-2].data.l, sp [-1].data.l))
5857 goto overflow_label;
5858 BINOP(l, *);
5859 MINT_IN_BREAK;
5860 MINT_IN_CASE(MINT_MUL_OVF_UN_I4)
5861 if (CHECK_MUL_OVERFLOW_UN (sp [-2].data.i, sp [-1].data.i))
5862 goto overflow_label;
5863 BINOP_CAST(i, *, guint32);
5864 MINT_IN_BREAK;
5865 MINT_IN_CASE(MINT_MUL_OVF_UN_I8)
5866 if (CHECK_MUL_OVERFLOW64_UN (sp [-2].data.l, sp [-1].data.l))
5867 goto overflow_label;
5868 BINOP_CAST(l, *, guint64);
5869 MINT_IN_BREAK;
5870 MINT_IN_CASE(MINT_SUB_OVF_I4)
5871 if (CHECK_SUB_OVERFLOW (sp [-2].data.i, sp [-1].data.i))
5872 goto overflow_label;
5873 BINOP(i, -);
5874 MINT_IN_BREAK;
5875 MINT_IN_CASE(MINT_SUB_OVF_I8)
5876 if (CHECK_SUB_OVERFLOW64 (sp [-2].data.l, sp [-1].data.l))
5877 goto overflow_label;
5878 BINOP(l, -);
5879 MINT_IN_BREAK;
5880 MINT_IN_CASE(MINT_SUB_OVF_UN_I4)
5881 if (CHECK_SUB_OVERFLOW_UN (sp [-2].data.i, sp [-1].data.i))
5882 goto overflow_label;
5883 BINOP_CAST(i, -, guint32);
5884 MINT_IN_BREAK;
5885 MINT_IN_CASE(MINT_SUB_OVF_UN_I8)
5886 if (CHECK_SUB_OVERFLOW64_UN (sp [-2].data.l, sp [-1].data.l))
5887 goto overflow_label;
5888 BINOP_CAST(l, -, guint64);
5889 MINT_IN_BREAK;
5890 MINT_IN_CASE(MINT_START_ABORT_PROT)
5891 mono_threads_begin_abort_protected_block ();
5892 ip ++;
5893 MINT_IN_BREAK;
5894 MINT_IN_CASE(MINT_ENDFINALLY) {
5895 ip ++;
5896 gboolean pending_abort = mono_threads_end_abort_protected_block ();
5898 // After mono_threads_end_abort_protected_block to conserve stack.
5899 const int clause_index = *ip;
5901 if (clause_args && clause_index == clause_args->exit_clause)
5902 goto exit_frame;
5904 #if DEBUG_INTERP // This assert causes Linux/amd64/clang to use more stack.
5905 g_assert (sp >= frame->stack);
5906 #endif
5907 sp = frame->stack;
5909 if (finally_ips) {
5910 ip = (const guint16*)finally_ips->data;
5911 finally_ips = g_slist_remove (finally_ips, ip);
5912 /* Throw abort after the last finally block to avoid confusing EH */
5913 if (pending_abort && !finally_ips)
5914 EXCEPTION_CHECKPOINT;
5915 // goto main_loop instead of MINT_IN_DISPATCH helps the compiler and therefore conserves stack.
5916 // This is a slow/rare path and conserving stack is preferred over its performance otherwise.
5917 goto main_loop;
5919 ves_abort();
5920 MINT_IN_BREAK;
5923 MINT_IN_CASE(MINT_LEAVE)
5924 MINT_IN_CASE(MINT_LEAVE_S)
5925 MINT_IN_CASE(MINT_LEAVE_CHECK)
5926 MINT_IN_CASE(MINT_LEAVE_S_CHECK) {
5928 // Leave is split into pieces in order to consume less stack,
5929 // but not have to change how exception handling macros access labels and locals.
5931 g_assert (sp >= frame->stack);
5932 sp = frame->stack;
5933 frame->ip = ip;
5935 int opcode = *ip;
5936 gboolean const check = opcode == MINT_LEAVE_CHECK || opcode == MINT_LEAVE_S_CHECK;
5938 if (check && frame->imethod->method->wrapper_type != MONO_WRAPPER_RUNTIME_INVOKE) {
5939 child_frame.parent = frame;
5940 child_frame.imethod = NULL;
5941 MonoException *abort_exc = mono_interp_leave (&child_frame);
5942 if (abort_exc)
5943 THROW_EX (abort_exc, frame->ip);
5946 opcode = *ip; // Refetch to avoid register/stack pressure.
5947 gboolean const short_offset = opcode == MINT_LEAVE_S || opcode == MINT_LEAVE_S_CHECK;
5948 ip += short_offset ? (short)*(ip + 1) : (gint32)READ32 (ip + 1);
5949 endfinally_ip = ip;
5950 GSList *old_list = finally_ips;
5951 MonoMethod *method = frame->imethod->method;
5952 #if DEBUG_INTERP
5953 if (tracing)
5954 g_print ("* Handle finally IL_%04x\n", endfinally_ip == NULL ? 0 : endfinally_ip - frame->imethod->code);
5955 #endif
5956 // FIXME Null check for frame->imethod follows deref.
5957 if (frame->imethod == NULL || (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
5958 || (method->iflags & (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL | METHOD_IMPL_ATTRIBUTE_RUNTIME))) {
5959 goto exit_frame;
5961 guint32 const ip_offset = frame->ip - frame->imethod->code;
5963 if (endfinally_ip != NULL)
5964 finally_ips = g_slist_prepend (finally_ips, (void *)endfinally_ip);
5966 for (int i = frame->imethod->num_clauses - 1; i >= 0; i--) {
5967 MonoExceptionClause* const clause = &frame->imethod->clauses [i];
5968 if (MONO_OFFSET_IN_CLAUSE (clause, ip_offset) && (endfinally_ip == NULL || !(MONO_OFFSET_IN_CLAUSE (clause, endfinally_ip - frame->imethod->code)))) {
5969 if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY) {
5970 ip = frame->imethod->code + clause->handler_offset;
5971 finally_ips = g_slist_prepend (finally_ips, (gpointer) ip);
5972 #if DEBUG_INTERP
5973 if (tracing)
5974 g_print ("* Found finally at IL_%04x with exception: %s\n", clause->handler_offset, frame->ex? "yes": "no");
5975 #endif
5980 endfinally_ip = NULL;
5982 if (old_list != finally_ips && finally_ips) {
5983 ip = (const guint16*)finally_ips->data;
5984 finally_ips = g_slist_remove (finally_ips, ip);
5985 sp = frame->stack; /* spec says stack should be empty at endfinally so it should be at the start too */
5986 vt_sp = (unsigned char *) sp + frame->imethod->stack_size;
5987 // goto main_loop instead of MINT_IN_DISPATCH helps the compiler and therefore conserves stack.
5988 // This is a slow/rare path and conserving stack is preferred over its performance otherwise.
5989 goto main_loop;
5992 ves_abort();
5993 MINT_IN_BREAK;
5995 MINT_IN_CASE(MINT_ICALL_V_V)
5996 MINT_IN_CASE(MINT_ICALL_V_P)
5997 MINT_IN_CASE(MINT_ICALL_P_V)
5998 MINT_IN_CASE(MINT_ICALL_P_P)
5999 MINT_IN_CASE(MINT_ICALL_PP_V)
6000 MINT_IN_CASE(MINT_ICALL_PP_P)
6001 MINT_IN_CASE(MINT_ICALL_PPP_V)
6002 MINT_IN_CASE(MINT_ICALL_PPP_P)
6003 MINT_IN_CASE(MINT_ICALL_PPPP_V)
6004 MINT_IN_CASE(MINT_ICALL_PPPP_P)
6005 MINT_IN_CASE(MINT_ICALL_PPPPP_V)
6006 MINT_IN_CASE(MINT_ICALL_PPPPP_P)
6007 MINT_IN_CASE(MINT_ICALL_PPPPPP_V)
6008 MINT_IN_CASE(MINT_ICALL_PPPPPP_P)
6009 frame->ip = ip;
6010 sp = do_icall_wrapper (frame, NULL, *ip, sp, frame->imethod->data_items [*(guint16 *)(ip + 1)], FALSE);
6011 EXCEPTION_CHECKPOINT;
6012 CHECK_RESUME_STATE (context);
6013 ip += 2;
6014 MINT_IN_BREAK;
6015 MINT_IN_CASE(MINT_MONO_LDPTR)
6016 sp->data.p = frame->imethod->data_items [*(guint16 *)(ip + 1)];
6017 ip += 2;
6018 ++sp;
6019 MINT_IN_BREAK;
6020 MINT_IN_CASE(MINT_MONO_NEWOBJ)
6021 sp->data.o = mono_interp_new (frame->imethod->domain, (MonoClass*)frame->imethod->data_items [*(guint16 *)(ip + 1)]); // FIXME: do not swallow the error
6022 ip += 2;
6023 sp++;
6024 MINT_IN_BREAK;
6025 MINT_IN_CASE(MINT_MONO_FREE)
6026 ++ip;
6027 --sp;
6028 g_error ("that doesn't seem right");
6029 g_free (sp->data.p);
6030 MINT_IN_BREAK;
6031 MINT_IN_CASE(MINT_MONO_RETOBJ)
6032 ++ip;
6033 sp--;
6034 stackval_from_data (mono_method_signature_internal (frame->imethod->method)->ret, frame->retval, sp->data.p,
6035 mono_method_signature_internal (frame->imethod->method)->pinvoke);
6036 if (sp > frame->stack)
6037 g_warning ("retobj: more values on stack: %d", sp-frame->stack);
6038 goto exit_frame;
6039 MINT_IN_CASE(MINT_MONO_SGEN_THREAD_INFO)
6040 sp->data.p = mono_tls_get_sgen_thread_info ();
6041 sp++;
6042 ++ip;
6043 MINT_IN_BREAK;
6044 MINT_IN_CASE(MINT_MONO_MEMORY_BARRIER) {
6045 ++ip;
6046 mono_memory_barrier ();
6047 MINT_IN_BREAK;
6049 MINT_IN_CASE(MINT_MONO_LDDOMAIN)
6050 sp->data.p = mono_domain_get ();
6051 ++sp;
6052 ++ip;
6053 MINT_IN_BREAK;
6054 MINT_IN_CASE(MINT_SDB_INTR_LOC)
6055 if (G_UNLIKELY (ss_enabled)) {
6056 typedef void (*T) (void);
6057 static T ss_tramp;
6059 if (!ss_tramp) {
6060 void *tramp = mini_get_single_step_trampoline ();
6061 mono_memory_barrier ();
6062 ss_tramp = (T)tramp;
6066 * Make this point to the MINT_SDB_SEQ_POINT instruction which follows this since
6067 * the address of that instruction is stored as the seq point address.
6069 frame->ip = ip + 1;
6072 * Use the same trampoline as the JIT. This ensures that
6073 * the debugger has the context for the last interpreter
6074 * native frame.
6076 do_debugger_tramp (ss_tramp, frame);
6078 CHECK_RESUME_STATE (context);
6080 ++ip;
6081 MINT_IN_BREAK;
6082 MINT_IN_CASE(MINT_SDB_SEQ_POINT)
6083 /* Just a placeholder for a breakpoint */
6084 ++ip;
6085 MINT_IN_BREAK;
6086 MINT_IN_CASE(MINT_SDB_BREAKPOINT) {
6087 typedef void (*T) (void);
6088 static T bp_tramp;
6089 if (!bp_tramp) {
6090 void *tramp = mini_get_breakpoint_trampoline ();
6091 mono_memory_barrier ();
6092 bp_tramp = (T)tramp;
6095 frame->ip = ip;
6097 /* Use the same trampoline as the JIT */
6098 do_debugger_tramp (bp_tramp, frame);
6100 CHECK_RESUME_STATE (context);
6102 ++ip;
6103 MINT_IN_BREAK;
6106 #define RELOP(datamem, op) \
6107 --sp; \
6108 sp [-1].data.i = sp [-1].data.datamem op sp [0].data.datamem; \
6109 ++ip;
6111 #define RELOP_FP(datamem, op, noorder) \
6112 --sp; \
6113 if (mono_isunordered (sp [-1].data.datamem, sp [0].data.datamem)) \
6114 sp [-1].data.i = noorder; \
6115 else \
6116 sp [-1].data.i = sp [-1].data.datamem op sp [0].data.datamem; \
6117 ++ip;
6119 MINT_IN_CASE(MINT_CEQ_I4)
6120 RELOP(i, ==);
6121 MINT_IN_BREAK;
6122 MINT_IN_CASE(MINT_CEQ0_I4)
6123 sp [-1].data.i = (sp [-1].data.i == 0);
6124 ++ip;
6125 MINT_IN_BREAK;
6126 MINT_IN_CASE(MINT_CEQ_I8)
6127 RELOP(l, ==);
6128 MINT_IN_BREAK;
6129 MINT_IN_CASE(MINT_CEQ_R4)
6130 RELOP_FP(f_r4, ==, 0);
6131 MINT_IN_BREAK;
6132 MINT_IN_CASE(MINT_CEQ_R8)
6133 RELOP_FP(f, ==, 0);
6134 MINT_IN_BREAK;
6135 MINT_IN_CASE(MINT_CNE_I4)
6136 RELOP(i, !=);
6137 MINT_IN_BREAK;
6138 MINT_IN_CASE(MINT_CNE_I8)
6139 RELOP(l, !=);
6140 MINT_IN_BREAK;
6141 MINT_IN_CASE(MINT_CNE_R4)
6142 RELOP_FP(f_r4, !=, 1);
6143 MINT_IN_BREAK;
6144 MINT_IN_CASE(MINT_CNE_R8)
6145 RELOP_FP(f, !=, 1);
6146 MINT_IN_BREAK;
6147 MINT_IN_CASE(MINT_CGT_I4)
6148 RELOP(i, >);
6149 MINT_IN_BREAK;
6150 MINT_IN_CASE(MINT_CGT_I8)
6151 RELOP(l, >);
6152 MINT_IN_BREAK;
6153 MINT_IN_CASE(MINT_CGT_R4)
6154 RELOP_FP(f_r4, >, 0);
6155 MINT_IN_BREAK;
6156 MINT_IN_CASE(MINT_CGT_R8)
6157 RELOP_FP(f, >, 0);
6158 MINT_IN_BREAK;
6159 MINT_IN_CASE(MINT_CGE_I4)
6160 RELOP(i, >=);
6161 MINT_IN_BREAK;
6162 MINT_IN_CASE(MINT_CGE_I8)
6163 RELOP(l, >=);
6164 MINT_IN_BREAK;
6165 MINT_IN_CASE(MINT_CGE_R4)
6166 RELOP_FP(f_r4, >=, 0);
6167 MINT_IN_BREAK;
6168 MINT_IN_CASE(MINT_CGE_R8)
6169 RELOP_FP(f, >=, 0);
6170 MINT_IN_BREAK;
6172 #define RELOP_CAST(datamem, op, type) \
6173 --sp; \
6174 sp [-1].data.i = (type)sp [-1].data.datamem op (type)sp [0].data.datamem; \
6175 ++ip;
6177 MINT_IN_CASE(MINT_CGE_UN_I4)
6178 RELOP_CAST(l, >=, guint32);
6179 MINT_IN_BREAK;
6180 MINT_IN_CASE(MINT_CGE_UN_I8)
6181 RELOP_CAST(l, >=, guint64);
6182 MINT_IN_BREAK;
6184 MINT_IN_CASE(MINT_CGT_UN_I4)
6185 RELOP_CAST(i, >, guint32);
6186 MINT_IN_BREAK;
6187 MINT_IN_CASE(MINT_CGT_UN_I8)
6188 RELOP_CAST(l, >, guint64);
6189 MINT_IN_BREAK;
6190 MINT_IN_CASE(MINT_CGT_UN_R4)
6191 RELOP_FP(f_r4, >, 1);
6192 MINT_IN_BREAK;
6193 MINT_IN_CASE(MINT_CGT_UN_R8)
6194 RELOP_FP(f, >, 1);
6195 MINT_IN_BREAK;
6196 MINT_IN_CASE(MINT_CLT_I4)
6197 RELOP(i, <);
6198 MINT_IN_BREAK;
6199 MINT_IN_CASE(MINT_CLT_I8)
6200 RELOP(l, <);
6201 MINT_IN_BREAK;
6202 MINT_IN_CASE(MINT_CLT_R4)
6203 RELOP_FP(f_r4, <, 0);
6204 MINT_IN_BREAK;
6205 MINT_IN_CASE(MINT_CLT_R8)
6206 RELOP_FP(f, <, 0);
6207 MINT_IN_BREAK;
6208 MINT_IN_CASE(MINT_CLT_UN_I4)
6209 RELOP_CAST(i, <, guint32);
6210 MINT_IN_BREAK;
6211 MINT_IN_CASE(MINT_CLT_UN_I8)
6212 RELOP_CAST(l, <, guint64);
6213 MINT_IN_BREAK;
6214 MINT_IN_CASE(MINT_CLT_UN_R4)
6215 RELOP_FP(f_r4, <, 1);
6216 MINT_IN_BREAK;
6217 MINT_IN_CASE(MINT_CLT_UN_R8)
6218 RELOP_FP(f, <, 1);
6219 MINT_IN_BREAK;
6220 MINT_IN_CASE(MINT_CLE_I4)
6221 RELOP(i, <=);
6222 MINT_IN_BREAK;
6223 MINT_IN_CASE(MINT_CLE_I8)
6224 RELOP(l, <=);
6225 MINT_IN_BREAK;
6226 MINT_IN_CASE(MINT_CLE_UN_I4)
6227 RELOP_CAST(l, <=, guint32);
6228 MINT_IN_BREAK;
6229 MINT_IN_CASE(MINT_CLE_UN_I8)
6230 RELOP_CAST(l, <=, guint64);
6231 MINT_IN_BREAK;
6232 MINT_IN_CASE(MINT_CLE_R4)
6233 RELOP_FP(f_r4, <=, 0);
6234 MINT_IN_BREAK;
6235 MINT_IN_CASE(MINT_CLE_R8)
6236 RELOP_FP(f, <=, 0);
6237 MINT_IN_BREAK;
6239 #undef RELOP
6240 #undef RELOP_FP
6241 #undef RELOP_CAST
6243 MINT_IN_CASE(MINT_LDFTN) {
6244 sp->data.p = frame->imethod->data_items [* (guint16 *)(ip + 1)];
6245 ++sp;
6246 ip += 2;
6247 MINT_IN_BREAK;
6249 MINT_IN_CASE(MINT_LDVIRTFTN) {
6250 InterpMethod *m = (InterpMethod*)frame->imethod->data_items [* (guint16 *)(ip + 1)];
6251 --sp;
6252 NULL_CHECK (sp->data.p);
6254 sp->data.p = get_virtual_method (m, sp->data.o->vtable);
6255 ip += 2;
6256 ++sp;
6257 MINT_IN_BREAK;
6259 MINT_IN_CASE(MINT_LDFTN_DYNAMIC) {
6260 MONO_API_ERROR_INIT (error);
6261 InterpMethod *m = mono_interp_get_imethod (mono_domain_get (), (MonoMethod*) sp [-1].data.p, error);
6262 mono_error_assert_ok (error);
6263 sp [-1].data.p = m;
6264 ip++;
6265 MINT_IN_BREAK;
6268 #define LDARG(datamem, argtype) \
6269 sp->data.datamem = (argtype) frame->stack_args [*(guint16 *)(ip + 1)].data.datamem; \
6270 ip += 2; \
6271 ++sp;
6273 MINT_IN_CASE(MINT_LDARG_I1) LDARG(i, gint8); MINT_IN_BREAK;
6274 MINT_IN_CASE(MINT_LDARG_U1) LDARG(i, guint8); MINT_IN_BREAK;
6275 MINT_IN_CASE(MINT_LDARG_I2) LDARG(i, gint16); MINT_IN_BREAK;
6276 MINT_IN_CASE(MINT_LDARG_U2) LDARG(i, guint16); MINT_IN_BREAK;
6277 MINT_IN_CASE(MINT_LDARG_I4) LDARG(i, gint32); MINT_IN_BREAK;
6278 MINT_IN_CASE(MINT_LDARG_I8) LDARG(l, gint64); MINT_IN_BREAK;
6279 MINT_IN_CASE(MINT_LDARG_R4) LDARG(f_r4, float); MINT_IN_BREAK;
6280 MINT_IN_CASE(MINT_LDARG_R8) LDARG(f, double); MINT_IN_BREAK;
6281 MINT_IN_CASE(MINT_LDARG_O) LDARG(p, gpointer); MINT_IN_BREAK;
6282 MINT_IN_CASE(MINT_LDARG_P) LDARG(p, gpointer); MINT_IN_BREAK;
6284 MINT_IN_CASE(MINT_LDARG_VT) {
6285 sp->data.p = vt_sp;
6286 int const i32 = READ32 (ip + 2);
6287 memcpy(sp->data.p, frame->stack_args [* (guint16 *)(ip + 1)].data.p, i32);
6288 vt_sp += ALIGN_TO (i32, MINT_VT_ALIGNMENT);
6289 ip += 4;
6290 ++sp;
6291 MINT_IN_BREAK;
6294 #define STARG(datamem, argtype) \
6295 --sp; \
6296 frame->stack_args [*(guint16 *)(ip + 1)].data.datamem = (argtype) sp->data.datamem; \
6297 ip += 2; \
6299 MINT_IN_CASE(MINT_STARG_I1) STARG(i, gint8); MINT_IN_BREAK;
6300 MINT_IN_CASE(MINT_STARG_U1) STARG(i, guint8); MINT_IN_BREAK;
6301 MINT_IN_CASE(MINT_STARG_I2) STARG(i, gint16); MINT_IN_BREAK;
6302 MINT_IN_CASE(MINT_STARG_U2) STARG(i, guint16); MINT_IN_BREAK;
6303 MINT_IN_CASE(MINT_STARG_I4) STARG(i, gint32); MINT_IN_BREAK;
6304 MINT_IN_CASE(MINT_STARG_I8) STARG(l, gint64); MINT_IN_BREAK;
6305 MINT_IN_CASE(MINT_STARG_R4) STARG(f_r4, float); MINT_IN_BREAK;
6306 MINT_IN_CASE(MINT_STARG_R8) STARG(f, double); MINT_IN_BREAK;
6307 MINT_IN_CASE(MINT_STARG_O) STARG(p, gpointer); MINT_IN_BREAK;
6308 MINT_IN_CASE(MINT_STARG_P) STARG(p, gpointer); MINT_IN_BREAK;
6310 MINT_IN_CASE(MINT_STARG_VT) {
6311 int const i32 = READ32 (ip + 2);
6312 --sp;
6313 memcpy(frame->stack_args [* (guint16 *)(ip + 1)].data.p, sp->data.p, i32);
6314 vt_sp -= ALIGN_TO (i32, MINT_VT_ALIGNMENT);
6315 ip += 4;
6316 MINT_IN_BREAK;
6318 MINT_IN_CASE(MINT_PROF_ENTER) {
6319 ip += 1;
6321 if (MONO_PROFILER_ENABLED (method_enter)) {
6322 MonoProfilerCallContext *prof_ctx = NULL;
6324 if (frame->imethod->prof_flags & MONO_PROFILER_CALL_INSTRUMENTATION_ENTER_CONTEXT) {
6325 prof_ctx = g_new0 (MonoProfilerCallContext, 1);
6326 prof_ctx->interp_frame = frame;
6327 prof_ctx->method = frame->imethod->method;
6330 MONO_PROFILER_RAISE (method_enter, (frame->imethod->method, prof_ctx));
6332 g_free (prof_ctx);
6335 MINT_IN_BREAK;
6338 MINT_IN_CASE(MINT_TRACE_ENTER) {
6339 ip += 1;
6341 MonoProfilerCallContext *prof_ctx = g_alloca (sizeof (MonoProfilerCallContext));
6342 prof_ctx->interp_frame = frame;
6343 prof_ctx->method = frame->imethod->method;
6345 mono_trace_enter_method (frame->imethod->method, prof_ctx);
6346 MINT_IN_BREAK;
6349 MINT_IN_CASE(MINT_TRACE_EXIT) {
6350 // Set retval
6351 int const i32 = READ32 (ip + 1);
6352 --sp;
6353 if (i32 == -1)
6355 else if (i32)
6356 memcpy(frame->retval->data.p, sp->data.p, i32);
6357 else
6358 *frame->retval = *sp;
6360 MonoProfilerCallContext *prof_ctx = g_alloca (sizeof (MonoProfilerCallContext));
6361 prof_ctx->interp_frame = frame;
6362 prof_ctx->method = frame->imethod->method;
6364 mono_trace_leave_method (frame->imethod->method, prof_ctx);
6365 ip += 3;
6366 goto exit_frame;
6369 MINT_IN_CASE(MINT_LDARGA)
6370 sp->data.p = &frame->stack_args [* (guint16 *)(ip + 1)];
6371 ip += 2;
6372 ++sp;
6373 MINT_IN_BREAK;
6375 MINT_IN_CASE(MINT_LDARGA_VT)
6376 sp->data.p = frame->stack_args [* (guint16 *)(ip + 1)].data.p;
6377 ip += 2;
6378 ++sp;
6379 MINT_IN_BREAK;
6381 #define LDLOC(datamem, argtype) \
6382 sp->data.datamem = * (argtype *)(locals + * (guint16 *)(ip + 1)); \
6383 ip += 2; \
6384 ++sp;
6386 MINT_IN_CASE(MINT_LDLOC_I1) LDLOC(i, gint8); MINT_IN_BREAK;
6387 MINT_IN_CASE(MINT_LDLOC_U1) LDLOC(i, guint8); MINT_IN_BREAK;
6388 MINT_IN_CASE(MINT_LDLOC_I2) LDLOC(i, gint16); MINT_IN_BREAK;
6389 MINT_IN_CASE(MINT_LDLOC_U2) LDLOC(i, guint16); MINT_IN_BREAK;
6390 MINT_IN_CASE(MINT_LDLOC_I4) LDLOC(i, gint32); MINT_IN_BREAK;
6391 MINT_IN_CASE(MINT_LDLOC_I8) LDLOC(l, gint64); MINT_IN_BREAK;
6392 MINT_IN_CASE(MINT_LDLOC_R4) LDLOC(f_r4, float); MINT_IN_BREAK;
6393 MINT_IN_CASE(MINT_LDLOC_R8) LDLOC(f, double); MINT_IN_BREAK;
6394 MINT_IN_CASE(MINT_LDLOC_O) LDLOC(p, gpointer); MINT_IN_BREAK;
6395 MINT_IN_CASE(MINT_LDLOC_P) LDLOC(p, gpointer); MINT_IN_BREAK;
6397 MINT_IN_CASE(MINT_LDLOC_VT) {
6398 sp->data.p = vt_sp;
6399 int const i32 = READ32 (ip + 2);
6400 memcpy(sp->data.p, locals + * (guint16 *)(ip + 1), i32);
6401 vt_sp += ALIGN_TO (i32, MINT_VT_ALIGNMENT);
6402 ip += 4;
6403 ++sp;
6404 MINT_IN_BREAK;
6406 MINT_IN_CASE(MINT_LDLOCA_S)
6407 sp->data.p = locals + * (guint16 *)(ip + 1);
6408 ip += 2;
6409 ++sp;
6410 MINT_IN_BREAK;
6412 #define STLOC(datamem, argtype) \
6413 --sp; \
6414 * (argtype *)(locals + * (guint16 *)(ip + 1)) = sp->data.datamem; \
6415 ip += 2;
6417 MINT_IN_CASE(MINT_STLOC_I1) STLOC(i, gint8); MINT_IN_BREAK;
6418 MINT_IN_CASE(MINT_STLOC_U1) STLOC(i, guint8); MINT_IN_BREAK;
6419 MINT_IN_CASE(MINT_STLOC_I2) STLOC(i, gint16); MINT_IN_BREAK;
6420 MINT_IN_CASE(MINT_STLOC_U2) STLOC(i, guint16); MINT_IN_BREAK;
6421 MINT_IN_CASE(MINT_STLOC_I4) STLOC(i, gint32); MINT_IN_BREAK;
6422 MINT_IN_CASE(MINT_STLOC_I8) STLOC(l, gint64); MINT_IN_BREAK;
6423 MINT_IN_CASE(MINT_STLOC_R4) STLOC(f_r4, float); MINT_IN_BREAK;
6424 MINT_IN_CASE(MINT_STLOC_R8) STLOC(f, double); MINT_IN_BREAK;
6425 MINT_IN_CASE(MINT_STLOC_O) STLOC(p, gpointer); MINT_IN_BREAK;
6426 MINT_IN_CASE(MINT_STLOC_P) STLOC(p, gpointer); MINT_IN_BREAK;
6428 #define STLOC_NP(datamem, argtype) \
6429 * (argtype *)(locals + * (guint16 *)(ip + 1)) = sp [-1].data.datamem; \
6430 ip += 2;
6432 MINT_IN_CASE(MINT_STLOC_NP_I4) STLOC_NP(i, gint32); MINT_IN_BREAK;
6433 MINT_IN_CASE(MINT_STLOC_NP_O) STLOC_NP(p, gpointer); MINT_IN_BREAK;
6435 MINT_IN_CASE(MINT_STLOC_VT) {
6436 int const i32 = READ32 (ip + 2);
6437 --sp;
6438 memcpy(locals + * (guint16 *)(ip + 1), sp->data.p, i32);
6439 vt_sp -= ALIGN_TO (i32, MINT_VT_ALIGNMENT);
6440 ip += 4;
6441 MINT_IN_BREAK;
6443 MINT_IN_CASE(MINT_LOCALLOC) {
6444 if (sp != frame->stack + 1) /*FIX?*/
6445 goto abort_label;
6447 int len = sp [-1].data.i;
6448 sp [-1].data.p = alloca (len);
6450 if (frame->imethod->init_locals)
6451 memset (sp [-1].data.p, 0, len);
6452 ++ip;
6453 MINT_IN_BREAK;
6455 MINT_IN_CASE(MINT_ENDFILTER)
6456 /* top of stack is result of filter */
6457 frame->retval = &sp [-1];
6458 goto exit_frame;
6459 MINT_IN_CASE(MINT_INITOBJ)
6460 --sp;
6461 memset (sp->data.vt, 0, READ32(ip + 1));
6462 ip += 3;
6463 MINT_IN_BREAK;
6464 MINT_IN_CASE(MINT_CPBLK)
6465 sp -= 3;
6466 if (!sp [0].data.p || !sp [1].data.p)
6467 THROW_EX (mono_get_exception_null_reference(), ip - 1);
6468 ++ip;
6469 /* FIXME: value and size may be int64... */
6470 memcpy (sp [0].data.p, sp [1].data.p, sp [2].data.i);
6471 MINT_IN_BREAK;
6472 #if 0
6473 MINT_IN_CASE(MINT_CONSTRAINED_) {
6474 guint32 token;
6475 /* FIXME: implement */
6476 ++ip;
6477 token = READ32 (ip);
6478 ip += 2;
6479 MINT_IN_BREAK;
6481 #endif
6482 MINT_IN_CASE(MINT_INITBLK)
6483 sp -= 3;
6484 NULL_CHECK (sp [0].data.p);
6485 ++ip;
6486 /* FIXME: value and size may be int64... */
6487 memset (sp [0].data.p, sp [1].data.i, sp [2].data.i);
6488 MINT_IN_BREAK;
6489 #if 0
6490 MINT_IN_CASE(MINT_NO_)
6491 /* FIXME: implement */
6492 ip += 2;
6493 MINT_IN_BREAK;
6494 #endif
6495 MINT_IN_CASE(MINT_RETHROW) {
6496 int exvar_offset = *(guint16*)(ip + 1);
6497 THROW_EX_GENERAL (*(MonoException**)(frame_locals (frame) + exvar_offset), ip, TRUE);
6498 MINT_IN_BREAK;
6500 MINT_IN_CASE(MINT_MONO_RETHROW) {
6502 * need to clarify what this should actually do:
6504 * Takes an exception from the stack and rethrows it.
6505 * This is useful for wrappers that don't want to have to
6506 * use CEE_THROW and lose the exception stacktrace.
6509 --sp;
6510 if (!sp->data.p)
6511 sp->data.p = mono_get_exception_null_reference ();
6513 THROW_EX_GENERAL ((MonoException *)sp->data.p, ip, TRUE);
6514 MINT_IN_BREAK;
6516 MINT_IN_CASE(MINT_LD_DELEGATE_METHOD_PTR) {
6517 MonoDelegate *del;
6519 --sp;
6520 del = (MonoDelegate*)sp->data.p;
6521 if (!del->interp_method) {
6522 /* Not created from interpreted code */
6523 MONO_API_ERROR_INIT (error);
6524 g_assert (del->method);
6525 del->interp_method = mono_interp_get_imethod (del->object.vtable->domain, del->method, error);
6526 mono_error_assert_ok (error);
6528 g_assert (del->interp_method);
6529 sp->data.p = del->interp_method;
6530 ++sp;
6531 ip += 1;
6532 MINT_IN_BREAK;
6534 MINT_IN_CASE(MINT_LD_DELEGATE_INVOKE_IMPL) {
6535 MonoDelegate *del;
6536 int n = *(guint16*)(ip + 1);
6537 del = (MonoDelegate*)sp [-n].data.p;
6538 if (!del->interp_invoke_impl) {
6540 * First time we are called. Set up the invoke wrapper. We might be able to do this
6541 * in ctor but we would need to handle AllocDelegateLike_internal separately
6543 MONO_API_ERROR_INIT (error);
6544 MonoMethod *invoke = mono_get_delegate_invoke_internal (del->object.vtable->klass);
6545 del->interp_invoke_impl = mono_interp_get_imethod (del->object.vtable->domain, mono_marshal_get_delegate_invoke (invoke, del), error);
6546 mono_error_assert_ok (error);
6548 sp ++;
6549 sp [-1].data.p = del->interp_invoke_impl;
6550 ip += 2;
6551 MINT_IN_BREAK;
6554 #define MATH_UNOP(mathfunc) \
6555 sp [-1].data.f = mathfunc (sp [-1].data.f); \
6556 ++ip;
6558 MINT_IN_CASE(MINT_ABS) MATH_UNOP(fabs); MINT_IN_BREAK;
6559 MINT_IN_CASE(MINT_ASIN) MATH_UNOP(asin); MINT_IN_BREAK;
6560 MINT_IN_CASE(MINT_ASINH) MATH_UNOP(asinh); MINT_IN_BREAK;
6561 MINT_IN_CASE(MINT_ACOS) MATH_UNOP(acos); MINT_IN_BREAK;
6562 MINT_IN_CASE(MINT_ACOSH) MATH_UNOP(acosh); MINT_IN_BREAK;
6563 MINT_IN_CASE(MINT_ATAN) MATH_UNOP(atan); MINT_IN_BREAK;
6564 MINT_IN_CASE(MINT_ATANH) MATH_UNOP(atanh); MINT_IN_BREAK;
6565 MINT_IN_CASE(MINT_COS) MATH_UNOP(cos); MINT_IN_BREAK;
6566 MINT_IN_CASE(MINT_CBRT) MATH_UNOP(cbrt); MINT_IN_BREAK;
6567 MINT_IN_CASE(MINT_COSH) MATH_UNOP(cosh); MINT_IN_BREAK;
6568 MINT_IN_CASE(MINT_SIN) MATH_UNOP(sin); MINT_IN_BREAK;
6569 MINT_IN_CASE(MINT_SQRT) MATH_UNOP(sqrt); MINT_IN_BREAK;
6570 MINT_IN_CASE(MINT_SINH) MATH_UNOP(sinh); MINT_IN_BREAK;
6571 MINT_IN_CASE(MINT_TAN) MATH_UNOP(tan); MINT_IN_BREAK;
6572 MINT_IN_CASE(MINT_TANH) MATH_UNOP(tanh); MINT_IN_BREAK;
6574 MINT_IN_CASE(MINT_INTRINS_ENUM_HASFLAG) {
6575 MonoClass *klass = (MonoClass*)frame->imethod->data_items[* (guint16 *)(ip + 1)];
6576 mono_interp_enum_hasflag (sp, klass);
6577 sp--;
6578 ip += 2;
6579 MINT_IN_BREAK;
6581 MINT_IN_CASE(MINT_INTRINS_GET_HASHCODE) {
6582 sp [-1].data.i = mono_object_hash_internal (sp [-1].data.o);
6583 ip++;
6584 MINT_IN_BREAK;
6586 MINT_IN_CASE(MINT_INTRINS_GET_TYPE) {
6587 NULL_CHECK (sp [-1].data.p);
6588 sp [-1].data.o = (MonoObject*) sp [-1].data.o->vtable->type;
6589 ip++;
6590 MINT_IN_BREAK;
6593 MINT_IN_DEFAULT
6594 g_error ("Unimplemented opcode: %04x %s at 0x%x\n", *ip, mono_interp_opname (*ip), ip - frame->imethod->code);
6598 g_assert_not_reached ();
6600 abort_label:
6601 THROW_EX (mono_get_exception_execution_engine (NULL), ip);
6602 null_label:
6603 THROW_EX (mono_get_exception_null_reference (), ip);
6604 div_zero_label:
6605 THROW_EX (mono_get_exception_divide_by_zero (), ip);
6606 overflow_label:
6607 THROW_EX (mono_get_exception_overflow (), ip);
6608 throw_error_label:
6609 THROW_EX (mono_error_convert_to_exception (error), ip);
6610 invalid_cast_label:
6611 THROW_EX (mono_get_exception_invalid_cast (), ip);
6612 resume:
6613 g_assert (context->has_resume_state);
6615 if (frame == context->handler_frame && (!clause_args || context->handler_ip < clause_args->end_at_ip)) {
6616 /* Set the current execution state to the resume state in context */
6618 ip = context->handler_ip;
6619 /* spec says stack should be empty at endfinally so it should be at the start too */
6620 sp = frame->stack;
6621 vt_sp = (guchar*)sp + frame->imethod->stack_size;
6622 if (frame->ex) {
6623 sp->data.p = frame->ex;
6624 ++sp;
6627 // FIXME Reevaluate if this should be inlined.
6628 finally_ips = set_resume_state (context, frame, finally_ips);
6629 // goto main_loop instead of MINT_IN_DISPATCH helps the compiler and therefore conserves stack.
6630 // This is a slow/rare path and conserving stack is preferred over its performance otherwise.
6632 goto main_loop;
6634 // fall through
6635 exit_frame:
6636 error_init_reuse (error);
6638 if (clause_args && clause_args->base_frame)
6639 memcpy (clause_args->base_frame->stack, frame->stack, frame->imethod->alloca_size);
6641 if (!frame->ex && MONO_PROFILER_ENABLED (method_leave) &&
6642 frame->imethod->prof_flags & MONO_PROFILER_CALL_INSTRUMENTATION_LEAVE) {
6643 MonoProfilerCallContext *prof_ctx = NULL;
6645 if (frame->imethod->prof_flags & MONO_PROFILER_CALL_INSTRUMENTATION_LEAVE_CONTEXT) {
6646 prof_ctx = g_new0 (MonoProfilerCallContext, 1);
6647 prof_ctx->interp_frame = frame;
6648 prof_ctx->method = frame->imethod->method;
6650 MonoType *rtype = mono_method_signature_internal (frame->imethod->method)->ret;
6652 switch (rtype->type) {
6653 case MONO_TYPE_VOID:
6654 break;
6655 case MONO_TYPE_VALUETYPE:
6656 prof_ctx->return_value = frame->retval->data.p;
6657 break;
6658 default:
6659 prof_ctx->return_value = frame->retval;
6660 break;
6664 MONO_PROFILER_RAISE (method_leave, (frame->imethod->method, prof_ctx));
6666 g_free (prof_ctx);
6667 } else if (frame->ex && frame->imethod->prof_flags & MONO_PROFILER_CALL_INSTRUMENTATION_EXCEPTION_LEAVE)
6668 MONO_PROFILER_RAISE (method_exception_leave, (frame->imethod->method, &frame->ex->object));
6670 DEBUG_LEAVE ();
6673 static void
6674 interp_parse_options (const char *options)
6676 char **args, **ptr;
6678 if (!options)
6679 return;
6681 args = g_strsplit (options, ",", -1);
6682 for (ptr = args; ptr && *ptr; ptr ++) {
6683 char *arg = *ptr;
6685 if (strncmp (arg, "jit=", 4) == 0)
6686 mono_interp_jit_classes = g_slist_prepend (mono_interp_jit_classes, arg + 4);
6687 if (strncmp (arg, "interp-only=", 4) == 0)
6688 mono_interp_only_classes = g_slist_prepend (mono_interp_only_classes, arg + strlen ("interp-only="));
6689 if (strncmp (arg, "-inline", 7) == 0)
6690 mono_interp_opt &= ~INTERP_OPT_INLINE;
6695 * interp_set_resume_state:
6697 * Set the state the interpeter will continue to execute from after execution returns to the interpreter.
6699 static void
6700 interp_set_resume_state (MonoJitTlsData *jit_tls, MonoException *ex, MonoJitExceptionInfo *ei, MonoInterpFrameHandle interp_frame, gpointer handler_ip)
6702 ThreadContext *context;
6704 g_assert (jit_tls);
6705 context = (ThreadContext*)jit_tls->interp_context;
6706 g_assert (context);
6708 context->has_resume_state = TRUE;
6709 context->handler_frame = (InterpFrame*)interp_frame;
6710 context->handler_ei = ei;
6711 /* This is on the stack, so it doesn't need a wbarrier */
6712 context->handler_frame->ex = ex;
6713 /* Ditto */
6714 if (ei)
6715 *(MonoException**)(frame_locals (context->handler_frame) + ei->exvar_offset) = ex;
6716 context->handler_ip = (const guint16*)handler_ip;
6719 static void
6720 interp_get_resume_state (const MonoJitTlsData *jit_tls, gboolean *has_resume_state, MonoInterpFrameHandle *interp_frame, gpointer *handler_ip)
6722 g_assert (jit_tls);
6723 ThreadContext *context = (ThreadContext*)jit_tls->interp_context;
6724 g_assert (context);
6725 *has_resume_state = context->has_resume_state;
6726 if (context->has_resume_state) {
6727 *interp_frame = context->handler_frame;
6728 *handler_ip = (gpointer)context->handler_ip;
6733 * interp_run_finally:
6735 * Run the finally clause identified by CLAUSE_INDEX in the intepreter frame given by
6736 * frame->interp_frame.
6737 * Return TRUE if the finally clause threw an exception.
6739 static gboolean
6740 interp_run_finally (StackFrameInfo *frame, int clause_index, gpointer handler_ip, gpointer handler_ip_end)
6742 InterpFrame *iframe = (InterpFrame*)frame->interp_frame;
6743 ThreadContext *context = get_context ();
6744 const unsigned short *old_ip = iframe->ip;
6745 FrameClauseArgs clause_args;
6747 memset (&clause_args, 0, sizeof (FrameClauseArgs));
6748 clause_args.start_with_ip = (const guint16*)handler_ip;
6749 clause_args.end_at_ip = (const guint16*)handler_ip_end;
6750 clause_args.exit_clause = clause_index;
6752 ERROR_DECL (error);
6753 interp_exec_method_full (iframe, context, &clause_args, error);
6754 if (context->has_resume_state) {
6755 return TRUE;
6756 } else {
6757 iframe->ip = old_ip;
6758 return FALSE;
6763 * interp_run_filter:
6765 * Run the filter clause identified by CLAUSE_INDEX in the intepreter frame given by
6766 * frame->interp_frame.
6768 static gboolean
6769 interp_run_filter (StackFrameInfo *frame, MonoException *ex, int clause_index, gpointer handler_ip, gpointer handler_ip_end)
6771 InterpFrame *iframe = (InterpFrame*)frame->interp_frame;
6772 ThreadContext *context = get_context ();
6773 InterpFrame child_frame;
6774 stackval retval;
6775 FrameClauseArgs clause_args;
6778 * Have to run the clause in a new frame which is a copy of IFRAME, since
6779 * during debugging, there are two copies of the frame on the stack.
6781 memset (&child_frame, 0, sizeof (InterpFrame));
6782 child_frame.imethod = iframe->imethod;
6783 child_frame.retval = &retval;
6784 child_frame.parent = iframe;
6785 child_frame.stack_args = iframe->stack_args;
6787 memset (&clause_args, 0, sizeof (FrameClauseArgs));
6788 clause_args.start_with_ip = (const guint16*)handler_ip;
6789 clause_args.end_at_ip = (const guint16*)handler_ip_end;
6790 clause_args.filter_exception = ex;
6791 clause_args.base_frame = iframe;
6793 ERROR_DECL (error);
6794 interp_exec_method_full (&child_frame, context, &clause_args, error);
6795 /* ENDFILTER stores the result into child_frame->retval */
6796 return child_frame.retval->data.i ? TRUE : FALSE;
6799 typedef struct {
6800 InterpFrame *current;
6801 } StackIter;
6804 * interp_frame_iter_init:
6806 * Initialize an iterator for iterating through interpreted frames.
6808 static void
6809 interp_frame_iter_init (MonoInterpStackIter *iter, gpointer interp_exit_data)
6811 StackIter *stack_iter = (StackIter*)iter;
6813 stack_iter->current = (InterpFrame*)interp_exit_data;
6817 * interp_frame_iter_next:
6819 * Fill out FRAME with date for the next interpreter frame.
6821 static gboolean
6822 interp_frame_iter_next (MonoInterpStackIter *iter, StackFrameInfo *frame)
6824 StackIter *stack_iter = (StackIter*)iter;
6825 InterpFrame *iframe = stack_iter->current;
6827 memset (frame, 0, sizeof (StackFrameInfo));
6828 /* pinvoke frames doesn't have imethod set */
6829 while (iframe && !(iframe->imethod && iframe->imethod->code && iframe->imethod->jinfo))
6830 iframe = iframe->parent;
6831 if (!iframe)
6832 return FALSE;
6834 MonoMethod *method = iframe->imethod->method;
6835 frame->domain = iframe->imethod->domain;
6836 frame->interp_frame = iframe;
6837 frame->method = method;
6838 frame->actual_method = method;
6839 if (method && ((method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) || (method->iflags & (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL | METHOD_IMPL_ATTRIBUTE_RUNTIME)))) {
6840 frame->native_offset = -1;
6841 frame->type = FRAME_TYPE_MANAGED_TO_NATIVE;
6842 } else {
6843 frame->type = FRAME_TYPE_INTERP;
6844 /* This is the offset in the interpreter IR */
6845 frame->native_offset = (guint8*)iframe->ip - (guint8*)iframe->imethod->code;
6846 if (!method->wrapper_type || method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD)
6847 frame->managed = TRUE;
6849 frame->ji = iframe->imethod->jinfo;
6850 frame->frame_addr = iframe;
6852 stack_iter->current = iframe->parent;
6854 return TRUE;
6857 static MonoJitInfo*
6858 interp_find_jit_info (MonoDomain *domain, MonoMethod *method)
6860 InterpMethod* imethod;
6862 imethod = lookup_imethod (domain, method);
6863 if (imethod)
6864 return imethod->jinfo;
6865 else
6866 return NULL;
6869 static void
6870 interp_set_breakpoint (MonoJitInfo *jinfo, gpointer ip)
6872 guint16 *code = (guint16*)ip;
6873 g_assert (*code == MINT_SDB_SEQ_POINT);
6874 *code = MINT_SDB_BREAKPOINT;
6877 static void
6878 interp_clear_breakpoint (MonoJitInfo *jinfo, gpointer ip)
6880 guint16 *code = (guint16*)ip;
6881 g_assert (*code == MINT_SDB_BREAKPOINT);
6882 *code = MINT_SDB_SEQ_POINT;
6885 static MonoJitInfo*
6886 interp_frame_get_jit_info (MonoInterpFrameHandle frame)
6888 InterpFrame *iframe = (InterpFrame*)frame;
6890 g_assert (iframe->imethod);
6891 return iframe->imethod->jinfo;
6894 static gpointer
6895 interp_frame_get_ip (MonoInterpFrameHandle frame)
6897 InterpFrame *iframe = (InterpFrame*)frame;
6899 g_assert (iframe->imethod);
6900 return (gpointer)iframe->ip;
6903 static gpointer
6904 interp_frame_get_arg (MonoInterpFrameHandle frame, int pos)
6906 InterpFrame *iframe = (InterpFrame*)frame;
6907 MonoMethodSignature *sig;
6909 g_assert (iframe->imethod);
6911 sig = mono_method_signature_internal (iframe->imethod->method);
6912 return stackval_to_data_addr (sig->params [pos], &iframe->stack_args [pos + !!iframe->imethod->hasthis]);
6915 static gpointer
6916 interp_frame_get_local (MonoInterpFrameHandle frame, int pos)
6918 InterpFrame *iframe = (InterpFrame*)frame;
6920 g_assert (iframe->imethod);
6922 return frame_locals (iframe) + iframe->imethod->local_offsets [pos];
6925 static gpointer
6926 interp_frame_get_this (MonoInterpFrameHandle frame)
6928 InterpFrame *iframe = (InterpFrame*)frame;
6930 g_assert (iframe->imethod);
6931 g_assert (iframe->imethod->hasthis);
6932 return &iframe->stack_args [0].data.p;
6935 static MonoInterpFrameHandle
6936 interp_frame_get_parent (MonoInterpFrameHandle frame)
6938 InterpFrame *iframe = (InterpFrame*)frame;
6940 return iframe->parent;
6943 static gpointer
6944 interp_frame_get_res (MonoInterpFrameHandle frame)
6946 InterpFrame *iframe = (InterpFrame*)frame;
6947 MonoMethodSignature *sig;
6949 g_assert (iframe->imethod);
6950 sig = mono_method_signature_internal (iframe->imethod->method);
6951 if (sig->ret->type == MONO_TYPE_VOID)
6952 return NULL;
6953 else
6954 return stackval_to_data_addr (sig->ret, iframe->retval);
6957 static void
6958 interp_start_single_stepping (void)
6960 ss_enabled = TRUE;
6963 static void
6964 interp_stop_single_stepping (void)
6966 ss_enabled = FALSE;
6969 static void
6970 register_interp_stats (void)
6972 mono_counters_init ();
6973 mono_counters_register ("Total transform time", MONO_COUNTER_INTERP | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_interp_stats.transform_time);
6974 mono_counters_register ("Methods inlined", MONO_COUNTER_INTERP | MONO_COUNTER_INT, &mono_interp_stats.inlined_methods);
6975 mono_counters_register ("Inline failures", MONO_COUNTER_INTERP | MONO_COUNTER_INT, &mono_interp_stats.inline_failures);
6978 #undef MONO_EE_CALLBACK
6979 #define MONO_EE_CALLBACK(ret, name, sig) interp_ ## name,
6981 static const MonoEECallbacks mono_interp_callbacks = {
6982 MONO_EE_CALLBACKS
6985 void
6986 mono_ee_interp_init (const char *opts)
6988 g_assert (mono_ee_api_version () == MONO_EE_API_VERSION);
6989 g_assert (!interp_init_done);
6990 interp_init_done = TRUE;
6992 mono_native_tls_alloc (&thread_context_id, NULL);
6993 set_context (NULL);
6995 interp_parse_options (opts);
6996 if (mini_get_debug_options ()->mdb_optimizations)
6997 mono_interp_opt &= ~INTERP_OPT_INLINE;
6998 mono_interp_transform_init ();
7000 mini_install_interp_callbacks (&mono_interp_callbacks);
7002 register_interp_stats ();