[interp] Outline STRMFLD_VT. (#16355)
[mono-project.git] / mono / mini / interp / interp.c
blob46a4601109a42add1f619eee9725e7bb7f5cc116
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 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 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 inline 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 static MONO_NEVER_INLINE GSList* // Inlining this causes caller to use more stack.
233 set_resume_state (ThreadContext *context, InterpFrame *frame, GSList* finally_ips)
235 /* We have thrown an exception from a finally block. Some of the leave targets were unwound already */
236 while (finally_ips &&
237 finally_ips->data >= context->handler_ei->try_start &&
238 finally_ips->data < context->handler_ei->try_end)
239 finally_ips = g_slist_remove (finally_ips, finally_ips->data);
240 frame->ex = NULL;
241 context->has_resume_state = 0;
242 context->handler_frame = NULL;
243 context->handler_ei = NULL;
244 return finally_ips;
247 /* Set the current execution state to the resume state in context */
248 #define SET_RESUME_STATE(context) do { \
249 ip = (const guint16*)(context)->handler_ip; \
250 /* spec says stack should be empty at endfinally so it should be at the start too */ \
251 sp = frame->stack; \
252 vt_sp = (unsigned char *) sp + imethod->stack_size; \
253 if (frame->ex) { \
254 sp->data.p = frame->ex; \
255 ++sp; \
257 (finally_ips) = set_resume_state ((context), (frame), (finally_ips)); \
258 /* goto main_loop instead of MINT_IN_DISPATCH helps the compiler and therefore conserves stack. \
259 * This is a slow/rare path and conserving stack is preferred over its performance otherwise. \
260 */ \
261 goto main_loop; \
262 } while (0)
265 * If this bit is set, it means the call has thrown the exception, and we
266 * reached this point because the EH code in mono_handle_exception ()
267 * unwound all the JITted frames below us. mono_interp_set_resume_state ()
268 * has set the fields in context to indicate where we have to resume execution.
270 #define CHECK_RESUME_STATE(context) do { \
271 if ((context)->has_resume_state) { \
272 if (frame == (context)->handler_frame && (!clause_args || (context)->handler_ip < clause_args->end_at_ip)) \
273 SET_RESUME_STATE (context); \
274 else \
275 goto exit_frame; \
277 } while (0)
279 // In a void function, leave ret empty.
280 #define CHECK_RESUME_STATE_IN_HELPER_FUNCTION(context, ret) do { \
281 if ((context)->has_resume_state) \
282 return ret; \
283 } while (0)
285 static void
286 set_context (ThreadContext *context)
288 mono_native_tls_set_value (thread_context_id, context);
290 if (!context)
291 return;
293 MonoJitTlsData *jit_tls = mono_tls_get_jit_tls ();
294 g_assertf (jit_tls, "ThreadContext needs initialized JIT TLS");
296 /* jit_tls assumes ownership of 'context' */
297 jit_tls->interp_context = context;
300 static ThreadContext *
301 get_context (void)
303 ThreadContext *context = (ThreadContext *) mono_native_tls_get_value (thread_context_id);
304 if (context == NULL) {
305 context = g_new0 (ThreadContext, 1);
306 set_context (context);
308 return context;
311 static MONO_NEVER_INLINE void
312 ves_real_abort (int line, MonoMethod *mh,
313 const unsigned short *ip, stackval *stack, stackval *sp)
315 ERROR_DECL (error);
316 MonoMethodHeader *header = mono_method_get_header_checked (mh, error);
317 mono_error_cleanup (error); /* FIXME: don't swallow the error */
318 g_printerr ("Execution aborted in method: %s::%s\n", m_class_get_name (mh->klass), mh->name);
319 g_printerr ("Line=%d IP=0x%04lx, Aborted execution\n", line, ip-(const unsigned short *) header->code);
320 g_printerr ("0x%04x %02x\n", ip-(const unsigned short *) header->code, *ip);
321 mono_metadata_free_mh (header);
324 #define ves_abort() \
325 do {\
326 ves_real_abort(__LINE__, frame->imethod->method, ip, frame->stack, sp); \
327 THROW_EX (mono_get_exception_execution_engine (NULL), ip); \
328 } while (0);
330 static InterpMethod*
331 lookup_imethod (MonoDomain *domain, MonoMethod *method)
333 InterpMethod *imethod;
334 MonoJitDomainInfo *info;
336 info = domain_jit_info (domain);
337 mono_domain_jit_code_hash_lock (domain);
338 imethod = (InterpMethod*)mono_internal_hash_table_lookup (&info->interp_code_hash, method);
339 mono_domain_jit_code_hash_unlock (domain);
340 return imethod;
343 static gpointer
344 interp_get_remoting_invoke (MonoMethod *method, gpointer addr, MonoError *error)
346 #ifndef DISABLE_REMOTING
347 InterpMethod *imethod;
349 if (addr) {
350 imethod = lookup_method_pointer (addr);
351 } else {
352 g_assert (method);
353 imethod = mono_interp_get_imethod (mono_domain_get (), method, error);
354 return_val_if_nok (error, NULL);
356 g_assert (imethod);
357 g_assert (mono_use_interpreter);
359 MonoMethod *remoting_invoke_method = mono_marshal_get_remoting_invoke (imethod->method, error);
360 return_val_if_nok (error, NULL);
361 return mono_interp_get_imethod (mono_domain_get (), remoting_invoke_method, error);
362 #else
363 g_assert_not_reached ();
364 return NULL;
365 #endif
368 InterpMethod*
369 mono_interp_get_imethod (MonoDomain *domain, MonoMethod *method, MonoError *error)
371 InterpMethod *imethod;
372 MonoJitDomainInfo *info;
373 MonoMethodSignature *sig;
374 int i;
376 error_init (error);
378 info = domain_jit_info (domain);
379 mono_domain_jit_code_hash_lock (domain);
380 imethod = (InterpMethod*)mono_internal_hash_table_lookup (&info->interp_code_hash, method);
381 mono_domain_jit_code_hash_unlock (domain);
382 if (imethod)
383 return imethod;
385 sig = mono_method_signature_internal (method);
387 imethod = (InterpMethod*)mono_domain_alloc0 (domain, sizeof (InterpMethod));
388 imethod->method = method;
389 imethod->domain = domain;
390 imethod->param_count = sig->param_count;
391 imethod->hasthis = sig->hasthis;
392 imethod->vararg = sig->call_convention == MONO_CALL_VARARG;
393 imethod->rtype = mini_get_underlying_type (sig->ret);
394 imethod->param_types = (MonoType**)mono_domain_alloc0 (domain, sizeof (MonoType*) * sig->param_count);
395 for (i = 0; i < sig->param_count; ++i)
396 imethod->param_types [i] = mini_get_underlying_type (sig->params [i]);
398 mono_domain_jit_code_hash_lock (domain);
399 if (!mono_internal_hash_table_lookup (&info->interp_code_hash, method))
400 mono_internal_hash_table_insert (&info->interp_code_hash, method, imethod);
401 mono_domain_jit_code_hash_unlock (domain);
403 imethod->prof_flags = mono_profiler_get_call_instrumentation_flags (imethod->method);
405 return imethod;
408 #if defined (MONO_CROSS_COMPILE) || defined (HOST_WASM)
409 #define INTERP_PUSH_LMF_WITH_CTX_BODY(ext, exit_label) \
410 (ext).kind = MONO_LMFEXT_INTERP_EXIT;
412 #elif defined(MONO_ARCH_HAS_NO_PROPER_MONOCTX)
413 /* some platforms, e.g. appleTV, don't provide us a precise MonoContext
414 * (registers are not accurate), thus resuming to the label does not work. */
415 #define INTERP_PUSH_LMF_WITH_CTX_BODY(ext, exit_label) \
416 (ext).kind = MONO_LMFEXT_INTERP_EXIT;
417 #elif defined (_MSC_VER)
418 #define INTERP_PUSH_LMF_WITH_CTX_BODY(ext, exit_label) \
419 (ext).kind = MONO_LMFEXT_INTERP_EXIT_WITH_CTX; \
420 (ext).interp_exit_label_set = FALSE; \
421 MONO_CONTEXT_GET_CURRENT ((ext).ctx); \
422 if ((ext).interp_exit_label_set == FALSE) \
423 mono_arch_do_ip_adjustment (&(ext).ctx); \
424 if ((ext).interp_exit_label_set == TRUE) \
425 goto exit_label; \
426 (ext).interp_exit_label_set = TRUE;
427 #elif defined(MONO_ARCH_HAS_MONO_CONTEXT)
428 #define INTERP_PUSH_LMF_WITH_CTX_BODY(ext, exit_label) \
429 (ext).kind = MONO_LMFEXT_INTERP_EXIT_WITH_CTX; \
430 MONO_CONTEXT_GET_CURRENT ((ext).ctx); \
431 MONO_CONTEXT_SET_IP (&(ext).ctx, (&&exit_label)); \
432 mono_arch_do_ip_adjustment (&(ext).ctx);
433 #else
434 #define INTERP_PUSH_LMF_WITH_CTX_BODY(ext, exit_label) g_error ("requires working mono-context");
435 #endif
437 /* INTERP_PUSH_LMF_WITH_CTX:
439 * same as interp_push_lmf, but retrieving and attaching MonoContext to it.
440 * This is needed to resume into the interp when the exception is thrown from
441 * native code (see ./mono/tests/install_eh_callback.exe).
443 * This must be a macro in order to retrieve the right register values for
444 * MonoContext.
446 #define INTERP_PUSH_LMF_WITH_CTX(frame, ext, exit_label) \
447 memset (&(ext), 0, sizeof (MonoLMFExt)); \
448 (ext).interp_exit_data = (frame); \
449 INTERP_PUSH_LMF_WITH_CTX_BODY ((ext), exit_label); \
450 mono_push_lmf (&(ext));
453 * interp_push_lmf:
455 * Push an LMF frame on the LMF stack
456 * to mark the transition to native code.
457 * This is needed for the native code to
458 * be able to do stack walks.
460 static void
461 interp_push_lmf (MonoLMFExt *ext, InterpFrame *frame)
463 memset (ext, 0, sizeof (MonoLMFExt));
464 ext->kind = MONO_LMFEXT_INTERP_EXIT;
465 ext->interp_exit_data = frame;
467 mono_push_lmf (ext);
470 static void
471 interp_pop_lmf (MonoLMFExt *ext)
473 mono_pop_lmf (&ext->lmf);
476 static MONO_NEVER_INLINE InterpMethod*
477 get_virtual_method (InterpMethod *imethod, MonoVTable *vtable)
479 MonoMethod *m = imethod->method;
480 MonoDomain *domain = imethod->domain;
481 InterpMethod *ret = NULL;
483 #ifndef DISABLE_REMOTING
484 if (mono_class_is_transparent_proxy (vtable->klass)) {
485 ERROR_DECL (error);
486 MonoMethod *remoting_invoke_method = mono_marshal_get_remoting_invoke_with_check (m, error);
487 mono_error_assert_ok (error);
488 ret = mono_interp_get_imethod (domain, remoting_invoke_method, error);
489 mono_error_assert_ok (error);
490 return ret;
492 #endif
494 if ((m->flags & METHOD_ATTRIBUTE_FINAL) || !(m->flags & METHOD_ATTRIBUTE_VIRTUAL)) {
495 if (m->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED) {
496 ERROR_DECL (error);
497 ret = mono_interp_get_imethod (domain, mono_marshal_get_synchronized_wrapper (m), error);
498 mono_error_cleanup (error); /* FIXME: don't swallow the error */
499 } else {
500 ret = imethod;
502 return ret;
505 mono_class_setup_vtable (vtable->klass);
507 int slot = mono_method_get_vtable_slot (m);
508 if (mono_class_is_interface (m->klass)) {
509 g_assert (vtable->klass != m->klass);
510 /* TODO: interface offset lookup is slow, go through IMT instead */
511 gboolean non_exact_match;
512 slot += mono_class_interface_offset_with_variance (vtable->klass, m->klass, &non_exact_match);
515 MonoMethod *virtual_method = m_class_get_vtable (vtable->klass) [slot];
516 if (m->is_inflated && mono_method_get_context (m)->method_inst) {
517 MonoGenericContext context = { NULL, NULL };
519 if (mono_class_is_ginst (virtual_method->klass))
520 context.class_inst = mono_class_get_generic_class (virtual_method->klass)->context.class_inst;
521 else if (mono_class_is_gtd (virtual_method->klass))
522 context.class_inst = mono_class_get_generic_container (virtual_method->klass)->context.class_inst;
523 context.method_inst = mono_method_get_context (m)->method_inst;
525 ERROR_DECL (error);
526 virtual_method = mono_class_inflate_generic_method_checked (virtual_method, &context, error);
527 mono_error_cleanup (error); /* FIXME: don't swallow the error */
530 if (virtual_method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) {
531 virtual_method = mono_marshal_get_native_wrapper (virtual_method, FALSE, FALSE);
534 if (virtual_method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED) {
535 virtual_method = mono_marshal_get_synchronized_wrapper (virtual_method);
538 ERROR_DECL (error);
539 InterpMethod *virtual_imethod = mono_interp_get_imethod (domain, virtual_method, error);
540 mono_error_cleanup (error); /* FIXME: don't swallow the error */
541 return virtual_imethod;
544 typedef struct {
545 InterpMethod *imethod;
546 InterpMethod *target_imethod;
547 } InterpVTableEntry;
549 /* domain lock must be held */
550 static GSList*
551 append_imethod (MonoDomain *domain, GSList *list, InterpMethod *imethod, InterpMethod *target_imethod)
553 GSList *ret;
554 InterpVTableEntry *entry;
556 entry = (InterpVTableEntry*) mono_mempool_alloc (domain->mp, sizeof (InterpVTableEntry));
557 entry->imethod = imethod;
558 entry->target_imethod = target_imethod;
559 ret = g_slist_append_mempool (domain->mp, list, entry);
561 return ret;
564 static InterpMethod*
565 get_target_imethod (GSList *list, InterpMethod *imethod)
567 while (list != NULL) {
568 InterpVTableEntry *entry = (InterpVTableEntry*) list->data;
569 if (entry->imethod == imethod)
570 return entry->target_imethod;
571 list = list->next;
573 return NULL;
576 static gpointer*
577 get_method_table (MonoVTable *vtable, int offset)
579 if (offset >= 0)
580 return vtable->interp_vtable;
581 else
582 return (gpointer*)vtable;
585 static gpointer*
586 alloc_method_table (MonoVTable *vtable, int offset)
588 gpointer *table;
590 if (offset >= 0) {
591 table = mono_domain_alloc0 (vtable->domain, m_class_get_vtable_size (vtable->klass) * sizeof (gpointer));
592 vtable->interp_vtable = table;
593 } else {
594 table = (gpointer*)vtable;
597 return table;
600 static MONO_NEVER_INLINE InterpMethod* // Inlining causes additional stack use in caller.
601 get_virtual_method_fast (InterpMethod *imethod, MonoVTable *vtable, int offset)
603 gpointer *table;
605 #ifndef DISABLE_REMOTING
606 /* FIXME Remoting */
607 if (mono_class_is_transparent_proxy (vtable->klass))
608 return get_virtual_method (imethod, vtable);
609 #endif
611 table = get_method_table (vtable, offset);
613 if (!table) {
614 /* Lazily allocate method table */
615 mono_domain_lock (vtable->domain);
616 table = get_method_table (vtable, offset);
617 if (!table)
618 table = alloc_method_table (vtable, offset);
619 mono_domain_unlock (vtable->domain);
622 if (!table [offset]) {
623 InterpMethod *target_imethod = get_virtual_method (imethod, vtable);
624 /* Lazily initialize the method table slot */
625 mono_domain_lock (vtable->domain);
626 if (!table [offset]) {
627 if (imethod->method->is_inflated || offset < 0)
628 table [offset] = append_imethod (vtable->domain, NULL, imethod, target_imethod);
629 else
630 table [offset] = (gpointer) ((gsize)target_imethod | 0x1);
632 mono_domain_unlock (vtable->domain);
635 if ((gsize)table [offset] & 0x1) {
636 /* Non generic virtual call. Only one method in slot */
637 return (InterpMethod*) ((gsize)table [offset] & ~0x1);
638 } else {
639 /* Virtual generic or interface call. Multiple methods in slot */
640 InterpMethod *target_imethod = get_target_imethod ((GSList*)table [offset], imethod);
642 if (!target_imethod) {
643 target_imethod = get_virtual_method (imethod, vtable);
644 mono_domain_lock (vtable->domain);
645 if (!get_target_imethod ((GSList*)table [offset], imethod))
646 table [offset] = append_imethod (vtable->domain, (GSList*)table [offset], imethod, target_imethod);
647 mono_domain_unlock (vtable->domain);
649 return target_imethod;
653 static void inline
654 stackval_from_data (MonoType *type_, stackval *result, void *data, gboolean pinvoke)
656 MonoType *type = mini_native_type_replace_type (type_);
657 if (type->byref) {
658 switch (type->type) {
659 case MONO_TYPE_OBJECT:
660 case MONO_TYPE_CLASS:
661 case MONO_TYPE_STRING:
662 case MONO_TYPE_ARRAY:
663 case MONO_TYPE_SZARRAY:
664 break;
665 default:
666 break;
668 result->data.p = *(gpointer*)data;
669 return;
671 switch (type->type) {
672 case MONO_TYPE_VOID:
673 return;
674 case MONO_TYPE_I1:
675 result->data.i = *(gint8*)data;
676 return;
677 case MONO_TYPE_U1:
678 case MONO_TYPE_BOOLEAN:
679 result->data.i = *(guint8*)data;
680 return;
681 case MONO_TYPE_I2:
682 result->data.i = *(gint16*)data;
683 return;
684 case MONO_TYPE_U2:
685 case MONO_TYPE_CHAR:
686 result->data.i = *(guint16*)data;
687 return;
688 case MONO_TYPE_I4:
689 result->data.i = *(gint32*)data;
690 return;
691 case MONO_TYPE_U:
692 case MONO_TYPE_I:
693 result->data.nati = *(mono_i*)data;
694 return;
695 case MONO_TYPE_PTR:
696 result->data.p = *(gpointer*)data;
697 return;
698 case MONO_TYPE_U4:
699 result->data.i = *(guint32*)data;
700 return;
701 case MONO_TYPE_R4:
702 /* memmove handles unaligned case */
703 memmove (&result->data.f_r4, data, sizeof (float));
704 return;
705 case MONO_TYPE_I8:
706 case MONO_TYPE_U8:
707 memmove (&result->data.l, data, sizeof (gint64));
708 return;
709 case MONO_TYPE_R8:
710 memmove (&result->data.f, data, sizeof (double));
711 return;
712 case MONO_TYPE_STRING:
713 case MONO_TYPE_SZARRAY:
714 case MONO_TYPE_CLASS:
715 case MONO_TYPE_OBJECT:
716 case MONO_TYPE_ARRAY:
717 result->data.p = *(gpointer*)data;
718 return;
719 case MONO_TYPE_VALUETYPE:
720 if (m_class_is_enumtype (type->data.klass)) {
721 stackval_from_data (mono_class_enum_basetype_internal (type->data.klass), result, data, pinvoke);
722 return;
723 } else if (pinvoke) {
724 memcpy (result->data.vt, data, mono_class_native_size (type->data.klass, NULL));
725 } else {
726 mono_value_copy_internal (result->data.vt, data, type->data.klass);
728 return;
729 case MONO_TYPE_GENERICINST: {
730 if (mono_type_generic_inst_is_valuetype (type)) {
731 mono_value_copy_internal (result->data.vt, data, mono_class_from_mono_type_internal (type));
732 return;
734 stackval_from_data (m_class_get_byval_arg (type->data.generic_class->container_class), result, data, pinvoke);
735 return;
737 default:
738 g_error ("got type 0x%02x", type->type);
742 static void inline
743 stackval_to_data (MonoType *type_, stackval *val, void *data, gboolean pinvoke)
745 MonoType *type = mini_native_type_replace_type (type_);
746 if (type->byref) {
747 gpointer *p = (gpointer*)data;
748 *p = val->data.p;
749 return;
751 /* printf ("TODAT0 %p\n", data); */
752 switch (type->type) {
753 case MONO_TYPE_I1:
754 case MONO_TYPE_U1: {
755 guint8 *p = (guint8*)data;
756 *p = val->data.i;
757 return;
759 case MONO_TYPE_BOOLEAN: {
760 guint8 *p = (guint8*)data;
761 *p = (val->data.i != 0);
762 return;
764 case MONO_TYPE_I2:
765 case MONO_TYPE_U2:
766 case MONO_TYPE_CHAR: {
767 guint16 *p = (guint16*)data;
768 *p = val->data.i;
769 return;
771 case MONO_TYPE_I: {
772 mono_i *p = (mono_i*)data;
773 /* In theory the value used by stloc should match the local var type
774 but in practice it sometimes doesn't (a int32 gets dup'd and stloc'd into
775 a native int - both by csc and mcs). Not sure what to do about sign extension
776 as it is outside the spec... doing the obvious */
777 *p = (mono_i)val->data.nati;
778 return;
780 case MONO_TYPE_U: {
781 mono_u *p = (mono_u*)data;
782 /* see above. */
783 *p = (mono_u)val->data.nati;
784 return;
786 case MONO_TYPE_I4:
787 case MONO_TYPE_U4: {
788 gint32 *p = (gint32*)data;
789 *p = val->data.i;
790 return;
792 case MONO_TYPE_I8:
793 case MONO_TYPE_U8: {
794 memmove (data, &val->data.l, sizeof (gint64));
795 return;
797 case MONO_TYPE_R4: {
798 /* memmove handles unaligned case */
799 memmove (data, &val->data.f_r4, sizeof (float));
800 return;
802 case MONO_TYPE_R8: {
803 memmove (data, &val->data.f, sizeof (double));
804 return;
806 case MONO_TYPE_STRING:
807 case MONO_TYPE_SZARRAY:
808 case MONO_TYPE_CLASS:
809 case MONO_TYPE_OBJECT:
810 case MONO_TYPE_ARRAY: {
811 gpointer *p = (gpointer *) data;
812 mono_gc_wbarrier_generic_store_internal (p, val->data.o);
813 return;
815 case MONO_TYPE_PTR: {
816 gpointer *p = (gpointer *) data;
817 *p = val->data.p;
818 return;
820 case MONO_TYPE_VALUETYPE:
821 if (m_class_is_enumtype (type->data.klass)) {
822 stackval_to_data (mono_class_enum_basetype_internal (type->data.klass), val, data, pinvoke);
823 return;
824 } else if (pinvoke) {
825 memcpy (data, val->data.vt, mono_class_native_size (type->data.klass, NULL));
826 } else {
827 mono_value_copy_internal (data, val->data.vt, type->data.klass);
829 return;
830 case MONO_TYPE_GENERICINST: {
831 MonoClass *container_class = type->data.generic_class->container_class;
833 if (m_class_is_valuetype (container_class) && !m_class_is_enumtype (container_class)) {
834 mono_value_copy_internal (data, val->data.vt, mono_class_from_mono_type_internal (type));
835 return;
837 stackval_to_data (m_class_get_byval_arg (type->data.generic_class->container_class), val, data, pinvoke);
838 return;
840 default:
841 g_error ("got type %x", type->type);
846 * Same as stackval_to_data but return address of storage instead
847 * of copying the value.
849 static gpointer
850 stackval_to_data_addr (MonoType *type_, stackval *val)
852 MonoType *type = mini_native_type_replace_type (type_);
853 if (type->byref)
854 return &val->data.p;
856 switch (type->type) {
857 case MONO_TYPE_I1:
858 case MONO_TYPE_U1:
859 case MONO_TYPE_BOOLEAN:
860 case MONO_TYPE_I2:
861 case MONO_TYPE_U2:
862 case MONO_TYPE_CHAR:
863 case MONO_TYPE_I4:
864 case MONO_TYPE_U4:
865 return &val->data.i;
866 case MONO_TYPE_I:
867 case MONO_TYPE_U:
868 return &val->data.nati;
869 case MONO_TYPE_I8:
870 case MONO_TYPE_U8:
871 return &val->data.l;
872 case MONO_TYPE_R4:
873 return &val->data.f_r4;
874 case MONO_TYPE_R8:
875 return &val->data.f;
876 case MONO_TYPE_STRING:
877 case MONO_TYPE_SZARRAY:
878 case MONO_TYPE_CLASS:
879 case MONO_TYPE_OBJECT:
880 case MONO_TYPE_ARRAY:
881 case MONO_TYPE_PTR:
882 return &val->data.p;
883 case MONO_TYPE_VALUETYPE:
884 if (m_class_is_enumtype (type->data.klass))
885 return stackval_to_data_addr (mono_class_enum_basetype_internal (type->data.klass), val);
886 else
887 return val->data.vt;
888 case MONO_TYPE_TYPEDBYREF:
889 return val->data.vt;
890 case MONO_TYPE_GENERICINST: {
891 MonoClass *container_class = type->data.generic_class->container_class;
893 if (m_class_is_valuetype (container_class) && !m_class_is_enumtype (container_class))
894 return val->data.vt;
895 return stackval_to_data_addr (m_class_get_byval_arg (type->data.generic_class->container_class), val);
897 default:
898 g_error ("got type %x", type->type);
903 * interp_throw:
904 * Throw an exception from the interpreter.
906 static MONO_NEVER_INLINE void
907 interp_throw (ThreadContext *context, MonoException *ex, InterpFrame *frame, const guint16* ip, gboolean rethrow)
909 ERROR_DECL (error);
910 MonoLMFExt ext;
912 interp_push_lmf (&ext, frame);
913 frame->ip = ip;
914 frame->ex = ex;
916 if (mono_object_isinst_checked ((MonoObject *) ex, mono_defaults.exception_class, error)) {
917 MonoException *mono_ex = ex;
918 if (!rethrow) {
919 mono_ex->stack_trace = NULL;
920 mono_ex->trace_ips = NULL;
923 mono_error_assert_ok (error);
925 MonoContext ctx;
926 memset (&ctx, 0, sizeof (MonoContext));
927 MONO_CONTEXT_SET_SP (&ctx, frame);
930 * Call the JIT EH code. The EH code will call back to us using:
931 * - mono_interp_set_resume_state ()/run_finally ()/run_filter ().
932 * Since ctx.ip is 0, this will start unwinding from the LMF frame
933 * pushed above, which points to our frames.
935 mono_handle_exception (&ctx, (MonoObject*)ex);
936 if (MONO_CONTEXT_GET_IP (&ctx) != 0) {
937 /* We need to unwind into non-interpreter code */
938 mono_restore_context (&ctx);
939 g_assert_not_reached ();
942 interp_pop_lmf (&ext);
944 g_assert (context->has_resume_state);
947 #define THROW_EX_GENERAL(exception,ex_ip, rethrow) \
948 do { \
949 interp_throw (context, (exception), (frame), (ex_ip), (rethrow)); \
950 CHECK_RESUME_STATE(context); \
951 } while (0)
953 #define THROW_EX(exception,ex_ip) THROW_EX_GENERAL ((exception), (ex_ip), FALSE)
955 #define THROW_EX_OVF(ip) THROW_EX (mono_get_exception_overflow (), ip)
957 #define THROW_EX_DIV_ZERO(ip) THROW_EX (mono_get_exception_divide_by_zero (), ip)
959 #define NULL_CHECK(o) do { \
960 if (G_UNLIKELY (!(o))) \
961 THROW_EX (mono_get_exception_null_reference (), ip); \
962 } while (0)
964 #define EXCEPTION_CHECKPOINT \
965 do { \
966 if (*mono_thread_interruption_request_flag () && !mono_threads_is_critical_method (imethod->method)) { \
967 MonoException *exc = mono_thread_interruption_checkpoint (); \
968 if (exc) \
969 THROW_EX (exc, ip); \
971 } while (0)
974 #define EXCEPTION_CHECKPOINT_IN_HELPER_FUNCTION \
975 do { \
976 if (*mono_thread_interruption_request_flag () && !mono_threads_is_critical_method (imethod->method)) { \
977 MonoException *exc = mono_thread_interruption_checkpoint (); \
978 if (exc) \
979 return exc; \
981 } while (0)
983 static MonoObject*
984 ves_array_create (MonoDomain *domain, MonoClass *klass, int param_count, stackval *values, MonoError *error)
986 uintptr_t *lengths;
987 intptr_t *lower_bounds;
988 int i;
990 lengths = g_newa (uintptr_t, m_class_get_rank (klass) * 2);
991 for (i = 0; i < param_count; ++i) {
992 lengths [i] = values->data.i;
993 values ++;
995 if (m_class_get_rank (klass) == param_count) {
996 /* Only lengths provided. */
997 lower_bounds = NULL;
998 } else {
999 /* lower bounds are first. */
1000 lower_bounds = (intptr_t *) lengths;
1001 lengths += m_class_get_rank (klass);
1003 return (MonoObject*) mono_array_new_full_checked (domain, klass, lengths, lower_bounds, error);
1006 static gint32
1007 ves_array_calculate_index (MonoArray *ao, stackval *sp, InterpFrame *frame, gboolean safe)
1009 g_assert (!frame->ex);
1010 MonoClass *ac = ((MonoObject *) ao)->vtable->klass;
1012 guint32 pos = 0;
1013 if (ao->bounds) {
1014 for (gint32 i = 0; i < m_class_get_rank (ac); i++) {
1015 guint32 idx = sp [i].data.i;
1016 guint32 lower = ao->bounds [i].lower_bound;
1017 guint32 len = ao->bounds [i].length;
1018 if (safe && (idx < lower || (idx - lower) >= len)) {
1019 frame->ex = mono_get_exception_index_out_of_range ();
1020 return -1;
1022 pos = (pos * len) + idx - lower;
1024 } else {
1025 pos = sp [0].data.i;
1026 if (safe && pos >= ao->max_length) {
1027 frame->ex = mono_get_exception_index_out_of_range ();
1028 return -1;
1031 return pos;
1034 static MONO_NEVER_INLINE void
1035 ves_array_set (InterpFrame *frame, stackval *sp, MonoMethodSignature *sig)
1037 MonoObject *o = sp->data.o;
1038 MonoArray *ao = (MonoArray *) o;
1039 MonoClass *ac = o->vtable->klass;
1041 g_assert (m_class_get_rank (ac) >= 1);
1043 gint32 pos = ves_array_calculate_index (ao, sp + 1, frame, TRUE);
1044 if (frame->ex)
1045 return;
1047 int val_index = 1 + m_class_get_rank (ac);
1048 if (sp [val_index].data.p && !m_class_is_valuetype (m_class_get_element_class (mono_object_class (o)))) {
1049 ERROR_DECL (error);
1050 MonoObject *isinst = mono_object_isinst_checked (sp [val_index].data.o, m_class_get_element_class (mono_object_class (o)), error);
1051 mono_error_cleanup (error);
1052 if (!isinst) {
1053 frame->ex = mono_get_exception_array_type_mismatch ();
1054 return;
1058 gint32 esize = mono_array_element_size (ac);
1059 gpointer ea = mono_array_addr_with_size_fast (ao, esize, pos);
1061 MonoType *mt = sig->params [m_class_get_rank (ac)];
1062 stackval_to_data (mt, &sp [val_index], ea, FALSE);
1065 static void
1066 ves_array_get (InterpFrame *frame, stackval *sp, stackval *retval, MonoMethodSignature *sig, gboolean safe)
1068 MonoObject *o = sp->data.o;
1069 MonoArray *ao = (MonoArray *) o;
1070 MonoClass *ac = o->vtable->klass;
1072 g_assert (m_class_get_rank (ac) >= 1);
1074 gint32 pos = ves_array_calculate_index (ao, sp + 1, frame, safe);
1075 if (frame->ex)
1076 return;
1078 gint32 esize = mono_array_element_size (ac);
1079 gpointer ea = mono_array_addr_with_size_fast (ao, esize, pos);
1081 MonoType *mt = sig->ret;
1082 stackval_from_data (mt, retval, ea, FALSE);
1085 static MONO_NEVER_INLINE gpointer
1086 ves_array_element_address (InterpFrame *frame, MonoClass *required_type, MonoArray *ao, stackval *sp, gboolean needs_typecheck)
1088 MonoClass *ac = ((MonoObject *) ao)->vtable->klass;
1090 g_assert (m_class_get_rank (ac) >= 1);
1092 gint32 pos = ves_array_calculate_index (ao, sp, frame, TRUE);
1093 if (frame->ex)
1094 return NULL;
1096 if (needs_typecheck && !mono_class_is_assignable_from_internal (m_class_get_element_class (mono_object_class ((MonoObject *) ao)), required_type)) {
1097 frame->ex = mono_get_exception_array_type_mismatch ();
1098 return NULL;
1100 gint32 esize = mono_array_element_size (ac);
1101 return mono_array_addr_with_size_fast (ao, esize, pos);
1104 #ifdef MONO_ARCH_HAVE_INTERP_ENTRY_TRAMPOLINE
1105 static MonoFuncV mono_native_to_interp_trampoline = NULL;
1106 #endif
1108 #ifndef MONO_ARCH_HAVE_INTERP_PINVOKE_TRAMP
1109 static InterpMethodArguments* build_args_from_sig (MonoMethodSignature *sig, InterpFrame *frame)
1111 InterpMethodArguments *margs = g_malloc0 (sizeof (InterpMethodArguments));
1113 #ifdef TARGET_ARM
1114 g_assert (mono_arm_eabi_supported ());
1115 int i8_align = mono_arm_i8_align ();
1116 #endif
1118 #ifdef TARGET_WASM
1119 margs->sig = sig;
1120 #endif
1122 if (sig->hasthis)
1123 margs->ilen++;
1125 for (int i = 0; i < sig->param_count; i++) {
1126 guint32 ptype = sig->params [i]->byref ? MONO_TYPE_PTR : sig->params [i]->type;
1127 switch (ptype) {
1128 case MONO_TYPE_BOOLEAN:
1129 case MONO_TYPE_CHAR:
1130 case MONO_TYPE_I1:
1131 case MONO_TYPE_U1:
1132 case MONO_TYPE_I2:
1133 case MONO_TYPE_U2:
1134 case MONO_TYPE_I4:
1135 case MONO_TYPE_U4:
1136 case MONO_TYPE_I:
1137 case MONO_TYPE_U:
1138 case MONO_TYPE_PTR:
1139 case MONO_TYPE_SZARRAY:
1140 case MONO_TYPE_CLASS:
1141 case MONO_TYPE_OBJECT:
1142 case MONO_TYPE_STRING:
1143 case MONO_TYPE_VALUETYPE:
1144 case MONO_TYPE_GENERICINST:
1145 #if SIZEOF_VOID_P == 8
1146 case MONO_TYPE_I8:
1147 case MONO_TYPE_U8:
1148 #endif
1149 margs->ilen++;
1150 break;
1151 #if SIZEOF_VOID_P == 4
1152 case MONO_TYPE_I8:
1153 case MONO_TYPE_U8:
1154 #ifdef TARGET_ARM
1155 /* pairs begin at even registers */
1156 if (i8_align == 8 && margs->ilen & 1)
1157 margs->ilen++;
1158 #endif
1159 margs->ilen += 2;
1160 break;
1161 #endif
1162 case MONO_TYPE_R4:
1163 #if SIZEOF_VOID_P == 8
1164 case MONO_TYPE_R8:
1165 #endif
1166 margs->flen++;
1167 break;
1168 #if SIZEOF_VOID_P == 4
1169 case MONO_TYPE_R8:
1170 margs->flen += 2;
1171 break;
1172 #endif
1173 default:
1174 g_error ("build_args_from_sig: not implemented yet (1): 0x%x\n", ptype);
1178 if (margs->ilen > 0)
1179 margs->iargs = g_malloc0 (sizeof (gpointer) * margs->ilen);
1181 if (margs->flen > 0)
1182 margs->fargs = g_malloc0 (sizeof (double) * margs->flen);
1184 if (margs->ilen > INTERP_ICALL_TRAMP_IARGS)
1185 g_error ("build_args_from_sig: TODO, allocate gregs: %d\n", margs->ilen);
1187 if (margs->flen > INTERP_ICALL_TRAMP_FARGS)
1188 g_error ("build_args_from_sig: TODO, allocate fregs: %d\n", margs->flen);
1191 size_t int_i = 0;
1192 size_t int_f = 0;
1194 if (sig->hasthis) {
1195 margs->iargs [0] = frame->stack_args->data.p;
1196 int_i++;
1199 for (int i = 0; i < sig->param_count; i++) {
1200 guint32 ptype = sig->params [i]->byref ? MONO_TYPE_PTR : sig->params [i]->type;
1201 switch (ptype) {
1202 case MONO_TYPE_BOOLEAN:
1203 case MONO_TYPE_CHAR:
1204 case MONO_TYPE_I1:
1205 case MONO_TYPE_U1:
1206 case MONO_TYPE_I2:
1207 case MONO_TYPE_U2:
1208 case MONO_TYPE_I4:
1209 case MONO_TYPE_U4:
1210 case MONO_TYPE_I:
1211 case MONO_TYPE_U:
1212 case MONO_TYPE_PTR:
1213 case MONO_TYPE_SZARRAY:
1214 case MONO_TYPE_CLASS:
1215 case MONO_TYPE_OBJECT:
1216 case MONO_TYPE_STRING:
1217 case MONO_TYPE_VALUETYPE:
1218 case MONO_TYPE_GENERICINST:
1219 #if SIZEOF_VOID_P == 8
1220 case MONO_TYPE_I8:
1221 case MONO_TYPE_U8:
1222 #endif
1223 margs->iargs [int_i] = frame->stack_args [i].data.p;
1224 #if DEBUG_INTERP
1225 g_print ("build_args_from_sig: margs->iargs [%d]: %p (frame @ %d)\n", int_i, margs->iargs [int_i], i);
1226 #endif
1227 int_i++;
1228 break;
1229 #if SIZEOF_VOID_P == 4
1230 case MONO_TYPE_I8:
1231 case MONO_TYPE_U8: {
1232 stackval *sarg = &frame->stack_args [i];
1233 #ifdef TARGET_ARM
1234 /* pairs begin at even registers */
1235 if (i8_align == 8 && int_i & 1)
1236 int_i++;
1237 #endif
1238 margs->iargs [int_i] = (gpointer) sarg->data.pair.lo;
1239 int_i++;
1240 margs->iargs [int_i] = (gpointer) sarg->data.pair.hi;
1241 #if DEBUG_INTERP
1242 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);
1243 #endif
1244 int_i++;
1245 break;
1247 #endif
1248 case MONO_TYPE_R4:
1249 case MONO_TYPE_R8:
1250 if (ptype == MONO_TYPE_R4)
1251 * (float *) &(margs->fargs [int_f]) = frame->stack_args [i].data.f_r4;
1252 else
1253 margs->fargs [int_f] = frame->stack_args [i].data.f;
1254 #if DEBUG_INTERP
1255 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);
1256 #endif
1257 #if SIZEOF_VOID_P == 4
1258 int_f += 2;
1259 #else
1260 int_f++;
1261 #endif
1262 break;
1263 default:
1264 g_error ("build_args_from_sig: not implemented yet (2): 0x%x\n", ptype);
1268 switch (sig->ret->type) {
1269 case MONO_TYPE_BOOLEAN:
1270 case MONO_TYPE_CHAR:
1271 case MONO_TYPE_I1:
1272 case MONO_TYPE_U1:
1273 case MONO_TYPE_I2:
1274 case MONO_TYPE_U2:
1275 case MONO_TYPE_I4:
1276 case MONO_TYPE_U4:
1277 case MONO_TYPE_I:
1278 case MONO_TYPE_U:
1279 case MONO_TYPE_PTR:
1280 case MONO_TYPE_SZARRAY:
1281 case MONO_TYPE_CLASS:
1282 case MONO_TYPE_OBJECT:
1283 case MONO_TYPE_STRING:
1284 case MONO_TYPE_I8:
1285 case MONO_TYPE_U8:
1286 case MONO_TYPE_VALUETYPE:
1287 case MONO_TYPE_GENERICINST:
1288 margs->retval = &(frame->retval->data.p);
1289 margs->is_float_ret = 0;
1290 break;
1291 case MONO_TYPE_R4:
1292 case MONO_TYPE_R8:
1293 margs->retval = &(frame->retval->data.p);
1294 margs->is_float_ret = 1;
1295 break;
1296 case MONO_TYPE_VOID:
1297 margs->retval = NULL;
1298 break;
1299 default:
1300 g_error ("build_args_from_sig: ret type not implemented yet: 0x%x\n", sig->ret->type);
1303 return margs;
1305 #endif
1307 static void
1308 interp_frame_arg_to_data (MonoInterpFrameHandle frame, MonoMethodSignature *sig, int index, gpointer data)
1310 InterpFrame *iframe = (InterpFrame*)frame;
1312 if (index == -1)
1313 stackval_to_data (sig->ret, iframe->retval, data, sig->pinvoke);
1314 else
1315 stackval_to_data (sig->params [index], &iframe->stack_args [index], data, sig->pinvoke);
1318 static void
1319 interp_data_to_frame_arg (MonoInterpFrameHandle frame, MonoMethodSignature *sig, int index, gpointer data)
1321 InterpFrame *iframe = (InterpFrame*)frame;
1323 if (index == -1)
1324 stackval_from_data (sig->ret, iframe->retval, data, sig->pinvoke);
1325 else if (sig->hasthis && index == 0)
1326 iframe->stack_args [index].data.p = *(gpointer*)data;
1327 else
1328 stackval_from_data (sig->params [index - sig->hasthis], &iframe->stack_args [index], data, sig->pinvoke);
1331 static gpointer
1332 interp_frame_arg_to_storage (MonoInterpFrameHandle frame, MonoMethodSignature *sig, int index)
1334 InterpFrame *iframe = (InterpFrame*)frame;
1336 if (index == -1)
1337 return stackval_to_data_addr (sig->ret, iframe->retval);
1338 else
1339 return stackval_to_data_addr (sig->params [index], &iframe->stack_args [index]);
1342 static void
1343 interp_frame_arg_set_storage (MonoInterpFrameHandle frame, MonoMethodSignature *sig, int index, gpointer storage)
1345 InterpFrame *iframe = (InterpFrame*)frame;
1346 stackval *val = (index == -1) ? iframe->retval : &iframe->stack_args [index];
1347 MonoType *type = (index == -1) ? sig->ret : sig->params [index];
1349 switch (type->type) {
1350 case MONO_TYPE_GENERICINST:
1351 if (!MONO_TYPE_IS_REFERENCE (type))
1352 val->data.vt = storage;
1353 break;
1354 case MONO_TYPE_VALUETYPE:
1355 val->data.vt = storage;
1356 break;
1357 default:
1358 g_assert_not_reached ();
1362 static MonoPIFunc
1363 get_interp_to_native_trampoline (void)
1365 static MonoPIFunc trampoline = NULL;
1367 if (!trampoline) {
1368 if (mono_ee_features.use_aot_trampolines) {
1369 trampoline = (MonoPIFunc) mono_aot_get_trampoline ("interp_to_native_trampoline");
1370 } else {
1371 MonoTrampInfo *info;
1372 trampoline = (MonoPIFunc) mono_arch_get_interp_to_native_trampoline (&info);
1373 mono_tramp_info_register (info, NULL);
1375 mono_memory_barrier ();
1377 return trampoline;
1380 static void
1381 interp_to_native_trampoline (gpointer addr, gpointer ccontext)
1383 get_interp_to_native_trampoline () (addr, ccontext);
1386 /* MONO_NO_OPTIMIATION is needed due to usage of INTERP_PUSH_LMF_WITH_CTX. */
1387 #ifdef _MSC_VER
1388 #pragma optimize ("", off)
1389 #endif
1390 static MONO_NO_OPTIMIZATION MONO_NEVER_INLINE void
1391 ves_pinvoke_method (InterpFrame *frame, MonoMethodSignature *sig, MonoFuncV addr, gboolean string_ctor, ThreadContext *context, gboolean save_last_error)
1393 MonoLMFExt ext;
1394 gpointer args;
1396 frame->ex = NULL;
1398 g_assert (!frame->imethod);
1400 static MonoPIFunc entry_func = NULL;
1401 if (!entry_func) {
1402 #ifdef MONO_ARCH_HAS_NO_PROPER_MONOCTX
1403 ERROR_DECL (error);
1404 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);
1405 mono_error_assert_ok (error);
1406 #else
1407 entry_func = get_interp_to_native_trampoline ();
1408 #endif
1409 mono_memory_barrier ();
1412 #ifdef ENABLE_NETCORE
1413 if (save_last_error) {
1414 mono_marshal_clear_last_error ();
1416 #endif
1418 #ifdef MONO_ARCH_HAVE_INTERP_PINVOKE_TRAMP
1419 CallContext ccontext;
1420 mono_arch_set_native_call_context_args (&ccontext, frame, sig);
1421 args = &ccontext;
1422 #else
1423 InterpMethodArguments *margs = build_args_from_sig (sig, frame);
1424 args = margs;
1425 #endif
1427 INTERP_PUSH_LMF_WITH_CTX (frame, ext, exit_pinvoke);
1428 entry_func ((gpointer) addr, args);
1429 if (save_last_error)
1430 mono_marshal_set_last_error ();
1431 interp_pop_lmf (&ext);
1433 #ifdef MONO_ARCH_HAVE_INTERP_PINVOKE_TRAMP
1434 if (!frame->ex)
1435 mono_arch_get_native_call_context_ret (&ccontext, frame, sig);
1437 if (ccontext.stack != NULL)
1438 g_free (ccontext.stack);
1439 #else
1440 if (!frame->ex && !MONO_TYPE_ISSTRUCT (sig->ret))
1441 stackval_from_data (sig->ret, frame->retval, (char*)&frame->retval->data.p, sig->pinvoke);
1443 g_free (margs->iargs);
1444 g_free (margs->fargs);
1445 g_free (margs);
1446 #endif
1447 goto exit_pinvoke; // prevent unused label warning in some configurations
1448 exit_pinvoke:
1449 return;
1451 #ifdef _MSC_VER
1452 #pragma optimize ("", on)
1453 #endif
1456 * interp_init_delegate:
1458 * Initialize del->interp_method.
1460 static void
1461 interp_init_delegate (MonoDelegate *del, MonoError *error)
1463 MonoMethod *method;
1465 if (del->interp_method) {
1466 /* Delegate created by a call to ves_icall_mono_delegate_ctor_interp () */
1467 del->method = ((InterpMethod *)del->interp_method)->method;
1468 } else if (del->method) {
1469 /* Delegate created dynamically */
1470 del->interp_method = mono_interp_get_imethod (del->object.vtable->domain, del->method, error);
1471 } else {
1472 /* Created from JITted code */
1473 g_assert_not_reached ();
1476 method = ((InterpMethod*)del->interp_method)->method;
1477 if (del->target &&
1478 method &&
1479 method->flags & METHOD_ATTRIBUTE_VIRTUAL &&
1480 method->flags & METHOD_ATTRIBUTE_ABSTRACT &&
1481 mono_class_is_abstract (method->klass))
1482 del->interp_method = get_virtual_method ((InterpMethod*)del->interp_method, del->target->vtable);
1484 method = ((InterpMethod*)del->interp_method)->method;
1485 if (method && m_class_get_parent (method->klass) == mono_defaults.multicastdelegate_class) {
1486 const char *name = method->name;
1487 if (*name == 'I' && (strcmp (name, "Invoke") == 0)) {
1489 * When invoking the delegate interp_method is executed directly. If it's an
1490 * invoke make sure we replace it with the appropriate delegate invoke wrapper.
1492 * FIXME We should do this later, when we also know the delegate on which the
1493 * target method is called.
1495 del->interp_method = mono_interp_get_imethod (del->object.vtable->domain, mono_marshal_get_delegate_invoke (method, NULL), error);
1496 mono_error_assert_ok (error);
1500 if (!((InterpMethod *) del->interp_method)->transformed && method_is_dynamic (method)) {
1501 /* Return any errors from method compilation */
1502 mono_interp_transform_method ((InterpMethod *) del->interp_method, get_context (), error);
1503 return_if_nok (error);
1507 static void
1508 interp_delegate_ctor (MonoObjectHandle this_obj, MonoObjectHandle target, gpointer addr, MonoError *error)
1511 * addr is the result of an LDFTN opcode, i.e. an InterpMethod
1513 InterpMethod *imethod = (InterpMethod*)addr;
1515 if (!(imethod->method->flags & METHOD_ATTRIBUTE_STATIC)) {
1516 MonoMethod *invoke = mono_get_delegate_invoke_internal (mono_handle_class (this_obj));
1517 /* virtual invoke delegates must not have null check */
1518 if (mono_method_signature_internal (imethod->method)->param_count == mono_method_signature_internal (invoke)->param_count
1519 && MONO_HANDLE_IS_NULL (target)) {
1520 mono_error_set_argument (error, "this", "Delegate to an instance method cannot have null 'this'");
1521 return;
1525 g_assert (imethod->method);
1526 gpointer entry = mini_get_interp_callbacks ()->create_method_pointer (imethod->method, FALSE, error);
1527 return_if_nok (error);
1529 MONO_HANDLE_SETVAL (MONO_HANDLE_CAST (MonoDelegate, this_obj), interp_method, gpointer, imethod);
1531 mono_delegate_ctor (this_obj, target, entry, error);
1535 * From the spec:
1536 * runtime specifies that the implementation of the method is automatically
1537 * provided by the runtime and is primarily used for the methods of delegates.
1539 static MONO_NEVER_INLINE void
1540 ves_imethod (InterpFrame *frame, MonoMethod *method, MonoMethodSignature *sig, stackval *sp, stackval *retval)
1542 const char *name = method->name;
1543 mono_class_init_internal (method->klass);
1545 if (method->klass == mono_defaults.array_class) {
1546 if (!strcmp (name, "UnsafeMov")) {
1547 /* TODO: layout checks */
1548 stackval_from_data (sig->ret, retval, (char*) sp, FALSE);
1549 return;
1551 if (!strcmp (name, "UnsafeLoad")) {
1552 ves_array_get (frame, sp, retval, sig, FALSE);
1553 return;
1555 } else if (mini_class_is_system_array (method->klass)) {
1556 MonoObject *obj = (MonoObject*) sp->data.p;
1557 if (!obj) {
1558 frame->ex = mono_get_exception_null_reference ();
1559 return;
1561 if (*name == 'S' && (strcmp (name, "Set") == 0)) {
1562 ves_array_set (frame, sp, sig);
1563 return;
1565 if (*name == 'G' && (strcmp (name, "Get") == 0)) {
1566 ves_array_get (frame, sp, retval, sig, TRUE);
1567 return;
1571 g_error ("Don't know how to exec runtime method %s.%s::%s",
1572 m_class_get_name_space (method->klass), m_class_get_name (method->klass),
1573 method->name);
1576 #if DEBUG_INTERP
1577 static char*
1578 dump_stack (stackval *stack, stackval *sp)
1580 stackval *s = stack;
1581 GString *str = g_string_new ("");
1583 if (sp == stack)
1584 return g_string_free (str, FALSE);
1586 while (s < sp) {
1587 g_string_append_printf (str, "[%p (%lld)] ", s->data.l, s->data.l);
1588 ++s;
1590 return g_string_free (str, FALSE);
1593 static void
1594 dump_stackval (GString *str, stackval *s, MonoType *type)
1596 switch (type->type) {
1597 case MONO_TYPE_I1:
1598 case MONO_TYPE_U1:
1599 case MONO_TYPE_I2:
1600 case MONO_TYPE_U2:
1601 case MONO_TYPE_I4:
1602 case MONO_TYPE_U4:
1603 case MONO_TYPE_CHAR:
1604 case MONO_TYPE_BOOLEAN:
1605 g_string_append_printf (str, "[%d] ", s->data.i);
1606 break;
1607 case MONO_TYPE_STRING:
1608 case MONO_TYPE_SZARRAY:
1609 case MONO_TYPE_CLASS:
1610 case MONO_TYPE_OBJECT:
1611 case MONO_TYPE_ARRAY:
1612 case MONO_TYPE_PTR:
1613 case MONO_TYPE_I:
1614 case MONO_TYPE_U:
1615 g_string_append_printf (str, "[%p] ", s->data.p);
1616 break;
1617 case MONO_TYPE_VALUETYPE:
1618 if (m_class_is_enumtype (type->data.klass))
1619 g_string_append_printf (str, "[%d] ", s->data.i);
1620 else
1621 g_string_append_printf (str, "[vt:%p] ", s->data.p);
1622 break;
1623 case MONO_TYPE_R4:
1624 g_string_append_printf (str, "[%g] ", s->data.f_r4);
1625 break;
1626 case MONO_TYPE_R8:
1627 g_string_append_printf (str, "[%g] ", s->data.f);
1628 break;
1629 case MONO_TYPE_I8:
1630 case MONO_TYPE_U8:
1631 default: {
1632 GString *res = g_string_new ("");
1633 mono_type_get_desc (res, type, TRUE);
1634 g_string_append_printf (str, "[{%s} %lld/0x%0llx] ", res->str, s->data.l, s->data.l);
1635 g_string_free (res, TRUE);
1636 break;
1641 static char*
1642 dump_retval (InterpFrame *inv)
1644 GString *str = g_string_new ("");
1645 MonoType *ret = mono_method_signature_internal (inv->imethod->method)->ret;
1647 if (ret->type != MONO_TYPE_VOID)
1648 dump_stackval (str, inv->retval, ret);
1650 return g_string_free (str, FALSE);
1653 static char*
1654 dump_args (InterpFrame *inv)
1656 GString *str = g_string_new ("");
1657 int i;
1658 MonoMethodSignature *signature = mono_method_signature_internal (inv->imethod->method);
1660 if (signature->param_count == 0 && !signature->hasthis)
1661 return g_string_free (str, FALSE);
1663 if (signature->hasthis) {
1664 MonoMethod *method = inv->imethod->method;
1665 dump_stackval (str, inv->stack_args, m_class_get_byval_arg (method->klass));
1668 for (i = 0; i < signature->param_count; ++i)
1669 dump_stackval (str, inv->stack_args + (!!signature->hasthis) + i, signature->params [i]);
1671 return g_string_free (str, FALSE);
1673 #endif
1675 #define CHECK_ADD_OVERFLOW(a,b) \
1676 (gint32)(b) >= 0 ? (gint32)(G_MAXINT32) - (gint32)(b) < (gint32)(a) ? -1 : 0 \
1677 : (gint32)(G_MININT32) - (gint32)(b) > (gint32)(a) ? +1 : 0
1679 #define CHECK_SUB_OVERFLOW(a,b) \
1680 (gint32)(b) < 0 ? (gint32)(G_MAXINT32) + (gint32)(b) < (gint32)(a) ? -1 : 0 \
1681 : (gint32)(G_MININT32) + (gint32)(b) > (gint32)(a) ? +1 : 0
1683 #define CHECK_ADD_OVERFLOW_UN(a,b) \
1684 (guint32)(G_MAXUINT32) - (guint32)(b) < (guint32)(a) ? -1 : 0
1686 #define CHECK_SUB_OVERFLOW_UN(a,b) \
1687 (guint32)(a) < (guint32)(b) ? -1 : 0
1689 #define CHECK_ADD_OVERFLOW64(a,b) \
1690 (gint64)(b) >= 0 ? (gint64)(G_MAXINT64) - (gint64)(b) < (gint64)(a) ? -1 : 0 \
1691 : (gint64)(G_MININT64) - (gint64)(b) > (gint64)(a) ? +1 : 0
1693 #define CHECK_SUB_OVERFLOW64(a,b) \
1694 (gint64)(b) < 0 ? (gint64)(G_MAXINT64) + (gint64)(b) < (gint64)(a) ? -1 : 0 \
1695 : (gint64)(G_MININT64) + (gint64)(b) > (gint64)(a) ? +1 : 0
1697 #define CHECK_ADD_OVERFLOW64_UN(a,b) \
1698 (guint64)(G_MAXUINT64) - (guint64)(b) < (guint64)(a) ? -1 : 0
1700 #define CHECK_SUB_OVERFLOW64_UN(a,b) \
1701 (guint64)(a) < (guint64)(b) ? -1 : 0
1703 #if SIZEOF_VOID_P == 4
1704 #define CHECK_ADD_OVERFLOW_NAT(a,b) CHECK_ADD_OVERFLOW(a,b)
1705 #define CHECK_ADD_OVERFLOW_NAT_UN(a,b) CHECK_ADD_OVERFLOW_UN(a,b)
1706 #else
1707 #define CHECK_ADD_OVERFLOW_NAT(a,b) CHECK_ADD_OVERFLOW64(a,b)
1708 #define CHECK_ADD_OVERFLOW_NAT_UN(a,b) CHECK_ADD_OVERFLOW64_UN(a,b)
1709 #endif
1711 /* Resolves to TRUE if the operands would overflow */
1712 #define CHECK_MUL_OVERFLOW(a,b) \
1713 ((gint32)(a) == 0) || ((gint32)(b) == 0) ? 0 : \
1714 (((gint32)(a) > 0) && ((gint32)(b) == -1)) ? FALSE : \
1715 (((gint32)(a) < 0) && ((gint32)(b) == -1)) ? (a == G_MININT32) : \
1716 (((gint32)(a) > 0) && ((gint32)(b) > 0)) ? (gint32)(a) > ((G_MAXINT32) / (gint32)(b)) : \
1717 (((gint32)(a) > 0) && ((gint32)(b) < 0)) ? (gint32)(a) > ((G_MININT32) / (gint32)(b)) : \
1718 (((gint32)(a) < 0) && ((gint32)(b) > 0)) ? (gint32)(a) < ((G_MININT32) / (gint32)(b)) : \
1719 (gint32)(a) < ((G_MAXINT32) / (gint32)(b))
1721 #define CHECK_MUL_OVERFLOW_UN(a,b) \
1722 ((guint32)(a) == 0) || ((guint32)(b) == 0) ? 0 : \
1723 (guint32)(b) > ((G_MAXUINT32) / (guint32)(a))
1725 #define CHECK_MUL_OVERFLOW64(a,b) \
1726 ((gint64)(a) == 0) || ((gint64)(b) == 0) ? 0 : \
1727 (((gint64)(a) > 0) && ((gint64)(b) == -1)) ? FALSE : \
1728 (((gint64)(a) < 0) && ((gint64)(b) == -1)) ? (a == G_MININT64) : \
1729 (((gint64)(a) > 0) && ((gint64)(b) > 0)) ? (gint64)(a) > ((G_MAXINT64) / (gint64)(b)) : \
1730 (((gint64)(a) > 0) && ((gint64)(b) < 0)) ? (gint64)(a) > ((G_MININT64) / (gint64)(b)) : \
1731 (((gint64)(a) < 0) && ((gint64)(b) > 0)) ? (gint64)(a) < ((G_MININT64) / (gint64)(b)) : \
1732 (gint64)(a) < ((G_MAXINT64) / (gint64)(b))
1734 #define CHECK_MUL_OVERFLOW64_UN(a,b) \
1735 ((guint64)(a) == 0) || ((guint64)(b) == 0) ? 0 : \
1736 (guint64)(b) > ((G_MAXUINT64) / (guint64)(a))
1738 #if SIZEOF_VOID_P == 4
1739 #define CHECK_MUL_OVERFLOW_NAT(a,b) CHECK_MUL_OVERFLOW(a,b)
1740 #define CHECK_MUL_OVERFLOW_NAT_UN(a,b) CHECK_MUL_OVERFLOW_UN(a,b)
1741 #else
1742 #define CHECK_MUL_OVERFLOW_NAT(a,b) CHECK_MUL_OVERFLOW64(a,b)
1743 #define CHECK_MUL_OVERFLOW_NAT_UN(a,b) CHECK_MUL_OVERFLOW64_UN(a,b)
1744 #endif
1746 static MonoObject*
1747 interp_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError *error)
1749 InterpFrame frame;
1750 ThreadContext *context = get_context ();
1751 MonoMethodSignature *sig = mono_method_signature_internal (method);
1752 MonoClass *klass = mono_class_from_mono_type_internal (sig->ret);
1753 stackval result;
1754 MonoMethod *target_method = method;
1756 error_init (error);
1757 if (exc)
1758 *exc = NULL;
1760 frame.ex = NULL;
1762 MonoDomain *domain = mono_domain_get ();
1764 if (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
1765 target_method = mono_marshal_get_native_wrapper (target_method, FALSE, FALSE);
1766 MonoMethod *invoke_wrapper = mono_marshal_get_runtime_invoke_full (target_method, FALSE, TRUE);
1768 //* <code>MonoObject *runtime_invoke (MonoObject *this_obj, void **params, MonoObject **exc, void* method)</code>
1770 result.data.vt = alloca (mono_class_instance_size (klass));
1771 stackval args [4];
1773 if (sig->hasthis)
1774 args [0].data.p = obj;
1775 else
1776 args [0].data.p = NULL;
1777 args [1].data.p = params;
1778 args [2].data.p = exc;
1779 args [3].data.p = target_method;
1781 InterpMethod *imethod = mono_interp_get_imethod (domain, invoke_wrapper, error);
1782 mono_error_assert_ok (error);
1783 init_frame (&frame, NULL, imethod, args, &result);
1785 interp_exec_method (&frame, context, error);
1787 if (frame.ex) {
1788 if (exc) {
1789 *exc = (MonoObject*) frame.ex;
1790 return NULL;
1792 mono_error_set_exception_instance (error, frame.ex);
1793 return NULL;
1795 return (MonoObject*)result.data.p;
1798 typedef struct {
1799 InterpMethod *rmethod;
1800 gpointer this_arg;
1801 gpointer res;
1802 gpointer args [16];
1803 gpointer *many_args;
1804 } InterpEntryData;
1806 /* Main function for entering the interpreter from compiled code */
1807 static void
1808 interp_entry (InterpEntryData *data)
1810 InterpFrame frame;
1811 InterpMethod *rmethod;
1812 ThreadContext *context;
1813 stackval result;
1814 stackval *args;
1815 MonoMethod *method;
1816 MonoMethodSignature *sig;
1817 MonoType *type;
1818 gpointer orig_domain = NULL, attach_cookie;
1819 int i;
1821 if ((gsize)data->rmethod & 1) {
1822 /* Unbox */
1823 data->this_arg = mono_object_unbox_internal ((MonoObject*)data->this_arg);
1824 data->rmethod = (InterpMethod*)(gpointer)((gsize)data->rmethod & ~1);
1826 rmethod = data->rmethod;
1828 if (rmethod->needs_thread_attach)
1829 orig_domain = mono_threads_attach_coop (mono_domain_get (), &attach_cookie);
1831 context = get_context ();
1833 method = rmethod->method;
1834 sig = mono_method_signature_internal (method);
1836 // FIXME: Optimize this
1838 //printf ("%s\n", mono_method_full_name (method, 1));
1840 frame.ex = NULL;
1842 args = g_newa (stackval, sig->param_count + (sig->hasthis ? 1 : 0));
1843 if (sig->hasthis)
1844 args [0].data.p = data->this_arg;
1846 gpointer *params;
1847 if (data->many_args)
1848 params = data->many_args;
1849 else
1850 params = data->args;
1851 for (i = 0; i < sig->param_count; ++i) {
1852 int a_index = i + (sig->hasthis ? 1 : 0);
1853 if (sig->params [i]->byref) {
1854 args [a_index].data.p = params [i];
1855 continue;
1857 type = rmethod->param_types [i];
1858 switch (type->type) {
1859 case MONO_TYPE_VALUETYPE:
1860 args [a_index].data.p = params [i];
1861 break;
1862 case MONO_TYPE_GENERICINST:
1863 if (MONO_TYPE_IS_REFERENCE (type))
1864 args [a_index].data.p = *(gpointer*)params [i];
1865 else
1866 args [a_index].data.vt = params [i];
1867 break;
1868 default:
1869 stackval_from_data (type, &args [a_index], params [i], FALSE);
1870 break;
1874 memset (&result, 0, sizeof (result));
1875 init_frame (&frame, NULL, data->rmethod, args, &result);
1877 type = rmethod->rtype;
1878 switch (type->type) {
1879 case MONO_TYPE_GENERICINST:
1880 if (!MONO_TYPE_IS_REFERENCE (type))
1881 frame.retval->data.vt = data->res;
1882 break;
1883 case MONO_TYPE_VALUETYPE:
1884 frame.retval->data.vt = data->res;
1885 break;
1886 default:
1887 break;
1890 ERROR_DECL (error);
1891 interp_exec_method (&frame, context, error);
1893 if (rmethod->needs_thread_attach)
1894 mono_threads_detach_coop (orig_domain, &attach_cookie);
1896 if (mono_llvm_only) {
1897 if (frame.ex)
1898 mono_llvm_reraise_exception (frame.ex);
1899 } else {
1900 g_assert (frame.ex == NULL);
1903 type = rmethod->rtype;
1904 switch (type->type) {
1905 case MONO_TYPE_VOID:
1906 break;
1907 case MONO_TYPE_OBJECT:
1908 /* No need for a write barrier */
1909 *(MonoObject**)data->res = (MonoObject*)frame.retval->data.p;
1910 break;
1911 case MONO_TYPE_GENERICINST:
1912 if (MONO_TYPE_IS_REFERENCE (type)) {
1913 *(MonoObject**)data->res = (MonoObject*)frame.retval->data.p;
1914 } else {
1915 /* Already set before the call */
1917 break;
1918 case MONO_TYPE_VALUETYPE:
1919 /* Already set before the call */
1920 break;
1921 default:
1922 stackval_to_data (type, frame.retval, data->res, FALSE);
1923 break;
1927 static stackval *
1928 do_icall (InterpFrame *frame, MonoMethodSignature *sig, int op, stackval *sp, gpointer ptr, gboolean save_last_error)
1930 #ifdef ENABLE_NETCORE
1931 if (save_last_error)
1932 mono_marshal_clear_last_error ();
1933 #endif
1935 switch (op) {
1936 case MINT_ICALL_V_V: {
1937 typedef void (*T)(void);
1938 T func = (T)ptr;
1939 func ();
1940 break;
1942 case MINT_ICALL_V_P: {
1943 typedef gpointer (*T)(void);
1944 T func = (T)ptr;
1945 sp++;
1946 sp [-1].data.p = func ();
1947 break;
1949 case MINT_ICALL_P_V: {
1950 typedef void (*T)(gpointer);
1951 T func = (T)ptr;
1952 func (sp [-1].data.p);
1953 sp --;
1954 break;
1956 case MINT_ICALL_P_P: {
1957 typedef gpointer (*T)(gpointer);
1958 T func = (T)ptr;
1959 sp [-1].data.p = func (sp [-1].data.p);
1960 break;
1962 case MINT_ICALL_PP_V: {
1963 typedef void (*T)(gpointer,gpointer);
1964 T func = (T)ptr;
1965 sp -= 2;
1966 func (sp [0].data.p, sp [1].data.p);
1967 break;
1969 case MINT_ICALL_PP_P: {
1970 typedef gpointer (*T)(gpointer,gpointer);
1971 T func = (T)ptr;
1972 --sp;
1973 sp [-1].data.p = func (sp [-1].data.p, sp [0].data.p);
1974 break;
1976 case MINT_ICALL_PPP_V: {
1977 typedef void (*T)(gpointer,gpointer,gpointer);
1978 T func = (T)ptr;
1979 sp -= 3;
1980 func (sp [0].data.p, sp [1].data.p, sp [2].data.p);
1981 break;
1983 case MINT_ICALL_PPP_P: {
1984 typedef gpointer (*T)(gpointer,gpointer,gpointer);
1985 T func = (T)ptr;
1986 sp -= 2;
1987 sp [-1].data.p = func (sp [-1].data.p, sp [0].data.p, sp [1].data.p);
1988 break;
1990 case MINT_ICALL_PPPP_V: {
1991 typedef void (*T)(gpointer,gpointer,gpointer,gpointer);
1992 T func = (T)ptr;
1993 sp -= 4;
1994 func (sp [0].data.p, sp [1].data.p, sp [2].data.p, sp [3].data.p);
1995 break;
1997 case MINT_ICALL_PPPP_P: {
1998 typedef gpointer (*T)(gpointer,gpointer,gpointer,gpointer);
1999 T func = (T)ptr;
2000 sp -= 3;
2001 sp [-1].data.p = func (sp [-1].data.p, sp [0].data.p, sp [1].data.p, sp [2].data.p);
2002 break;
2004 case MINT_ICALL_PPPPP_V: {
2005 typedef void (*T)(gpointer,gpointer,gpointer,gpointer,gpointer);
2006 T func = (T)ptr;
2007 sp -= 5;
2008 func (sp [0].data.p, sp [1].data.p, sp [2].data.p, sp [3].data.p, sp [4].data.p);
2009 break;
2011 case MINT_ICALL_PPPPP_P: {
2012 typedef gpointer (*T)(gpointer,gpointer,gpointer,gpointer,gpointer);
2013 T func = (T)ptr;
2014 sp -= 4;
2015 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);
2016 break;
2018 case MINT_ICALL_PPPPPP_V: {
2019 typedef void (*T)(gpointer,gpointer,gpointer,gpointer,gpointer,gpointer);
2020 T func = (T)ptr;
2021 sp -= 6;
2022 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);
2023 break;
2025 case MINT_ICALL_PPPPPP_P: {
2026 typedef gpointer (*T)(gpointer,gpointer,gpointer,gpointer,gpointer,gpointer);
2027 T func = (T)ptr;
2028 sp -= 5;
2029 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);
2030 break;
2032 default:
2033 g_assert_not_reached ();
2036 if (save_last_error)
2037 mono_marshal_set_last_error ();
2039 /* convert the native representation to the stackval representation */
2040 if (sig)
2041 stackval_from_data (sig->ret, &sp [-1], (char*) &sp [-1].data.p, sig->pinvoke);
2043 return sp;
2046 /* MONO_NO_OPTIMIATION is needed due to usage of INTERP_PUSH_LMF_WITH_CTX. */
2047 #ifdef _MSC_VER
2048 #pragma optimize ("", off)
2049 #endif
2050 static MONO_NO_OPTIMIZATION MONO_NEVER_INLINE stackval *
2051 do_icall_wrapper (InterpFrame *frame, MonoMethodSignature *sig, int op, stackval *sp, gpointer ptr, gboolean save_last_error)
2053 MonoLMFExt ext;
2054 INTERP_PUSH_LMF_WITH_CTX (frame, ext, exit_icall);
2056 sp = do_icall (frame, sig, op, sp, ptr, save_last_error);
2058 interp_pop_lmf (&ext);
2060 goto exit_icall; // prevent unused label warning in some configurations
2061 exit_icall:
2062 return sp;
2064 #ifdef _MSC_VER
2065 #pragma optimize ("", on)
2066 #endif
2068 typedef struct {
2069 int pindex;
2070 gpointer jit_wrapper;
2071 gpointer *args;
2072 MonoFtnDesc *ftndesc;
2073 } JitCallCbData;
2075 static void
2076 jit_call_cb (gpointer arg)
2078 JitCallCbData *cb_data = (JitCallCbData*)arg;
2079 gpointer jit_wrapper = cb_data->jit_wrapper;
2080 int pindex = cb_data->pindex;
2081 gpointer *args = cb_data->args;
2082 MonoFtnDesc ftndesc = *cb_data->ftndesc;
2084 switch (pindex) {
2085 case 0: {
2086 typedef void (*T)(gpointer);
2087 T func = (T)jit_wrapper;
2089 func (&ftndesc);
2090 break;
2092 case 1: {
2093 typedef void (*T)(gpointer, gpointer);
2094 T func = (T)jit_wrapper;
2096 func (args [0], &ftndesc);
2097 break;
2099 case 2: {
2100 typedef void (*T)(gpointer, gpointer, gpointer);
2101 T func = (T)jit_wrapper;
2103 func (args [0], args [1], &ftndesc);
2104 break;
2106 case 3: {
2107 typedef void (*T)(gpointer, gpointer, gpointer, gpointer);
2108 T func = (T)jit_wrapper;
2110 func (args [0], args [1], args [2], &ftndesc);
2111 break;
2113 case 4: {
2114 typedef void (*T)(gpointer, gpointer, gpointer, gpointer, gpointer);
2115 T func = (T)jit_wrapper;
2117 func (args [0], args [1], args [2], args [3], &ftndesc);
2118 break;
2120 case 5: {
2121 typedef void (*T)(gpointer, gpointer, gpointer, gpointer, gpointer, gpointer);
2122 T func = (T)jit_wrapper;
2124 func (args [0], args [1], args [2], args [3], args [4], &ftndesc);
2125 break;
2127 case 6: {
2128 typedef void (*T)(gpointer, gpointer, gpointer, gpointer, gpointer, gpointer, gpointer);
2129 T func = (T)jit_wrapper;
2131 func (args [0], args [1], args [2], args [3], args [4], args [5], &ftndesc);
2132 break;
2134 case 7: {
2135 typedef void (*T)(gpointer, gpointer, gpointer, gpointer, gpointer, gpointer, gpointer, gpointer);
2136 T func = (T)jit_wrapper;
2138 func (args [0], args [1], args [2], args [3], args [4], args [5], args [6], &ftndesc);
2139 break;
2141 case 8: {
2142 typedef void (*T)(gpointer, gpointer, gpointer, gpointer, gpointer, gpointer, gpointer, gpointer, gpointer);
2143 T func = (T)jit_wrapper;
2145 func (args [0], args [1], args [2], args [3], args [4], args [5], args [6], args [7], &ftndesc);
2146 break;
2148 default:
2149 g_assert_not_reached ();
2150 break;
2154 static MONO_NEVER_INLINE stackval *
2155 do_jit_call (stackval *sp, unsigned char *vt_sp, ThreadContext *context, InterpFrame *frame, InterpMethod *rmethod, MonoError *error)
2157 MonoMethodSignature *sig;
2158 MonoFtnDesc ftndesc;
2159 guint8 res_buf [256];
2160 MonoType *type;
2161 MonoLMFExt ext;
2163 //printf ("jit_call: %s\n", mono_method_full_name (rmethod->method, 1));
2166 * Call JITted code through a gsharedvt_out wrapper. These wrappers receive every argument
2167 * by ref and return a return value using an explicit return value argument.
2169 if (!rmethod->jit_wrapper) {
2170 MonoMethod *method = rmethod->method;
2172 sig = mono_method_signature_internal (method);
2173 g_assert (sig);
2175 MonoMethod *wrapper = mini_get_gsharedvt_out_sig_wrapper (sig);
2176 //printf ("J: %s %s\n", mono_method_full_name (method, 1), mono_method_full_name (wrapper, 1));
2178 gpointer jit_wrapper = mono_jit_compile_method_jit_only (wrapper, error);
2179 mono_error_assert_ok (error);
2181 gpointer addr = mono_jit_compile_method_jit_only (method, error);
2182 return_val_if_nok (error, NULL);
2183 g_assert (addr);
2185 rmethod->jit_addr = addr;
2186 rmethod->jit_sig = sig;
2187 mono_memory_barrier ();
2188 rmethod->jit_wrapper = jit_wrapper;
2190 } else {
2191 sig = rmethod->jit_sig;
2194 sp -= sig->param_count;
2195 if (sig->hasthis)
2196 --sp;
2198 ftndesc.addr = rmethod->jit_addr;
2199 ftndesc.arg = NULL;
2201 // FIXME: Optimize this
2203 gpointer args [32];
2204 int pindex = 0;
2205 int stack_index = 0;
2206 if (rmethod->hasthis) {
2207 args [pindex ++] = sp [0].data.p;
2208 stack_index ++;
2210 type = rmethod->rtype;
2211 if (type->type != MONO_TYPE_VOID) {
2212 if (MONO_TYPE_ISSTRUCT (type))
2213 args [pindex ++] = vt_sp;
2214 else
2215 args [pindex ++] = res_buf;
2217 for (int i = 0; i < rmethod->param_count; ++i) {
2218 MonoType *t = rmethod->param_types [i];
2219 stackval *sval = &sp [stack_index + i];
2220 if (sig->params [i]->byref) {
2221 args [pindex ++] = sval->data.p;
2222 } else if (MONO_TYPE_ISSTRUCT (t)) {
2223 args [pindex ++] = sval->data.p;
2224 } else if (MONO_TYPE_IS_REFERENCE (t)) {
2225 args [pindex ++] = &sval->data.p;
2226 } else {
2227 switch (t->type) {
2228 case MONO_TYPE_I1:
2229 case MONO_TYPE_U1:
2230 case MONO_TYPE_I2:
2231 case MONO_TYPE_U2:
2232 case MONO_TYPE_I4:
2233 case MONO_TYPE_U4:
2234 case MONO_TYPE_VALUETYPE:
2235 args [pindex ++] = &sval->data.i;
2236 break;
2237 case MONO_TYPE_PTR:
2238 case MONO_TYPE_FNPTR:
2239 case MONO_TYPE_I:
2240 case MONO_TYPE_U:
2241 case MONO_TYPE_OBJECT:
2242 args [pindex ++] = &sval->data.p;
2243 break;
2244 case MONO_TYPE_I8:
2245 case MONO_TYPE_U8:
2246 args [pindex ++] = &sval->data.l;
2247 break;
2248 case MONO_TYPE_R4:
2249 args [pindex ++] = &sval->data.f_r4;
2250 break;
2251 case MONO_TYPE_R8:
2252 args [pindex ++] = &sval->data.f;
2253 break;
2254 default:
2255 printf ("%s\n", mono_type_full_name (t));
2256 g_assert_not_reached ();
2261 interp_push_lmf (&ext, frame);
2263 JitCallCbData cb_data;
2264 memset (&cb_data, 0, sizeof (cb_data));
2265 cb_data.jit_wrapper = rmethod->jit_wrapper;
2266 cb_data.pindex = pindex;
2267 cb_data.args = args;
2268 cb_data.ftndesc = &ftndesc;
2270 if (mono_aot_mode == MONO_AOT_MODE_LLVMONLY_INTERP) {
2271 /* Catch the exception thrown by the native code using a try-catch */
2272 gboolean thrown = FALSE;
2273 mono_llvm_cpp_catch_exception (jit_call_cb, &cb_data, &thrown);
2274 interp_pop_lmf (&ext);
2275 if (thrown) {
2276 MonoObject *obj = mono_llvm_load_exception ();
2277 g_assert (obj);
2278 mono_error_set_exception_instance (error, (MonoException*)obj);
2279 return sp;
2281 } else {
2282 jit_call_cb (&cb_data);
2283 interp_pop_lmf (&ext);
2286 MonoType *rtype = rmethod->rtype;
2287 switch (rtype->type) {
2288 case MONO_TYPE_VOID:
2289 case MONO_TYPE_OBJECT:
2290 case MONO_TYPE_STRING:
2291 case MONO_TYPE_CLASS:
2292 case MONO_TYPE_ARRAY:
2293 case MONO_TYPE_SZARRAY:
2294 case MONO_TYPE_I:
2295 case MONO_TYPE_U:
2296 case MONO_TYPE_PTR:
2297 sp->data.p = *(gpointer*)res_buf;
2298 break;
2299 case MONO_TYPE_I1:
2300 sp->data.i = *(gint8*)res_buf;
2301 break;
2302 case MONO_TYPE_U1:
2303 sp->data.i = *(guint8*)res_buf;
2304 break;
2305 case MONO_TYPE_I2:
2306 sp->data.i = *(gint16*)res_buf;
2307 break;
2308 case MONO_TYPE_U2:
2309 sp->data.i = *(guint16*)res_buf;
2310 break;
2311 case MONO_TYPE_I4:
2312 sp->data.i = *(gint32*)res_buf;
2313 break;
2314 case MONO_TYPE_U4:
2315 sp->data.i = *(guint32*)res_buf;
2316 break;
2317 case MONO_TYPE_I8:
2318 sp->data.l = *(gint64*)res_buf;
2319 break;
2320 case MONO_TYPE_U8:
2321 sp->data.l = *(guint64*)res_buf;
2322 break;
2323 case MONO_TYPE_R4:
2324 sp->data.f_r4 = *(float*)res_buf;
2325 break;
2326 case MONO_TYPE_R8:
2327 sp->data.f = *(double*)res_buf;
2328 break;
2329 case MONO_TYPE_TYPEDBYREF:
2330 case MONO_TYPE_VALUETYPE:
2331 /* The result was written to vt_sp */
2332 sp->data.p = vt_sp;
2333 break;
2334 case MONO_TYPE_GENERICINST:
2335 if (MONO_TYPE_IS_REFERENCE (rtype)) {
2336 sp->data.p = *(gpointer*)res_buf;
2337 } else {
2338 /* The result was written to vt_sp */
2339 sp->data.p = vt_sp;
2341 break;
2342 default:
2343 g_print ("%s\n", mono_type_full_name (rtype));
2344 g_assert_not_reached ();
2345 break;
2348 return sp;
2351 static MONO_NEVER_INLINE void
2352 do_debugger_tramp (void (*tramp) (void), InterpFrame *frame)
2354 MonoLMFExt ext;
2355 interp_push_lmf (&ext, frame);
2356 tramp ();
2357 interp_pop_lmf (&ext);
2360 static MONO_NEVER_INLINE void
2361 do_transform_method (InterpFrame *frame, ThreadContext *context)
2363 MonoLMFExt ext;
2364 /* Don't push lmf if we have no interp data */
2365 gboolean push_lmf = frame->parent != NULL;
2366 ERROR_DECL (error);
2368 /* Use the parent frame as the current frame is not complete yet */
2369 if (push_lmf)
2370 interp_push_lmf (&ext, frame->parent);
2372 mono_interp_transform_method (frame->imethod, context, error);
2373 frame->ex = mono_error_convert_to_exception (error);
2375 if (push_lmf)
2376 interp_pop_lmf (&ext);
2379 static MONO_NEVER_INLINE guchar*
2380 copy_varargs_vtstack (MonoMethodSignature *csig, stackval *sp, guchar *vt_sp)
2382 stackval *first_arg = sp - csig->param_count;
2385 * We need to have the varargs linearly on the stack so the ArgIterator
2386 * can iterate over them. We pass the signature first and then copy them
2387 * one by one on the vtstack.
2389 *(gpointer*)vt_sp = csig;
2390 vt_sp += sizeof (gpointer);
2392 for (int i = csig->sentinelpos; i < csig->param_count; i++) {
2393 int align, arg_size;
2394 arg_size = mono_type_stack_size (csig->params [i], &align);
2395 vt_sp = (guchar*)ALIGN_PTR_TO (vt_sp, align);
2397 stackval_to_data (csig->params [i], &first_arg [i], vt_sp, FALSE);
2398 vt_sp += arg_size;
2401 return (guchar*)ALIGN_PTR_TO (vt_sp, MINT_VT_ALIGNMENT);
2405 * These functions are the entry points into the interpreter from compiled code.
2406 * They are called by the interp_in wrappers. They have the following signature:
2407 * void (<optional this_arg>, <optional retval pointer>, <arg1>, ..., <argn>, <method ptr>)
2408 * They pack up their arguments into an InterpEntryData structure and call interp_entry ().
2409 * It would be possible for the wrappers to pack up the arguments etc, but that would make them bigger, and there are
2410 * more wrappers then these functions.
2411 * this/static * ret/void * 16 arguments -> 64 functions.
2414 #define MAX_INTERP_ENTRY_ARGS 8
2416 #define INTERP_ENTRY_BASE(_method, _this_arg, _res) \
2417 InterpEntryData data; \
2418 (data).rmethod = (_method); \
2419 (data).res = (_res); \
2420 (data).this_arg = (_this_arg); \
2421 (data).many_args = NULL;
2423 #define INTERP_ENTRY0(_this_arg, _res, _method) { \
2424 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2425 interp_entry (&data); \
2427 #define INTERP_ENTRY1(_this_arg, _res, _method) { \
2428 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2429 (data).args [0] = arg1; \
2430 interp_entry (&data); \
2432 #define INTERP_ENTRY2(_this_arg, _res, _method) { \
2433 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2434 (data).args [0] = arg1; \
2435 (data).args [1] = arg2; \
2436 interp_entry (&data); \
2438 #define INTERP_ENTRY3(_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 interp_entry (&data); \
2445 #define INTERP_ENTRY4(_this_arg, _res, _method) { \
2446 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2447 (data).args [0] = arg1; \
2448 (data).args [1] = arg2; \
2449 (data).args [2] = arg3; \
2450 (data).args [3] = arg4; \
2451 interp_entry (&data); \
2453 #define INTERP_ENTRY5(_this_arg, _res, _method) { \
2454 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2455 (data).args [0] = arg1; \
2456 (data).args [1] = arg2; \
2457 (data).args [2] = arg3; \
2458 (data).args [3] = arg4; \
2459 (data).args [4] = arg5; \
2460 interp_entry (&data); \
2462 #define INTERP_ENTRY6(_this_arg, _res, _method) { \
2463 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2464 (data).args [0] = arg1; \
2465 (data).args [1] = arg2; \
2466 (data).args [2] = arg3; \
2467 (data).args [3] = arg4; \
2468 (data).args [4] = arg5; \
2469 (data).args [5] = arg6; \
2470 interp_entry (&data); \
2472 #define INTERP_ENTRY7(_this_arg, _res, _method) { \
2473 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2474 (data).args [0] = arg1; \
2475 (data).args [1] = arg2; \
2476 (data).args [2] = arg3; \
2477 (data).args [3] = arg4; \
2478 (data).args [4] = arg5; \
2479 (data).args [5] = arg6; \
2480 (data).args [6] = arg7; \
2481 interp_entry (&data); \
2483 #define INTERP_ENTRY8(_this_arg, _res, _method) { \
2484 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2485 (data).args [0] = arg1; \
2486 (data).args [1] = arg2; \
2487 (data).args [2] = arg3; \
2488 (data).args [3] = arg4; \
2489 (data).args [4] = arg5; \
2490 (data).args [5] = arg6; \
2491 (data).args [6] = arg7; \
2492 (data).args [7] = arg8; \
2493 interp_entry (&data); \
2496 #define ARGLIST0 InterpMethod *rmethod
2497 #define ARGLIST1 gpointer arg1, InterpMethod *rmethod
2498 #define ARGLIST2 gpointer arg1, gpointer arg2, InterpMethod *rmethod
2499 #define ARGLIST3 gpointer arg1, gpointer arg2, gpointer arg3, InterpMethod *rmethod
2500 #define ARGLIST4 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, InterpMethod *rmethod
2501 #define ARGLIST5 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, gpointer arg5, InterpMethod *rmethod
2502 #define ARGLIST6 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, gpointer arg5, gpointer arg6, InterpMethod *rmethod
2503 #define ARGLIST7 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, gpointer arg5, gpointer arg6, gpointer arg7, InterpMethod *rmethod
2504 #define ARGLIST8 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, gpointer arg5, gpointer arg6, gpointer arg7, gpointer arg8, InterpMethod *rmethod
2506 static void interp_entry_static_0 (ARGLIST0) INTERP_ENTRY0 (NULL, NULL, rmethod)
2507 static void interp_entry_static_1 (ARGLIST1) INTERP_ENTRY1 (NULL, NULL, rmethod)
2508 static void interp_entry_static_2 (ARGLIST2) INTERP_ENTRY2 (NULL, NULL, rmethod)
2509 static void interp_entry_static_3 (ARGLIST3) INTERP_ENTRY3 (NULL, NULL, rmethod)
2510 static void interp_entry_static_4 (ARGLIST4) INTERP_ENTRY4 (NULL, NULL, rmethod)
2511 static void interp_entry_static_5 (ARGLIST5) INTERP_ENTRY5 (NULL, NULL, rmethod)
2512 static void interp_entry_static_6 (ARGLIST6) INTERP_ENTRY6 (NULL, NULL, rmethod)
2513 static void interp_entry_static_7 (ARGLIST7) INTERP_ENTRY7 (NULL, NULL, rmethod)
2514 static void interp_entry_static_8 (ARGLIST8) INTERP_ENTRY8 (NULL, NULL, rmethod)
2515 static void interp_entry_static_ret_0 (gpointer res, ARGLIST0) INTERP_ENTRY0 (NULL, res, rmethod)
2516 static void interp_entry_static_ret_1 (gpointer res, ARGLIST1) INTERP_ENTRY1 (NULL, res, rmethod)
2517 static void interp_entry_static_ret_2 (gpointer res, ARGLIST2) INTERP_ENTRY2 (NULL, res, rmethod)
2518 static void interp_entry_static_ret_3 (gpointer res, ARGLIST3) INTERP_ENTRY3 (NULL, res, rmethod)
2519 static void interp_entry_static_ret_4 (gpointer res, ARGLIST4) INTERP_ENTRY4 (NULL, res, rmethod)
2520 static void interp_entry_static_ret_5 (gpointer res, ARGLIST5) INTERP_ENTRY5 (NULL, res, rmethod)
2521 static void interp_entry_static_ret_6 (gpointer res, ARGLIST6) INTERP_ENTRY6 (NULL, res, rmethod)
2522 static void interp_entry_static_ret_7 (gpointer res, ARGLIST7) INTERP_ENTRY7 (NULL, res, rmethod)
2523 static void interp_entry_static_ret_8 (gpointer res, ARGLIST8) INTERP_ENTRY8 (NULL, res, rmethod)
2524 static void interp_entry_instance_0 (gpointer this_arg, ARGLIST0) INTERP_ENTRY0 (this_arg, NULL, rmethod)
2525 static void interp_entry_instance_1 (gpointer this_arg, ARGLIST1) INTERP_ENTRY1 (this_arg, NULL, rmethod)
2526 static void interp_entry_instance_2 (gpointer this_arg, ARGLIST2) INTERP_ENTRY2 (this_arg, NULL, rmethod)
2527 static void interp_entry_instance_3 (gpointer this_arg, ARGLIST3) INTERP_ENTRY3 (this_arg, NULL, rmethod)
2528 static void interp_entry_instance_4 (gpointer this_arg, ARGLIST4) INTERP_ENTRY4 (this_arg, NULL, rmethod)
2529 static void interp_entry_instance_5 (gpointer this_arg, ARGLIST5) INTERP_ENTRY5 (this_arg, NULL, rmethod)
2530 static void interp_entry_instance_6 (gpointer this_arg, ARGLIST6) INTERP_ENTRY6 (this_arg, NULL, rmethod)
2531 static void interp_entry_instance_7 (gpointer this_arg, ARGLIST7) INTERP_ENTRY7 (this_arg, NULL, rmethod)
2532 static void interp_entry_instance_8 (gpointer this_arg, ARGLIST8) INTERP_ENTRY8 (this_arg, NULL, rmethod)
2533 static void interp_entry_instance_ret_0 (gpointer this_arg, gpointer res, ARGLIST0) INTERP_ENTRY0 (this_arg, res, rmethod)
2534 static void interp_entry_instance_ret_1 (gpointer this_arg, gpointer res, ARGLIST1) INTERP_ENTRY1 (this_arg, res, rmethod)
2535 static void interp_entry_instance_ret_2 (gpointer this_arg, gpointer res, ARGLIST2) INTERP_ENTRY2 (this_arg, res, rmethod)
2536 static void interp_entry_instance_ret_3 (gpointer this_arg, gpointer res, ARGLIST3) INTERP_ENTRY3 (this_arg, res, rmethod)
2537 static void interp_entry_instance_ret_4 (gpointer this_arg, gpointer res, ARGLIST4) INTERP_ENTRY4 (this_arg, res, rmethod)
2538 static void interp_entry_instance_ret_5 (gpointer this_arg, gpointer res, ARGLIST5) INTERP_ENTRY5 (this_arg, res, rmethod)
2539 static void interp_entry_instance_ret_6 (gpointer this_arg, gpointer res, ARGLIST6) INTERP_ENTRY6 (this_arg, res, rmethod)
2540 static void interp_entry_instance_ret_7 (gpointer this_arg, gpointer res, ARGLIST7) INTERP_ENTRY7 (this_arg, res, rmethod)
2541 static void interp_entry_instance_ret_8 (gpointer this_arg, gpointer res, ARGLIST8) INTERP_ENTRY8 (this_arg, res, rmethod)
2543 #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
2545 static gpointer entry_funcs_static [MAX_INTERP_ENTRY_ARGS + 1] = { INTERP_ENTRY_FUNCLIST (static) };
2546 static gpointer entry_funcs_static_ret [MAX_INTERP_ENTRY_ARGS + 1] = { INTERP_ENTRY_FUNCLIST (static_ret) };
2547 static gpointer entry_funcs_instance [MAX_INTERP_ENTRY_ARGS + 1] = { INTERP_ENTRY_FUNCLIST (instance) };
2548 static gpointer entry_funcs_instance_ret [MAX_INTERP_ENTRY_ARGS + 1] = { INTERP_ENTRY_FUNCLIST (instance_ret) };
2550 /* General version for methods with more than MAX_INTERP_ENTRY_ARGS arguments */
2551 static void
2552 interp_entry_general (gpointer this_arg, gpointer res, gpointer *args, gpointer rmethod)
2554 INTERP_ENTRY_BASE ((InterpMethod*)rmethod, this_arg, res);
2555 data.many_args = args;
2556 interp_entry (&data);
2559 #ifdef MONO_ARCH_HAVE_INTERP_ENTRY_TRAMPOLINE
2561 // inline so we can alloc on stack
2562 #define alloc_storage_for_stackval(s, t, p) do { \
2563 if ((t)->type == MONO_TYPE_GENERICINST && !MONO_TYPE_IS_REFERENCE (t)) { \
2564 (s)->data.vt = alloca (mono_class_value_size (mono_class_from_mono_type_internal (t), NULL)); \
2565 } else if ((t)->type == MONO_TYPE_VALUETYPE) { \
2566 if (p) \
2567 (s)->data.vt = alloca (mono_class_native_size ((t)->data.klass, NULL)); \
2568 else \
2569 (s)->data.vt = alloca (mono_class_value_size ((t)->data.klass, NULL)); \
2571 } while (0)
2573 static void
2574 interp_entry_from_trampoline (gpointer ccontext_untyped, gpointer rmethod_untyped)
2576 InterpFrame frame;
2577 ThreadContext *context;
2578 stackval result;
2579 stackval *args;
2580 MonoMethod *method;
2581 MonoMethodSignature *sig;
2582 CallContext *ccontext = (CallContext*) ccontext_untyped;
2583 InterpMethod *rmethod = (InterpMethod*) rmethod_untyped;
2584 gpointer orig_domain = NULL, attach_cookie;
2585 int i;
2587 if (rmethod->needs_thread_attach)
2588 orig_domain = mono_threads_attach_coop (mono_domain_get (), &attach_cookie);
2590 context = get_context ();
2592 method = rmethod->method;
2593 sig = mono_method_signature_internal (method);
2595 frame.ex = NULL;
2597 args = (stackval*)alloca (sizeof (stackval) * (sig->param_count + (sig->hasthis ? 1 : 0)));
2599 init_frame (&frame, NULL, rmethod, args, &result);
2601 /* Allocate storage for value types */
2602 for (i = 0; i < sig->param_count; i++) {
2603 MonoType *type = sig->params [i];
2604 alloc_storage_for_stackval (&frame.stack_args [i + sig->hasthis], type, sig->pinvoke);
2607 if (sig->ret->type != MONO_TYPE_VOID)
2608 alloc_storage_for_stackval (frame.retval, sig->ret, sig->pinvoke);
2610 /* Copy the args saved in the trampoline to the frame stack */
2611 mono_arch_get_native_call_context_args (ccontext, &frame, sig);
2613 ERROR_DECL (error);
2614 interp_exec_method (&frame, context, error);
2616 if (rmethod->needs_thread_attach)
2617 mono_threads_detach_coop (orig_domain, &attach_cookie);
2619 // FIXME:
2620 g_assert (frame.ex == NULL);
2622 /* Write back the return value */
2623 mono_arch_set_native_call_context_ret (ccontext, &frame, sig);
2626 #else
2628 static void
2629 interp_entry_from_trampoline (gpointer ccontext_untyped, gpointer rmethod_untyped)
2631 g_assert_not_reached ();
2634 #endif /* MONO_ARCH_HAVE_INTERP_ENTRY_TRAMPOLINE */
2636 static InterpMethod*
2637 lookup_method_pointer (gpointer addr)
2639 MonoDomain *domain = mono_domain_get ();
2640 MonoJitDomainInfo *info = domain_jit_info (domain);
2641 InterpMethod *res = NULL;
2643 mono_domain_lock (domain);
2644 if (info->interp_method_pointer_hash)
2645 res = (InterpMethod*)g_hash_table_lookup (info->interp_method_pointer_hash, addr);
2646 mono_domain_unlock (domain);
2648 return res;
2651 #ifndef MONO_ARCH_HAVE_INTERP_NATIVE_TO_MANAGED
2652 static void
2653 interp_no_native_to_managed (void)
2655 g_error ("interpreter: native-to-managed transition not available on this platform");
2657 #endif
2659 static void
2660 no_llvmonly_interp_method_pointer (void)
2662 g_assert_not_reached ();
2666 * interp_create_method_pointer_llvmonly:
2668 * Return an ftndesc for entering the interpreter and executing METHOD.
2670 static MonoFtnDesc*
2671 interp_create_method_pointer_llvmonly (MonoMethod *method, gboolean unbox, MonoError *error)
2673 MonoDomain *domain = mono_domain_get ();
2674 gpointer addr, entry_func, entry_wrapper;
2675 MonoMethodSignature *sig;
2676 MonoMethod *wrapper;
2677 MonoJitDomainInfo *info;
2678 InterpMethod *imethod;
2680 imethod = mono_interp_get_imethod (domain, method, error);
2681 return_val_if_nok (error, NULL);
2683 if (unbox) {
2684 if (imethod->llvmonly_unbox_entry)
2685 return (MonoFtnDesc*)imethod->llvmonly_unbox_entry;
2686 } else {
2687 if (imethod->jit_entry)
2688 return (MonoFtnDesc*)imethod->jit_entry;
2691 sig = mono_method_signature_internal (method);
2694 * The entry functions need access to the method to call, so we have
2695 * to use a ftndesc. The caller uses a normal signature, while the
2696 * entry functions use a gsharedvt_in signature, so wrap the entry function in
2697 * a gsharedvt_in_sig wrapper.
2699 wrapper = mini_get_gsharedvt_in_sig_wrapper (sig);
2701 entry_wrapper = mono_jit_compile_method_jit_only (wrapper, error);
2702 mono_error_assertf_ok (error, "couldn't compile wrapper \"%s\" for \"%s\"",
2703 mono_method_get_name_full (wrapper, TRUE, TRUE, MONO_TYPE_NAME_FORMAT_IL),
2704 mono_method_get_name_full (method, TRUE, TRUE, MONO_TYPE_NAME_FORMAT_IL));
2706 if (sig->param_count > MAX_INTERP_ENTRY_ARGS) {
2707 g_assert_not_reached ();
2708 //entry_func = (gpointer)interp_entry_general;
2709 } else if (sig->hasthis) {
2710 if (sig->ret->type == MONO_TYPE_VOID)
2711 entry_func = entry_funcs_instance [sig->param_count];
2712 else
2713 entry_func = entry_funcs_instance_ret [sig->param_count];
2714 } else {
2715 if (sig->ret->type == MONO_TYPE_VOID)
2716 entry_func = entry_funcs_static [sig->param_count];
2717 else
2718 entry_func = entry_funcs_static_ret [sig->param_count];
2720 g_assert (entry_func);
2722 /* Encode unbox in the lower bit of imethod */
2723 gpointer entry_arg = imethod;
2724 if (unbox)
2725 entry_arg = (gpointer)(((gsize)entry_arg) | 1);
2726 MonoFtnDesc *entry_ftndesc = mini_llvmonly_create_ftndesc (mono_domain_get (), entry_func, entry_arg);
2728 addr = mini_llvmonly_create_ftndesc (mono_domain_get (), entry_wrapper, entry_ftndesc);
2730 info = domain_jit_info (domain);
2731 mono_domain_lock (domain);
2732 if (!info->interp_method_pointer_hash)
2733 info->interp_method_pointer_hash = g_hash_table_new (NULL, NULL);
2734 g_hash_table_insert (info->interp_method_pointer_hash, addr, imethod);
2735 mono_domain_unlock (domain);
2737 mono_memory_barrier ();
2738 if (unbox)
2739 imethod->llvmonly_unbox_entry = addr;
2740 else
2741 imethod->jit_entry = addr;
2743 return (MonoFtnDesc*)addr;
2747 * interp_create_method_pointer:
2749 * Return a function pointer which can be used to call METHOD using the
2750 * interpreter. Return NULL for methods which are not supported.
2752 static gpointer
2753 interp_create_method_pointer (MonoMethod *method, gboolean compile, MonoError *error)
2755 #ifndef MONO_ARCH_HAVE_INTERP_NATIVE_TO_MANAGED
2756 if (mono_llvm_only)
2757 return (gpointer)no_llvmonly_interp_method_pointer;
2758 return (gpointer)interp_no_native_to_managed;
2759 #else
2760 gpointer addr, entry_func, entry_wrapper = NULL;
2761 MonoDomain *domain = mono_domain_get ();
2762 MonoJitDomainInfo *info;
2763 InterpMethod *imethod = mono_interp_get_imethod (domain, method, error);
2765 if (mono_llvm_only)
2766 return (gpointer)no_llvmonly_interp_method_pointer;
2768 if (imethod->jit_entry)
2769 return imethod->jit_entry;
2771 if (compile && !imethod->transformed) {
2772 /* Return any errors from method compilation */
2773 mono_interp_transform_method (imethod, get_context (), error);
2774 return_val_if_nok (error, NULL);
2777 MonoMethodSignature *sig = mono_method_signature_internal (method);
2779 if (mono_llvm_only)
2780 /* The caller should call interp_create_method_pointer_llvmonly */
2781 g_assert_not_reached ();
2783 if (method->wrapper_type && method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE)
2784 return imethod;
2786 #ifndef MONO_ARCH_HAVE_FTNPTR_ARG_TRAMPOLINE
2788 * Interp in wrappers get the argument in the rgctx register. If
2789 * MONO_ARCH_HAVE_FTNPTR_ARG_TRAMPOLINE is defined it means that
2790 * on that arch the rgctx register is not scratch, so we use a
2791 * separate temp register. We should update the wrappers for this
2792 * if we really care about those architectures (arm).
2794 MonoMethod *wrapper = mini_get_interp_in_wrapper (sig);
2796 entry_wrapper = mono_jit_compile_method_jit_only (wrapper, error);
2797 #endif
2798 if (entry_wrapper) {
2799 if (sig->param_count > MAX_INTERP_ENTRY_ARGS) {
2800 entry_func = (gpointer)interp_entry_general;
2801 } else if (sig->hasthis) {
2802 if (sig->ret->type == MONO_TYPE_VOID)
2803 entry_func = entry_funcs_instance [sig->param_count];
2804 else
2805 entry_func = entry_funcs_instance_ret [sig->param_count];
2806 } else {
2807 if (sig->ret->type == MONO_TYPE_VOID)
2808 entry_func = entry_funcs_static [sig->param_count];
2809 else
2810 entry_func = entry_funcs_static_ret [sig->param_count];
2812 } else {
2813 #ifndef MONO_ARCH_HAVE_INTERP_ENTRY_TRAMPOLINE
2814 mono_error_assertf_ok (error, "couldn't compile wrapper \"%s\" for \"%s\"",
2815 mono_method_get_name_full (wrapper, TRUE, TRUE, MONO_TYPE_NAME_FORMAT_IL),
2816 mono_method_get_name_full (method, TRUE, TRUE, MONO_TYPE_NAME_FORMAT_IL));
2817 #else
2818 mono_error_cleanup (error);
2819 error_init_reuse (error);
2820 if (!mono_native_to_interp_trampoline) {
2821 if (mono_aot_only) {
2822 mono_native_to_interp_trampoline = (MonoFuncV)mono_aot_get_trampoline ("native_to_interp_trampoline");
2823 } else {
2824 MonoTrampInfo *info;
2825 mono_native_to_interp_trampoline = (MonoFuncV)mono_arch_get_native_to_interp_trampoline (&info);
2826 mono_tramp_info_register (info, NULL);
2829 entry_wrapper = (gpointer)mono_native_to_interp_trampoline;
2830 /* We need the lmf wrapper only when being called from mixed mode */
2831 if (sig->pinvoke)
2832 entry_func = (gpointer)interp_entry_from_trampoline;
2833 else {
2834 static gpointer cached_func = NULL;
2835 if (!cached_func) {
2836 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);
2837 mono_memory_barrier ();
2839 entry_func = cached_func;
2841 #endif
2844 g_assert (entry_func);
2845 /* This is the argument passed to the interp_in wrapper by the static rgctx trampoline */
2846 MonoFtnDesc *ftndesc = g_new0 (MonoFtnDesc, 1);
2847 ftndesc->addr = entry_func;
2848 ftndesc->arg = imethod;
2849 mono_error_assert_ok (error);
2852 * The wrapper is called by compiled code, which doesn't pass the extra argument, so we pass it in the
2853 * rgctx register using a trampoline.
2856 addr = mono_create_ftnptr_arg_trampoline (ftndesc, entry_wrapper);
2858 info = domain_jit_info (domain);
2859 mono_domain_lock (domain);
2860 if (!info->interp_method_pointer_hash)
2861 info->interp_method_pointer_hash = g_hash_table_new (NULL, NULL);
2862 g_hash_table_insert (info->interp_method_pointer_hash, addr, imethod);
2863 mono_domain_unlock (domain);
2865 mono_memory_barrier ();
2866 imethod->jit_entry = addr;
2868 return addr;
2869 #endif
2872 #if COUNT_OPS
2873 static int opcode_counts[512];
2875 #define COUNT_OP(op) opcode_counts[op]++
2876 #else
2877 #define COUNT_OP(op)
2878 #endif
2880 #if DEBUG_INTERP
2881 #define DUMP_INSTR() \
2882 if (tracing > 1) { \
2883 char *ins; \
2884 if (sp > frame->stack) { \
2885 ins = dump_stack (frame->stack, sp); \
2886 } else { \
2887 ins = g_strdup (""); \
2889 sp->data.l = 0; \
2890 output_indent (); \
2891 char *mn = mono_method_full_name (frame->imethod->method, FALSE); \
2892 char *disasm = mono_interp_dis_mintop(imethod->code, ip); \
2893 g_print ("(%p) %s -> %s\t%d:%s\n", mono_thread_internal_current (), mn, disasm, vt_sp - vtalloc, ins); \
2894 g_free (mn); \
2895 g_free (ins); \
2896 g_free (disasm); \
2898 #else
2899 #define DUMP_INSTR()
2900 #endif
2902 #define INIT_VTABLE(vtable) do { \
2903 if (G_UNLIKELY (!(vtable)->initialized)) { \
2904 mono_runtime_class_init_full ((vtable), error); \
2905 if (!is_ok (error)) \
2906 THROW_EX (mono_error_convert_to_exception (error), ip); \
2908 } while (0);
2910 static MONO_NEVER_INLINE MonoObject*
2911 mono_interp_new (MonoDomain* domain, MonoClass* klass)
2913 ERROR_DECL (error);
2914 MonoObject* const object = mono_object_new_checked (domain, klass, error);
2915 mono_error_cleanup (error); // FIXME: do not swallow the error
2916 return object;
2919 static
2920 #ifndef DISABLE_REMOTING
2921 MONO_NEVER_INLINE // To reduce stack.
2922 #endif
2923 void
2924 mono_interp_load_remote_field (
2925 InterpMethod* imethod,
2926 MonoObject* o,
2927 const guint16* ip,
2928 stackval* sp)
2930 g_assert (o); // Caller checks and throws exception properly.
2932 void* addr;
2933 MonoClassField* const field = (MonoClassField*)imethod->data_items[* (guint16 *)(ip + 1)];
2935 #ifndef DISABLE_REMOTING
2936 gpointer tmp;
2937 if (mono_object_is_transparent_proxy (o)) {
2938 MonoClass * const klass = ((MonoTransparentProxy*)o)->remote_class->proxy_class;
2939 ERROR_DECL (error);
2940 addr = mono_load_remote_field_checked (o, klass, field, &tmp, error);
2941 mono_error_cleanup (error); /* FIXME: don't swallow the error */
2942 } else
2943 #endif
2944 addr = (char*)o + field->offset;
2945 stackval_from_data (field->type, &sp [-1], addr, FALSE);
2948 static
2949 #ifndef DISABLE_REMOTING
2950 MONO_NEVER_INLINE // To reduce stack.
2951 #endif
2952 guchar* // Return new vt_sp instead of take-address.
2953 mono_interp_load_remote_field_vt (
2954 InterpMethod* imethod,
2955 MonoObject* o,
2956 const guint16* ip,
2957 stackval* sp,
2958 guchar* vt_sp)
2960 g_assert (o); // Caller checks and throws exception properly.
2962 void* addr;
2963 MonoClassField* const field = (MonoClassField*)imethod->data_items[* (guint16 *)(ip + 1)];
2964 MonoClass* klass = mono_class_from_mono_type_internal (field->type);
2965 int const i32 = mono_class_value_size (klass, NULL);
2967 #ifndef DISABLE_REMOTING
2968 gpointer tmp;
2969 if (mono_object_is_transparent_proxy (o)) {
2970 klass = ((MonoTransparentProxy*)o)->remote_class->proxy_class;
2971 ERROR_DECL (error);
2972 addr = mono_load_remote_field_checked (o, klass, field, &tmp, error);
2973 mono_error_cleanup (error); /* FIXME: don't swallow the error */
2974 } else
2975 #endif
2976 addr = (char*)o + field->offset;
2977 sp [-1].data.p = vt_sp;
2978 memcpy (vt_sp, addr, i32);
2979 return vt_sp + ALIGN_TO (i32, MINT_VT_ALIGNMENT);
2982 static MONO_NEVER_INLINE gboolean
2983 mono_interp_isinst (MonoObject* object, MonoClass* klass)
2985 ERROR_DECL (error);
2986 const gboolean isinst = mono_object_isinst_checked (object, klass, error) != NULL;
2987 mono_error_cleanup (error); // FIXME: do not swallow the error
2988 return isinst;
2992 * GC SAFETY:
2994 * The interpreter executes in gc unsafe (non-preempt) mode. On wasm, the C stack is
2995 * scannable but the wasm stack is not, so to make the code GC safe, the following rules
2996 * should be followed:
2997 * - every objref handled by the code needs to have a copy stored inside InterpFrame,
2998 * in stackval->data.o. For objrefs which are not yet on the IL stack, they can be stored
2999 * in frame->o. This will ensure the objects are pinned. The 'frame' local is assumed
3000 * to be allocated to the C stack and not to registers.
3001 * - minimalize the number of MonoObject* locals/arguments.
3004 #ifdef TARGET_WASM
3005 #define frame_objref(frame) (frame)->o
3006 #else
3007 #define frame_objref(frame) o
3008 #endif
3010 // This function is outlined to help save stack in its caller, on the premise
3011 // that it is relatively rarely called. This also lets it use alloca.
3012 static MONO_NEVER_INLINE void
3013 mono_interp_calli_nat_dynamic_pinvoke (
3014 // Parameters are sorted by name.
3015 InterpFrame* child_frame,
3016 guchar* code,
3017 ThreadContext* context,
3018 MonoMethodSignature* csignature,
3019 MonoError* error)
3021 // Recompute to limit parameters, which can also contribute to caller stack.
3022 InterpMethod* const imethod = child_frame->parent->imethod;
3024 g_assert (imethod->method->dynamic && csignature->pinvoke);
3026 /* Pinvoke call is missing the wrapper. See mono_get_native_calli_wrapper */
3027 MonoMarshalSpec** mspecs = g_newa (MonoMarshalSpec*, csignature->param_count + 1);
3028 memset (mspecs, 0, sizeof (MonoMarshalSpec*) * (csignature->param_count + 1));
3030 MonoMethodPInvoke iinfo;
3031 memset (&iinfo, 0, sizeof (iinfo));
3033 MonoMethod* m = mono_marshal_get_native_func_wrapper (m_class_get_image (imethod->method->klass), csignature, &iinfo, mspecs, code);
3035 for (int i = csignature->param_count; i >= 0; i--)
3036 if (mspecs [i])
3037 mono_metadata_free_marshal_spec (mspecs [i]);
3040 ERROR_DECL (error);
3041 child_frame->imethod = mono_interp_get_imethod (imethod->domain, m, error);
3042 mono_error_cleanup (error); /* FIXME: don't swallow the error */
3045 interp_exec_method (child_frame, context, error);
3048 // Leave is split into pieces in order to consume less stack,
3049 // but not have to change how exception handling macros access labels and locals.
3050 static MONO_NEVER_INLINE MonoException*
3051 mono_interp_leave (InterpFrame* child_frame)
3053 stackval tmp_sp;
3055 * We need for mono_thread_get_undeniable_exception to be able to unwind
3056 * to check the abort threshold. For this to work we use child_frame as a
3057 * dummy frame that is stored in the lmf and serves as the transition frame
3059 do_icall_wrapper (child_frame, NULL, MINT_ICALL_V_P, &tmp_sp, (gpointer)mono_thread_get_undeniable_exception, FALSE);
3061 return (MonoException*)tmp_sp.data.p;
3064 static MONO_NEVER_INLINE void
3065 mono_interp_newobj_vt (
3066 // Parameters are sorted by name and parameter list is minimized
3067 // to reduce stack use in caller, on e.g. NT/AMD64 (up to 4 parameters
3068 // use no stack in caller).
3069 InterpFrame* child_frame,
3070 ThreadContext* context,
3071 MonoError* error)
3073 stackval* const sp = child_frame->stack_args;
3075 stackval valuetype_this;
3077 memset (&valuetype_this, 0, sizeof (stackval));
3078 sp->data.p = &valuetype_this;
3080 // FIXME It is unfortunate to outline a recursive case as it
3081 // increases its stack usage. We do this however as it conserves
3082 // stack for all the other recursive cases.
3083 interp_exec_method (child_frame, context, error);
3085 CHECK_RESUME_STATE_IN_HELPER_FUNCTION (context, );
3087 *sp = valuetype_this;
3090 static MONO_NEVER_INLINE MonoException*
3091 mono_interp_newobj (
3092 // Parameters are sorted by name and parameter list is minimized
3093 // to reduce stack use in caller, on e.g. NT/AMD64 (up to 4 parameters
3094 // use no stack in caller).
3095 InterpFrame* child_frame,
3096 ThreadContext* context,
3097 MonoError* error,
3098 guchar* vt_sp)
3100 InterpFrame* const frame = child_frame->parent;
3101 InterpMethod* const imethod = frame->imethod;
3102 stackval* const sp = child_frame->stack_args;
3104 MonoObject* o = NULL; // See the comment about GC safety above.
3105 stackval valuetype_this;
3106 stackval retval;
3108 MonoClass * const newobj_class = child_frame->imethod->method->klass;
3109 /*if (profiling_classes) {
3110 guint count = GPOINTER_TO_UINT (g_hash_table_lookup (profiling_classes, newobj_class));
3111 count++;
3112 g_hash_table_insert (profiling_classes, newobj_class, GUINT_TO_POINTER (count));
3116 * First arg is the object.
3118 if (m_class_is_valuetype (newobj_class)) {
3119 MonoType *t = m_class_get_byval_arg (newobj_class);
3120 memset (&valuetype_this, 0, sizeof (stackval));
3121 if (!m_class_is_enumtype (newobj_class) && (t->type == MONO_TYPE_VALUETYPE || (t->type == MONO_TYPE_GENERICINST && mono_type_generic_inst_is_valuetype (t)))) {
3122 sp->data.p = vt_sp;
3123 valuetype_this.data.p = vt_sp;
3124 } else {
3125 sp->data.p = &valuetype_this;
3127 } else {
3128 if (newobj_class != mono_defaults.string_class) {
3129 MonoVTable *vtable = mono_class_vtable_checked (imethod->domain, newobj_class, error);
3130 if (!is_ok (error) || !mono_runtime_class_init_full (vtable, error)) {
3131 MonoException* const exc = mono_error_convert_to_exception (error);
3132 g_assert (exc);
3133 return exc;
3135 ERROR_DECL (error);
3136 frame_objref (frame) = mono_object_new_checked (imethod->domain, newobj_class, error);
3137 mono_error_cleanup (error); // FIXME: do not swallow the error
3138 EXCEPTION_CHECKPOINT_IN_HELPER_FUNCTION;
3139 sp->data.o = frame_objref (frame);
3140 #ifndef DISABLE_REMOTING
3141 if (mono_object_is_transparent_proxy (frame_objref (frame))) {
3142 MonoMethod *remoting_invoke_method = mono_marshal_get_remoting_invoke_with_check (child_frame->imethod->method, error);
3143 mono_error_assert_ok (error);
3144 child_frame->imethod = mono_interp_get_imethod (imethod->domain, remoting_invoke_method, error);
3145 mono_error_assert_ok (error);
3147 #endif
3148 } else {
3149 sp->data.p = NULL;
3150 child_frame->retval = &retval;
3154 interp_exec_method (child_frame, context, error);
3156 CHECK_RESUME_STATE_IN_HELPER_FUNCTION (context, NULL);
3159 * a constructor returns void, but we need to return the object we created
3161 if (m_class_is_valuetype (newobj_class) && !m_class_is_enumtype (newobj_class)) {
3162 *sp = valuetype_this;
3163 } else if (newobj_class == mono_defaults.string_class) {
3164 *sp = retval;
3165 } else {
3166 sp->data.o = frame_objref (frame);
3168 return NULL;
3171 static MONO_NEVER_INLINE void
3172 mono_interp_enum_hasflag (stackval* sp, MonoClass* klass)
3174 guint64 a_val = 0, b_val = 0;
3176 stackval_to_data (m_class_get_byval_arg (klass), --sp, &b_val, FALSE);
3177 stackval_to_data (m_class_get_byval_arg (klass), --sp, &a_val, FALSE);
3178 sp->data.i = (a_val & b_val) == b_val;
3181 static MONO_NEVER_INLINE int
3182 mono_interp_box_nullable (InterpFrame* frame, const guint16* ip, stackval* sp, MonoError* error)
3184 InterpMethod* const imethod = frame->imethod;
3185 MonoClass* const c = (MonoClass*)imethod->data_items [* (guint16 *)(ip + 1)];
3187 int size = mono_class_value_size (c, NULL);
3189 guint16 offset = * (guint16 *)(ip + 2);
3190 gboolean pop_vt_sp = !(offset & BOX_NOT_CLEAR_VT_SP);
3191 offset &= ~BOX_NOT_CLEAR_VT_SP;
3193 sp [-1 - offset].data.o = mono_nullable_box (sp [-1 - offset].data.p, c, error);
3194 mono_error_cleanup (error); /* FIXME: don't swallow the error */
3196 size = ALIGN_TO (size, MINT_VT_ALIGNMENT);
3198 return pop_vt_sp ? size : 0;
3201 static MONO_NEVER_INLINE int
3202 mono_interp_store_remote_field_vt (InterpFrame* frame, const guint16* ip, stackval* sp, MonoError* error)
3204 InterpMethod* const imethod = frame->imethod;
3205 MonoClassField *field;
3207 MonoObject* const o = sp [-2].data.o;
3209 field = (MonoClassField*)imethod->data_items[* (guint16 *)(ip + 1)];
3210 MonoClass *klass = mono_class_from_mono_type_internal (field->type);
3211 int const i32 = mono_class_value_size (klass, NULL);
3213 #ifndef DISABLE_REMOTING
3214 if (mono_object_is_transparent_proxy (o)) {
3215 MonoClass *klass = ((MonoTransparentProxy*)o)->remote_class->proxy_class;
3216 mono_store_remote_field_checked (o, klass, field, sp [-1].data.p, error);
3217 mono_error_cleanup (error); /* FIXME: don't swallow the error */
3218 } else
3219 #endif
3220 mono_value_copy_internal ((char *) o + field->offset, sp [-1].data.p, klass);
3222 return ALIGN_TO (i32, MINT_VT_ALIGNMENT);
3226 * If EXIT_AT_FINALLY is not -1, exit after exiting the finally clause with that index.
3227 * If BASE_FRAME is not NULL, copy arguments/locals from BASE_FRAME.
3228 * The ERROR argument is used to avoid declaring an error object for every interp frame, its not used
3229 * to return error information.
3231 static void
3232 interp_exec_method_full (InterpFrame *frame, ThreadContext *context, FrameClauseArgs *clause_args, MonoError *error)
3234 InterpFrame child_frame;
3235 GSList *finally_ips = NULL;
3236 const guint16 *endfinally_ip = NULL;
3237 const guint16 *ip = NULL;
3238 stackval *sp;
3239 InterpMethod *imethod = NULL;
3240 #if DEBUG_INTERP
3241 gint tracing = global_tracing;
3242 unsigned char *vtalloc;
3243 #endif
3244 unsigned char *vt_sp;
3245 unsigned char *locals = NULL;
3246 #if USE_COMPUTED_GOTO
3247 static void * const in_labels[] = {
3248 #define OPDEF(a,b,c,d) &&LAB_ ## a,
3249 #include "mintops.def"
3251 #endif
3253 frame->ex = NULL;
3254 #if DEBUG_INTERP
3255 debug_enter (frame, &tracing);
3256 #endif
3258 imethod = frame->imethod;
3259 if (!imethod->transformed) {
3260 #if DEBUG_INTERP
3261 char *mn = mono_method_full_name (imethod->method, TRUE);
3262 g_print ("(%p) Transforming %s\n", mono_thread_internal_current (), mn);
3263 g_free (mn);
3264 #endif
3266 frame->ip = NULL;
3267 do_transform_method (frame, context);
3268 if (frame->ex)
3269 THROW_EX (frame->ex, NULL);
3270 EXCEPTION_CHECKPOINT;
3273 if (!clause_args) {
3274 frame->stack = (stackval*)g_alloca (imethod->alloca_size);
3275 ip = imethod->code;
3276 } else {
3277 ip = clause_args->start_with_ip;
3278 if (clause_args->base_frame) {
3279 frame->stack = (stackval*)g_alloca (imethod->alloca_size);
3280 memcpy (frame->stack, clause_args->base_frame->stack, imethod->alloca_size);
3283 sp = frame->stack;
3284 vt_sp = (unsigned char *) sp + imethod->stack_size;
3285 #if DEBUG_INTERP
3286 vtalloc = vt_sp;
3287 #endif
3288 locals = frame_locals (frame);
3289 child_frame.parent = frame;
3291 if (clause_args && clause_args->filter_exception) {
3292 sp->data.p = clause_args->filter_exception;
3293 sp++;
3296 //g_print ("(%p) Call %s\n", mono_thread_internal_current (), mono_method_get_full_name (frame->imethod->method));
3299 * using while (ip < end) may result in a 15% performance drop,
3300 * but it may be useful for debug
3302 while (1) {
3303 main_loop:
3304 /* g_assert (sp >= frame->stack); */
3305 /* g_assert(vt_sp - vtalloc <= imethod->vt_stack_size); */
3306 DUMP_INSTR();
3307 MINT_IN_SWITCH (*ip) {
3308 MINT_IN_CASE(MINT_INITLOCALS)
3309 memset (frame_locals (frame), 0, imethod->locals_size);
3310 ++ip;
3311 MINT_IN_BREAK;
3312 MINT_IN_CASE(MINT_NOP)
3313 ++ip;
3314 MINT_IN_BREAK;
3315 MINT_IN_CASE(MINT_NIY)
3316 g_error ("mint_niy: instruction not implemented yet. This shouldn't happen.");
3317 MINT_IN_BREAK;
3318 MINT_IN_CASE(MINT_BREAK)
3319 ++ip;
3320 do_debugger_tramp (mini_get_dbg_callbacks ()->user_break, frame);
3321 MINT_IN_BREAK;
3322 MINT_IN_CASE(MINT_BREAKPOINT)
3323 ++ip;
3324 mono_break ();
3325 MINT_IN_BREAK;
3326 MINT_IN_CASE(MINT_LDNULL)
3327 sp->data.p = NULL;
3328 ++ip;
3329 ++sp;
3330 MINT_IN_BREAK;
3331 MINT_IN_CASE(MINT_ARGLIST)
3332 g_assert (frame->varargs);
3333 sp->data.p = vt_sp;
3334 *(gpointer*)sp->data.p = frame->varargs;
3335 vt_sp += ALIGN_TO (sizeof (gpointer), MINT_VT_ALIGNMENT);
3336 ++ip;
3337 ++sp;
3338 MINT_IN_BREAK;
3339 MINT_IN_CASE(MINT_VTRESULT) {
3340 int ret_size = * (guint16 *)(ip + 1);
3341 unsigned char *ret_vt_sp = vt_sp;
3342 vt_sp -= READ32(ip + 2);
3343 if (ret_size > 0) {
3344 memmove (vt_sp, ret_vt_sp, ret_size);
3345 sp [-1].data.p = vt_sp;
3346 vt_sp += ALIGN_TO (ret_size, MINT_VT_ALIGNMENT);
3348 ip += 4;
3349 MINT_IN_BREAK;
3351 #define LDC(n) do { sp->data.i = (n); ++ip; ++sp; } while (0)
3352 MINT_IN_CASE(MINT_LDC_I4_M1)
3353 LDC(-1);
3354 MINT_IN_BREAK;
3355 MINT_IN_CASE(MINT_LDC_I4_0)
3356 LDC(0);
3357 MINT_IN_BREAK;
3358 MINT_IN_CASE(MINT_LDC_I4_1)
3359 LDC(1);
3360 MINT_IN_BREAK;
3361 MINT_IN_CASE(MINT_LDC_I4_2)
3362 LDC(2);
3363 MINT_IN_BREAK;
3364 MINT_IN_CASE(MINT_LDC_I4_3)
3365 LDC(3);
3366 MINT_IN_BREAK;
3367 MINT_IN_CASE(MINT_LDC_I4_4)
3368 LDC(4);
3369 MINT_IN_BREAK;
3370 MINT_IN_CASE(MINT_LDC_I4_5)
3371 LDC(5);
3372 MINT_IN_BREAK;
3373 MINT_IN_CASE(MINT_LDC_I4_6)
3374 LDC(6);
3375 MINT_IN_BREAK;
3376 MINT_IN_CASE(MINT_LDC_I4_7)
3377 LDC(7);
3378 MINT_IN_BREAK;
3379 MINT_IN_CASE(MINT_LDC_I4_8)
3380 LDC(8);
3381 MINT_IN_BREAK;
3382 MINT_IN_CASE(MINT_LDC_I4_S)
3383 sp->data.i = *(const short *)(ip + 1);
3384 ip += 2;
3385 ++sp;
3386 MINT_IN_BREAK;
3387 MINT_IN_CASE(MINT_LDC_I4)
3388 ++ip;
3389 sp->data.i = READ32 (ip);
3390 ip += 2;
3391 ++sp;
3392 MINT_IN_BREAK;
3393 MINT_IN_CASE(MINT_LDC_I8)
3394 ++ip;
3395 sp->data.l = READ64 (ip);
3396 ip += 4;
3397 ++sp;
3398 MINT_IN_BREAK;
3399 MINT_IN_CASE(MINT_LDC_I8_S)
3400 sp->data.l = *(const short *)(ip + 1);
3401 ip += 2;
3402 ++sp;
3403 MINT_IN_BREAK;
3404 MINT_IN_CASE(MINT_LDC_R4) {
3405 guint32 val;
3406 ++ip;
3407 val = READ32(ip);
3408 sp->data.f_r4 = * (float *)&val;
3409 ip += 2;
3410 ++sp;
3411 MINT_IN_BREAK;
3413 MINT_IN_CASE(MINT_LDC_R8)
3414 sp->data.l = READ64 (ip + 1); /* note union usage */
3415 ip += 5;
3416 ++sp;
3417 MINT_IN_BREAK;
3418 MINT_IN_CASE(MINT_DUP)
3419 sp [0] = sp[-1];
3420 ++sp;
3421 ++ip;
3422 MINT_IN_BREAK;
3423 MINT_IN_CASE(MINT_DUP_VT) {
3424 int const i32 = READ32 (ip + 1);
3425 sp->data.p = vt_sp;
3426 memcpy(sp->data.p, sp [-1].data.p, i32);
3427 vt_sp += ALIGN_TO (i32, MINT_VT_ALIGNMENT);
3428 ++sp;
3429 ip += 3;
3430 MINT_IN_BREAK;
3432 MINT_IN_CASE(MINT_POP) {
3433 guint16 u16 = (* (guint16 *)(ip + 1)) + 1;
3434 if (u16 > 1)
3435 memmove (sp - u16, sp - 1, (u16 - 1) * sizeof (stackval));
3436 sp--;
3437 ip += 2;
3438 MINT_IN_BREAK;
3440 MINT_IN_CASE(MINT_JMP) {
3441 InterpMethod *new_method = (InterpMethod*)imethod->data_items [* (guint16 *)(ip + 1)];
3443 if (imethod->prof_flags & MONO_PROFILER_CALL_INSTRUMENTATION_TAIL_CALL)
3444 MONO_PROFILER_RAISE (method_tail_call, (imethod->method, new_method->method));
3446 if (!new_method->transformed) {
3447 MONO_API_ERROR_INIT (error);
3449 frame->ip = ip;
3450 mono_interp_transform_method (new_method, context, error);
3451 frame->ex = mono_error_convert_to_exception (error);
3452 if (frame->ex)
3453 goto exit_frame;
3455 ip += 2;
3456 const gboolean realloc_frame = new_method->alloca_size > imethod->alloca_size;
3457 imethod = frame->imethod = new_method;
3459 * We allocate the stack frame from scratch and store the arguments in the
3460 * locals again since it's possible for the caller stack frame to be smaller
3461 * than the callee stack frame (at the interp level)
3463 if (realloc_frame) {
3464 frame->stack = (stackval*)g_alloca (imethod->alloca_size);
3465 memset (frame->stack, 0, imethod->alloca_size);
3466 sp = frame->stack;
3468 vt_sp = (unsigned char *) sp + imethod->stack_size;
3469 #if DEBUG_INTERP
3470 vtalloc = vt_sp;
3471 #endif
3472 locals = frame_locals (frame);
3473 ip = imethod->code;
3474 MINT_IN_BREAK;
3476 MINT_IN_CASE(MINT_CALLI) {
3477 MonoMethodSignature *csignature;
3479 frame->ip = ip;
3481 csignature = (MonoMethodSignature*)imethod->data_items [* (guint16 *)(ip + 1)];
3482 ip += 2;
3483 --sp;
3484 child_frame.imethod = (InterpMethod*)sp->data.p;
3486 sp->data.p = vt_sp;
3487 child_frame.retval = sp;
3488 /* decrement by the actual number of args */
3489 sp -= csignature->param_count;
3490 if (csignature->hasthis)
3491 --sp;
3492 child_frame.stack_args = sp;
3494 if (child_frame.imethod->method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) {
3495 child_frame.imethod = mono_interp_get_imethod (imethod->domain, mono_marshal_get_native_wrapper (child_frame.imethod->method, FALSE, FALSE), error);
3496 mono_error_cleanup (error); /* FIXME: don't swallow the error */
3499 if (csignature->hasthis) {
3500 MonoObject *this_arg = (MonoObject*)sp->data.p;
3502 if (m_class_is_valuetype (this_arg->vtable->klass)) {
3503 gpointer unboxed = mono_object_unbox_internal (this_arg);
3504 sp [0].data.p = unboxed;
3508 interp_exec_method (&child_frame, context, error);
3510 CHECK_RESUME_STATE (context);
3512 /* need to handle typedbyref ... */
3513 if (csignature->ret->type != MONO_TYPE_VOID) {
3514 *sp = *child_frame.retval;
3515 sp++;
3517 MINT_IN_BREAK;
3519 MINT_IN_CASE(MINT_CALLI_NAT_FAST) {
3520 gpointer target_ip = sp [-1].data.p;
3521 MonoMethodSignature *csignature = (MonoMethodSignature*)imethod->data_items [* (guint16 *)(ip + 1)];
3522 int opcode = *(guint16 *)(ip + 2);
3523 gboolean save_last_error = *(guint16 *)(ip + 3);
3525 sp--;
3526 frame->ip = ip;
3528 sp = do_icall_wrapper (frame, csignature, opcode, sp, target_ip, save_last_error);
3529 EXCEPTION_CHECKPOINT;
3530 CHECK_RESUME_STATE (context);
3531 ip += 4;
3532 MINT_IN_BREAK;
3534 MINT_IN_CASE(MINT_CALLI_NAT) {
3536 frame->ip = ip;
3538 MonoMethodSignature* csignature = (MonoMethodSignature*)imethod->data_items [* (guint16 *)(ip + 1)];
3540 ip += 3;
3541 --sp;
3542 guchar* const code = (guchar*)sp->data.p;
3543 child_frame.imethod = NULL;
3545 sp->data.p = vt_sp;
3546 child_frame.retval = sp;
3547 /* decrement by the actual number of args */
3548 sp -= csignature->param_count;
3549 if (csignature->hasthis)
3550 --sp;
3551 child_frame.stack_args = sp;
3553 if (imethod->method->dynamic && csignature->pinvoke) {
3554 mono_interp_calli_nat_dynamic_pinvoke (&child_frame, code, context, csignature, error);
3555 } else {
3556 const gboolean save_last_error = *(guint16 *)(ip - 3 + 2);
3557 ves_pinvoke_method (&child_frame, csignature, (MonoFuncV) code, FALSE, context, save_last_error);
3560 CHECK_RESUME_STATE (context);
3562 /* need to handle typedbyref ... */
3563 if (csignature->ret->type != MONO_TYPE_VOID) {
3564 *sp = *child_frame.retval;
3565 sp++;
3567 MINT_IN_BREAK;
3569 MINT_IN_CASE(MINT_CALLVIRT_FAST)
3570 MINT_IN_CASE(MINT_VCALLVIRT_FAST) {
3571 MonoObject *this_arg;
3572 InterpMethod *target_imethod;
3573 int slot;
3575 // FIXME Have it handle also remoting calls and use a single opcode for virtual calls
3577 frame->ip = ip;
3579 target_imethod = (InterpMethod*)imethod->data_items [* (guint16 *)(ip + 1)];
3580 slot = *(gint16*)(ip + 2);
3581 ip += 3;
3582 sp->data.p = vt_sp;
3583 child_frame.retval = sp;
3585 /* decrement by the actual number of args */
3586 sp -= target_imethod->param_count + target_imethod->hasthis;
3587 child_frame.stack_args = sp;
3589 this_arg = (MonoObject*)sp->data.p;
3591 child_frame.imethod = get_virtual_method_fast (target_imethod, this_arg->vtable, slot);
3592 if (m_class_is_valuetype (this_arg->vtable->klass) && m_class_is_valuetype (child_frame.imethod->method->klass)) {
3593 /* unbox */
3594 gpointer unboxed = mono_object_unbox_internal (this_arg);
3595 sp [0].data.p = unboxed;
3598 interp_exec_method (&child_frame, context, error);
3600 CHECK_RESUME_STATE (context);
3602 const gboolean is_void = ip [-3] == MINT_VCALLVIRT_FAST;
3603 if (!is_void) {
3604 /* need to handle typedbyref ... */
3605 *sp = *child_frame.retval;
3606 sp++;
3608 MINT_IN_BREAK;
3610 MINT_IN_CASE(MINT_CALL_VARARG) {
3611 int num_varargs = 0;
3612 MonoMethodSignature *csig;
3614 frame->ip = ip;
3616 child_frame.imethod = (InterpMethod*)imethod->data_items [* (guint16 *)(ip + 1)];
3617 /* The real signature for vararg calls */
3618 csig = (MonoMethodSignature*) imethod->data_items [* (guint16*) (ip + 2)];
3619 /* Push all vararg arguments from normal sp to vt_sp together with the signature */
3620 num_varargs = csig->param_count - csig->sentinelpos;
3621 child_frame.varargs = (char*) vt_sp;
3622 vt_sp = copy_varargs_vtstack (csig, sp, vt_sp);
3624 ip += 3;
3625 sp->data.p = vt_sp;
3626 child_frame.retval = sp;
3628 /* decrement by the actual number of args */
3629 sp -= child_frame.imethod->param_count + child_frame.imethod->hasthis + num_varargs;
3630 child_frame.stack_args = sp;
3632 interp_exec_method (&child_frame, context, error);
3634 CHECK_RESUME_STATE (context);
3636 if (csig->ret->type != MONO_TYPE_VOID) {
3637 *sp = *child_frame.retval;
3638 sp++;
3640 MINT_IN_BREAK;
3642 MINT_IN_CASE(MINT_CALL)
3643 MINT_IN_CASE(MINT_VCALL)
3644 MINT_IN_CASE(MINT_CALLVIRT)
3645 MINT_IN_CASE(MINT_VCALLVIRT) {
3647 frame->ip = ip;
3649 child_frame.imethod = (InterpMethod*)imethod->data_items [* (guint16 *)(ip + 1)];
3650 ip += 2;
3651 sp->data.p = vt_sp;
3652 child_frame.retval = sp;
3654 /* decrement by the actual number of args */
3655 sp -= child_frame.imethod->param_count + child_frame.imethod->hasthis;
3656 child_frame.stack_args = sp;
3658 const gboolean is_virtual = ip [-2] == MINT_CALLVIRT || ip [-2] == MINT_VCALLVIRT;
3659 if (is_virtual) {
3660 MonoObject *this_arg = (MonoObject*)sp->data.p;
3662 child_frame.imethod = get_virtual_method (child_frame.imethod, this_arg->vtable);
3663 if (m_class_is_valuetype (this_arg->vtable->klass) && m_class_is_valuetype (child_frame.imethod->method->klass)) {
3664 /* unbox */
3665 gpointer unboxed = mono_object_unbox_internal (this_arg);
3666 sp [0].data.p = unboxed;
3670 interp_exec_method (&child_frame, context, error);
3672 CHECK_RESUME_STATE (context);
3674 const gboolean is_void = ip [-2] == MINT_VCALL || ip [-2] == MINT_VCALLVIRT;
3675 if (!is_void) {
3676 /* need to handle typedbyref ... */
3677 *sp = *child_frame.retval;
3678 sp++;
3680 MINT_IN_BREAK;
3682 MINT_IN_CASE(MINT_JIT_CALL) {
3683 InterpMethod *rmethod = (InterpMethod*)imethod->data_items [* (guint16 *)(ip + 1)];
3684 MONO_API_ERROR_INIT (error);
3685 frame->ip = ip;
3686 sp = do_jit_call (sp, vt_sp, context, frame, rmethod, error);
3687 if (!is_ok (error)) {
3688 MonoException *ex = mono_error_convert_to_exception (error);
3689 THROW_EX (ex, ip);
3691 ip += 2;
3693 CHECK_RESUME_STATE (context);
3695 if (rmethod->rtype->type != MONO_TYPE_VOID)
3696 sp++;
3698 MINT_IN_BREAK;
3700 MINT_IN_CASE(MINT_CALLRUN) {
3701 MonoMethod *target_method = (MonoMethod*) imethod->data_items [* (guint16 *)(ip + 1)];
3702 MonoMethodSignature *sig = (MonoMethodSignature*) imethod->data_items [* (guint16 *)(ip + 2)];
3703 stackval *retval;
3705 sp->data.p = vt_sp;
3706 retval = sp;
3708 sp -= sig->param_count;
3709 if (sig->hasthis)
3710 sp--;
3712 ves_imethod (frame, target_method, sig, sp, retval);
3713 if (frame->ex)
3714 THROW_EX (frame->ex, ip);
3716 if (sig->ret->type != MONO_TYPE_VOID) {
3717 *sp = *retval;
3718 sp++;
3720 ip += 3;
3721 MINT_IN_BREAK;
3723 MINT_IN_CASE(MINT_RET)
3724 --sp;
3725 *frame->retval = *sp;
3726 if (sp > frame->stack)
3727 g_warning ("ret: more values on stack: %d", sp-frame->stack);
3728 goto exit_frame;
3729 MINT_IN_CASE(MINT_RET_VOID)
3730 if (sp > frame->stack)
3731 g_warning ("ret.void: more values on stack: %d %s", sp-frame->stack, mono_method_full_name (imethod->method, TRUE));
3732 goto exit_frame;
3733 MINT_IN_CASE(MINT_RET_VT) {
3734 int const i32 = READ32 (ip + 1);
3735 --sp;
3736 memcpy(frame->retval->data.p, sp->data.p, i32);
3737 if (sp > frame->stack)
3738 g_warning ("ret.vt: more values on stack: %d", sp-frame->stack);
3739 goto exit_frame;
3741 MINT_IN_CASE(MINT_BR_S)
3742 ip += (short) *(ip + 1);
3743 MINT_IN_BREAK;
3744 MINT_IN_CASE(MINT_BR)
3745 ip += (gint32) READ32(ip + 1);
3746 MINT_IN_BREAK;
3747 #define ZEROP_S(datamem, op) \
3748 --sp; \
3749 if (sp->data.datamem op 0) \
3750 ip += * (gint16 *)(ip + 1); \
3751 else \
3752 ip += 2;
3754 #define ZEROP(datamem, op) \
3755 --sp; \
3756 if (sp->data.datamem op 0) \
3757 ip += (gint32)READ32(ip + 1); \
3758 else \
3759 ip += 3;
3761 MINT_IN_CASE(MINT_BRFALSE_I4_S)
3762 ZEROP_S(i, ==);
3763 MINT_IN_BREAK;
3764 MINT_IN_CASE(MINT_BRFALSE_I8_S)
3765 ZEROP_S(l, ==);
3766 MINT_IN_BREAK;
3767 MINT_IN_CASE(MINT_BRFALSE_R4_S)
3768 ZEROP_S(f_r4, ==);
3769 MINT_IN_BREAK;
3770 MINT_IN_CASE(MINT_BRFALSE_R8_S)
3771 ZEROP_S(f, ==);
3772 MINT_IN_BREAK;
3773 MINT_IN_CASE(MINT_BRFALSE_I4)
3774 ZEROP(i, ==);
3775 MINT_IN_BREAK;
3776 MINT_IN_CASE(MINT_BRFALSE_I8)
3777 ZEROP(l, ==);
3778 MINT_IN_BREAK;
3779 MINT_IN_CASE(MINT_BRFALSE_R4)
3780 ZEROP_S(f_r4, ==);
3781 MINT_IN_BREAK;
3782 MINT_IN_CASE(MINT_BRFALSE_R8)
3783 ZEROP_S(f, ==);
3784 MINT_IN_BREAK;
3785 MINT_IN_CASE(MINT_BRTRUE_I4_S)
3786 ZEROP_S(i, !=);
3787 MINT_IN_BREAK;
3788 MINT_IN_CASE(MINT_BRTRUE_I8_S)
3789 ZEROP_S(l, !=);
3790 MINT_IN_BREAK;
3791 MINT_IN_CASE(MINT_BRTRUE_R4_S)
3792 ZEROP_S(f_r4, !=);
3793 MINT_IN_BREAK;
3794 MINT_IN_CASE(MINT_BRTRUE_R8_S)
3795 ZEROP_S(f, !=);
3796 MINT_IN_BREAK;
3797 MINT_IN_CASE(MINT_BRTRUE_I4)
3798 ZEROP(i, !=);
3799 MINT_IN_BREAK;
3800 MINT_IN_CASE(MINT_BRTRUE_I8)
3801 ZEROP(l, !=);
3802 MINT_IN_BREAK;
3803 MINT_IN_CASE(MINT_BRTRUE_R4)
3804 ZEROP(f_r4, !=);
3805 MINT_IN_BREAK;
3806 MINT_IN_CASE(MINT_BRTRUE_R8)
3807 ZEROP(f, !=);
3808 MINT_IN_BREAK;
3809 #define CONDBR_S(cond) \
3810 sp -= 2; \
3811 if (cond) \
3812 ip += * (gint16 *)(ip + 1); \
3813 else \
3814 ip += 2;
3815 #define BRELOP_S(datamem, op) \
3816 CONDBR_S(sp[0].data.datamem op sp[1].data.datamem)
3818 #define CONDBR(cond) \
3819 sp -= 2; \
3820 if (cond) \
3821 ip += (gint32)READ32(ip + 1); \
3822 else \
3823 ip += 3;
3825 #define BRELOP(datamem, op) \
3826 CONDBR(sp[0].data.datamem op sp[1].data.datamem)
3828 MINT_IN_CASE(MINT_BEQ_I4_S)
3829 BRELOP_S(i, ==)
3830 MINT_IN_BREAK;
3831 MINT_IN_CASE(MINT_BEQ_I8_S)
3832 BRELOP_S(l, ==)
3833 MINT_IN_BREAK;
3834 MINT_IN_CASE(MINT_BEQ_R4_S)
3835 CONDBR_S(!isunordered (sp [0].data.f_r4, sp [1].data.f_r4) && sp[0].data.f_r4 == sp[1].data.f_r4)
3836 MINT_IN_BREAK;
3837 MINT_IN_CASE(MINT_BEQ_R8_S)
3838 CONDBR_S(!mono_isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f == sp[1].data.f)
3839 MINT_IN_BREAK;
3840 MINT_IN_CASE(MINT_BEQ_I4)
3841 BRELOP(i, ==)
3842 MINT_IN_BREAK;
3843 MINT_IN_CASE(MINT_BEQ_I8)
3844 BRELOP(l, ==)
3845 MINT_IN_BREAK;
3846 MINT_IN_CASE(MINT_BEQ_R4)
3847 CONDBR(!isunordered (sp [0].data.f_r4, sp [1].data.f_r4) && sp[0].data.f_r4 == sp[1].data.f_r4)
3848 MINT_IN_BREAK;
3849 MINT_IN_CASE(MINT_BEQ_R8)
3850 CONDBR(!mono_isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f == sp[1].data.f)
3851 MINT_IN_BREAK;
3852 MINT_IN_CASE(MINT_BGE_I4_S)
3853 BRELOP_S(i, >=)
3854 MINT_IN_BREAK;
3855 MINT_IN_CASE(MINT_BGE_I8_S)
3856 BRELOP_S(l, >=)
3857 MINT_IN_BREAK;
3858 MINT_IN_CASE(MINT_BGE_R4_S)
3859 CONDBR_S(!isunordered (sp [0].data.f_r4, sp [1].data.f_r4) && sp[0].data.f_r4 >= sp[1].data.f_r4)
3860 MINT_IN_BREAK;
3861 MINT_IN_CASE(MINT_BGE_R8_S)
3862 CONDBR_S(!mono_isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f >= sp[1].data.f)
3863 MINT_IN_BREAK;
3864 MINT_IN_CASE(MINT_BGE_I4)
3865 BRELOP(i, >=)
3866 MINT_IN_BREAK;
3867 MINT_IN_CASE(MINT_BGE_I8)
3868 BRELOP(l, >=)
3869 MINT_IN_BREAK;
3870 MINT_IN_CASE(MINT_BGE_R4)
3871 CONDBR(!isunordered (sp [0].data.f_r4, sp [1].data.f_r4) && sp[0].data.f_r4 >= sp[1].data.f_r4)
3872 MINT_IN_BREAK;
3873 MINT_IN_CASE(MINT_BGE_R8)
3874 CONDBR(!mono_isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f >= sp[1].data.f)
3875 MINT_IN_BREAK;
3876 MINT_IN_CASE(MINT_BGT_I4_S)
3877 BRELOP_S(i, >)
3878 MINT_IN_BREAK;
3879 MINT_IN_CASE(MINT_BGT_I8_S)
3880 BRELOP_S(l, >)
3881 MINT_IN_BREAK;
3882 MINT_IN_CASE(MINT_BGT_R4_S)
3883 CONDBR_S(!isunordered (sp [0].data.f_r4, sp [1].data.f_r4) && sp[0].data.f_r4 > sp[1].data.f_r4)
3884 MINT_IN_BREAK;
3885 MINT_IN_CASE(MINT_BGT_R8_S)
3886 CONDBR_S(!mono_isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f > sp[1].data.f)
3887 MINT_IN_BREAK;
3888 MINT_IN_CASE(MINT_BGT_I4)
3889 BRELOP(i, >)
3890 MINT_IN_BREAK;
3891 MINT_IN_CASE(MINT_BGT_I8)
3892 BRELOP(l, >)
3893 MINT_IN_BREAK;
3894 MINT_IN_CASE(MINT_BGT_R4)
3895 CONDBR(!isunordered (sp [0].data.f_r4, sp [1].data.f_r4) && sp[0].data.f_r4 > sp[1].data.f_r4)
3896 MINT_IN_BREAK;
3897 MINT_IN_CASE(MINT_BGT_R8)
3898 CONDBR(!mono_isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f > sp[1].data.f)
3899 MINT_IN_BREAK;
3900 MINT_IN_CASE(MINT_BLT_I4_S)
3901 BRELOP_S(i, <)
3902 MINT_IN_BREAK;
3903 MINT_IN_CASE(MINT_BLT_I8_S)
3904 BRELOP_S(l, <)
3905 MINT_IN_BREAK;
3906 MINT_IN_CASE(MINT_BLT_R4_S)
3907 CONDBR_S(!isunordered (sp [0].data.f_r4, sp [1].data.f_r4) && sp[0].data.f_r4 < sp[1].data.f_r4)
3908 MINT_IN_BREAK;
3909 MINT_IN_CASE(MINT_BLT_R8_S)
3910 CONDBR_S(!mono_isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f < sp[1].data.f)
3911 MINT_IN_BREAK;
3912 MINT_IN_CASE(MINT_BLT_I4)
3913 BRELOP(i, <)
3914 MINT_IN_BREAK;
3915 MINT_IN_CASE(MINT_BLT_I8)
3916 BRELOP(l, <)
3917 MINT_IN_BREAK;
3918 MINT_IN_CASE(MINT_BLT_R4)
3919 CONDBR(!isunordered (sp [0].data.f_r4, sp [1].data.f_r4) && sp[0].data.f_r4 < sp[1].data.f_r4)
3920 MINT_IN_BREAK;
3921 MINT_IN_CASE(MINT_BLT_R8)
3922 CONDBR(!mono_isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f < sp[1].data.f)
3923 MINT_IN_BREAK;
3924 MINT_IN_CASE(MINT_BLE_I4_S)
3925 BRELOP_S(i, <=)
3926 MINT_IN_BREAK;
3927 MINT_IN_CASE(MINT_BLE_I8_S)
3928 BRELOP_S(l, <=)
3929 MINT_IN_BREAK;
3930 MINT_IN_CASE(MINT_BLE_R4_S)
3931 CONDBR_S(!isunordered (sp [0].data.f_r4, sp [1].data.f_r4) && sp[0].data.f_r4 <= sp[1].data.f_r4)
3932 MINT_IN_BREAK;
3933 MINT_IN_CASE(MINT_BLE_R8_S)
3934 CONDBR_S(!mono_isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f <= sp[1].data.f)
3935 MINT_IN_BREAK;
3936 MINT_IN_CASE(MINT_BLE_I4)
3937 BRELOP(i, <=)
3938 MINT_IN_BREAK;
3939 MINT_IN_CASE(MINT_BLE_I8)
3940 BRELOP(l, <=)
3941 MINT_IN_BREAK;
3942 MINT_IN_CASE(MINT_BLE_R4)
3943 CONDBR(!isunordered (sp [0].data.f_r4, sp [1].data.f_r4) && sp[0].data.f_r4 <= sp[1].data.f_r4)
3944 MINT_IN_BREAK;
3945 MINT_IN_CASE(MINT_BLE_R8)
3946 CONDBR(!mono_isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f <= sp[1].data.f)
3947 MINT_IN_BREAK;
3948 MINT_IN_CASE(MINT_BNE_UN_I4_S)
3949 BRELOP_S(i, !=)
3950 MINT_IN_BREAK;
3951 MINT_IN_CASE(MINT_BNE_UN_I8_S)
3952 BRELOP_S(l, !=)
3953 MINT_IN_BREAK;
3954 MINT_IN_CASE(MINT_BNE_UN_R4_S)
3955 CONDBR_S(isunordered (sp [0].data.f_r4, sp [1].data.f_r4) || sp[0].data.f_r4 != sp[1].data.f_r4)
3956 MINT_IN_BREAK;
3957 MINT_IN_CASE(MINT_BNE_UN_R8_S)
3958 CONDBR_S(mono_isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f != sp[1].data.f)
3959 MINT_IN_BREAK;
3960 MINT_IN_CASE(MINT_BNE_UN_I4)
3961 BRELOP(i, !=)
3962 MINT_IN_BREAK;
3963 MINT_IN_CASE(MINT_BNE_UN_I8)
3964 BRELOP(l, !=)
3965 MINT_IN_BREAK;
3966 MINT_IN_CASE(MINT_BNE_UN_R4)
3967 CONDBR(isunordered (sp [0].data.f_r4, sp [1].data.f_r4) || sp[0].data.f_r4 != sp[1].data.f_r4)
3968 MINT_IN_BREAK;
3969 MINT_IN_CASE(MINT_BNE_UN_R8)
3970 CONDBR(mono_isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f != sp[1].data.f)
3971 MINT_IN_BREAK;
3973 #define BRELOP_S_CAST(datamem, op, type) \
3974 sp -= 2; \
3975 if ((type) sp[0].data.datamem op (type) sp[1].data.datamem) \
3976 ip += * (gint16 *)(ip + 1); \
3977 else \
3978 ip += 2;
3980 #define BRELOP_CAST(datamem, op, type) \
3981 sp -= 2; \
3982 if ((type) sp[0].data.datamem op (type) sp[1].data.datamem) \
3983 ip += (gint32)READ32(ip + 1); \
3984 else \
3985 ip += 3;
3987 MINT_IN_CASE(MINT_BGE_UN_I4_S)
3988 BRELOP_S_CAST(i, >=, guint32);
3989 MINT_IN_BREAK;
3990 MINT_IN_CASE(MINT_BGE_UN_I8_S)
3991 BRELOP_S_CAST(l, >=, guint64);
3992 MINT_IN_BREAK;
3993 MINT_IN_CASE(MINT_BGE_UN_R4_S)
3994 CONDBR_S(isunordered (sp [0].data.f_r4, sp [1].data.f_r4) || sp[0].data.f_r4 >= sp[1].data.f_r4)
3995 MINT_IN_BREAK;
3996 MINT_IN_CASE(MINT_BGE_UN_R8_S)
3997 CONDBR_S(mono_isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f >= sp[1].data.f)
3998 MINT_IN_BREAK;
3999 MINT_IN_CASE(MINT_BGE_UN_I4)
4000 BRELOP_CAST(i, >=, guint32);
4001 MINT_IN_BREAK;
4002 MINT_IN_CASE(MINT_BGE_UN_I8)
4003 BRELOP_CAST(l, >=, guint64);
4004 MINT_IN_BREAK;
4005 MINT_IN_CASE(MINT_BGE_UN_R4)
4006 CONDBR(isunordered (sp [0].data.f_r4, sp [1].data.f_r4) || sp[0].data.f_r4 >= sp[1].data.f_r4)
4007 MINT_IN_BREAK;
4008 MINT_IN_CASE(MINT_BGE_UN_R8)
4009 CONDBR(mono_isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f >= sp[1].data.f)
4010 MINT_IN_BREAK;
4011 MINT_IN_CASE(MINT_BGT_UN_I4_S)
4012 BRELOP_S_CAST(i, >, guint32);
4013 MINT_IN_BREAK;
4014 MINT_IN_CASE(MINT_BGT_UN_I8_S)
4015 BRELOP_S_CAST(l, >, guint64);
4016 MINT_IN_BREAK;
4017 MINT_IN_CASE(MINT_BGT_UN_R4_S)
4018 CONDBR_S(isunordered (sp [0].data.f_r4, sp [1].data.f_r4) || sp[0].data.f_r4 > sp[1].data.f_r4)
4019 MINT_IN_BREAK;
4020 MINT_IN_CASE(MINT_BGT_UN_R8_S)
4021 CONDBR_S(mono_isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f > sp[1].data.f)
4022 MINT_IN_BREAK;
4023 MINT_IN_CASE(MINT_BGT_UN_I4)
4024 BRELOP_CAST(i, >, guint32);
4025 MINT_IN_BREAK;
4026 MINT_IN_CASE(MINT_BGT_UN_I8)
4027 BRELOP_CAST(l, >, guint64);
4028 MINT_IN_BREAK;
4029 MINT_IN_CASE(MINT_BGT_UN_R4)
4030 CONDBR(isunordered (sp [0].data.f_r4, sp [1].data.f_r4) || sp[0].data.f_r4 > sp[1].data.f_r4)
4031 MINT_IN_BREAK;
4032 MINT_IN_CASE(MINT_BGT_UN_R8)
4033 CONDBR(mono_isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f > sp[1].data.f)
4034 MINT_IN_BREAK;
4035 MINT_IN_CASE(MINT_BLE_UN_I4_S)
4036 BRELOP_S_CAST(i, <=, guint32);
4037 MINT_IN_BREAK;
4038 MINT_IN_CASE(MINT_BLE_UN_I8_S)
4039 BRELOP_S_CAST(l, <=, guint64);
4040 MINT_IN_BREAK;
4041 MINT_IN_CASE(MINT_BLE_UN_R4_S)
4042 CONDBR_S(isunordered (sp [0].data.f_r4, sp [1].data.f_r4) || sp[0].data.f_r4 <= sp[1].data.f_r4)
4043 MINT_IN_BREAK;
4044 MINT_IN_CASE(MINT_BLE_UN_R8_S)
4045 CONDBR_S(mono_isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f <= sp[1].data.f)
4046 MINT_IN_BREAK;
4047 MINT_IN_CASE(MINT_BLE_UN_I4)
4048 BRELOP_CAST(i, <=, guint32);
4049 MINT_IN_BREAK;
4050 MINT_IN_CASE(MINT_BLE_UN_I8)
4051 BRELOP_CAST(l, <=, guint64);
4052 MINT_IN_BREAK;
4053 MINT_IN_CASE(MINT_BLE_UN_R4)
4054 CONDBR(isunordered (sp [0].data.f_r4, sp [1].data.f_r4) || sp[0].data.f_r4 <= sp[1].data.f_r4)
4055 MINT_IN_BREAK;
4056 MINT_IN_CASE(MINT_BLE_UN_R8)
4057 CONDBR(mono_isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f <= sp[1].data.f)
4058 MINT_IN_BREAK;
4059 MINT_IN_CASE(MINT_BLT_UN_I4_S)
4060 BRELOP_S_CAST(i, <, guint32);
4061 MINT_IN_BREAK;
4062 MINT_IN_CASE(MINT_BLT_UN_I8_S)
4063 BRELOP_S_CAST(l, <, guint64);
4064 MINT_IN_BREAK;
4065 MINT_IN_CASE(MINT_BLT_UN_R4_S)
4066 CONDBR_S(isunordered (sp [0].data.f_r4, sp [1].data.f_r4) || sp[0].data.f_r4 < sp[1].data.f_r4)
4067 MINT_IN_BREAK;
4068 MINT_IN_CASE(MINT_BLT_UN_R8_S)
4069 CONDBR_S(mono_isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f < sp[1].data.f)
4070 MINT_IN_BREAK;
4071 MINT_IN_CASE(MINT_BLT_UN_I4)
4072 BRELOP_CAST(i, <, guint32);
4073 MINT_IN_BREAK;
4074 MINT_IN_CASE(MINT_BLT_UN_I8)
4075 BRELOP_CAST(l, <, guint64);
4076 MINT_IN_BREAK;
4077 MINT_IN_CASE(MINT_BLT_UN_R4)
4078 CONDBR(isunordered (sp [0].data.f_r4, sp [1].data.f_r4) || sp[0].data.f_r4 < sp[1].data.f_r4)
4079 MINT_IN_BREAK;
4080 MINT_IN_CASE(MINT_BLT_UN_R8)
4081 CONDBR(mono_isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f < sp[1].data.f)
4082 MINT_IN_BREAK;
4083 MINT_IN_CASE(MINT_SWITCH) {
4084 guint32 n;
4085 const unsigned short *st;
4086 ++ip;
4087 n = READ32 (ip);
4088 ip += 2;
4089 st = ip + 2 * n;
4090 --sp;
4091 if ((guint32)sp->data.i < n) {
4092 gint offset;
4093 ip += 2 * (guint32)sp->data.i;
4094 offset = READ32 (ip);
4095 ip = ip + offset;
4096 } else {
4097 ip = st;
4099 MINT_IN_BREAK;
4101 MINT_IN_CASE(MINT_LDIND_I1_CHECK)
4102 NULL_CHECK (sp [-1].data.p);
4103 ++ip;
4104 sp[-1].data.i = *(gint8*)sp[-1].data.p;
4105 MINT_IN_BREAK;
4106 MINT_IN_CASE(MINT_LDIND_U1_CHECK)
4107 NULL_CHECK (sp [-1].data.p);
4108 ++ip;
4109 sp[-1].data.i = *(guint8*)sp[-1].data.p;
4110 MINT_IN_BREAK;
4111 MINT_IN_CASE(MINT_LDIND_I2_CHECK)
4112 NULL_CHECK (sp [-1].data.p);
4113 ++ip;
4114 sp[-1].data.i = *(gint16*)sp[-1].data.p;
4115 MINT_IN_BREAK;
4116 MINT_IN_CASE(MINT_LDIND_U2_CHECK)
4117 NULL_CHECK (sp [-1].data.p);
4118 ++ip;
4119 sp[-1].data.i = *(guint16*)sp[-1].data.p;
4120 MINT_IN_BREAK;
4121 MINT_IN_CASE(MINT_LDIND_I4_CHECK) /* Fall through */
4122 MINT_IN_CASE(MINT_LDIND_U4_CHECK)
4123 NULL_CHECK (sp [-1].data.p);
4124 ++ip;
4125 sp[-1].data.i = *(gint32*)sp[-1].data.p;
4126 MINT_IN_BREAK;
4127 MINT_IN_CASE(MINT_LDIND_I8_CHECK)
4128 NULL_CHECK (sp [-1].data.p);
4129 ++ip;
4130 #ifdef NO_UNALIGNED_ACCESS
4131 if ((gsize)sp [-1].data.p % SIZEOF_VOID_P)
4132 memcpy (&sp [-1].data.l, sp [-1].data.p, sizeof (gint64));
4133 else
4134 #endif
4135 sp[-1].data.l = *(gint64*)sp[-1].data.p;
4136 MINT_IN_BREAK;
4137 MINT_IN_CASE(MINT_LDIND_I) {
4138 guint16 offset = * (guint16 *)(ip + 1);
4139 sp[-1 - offset].data.p = *(gpointer*)sp[-1 - offset].data.p;
4140 ip += 2;
4141 MINT_IN_BREAK;
4143 MINT_IN_CASE(MINT_LDIND_I8) {
4144 guint16 offset = * (guint16 *)(ip + 1);
4145 #ifdef NO_UNALIGNED_ACCESS
4146 if ((gsize)sp [-1 - offset].data.p % SIZEOF_VOID_P)
4147 memcpy (&sp [-1 - offset].data.l, sp [-1 - offset].data.p, sizeof (gint64));
4148 else
4149 #endif
4150 sp[-1 - offset].data.l = *(gint64*)sp[-1 - offset].data.p;
4151 ip += 2;
4152 MINT_IN_BREAK;
4154 MINT_IN_CASE(MINT_LDIND_R4_CHECK)
4155 NULL_CHECK (sp [-1].data.p);
4156 ++ip;
4157 sp[-1].data.f_r4 = *(gfloat*)sp[-1].data.p;
4158 MINT_IN_BREAK;
4159 MINT_IN_CASE(MINT_LDIND_R8_CHECK)
4160 NULL_CHECK (sp [-1].data.p);
4161 ++ip;
4162 #ifdef NO_UNALIGNED_ACCESS
4163 if ((gsize)sp [-1].data.p % SIZEOF_VOID_P)
4164 memcpy (&sp [-1].data.f, sp [-1].data.p, sizeof (gdouble));
4165 else
4166 #endif
4167 sp[-1].data.f = *(gdouble*)sp[-1].data.p;
4168 MINT_IN_BREAK;
4169 MINT_IN_CASE(MINT_LDIND_REF)
4170 ++ip;
4171 sp[-1].data.p = *(gpointer*)sp[-1].data.p;
4172 MINT_IN_BREAK;
4173 MINT_IN_CASE(MINT_LDIND_REF_CHECK) {
4174 NULL_CHECK (sp [-1].data.p);
4175 ++ip;
4176 sp [-1].data.p = *(gpointer*)sp [-1].data.p;
4177 MINT_IN_BREAK;
4179 MINT_IN_CASE(MINT_STIND_REF)
4180 ++ip;
4181 sp -= 2;
4182 mono_gc_wbarrier_generic_store_internal (sp->data.p, sp [1].data.o);
4183 MINT_IN_BREAK;
4184 MINT_IN_CASE(MINT_STIND_I1)
4185 ++ip;
4186 sp -= 2;
4187 * (gint8 *) sp->data.p = (gint8)sp[1].data.i;
4188 MINT_IN_BREAK;
4189 MINT_IN_CASE(MINT_STIND_I2)
4190 ++ip;
4191 sp -= 2;
4192 * (gint16 *) sp->data.p = (gint16)sp[1].data.i;
4193 MINT_IN_BREAK;
4194 MINT_IN_CASE(MINT_STIND_I4)
4195 ++ip;
4196 sp -= 2;
4197 * (gint32 *) sp->data.p = sp[1].data.i;
4198 MINT_IN_BREAK;
4199 MINT_IN_CASE(MINT_STIND_I)
4200 ++ip;
4201 sp -= 2;
4202 * (mono_i *) sp->data.p = (mono_i)sp[1].data.p;
4203 MINT_IN_BREAK;
4204 MINT_IN_CASE(MINT_STIND_I8)
4205 ++ip;
4206 sp -= 2;
4207 #ifdef NO_UNALIGNED_ACCESS
4208 if ((gsize)sp->data.p % SIZEOF_VOID_P)
4209 memcpy (sp->data.p, &sp [1].data.l, sizeof (gint64));
4210 else
4211 #endif
4212 * (gint64 *) sp->data.p = sp[1].data.l;
4213 MINT_IN_BREAK;
4214 MINT_IN_CASE(MINT_STIND_R4)
4215 ++ip;
4216 sp -= 2;
4217 * (float *) sp->data.p = sp[1].data.f_r4;
4218 MINT_IN_BREAK;
4219 MINT_IN_CASE(MINT_STIND_R8)
4220 ++ip;
4221 sp -= 2;
4222 #ifdef NO_UNALIGNED_ACCESS
4223 if ((gsize)sp->data.p % SIZEOF_VOID_P)
4224 memcpy (sp->data.p, &sp [1].data.f, sizeof (double));
4225 else
4226 #endif
4227 * (double *) sp->data.p = sp[1].data.f;
4228 MINT_IN_BREAK;
4229 MINT_IN_CASE(MINT_MONO_ATOMIC_STORE_I4)
4230 ++ip;
4231 sp -= 2;
4232 mono_atomic_store_i32 ((gint32 *) sp->data.p, sp [1].data.i);
4233 MINT_IN_BREAK;
4234 #define BINOP(datamem, op) \
4235 --sp; \
4236 sp [-1].data.datamem = sp [-1].data.datamem op sp [0].data.datamem; \
4237 ++ip;
4238 MINT_IN_CASE(MINT_ADD_I4)
4239 BINOP(i, +);
4240 MINT_IN_BREAK;
4241 MINT_IN_CASE(MINT_ADD_I8)
4242 BINOP(l, +);
4243 MINT_IN_BREAK;
4244 MINT_IN_CASE(MINT_ADD_R4)
4245 BINOP(f_r4, +);
4246 MINT_IN_BREAK;
4247 MINT_IN_CASE(MINT_ADD_R8)
4248 BINOP(f, +);
4249 MINT_IN_BREAK;
4250 MINT_IN_CASE(MINT_ADD1_I4)
4251 ++sp [-1].data.i;
4252 ++ip;
4253 MINT_IN_BREAK;
4254 MINT_IN_CASE(MINT_ADD1_I8)
4255 ++sp [-1].data.l;
4256 ++ip;
4257 MINT_IN_BREAK;
4258 MINT_IN_CASE(MINT_SUB_I4)
4259 BINOP(i, -);
4260 MINT_IN_BREAK;
4261 MINT_IN_CASE(MINT_SUB_I8)
4262 BINOP(l, -);
4263 MINT_IN_BREAK;
4264 MINT_IN_CASE(MINT_SUB_R4)
4265 BINOP(f_r4, -);
4266 MINT_IN_BREAK;
4267 MINT_IN_CASE(MINT_SUB_R8)
4268 BINOP(f, -);
4269 MINT_IN_BREAK;
4270 MINT_IN_CASE(MINT_SUB1_I4)
4271 --sp [-1].data.i;
4272 ++ip;
4273 MINT_IN_BREAK;
4274 MINT_IN_CASE(MINT_SUB1_I8)
4275 --sp [-1].data.l;
4276 ++ip;
4277 MINT_IN_BREAK;
4278 MINT_IN_CASE(MINT_MUL_I4)
4279 BINOP(i, *);
4280 MINT_IN_BREAK;
4281 MINT_IN_CASE(MINT_MUL_I8)
4282 BINOP(l, *);
4283 MINT_IN_BREAK;
4284 MINT_IN_CASE(MINT_MUL_R4)
4285 BINOP(f_r4, *);
4286 MINT_IN_BREAK;
4287 MINT_IN_CASE(MINT_MUL_R8)
4288 BINOP(f, *);
4289 MINT_IN_BREAK;
4290 MINT_IN_CASE(MINT_DIV_I4)
4291 if (sp [-1].data.i == 0)
4292 THROW_EX_DIV_ZERO (ip);
4293 if (sp [-1].data.i == (-1) && sp [-2].data.i == G_MININT32)
4294 THROW_EX_OVF (ip);
4295 BINOP(i, /);
4296 MINT_IN_BREAK;
4297 MINT_IN_CASE(MINT_DIV_I8)
4298 if (sp [-1].data.l == 0)
4299 THROW_EX_DIV_ZERO (ip);
4300 if (sp [-1].data.l == (-1) && sp [-2].data.l == G_MININT64)
4301 THROW_EX_OVF (ip);
4302 BINOP(l, /);
4303 MINT_IN_BREAK;
4304 MINT_IN_CASE(MINT_DIV_R4)
4305 BINOP(f_r4, /);
4306 MINT_IN_BREAK;
4307 MINT_IN_CASE(MINT_DIV_R8)
4308 BINOP(f, /);
4309 MINT_IN_BREAK;
4311 #define BINOP_CAST(datamem, op, type) \
4312 --sp; \
4313 sp [-1].data.datamem = (type)sp [-1].data.datamem op (type)sp [0].data.datamem; \
4314 ++ip;
4315 MINT_IN_CASE(MINT_DIV_UN_I4)
4316 if (sp [-1].data.i == 0)
4317 THROW_EX_DIV_ZERO (ip);
4318 BINOP_CAST(i, /, guint32);
4319 MINT_IN_BREAK;
4320 MINT_IN_CASE(MINT_DIV_UN_I8)
4321 if (sp [-1].data.l == 0)
4322 THROW_EX_DIV_ZERO (ip);
4323 BINOP_CAST(l, /, guint64);
4324 MINT_IN_BREAK;
4325 MINT_IN_CASE(MINT_REM_I4)
4326 if (sp [-1].data.i == 0)
4327 THROW_EX_DIV_ZERO (ip);
4328 if (sp [-1].data.i == (-1) && sp [-2].data.i == G_MININT32)
4329 THROW_EX_OVF (ip);
4330 BINOP(i, %);
4331 MINT_IN_BREAK;
4332 MINT_IN_CASE(MINT_REM_I8)
4333 if (sp [-1].data.l == 0)
4334 THROW_EX_DIV_ZERO (ip);
4335 if (sp [-1].data.l == (-1) && sp [-2].data.l == G_MININT64)
4336 THROW_EX_OVF (ip);
4337 BINOP(l, %);
4338 MINT_IN_BREAK;
4339 MINT_IN_CASE(MINT_REM_R4)
4340 /* FIXME: what do we actually do here? */
4341 --sp;
4342 sp [-1].data.f_r4 = fmodf (sp [-1].data.f_r4, sp [0].data.f_r4);
4343 ++ip;
4344 MINT_IN_BREAK;
4345 MINT_IN_CASE(MINT_REM_R8)
4346 /* FIXME: what do we actually do here? */
4347 --sp;
4348 sp [-1].data.f = fmod (sp [-1].data.f, sp [0].data.f);
4349 ++ip;
4350 MINT_IN_BREAK;
4351 MINT_IN_CASE(MINT_REM_UN_I4)
4352 if (sp [-1].data.i == 0)
4353 THROW_EX_DIV_ZERO (ip);
4354 BINOP_CAST(i, %, guint32);
4355 MINT_IN_BREAK;
4356 MINT_IN_CASE(MINT_REM_UN_I8)
4357 if (sp [-1].data.l == 0)
4358 THROW_EX_DIV_ZERO (ip);
4359 BINOP_CAST(l, %, guint64);
4360 MINT_IN_BREAK;
4361 MINT_IN_CASE(MINT_AND_I4)
4362 BINOP(i, &);
4363 MINT_IN_BREAK;
4364 MINT_IN_CASE(MINT_AND_I8)
4365 BINOP(l, &);
4366 MINT_IN_BREAK;
4367 MINT_IN_CASE(MINT_OR_I4)
4368 BINOP(i, |);
4369 MINT_IN_BREAK;
4370 MINT_IN_CASE(MINT_OR_I8)
4371 BINOP(l, |);
4372 MINT_IN_BREAK;
4373 MINT_IN_CASE(MINT_XOR_I4)
4374 BINOP(i, ^);
4375 MINT_IN_BREAK;
4376 MINT_IN_CASE(MINT_XOR_I8)
4377 BINOP(l, ^);
4378 MINT_IN_BREAK;
4380 #define SHIFTOP(datamem, op) \
4381 --sp; \
4382 sp [-1].data.datamem = sp [-1].data.datamem op sp [0].data.i; \
4383 ++ip;
4385 MINT_IN_CASE(MINT_SHL_I4)
4386 SHIFTOP(i, <<);
4387 MINT_IN_BREAK;
4388 MINT_IN_CASE(MINT_SHL_I8)
4389 SHIFTOP(l, <<);
4390 MINT_IN_BREAK;
4391 MINT_IN_CASE(MINT_SHR_I4)
4392 SHIFTOP(i, >>);
4393 MINT_IN_BREAK;
4394 MINT_IN_CASE(MINT_SHR_I8)
4395 SHIFTOP(l, >>);
4396 MINT_IN_BREAK;
4397 MINT_IN_CASE(MINT_SHR_UN_I4)
4398 --sp;
4399 sp [-1].data.i = (guint32)sp [-1].data.i >> sp [0].data.i;
4400 ++ip;
4401 MINT_IN_BREAK;
4402 MINT_IN_CASE(MINT_SHR_UN_I8)
4403 --sp;
4404 sp [-1].data.l = (guint64)sp [-1].data.l >> sp [0].data.i;
4405 ++ip;
4406 MINT_IN_BREAK;
4407 MINT_IN_CASE(MINT_NEG_I4)
4408 sp [-1].data.i = - sp [-1].data.i;
4409 ++ip;
4410 MINT_IN_BREAK;
4411 MINT_IN_CASE(MINT_NEG_I8)
4412 sp [-1].data.l = - sp [-1].data.l;
4413 ++ip;
4414 MINT_IN_BREAK;
4415 MINT_IN_CASE(MINT_NEG_R4)
4416 sp [-1].data.f_r4 = - sp [-1].data.f_r4;
4417 ++ip;
4418 MINT_IN_BREAK;
4419 MINT_IN_CASE(MINT_NEG_R8)
4420 sp [-1].data.f = - sp [-1].data.f;
4421 ++ip;
4422 MINT_IN_BREAK;
4423 MINT_IN_CASE(MINT_NOT_I4)
4424 sp [-1].data.i = ~ sp [-1].data.i;
4425 ++ip;
4426 MINT_IN_BREAK;
4427 MINT_IN_CASE(MINT_NOT_I8)
4428 sp [-1].data.l = ~ sp [-1].data.l;
4429 ++ip;
4430 MINT_IN_BREAK;
4431 MINT_IN_CASE(MINT_CONV_I1_I4)
4432 sp [-1].data.i = (gint8)sp [-1].data.i;
4433 ++ip;
4434 MINT_IN_BREAK;
4435 MINT_IN_CASE(MINT_CONV_I1_I8)
4436 sp [-1].data.i = (gint8)sp [-1].data.l;
4437 ++ip;
4438 MINT_IN_BREAK;
4439 MINT_IN_CASE(MINT_CONV_I1_R4)
4440 sp [-1].data.i = (gint8) (gint32) sp [-1].data.f_r4;
4441 ++ip;
4442 MINT_IN_BREAK;
4443 MINT_IN_CASE(MINT_CONV_I1_R8)
4444 /* without gint32 cast, C compiler is allowed to use undefined
4445 * behaviour if data.f is bigger than >255. See conv.fpint section
4446 * in C standard:
4447 * > The conversion truncates; that is, the fractional part
4448 * > is discarded. The behavior is undefined if the truncated
4449 * > value cannot be represented in the destination type.
4450 * */
4451 sp [-1].data.i = (gint8) (gint32) sp [-1].data.f;
4452 ++ip;
4453 MINT_IN_BREAK;
4454 MINT_IN_CASE(MINT_CONV_U1_I4)
4455 sp [-1].data.i = (guint8)sp [-1].data.i;
4456 ++ip;
4457 MINT_IN_BREAK;
4458 MINT_IN_CASE(MINT_CONV_U1_I8)
4459 sp [-1].data.i = (guint8)sp [-1].data.l;
4460 ++ip;
4461 MINT_IN_BREAK;
4462 MINT_IN_CASE(MINT_CONV_U1_R4)
4463 sp [-1].data.i = (guint8) (guint32) sp [-1].data.f_r4;
4464 ++ip;
4465 MINT_IN_BREAK;
4466 MINT_IN_CASE(MINT_CONV_U1_R8)
4467 sp [-1].data.i = (guint8) (guint32) sp [-1].data.f;
4468 ++ip;
4469 MINT_IN_BREAK;
4470 MINT_IN_CASE(MINT_CONV_I2_I4)
4471 sp [-1].data.i = (gint16)sp [-1].data.i;
4472 ++ip;
4473 MINT_IN_BREAK;
4474 MINT_IN_CASE(MINT_CONV_I2_I8)
4475 sp [-1].data.i = (gint16)sp [-1].data.l;
4476 ++ip;
4477 MINT_IN_BREAK;
4478 MINT_IN_CASE(MINT_CONV_I2_R4)
4479 sp [-1].data.i = (gint16) (gint32) sp [-1].data.f_r4;
4480 ++ip;
4481 MINT_IN_BREAK;
4482 MINT_IN_CASE(MINT_CONV_I2_R8)
4483 sp [-1].data.i = (gint16) (gint32) sp [-1].data.f;
4484 ++ip;
4485 MINT_IN_BREAK;
4486 MINT_IN_CASE(MINT_CONV_U2_I4)
4487 sp [-1].data.i = (guint16)sp [-1].data.i;
4488 ++ip;
4489 MINT_IN_BREAK;
4490 MINT_IN_CASE(MINT_CONV_U2_I8)
4491 sp [-1].data.i = (guint16)sp [-1].data.l;
4492 ++ip;
4493 MINT_IN_BREAK;
4494 MINT_IN_CASE(MINT_CONV_U2_R4)
4495 sp [-1].data.i = (guint16) (guint32) sp [-1].data.f_r4;
4496 ++ip;
4497 MINT_IN_BREAK;
4498 MINT_IN_CASE(MINT_CONV_U2_R8)
4499 sp [-1].data.i = (guint16) (guint32) sp [-1].data.f;
4500 ++ip;
4501 MINT_IN_BREAK;
4502 MINT_IN_CASE(MINT_CONV_I4_R4)
4503 sp [-1].data.i = (gint32) sp [-1].data.f_r4;
4504 ++ip;
4505 MINT_IN_BREAK;
4506 MINT_IN_CASE(MINT_CONV_I4_R8)
4507 sp [-1].data.i = (gint32)sp [-1].data.f;
4508 ++ip;
4509 MINT_IN_BREAK;
4510 MINT_IN_CASE(MINT_CONV_U4_I8)
4511 MINT_IN_CASE(MINT_CONV_I4_I8)
4512 sp [-1].data.i = (gint32)sp [-1].data.l;
4513 ++ip;
4514 MINT_IN_BREAK;
4515 MINT_IN_CASE(MINT_CONV_I4_I8_SP)
4516 sp [-2].data.i = (gint32)sp [-2].data.l;
4517 ++ip;
4518 MINT_IN_BREAK;
4519 MINT_IN_CASE(MINT_CONV_U4_R4)
4520 #ifdef MONO_ARCH_EMULATE_FCONV_TO_U4
4521 sp [-1].data.i = mono_rconv_u4 (sp [-1].data.f_r4);
4522 #else
4523 sp [-1].data.i = (guint32) sp [-1].data.f_r4;
4524 #endif
4525 ++ip;
4526 MINT_IN_BREAK;
4527 MINT_IN_CASE(MINT_CONV_U4_R8)
4528 #ifdef MONO_ARCH_EMULATE_FCONV_TO_U4
4529 sp [-1].data.i = mono_fconv_u4_2 (sp [-1].data.f);
4530 #else
4531 sp [-1].data.i = (guint32) sp [-1].data.f;
4532 #endif
4533 ++ip;
4534 MINT_IN_BREAK;
4535 MINT_IN_CASE(MINT_CONV_I8_I4)
4536 sp [-1].data.l = sp [-1].data.i;
4537 ++ip;
4538 MINT_IN_BREAK;
4539 MINT_IN_CASE(MINT_CONV_I8_I4_SP)
4540 sp [-2].data.l = sp [-2].data.i;
4541 ++ip;
4542 MINT_IN_BREAK;
4543 MINT_IN_CASE(MINT_CONV_I8_U4)
4544 sp [-1].data.l = (guint32)sp [-1].data.i;
4545 ++ip;
4546 MINT_IN_BREAK;
4547 MINT_IN_CASE(MINT_CONV_I8_R4)
4548 sp [-1].data.l = (gint64) sp [-1].data.f_r4;
4549 ++ip;
4550 MINT_IN_BREAK;
4551 MINT_IN_CASE(MINT_CONV_I8_R8)
4552 sp [-1].data.l = (gint64)sp [-1].data.f;
4553 ++ip;
4554 MINT_IN_BREAK;
4555 MINT_IN_CASE(MINT_CONV_R4_I4)
4556 sp [-1].data.f_r4 = (float)sp [-1].data.i;
4557 ++ip;
4558 MINT_IN_BREAK;
4559 MINT_IN_CASE(MINT_CONV_R4_I8)
4560 sp [-1].data.f_r4 = (float)sp [-1].data.l;
4561 ++ip;
4562 MINT_IN_BREAK;
4563 MINT_IN_CASE(MINT_CONV_R4_R8)
4564 sp [-1].data.f_r4 = (float)sp [-1].data.f;
4565 ++ip;
4566 MINT_IN_BREAK;
4567 MINT_IN_CASE(MINT_CONV_R8_I4)
4568 sp [-1].data.f = (double)sp [-1].data.i;
4569 ++ip;
4570 MINT_IN_BREAK;
4571 MINT_IN_CASE(MINT_CONV_R8_I8)
4572 sp [-1].data.f = (double)sp [-1].data.l;
4573 ++ip;
4574 MINT_IN_BREAK;
4575 MINT_IN_CASE(MINT_CONV_R8_R4)
4576 sp [-1].data.f = (double) sp [-1].data.f_r4;
4577 ++ip;
4578 MINT_IN_BREAK;
4579 MINT_IN_CASE(MINT_CONV_R8_R4_SP)
4580 sp [-2].data.f = (double) sp [-2].data.f_r4;
4581 ++ip;
4582 MINT_IN_BREAK;
4583 MINT_IN_CASE(MINT_CONV_U8_I4)
4584 sp [-1].data.l = sp [-1].data.i & 0xffffffff;
4585 ++ip;
4586 MINT_IN_BREAK;
4587 MINT_IN_CASE(MINT_CONV_U8_R4)
4588 #ifdef MONO_ARCH_EMULATE_FCONV_TO_U8
4589 sp [-1].data.l = mono_rconv_u8 (sp [-1].data.f_r4);
4590 #else
4591 sp [-1].data.l = (guint64) sp [-1].data.f_r4;
4592 #endif
4593 ++ip;
4594 MINT_IN_BREAK;
4595 MINT_IN_CASE(MINT_CONV_U8_R8)
4596 #ifdef MONO_ARCH_EMULATE_FCONV_TO_U8
4597 sp [-1].data.l = mono_fconv_u8_2 (sp [-1].data.f);
4598 #else
4599 sp [-1].data.l = (guint64)sp [-1].data.f;
4600 #endif
4601 ++ip;
4602 MINT_IN_BREAK;
4603 MINT_IN_CASE(MINT_CPOBJ) {
4604 MonoClass* const c = (MonoClass*)imethod->data_items[* (guint16 *)(ip + 1)];
4605 g_assert (m_class_is_valuetype (c));
4606 /* if this assertion fails, we need to add a write barrier */
4607 g_assert (!MONO_TYPE_IS_REFERENCE (m_class_get_byval_arg (c)));
4608 stackval_from_data (m_class_get_byval_arg (c), (stackval*)sp [-2].data.p, sp [-1].data.p, FALSE);
4609 ip += 2;
4610 sp -= 2;
4611 MINT_IN_BREAK;
4613 MINT_IN_CASE(MINT_CPOBJ_VT) {
4614 MonoClass* const c = (MonoClass*)imethod->data_items[* (guint16 *)(ip + 1)];
4615 mono_value_copy_internal (sp [-2].data.vt, sp [-1].data.vt, c);
4616 ip += 2;
4617 sp -= 2;
4618 MINT_IN_BREAK;
4620 MINT_IN_CASE(MINT_LDOBJ_VT) {
4621 int size = READ32(ip + 1);
4622 ip += 3;
4623 memcpy (vt_sp, sp [-1].data.p, size);
4624 sp [-1].data.p = vt_sp;
4625 vt_sp += ALIGN_TO (size, MINT_VT_ALIGNMENT);
4626 MINT_IN_BREAK;
4628 MINT_IN_CASE(MINT_LDSTR)
4629 sp->data.p = imethod->data_items [* (guint16 *)(ip + 1)];
4630 ++sp;
4631 ip += 2;
4632 MINT_IN_BREAK;
4633 MINT_IN_CASE(MINT_LDSTR_TOKEN) {
4634 MonoString *s = NULL;
4635 guint32 strtoken = (guint32)(gsize)imethod->data_items [* (guint16 *)(ip + 1)];
4637 MonoMethod *method = imethod->method;
4638 if (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD) {
4639 s = (MonoString*)mono_method_get_wrapper_data (method, strtoken);
4640 } else if (method->wrapper_type != MONO_WRAPPER_NONE) {
4641 s = mono_string_new_wrapper_internal ((const char*)mono_method_get_wrapper_data (method, strtoken));
4642 } else {
4643 g_assert_not_reached ();
4645 sp->data.p = s;
4646 ++sp;
4647 ip += 2;
4648 MINT_IN_BREAK;
4650 MINT_IN_CASE(MINT_NEWOBJ_ARRAY) {
4651 MonoClass *newobj_class;
4652 guint32 token = * (guint16 *)(ip + 1);
4653 guint16 param_count = * (guint16 *)(ip + 2);
4655 newobj_class = (MonoClass*) imethod->data_items [token];
4657 sp -= param_count;
4658 sp->data.o = ves_array_create (imethod->domain, newobj_class, param_count, sp, error);
4659 if (!is_ok (error))
4660 THROW_EX (mono_error_convert_to_exception (error), ip);
4662 ++sp;
4663 ip += 3;
4664 MINT_IN_BREAK;
4666 MINT_IN_CASE(MINT_NEWOBJ_FAST) {
4668 MonoVTable *vtable = (MonoVTable*) imethod->data_items [*(guint16*)(ip + 3)];
4669 INIT_VTABLE (vtable);
4671 MonoObject* o = NULL; // See the comment about GC safety above.
4672 guint16 param_count;
4673 guint16 imethod_index = *(guint16*) (ip + 1);
4675 const gboolean is_inlined = imethod_index == 0xffff;
4677 param_count = *(guint16*)(ip + 2);
4679 if (param_count) {
4680 sp -= param_count;
4681 memmove (sp + 1 + is_inlined, sp, param_count * sizeof (stackval));
4684 frame_objref (frame) = mono_gc_alloc_obj (vtable, m_class_get_instance_size (vtable->klass));
4685 if (G_UNLIKELY (!frame_objref (frame))) {
4686 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", m_class_get_instance_size (vtable->klass));
4687 THROW_EX (mono_error_convert_to_exception (error), ip);
4690 sp [0].data.o = frame_objref (frame);
4691 if (is_inlined) {
4692 sp [1].data.o = frame_objref (frame);
4693 sp += param_count + 2;
4694 } else {
4695 InterpMethod *ctor_method = (InterpMethod*) imethod->data_items [imethod_index];
4696 frame->ip = ip;
4698 child_frame.imethod = ctor_method;
4699 child_frame.stack_args = sp;
4701 interp_exec_method (&child_frame, context, error);
4702 CHECK_RESUME_STATE (context);
4703 sp [0].data.o = frame_objref (frame);
4704 sp++;
4706 ip += 4;
4708 MINT_IN_BREAK;
4710 MINT_IN_CASE(MINT_NEWOBJ_VT_FAST)
4711 MINT_IN_CASE(MINT_NEWOBJ_VTST_FAST) {
4713 // This is split up to:
4714 // - conserve stack
4715 // - keep exception handling and resume mostly in the main function
4717 frame->ip = ip;
4718 child_frame.imethod = (InterpMethod*) imethod->data_items [*(guint16*)(ip + 1)];
4719 guint16 const param_count = *(guint16*)(ip + 2);
4721 if (param_count) {
4722 sp -= param_count;
4723 memmove (sp + 1, sp, param_count * sizeof (stackval));
4725 child_frame.stack_args = sp;
4726 gboolean const vtst = *ip == MINT_NEWOBJ_VTST_FAST;
4727 if (vtst) {
4728 memset (vt_sp, 0, *(guint16*)(ip + 3));
4729 sp->data.p = vt_sp;
4730 ip += 4;
4732 interp_exec_method (&child_frame, context, error);
4734 CHECK_RESUME_STATE (context);
4735 sp->data.p = vt_sp;
4737 } else {
4738 ip += 3;
4739 mono_interp_newobj_vt (&child_frame, context, error);
4740 CHECK_RESUME_STATE (context);
4742 ++sp;
4743 MINT_IN_BREAK;
4746 MINT_IN_CASE(MINT_NEWOBJ) {
4748 // This is split up to:
4749 // - conserve stack
4750 // - keep exception handling and resume mostly in the main function
4752 frame->ip = ip;
4754 guint32 const token = * (guint16 *)(ip + 1);
4755 ip += 2; // FIXME: Do this after throw?
4757 child_frame.ip = NULL;
4758 child_frame.ex = NULL;
4760 child_frame.imethod = (InterpMethod*)imethod->data_items [token];
4761 MonoMethodSignature* const csig = mono_method_signature_internal (child_frame.imethod->method);
4763 g_assert (csig->hasthis);
4764 if (csig->param_count) {
4765 sp -= csig->param_count;
4766 memmove (sp + 1, sp, csig->param_count * sizeof (stackval));
4769 child_frame.stack_args = sp;
4771 MonoException* const exc = mono_interp_newobj (&child_frame, context, error, vt_sp);
4772 if (exc)
4773 THROW_EX (exc, ip);
4774 CHECK_RESUME_STATE (context);
4775 ++sp;
4776 MINT_IN_BREAK;
4778 MINT_IN_CASE(MINT_NEWOBJ_MAGIC) {
4779 frame->ip = ip;
4780 ip += 2;
4782 MINT_IN_BREAK;
4784 MINT_IN_CASE(MINT_INTRINS_BYREFERENCE_CTOR) {
4785 MonoMethodSignature *csig;
4786 guint32 token;
4788 frame->ip = ip;
4789 token = * (guint16 *)(ip + 1);
4790 ip += 2;
4792 InterpMethod *cmethod = (InterpMethod*)imethod->data_items [token];
4793 csig = mono_method_signature_internal (cmethod->method);
4795 g_assert (csig->hasthis);
4796 sp -= csig->param_count;
4798 gpointer arg0 = sp [0].data.p;
4800 gpointer *byreference_this = (gpointer*)vt_sp;
4801 *byreference_this = arg0;
4803 /* Followed by a VTRESULT opcode which will push the result on the stack */
4804 ++sp;
4805 MINT_IN_BREAK;
4807 MINT_IN_CASE(MINT_INTRINS_BYREFERENCE_GET_VALUE) {
4808 gpointer *byreference_this = (gpointer*)sp [-1].data.p;
4809 sp [-1].data.p = *byreference_this;
4810 ++ip;
4811 MINT_IN_BREAK;
4813 MINT_IN_CASE(MINT_INTRINS_UNSAFE_ADD_BYTE_OFFSET) {
4814 sp -= 2;
4815 sp [0].data.p = (guint8*)sp [0].data.p + sp [1].data.nati;
4816 sp ++;
4817 ++ip;
4818 MINT_IN_BREAK;
4820 MINT_IN_CASE(MINT_INTRINS_UNSAFE_BYTE_OFFSET) {
4821 sp -= 2;
4822 sp [0].data.nati = (guint8*)sp [1].data.p - (guint8*)sp [0].data.p;
4823 sp ++;
4824 ++ip;
4825 MINT_IN_BREAK;
4827 MINT_IN_CASE(MINT_INTRINS_RUNTIMEHELPERS_OBJECT_HAS_COMPONENT_SIZE) {
4828 sp -= 1;
4829 MonoObject *obj = sp [0].data.o;
4830 sp [0].data.i = (obj->vtable->flags & MONO_VT_FLAG_ARRAY_OR_STRING) != 0;
4831 sp ++;
4832 ++ip;
4833 MINT_IN_BREAK;
4835 MINT_IN_CASE(MINT_CASTCLASS_INTERFACE)
4836 MINT_IN_CASE(MINT_ISINST_INTERFACE) {
4837 MonoObject* const o = sp [-1].data.o; // See the comment about GC safety above.
4838 if (o) {
4839 MonoClass* const c = (MonoClass*)imethod->data_items [*(guint16 *)(ip + 1)];
4840 gboolean isinst;
4841 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (o->vtable, m_class_get_interface_id (c))) {
4842 isinst = TRUE;
4843 } else if (m_class_is_array_special_interface (c) || mono_object_is_transparent_proxy (o)) {
4844 /* slow path */
4845 isinst = mono_interp_isinst (o, c); // FIXME: do not swallow the error
4846 } else {
4847 isinst = FALSE;
4850 if (!isinst) {
4851 gboolean const isinst_instr = *ip == MINT_ISINST_INTERFACE;
4852 if (isinst_instr)
4853 sp [-1].data.p = NULL;
4854 else
4855 THROW_EX (mono_get_exception_invalid_cast (), ip);
4858 ip += 2;
4859 MINT_IN_BREAK;
4861 MINT_IN_CASE(MINT_CASTCLASS_COMMON)
4862 MINT_IN_CASE(MINT_ISINST_COMMON) {
4863 MonoObject* const o = sp [-1].data.o; // See the comment about GC safety above
4864 if (o) {
4865 MonoClass* const c = (MonoClass*)imethod->data_items [*(guint16 *)(ip + 1)];
4866 gboolean isinst = mono_class_has_parent_fast (o->vtable->klass, c);
4868 if (!isinst) {
4869 gboolean const isinst_instr = *ip == MINT_ISINST_COMMON;
4870 if (isinst_instr)
4871 sp [-1].data.p = NULL;
4872 else
4873 THROW_EX (mono_get_exception_invalid_cast (), ip);
4876 ip += 2;
4877 MINT_IN_BREAK;
4879 MINT_IN_CASE(MINT_CASTCLASS)
4880 MINT_IN_CASE(MINT_ISINST) {
4881 MonoObject* const o = sp [-1].data.o; // See the comment about GC safety above
4882 if (o) {
4883 MonoClass* const c = (MonoClass*)imethod->data_items [*(guint16 *)(ip + 1)];
4884 if (!mono_interp_isinst (o, c)) { // FIXME: do not swallow the error
4885 gboolean const isinst_instr = *ip == MINT_ISINST;
4886 if (isinst_instr)
4887 sp [-1].data.p = NULL;
4888 else
4889 THROW_EX (mono_get_exception_invalid_cast (), ip);
4892 ip += 2;
4893 MINT_IN_BREAK;
4895 MINT_IN_CASE(MINT_CONV_R_UN_I4)
4896 sp [-1].data.f = (double)(guint32)sp [-1].data.i;
4897 ++ip;
4898 MINT_IN_BREAK;
4899 MINT_IN_CASE(MINT_CONV_R_UN_I8)
4900 sp [-1].data.f = (double)(guint64)sp [-1].data.l;
4901 ++ip;
4902 MINT_IN_BREAK;
4903 MINT_IN_CASE(MINT_UNBOX) {
4904 MonoObject* const o = sp [-1].data.o; // See the comment about GC safety above
4905 NULL_CHECK (o);
4906 MonoClass* const c = (MonoClass*)imethod->data_items[*(guint16 *)(ip + 1)];
4908 if (!(m_class_get_rank (o->vtable->klass) == 0 && m_class_get_element_class (o->vtable->klass) == m_class_get_element_class (c)))
4909 THROW_EX (mono_get_exception_invalid_cast (), ip);
4911 sp [-1].data.p = mono_object_unbox_internal (o);
4912 ip += 2;
4913 MINT_IN_BREAK;
4915 MINT_IN_CASE(MINT_THROW)
4916 --sp;
4917 if (!sp->data.p)
4918 sp->data.p = mono_get_exception_null_reference ();
4920 THROW_EX ((MonoException *)sp->data.p, ip);
4921 MINT_IN_BREAK;
4922 MINT_IN_CASE(MINT_CHECKPOINT)
4923 /* Do synchronous checking of abort requests */
4924 EXCEPTION_CHECKPOINT;
4925 ++ip;
4926 MINT_IN_BREAK;
4927 MINT_IN_CASE(MINT_SAFEPOINT)
4928 /* Do synchronous checking of abort requests */
4929 EXCEPTION_CHECKPOINT;
4930 /* Poll safepoint */
4931 mono_threads_safepoint ();
4932 ++ip;
4933 MINT_IN_BREAK;
4934 MINT_IN_CASE(MINT_LDFLDA_UNSAFE) {
4935 sp[-1].data.p = (char*)sp [-1].data.o + * (guint16 *)(ip + 1);
4936 ip += 2;
4937 MINT_IN_BREAK;
4939 MINT_IN_CASE(MINT_LDFLDA) {
4940 MonoObject* const o = sp [-1].data.o; // See the comment about GC safety above.
4941 NULL_CHECK (o);
4942 sp[-1].data.p = (char *)o + * (guint16 *)(ip + 1);
4943 ip += 2;
4944 MINT_IN_BREAK;
4946 MINT_IN_CASE(MINT_CKNULL_N) {
4947 /* Same as CKNULL, but further down the stack */
4948 int const n = *(guint16*)(ip + 1);
4949 MonoObject* const o = sp [-n].data.o; // See the comment about GC safety above.
4950 NULL_CHECK (o);
4951 ip += 2;
4952 MINT_IN_BREAK;
4955 #define LDFLD_UNALIGNED(datamem, fieldtype, unaligned) do { \
4956 MonoObject* const o = sp [-1].data.o; \
4957 NULL_CHECK (o); \
4958 if (unaligned) \
4959 memcpy (&sp[-1].data.datamem, (char *)o + * (guint16 *)(ip + 1), sizeof (fieldtype)); \
4960 else \
4961 sp[-1].data.datamem = * (fieldtype *)((char *)o + * (guint16 *)(ip + 1)) ; \
4962 ip += 2; \
4963 } while (0)
4965 #define LDFLD(datamem, fieldtype) LDFLD_UNALIGNED(datamem, fieldtype, FALSE)
4967 MINT_IN_CASE(MINT_LDFLD_I1) LDFLD(i, gint8); MINT_IN_BREAK;
4968 MINT_IN_CASE(MINT_LDFLD_U1) LDFLD(i, guint8); MINT_IN_BREAK;
4969 MINT_IN_CASE(MINT_LDFLD_I2) LDFLD(i, gint16); MINT_IN_BREAK;
4970 MINT_IN_CASE(MINT_LDFLD_U2) LDFLD(i, guint16); MINT_IN_BREAK;
4971 MINT_IN_CASE(MINT_LDFLD_I4) LDFLD(i, gint32); MINT_IN_BREAK;
4972 MINT_IN_CASE(MINT_LDFLD_I8) LDFLD(l, gint64); MINT_IN_BREAK;
4973 MINT_IN_CASE(MINT_LDFLD_R4) LDFLD(f_r4, float); MINT_IN_BREAK;
4974 MINT_IN_CASE(MINT_LDFLD_R8) LDFLD(f, double); MINT_IN_BREAK;
4975 MINT_IN_CASE(MINT_LDFLD_O) LDFLD(p, gpointer); MINT_IN_BREAK;
4976 MINT_IN_CASE(MINT_LDFLD_P) LDFLD(p, gpointer); MINT_IN_BREAK;
4977 MINT_IN_CASE(MINT_LDFLD_I8_UNALIGNED) LDFLD_UNALIGNED(l, gint64, TRUE); MINT_IN_BREAK;
4978 MINT_IN_CASE(MINT_LDFLD_R8_UNALIGNED) LDFLD_UNALIGNED(f, double, TRUE); MINT_IN_BREAK;
4980 MINT_IN_CASE(MINT_LDFLD_VT) {
4981 MonoObject* const o = sp [-1].data.o; // See the comment about GC safety above.
4982 NULL_CHECK (o);
4984 int size = READ32(ip + 2);
4985 sp [-1].data.p = vt_sp;
4986 memcpy (sp [-1].data.p, (char *)o + * (guint16 *)(ip + 1), size);
4987 vt_sp += ALIGN_TO (size, MINT_VT_ALIGNMENT);
4988 ip += 4;
4989 MINT_IN_BREAK;
4992 MINT_IN_CASE(MINT_LDRMFLD) {
4993 MonoObject* const o = sp [-1].data.o; // See the comment about GC safety above.
4994 NULL_CHECK (o);
4995 mono_interp_load_remote_field (imethod, o, ip, sp);
4996 ip += 2;
4997 MINT_IN_BREAK;
4999 MINT_IN_CASE(MINT_LDRMFLD_VT) {
5000 MonoObject* const o = sp [-1].data.o; // See the comment about GC safety above.
5001 NULL_CHECK (o);
5002 vt_sp = mono_interp_load_remote_field_vt (imethod, o, ip, sp, vt_sp);
5003 ip += 2;
5004 MINT_IN_BREAK;
5007 #define STFLD_UNALIGNED(datamem, fieldtype, unaligned) do { \
5008 MonoObject* const o = sp [-2].data.o; /* See the comment about GC safety above. */ \
5009 NULL_CHECK (o); \
5010 sp -= 2; \
5011 if (unaligned) \
5012 memcpy ((char *)o + * (guint16 *)(ip + 1), &sp[1].data.datamem, sizeof (fieldtype)); \
5013 else \
5014 * (fieldtype *)((char *)o + * (guint16 *)(ip + 1)) = sp[1].data.datamem; \
5015 ip += 2; \
5016 } while (0)
5018 #define STFLD(datamem, fieldtype) STFLD_UNALIGNED(datamem, fieldtype, FALSE)
5020 MINT_IN_CASE(MINT_STFLD_I1) STFLD(i, gint8); MINT_IN_BREAK;
5021 MINT_IN_CASE(MINT_STFLD_U1) STFLD(i, guint8); MINT_IN_BREAK;
5022 MINT_IN_CASE(MINT_STFLD_I2) STFLD(i, gint16); MINT_IN_BREAK;
5023 MINT_IN_CASE(MINT_STFLD_U2) STFLD(i, guint16); MINT_IN_BREAK;
5024 MINT_IN_CASE(MINT_STFLD_I4) STFLD(i, gint32); MINT_IN_BREAK;
5025 MINT_IN_CASE(MINT_STFLD_I8) STFLD(l, gint64); MINT_IN_BREAK;
5026 MINT_IN_CASE(MINT_STFLD_R4) STFLD(f_r4, float); MINT_IN_BREAK;
5027 MINT_IN_CASE(MINT_STFLD_R8) STFLD(f, double); MINT_IN_BREAK;
5028 MINT_IN_CASE(MINT_STFLD_P) STFLD(p, gpointer); MINT_IN_BREAK;
5029 MINT_IN_CASE(MINT_STFLD_O) {
5030 MonoObject* const o = sp [-2].data.o; // See the comment about GC safety above.
5031 NULL_CHECK (o);
5032 sp -= 2;
5033 mono_gc_wbarrier_set_field_internal (o, (char *) o + * (guint16 *)(ip + 1), sp [1].data.o);
5034 ip += 2;
5035 MINT_IN_BREAK;
5037 MINT_IN_CASE(MINT_STFLD_I8_UNALIGNED) STFLD_UNALIGNED(l, gint64, TRUE); MINT_IN_BREAK;
5038 MINT_IN_CASE(MINT_STFLD_R8_UNALIGNED) STFLD_UNALIGNED(f, double, TRUE); MINT_IN_BREAK;
5040 MINT_IN_CASE(MINT_STFLD_VT) {
5041 MonoObject* const o = sp [-2].data.o; // See the comment about GC safety above.
5042 NULL_CHECK (o);
5043 sp -= 2;
5045 MonoClass *klass = (MonoClass*)imethod->data_items[* (guint16 *)(ip + 2)];
5046 int const i32 = mono_class_value_size (klass, NULL);
5048 guint16 offset = * (guint16 *)(ip + 1);
5049 mono_value_copy_internal ((char *) o + offset, sp [1].data.p, klass);
5051 vt_sp -= ALIGN_TO (i32, MINT_VT_ALIGNMENT);
5052 ip += 3;
5053 MINT_IN_BREAK;
5055 MINT_IN_CASE(MINT_STRMFLD) {
5056 MonoClassField *field;
5058 MonoObject* const o = sp [-2].data.o; // See the comment about GC safety above.
5059 NULL_CHECK (o);
5061 field = (MonoClassField*)imethod->data_items[* (guint16 *)(ip + 1)];
5062 ip += 2;
5064 #ifndef DISABLE_REMOTING
5065 if (mono_object_is_transparent_proxy (o)) {
5066 MonoClass *klass = ((MonoTransparentProxy*)o)->remote_class->proxy_class;
5067 mono_store_remote_field_checked (o, klass, field, &sp [-1].data, error);
5068 mono_error_cleanup (error); /* FIXME: don't swallow the error */
5069 } else
5070 #endif
5071 stackval_to_data (field->type, &sp [-1], (char*)o + field->offset, FALSE);
5073 sp -= 2;
5074 MINT_IN_BREAK;
5076 MINT_IN_CASE(MINT_STRMFLD_VT)
5078 NULL_CHECK (sp [-2].data.o);
5079 vt_sp -= mono_interp_store_remote_field_vt (frame, ip, sp, error);
5080 ip += 2;
5081 sp -= 2;
5082 MINT_IN_BREAK;
5084 MINT_IN_CASE(MINT_LDSFLDA) {
5085 MonoVTable *vtable = (MonoVTable*) imethod->data_items [*(guint16*)(ip + 1)];
5086 INIT_VTABLE (vtable);
5087 sp->data.p = imethod->data_items [*(guint16*)(ip + 2)];
5088 ip += 3;
5089 ++sp;
5090 MINT_IN_BREAK;
5093 MINT_IN_CASE(MINT_LDSSFLDA) {
5094 guint32 offset = READ32(ip + 1);
5095 sp->data.p = mono_get_special_static_data (offset);
5096 ip += 3;
5097 ++sp;
5098 MINT_IN_BREAK;
5101 /* We init class here to preserve cctor order */
5102 #define LDSFLD(datamem, fieldtype) { \
5103 MonoVTable *vtable = (MonoVTable*) imethod->data_items [*(guint16*)(ip + 1)]; \
5104 INIT_VTABLE (vtable); \
5105 sp[0].data.datamem = * (fieldtype *)(imethod->data_items [* (guint16 *)(ip + 2)]) ; \
5106 ip += 3; \
5107 sp++; \
5110 MINT_IN_CASE(MINT_LDSFLD_I1) LDSFLD(i, gint8); MINT_IN_BREAK;
5111 MINT_IN_CASE(MINT_LDSFLD_U1) LDSFLD(i, guint8); MINT_IN_BREAK;
5112 MINT_IN_CASE(MINT_LDSFLD_I2) LDSFLD(i, gint16); MINT_IN_BREAK;
5113 MINT_IN_CASE(MINT_LDSFLD_U2) LDSFLD(i, guint16); MINT_IN_BREAK;
5114 MINT_IN_CASE(MINT_LDSFLD_I4) LDSFLD(i, gint32); MINT_IN_BREAK;
5115 MINT_IN_CASE(MINT_LDSFLD_I8) LDSFLD(l, gint64); MINT_IN_BREAK;
5116 MINT_IN_CASE(MINT_LDSFLD_R4) LDSFLD(f_r4, float); MINT_IN_BREAK;
5117 MINT_IN_CASE(MINT_LDSFLD_R8) LDSFLD(f, double); MINT_IN_BREAK;
5118 MINT_IN_CASE(MINT_LDSFLD_O) LDSFLD(p, gpointer); MINT_IN_BREAK;
5119 MINT_IN_CASE(MINT_LDSFLD_P) LDSFLD(p, gpointer); MINT_IN_BREAK;
5121 MINT_IN_CASE(MINT_LDSFLD_VT) {
5122 MonoVTable *vtable = (MonoVTable*) imethod->data_items [*(guint16*)(ip + 1)];
5123 INIT_VTABLE (vtable);
5124 sp->data.p = vt_sp;
5126 gpointer addr = imethod->data_items [*(guint16*)(ip + 2)];
5127 int const i32 = READ32 (ip + 3);
5128 memcpy (vt_sp, addr, i32);
5129 vt_sp += ALIGN_TO (i32, MINT_VT_ALIGNMENT);
5130 ip += 5;
5131 ++sp;
5132 MINT_IN_BREAK;
5135 #define LDTSFLD(datamem, fieldtype) { \
5136 MonoInternalThread *thread = mono_thread_internal_current (); \
5137 guint32 offset = READ32 (ip + 1); \
5138 gpointer addr = ((char*)thread->static_data [offset & 0x3f]) + (offset >> 6); \
5139 sp[0].data.datamem = *(fieldtype*)addr; \
5140 ip += 3; \
5141 ++sp; \
5143 MINT_IN_CASE(MINT_LDTSFLD_I1) LDTSFLD(i, gint8); MINT_IN_BREAK;
5144 MINT_IN_CASE(MINT_LDTSFLD_U1) LDTSFLD(i, guint8); MINT_IN_BREAK;
5145 MINT_IN_CASE(MINT_LDTSFLD_I2) LDTSFLD(i, gint16); MINT_IN_BREAK;
5146 MINT_IN_CASE(MINT_LDTSFLD_U2) LDTSFLD(i, guint16); MINT_IN_BREAK;
5147 MINT_IN_CASE(MINT_LDTSFLD_I4) LDTSFLD(i, gint32); MINT_IN_BREAK;
5148 MINT_IN_CASE(MINT_LDTSFLD_I8) LDTSFLD(l, gint64); MINT_IN_BREAK;
5149 MINT_IN_CASE(MINT_LDTSFLD_R4) LDTSFLD(f_r4, float); MINT_IN_BREAK;
5150 MINT_IN_CASE(MINT_LDTSFLD_R8) LDTSFLD(f, double); MINT_IN_BREAK;
5151 MINT_IN_CASE(MINT_LDTSFLD_O) LDTSFLD(p, gpointer); MINT_IN_BREAK;
5152 MINT_IN_CASE(MINT_LDTSFLD_P) LDTSFLD(p, gpointer); MINT_IN_BREAK;
5154 MINT_IN_CASE(MINT_LDSSFLD) {
5155 guint32 offset = READ32(ip + 2);
5156 gpointer addr = mono_get_special_static_data (offset);
5157 MonoClassField *field = (MonoClassField*)imethod->data_items [* (guint16 *)(ip + 1)];
5158 stackval_from_data (field->type, sp, addr, FALSE);
5159 ip += 4;
5160 ++sp;
5161 MINT_IN_BREAK;
5163 MINT_IN_CASE(MINT_LDSSFLD_VT) {
5164 guint32 offset = READ32(ip + 1);
5165 gpointer addr = mono_get_special_static_data (offset);
5167 int size = READ32 (ip + 3);
5168 memcpy (vt_sp, addr, size);
5169 sp->data.p = vt_sp;
5170 vt_sp += ALIGN_TO (size, MINT_VT_ALIGNMENT);
5171 ip += 5;
5172 ++sp;
5173 MINT_IN_BREAK;
5175 #define STSFLD(datamem, fieldtype) { \
5176 MonoVTable *vtable = (MonoVTable*) imethod->data_items [*(guint16*)(ip + 1)]; \
5177 INIT_VTABLE (vtable); \
5178 sp --; \
5179 * (fieldtype *)(imethod->data_items [* (guint16 *)(ip + 2)]) = sp[0].data.datamem; \
5180 ip += 3; \
5183 MINT_IN_CASE(MINT_STSFLD_I1) STSFLD(i, gint8); MINT_IN_BREAK;
5184 MINT_IN_CASE(MINT_STSFLD_U1) STSFLD(i, guint8); MINT_IN_BREAK;
5185 MINT_IN_CASE(MINT_STSFLD_I2) STSFLD(i, gint16); MINT_IN_BREAK;
5186 MINT_IN_CASE(MINT_STSFLD_U2) STSFLD(i, guint16); MINT_IN_BREAK;
5187 MINT_IN_CASE(MINT_STSFLD_I4) STSFLD(i, gint32); MINT_IN_BREAK;
5188 MINT_IN_CASE(MINT_STSFLD_I8) STSFLD(l, gint64); MINT_IN_BREAK;
5189 MINT_IN_CASE(MINT_STSFLD_R4) STSFLD(f_r4, float); MINT_IN_BREAK;
5190 MINT_IN_CASE(MINT_STSFLD_R8) STSFLD(f, double); MINT_IN_BREAK;
5191 MINT_IN_CASE(MINT_STSFLD_P) STSFLD(p, gpointer); MINT_IN_BREAK;
5192 MINT_IN_CASE(MINT_STSFLD_O) STSFLD(p, gpointer); MINT_IN_BREAK;
5194 MINT_IN_CASE(MINT_STSFLD_VT) {
5195 MonoVTable *vtable = (MonoVTable*) imethod->data_items [*(guint16*)(ip + 1)];
5196 INIT_VTABLE (vtable);
5197 int const i32 = READ32 (ip + 3);
5198 gpointer addr = imethod->data_items [*(guint16*)(ip + 2)];
5200 memcpy (addr, sp [-1].data.vt, i32);
5201 vt_sp -= ALIGN_TO (i32, MINT_VT_ALIGNMENT);
5202 ip += 4;
5203 --sp;
5204 MINT_IN_BREAK;
5207 #define STTSFLD(datamem, fieldtype) { \
5208 MonoInternalThread *thread = mono_thread_internal_current (); \
5209 guint32 offset = READ32 (ip + 1); \
5210 gpointer addr = ((char*)thread->static_data [offset & 0x3f]) + (offset >> 6); \
5211 sp--; \
5212 *(fieldtype*)addr = sp[0].data.datamem; \
5213 ip += 3; \
5216 MINT_IN_CASE(MINT_STTSFLD_I1) STTSFLD(i, gint8); MINT_IN_BREAK;
5217 MINT_IN_CASE(MINT_STTSFLD_U1) STTSFLD(i, guint8); MINT_IN_BREAK;
5218 MINT_IN_CASE(MINT_STTSFLD_I2) STTSFLD(i, gint16); MINT_IN_BREAK;
5219 MINT_IN_CASE(MINT_STTSFLD_U2) STTSFLD(i, guint16); MINT_IN_BREAK;
5220 MINT_IN_CASE(MINT_STTSFLD_I4) STTSFLD(i, gint32); MINT_IN_BREAK;
5221 MINT_IN_CASE(MINT_STTSFLD_I8) STTSFLD(l, gint64); MINT_IN_BREAK;
5222 MINT_IN_CASE(MINT_STTSFLD_R4) STTSFLD(f_r4, float); MINT_IN_BREAK;
5223 MINT_IN_CASE(MINT_STTSFLD_R8) STTSFLD(f, double); MINT_IN_BREAK;
5224 MINT_IN_CASE(MINT_STTSFLD_P) STTSFLD(p, gpointer); MINT_IN_BREAK;
5225 MINT_IN_CASE(MINT_STTSFLD_O) STTSFLD(p, gpointer); MINT_IN_BREAK;
5227 MINT_IN_CASE(MINT_STSSFLD) {
5228 guint32 offset = READ32(ip + 2);
5229 gpointer addr = mono_get_special_static_data (offset);
5230 MonoClassField *field = (MonoClassField*)imethod->data_items [* (guint16 *)(ip + 1)];
5231 --sp;
5232 stackval_to_data (field->type, sp, addr, FALSE);
5233 ip += 4;
5234 MINT_IN_BREAK;
5236 MINT_IN_CASE(MINT_STSSFLD_VT) {
5237 guint32 offset = READ32(ip + 1);
5238 gpointer addr = mono_get_special_static_data (offset);
5239 --sp;
5240 int size = READ32 (ip + 3);
5241 memcpy (addr, sp->data.vt, size);
5242 vt_sp -= ALIGN_TO (size, MINT_VT_ALIGNMENT);
5243 ip += 5;
5244 MINT_IN_BREAK;
5247 MINT_IN_CASE(MINT_STOBJ_VT) {
5248 int size;
5249 MonoClass* const c = (MonoClass*)imethod->data_items[* (guint16 *)(ip + 1)];
5250 ip += 2;
5251 size = mono_class_value_size (c, NULL);
5252 mono_value_copy_internal (sp [-2].data.p, sp [-1].data.p, c);
5253 vt_sp -= ALIGN_TO (size, MINT_VT_ALIGNMENT);
5254 sp -= 2;
5255 MINT_IN_BREAK;
5257 MINT_IN_CASE(MINT_CONV_OVF_I4_UN_R8)
5258 if (sp [-1].data.f < 0 || sp [-1].data.f > G_MAXINT32)
5259 THROW_EX_OVF (ip);
5260 sp [-1].data.i = (gint32)sp [-1].data.f;
5261 ++ip;
5262 MINT_IN_BREAK;
5263 MINT_IN_CASE(MINT_CONV_OVF_U8_I4)
5264 if (sp [-1].data.i < 0)
5265 THROW_EX_OVF (ip);
5266 sp [-1].data.l = sp [-1].data.i;
5267 ++ip;
5268 MINT_IN_BREAK;
5269 MINT_IN_CASE(MINT_CONV_OVF_U8_I8)
5270 if (sp [-1].data.l < 0)
5271 THROW_EX_OVF (ip);
5272 ++ip;
5273 MINT_IN_BREAK;
5274 MINT_IN_CASE(MINT_CONV_OVF_I8_U8)
5275 if ((guint64) sp [-1].data.l > G_MAXINT64)
5276 THROW_EX_OVF (ip);
5277 ++ip;
5278 MINT_IN_BREAK;
5279 MINT_IN_CASE(MINT_CONV_OVF_U8_R4)
5280 if (sp [-1].data.f_r4 < 0 || sp [-1].data.f_r4 > G_MAXUINT64 || isnan (sp [-1].data.f_r4))
5281 THROW_EX_OVF (ip);
5282 sp [-1].data.l = (guint64)sp [-1].data.f_r4;
5283 ++ip;
5284 MINT_IN_BREAK;
5285 MINT_IN_CASE(MINT_CONV_OVF_U8_R8)
5286 if (sp [-1].data.f < 0 || sp [-1].data.f > G_MAXUINT64 || isnan (sp [-1].data.f))
5287 THROW_EX_OVF (ip);
5288 sp [-1].data.l = (guint64)sp [-1].data.f;
5289 ++ip;
5290 MINT_IN_BREAK;
5291 MINT_IN_CASE(MINT_CONV_OVF_I8_UN_R8)
5292 if (sp [-1].data.f < 0 || sp [-1].data.f > G_MAXINT64)
5293 THROW_EX_OVF (ip);
5294 sp [-1].data.l = (gint64)sp [-1].data.f;
5295 ++ip;
5296 MINT_IN_BREAK;
5297 MINT_IN_CASE(MINT_CONV_OVF_I8_UN_R4)
5298 if (sp [-1].data.f_r4 < 0 || sp [-1].data.f_r4 > G_MAXINT64)
5299 THROW_EX_OVF (ip);
5300 sp [-1].data.l = (gint64)sp [-1].data.f_r4;
5301 ++ip;
5302 MINT_IN_BREAK;
5303 MINT_IN_CASE(MINT_CONV_OVF_I8_R4)
5304 if (sp [-1].data.f_r4 < G_MININT64 || sp [-1].data.f_r4 > G_MAXINT64 || isnan (sp [-1].data.f_r4))
5305 THROW_EX_OVF (ip);
5306 sp [-1].data.l = (gint64)sp [-1].data.f_r4;
5307 ++ip;
5308 MINT_IN_BREAK;
5309 MINT_IN_CASE(MINT_CONV_OVF_I8_R8)
5310 if (sp [-1].data.f < G_MININT64 || sp [-1].data.f > G_MAXINT64 || isnan (sp [-1].data.f))
5311 THROW_EX_OVF (ip);
5312 sp [-1].data.l = (gint64)sp [-1].data.f;
5313 ++ip;
5314 MINT_IN_BREAK;
5315 MINT_IN_CASE(MINT_CONV_OVF_I4_UN_I8)
5316 if ((guint64)sp [-1].data.l > G_MAXINT32)
5317 THROW_EX_OVF (ip);
5318 sp [-1].data.i = (gint32)sp [-1].data.l;
5319 ++ip;
5320 MINT_IN_BREAK;
5321 MINT_IN_CASE(MINT_BOX) {
5322 MonoObject* o; // See the comment about GC safety above.
5323 MonoVTable *vtable = (MonoVTable*)imethod->data_items [* (guint16 *)(ip + 1)];
5325 frame_objref (frame) = mono_gc_alloc_obj (vtable, m_class_get_instance_size (vtable->klass));
5327 guint16 offset = * (guint16 *)(ip + 2);
5329 stackval_to_data (m_class_get_byval_arg (vtable->klass), &sp [-1 - offset], mono_object_get_data (frame_objref (frame)), FALSE);
5331 sp [-1 - offset].data.p = frame_objref (frame);
5333 ip += 3;
5334 MINT_IN_BREAK;
5336 MINT_IN_CASE(MINT_BOX_VT) {
5337 MonoObject* o; // See the comment about GC safety above.
5338 MonoVTable *vtable = (MonoVTable*)imethod->data_items [* (guint16 *)(ip + 1)];
5339 MonoClass* const c = vtable->klass;
5341 int size = mono_class_value_size (c, NULL);
5343 guint16 offset = * (guint16 *)(ip + 2);
5344 gboolean pop_vt_sp = !(offset & BOX_NOT_CLEAR_VT_SP);
5345 offset &= ~BOX_NOT_CLEAR_VT_SP;
5347 frame_objref (frame) = mono_gc_alloc_obj (vtable, m_class_get_instance_size (vtable->klass));
5348 mono_value_copy_internal (mono_object_get_data (frame_objref (frame)), sp [-1 - offset].data.p, c);
5350 sp [-1 - offset].data.p = frame_objref (frame);
5351 size = ALIGN_TO (size, MINT_VT_ALIGNMENT);
5352 if (pop_vt_sp)
5353 vt_sp -= size;
5355 ip += 3;
5356 MINT_IN_BREAK;
5358 MINT_IN_CASE(MINT_BOX_NULLABLE)
5360 vt_sp -= mono_interp_box_nullable (frame, ip, sp, error);
5361 ip += 3;
5362 MINT_IN_BREAK;
5364 MINT_IN_CASE(MINT_NEWARR) {
5365 MonoVTable *vtable = (MonoVTable*)imethod->data_items[*(guint16 *)(ip + 1)];
5366 sp [-1].data.o = (MonoObject*) mono_array_new_specific_checked (vtable, sp [-1].data.i, error);
5367 if (!is_ok (error)) {
5368 THROW_EX (mono_error_convert_to_exception (error), ip);
5370 mono_error_cleanup (error); /* FIXME: don't swallow the error */
5371 ip += 2;
5372 /*if (profiling_classes) {
5373 guint count = GPOINTER_TO_UINT (g_hash_table_lookup (profiling_classes, o->vtable->klass));
5374 count++;
5375 g_hash_table_insert (profiling_classes, o->vtable->klass, GUINT_TO_POINTER (count));
5378 MINT_IN_BREAK;
5380 MINT_IN_CASE(MINT_LDLEN) {
5381 MonoObject* const o = sp [-1].data.o; // See the comment about GC safety above.
5382 NULL_CHECK (o);
5383 sp [-1].data.nati = mono_array_length_internal ((MonoArray *)o);
5384 ++ip;
5385 MINT_IN_BREAK;
5387 MINT_IN_CASE(MINT_LDLEN_SPAN) {
5388 MonoObject* const o = sp [-1].data.o; // See the comment about GC safety above.
5389 NULL_CHECK (o);
5390 gsize offset_length = (gsize) *(gint16 *) (ip + 1);
5391 sp [-1].data.nati = *(gint32 *) ((guint8 *) o + offset_length);
5392 ip += 2;
5393 MINT_IN_BREAK;
5395 MINT_IN_CASE(MINT_GETCHR) {
5396 MonoString *s;
5397 s = (MonoString*)sp [-2].data.p;
5398 NULL_CHECK (s);
5399 int const i32 = sp [-1].data.i;
5400 if (i32 < 0 || i32 >= mono_string_length_internal (s))
5401 THROW_EX (mono_get_exception_index_out_of_range (), ip);
5402 --sp;
5403 sp [-1].data.i = mono_string_chars_internal (s)[i32];
5404 ++ip;
5405 MINT_IN_BREAK;
5407 MINT_IN_CASE(MINT_GETITEM_SPAN) {
5408 guint8 * const span = (guint8 *) sp [-2].data.p;
5409 const int index = sp [-1].data.i;
5410 sp--;
5412 NULL_CHECK (span);
5414 const gsize offset_length = (gsize) *(gint16 *) (ip + 2);
5416 const gint32 length = *(gint32 *) (span + offset_length);
5417 if (index < 0 || index >= length)
5418 THROW_EX (mono_get_exception_index_out_of_range (), ip);
5420 const gsize element_size = (gsize) *(gint16 *) (ip + 1);
5421 const gsize offset_pointer = (gsize) *(gint16 *) (ip + 3);
5423 const gpointer pointer = *(gpointer *)(span + offset_pointer);
5424 sp [-1].data.p = (guint8 *) pointer + index * element_size;
5426 ip += 4;
5427 MINT_IN_BREAK;
5429 MINT_IN_CASE(MINT_STRLEN) {
5430 ++ip;
5431 MonoObject* const o = sp [-1].data.o; // See the comment about GC safety above.
5432 NULL_CHECK (o);
5433 sp [-1].data.i = mono_string_length_internal ((MonoString*) o);
5434 MINT_IN_BREAK;
5436 MINT_IN_CASE(MINT_ARRAY_RANK) {
5437 MonoObject* const o = sp [-1].data.o; // See the comment about GC safety above.
5438 NULL_CHECK (o);
5439 sp [-1].data.i = m_class_get_rank (mono_object_class (sp [-1].data.p));
5440 ip++;
5441 MINT_IN_BREAK;
5443 MINT_IN_CASE(MINT_LDELEMA_FAST) {
5444 /* No bounds, one direction */
5445 MonoArray *ao = (MonoArray*)sp [-2].data.o;
5446 NULL_CHECK (ao);
5447 gint32 const index = sp [-1].data.i;
5448 if (index >= ao->max_length)
5449 THROW_EX (mono_get_exception_index_out_of_range (), ip);
5450 gint32 const size = READ32 (ip + 1);
5451 sp [-2].data.p = mono_array_addr_with_size_fast (ao, size, index);
5452 ip += 3;
5453 sp --;
5455 MINT_IN_BREAK;
5457 MINT_IN_CASE(MINT_LDELEMA)
5458 MINT_IN_CASE(MINT_LDELEMA_TC) {
5460 guint16 numargs = *(guint16 *) (ip + 2);
5461 ip += 3;
5462 sp -= numargs;
5464 MonoObject* const o = sp [0].data.o; // See the comment about GC safety above.
5465 NULL_CHECK (o);
5467 MonoClass *klass = (MonoClass*)imethod->data_items [*(guint16 *) (ip - 3 + 1)];
5468 const gboolean needs_typecheck = ip [-3] == MINT_LDELEMA_TC;
5469 sp->data.p = ves_array_element_address (frame, klass, (MonoArray *) o, &sp [1], needs_typecheck);
5470 if (frame->ex)
5471 THROW_EX (frame->ex, ip);
5472 ++sp;
5474 MINT_IN_BREAK;
5476 MINT_IN_CASE(MINT_LDELEM_I1) /* fall through */
5477 MINT_IN_CASE(MINT_LDELEM_U1) /* fall through */
5478 MINT_IN_CASE(MINT_LDELEM_I2) /* fall through */
5479 MINT_IN_CASE(MINT_LDELEM_U2) /* fall through */
5480 MINT_IN_CASE(MINT_LDELEM_I4) /* fall through */
5481 MINT_IN_CASE(MINT_LDELEM_U4) /* fall through */
5482 MINT_IN_CASE(MINT_LDELEM_I8) /* fall through */
5483 MINT_IN_CASE(MINT_LDELEM_I) /* fall through */
5484 MINT_IN_CASE(MINT_LDELEM_R4) /* fall through */
5485 MINT_IN_CASE(MINT_LDELEM_R8) /* fall through */
5486 MINT_IN_CASE(MINT_LDELEM_REF) /* fall through */
5487 MINT_IN_CASE(MINT_LDELEM_VT) {
5488 MonoArray *o;
5489 mono_u aindex;
5491 sp -= 2;
5493 o = (MonoArray*)sp [0].data.p;
5494 NULL_CHECK (o);
5496 aindex = sp [1].data.i;
5497 if (aindex >= mono_array_length_internal (o))
5498 THROW_EX (mono_get_exception_index_out_of_range (), ip);
5501 * FIXME: throw mono_get_exception_array_type_mismatch () if needed
5503 switch (*ip) {
5504 case MINT_LDELEM_I1:
5505 sp [0].data.i = mono_array_get_fast (o, gint8, aindex);
5506 break;
5507 case MINT_LDELEM_U1:
5508 sp [0].data.i = mono_array_get_fast (o, guint8, aindex);
5509 break;
5510 case MINT_LDELEM_I2:
5511 sp [0].data.i = mono_array_get_fast (o, gint16, aindex);
5512 break;
5513 case MINT_LDELEM_U2:
5514 sp [0].data.i = mono_array_get_fast (o, guint16, aindex);
5515 break;
5516 case MINT_LDELEM_I:
5517 sp [0].data.nati = mono_array_get_fast (o, mono_i, aindex);
5518 break;
5519 case MINT_LDELEM_I4:
5520 sp [0].data.i = mono_array_get_fast (o, gint32, aindex);
5521 break;
5522 case MINT_LDELEM_U4:
5523 sp [0].data.i = mono_array_get_fast (o, guint32, aindex);
5524 break;
5525 case MINT_LDELEM_I8:
5526 sp [0].data.l = mono_array_get_fast (o, guint64, aindex);
5527 break;
5528 case MINT_LDELEM_R4:
5529 sp [0].data.f_r4 = mono_array_get_fast (o, float, aindex);
5530 break;
5531 case MINT_LDELEM_R8:
5532 sp [0].data.f = mono_array_get_fast (o, double, aindex);
5533 break;
5534 case MINT_LDELEM_REF:
5535 sp [0].data.p = mono_array_get_fast (o, gpointer, aindex);
5536 break;
5537 case MINT_LDELEM_VT: {
5538 int const i32 = READ32 (ip + 1);
5539 char *src_addr = mono_array_addr_with_size_fast ((MonoArray *) o, i32, aindex);
5540 sp [0].data.vt = vt_sp;
5541 // Copying to vtstack. No wbarrier needed
5542 memcpy (sp [0].data.vt, src_addr, i32);
5543 vt_sp += ALIGN_TO (i32, MINT_VT_ALIGNMENT);
5544 ip += 2;
5545 break;
5547 default:
5548 ves_abort();
5551 ++ip;
5552 ++sp;
5553 MINT_IN_BREAK;
5555 MINT_IN_CASE(MINT_STELEM_I) /* fall through */
5556 MINT_IN_CASE(MINT_STELEM_I1) /* fall through */
5557 MINT_IN_CASE(MINT_STELEM_U1) /* fall through */
5558 MINT_IN_CASE(MINT_STELEM_I2) /* fall through */
5559 MINT_IN_CASE(MINT_STELEM_U2) /* fall through */
5560 MINT_IN_CASE(MINT_STELEM_I4) /* fall through */
5561 MINT_IN_CASE(MINT_STELEM_I8) /* fall through */
5562 MINT_IN_CASE(MINT_STELEM_R4) /* fall through */
5563 MINT_IN_CASE(MINT_STELEM_R8) /* fall through */
5564 MINT_IN_CASE(MINT_STELEM_REF) /* fall through */
5565 MINT_IN_CASE(MINT_STELEM_VT) {
5566 mono_u aindex;
5568 sp -= 3;
5570 MonoObject* const o = sp [0].data.o; // See the comment about GC safety above.
5571 NULL_CHECK (o);
5573 aindex = sp [1].data.i;
5574 if (aindex >= mono_array_length_internal ((MonoArray *)o))
5575 THROW_EX (mono_get_exception_index_out_of_range (), ip);
5577 switch (*ip) {
5578 case MINT_STELEM_I:
5579 mono_array_set_fast ((MonoArray *)o, mono_i, aindex, sp [2].data.nati);
5580 break;
5581 case MINT_STELEM_I1:
5582 mono_array_set_fast ((MonoArray *)o, gint8, aindex, sp [2].data.i);
5583 break;
5584 case MINT_STELEM_U1:
5585 mono_array_set_fast ((MonoArray *) o, guint8, aindex, sp [2].data.i);
5586 break;
5587 case MINT_STELEM_I2:
5588 mono_array_set_fast ((MonoArray *)o, gint16, aindex, sp [2].data.i);
5589 break;
5590 case MINT_STELEM_U2:
5591 mono_array_set_fast ((MonoArray *)o, guint16, aindex, sp [2].data.i);
5592 break;
5593 case MINT_STELEM_I4:
5594 mono_array_set_fast ((MonoArray *)o, gint32, aindex, sp [2].data.i);
5595 break;
5596 case MINT_STELEM_I8:
5597 mono_array_set_fast ((MonoArray *)o, gint64, aindex, sp [2].data.l);
5598 break;
5599 case MINT_STELEM_R4:
5600 mono_array_set_fast ((MonoArray *)o, float, aindex, sp [2].data.f_r4);
5601 break;
5602 case MINT_STELEM_R8:
5603 mono_array_set_fast ((MonoArray *)o, double, aindex, sp [2].data.f);
5604 break;
5605 case MINT_STELEM_REF: {
5606 if (sp [2].data.p) {
5607 MonoObject *isinst_obj = mono_object_isinst_checked (sp [2].data.o, m_class_get_element_class (mono_object_class (o)), error);
5608 mono_error_cleanup (error); /* FIXME: don't swallow the error */
5609 if (!isinst_obj)
5610 THROW_EX (mono_get_exception_array_type_mismatch (), ip);
5612 mono_array_setref_fast ((MonoArray *) o, aindex, sp [2].data.p);
5613 break;
5615 case MINT_STELEM_VT: {
5616 MonoClass *klass_vt = (MonoClass*)imethod->data_items [*(guint16 *) (ip + 1)];
5617 int const i32 = READ32 (ip + 2);
5618 char *dst_addr = mono_array_addr_with_size_fast ((MonoArray *) o, i32, aindex);
5620 mono_value_copy_internal (dst_addr, sp [2].data.vt, klass_vt);
5621 vt_sp -= ALIGN_TO (i32, MINT_VT_ALIGNMENT);
5622 ip += 3;
5623 break;
5625 default:
5626 ves_abort();
5629 ++ip;
5630 MINT_IN_BREAK;
5632 MINT_IN_CASE(MINT_CONV_OVF_I4_U4)
5633 if (sp [-1].data.i < 0)
5634 THROW_EX_OVF (ip);
5635 ++ip;
5636 MINT_IN_BREAK;
5637 MINT_IN_CASE(MINT_CONV_OVF_I4_I8)
5638 if (sp [-1].data.l < G_MININT32 || sp [-1].data.l > G_MAXINT32)
5639 THROW_EX_OVF (ip);
5640 sp [-1].data.i = (gint32) sp [-1].data.l;
5641 ++ip;
5642 MINT_IN_BREAK;
5643 MINT_IN_CASE(MINT_CONV_OVF_I4_U8)
5644 if (sp [-1].data.l < 0 || sp [-1].data.l > G_MAXINT32)
5645 THROW_EX_OVF (ip);
5646 sp [-1].data.i = (gint32) sp [-1].data.l;
5647 ++ip;
5648 MINT_IN_BREAK;
5649 MINT_IN_CASE(MINT_CONV_OVF_I4_R4)
5650 if (sp [-1].data.f_r4 < G_MININT32 || sp [-1].data.f_r4 > G_MAXINT32)
5651 THROW_EX_OVF (ip);
5652 sp [-1].data.i = (gint32) sp [-1].data.f_r4;
5653 ++ip;
5654 MINT_IN_BREAK;
5655 MINT_IN_CASE(MINT_CONV_OVF_I4_R8)
5656 if (sp [-1].data.f < G_MININT32 || sp [-1].data.f > G_MAXINT32)
5657 THROW_EX_OVF (ip);
5658 sp [-1].data.i = (gint32) sp [-1].data.f;
5659 ++ip;
5660 MINT_IN_BREAK;
5661 MINT_IN_CASE(MINT_CONV_OVF_U4_I4)
5662 if (sp [-1].data.i < 0)
5663 THROW_EX_OVF (ip);
5664 ++ip;
5665 MINT_IN_BREAK;
5666 MINT_IN_CASE(MINT_CONV_OVF_U4_I8)
5667 if (sp [-1].data.l < 0 || sp [-1].data.l > G_MAXUINT32)
5668 THROW_EX_OVF (ip);
5669 sp [-1].data.i = (guint32) sp [-1].data.l;
5670 ++ip;
5671 MINT_IN_BREAK;
5672 MINT_IN_CASE(MINT_CONV_OVF_U4_R4)
5673 if (sp [-1].data.f_r4 < 0 || sp [-1].data.f_r4 > G_MAXUINT32)
5674 THROW_EX_OVF (ip);
5675 sp [-1].data.i = (guint32) sp [-1].data.f_r4;
5676 ++ip;
5677 MINT_IN_BREAK;
5678 MINT_IN_CASE(MINT_CONV_OVF_U4_R8)
5679 if (sp [-1].data.f < 0 || sp [-1].data.f > G_MAXUINT32)
5680 THROW_EX_OVF (ip);
5681 sp [-1].data.i = (guint32) sp [-1].data.f;
5682 ++ip;
5683 MINT_IN_BREAK;
5684 MINT_IN_CASE(MINT_CONV_OVF_I2_I4)
5685 if (sp [-1].data.i < G_MININT16 || sp [-1].data.i > G_MAXINT16)
5686 THROW_EX_OVF (ip);
5687 ++ip;
5688 MINT_IN_BREAK;
5689 MINT_IN_CASE(MINT_CONV_OVF_I2_U4)
5690 if (sp [-1].data.i < 0 || sp [-1].data.i > G_MAXINT16)
5691 THROW_EX_OVF (ip);
5692 ++ip;
5693 MINT_IN_BREAK;
5694 MINT_IN_CASE(MINT_CONV_OVF_I2_I8)
5695 if (sp [-1].data.l < G_MININT16 || sp [-1].data.l > G_MAXINT16)
5696 THROW_EX_OVF (ip);
5697 sp [-1].data.i = (gint16) sp [-1].data.l;
5698 ++ip;
5699 MINT_IN_BREAK;
5700 MINT_IN_CASE(MINT_CONV_OVF_I2_U8)
5701 if (sp [-1].data.l < 0 || sp [-1].data.l > G_MAXINT16)
5702 THROW_EX_OVF (ip);
5703 sp [-1].data.i = (gint16) sp [-1].data.l;
5704 ++ip;
5705 MINT_IN_BREAK;
5706 MINT_IN_CASE(MINT_CONV_OVF_I2_R8)
5707 if (sp [-1].data.f < G_MININT16 || sp [-1].data.f > G_MAXINT16)
5708 THROW_EX_OVF (ip);
5709 sp [-1].data.i = (gint16) sp [-1].data.f;
5710 ++ip;
5711 MINT_IN_BREAK;
5712 MINT_IN_CASE(MINT_CONV_OVF_I2_UN_R8)
5713 if (sp [-1].data.f < 0 || sp [-1].data.f > G_MAXINT16)
5714 THROW_EX_OVF (ip);
5715 sp [-1].data.i = (gint16) sp [-1].data.f;
5716 ++ip;
5717 MINT_IN_BREAK;
5718 MINT_IN_CASE(MINT_CONV_OVF_U2_I4)
5719 if (sp [-1].data.i < 0 || sp [-1].data.i > G_MAXUINT16)
5720 THROW_EX_OVF (ip);
5721 ++ip;
5722 MINT_IN_BREAK;
5723 MINT_IN_CASE(MINT_CONV_OVF_U2_I8)
5724 if (sp [-1].data.l < 0 || sp [-1].data.l > G_MAXUINT16)
5725 THROW_EX_OVF (ip);
5726 sp [-1].data.i = (guint16) sp [-1].data.l;
5727 ++ip;
5728 MINT_IN_BREAK;
5729 MINT_IN_CASE(MINT_CONV_OVF_U2_R8)
5730 if (sp [-1].data.f < 0 || sp [-1].data.f > G_MAXUINT16)
5731 THROW_EX_OVF (ip);
5732 sp [-1].data.i = (guint16) sp [-1].data.f;
5733 ++ip;
5734 MINT_IN_BREAK;
5735 MINT_IN_CASE(MINT_CONV_OVF_I1_I4)
5736 if (sp [-1].data.i < G_MININT8 || sp [-1].data.i > G_MAXINT8)
5737 THROW_EX_OVF (ip);
5738 ++ip;
5739 MINT_IN_BREAK;
5740 MINT_IN_CASE(MINT_CONV_OVF_I1_U4)
5741 if (sp [-1].data.i < 0 || sp [-1].data.i > G_MAXINT8)
5742 THROW_EX_OVF (ip);
5743 ++ip;
5744 MINT_IN_BREAK;
5745 MINT_IN_CASE(MINT_CONV_OVF_I1_I8)
5746 if (sp [-1].data.l < G_MININT8 || sp [-1].data.l > G_MAXINT8)
5747 THROW_EX_OVF (ip);
5748 sp [-1].data.i = (gint8) sp [-1].data.l;
5749 ++ip;
5750 MINT_IN_BREAK;
5751 MINT_IN_CASE(MINT_CONV_OVF_I1_U8)
5752 if (sp [-1].data.l < 0 || sp [-1].data.l > G_MAXINT8)
5753 THROW_EX_OVF (ip);
5754 sp [-1].data.i = (gint8) sp [-1].data.l;
5755 ++ip;
5756 MINT_IN_BREAK;
5757 MINT_IN_CASE(MINT_CONV_OVF_I1_R8)
5758 if (sp [-1].data.f < G_MININT8 || sp [-1].data.f > G_MAXINT8)
5759 THROW_EX_OVF (ip);
5760 sp [-1].data.i = (gint8) sp [-1].data.f;
5761 ++ip;
5762 MINT_IN_BREAK;
5763 MINT_IN_CASE(MINT_CONV_OVF_I1_UN_R8)
5764 if (sp [-1].data.f < 0 || sp [-1].data.f > G_MAXINT8)
5765 THROW_EX_OVF (ip);
5766 sp [-1].data.i = (gint8) sp [-1].data.f;
5767 ++ip;
5768 MINT_IN_BREAK;
5769 MINT_IN_CASE(MINT_CONV_OVF_U1_I4)
5770 if (sp [-1].data.i < 0 || sp [-1].data.i > G_MAXUINT8)
5771 THROW_EX_OVF (ip);
5772 ++ip;
5773 MINT_IN_BREAK;
5774 MINT_IN_CASE(MINT_CONV_OVF_U1_I8)
5775 if (sp [-1].data.l < 0 || sp [-1].data.l > G_MAXUINT8)
5776 THROW_EX_OVF (ip);
5777 sp [-1].data.i = (guint8) sp [-1].data.l;
5778 ++ip;
5779 MINT_IN_BREAK;
5780 MINT_IN_CASE(MINT_CONV_OVF_U1_R8)
5781 if (sp [-1].data.f < 0 || sp [-1].data.f > G_MAXUINT8)
5782 THROW_EX_OVF (ip);
5783 sp [-1].data.i = (guint8) sp [-1].data.f;
5784 ++ip;
5785 MINT_IN_BREAK;
5786 MINT_IN_CASE(MINT_CKFINITE)
5787 if (!mono_isfinite (sp [-1].data.f))
5788 THROW_EX (mono_get_exception_arithmetic (), ip);
5789 ++ip;
5790 MINT_IN_BREAK;
5791 MINT_IN_CASE(MINT_MKREFANY) {
5792 MonoClass* const c = (MonoClass*)imethod->data_items [*(guint16 *)(ip + 1)];
5794 /* The value address is on the stack */
5795 gpointer addr = sp [-1].data.p;
5796 /* Push the typedref value on the stack */
5797 sp [-1].data.p = vt_sp;
5798 vt_sp += ALIGN_TO (sizeof (MonoTypedRef), MINT_VT_ALIGNMENT);
5800 MonoTypedRef *tref = (MonoTypedRef*)sp [-1].data.p;
5801 tref->klass = c;
5802 tref->type = m_class_get_byval_arg (c);
5803 tref->value = addr;
5805 ip += 2;
5806 MINT_IN_BREAK;
5808 MINT_IN_CASE(MINT_REFANYTYPE) {
5809 MonoTypedRef *tref = (MonoTypedRef*)sp [-1].data.p;
5810 MonoType *type = tref->type;
5812 vt_sp -= ALIGN_TO (sizeof (MonoTypedRef), MINT_VT_ALIGNMENT);
5813 sp [-1].data.p = vt_sp;
5814 vt_sp += 8;
5815 *(gpointer*)sp [-1].data.p = type;
5816 ip ++;
5817 MINT_IN_BREAK;
5819 MINT_IN_CASE(MINT_REFANYVAL) {
5820 MonoTypedRef *tref = (MonoTypedRef*)sp [-1].data.p;
5821 gpointer addr = tref->value;
5823 MonoClass* const c = (MonoClass*)imethod->data_items [*(guint16 *)(ip + 1)];
5824 if (c != tref->klass)
5825 THROW_EX (mono_get_exception_invalid_cast (), ip);
5827 vt_sp -= ALIGN_TO (sizeof (MonoTypedRef), MINT_VT_ALIGNMENT);
5829 sp [-1].data.p = addr;
5830 ip += 2;
5831 MINT_IN_BREAK;
5833 MINT_IN_CASE(MINT_LDTOKEN)
5834 sp->data.p = vt_sp;
5835 vt_sp += 8;
5836 * (gpointer *)sp->data.p = imethod->data_items[*(guint16 *)(ip + 1)];
5837 ip += 2;
5838 ++sp;
5839 MINT_IN_BREAK;
5840 MINT_IN_CASE(MINT_ADD_OVF_I4)
5841 if (CHECK_ADD_OVERFLOW (sp [-2].data.i, sp [-1].data.i))
5842 THROW_EX_OVF (ip);
5843 BINOP(i, +);
5844 MINT_IN_BREAK;
5845 MINT_IN_CASE(MINT_ADD_OVF_I8)
5846 if (CHECK_ADD_OVERFLOW64 (sp [-2].data.l, sp [-1].data.l))
5847 THROW_EX_OVF (ip);
5848 BINOP(l, +);
5849 MINT_IN_BREAK;
5850 MINT_IN_CASE(MINT_ADD_OVF_UN_I4)
5851 if (CHECK_ADD_OVERFLOW_UN (sp [-2].data.i, sp [-1].data.i))
5852 THROW_EX_OVF (ip);
5853 BINOP_CAST(i, +, guint32);
5854 MINT_IN_BREAK;
5855 MINT_IN_CASE(MINT_ADD_OVF_UN_I8)
5856 if (CHECK_ADD_OVERFLOW64_UN (sp [-2].data.l, sp [-1].data.l))
5857 THROW_EX_OVF (ip);
5858 BINOP_CAST(l, +, guint64);
5859 MINT_IN_BREAK;
5860 MINT_IN_CASE(MINT_MUL_OVF_I4)
5861 if (CHECK_MUL_OVERFLOW (sp [-2].data.i, sp [-1].data.i))
5862 THROW_EX_OVF (ip);
5863 BINOP(i, *);
5864 MINT_IN_BREAK;
5865 MINT_IN_CASE(MINT_MUL_OVF_I8)
5866 if (CHECK_MUL_OVERFLOW64 (sp [-2].data.l, sp [-1].data.l))
5867 THROW_EX_OVF (ip);
5868 BINOP(l, *);
5869 MINT_IN_BREAK;
5870 MINT_IN_CASE(MINT_MUL_OVF_UN_I4)
5871 if (CHECK_MUL_OVERFLOW_UN (sp [-2].data.i, sp [-1].data.i))
5872 THROW_EX_OVF (ip);
5873 BINOP_CAST(i, *, guint32);
5874 MINT_IN_BREAK;
5875 MINT_IN_CASE(MINT_MUL_OVF_UN_I8)
5876 if (CHECK_MUL_OVERFLOW64_UN (sp [-2].data.l, sp [-1].data.l))
5877 THROW_EX_OVF (ip);
5878 BINOP_CAST(l, *, guint64);
5879 MINT_IN_BREAK;
5880 MINT_IN_CASE(MINT_SUB_OVF_I4)
5881 if (CHECK_SUB_OVERFLOW (sp [-2].data.i, sp [-1].data.i))
5882 THROW_EX_OVF (ip);
5883 BINOP(i, -);
5884 MINT_IN_BREAK;
5885 MINT_IN_CASE(MINT_SUB_OVF_I8)
5886 if (CHECK_SUB_OVERFLOW64 (sp [-2].data.l, sp [-1].data.l))
5887 THROW_EX_OVF (ip);
5888 BINOP(l, -);
5889 MINT_IN_BREAK;
5890 MINT_IN_CASE(MINT_SUB_OVF_UN_I4)
5891 if (CHECK_SUB_OVERFLOW_UN (sp [-2].data.i, sp [-1].data.i))
5892 THROW_EX_OVF (ip);
5893 BINOP_CAST(i, -, guint32);
5894 MINT_IN_BREAK;
5895 MINT_IN_CASE(MINT_SUB_OVF_UN_I8)
5896 if (CHECK_SUB_OVERFLOW64_UN (sp [-2].data.l, sp [-1].data.l))
5897 THROW_EX_OVF (ip);
5898 BINOP_CAST(l, -, guint64);
5899 MINT_IN_BREAK;
5900 MINT_IN_CASE(MINT_START_ABORT_PROT)
5901 mono_threads_begin_abort_protected_block ();
5902 ip ++;
5903 MINT_IN_BREAK;
5904 MINT_IN_CASE(MINT_ENDFINALLY) {
5905 ip ++;
5906 gboolean pending_abort = mono_threads_end_abort_protected_block ();
5908 // After mono_threads_end_abort_protected_block to conserve stack.
5909 const int clause_index = *ip;
5911 if (clause_args && clause_index == clause_args->exit_clause)
5912 goto exit_frame;
5914 g_assert (sp >= frame->stack);
5915 sp = frame->stack;
5917 if (finally_ips) {
5918 ip = (const guint16*)finally_ips->data;
5919 finally_ips = g_slist_remove (finally_ips, ip);
5920 /* Throw abort after the last finally block to avoid confusing EH */
5921 if (pending_abort && !finally_ips)
5922 EXCEPTION_CHECKPOINT;
5923 // goto main_loop instead of MINT_IN_DISPATCH helps the compiler and therefore conserves stack.
5924 // This is a slow/rare path and conserving stack is preferred over its performance otherwise.
5925 goto main_loop;
5927 ves_abort();
5928 MINT_IN_BREAK;
5931 MINT_IN_CASE(MINT_LEAVE)
5932 MINT_IN_CASE(MINT_LEAVE_S)
5933 MINT_IN_CASE(MINT_LEAVE_CHECK)
5934 MINT_IN_CASE(MINT_LEAVE_S_CHECK) {
5936 // Leave is split into pieces in order to consume less stack,
5937 // but not have to change how exception handling macros access labels and locals.
5939 g_assert (sp >= frame->stack);
5940 sp = frame->stack;
5941 frame->ip = ip;
5943 int opcode = *ip;
5944 gboolean const check = opcode == MINT_LEAVE_CHECK || opcode == MINT_LEAVE_S_CHECK;
5946 if (check && imethod->method->wrapper_type != MONO_WRAPPER_RUNTIME_INVOKE) {
5947 child_frame.parent = frame;
5948 child_frame.imethod = NULL;
5949 MonoException *abort_exc = mono_interp_leave (&child_frame);
5950 if (abort_exc)
5951 THROW_EX (abort_exc, frame->ip);
5954 opcode = *ip; // Refetch to avoid register/stack pressure.
5955 gboolean const short_offset = opcode == MINT_LEAVE_S || opcode == MINT_LEAVE_S_CHECK;
5956 ip += short_offset ? (short)*(ip + 1) : (gint32)READ32 (ip + 1);
5957 endfinally_ip = ip;
5958 GSList *old_list = finally_ips;
5959 MonoMethod *method = imethod->method;
5960 #if DEBUG_INTERP
5961 if (tracing)
5962 g_print ("* Handle finally IL_%04x\n", endfinally_ip == NULL ? 0 : endfinally_ip - imethod->code);
5963 #endif
5964 // FIXME Null check for imethod follows deref.
5965 if (imethod == NULL || (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
5966 || (method->iflags & (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL | METHOD_IMPL_ATTRIBUTE_RUNTIME))) {
5967 goto exit_frame;
5969 guint32 const ip_offset = frame->ip - imethod->code;
5971 if (endfinally_ip != NULL)
5972 finally_ips = g_slist_prepend (finally_ips, (void *)endfinally_ip);
5974 for (int i = imethod->num_clauses - 1; i >= 0; i--) {
5975 MonoExceptionClause* const clause = &imethod->clauses [i];
5976 if (MONO_OFFSET_IN_CLAUSE (clause, ip_offset) && (endfinally_ip == NULL || !(MONO_OFFSET_IN_CLAUSE (clause, endfinally_ip - imethod->code)))) {
5977 if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY) {
5978 ip = imethod->code + clause->handler_offset;
5979 finally_ips = g_slist_prepend (finally_ips, (gpointer) ip);
5980 #if DEBUG_INTERP
5981 if (tracing)
5982 g_print ("* Found finally at IL_%04x with exception: %s\n", clause->handler_offset, frame->ex? "yes": "no");
5983 #endif
5988 endfinally_ip = NULL;
5990 if (old_list != finally_ips && finally_ips) {
5991 ip = (const guint16*)finally_ips->data;
5992 finally_ips = g_slist_remove (finally_ips, ip);
5993 sp = frame->stack; /* spec says stack should be empty at endfinally so it should be at the start too */
5994 vt_sp = (unsigned char *) sp + imethod->stack_size;
5995 // goto main_loop instead of MINT_IN_DISPATCH helps the compiler and therefore conserves stack.
5996 // This is a slow/rare path and conserving stack is preferred over its performance otherwise.
5997 goto main_loop;
6000 ves_abort();
6001 MINT_IN_BREAK;
6003 MINT_IN_CASE(MINT_ICALL_V_V)
6004 MINT_IN_CASE(MINT_ICALL_V_P)
6005 MINT_IN_CASE(MINT_ICALL_P_V)
6006 MINT_IN_CASE(MINT_ICALL_P_P)
6007 MINT_IN_CASE(MINT_ICALL_PP_V)
6008 MINT_IN_CASE(MINT_ICALL_PP_P)
6009 MINT_IN_CASE(MINT_ICALL_PPP_V)
6010 MINT_IN_CASE(MINT_ICALL_PPP_P)
6011 MINT_IN_CASE(MINT_ICALL_PPPP_V)
6012 MINT_IN_CASE(MINT_ICALL_PPPP_P)
6013 MINT_IN_CASE(MINT_ICALL_PPPPP_V)
6014 MINT_IN_CASE(MINT_ICALL_PPPPP_P)
6015 MINT_IN_CASE(MINT_ICALL_PPPPPP_V)
6016 MINT_IN_CASE(MINT_ICALL_PPPPPP_P)
6017 frame->ip = ip;
6018 sp = do_icall_wrapper (frame, NULL, *ip, sp, imethod->data_items [*(guint16 *)(ip + 1)], FALSE);
6019 EXCEPTION_CHECKPOINT;
6020 CHECK_RESUME_STATE (context);
6021 ip += 2;
6022 MINT_IN_BREAK;
6023 MINT_IN_CASE(MINT_MONO_LDPTR)
6024 sp->data.p = imethod->data_items [*(guint16 *)(ip + 1)];
6025 ip += 2;
6026 ++sp;
6027 MINT_IN_BREAK;
6028 MINT_IN_CASE(MINT_MONO_NEWOBJ)
6029 sp->data.o = mono_interp_new (imethod->domain, (MonoClass*)imethod->data_items [*(guint16 *)(ip + 1)]); // FIXME: do not swallow the error
6030 ip += 2;
6031 sp++;
6032 MINT_IN_BREAK;
6033 MINT_IN_CASE(MINT_MONO_FREE)
6034 ++ip;
6035 --sp;
6036 g_error ("that doesn't seem right");
6037 g_free (sp->data.p);
6038 MINT_IN_BREAK;
6039 MINT_IN_CASE(MINT_MONO_RETOBJ)
6040 ++ip;
6041 sp--;
6042 stackval_from_data (mono_method_signature_internal (imethod->method)->ret, frame->retval, sp->data.p,
6043 mono_method_signature_internal (imethod->method)->pinvoke);
6044 if (sp > frame->stack)
6045 g_warning ("retobj: more values on stack: %d", sp-frame->stack);
6046 goto exit_frame;
6047 MINT_IN_CASE(MINT_MONO_SGEN_THREAD_INFO)
6048 sp->data.p = mono_tls_get_sgen_thread_info ();
6049 sp++;
6050 ++ip;
6051 MINT_IN_BREAK;
6052 MINT_IN_CASE(MINT_MONO_MEMORY_BARRIER) {
6053 ++ip;
6054 mono_memory_barrier ();
6055 MINT_IN_BREAK;
6057 MINT_IN_CASE(MINT_MONO_LDDOMAIN)
6058 sp->data.p = mono_domain_get ();
6059 ++sp;
6060 ++ip;
6061 MINT_IN_BREAK;
6062 MINT_IN_CASE(MINT_SDB_INTR_LOC)
6063 if (G_UNLIKELY (ss_enabled)) {
6064 typedef void (*T) (void);
6065 static T ss_tramp;
6067 if (!ss_tramp) {
6068 void *tramp = mini_get_single_step_trampoline ();
6069 mono_memory_barrier ();
6070 ss_tramp = (T)tramp;
6074 * Make this point to the MINT_SDB_SEQ_POINT instruction which follows this since
6075 * the address of that instruction is stored as the seq point address.
6077 frame->ip = ip + 1;
6080 * Use the same trampoline as the JIT. This ensures that
6081 * the debugger has the context for the last interpreter
6082 * native frame.
6084 do_debugger_tramp (ss_tramp, frame);
6086 CHECK_RESUME_STATE (context);
6088 ++ip;
6089 MINT_IN_BREAK;
6090 MINT_IN_CASE(MINT_SDB_SEQ_POINT)
6091 /* Just a placeholder for a breakpoint */
6092 ++ip;
6093 MINT_IN_BREAK;
6094 MINT_IN_CASE(MINT_SDB_BREAKPOINT) {
6095 typedef void (*T) (void);
6096 static T bp_tramp;
6097 if (!bp_tramp) {
6098 void *tramp = mini_get_breakpoint_trampoline ();
6099 mono_memory_barrier ();
6100 bp_tramp = (T)tramp;
6103 frame->ip = ip;
6105 /* Use the same trampoline as the JIT */
6106 do_debugger_tramp (bp_tramp, frame);
6108 CHECK_RESUME_STATE (context);
6110 ++ip;
6111 MINT_IN_BREAK;
6114 #define RELOP(datamem, op) \
6115 --sp; \
6116 sp [-1].data.i = sp [-1].data.datamem op sp [0].data.datamem; \
6117 ++ip;
6119 #define RELOP_FP(datamem, op, noorder) \
6120 --sp; \
6121 if (mono_isunordered (sp [-1].data.datamem, sp [0].data.datamem)) \
6122 sp [-1].data.i = noorder; \
6123 else \
6124 sp [-1].data.i = sp [-1].data.datamem op sp [0].data.datamem; \
6125 ++ip;
6127 MINT_IN_CASE(MINT_CEQ_I4)
6128 RELOP(i, ==);
6129 MINT_IN_BREAK;
6130 MINT_IN_CASE(MINT_CEQ0_I4)
6131 sp [-1].data.i = (sp [-1].data.i == 0);
6132 ++ip;
6133 MINT_IN_BREAK;
6134 MINT_IN_CASE(MINT_CEQ_I8)
6135 RELOP(l, ==);
6136 MINT_IN_BREAK;
6137 MINT_IN_CASE(MINT_CEQ_R4)
6138 RELOP_FP(f_r4, ==, 0);
6139 MINT_IN_BREAK;
6140 MINT_IN_CASE(MINT_CEQ_R8)
6141 RELOP_FP(f, ==, 0);
6142 MINT_IN_BREAK;
6143 MINT_IN_CASE(MINT_CNE_I4)
6144 RELOP(i, !=);
6145 MINT_IN_BREAK;
6146 MINT_IN_CASE(MINT_CNE_I8)
6147 RELOP(l, !=);
6148 MINT_IN_BREAK;
6149 MINT_IN_CASE(MINT_CNE_R4)
6150 RELOP_FP(f_r4, !=, 1);
6151 MINT_IN_BREAK;
6152 MINT_IN_CASE(MINT_CNE_R8)
6153 RELOP_FP(f, !=, 1);
6154 MINT_IN_BREAK;
6155 MINT_IN_CASE(MINT_CGT_I4)
6156 RELOP(i, >);
6157 MINT_IN_BREAK;
6158 MINT_IN_CASE(MINT_CGT_I8)
6159 RELOP(l, >);
6160 MINT_IN_BREAK;
6161 MINT_IN_CASE(MINT_CGT_R4)
6162 RELOP_FP(f_r4, >, 0);
6163 MINT_IN_BREAK;
6164 MINT_IN_CASE(MINT_CGT_R8)
6165 RELOP_FP(f, >, 0);
6166 MINT_IN_BREAK;
6167 MINT_IN_CASE(MINT_CGE_I4)
6168 RELOP(i, >=);
6169 MINT_IN_BREAK;
6170 MINT_IN_CASE(MINT_CGE_I8)
6171 RELOP(l, >=);
6172 MINT_IN_BREAK;
6173 MINT_IN_CASE(MINT_CGE_R4)
6174 RELOP_FP(f_r4, >=, 0);
6175 MINT_IN_BREAK;
6176 MINT_IN_CASE(MINT_CGE_R8)
6177 RELOP_FP(f, >=, 0);
6178 MINT_IN_BREAK;
6180 #define RELOP_CAST(datamem, op, type) \
6181 --sp; \
6182 sp [-1].data.i = (type)sp [-1].data.datamem op (type)sp [0].data.datamem; \
6183 ++ip;
6185 MINT_IN_CASE(MINT_CGE_UN_I4)
6186 RELOP_CAST(l, >=, guint32);
6187 MINT_IN_BREAK;
6188 MINT_IN_CASE(MINT_CGE_UN_I8)
6189 RELOP_CAST(l, >=, guint64);
6190 MINT_IN_BREAK;
6192 MINT_IN_CASE(MINT_CGT_UN_I4)
6193 RELOP_CAST(i, >, guint32);
6194 MINT_IN_BREAK;
6195 MINT_IN_CASE(MINT_CGT_UN_I8)
6196 RELOP_CAST(l, >, guint64);
6197 MINT_IN_BREAK;
6198 MINT_IN_CASE(MINT_CGT_UN_R4)
6199 RELOP_FP(f_r4, >, 1);
6200 MINT_IN_BREAK;
6201 MINT_IN_CASE(MINT_CGT_UN_R8)
6202 RELOP_FP(f, >, 1);
6203 MINT_IN_BREAK;
6204 MINT_IN_CASE(MINT_CLT_I4)
6205 RELOP(i, <);
6206 MINT_IN_BREAK;
6207 MINT_IN_CASE(MINT_CLT_I8)
6208 RELOP(l, <);
6209 MINT_IN_BREAK;
6210 MINT_IN_CASE(MINT_CLT_R4)
6211 RELOP_FP(f_r4, <, 0);
6212 MINT_IN_BREAK;
6213 MINT_IN_CASE(MINT_CLT_R8)
6214 RELOP_FP(f, <, 0);
6215 MINT_IN_BREAK;
6216 MINT_IN_CASE(MINT_CLT_UN_I4)
6217 RELOP_CAST(i, <, guint32);
6218 MINT_IN_BREAK;
6219 MINT_IN_CASE(MINT_CLT_UN_I8)
6220 RELOP_CAST(l, <, guint64);
6221 MINT_IN_BREAK;
6222 MINT_IN_CASE(MINT_CLT_UN_R4)
6223 RELOP_FP(f_r4, <, 1);
6224 MINT_IN_BREAK;
6225 MINT_IN_CASE(MINT_CLT_UN_R8)
6226 RELOP_FP(f, <, 1);
6227 MINT_IN_BREAK;
6228 MINT_IN_CASE(MINT_CLE_I4)
6229 RELOP(i, <=);
6230 MINT_IN_BREAK;
6231 MINT_IN_CASE(MINT_CLE_I8)
6232 RELOP(l, <=);
6233 MINT_IN_BREAK;
6234 MINT_IN_CASE(MINT_CLE_UN_I4)
6235 RELOP_CAST(l, <=, guint32);
6236 MINT_IN_BREAK;
6237 MINT_IN_CASE(MINT_CLE_UN_I8)
6238 RELOP_CAST(l, <=, guint64);
6239 MINT_IN_BREAK;
6240 MINT_IN_CASE(MINT_CLE_R4)
6241 RELOP_FP(f_r4, <=, 0);
6242 MINT_IN_BREAK;
6243 MINT_IN_CASE(MINT_CLE_R8)
6244 RELOP_FP(f, <=, 0);
6245 MINT_IN_BREAK;
6247 #undef RELOP
6248 #undef RELOP_FP
6249 #undef RELOP_CAST
6251 MINT_IN_CASE(MINT_LDFTN) {
6252 sp->data.p = imethod->data_items [* (guint16 *)(ip + 1)];
6253 ++sp;
6254 ip += 2;
6255 MINT_IN_BREAK;
6257 MINT_IN_CASE(MINT_LDVIRTFTN) {
6258 InterpMethod *m = (InterpMethod*)imethod->data_items [* (guint16 *)(ip + 1)];
6259 --sp;
6260 NULL_CHECK (sp->data.p);
6262 sp->data.p = get_virtual_method (m, sp->data.o->vtable);
6263 ip += 2;
6264 ++sp;
6265 MINT_IN_BREAK;
6267 MINT_IN_CASE(MINT_LDFTN_DYNAMIC) {
6268 MONO_API_ERROR_INIT (error);
6269 InterpMethod *m = mono_interp_get_imethod (mono_domain_get (), (MonoMethod*) sp [-1].data.p, error);
6270 mono_error_assert_ok (error);
6271 sp [-1].data.p = m;
6272 ip++;
6273 MINT_IN_BREAK;
6276 #define LDARG(datamem, argtype) \
6277 sp->data.datamem = (argtype) frame->stack_args [*(guint16 *)(ip + 1)].data.datamem; \
6278 ip += 2; \
6279 ++sp;
6281 MINT_IN_CASE(MINT_LDARG_I1) LDARG(i, gint8); MINT_IN_BREAK;
6282 MINT_IN_CASE(MINT_LDARG_U1) LDARG(i, guint8); MINT_IN_BREAK;
6283 MINT_IN_CASE(MINT_LDARG_I2) LDARG(i, gint16); MINT_IN_BREAK;
6284 MINT_IN_CASE(MINT_LDARG_U2) LDARG(i, guint16); MINT_IN_BREAK;
6285 MINT_IN_CASE(MINT_LDARG_I4) LDARG(i, gint32); MINT_IN_BREAK;
6286 MINT_IN_CASE(MINT_LDARG_I8) LDARG(l, gint64); MINT_IN_BREAK;
6287 MINT_IN_CASE(MINT_LDARG_R4) LDARG(f_r4, float); MINT_IN_BREAK;
6288 MINT_IN_CASE(MINT_LDARG_R8) LDARG(f, double); MINT_IN_BREAK;
6289 MINT_IN_CASE(MINT_LDARG_O) LDARG(p, gpointer); MINT_IN_BREAK;
6290 MINT_IN_CASE(MINT_LDARG_P) LDARG(p, gpointer); MINT_IN_BREAK;
6292 MINT_IN_CASE(MINT_LDARG_VT) {
6293 sp->data.p = vt_sp;
6294 int const i32 = READ32 (ip + 2);
6295 memcpy(sp->data.p, frame->stack_args [* (guint16 *)(ip + 1)].data.p, i32);
6296 vt_sp += ALIGN_TO (i32, MINT_VT_ALIGNMENT);
6297 ip += 4;
6298 ++sp;
6299 MINT_IN_BREAK;
6302 #define STARG(datamem, argtype) \
6303 --sp; \
6304 frame->stack_args [*(guint16 *)(ip + 1)].data.datamem = (argtype) sp->data.datamem; \
6305 ip += 2; \
6307 MINT_IN_CASE(MINT_STARG_I1) STARG(i, gint8); MINT_IN_BREAK;
6308 MINT_IN_CASE(MINT_STARG_U1) STARG(i, guint8); MINT_IN_BREAK;
6309 MINT_IN_CASE(MINT_STARG_I2) STARG(i, gint16); MINT_IN_BREAK;
6310 MINT_IN_CASE(MINT_STARG_U2) STARG(i, guint16); MINT_IN_BREAK;
6311 MINT_IN_CASE(MINT_STARG_I4) STARG(i, gint32); MINT_IN_BREAK;
6312 MINT_IN_CASE(MINT_STARG_I8) STARG(l, gint64); MINT_IN_BREAK;
6313 MINT_IN_CASE(MINT_STARG_R4) STARG(f_r4, float); MINT_IN_BREAK;
6314 MINT_IN_CASE(MINT_STARG_R8) STARG(f, double); MINT_IN_BREAK;
6315 MINT_IN_CASE(MINT_STARG_O) STARG(p, gpointer); MINT_IN_BREAK;
6316 MINT_IN_CASE(MINT_STARG_P) STARG(p, gpointer); MINT_IN_BREAK;
6318 MINT_IN_CASE(MINT_STARG_VT) {
6319 int const i32 = READ32 (ip + 2);
6320 --sp;
6321 memcpy(frame->stack_args [* (guint16 *)(ip + 1)].data.p, sp->data.p, i32);
6322 vt_sp -= ALIGN_TO (i32, MINT_VT_ALIGNMENT);
6323 ip += 4;
6324 MINT_IN_BREAK;
6326 MINT_IN_CASE(MINT_PROF_ENTER) {
6327 ip += 1;
6329 if (MONO_PROFILER_ENABLED (method_enter)) {
6330 MonoProfilerCallContext *prof_ctx = NULL;
6332 if (imethod->prof_flags & MONO_PROFILER_CALL_INSTRUMENTATION_ENTER_CONTEXT) {
6333 prof_ctx = g_new0 (MonoProfilerCallContext, 1);
6334 prof_ctx->interp_frame = frame;
6335 prof_ctx->method = imethod->method;
6338 MONO_PROFILER_RAISE (method_enter, (imethod->method, prof_ctx));
6340 g_free (prof_ctx);
6343 MINT_IN_BREAK;
6346 MINT_IN_CASE(MINT_TRACE_ENTER) {
6347 ip += 1;
6349 MonoProfilerCallContext *prof_ctx = g_alloca (sizeof (MonoProfilerCallContext));
6350 prof_ctx->interp_frame = frame;
6351 prof_ctx->method = imethod->method;
6353 mono_trace_enter_method (imethod->method, prof_ctx);
6354 MINT_IN_BREAK;
6357 MINT_IN_CASE(MINT_TRACE_EXIT) {
6358 // Set retval
6359 int const i32 = READ32 (ip + 1);
6360 --sp;
6361 if (i32 == -1)
6363 else if (i32)
6364 memcpy(frame->retval->data.p, sp->data.p, i32);
6365 else
6366 *frame->retval = *sp;
6368 MonoProfilerCallContext *prof_ctx = g_alloca (sizeof (MonoProfilerCallContext));
6369 prof_ctx->interp_frame = frame;
6370 prof_ctx->method = imethod->method;
6372 mono_trace_leave_method (imethod->method, prof_ctx);
6373 ip += 3;
6374 goto exit_frame;
6377 MINT_IN_CASE(MINT_LDARGA)
6378 sp->data.p = &frame->stack_args [* (guint16 *)(ip + 1)];
6379 ip += 2;
6380 ++sp;
6381 MINT_IN_BREAK;
6383 MINT_IN_CASE(MINT_LDARGA_VT)
6384 sp->data.p = frame->stack_args [* (guint16 *)(ip + 1)].data.p;
6385 ip += 2;
6386 ++sp;
6387 MINT_IN_BREAK;
6389 #define LDLOC(datamem, argtype) \
6390 sp->data.datamem = * (argtype *)(locals + * (guint16 *)(ip + 1)); \
6391 ip += 2; \
6392 ++sp;
6394 MINT_IN_CASE(MINT_LDLOC_I1) LDLOC(i, gint8); MINT_IN_BREAK;
6395 MINT_IN_CASE(MINT_LDLOC_U1) LDLOC(i, guint8); MINT_IN_BREAK;
6396 MINT_IN_CASE(MINT_LDLOC_I2) LDLOC(i, gint16); MINT_IN_BREAK;
6397 MINT_IN_CASE(MINT_LDLOC_U2) LDLOC(i, guint16); MINT_IN_BREAK;
6398 MINT_IN_CASE(MINT_LDLOC_I4) LDLOC(i, gint32); MINT_IN_BREAK;
6399 MINT_IN_CASE(MINT_LDLOC_I8) LDLOC(l, gint64); MINT_IN_BREAK;
6400 MINT_IN_CASE(MINT_LDLOC_R4) LDLOC(f_r4, float); MINT_IN_BREAK;
6401 MINT_IN_CASE(MINT_LDLOC_R8) LDLOC(f, double); MINT_IN_BREAK;
6402 MINT_IN_CASE(MINT_LDLOC_O) LDLOC(p, gpointer); MINT_IN_BREAK;
6403 MINT_IN_CASE(MINT_LDLOC_P) LDLOC(p, gpointer); MINT_IN_BREAK;
6405 MINT_IN_CASE(MINT_LDLOC_VT) {
6406 sp->data.p = vt_sp;
6407 int const i32 = READ32 (ip + 2);
6408 memcpy(sp->data.p, locals + * (guint16 *)(ip + 1), i32);
6409 vt_sp += ALIGN_TO (i32, MINT_VT_ALIGNMENT);
6410 ip += 4;
6411 ++sp;
6412 MINT_IN_BREAK;
6414 MINT_IN_CASE(MINT_LDLOCA_S)
6415 sp->data.p = locals + * (guint16 *)(ip + 1);
6416 ip += 2;
6417 ++sp;
6418 MINT_IN_BREAK;
6420 #define STLOC(datamem, argtype) \
6421 --sp; \
6422 * (argtype *)(locals + * (guint16 *)(ip + 1)) = sp->data.datamem; \
6423 ip += 2;
6425 MINT_IN_CASE(MINT_STLOC_I1) STLOC(i, gint8); MINT_IN_BREAK;
6426 MINT_IN_CASE(MINT_STLOC_U1) STLOC(i, guint8); MINT_IN_BREAK;
6427 MINT_IN_CASE(MINT_STLOC_I2) STLOC(i, gint16); MINT_IN_BREAK;
6428 MINT_IN_CASE(MINT_STLOC_U2) STLOC(i, guint16); MINT_IN_BREAK;
6429 MINT_IN_CASE(MINT_STLOC_I4) STLOC(i, gint32); MINT_IN_BREAK;
6430 MINT_IN_CASE(MINT_STLOC_I8) STLOC(l, gint64); MINT_IN_BREAK;
6431 MINT_IN_CASE(MINT_STLOC_R4) STLOC(f_r4, float); MINT_IN_BREAK;
6432 MINT_IN_CASE(MINT_STLOC_R8) STLOC(f, double); MINT_IN_BREAK;
6433 MINT_IN_CASE(MINT_STLOC_O) STLOC(p, gpointer); MINT_IN_BREAK;
6434 MINT_IN_CASE(MINT_STLOC_P) STLOC(p, gpointer); MINT_IN_BREAK;
6436 #define STLOC_NP(datamem, argtype) \
6437 * (argtype *)(locals + * (guint16 *)(ip + 1)) = sp [-1].data.datamem; \
6438 ip += 2;
6440 MINT_IN_CASE(MINT_STLOC_NP_I4) STLOC_NP(i, gint32); MINT_IN_BREAK;
6441 MINT_IN_CASE(MINT_STLOC_NP_O) STLOC_NP(p, gpointer); MINT_IN_BREAK;
6443 MINT_IN_CASE(MINT_STLOC_VT) {
6444 int const i32 = READ32 (ip + 2);
6445 --sp;
6446 memcpy(locals + * (guint16 *)(ip + 1), sp->data.p, i32);
6447 vt_sp -= ALIGN_TO (i32, MINT_VT_ALIGNMENT);
6448 ip += 4;
6449 MINT_IN_BREAK;
6451 MINT_IN_CASE(MINT_LOCALLOC) {
6452 if (sp != frame->stack + 1) /*FIX?*/
6453 THROW_EX (mono_get_exception_execution_engine (NULL), ip);
6455 int len = sp [-1].data.i;
6456 sp [-1].data.p = alloca (len);
6458 if (imethod->init_locals)
6459 memset (sp [-1].data.p, 0, len);
6460 ++ip;
6461 MINT_IN_BREAK;
6463 MINT_IN_CASE(MINT_ENDFILTER)
6464 /* top of stack is result of filter */
6465 frame->retval = &sp [-1];
6466 goto exit_frame;
6467 MINT_IN_CASE(MINT_INITOBJ)
6468 --sp;
6469 memset (sp->data.vt, 0, READ32(ip + 1));
6470 ip += 3;
6471 MINT_IN_BREAK;
6472 MINT_IN_CASE(MINT_CPBLK)
6473 sp -= 3;
6474 if (!sp [0].data.p || !sp [1].data.p)
6475 THROW_EX (mono_get_exception_null_reference(), ip - 1);
6476 ++ip;
6477 /* FIXME: value and size may be int64... */
6478 memcpy (sp [0].data.p, sp [1].data.p, sp [2].data.i);
6479 MINT_IN_BREAK;
6480 #if 0
6481 MINT_IN_CASE(MINT_CONSTRAINED_) {
6482 guint32 token;
6483 /* FIXME: implement */
6484 ++ip;
6485 token = READ32 (ip);
6486 ip += 2;
6487 MINT_IN_BREAK;
6489 #endif
6490 MINT_IN_CASE(MINT_INITBLK)
6491 sp -= 3;
6492 NULL_CHECK (sp [0].data.p);
6493 ++ip;
6494 /* FIXME: value and size may be int64... */
6495 memset (sp [0].data.p, sp [1].data.i, sp [2].data.i);
6496 MINT_IN_BREAK;
6497 #if 0
6498 MINT_IN_CASE(MINT_NO_)
6499 /* FIXME: implement */
6500 ip += 2;
6501 MINT_IN_BREAK;
6502 #endif
6503 MINT_IN_CASE(MINT_RETHROW) {
6504 int exvar_offset = *(guint16*)(ip + 1);
6505 THROW_EX_GENERAL (*(MonoException**)(frame_locals (frame) + exvar_offset), ip, TRUE);
6506 MINT_IN_BREAK;
6508 MINT_IN_CASE(MINT_MONO_RETHROW) {
6510 * need to clarify what this should actually do:
6512 * Takes an exception from the stack and rethrows it.
6513 * This is useful for wrappers that don't want to have to
6514 * use CEE_THROW and lose the exception stacktrace.
6517 --sp;
6518 if (!sp->data.p)
6519 sp->data.p = mono_get_exception_null_reference ();
6521 THROW_EX_GENERAL ((MonoException *)sp->data.p, ip, TRUE);
6522 MINT_IN_BREAK;
6524 MINT_IN_CASE(MINT_LD_DELEGATE_METHOD_PTR) {
6525 MonoDelegate *del;
6527 --sp;
6528 del = (MonoDelegate*)sp->data.p;
6529 if (!del->interp_method) {
6530 /* Not created from interpreted code */
6531 MONO_API_ERROR_INIT (error);
6532 g_assert (del->method);
6533 del->interp_method = mono_interp_get_imethod (del->object.vtable->domain, del->method, error);
6534 mono_error_assert_ok (error);
6536 g_assert (del->interp_method);
6537 sp->data.p = del->interp_method;
6538 ++sp;
6539 ip += 1;
6540 MINT_IN_BREAK;
6542 MINT_IN_CASE(MINT_LD_DELEGATE_INVOKE_IMPL) {
6543 MonoDelegate *del;
6544 int n = *(guint16*)(ip + 1);
6545 del = (MonoDelegate*)sp [-n].data.p;
6546 if (!del->interp_invoke_impl) {
6548 * First time we are called. Set up the invoke wrapper. We might be able to do this
6549 * in ctor but we would need to handle AllocDelegateLike_internal separately
6551 MONO_API_ERROR_INIT (error);
6552 MonoMethod *invoke = mono_get_delegate_invoke_internal (del->object.vtable->klass);
6553 del->interp_invoke_impl = mono_interp_get_imethod (del->object.vtable->domain, mono_marshal_get_delegate_invoke (invoke, del), error);
6554 mono_error_assert_ok (error);
6556 sp ++;
6557 sp [-1].data.p = del->interp_invoke_impl;
6558 ip += 2;
6559 MINT_IN_BREAK;
6562 #define MATH_UNOP(mathfunc) \
6563 sp [-1].data.f = mathfunc (sp [-1].data.f); \
6564 ++ip;
6566 MINT_IN_CASE(MINT_ABS) MATH_UNOP(fabs); MINT_IN_BREAK;
6567 MINT_IN_CASE(MINT_ASIN) MATH_UNOP(asin); MINT_IN_BREAK;
6568 MINT_IN_CASE(MINT_ASINH) MATH_UNOP(asinh); MINT_IN_BREAK;
6569 MINT_IN_CASE(MINT_ACOS) MATH_UNOP(acos); MINT_IN_BREAK;
6570 MINT_IN_CASE(MINT_ACOSH) MATH_UNOP(acosh); MINT_IN_BREAK;
6571 MINT_IN_CASE(MINT_ATAN) MATH_UNOP(atan); MINT_IN_BREAK;
6572 MINT_IN_CASE(MINT_ATANH) MATH_UNOP(atanh); MINT_IN_BREAK;
6573 MINT_IN_CASE(MINT_COS) MATH_UNOP(cos); MINT_IN_BREAK;
6574 MINT_IN_CASE(MINT_CBRT) MATH_UNOP(cbrt); MINT_IN_BREAK;
6575 MINT_IN_CASE(MINT_COSH) MATH_UNOP(cosh); MINT_IN_BREAK;
6576 MINT_IN_CASE(MINT_SIN) MATH_UNOP(sin); MINT_IN_BREAK;
6577 MINT_IN_CASE(MINT_SQRT) MATH_UNOP(sqrt); MINT_IN_BREAK;
6578 MINT_IN_CASE(MINT_SINH) MATH_UNOP(sinh); MINT_IN_BREAK;
6579 MINT_IN_CASE(MINT_TAN) MATH_UNOP(tan); MINT_IN_BREAK;
6580 MINT_IN_CASE(MINT_TANH) MATH_UNOP(tanh); MINT_IN_BREAK;
6582 MINT_IN_CASE(MINT_INTRINS_ENUM_HASFLAG) {
6583 MonoClass *klass = (MonoClass*)imethod->data_items[* (guint16 *)(ip + 1)];
6584 mono_interp_enum_hasflag (sp, klass);
6585 sp--;
6586 ip += 2;
6587 MINT_IN_BREAK;
6589 MINT_IN_CASE(MINT_INTRINS_GET_HASHCODE) {
6590 sp [-1].data.i = mono_object_hash_internal (sp [-1].data.o);
6591 ip++;
6592 MINT_IN_BREAK;
6594 MINT_IN_CASE(MINT_INTRINS_GET_TYPE) {
6595 NULL_CHECK (sp [-1].data.p);
6596 sp [-1].data.o = (MonoObject*) sp [-1].data.o->vtable->type;
6597 ip++;
6598 MINT_IN_BREAK;
6601 MINT_IN_DEFAULT
6602 g_error ("Unimplemented opcode: %04x %s at 0x%x\n", *ip, mono_interp_opname[*ip], ip-imethod->code);
6606 g_assert_not_reached ();
6608 exit_frame:
6609 error_init_reuse (error);
6611 if (clause_args && clause_args->base_frame)
6612 memcpy (clause_args->base_frame->stack, frame->stack, imethod->alloca_size);
6614 if (!frame->ex && MONO_PROFILER_ENABLED (method_leave) &&
6615 imethod->prof_flags & MONO_PROFILER_CALL_INSTRUMENTATION_LEAVE) {
6616 MonoProfilerCallContext *prof_ctx = NULL;
6618 if (imethod->prof_flags & MONO_PROFILER_CALL_INSTRUMENTATION_LEAVE_CONTEXT) {
6619 prof_ctx = g_new0 (MonoProfilerCallContext, 1);
6620 prof_ctx->interp_frame = frame;
6621 prof_ctx->method = imethod->method;
6623 MonoType *rtype = mono_method_signature_internal (imethod->method)->ret;
6625 switch (rtype->type) {
6626 case MONO_TYPE_VOID:
6627 break;
6628 case MONO_TYPE_VALUETYPE:
6629 prof_ctx->return_value = frame->retval->data.p;
6630 break;
6631 default:
6632 prof_ctx->return_value = frame->retval;
6633 break;
6637 MONO_PROFILER_RAISE (method_leave, (imethod->method, prof_ctx));
6639 g_free (prof_ctx);
6640 } else if (frame->ex && imethod->prof_flags & MONO_PROFILER_CALL_INSTRUMENTATION_EXCEPTION_LEAVE)
6641 MONO_PROFILER_RAISE (method_exception_leave, (imethod->method, &frame->ex->object));
6643 DEBUG_LEAVE ();
6646 static void
6647 interp_parse_options (const char *options)
6649 char **args, **ptr;
6651 if (!options)
6652 return;
6654 args = g_strsplit (options, ",", -1);
6655 for (ptr = args; ptr && *ptr; ptr ++) {
6656 char *arg = *ptr;
6658 if (strncmp (arg, "jit=", 4) == 0)
6659 mono_interp_jit_classes = g_slist_prepend (mono_interp_jit_classes, arg + 4);
6660 if (strncmp (arg, "interp-only=", 4) == 0)
6661 mono_interp_only_classes = g_slist_prepend (mono_interp_only_classes, arg + strlen ("interp-only="));
6662 if (strncmp (arg, "-inline", 7) == 0)
6663 mono_interp_opt &= ~INTERP_OPT_INLINE;
6668 * interp_set_resume_state:
6670 * Set the state the interpeter will continue to execute from after execution returns to the interpreter.
6672 static void
6673 interp_set_resume_state (MonoJitTlsData *jit_tls, MonoException *ex, MonoJitExceptionInfo *ei, MonoInterpFrameHandle interp_frame, gpointer handler_ip)
6675 ThreadContext *context;
6677 g_assert (jit_tls);
6678 context = (ThreadContext*)jit_tls->interp_context;
6679 g_assert (context);
6681 context->has_resume_state = TRUE;
6682 context->handler_frame = (InterpFrame*)interp_frame;
6683 context->handler_ei = ei;
6684 /* This is on the stack, so it doesn't need a wbarrier */
6685 context->handler_frame->ex = ex;
6686 /* Ditto */
6687 if (ei)
6688 *(MonoException**)(frame_locals (context->handler_frame) + ei->exvar_offset) = ex;
6689 context->handler_ip = (guint16*) handler_ip;
6692 static void
6693 interp_get_resume_state (const MonoJitTlsData *jit_tls, gboolean *has_resume_state, MonoInterpFrameHandle *interp_frame, gpointer *handler_ip)
6695 g_assert (jit_tls);
6696 ThreadContext *context = (ThreadContext*)jit_tls->interp_context;
6697 g_assert (context);
6698 *has_resume_state = context->has_resume_state;
6699 if (context->has_resume_state) {
6700 *interp_frame = context->handler_frame;
6701 *handler_ip = context->handler_ip;
6706 * interp_run_finally:
6708 * Run the finally clause identified by CLAUSE_INDEX in the intepreter frame given by
6709 * frame->interp_frame.
6710 * Return TRUE if the finally clause threw an exception.
6712 static gboolean
6713 interp_run_finally (StackFrameInfo *frame, int clause_index, gpointer handler_ip, gpointer handler_ip_end)
6715 InterpFrame *iframe = (InterpFrame*)frame->interp_frame;
6716 ThreadContext *context = get_context ();
6717 const unsigned short *old_ip = iframe->ip;
6718 FrameClauseArgs clause_args;
6720 memset (&clause_args, 0, sizeof (FrameClauseArgs));
6721 clause_args.start_with_ip = (guint16*) handler_ip;
6722 clause_args.end_at_ip = (guint16*) handler_ip_end;
6723 clause_args.exit_clause = clause_index;
6725 ERROR_DECL (error);
6726 interp_exec_method_full (iframe, context, &clause_args, error);
6727 if (context->has_resume_state) {
6728 return TRUE;
6729 } else {
6730 iframe->ip = old_ip;
6731 return FALSE;
6736 * interp_run_filter:
6738 * Run the filter clause identified by CLAUSE_INDEX in the intepreter frame given by
6739 * frame->interp_frame.
6741 static gboolean
6742 interp_run_filter (StackFrameInfo *frame, MonoException *ex, int clause_index, gpointer handler_ip, gpointer handler_ip_end)
6744 InterpFrame *iframe = (InterpFrame*)frame->interp_frame;
6745 ThreadContext *context = get_context ();
6746 InterpFrame child_frame;
6747 stackval retval;
6748 FrameClauseArgs clause_args;
6751 * Have to run the clause in a new frame which is a copy of IFRAME, since
6752 * during debugging, there are two copies of the frame on the stack.
6754 memset (&child_frame, 0, sizeof (InterpFrame));
6755 child_frame.imethod = iframe->imethod;
6756 child_frame.retval = &retval;
6757 child_frame.parent = iframe;
6758 child_frame.stack_args = iframe->stack_args;
6760 memset (&clause_args, 0, sizeof (FrameClauseArgs));
6761 clause_args.start_with_ip = (guint16*) handler_ip;
6762 clause_args.end_at_ip = (guint16*) handler_ip_end;
6763 clause_args.filter_exception = ex;
6764 clause_args.base_frame = iframe;
6766 ERROR_DECL (error);
6767 interp_exec_method_full (&child_frame, context, &clause_args, error);
6768 /* ENDFILTER stores the result into child_frame->retval */
6769 return child_frame.retval->data.i ? TRUE : FALSE;
6772 typedef struct {
6773 InterpFrame *current;
6774 } StackIter;
6777 * interp_frame_iter_init:
6779 * Initialize an iterator for iterating through interpreted frames.
6781 static void
6782 interp_frame_iter_init (MonoInterpStackIter *iter, gpointer interp_exit_data)
6784 StackIter *stack_iter = (StackIter*)iter;
6786 stack_iter->current = (InterpFrame*)interp_exit_data;
6790 * interp_frame_iter_next:
6792 * Fill out FRAME with date for the next interpreter frame.
6794 static gboolean
6795 interp_frame_iter_next (MonoInterpStackIter *iter, StackFrameInfo *frame)
6797 StackIter *stack_iter = (StackIter*)iter;
6798 InterpFrame *iframe = stack_iter->current;
6800 memset (frame, 0, sizeof (StackFrameInfo));
6801 /* pinvoke frames doesn't have imethod set */
6802 while (iframe && !(iframe->imethod && iframe->imethod->code && iframe->imethod->jinfo))
6803 iframe = iframe->parent;
6804 if (!iframe)
6805 return FALSE;
6807 MonoMethod *method = iframe->imethod->method;
6808 frame->domain = iframe->imethod->domain;
6809 frame->interp_frame = iframe;
6810 frame->method = method;
6811 frame->actual_method = method;
6812 if (method && ((method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) || (method->iflags & (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL | METHOD_IMPL_ATTRIBUTE_RUNTIME)))) {
6813 frame->native_offset = -1;
6814 frame->type = FRAME_TYPE_MANAGED_TO_NATIVE;
6815 } else {
6816 frame->type = FRAME_TYPE_INTERP;
6817 /* This is the offset in the interpreter IR */
6818 frame->native_offset = (guint8*)iframe->ip - (guint8*)iframe->imethod->code;
6819 if (!method->wrapper_type || method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD)
6820 frame->managed = TRUE;
6822 frame->ji = iframe->imethod->jinfo;
6823 frame->frame_addr = iframe;
6825 stack_iter->current = iframe->parent;
6827 return TRUE;
6830 static MonoJitInfo*
6831 interp_find_jit_info (MonoDomain *domain, MonoMethod *method)
6833 InterpMethod* imethod;
6835 imethod = lookup_imethod (domain, method);
6836 if (imethod)
6837 return imethod->jinfo;
6838 else
6839 return NULL;
6842 static void
6843 interp_set_breakpoint (MonoJitInfo *jinfo, gpointer ip)
6845 guint16 *code = (guint16*)ip;
6846 g_assert (*code == MINT_SDB_SEQ_POINT);
6847 *code = MINT_SDB_BREAKPOINT;
6850 static void
6851 interp_clear_breakpoint (MonoJitInfo *jinfo, gpointer ip)
6853 guint16 *code = (guint16*)ip;
6854 g_assert (*code == MINT_SDB_BREAKPOINT);
6855 *code = MINT_SDB_SEQ_POINT;
6858 static MonoJitInfo*
6859 interp_frame_get_jit_info (MonoInterpFrameHandle frame)
6861 InterpFrame *iframe = (InterpFrame*)frame;
6863 g_assert (iframe->imethod);
6864 return iframe->imethod->jinfo;
6867 static gpointer
6868 interp_frame_get_ip (MonoInterpFrameHandle frame)
6870 InterpFrame *iframe = (InterpFrame*)frame;
6872 g_assert (iframe->imethod);
6873 return (gpointer)iframe->ip;
6876 static gpointer
6877 interp_frame_get_arg (MonoInterpFrameHandle frame, int pos)
6879 InterpFrame *iframe = (InterpFrame*)frame;
6880 MonoMethodSignature *sig;
6882 g_assert (iframe->imethod);
6884 sig = mono_method_signature_internal (iframe->imethod->method);
6885 return stackval_to_data_addr (sig->params [pos], &iframe->stack_args [pos + !!iframe->imethod->hasthis]);
6888 static gpointer
6889 interp_frame_get_local (MonoInterpFrameHandle frame, int pos)
6891 InterpFrame *iframe = (InterpFrame*)frame;
6893 g_assert (iframe->imethod);
6895 return frame_locals (iframe) + iframe->imethod->local_offsets [pos];
6898 static gpointer
6899 interp_frame_get_this (MonoInterpFrameHandle frame)
6901 InterpFrame *iframe = (InterpFrame*)frame;
6903 g_assert (iframe->imethod);
6904 g_assert (iframe->imethod->hasthis);
6905 return &iframe->stack_args [0].data.p;
6908 static MonoInterpFrameHandle
6909 interp_frame_get_parent (MonoInterpFrameHandle frame)
6911 InterpFrame *iframe = (InterpFrame*)frame;
6913 return iframe->parent;
6916 static gpointer
6917 interp_frame_get_res (MonoInterpFrameHandle frame)
6919 InterpFrame *iframe = (InterpFrame*)frame;
6920 MonoMethodSignature *sig;
6922 g_assert (iframe->imethod);
6923 sig = mono_method_signature_internal (iframe->imethod->method);
6924 if (sig->ret->type == MONO_TYPE_VOID)
6925 return NULL;
6926 else
6927 return stackval_to_data_addr (sig->ret, iframe->retval);
6930 static void
6931 interp_start_single_stepping (void)
6933 ss_enabled = TRUE;
6936 static void
6937 interp_stop_single_stepping (void)
6939 ss_enabled = FALSE;
6942 static void
6943 register_interp_stats (void)
6945 mono_counters_init ();
6946 mono_counters_register ("Total transform time", MONO_COUNTER_INTERP | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_interp_stats.transform_time);
6947 mono_counters_register ("Methods inlined", MONO_COUNTER_INTERP | MONO_COUNTER_INT, &mono_interp_stats.inlined_methods);
6948 mono_counters_register ("Inline failures", MONO_COUNTER_INTERP | MONO_COUNTER_INT, &mono_interp_stats.inline_failures);
6951 #undef MONO_EE_CALLBACK
6952 #define MONO_EE_CALLBACK(ret, name, sig) interp_ ## name,
6954 static const MonoEECallbacks mono_interp_callbacks = {
6955 MONO_EE_CALLBACKS
6958 void
6959 mono_ee_interp_init (const char *opts)
6961 g_assert (mono_ee_api_version () == MONO_EE_API_VERSION);
6962 g_assert (!interp_init_done);
6963 interp_init_done = TRUE;
6965 mono_native_tls_alloc (&thread_context_id, NULL);
6966 set_context (NULL);
6968 interp_parse_options (opts);
6969 if (mini_get_debug_options ()->mdb_optimizations)
6970 mono_interp_opt &= ~INTERP_OPT_INLINE;
6971 mono_interp_transform_init ();
6973 mini_install_interp_callbacks (&mono_interp_callbacks);
6975 register_interp_stats ();