[interp] Error handling refactor (optimize non-exception path) (helps clang save...
[mono-project.git] / mono / mini / interp / interp.c
blob556e0e2e3de95445cd32811a3a71f8d9efac07b5
1 /**
2 * \file
4 * interp.c: Interpreter for CIL byte codes
6 * Authors:
7 * Paolo Molaro (lupus@ximian.com)
8 * Miguel de Icaza (miguel@ximian.com)
9 * Dietmar Maurer (dietmar@ximian.com)
11 * (C) 2001, 2002 Ximian, Inc.
13 #ifndef __USE_ISOC99
14 #define __USE_ISOC99
15 #endif
16 #include "config.h"
18 #include <stdio.h>
19 #include <string.h>
20 #include <stdlib.h>
21 #include <glib.h>
22 #include <math.h>
23 #include <locale.h>
25 #include <mono/utils/gc_wrapper.h>
26 #include <mono/utils/mono-math.h>
27 #include <mono/utils/mono-counters.h>
29 #ifdef HAVE_ALLOCA_H
30 # include <alloca.h>
31 #else
32 # ifdef __CYGWIN__
33 # define alloca __builtin_alloca
34 # endif
35 #endif
37 /* trim excessive headers */
38 #include <mono/metadata/image.h>
39 #include <mono/metadata/assembly-internals.h>
40 #include <mono/metadata/cil-coff.h>
41 #include <mono/metadata/mono-endian.h>
42 #include <mono/metadata/tabledefs.h>
43 #include <mono/metadata/tokentype.h>
44 #include <mono/metadata/loader.h>
45 #include <mono/metadata/threads.h>
46 #include <mono/metadata/threadpool.h>
47 #include <mono/metadata/profiler-private.h>
48 #include <mono/metadata/appdomain.h>
49 #include <mono/metadata/reflection.h>
50 #include <mono/metadata/exception.h>
51 #include <mono/metadata/verify.h>
52 #include <mono/metadata/opcodes.h>
53 #include <mono/metadata/debug-helpers.h>
54 #include <mono/metadata/mono-config.h>
55 #include <mono/metadata/marshal.h>
56 #include <mono/metadata/environment.h>
57 #include <mono/metadata/mono-debug.h>
58 #include <mono/metadata/gc-internals.h>
59 #include <mono/utils/atomic.h>
61 #include "interp.h"
62 #include "interp-internals.h"
63 #include "mintops.h"
65 #include <mono/mini/mini.h>
66 #include <mono/mini/mini-runtime.h>
67 #include <mono/mini/aot-runtime.h>
68 #include <mono/mini/llvm-runtime.h>
69 #include <mono/mini/llvmonly-runtime.h>
70 #include <mono/mini/jit-icalls.h>
71 #include <mono/mini/debugger-agent.h>
72 #include <mono/mini/ee.h>
73 #include <mono/mini/trace.h>
75 #ifdef TARGET_ARM
76 #include <mono/mini/mini-arm.h>
77 #endif
78 #include <mono/metadata/icall-decl.h>
80 #ifdef _MSC_VER
81 #pragma warning(disable:4102) // label' : unreferenced label
82 #endif
84 /* Arguments that are passed when invoking only a finally/filter clause from the frame */
85 typedef struct {
86 /* Where we start the frame execution from */
87 const guint16 *start_with_ip;
89 * End ip of the exit_clause. We need it so we know whether the resume
90 * state is for this frame (which is called from EH) or for the original
91 * frame further down the stack.
93 const guint16 *end_at_ip;
94 /* When exiting this clause we also exit the frame */
95 int exit_clause;
96 /* Exception that we are filtering */
97 MonoException *filter_exception;
98 InterpFrame *base_frame;
99 } FrameClauseArgs;
101 static 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 // FIXME The inlining of this needs to be reevaluated in the context of later changes.
233 // Also there is now only one caller, so consider inlining it manually.
234 static MONO_NEVER_INLINE GSList* // Inlining this causes caller to use more stack.
235 set_resume_state (ThreadContext *context, InterpFrame *frame, GSList* finally_ips)
237 /* We have thrown an exception from a finally block. Some of the leave targets were unwound already */
238 while (finally_ips &&
239 finally_ips->data >= context->handler_ei->try_start &&
240 finally_ips->data < context->handler_ei->try_end)
241 finally_ips = g_slist_remove (finally_ips, finally_ips->data);
242 frame->ex = NULL;
243 context->has_resume_state = 0;
244 context->handler_frame = NULL;
245 context->handler_ei = NULL;
246 return finally_ips;
250 * If this bit is set, it means the call has thrown the exception, and we
251 * reached this point because the EH code in mono_handle_exception ()
252 * unwound all the JITted frames below us. mono_interp_set_resume_state ()
253 * has set the fields in context to indicate where we have to resume execution.
255 #define CHECK_RESUME_STATE(context) do { \
256 if ((context)->has_resume_state) \
257 goto resume; \
258 } while (0)
260 static void
261 set_context (ThreadContext *context)
263 mono_native_tls_set_value (thread_context_id, context);
265 if (!context)
266 return;
268 MonoJitTlsData *jit_tls = mono_tls_get_jit_tls ();
269 g_assertf (jit_tls, "ThreadContext needs initialized JIT TLS");
271 /* jit_tls assumes ownership of 'context' */
272 jit_tls->interp_context = context;
275 static ThreadContext *
276 get_context (void)
278 ThreadContext *context = (ThreadContext *) mono_native_tls_get_value (thread_context_id);
279 if (context == NULL) {
280 context = g_new0 (ThreadContext, 1);
281 set_context (context);
283 return context;
286 static MONO_NEVER_INLINE void
287 ves_real_abort (int line, MonoMethod *mh,
288 const unsigned short *ip, stackval *stack, stackval *sp)
290 ERROR_DECL (error);
291 MonoMethodHeader *header = mono_method_get_header_checked (mh, error);
292 mono_error_cleanup (error); /* FIXME: don't swallow the error */
293 g_printerr ("Execution aborted in method: %s::%s\n", m_class_get_name (mh->klass), mh->name);
294 g_printerr ("Line=%d IP=0x%04lx, Aborted execution\n", line, ip-(const unsigned short *) header->code);
295 g_printerr ("0x%04x %02x\n", ip-(const unsigned short *) header->code, *ip);
296 mono_metadata_free_mh (header);
299 #define ves_abort() \
300 do {\
301 ves_real_abort(__LINE__, frame->imethod->method, ip, frame->stack, sp); \
302 THROW_EX (mono_get_exception_execution_engine (NULL), ip); \
303 } while (0);
305 static InterpMethod*
306 lookup_imethod (MonoDomain *domain, MonoMethod *method)
308 InterpMethod *imethod;
309 MonoJitDomainInfo *info;
311 info = domain_jit_info (domain);
312 mono_domain_jit_code_hash_lock (domain);
313 imethod = (InterpMethod*)mono_internal_hash_table_lookup (&info->interp_code_hash, method);
314 mono_domain_jit_code_hash_unlock (domain);
315 return imethod;
318 static gpointer
319 interp_get_remoting_invoke (MonoMethod *method, gpointer addr, MonoError *error)
321 #ifndef DISABLE_REMOTING
322 InterpMethod *imethod;
324 if (addr) {
325 imethod = lookup_method_pointer (addr);
326 } else {
327 g_assert (method);
328 imethod = mono_interp_get_imethod (mono_domain_get (), method, error);
329 return_val_if_nok (error, NULL);
331 g_assert (imethod);
332 g_assert (mono_use_interpreter);
334 MonoMethod *remoting_invoke_method = mono_marshal_get_remoting_invoke (imethod->method, error);
335 return_val_if_nok (error, NULL);
336 return mono_interp_get_imethod (mono_domain_get (), remoting_invoke_method, error);
337 #else
338 g_assert_not_reached ();
339 return NULL;
340 #endif
343 InterpMethod*
344 mono_interp_get_imethod (MonoDomain *domain, MonoMethod *method, MonoError *error)
346 InterpMethod *imethod;
347 MonoJitDomainInfo *info;
348 MonoMethodSignature *sig;
349 int i;
351 error_init (error);
353 info = domain_jit_info (domain);
354 mono_domain_jit_code_hash_lock (domain);
355 imethod = (InterpMethod*)mono_internal_hash_table_lookup (&info->interp_code_hash, method);
356 mono_domain_jit_code_hash_unlock (domain);
357 if (imethod)
358 return imethod;
360 sig = mono_method_signature_internal (method);
362 imethod = (InterpMethod*)mono_domain_alloc0 (domain, sizeof (InterpMethod));
363 imethod->method = method;
364 imethod->domain = domain;
365 imethod->param_count = sig->param_count;
366 imethod->hasthis = sig->hasthis;
367 imethod->vararg = sig->call_convention == MONO_CALL_VARARG;
368 imethod->rtype = mini_get_underlying_type (sig->ret);
369 imethod->param_types = (MonoType**)mono_domain_alloc0 (domain, sizeof (MonoType*) * sig->param_count);
370 for (i = 0; i < sig->param_count; ++i)
371 imethod->param_types [i] = mini_get_underlying_type (sig->params [i]);
373 mono_domain_jit_code_hash_lock (domain);
374 if (!mono_internal_hash_table_lookup (&info->interp_code_hash, method))
375 mono_internal_hash_table_insert (&info->interp_code_hash, method, imethod);
376 mono_domain_jit_code_hash_unlock (domain);
378 imethod->prof_flags = mono_profiler_get_call_instrumentation_flags (imethod->method);
380 return imethod;
383 #if defined (MONO_CROSS_COMPILE) || defined (HOST_WASM)
384 #define INTERP_PUSH_LMF_WITH_CTX_BODY(ext, exit_label) \
385 (ext).kind = MONO_LMFEXT_INTERP_EXIT;
387 #elif defined(MONO_ARCH_HAS_NO_PROPER_MONOCTX)
388 /* some platforms, e.g. appleTV, don't provide us a precise MonoContext
389 * (registers are not accurate), thus resuming to the label does not work. */
390 #define INTERP_PUSH_LMF_WITH_CTX_BODY(ext, exit_label) \
391 (ext).kind = MONO_LMFEXT_INTERP_EXIT;
392 #elif defined (_MSC_VER)
393 #define INTERP_PUSH_LMF_WITH_CTX_BODY(ext, exit_label) \
394 (ext).kind = MONO_LMFEXT_INTERP_EXIT_WITH_CTX; \
395 (ext).interp_exit_label_set = FALSE; \
396 MONO_CONTEXT_GET_CURRENT ((ext).ctx); \
397 if ((ext).interp_exit_label_set == FALSE) \
398 mono_arch_do_ip_adjustment (&(ext).ctx); \
399 if ((ext).interp_exit_label_set == TRUE) \
400 goto exit_label; \
401 (ext).interp_exit_label_set = TRUE;
402 #elif defined(MONO_ARCH_HAS_MONO_CONTEXT)
403 #define INTERP_PUSH_LMF_WITH_CTX_BODY(ext, exit_label) \
404 (ext).kind = MONO_LMFEXT_INTERP_EXIT_WITH_CTX; \
405 MONO_CONTEXT_GET_CURRENT ((ext).ctx); \
406 MONO_CONTEXT_SET_IP (&(ext).ctx, (&&exit_label)); \
407 mono_arch_do_ip_adjustment (&(ext).ctx);
408 #else
409 #define INTERP_PUSH_LMF_WITH_CTX_BODY(ext, exit_label) g_error ("requires working mono-context");
410 #endif
412 /* INTERP_PUSH_LMF_WITH_CTX:
414 * same as interp_push_lmf, but retrieving and attaching MonoContext to it.
415 * This is needed to resume into the interp when the exception is thrown from
416 * native code (see ./mono/tests/install_eh_callback.exe).
418 * This must be a macro in order to retrieve the right register values for
419 * MonoContext.
421 #define INTERP_PUSH_LMF_WITH_CTX(frame, ext, exit_label) \
422 memset (&(ext), 0, sizeof (MonoLMFExt)); \
423 (ext).interp_exit_data = (frame); \
424 INTERP_PUSH_LMF_WITH_CTX_BODY ((ext), exit_label); \
425 mono_push_lmf (&(ext));
428 * interp_push_lmf:
430 * Push an LMF frame on the LMF stack
431 * to mark the transition to native code.
432 * This is needed for the native code to
433 * be able to do stack walks.
435 static void
436 interp_push_lmf (MonoLMFExt *ext, InterpFrame *frame)
438 memset (ext, 0, sizeof (MonoLMFExt));
439 ext->kind = MONO_LMFEXT_INTERP_EXIT;
440 ext->interp_exit_data = frame;
442 mono_push_lmf (ext);
445 static void
446 interp_pop_lmf (MonoLMFExt *ext)
448 mono_pop_lmf (&ext->lmf);
451 static MONO_NEVER_INLINE InterpMethod*
452 get_virtual_method (InterpMethod *imethod, MonoVTable *vtable)
454 MonoMethod *m = imethod->method;
455 MonoDomain *domain = imethod->domain;
456 InterpMethod *ret = NULL;
458 #ifndef DISABLE_REMOTING
459 if (mono_class_is_transparent_proxy (vtable->klass)) {
460 ERROR_DECL (error);
461 MonoMethod *remoting_invoke_method = mono_marshal_get_remoting_invoke_with_check (m, error);
462 mono_error_assert_ok (error);
463 ret = mono_interp_get_imethod (domain, remoting_invoke_method, error);
464 mono_error_assert_ok (error);
465 return ret;
467 #endif
469 if ((m->flags & METHOD_ATTRIBUTE_FINAL) || !(m->flags & METHOD_ATTRIBUTE_VIRTUAL)) {
470 if (m->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED) {
471 ERROR_DECL (error);
472 ret = mono_interp_get_imethod (domain, mono_marshal_get_synchronized_wrapper (m), error);
473 mono_error_cleanup (error); /* FIXME: don't swallow the error */
474 } else {
475 ret = imethod;
477 return ret;
480 mono_class_setup_vtable (vtable->klass);
482 int slot = mono_method_get_vtable_slot (m);
483 if (mono_class_is_interface (m->klass)) {
484 g_assert (vtable->klass != m->klass);
485 /* TODO: interface offset lookup is slow, go through IMT instead */
486 gboolean non_exact_match;
487 slot += mono_class_interface_offset_with_variance (vtable->klass, m->klass, &non_exact_match);
490 MonoMethod *virtual_method = m_class_get_vtable (vtable->klass) [slot];
491 if (m->is_inflated && mono_method_get_context (m)->method_inst) {
492 MonoGenericContext context = { NULL, NULL };
494 if (mono_class_is_ginst (virtual_method->klass))
495 context.class_inst = mono_class_get_generic_class (virtual_method->klass)->context.class_inst;
496 else if (mono_class_is_gtd (virtual_method->klass))
497 context.class_inst = mono_class_get_generic_container (virtual_method->klass)->context.class_inst;
498 context.method_inst = mono_method_get_context (m)->method_inst;
500 ERROR_DECL (error);
501 virtual_method = mono_class_inflate_generic_method_checked (virtual_method, &context, error);
502 mono_error_cleanup (error); /* FIXME: don't swallow the error */
505 if (virtual_method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) {
506 virtual_method = mono_marshal_get_native_wrapper (virtual_method, FALSE, FALSE);
509 if (virtual_method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED) {
510 virtual_method = mono_marshal_get_synchronized_wrapper (virtual_method);
513 ERROR_DECL (error);
514 InterpMethod *virtual_imethod = mono_interp_get_imethod (domain, virtual_method, error);
515 mono_error_cleanup (error); /* FIXME: don't swallow the error */
516 return virtual_imethod;
519 typedef struct {
520 InterpMethod *imethod;
521 InterpMethod *target_imethod;
522 } InterpVTableEntry;
524 /* domain lock must be held */
525 static GSList*
526 append_imethod (MonoDomain *domain, GSList *list, InterpMethod *imethod, InterpMethod *target_imethod)
528 GSList *ret;
529 InterpVTableEntry *entry;
531 entry = (InterpVTableEntry*) mono_mempool_alloc (domain->mp, sizeof (InterpVTableEntry));
532 entry->imethod = imethod;
533 entry->target_imethod = target_imethod;
534 ret = g_slist_append_mempool (domain->mp, list, entry);
536 return ret;
539 static InterpMethod*
540 get_target_imethod (GSList *list, InterpMethod *imethod)
542 while (list != NULL) {
543 InterpVTableEntry *entry = (InterpVTableEntry*) list->data;
544 if (entry->imethod == imethod)
545 return entry->target_imethod;
546 list = list->next;
548 return NULL;
551 static gpointer*
552 get_method_table (MonoVTable *vtable, int offset)
554 if (offset >= 0)
555 return vtable->interp_vtable;
556 else
557 return (gpointer*)vtable;
560 static gpointer*
561 alloc_method_table (MonoVTable *vtable, int offset)
563 gpointer *table;
565 if (offset >= 0) {
566 table = mono_domain_alloc0 (vtable->domain, m_class_get_vtable_size (vtable->klass) * sizeof (gpointer));
567 vtable->interp_vtable = table;
568 } else {
569 table = (gpointer*)vtable;
572 return table;
575 static MONO_NEVER_INLINE InterpMethod* // Inlining causes additional stack use in caller.
576 get_virtual_method_fast (InterpMethod *imethod, MonoVTable *vtable, int offset)
578 gpointer *table;
580 #ifndef DISABLE_REMOTING
581 /* FIXME Remoting */
582 if (mono_class_is_transparent_proxy (vtable->klass))
583 return get_virtual_method (imethod, vtable);
584 #endif
586 table = get_method_table (vtable, offset);
588 if (!table) {
589 /* Lazily allocate method table */
590 mono_domain_lock (vtable->domain);
591 table = get_method_table (vtable, offset);
592 if (!table)
593 table = alloc_method_table (vtable, offset);
594 mono_domain_unlock (vtable->domain);
597 if (!table [offset]) {
598 InterpMethod *target_imethod = get_virtual_method (imethod, vtable);
599 /* Lazily initialize the method table slot */
600 mono_domain_lock (vtable->domain);
601 if (!table [offset]) {
602 if (imethod->method->is_inflated || offset < 0)
603 table [offset] = append_imethod (vtable->domain, NULL, imethod, target_imethod);
604 else
605 table [offset] = (gpointer) ((gsize)target_imethod | 0x1);
607 mono_domain_unlock (vtable->domain);
610 if ((gsize)table [offset] & 0x1) {
611 /* Non generic virtual call. Only one method in slot */
612 return (InterpMethod*) ((gsize)table [offset] & ~0x1);
613 } else {
614 /* Virtual generic or interface call. Multiple methods in slot */
615 InterpMethod *target_imethod = get_target_imethod ((GSList*)table [offset], imethod);
617 if (!target_imethod) {
618 target_imethod = get_virtual_method (imethod, vtable);
619 mono_domain_lock (vtable->domain);
620 if (!get_target_imethod ((GSList*)table [offset], imethod))
621 table [offset] = append_imethod (vtable->domain, (GSList*)table [offset], imethod, target_imethod);
622 mono_domain_unlock (vtable->domain);
624 return target_imethod;
628 static void inline
629 stackval_from_data (MonoType *type_, stackval *result, const void *data, gboolean pinvoke)
631 MonoType *type = mini_native_type_replace_type (type_);
632 if (type->byref) {
633 switch (type->type) {
634 case MONO_TYPE_OBJECT:
635 case MONO_TYPE_CLASS:
636 case MONO_TYPE_STRING:
637 case MONO_TYPE_ARRAY:
638 case MONO_TYPE_SZARRAY:
639 break;
640 default:
641 break;
643 result->data.p = *(gpointer*)data;
644 return;
646 switch (type->type) {
647 case MONO_TYPE_VOID:
648 return;
649 case MONO_TYPE_I1:
650 result->data.i = *(gint8*)data;
651 return;
652 case MONO_TYPE_U1:
653 case MONO_TYPE_BOOLEAN:
654 result->data.i = *(guint8*)data;
655 return;
656 case MONO_TYPE_I2:
657 result->data.i = *(gint16*)data;
658 return;
659 case MONO_TYPE_U2:
660 case MONO_TYPE_CHAR:
661 result->data.i = *(guint16*)data;
662 return;
663 case MONO_TYPE_I4:
664 result->data.i = *(gint32*)data;
665 return;
666 case MONO_TYPE_U:
667 case MONO_TYPE_I:
668 result->data.nati = *(mono_i*)data;
669 return;
670 case MONO_TYPE_PTR:
671 result->data.p = *(gpointer*)data;
672 return;
673 case MONO_TYPE_U4:
674 result->data.i = *(guint32*)data;
675 return;
676 case MONO_TYPE_R4:
677 /* memmove handles unaligned case */
678 memmove (&result->data.f_r4, data, sizeof (float));
679 return;
680 case MONO_TYPE_I8:
681 case MONO_TYPE_U8:
682 memmove (&result->data.l, data, sizeof (gint64));
683 return;
684 case MONO_TYPE_R8:
685 memmove (&result->data.f, data, sizeof (double));
686 return;
687 case MONO_TYPE_STRING:
688 case MONO_TYPE_SZARRAY:
689 case MONO_TYPE_CLASS:
690 case MONO_TYPE_OBJECT:
691 case MONO_TYPE_ARRAY:
692 result->data.p = *(gpointer*)data;
693 return;
694 case MONO_TYPE_VALUETYPE:
695 if (m_class_is_enumtype (type->data.klass)) {
696 stackval_from_data (mono_class_enum_basetype_internal (type->data.klass), result, data, pinvoke);
697 return;
698 } else if (pinvoke) {
699 memcpy (result->data.vt, data, mono_class_native_size (type->data.klass, NULL));
700 } else {
701 mono_value_copy_internal (result->data.vt, data, type->data.klass);
703 return;
704 case MONO_TYPE_GENERICINST: {
705 if (mono_type_generic_inst_is_valuetype (type)) {
706 mono_value_copy_internal (result->data.vt, data, mono_class_from_mono_type_internal (type));
707 return;
709 stackval_from_data (m_class_get_byval_arg (type->data.generic_class->container_class), result, data, pinvoke);
710 return;
712 default:
713 g_error ("got type 0x%02x", type->type);
717 static void inline
718 stackval_to_data (MonoType *type, stackval *val, void *data, gboolean pinvoke)
720 type = mini_native_type_replace_type (type);
721 if (type->byref) {
722 gpointer *p = (gpointer*)data;
723 *p = val->data.p;
724 return;
726 /* printf ("TODAT0 %p\n", data); */
727 switch (type->type) {
728 case MONO_TYPE_I1:
729 case MONO_TYPE_U1: {
730 guint8 *p = (guint8*)data;
731 *p = val->data.i;
732 return;
734 case MONO_TYPE_BOOLEAN: {
735 guint8 *p = (guint8*)data;
736 *p = (val->data.i != 0);
737 return;
739 case MONO_TYPE_I2:
740 case MONO_TYPE_U2:
741 case MONO_TYPE_CHAR: {
742 guint16 *p = (guint16*)data;
743 *p = val->data.i;
744 return;
746 case MONO_TYPE_I: {
747 mono_i *p = (mono_i*)data;
748 /* In theory the value used by stloc should match the local var type
749 but in practice it sometimes doesn't (a int32 gets dup'd and stloc'd into
750 a native int - both by csc and mcs). Not sure what to do about sign extension
751 as it is outside the spec... doing the obvious */
752 *p = (mono_i)val->data.nati;
753 return;
755 case MONO_TYPE_U: {
756 mono_u *p = (mono_u*)data;
757 /* see above. */
758 *p = (mono_u)val->data.nati;
759 return;
761 case MONO_TYPE_I4:
762 case MONO_TYPE_U4: {
763 gint32 *p = (gint32*)data;
764 *p = val->data.i;
765 return;
767 case MONO_TYPE_I8:
768 case MONO_TYPE_U8: {
769 memmove (data, &val->data.l, sizeof (gint64));
770 return;
772 case MONO_TYPE_R4: {
773 /* memmove handles unaligned case */
774 memmove (data, &val->data.f_r4, sizeof (float));
775 return;
777 case MONO_TYPE_R8: {
778 memmove (data, &val->data.f, sizeof (double));
779 return;
781 case MONO_TYPE_STRING:
782 case MONO_TYPE_SZARRAY:
783 case MONO_TYPE_CLASS:
784 case MONO_TYPE_OBJECT:
785 case MONO_TYPE_ARRAY: {
786 gpointer *p = (gpointer *) data;
787 mono_gc_wbarrier_generic_store_internal (p, val->data.o);
788 return;
790 case MONO_TYPE_PTR: {
791 gpointer *p = (gpointer *) data;
792 *p = val->data.p;
793 return;
795 case MONO_TYPE_VALUETYPE:
796 if (m_class_is_enumtype (type->data.klass)) {
797 stackval_to_data (mono_class_enum_basetype_internal (type->data.klass), val, data, pinvoke);
798 return;
799 } else if (pinvoke) {
800 memcpy (data, val->data.vt, mono_class_native_size (type->data.klass, NULL));
801 } else {
802 mono_value_copy_internal (data, val->data.vt, type->data.klass);
804 return;
805 case MONO_TYPE_GENERICINST: {
806 MonoClass *container_class = type->data.generic_class->container_class;
808 if (m_class_is_valuetype (container_class) && !m_class_is_enumtype (container_class)) {
809 mono_value_copy_internal (data, val->data.vt, mono_class_from_mono_type_internal (type));
810 return;
812 stackval_to_data (m_class_get_byval_arg (type->data.generic_class->container_class), val, data, pinvoke);
813 return;
815 default:
816 g_error ("got type %x", type->type);
821 * Same as stackval_to_data but return address of storage instead
822 * of copying the value.
824 static gpointer
825 stackval_to_data_addr (MonoType *type, stackval *val)
827 type = mini_native_type_replace_type (type);
828 if (type->byref)
829 return &val->data.p;
831 switch (type->type) {
832 case MONO_TYPE_I1:
833 case MONO_TYPE_U1:
834 case MONO_TYPE_BOOLEAN:
835 case MONO_TYPE_I2:
836 case MONO_TYPE_U2:
837 case MONO_TYPE_CHAR:
838 case MONO_TYPE_I4:
839 case MONO_TYPE_U4:
840 return &val->data.i;
841 case MONO_TYPE_I:
842 case MONO_TYPE_U:
843 return &val->data.nati;
844 case MONO_TYPE_I8:
845 case MONO_TYPE_U8:
846 return &val->data.l;
847 case MONO_TYPE_R4:
848 return &val->data.f_r4;
849 case MONO_TYPE_R8:
850 return &val->data.f;
851 case MONO_TYPE_STRING:
852 case MONO_TYPE_SZARRAY:
853 case MONO_TYPE_CLASS:
854 case MONO_TYPE_OBJECT:
855 case MONO_TYPE_ARRAY:
856 case MONO_TYPE_PTR:
857 return &val->data.p;
858 case MONO_TYPE_VALUETYPE:
859 if (m_class_is_enumtype (type->data.klass))
860 return stackval_to_data_addr (mono_class_enum_basetype_internal (type->data.klass), val);
861 else
862 return val->data.vt;
863 case MONO_TYPE_TYPEDBYREF:
864 return val->data.vt;
865 case MONO_TYPE_GENERICINST: {
866 MonoClass *container_class = type->data.generic_class->container_class;
868 if (m_class_is_valuetype (container_class) && !m_class_is_enumtype (container_class))
869 return val->data.vt;
870 return stackval_to_data_addr (m_class_get_byval_arg (type->data.generic_class->container_class), val);
872 default:
873 g_error ("got type %x", type->type);
878 * interp_throw:
879 * Throw an exception from the interpreter.
881 static MONO_NEVER_INLINE void
882 interp_throw (ThreadContext *context, MonoException *ex, InterpFrame *frame, const guint16* ip, gboolean rethrow)
884 ERROR_DECL (error);
885 MonoLMFExt ext;
887 interp_push_lmf (&ext, frame);
888 frame->ip = ip;
889 frame->ex = ex;
891 if (mono_object_isinst_checked ((MonoObject *) ex, mono_defaults.exception_class, error)) {
892 MonoException *mono_ex = ex;
893 if (!rethrow) {
894 mono_ex->stack_trace = NULL;
895 mono_ex->trace_ips = NULL;
898 mono_error_assert_ok (error);
900 MonoContext ctx;
901 memset (&ctx, 0, sizeof (MonoContext));
902 MONO_CONTEXT_SET_SP (&ctx, frame);
905 * Call the JIT EH code. The EH code will call back to us using:
906 * - mono_interp_set_resume_state ()/run_finally ()/run_filter ().
907 * Since ctx.ip is 0, this will start unwinding from the LMF frame
908 * pushed above, which points to our frames.
910 mono_handle_exception (&ctx, (MonoObject*)ex);
911 if (MONO_CONTEXT_GET_IP (&ctx) != 0) {
912 /* We need to unwind into non-interpreter code */
913 mono_restore_context (&ctx);
914 g_assert_not_reached ();
917 interp_pop_lmf (&ext);
919 g_assert (context->has_resume_state);
922 #define THROW_EX_GENERAL(exception,ex_ip, rethrow) \
923 do { \
924 interp_throw (context, (exception), (frame), (ex_ip), (rethrow)); \
925 goto resume; \
926 } while (0)
928 #define THROW_EX(exception,ex_ip) THROW_EX_GENERAL ((exception), (ex_ip), FALSE)
930 #define THROW_EX_OVF(ip) THROW_EX (mono_get_exception_overflow (), ip)
932 #define THROW_EX_DIV_ZERO(ip) THROW_EX (mono_get_exception_divide_by_zero (), ip)
934 #define NULL_CHECK(o) do { \
935 if (G_UNLIKELY (!(o))) \
936 THROW_EX (mono_get_exception_null_reference (), ip); \
937 } while (0)
939 #define EXCEPTION_CHECKPOINT \
940 do { \
941 if (*mono_thread_interruption_request_flag () && !mono_threads_is_critical_method (frame->imethod->method)) { \
942 MonoException *exc = mono_thread_interruption_checkpoint (); \
943 if (exc) \
944 THROW_EX (exc, ip); \
946 } while (0)
949 #define EXCEPTION_CHECKPOINT_IN_HELPER_FUNCTION \
950 do { \
951 if (*mono_thread_interruption_request_flag () && !mono_threads_is_critical_method (frame->imethod->method)) { \
952 MonoException *exc = mono_thread_interruption_checkpoint (); \
953 if (exc) \
954 return exc; \
956 } while (0)
958 static MonoObject*
959 ves_array_create (MonoDomain *domain, MonoClass *klass, int param_count, stackval *values, MonoError *error)
961 uintptr_t *lengths;
962 intptr_t *lower_bounds;
963 int i;
965 lengths = g_newa (uintptr_t, m_class_get_rank (klass) * 2);
966 for (i = 0; i < param_count; ++i) {
967 lengths [i] = values->data.i;
968 values ++;
970 if (m_class_get_rank (klass) == param_count) {
971 /* Only lengths provided. */
972 lower_bounds = NULL;
973 } else {
974 /* lower bounds are first. */
975 lower_bounds = (intptr_t *) lengths;
976 lengths += m_class_get_rank (klass);
978 return (MonoObject*) mono_array_new_full_checked (domain, klass, lengths, lower_bounds, error);
981 static gint32
982 ves_array_calculate_index (MonoArray *ao, stackval *sp, InterpFrame *frame, gboolean safe)
984 g_assert (!frame->ex);
985 MonoClass *ac = ((MonoObject *) ao)->vtable->klass;
987 guint32 pos = 0;
988 if (ao->bounds) {
989 for (gint32 i = 0; i < m_class_get_rank (ac); i++) {
990 guint32 idx = sp [i].data.i;
991 guint32 lower = ao->bounds [i].lower_bound;
992 guint32 len = ao->bounds [i].length;
993 if (safe && (idx < lower || (idx - lower) >= len)) {
994 frame->ex = mono_get_exception_index_out_of_range ();
995 return -1;
997 pos = (pos * len) + idx - lower;
999 } else {
1000 pos = sp [0].data.i;
1001 if (safe && pos >= ao->max_length) {
1002 frame->ex = mono_get_exception_index_out_of_range ();
1003 return -1;
1006 return pos;
1009 static MONO_NEVER_INLINE void
1010 ves_array_set (InterpFrame *frame, stackval *sp, MonoMethodSignature *sig)
1012 MonoObject *o = sp->data.o;
1013 MonoArray *ao = (MonoArray *) o;
1014 MonoClass *ac = o->vtable->klass;
1016 g_assert (m_class_get_rank (ac) >= 1);
1018 gint32 pos = ves_array_calculate_index (ao, sp + 1, frame, TRUE);
1019 if (frame->ex)
1020 return;
1022 int val_index = 1 + m_class_get_rank (ac);
1023 if (sp [val_index].data.p && !m_class_is_valuetype (m_class_get_element_class (mono_object_class (o)))) {
1024 ERROR_DECL (error);
1025 MonoObject *isinst = mono_object_isinst_checked (sp [val_index].data.o, m_class_get_element_class (mono_object_class (o)), error);
1026 mono_error_cleanup (error);
1027 if (!isinst) {
1028 frame->ex = mono_get_exception_array_type_mismatch ();
1029 return;
1033 gint32 esize = mono_array_element_size (ac);
1034 gpointer ea = mono_array_addr_with_size_fast (ao, esize, pos);
1036 MonoType *mt = sig->params [m_class_get_rank (ac)];
1037 stackval_to_data (mt, &sp [val_index], ea, FALSE);
1040 static void
1041 ves_array_get (InterpFrame *frame, stackval *sp, stackval *retval, MonoMethodSignature *sig, gboolean safe)
1043 MonoObject *o = sp->data.o;
1044 MonoArray *ao = (MonoArray *) o;
1045 MonoClass *ac = o->vtable->klass;
1047 g_assert (m_class_get_rank (ac) >= 1);
1049 gint32 pos = ves_array_calculate_index (ao, sp + 1, frame, safe);
1050 if (frame->ex)
1051 return;
1053 gint32 esize = mono_array_element_size (ac);
1054 gconstpointer ea = mono_array_addr_with_size_fast (ao, esize, pos);
1056 MonoType *mt = sig->ret;
1057 stackval_from_data (mt, retval, ea, FALSE);
1060 static MONO_NEVER_INLINE gpointer
1061 ves_array_element_address (InterpFrame *frame, MonoClass *required_type, MonoArray *ao, stackval *sp, gboolean needs_typecheck)
1063 MonoClass *ac = ((MonoObject *) ao)->vtable->klass;
1065 g_assert (m_class_get_rank (ac) >= 1);
1067 gint32 pos = ves_array_calculate_index (ao, sp, frame, TRUE);
1068 if (frame->ex)
1069 return NULL;
1071 if (needs_typecheck && !mono_class_is_assignable_from_internal (m_class_get_element_class (mono_object_class ((MonoObject *) ao)), required_type)) {
1072 frame->ex = mono_get_exception_array_type_mismatch ();
1073 return NULL;
1075 gint32 esize = mono_array_element_size (ac);
1076 return mono_array_addr_with_size_fast (ao, esize, pos);
1079 #ifdef MONO_ARCH_HAVE_INTERP_ENTRY_TRAMPOLINE
1080 static MonoFuncV mono_native_to_interp_trampoline = NULL;
1081 #endif
1083 #ifndef MONO_ARCH_HAVE_INTERP_PINVOKE_TRAMP
1084 static InterpMethodArguments* build_args_from_sig (MonoMethodSignature *sig, InterpFrame *frame)
1086 InterpMethodArguments *margs = g_malloc0 (sizeof (InterpMethodArguments));
1088 #ifdef TARGET_ARM
1089 g_assert (mono_arm_eabi_supported ());
1090 int i8_align = mono_arm_i8_align ();
1091 #endif
1093 #ifdef TARGET_WASM
1094 margs->sig = sig;
1095 #endif
1097 if (sig->hasthis)
1098 margs->ilen++;
1100 for (int i = 0; i < sig->param_count; i++) {
1101 guint32 ptype = sig->params [i]->byref ? MONO_TYPE_PTR : sig->params [i]->type;
1102 switch (ptype) {
1103 case MONO_TYPE_BOOLEAN:
1104 case MONO_TYPE_CHAR:
1105 case MONO_TYPE_I1:
1106 case MONO_TYPE_U1:
1107 case MONO_TYPE_I2:
1108 case MONO_TYPE_U2:
1109 case MONO_TYPE_I4:
1110 case MONO_TYPE_U4:
1111 case MONO_TYPE_I:
1112 case MONO_TYPE_U:
1113 case MONO_TYPE_PTR:
1114 case MONO_TYPE_SZARRAY:
1115 case MONO_TYPE_CLASS:
1116 case MONO_TYPE_OBJECT:
1117 case MONO_TYPE_STRING:
1118 case MONO_TYPE_VALUETYPE:
1119 case MONO_TYPE_GENERICINST:
1120 #if SIZEOF_VOID_P == 8
1121 case MONO_TYPE_I8:
1122 case MONO_TYPE_U8:
1123 #endif
1124 margs->ilen++;
1125 break;
1126 #if SIZEOF_VOID_P == 4
1127 case MONO_TYPE_I8:
1128 case MONO_TYPE_U8:
1129 #ifdef TARGET_ARM
1130 /* pairs begin at even registers */
1131 if (i8_align == 8 && margs->ilen & 1)
1132 margs->ilen++;
1133 #endif
1134 margs->ilen += 2;
1135 break;
1136 #endif
1137 case MONO_TYPE_R4:
1138 #if SIZEOF_VOID_P == 8
1139 case MONO_TYPE_R8:
1140 #endif
1141 margs->flen++;
1142 break;
1143 #if SIZEOF_VOID_P == 4
1144 case MONO_TYPE_R8:
1145 margs->flen += 2;
1146 break;
1147 #endif
1148 default:
1149 g_error ("build_args_from_sig: not implemented yet (1): 0x%x\n", ptype);
1153 if (margs->ilen > 0)
1154 margs->iargs = g_malloc0 (sizeof (gpointer) * margs->ilen);
1156 if (margs->flen > 0)
1157 margs->fargs = g_malloc0 (sizeof (double) * margs->flen);
1159 if (margs->ilen > INTERP_ICALL_TRAMP_IARGS)
1160 g_error ("build_args_from_sig: TODO, allocate gregs: %d\n", margs->ilen);
1162 if (margs->flen > INTERP_ICALL_TRAMP_FARGS)
1163 g_error ("build_args_from_sig: TODO, allocate fregs: %d\n", margs->flen);
1166 size_t int_i = 0;
1167 size_t int_f = 0;
1169 if (sig->hasthis) {
1170 margs->iargs [0] = frame->stack_args->data.p;
1171 int_i++;
1174 for (int i = 0; i < sig->param_count; i++) {
1175 guint32 ptype = sig->params [i]->byref ? MONO_TYPE_PTR : sig->params [i]->type;
1176 switch (ptype) {
1177 case MONO_TYPE_BOOLEAN:
1178 case MONO_TYPE_CHAR:
1179 case MONO_TYPE_I1:
1180 case MONO_TYPE_U1:
1181 case MONO_TYPE_I2:
1182 case MONO_TYPE_U2:
1183 case MONO_TYPE_I4:
1184 case MONO_TYPE_U4:
1185 case MONO_TYPE_I:
1186 case MONO_TYPE_U:
1187 case MONO_TYPE_PTR:
1188 case MONO_TYPE_SZARRAY:
1189 case MONO_TYPE_CLASS:
1190 case MONO_TYPE_OBJECT:
1191 case MONO_TYPE_STRING:
1192 case MONO_TYPE_VALUETYPE:
1193 case MONO_TYPE_GENERICINST:
1194 #if SIZEOF_VOID_P == 8
1195 case MONO_TYPE_I8:
1196 case MONO_TYPE_U8:
1197 #endif
1198 margs->iargs [int_i] = frame->stack_args [i].data.p;
1199 #if DEBUG_INTERP
1200 g_print ("build_args_from_sig: margs->iargs [%d]: %p (frame @ %d)\n", int_i, margs->iargs [int_i], i);
1201 #endif
1202 int_i++;
1203 break;
1204 #if SIZEOF_VOID_P == 4
1205 case MONO_TYPE_I8:
1206 case MONO_TYPE_U8: {
1207 stackval *sarg = &frame->stack_args [i];
1208 #ifdef TARGET_ARM
1209 /* pairs begin at even registers */
1210 if (i8_align == 8 && int_i & 1)
1211 int_i++;
1212 #endif
1213 margs->iargs [int_i] = (gpointer) sarg->data.pair.lo;
1214 int_i++;
1215 margs->iargs [int_i] = (gpointer) sarg->data.pair.hi;
1216 #if DEBUG_INTERP
1217 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);
1218 #endif
1219 int_i++;
1220 break;
1222 #endif
1223 case MONO_TYPE_R4:
1224 case MONO_TYPE_R8:
1225 if (ptype == MONO_TYPE_R4)
1226 * (float *) &(margs->fargs [int_f]) = frame->stack_args [i].data.f_r4;
1227 else
1228 margs->fargs [int_f] = frame->stack_args [i].data.f;
1229 #if DEBUG_INTERP
1230 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);
1231 #endif
1232 #if SIZEOF_VOID_P == 4
1233 int_f += 2;
1234 #else
1235 int_f++;
1236 #endif
1237 break;
1238 default:
1239 g_error ("build_args_from_sig: not implemented yet (2): 0x%x\n", ptype);
1243 switch (sig->ret->type) {
1244 case MONO_TYPE_BOOLEAN:
1245 case MONO_TYPE_CHAR:
1246 case MONO_TYPE_I1:
1247 case MONO_TYPE_U1:
1248 case MONO_TYPE_I2:
1249 case MONO_TYPE_U2:
1250 case MONO_TYPE_I4:
1251 case MONO_TYPE_U4:
1252 case MONO_TYPE_I:
1253 case MONO_TYPE_U:
1254 case MONO_TYPE_PTR:
1255 case MONO_TYPE_SZARRAY:
1256 case MONO_TYPE_CLASS:
1257 case MONO_TYPE_OBJECT:
1258 case MONO_TYPE_STRING:
1259 case MONO_TYPE_I8:
1260 case MONO_TYPE_U8:
1261 case MONO_TYPE_VALUETYPE:
1262 case MONO_TYPE_GENERICINST:
1263 margs->retval = &(frame->retval->data.p);
1264 margs->is_float_ret = 0;
1265 break;
1266 case MONO_TYPE_R4:
1267 case MONO_TYPE_R8:
1268 margs->retval = &(frame->retval->data.p);
1269 margs->is_float_ret = 1;
1270 break;
1271 case MONO_TYPE_VOID:
1272 margs->retval = NULL;
1273 break;
1274 default:
1275 g_error ("build_args_from_sig: ret type not implemented yet: 0x%x\n", sig->ret->type);
1278 return margs;
1280 #endif
1282 static void
1283 interp_frame_arg_to_data (MonoInterpFrameHandle frame, MonoMethodSignature *sig, int index, gpointer data)
1285 InterpFrame *iframe = (InterpFrame*)frame;
1287 if (index == -1)
1288 stackval_to_data (sig->ret, iframe->retval, data, sig->pinvoke);
1289 else
1290 stackval_to_data (sig->params [index], &iframe->stack_args [index], data, sig->pinvoke);
1293 static void
1294 interp_data_to_frame_arg (MonoInterpFrameHandle frame, MonoMethodSignature *sig, int index, gconstpointer data)
1296 InterpFrame *iframe = (InterpFrame*)frame;
1298 if (index == -1)
1299 stackval_from_data (sig->ret, iframe->retval, data, sig->pinvoke);
1300 else if (sig->hasthis && index == 0)
1301 iframe->stack_args [index].data.p = *(gpointer*)data;
1302 else
1303 stackval_from_data (sig->params [index - sig->hasthis], &iframe->stack_args [index], data, sig->pinvoke);
1306 static gpointer
1307 interp_frame_arg_to_storage (MonoInterpFrameHandle frame, MonoMethodSignature *sig, int index)
1309 InterpFrame *iframe = (InterpFrame*)frame;
1311 if (index == -1)
1312 return stackval_to_data_addr (sig->ret, iframe->retval);
1313 else
1314 return stackval_to_data_addr (sig->params [index], &iframe->stack_args [index]);
1317 static void
1318 interp_frame_arg_set_storage (MonoInterpFrameHandle frame, MonoMethodSignature *sig, int index, gpointer storage)
1320 InterpFrame *iframe = (InterpFrame*)frame;
1321 stackval *val = (index == -1) ? iframe->retval : &iframe->stack_args [index];
1322 MonoType *type = (index == -1) ? sig->ret : sig->params [index];
1324 switch (type->type) {
1325 case MONO_TYPE_GENERICINST:
1326 if (!MONO_TYPE_IS_REFERENCE (type))
1327 val->data.vt = storage;
1328 break;
1329 case MONO_TYPE_VALUETYPE:
1330 val->data.vt = storage;
1331 break;
1332 default:
1333 g_assert_not_reached ();
1337 static MonoPIFunc
1338 get_interp_to_native_trampoline (void)
1340 static MonoPIFunc trampoline = NULL;
1342 if (!trampoline) {
1343 if (mono_ee_features.use_aot_trampolines) {
1344 trampoline = (MonoPIFunc) mono_aot_get_trampoline ("interp_to_native_trampoline");
1345 } else {
1346 MonoTrampInfo *info;
1347 trampoline = (MonoPIFunc) mono_arch_get_interp_to_native_trampoline (&info);
1348 mono_tramp_info_register (info, NULL);
1350 mono_memory_barrier ();
1352 return trampoline;
1355 static void
1356 interp_to_native_trampoline (gpointer addr, gpointer ccontext)
1358 get_interp_to_native_trampoline () (addr, ccontext);
1361 /* MONO_NO_OPTIMIATION is needed due to usage of INTERP_PUSH_LMF_WITH_CTX. */
1362 #ifdef _MSC_VER
1363 #pragma optimize ("", off)
1364 #endif
1365 static MONO_NO_OPTIMIZATION MONO_NEVER_INLINE void
1366 ves_pinvoke_method (InterpFrame *frame, MonoMethodSignature *sig, MonoFuncV addr, gboolean string_ctor, ThreadContext *context, gboolean save_last_error)
1368 MonoLMFExt ext;
1369 gpointer args;
1371 frame->ex = NULL;
1373 g_assert (!frame->imethod);
1375 static MonoPIFunc entry_func = NULL;
1376 if (!entry_func) {
1377 #ifdef MONO_ARCH_HAS_NO_PROPER_MONOCTX
1378 ERROR_DECL (error);
1379 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);
1380 mono_error_assert_ok (error);
1381 #else
1382 entry_func = get_interp_to_native_trampoline ();
1383 #endif
1384 mono_memory_barrier ();
1387 #ifdef ENABLE_NETCORE
1388 if (save_last_error) {
1389 mono_marshal_clear_last_error ();
1391 #endif
1393 #ifdef MONO_ARCH_HAVE_INTERP_PINVOKE_TRAMP
1394 CallContext ccontext;
1395 mono_arch_set_native_call_context_args (&ccontext, frame, sig);
1396 args = &ccontext;
1397 #else
1398 InterpMethodArguments *margs = build_args_from_sig (sig, frame);
1399 args = margs;
1400 #endif
1402 INTERP_PUSH_LMF_WITH_CTX (frame, ext, exit_pinvoke);
1403 entry_func ((gpointer) addr, args);
1404 if (save_last_error)
1405 mono_marshal_set_last_error ();
1406 interp_pop_lmf (&ext);
1408 #ifdef MONO_ARCH_HAVE_INTERP_PINVOKE_TRAMP
1409 if (!frame->ex)
1410 mono_arch_get_native_call_context_ret (&ccontext, frame, sig);
1412 if (ccontext.stack != NULL)
1413 g_free (ccontext.stack);
1414 #else
1415 if (!frame->ex && !MONO_TYPE_ISSTRUCT (sig->ret))
1416 stackval_from_data (sig->ret, frame->retval, (char*)&frame->retval->data.p, sig->pinvoke);
1418 g_free (margs->iargs);
1419 g_free (margs->fargs);
1420 g_free (margs);
1421 #endif
1422 goto exit_pinvoke; // prevent unused label warning in some configurations
1423 exit_pinvoke:
1424 return;
1426 #ifdef _MSC_VER
1427 #pragma optimize ("", on)
1428 #endif
1431 * interp_init_delegate:
1433 * Initialize del->interp_method.
1435 static void
1436 interp_init_delegate (MonoDelegate *del, MonoError *error)
1438 MonoMethod *method;
1440 if (del->interp_method) {
1441 /* Delegate created by a call to ves_icall_mono_delegate_ctor_interp () */
1442 del->method = ((InterpMethod *)del->interp_method)->method;
1443 } else if (del->method) {
1444 /* Delegate created dynamically */
1445 del->interp_method = mono_interp_get_imethod (del->object.vtable->domain, del->method, error);
1446 } else {
1447 /* Created from JITted code */
1448 g_assert_not_reached ();
1451 method = ((InterpMethod*)del->interp_method)->method;
1452 if (del->target &&
1453 method &&
1454 method->flags & METHOD_ATTRIBUTE_VIRTUAL &&
1455 method->flags & METHOD_ATTRIBUTE_ABSTRACT &&
1456 mono_class_is_abstract (method->klass))
1457 del->interp_method = get_virtual_method ((InterpMethod*)del->interp_method, del->target->vtable);
1459 method = ((InterpMethod*)del->interp_method)->method;
1460 if (method && m_class_get_parent (method->klass) == mono_defaults.multicastdelegate_class) {
1461 const char *name = method->name;
1462 if (*name == 'I' && (strcmp (name, "Invoke") == 0)) {
1464 * When invoking the delegate interp_method is executed directly. If it's an
1465 * invoke make sure we replace it with the appropriate delegate invoke wrapper.
1467 * FIXME We should do this later, when we also know the delegate on which the
1468 * target method is called.
1470 del->interp_method = mono_interp_get_imethod (del->object.vtable->domain, mono_marshal_get_delegate_invoke (method, NULL), error);
1471 mono_error_assert_ok (error);
1475 if (!((InterpMethod *) del->interp_method)->transformed && method_is_dynamic (method)) {
1476 /* Return any errors from method compilation */
1477 mono_interp_transform_method ((InterpMethod *) del->interp_method, get_context (), error);
1478 return_if_nok (error);
1482 static void
1483 interp_delegate_ctor (MonoObjectHandle this_obj, MonoObjectHandle target, gpointer addr, MonoError *error)
1486 * addr is the result of an LDFTN opcode, i.e. an InterpMethod
1488 InterpMethod *imethod = (InterpMethod*)addr;
1490 if (!(imethod->method->flags & METHOD_ATTRIBUTE_STATIC)) {
1491 MonoMethod *invoke = mono_get_delegate_invoke_internal (mono_handle_class (this_obj));
1492 /* virtual invoke delegates must not have null check */
1493 if (mono_method_signature_internal (imethod->method)->param_count == mono_method_signature_internal (invoke)->param_count
1494 && MONO_HANDLE_IS_NULL (target)) {
1495 mono_error_set_argument (error, "this", "Delegate to an instance method cannot have null 'this'");
1496 return;
1500 g_assert (imethod->method);
1501 gpointer entry = mini_get_interp_callbacks ()->create_method_pointer (imethod->method, FALSE, error);
1502 return_if_nok (error);
1504 MONO_HANDLE_SETVAL (MONO_HANDLE_CAST (MonoDelegate, this_obj), interp_method, gpointer, imethod);
1506 mono_delegate_ctor (this_obj, target, entry, error);
1510 * From the spec:
1511 * runtime specifies that the implementation of the method is automatically
1512 * provided by the runtime and is primarily used for the methods of delegates.
1514 static MONO_NEVER_INLINE void
1515 ves_imethod (InterpFrame *frame, MonoMethod *method, MonoMethodSignature *sig, stackval *sp, stackval *retval)
1517 const char *name = method->name;
1518 mono_class_init_internal (method->klass);
1520 if (method->klass == mono_defaults.array_class) {
1521 if (!strcmp (name, "UnsafeMov")) {
1522 /* TODO: layout checks */
1523 stackval_from_data (sig->ret, retval, (char*) sp, FALSE);
1524 return;
1526 if (!strcmp (name, "UnsafeLoad")) {
1527 ves_array_get (frame, sp, retval, sig, FALSE);
1528 return;
1530 } else if (mini_class_is_system_array (method->klass)) {
1531 MonoObject *obj = (MonoObject*) sp->data.p;
1532 if (!obj) {
1533 frame->ex = mono_get_exception_null_reference ();
1534 return;
1536 if (*name == 'S' && (strcmp (name, "Set") == 0)) {
1537 ves_array_set (frame, sp, sig);
1538 return;
1540 if (*name == 'G' && (strcmp (name, "Get") == 0)) {
1541 ves_array_get (frame, sp, retval, sig, TRUE);
1542 return;
1546 g_error ("Don't know how to exec runtime method %s.%s::%s",
1547 m_class_get_name_space (method->klass), m_class_get_name (method->klass),
1548 method->name);
1551 #if DEBUG_INTERP
1552 static char*
1553 dump_stack (stackval *stack, stackval *sp)
1555 stackval *s = stack;
1556 GString *str = g_string_new ("");
1558 if (sp == stack)
1559 return g_string_free (str, FALSE);
1561 while (s < sp) {
1562 g_string_append_printf (str, "[%p (%lld)] ", s->data.l, s->data.l);
1563 ++s;
1565 return g_string_free (str, FALSE);
1568 static void
1569 dump_stackval (GString *str, stackval *s, MonoType *type)
1571 switch (type->type) {
1572 case MONO_TYPE_I1:
1573 case MONO_TYPE_U1:
1574 case MONO_TYPE_I2:
1575 case MONO_TYPE_U2:
1576 case MONO_TYPE_I4:
1577 case MONO_TYPE_U4:
1578 case MONO_TYPE_CHAR:
1579 case MONO_TYPE_BOOLEAN:
1580 g_string_append_printf (str, "[%d] ", s->data.i);
1581 break;
1582 case MONO_TYPE_STRING:
1583 case MONO_TYPE_SZARRAY:
1584 case MONO_TYPE_CLASS:
1585 case MONO_TYPE_OBJECT:
1586 case MONO_TYPE_ARRAY:
1587 case MONO_TYPE_PTR:
1588 case MONO_TYPE_I:
1589 case MONO_TYPE_U:
1590 g_string_append_printf (str, "[%p] ", s->data.p);
1591 break;
1592 case MONO_TYPE_VALUETYPE:
1593 if (m_class_is_enumtype (type->data.klass))
1594 g_string_append_printf (str, "[%d] ", s->data.i);
1595 else
1596 g_string_append_printf (str, "[vt:%p] ", s->data.p);
1597 break;
1598 case MONO_TYPE_R4:
1599 g_string_append_printf (str, "[%g] ", s->data.f_r4);
1600 break;
1601 case MONO_TYPE_R8:
1602 g_string_append_printf (str, "[%g] ", s->data.f);
1603 break;
1604 case MONO_TYPE_I8:
1605 case MONO_TYPE_U8:
1606 default: {
1607 GString *res = g_string_new ("");
1608 mono_type_get_desc (res, type, TRUE);
1609 g_string_append_printf (str, "[{%s} %lld/0x%0llx] ", res->str, s->data.l, s->data.l);
1610 g_string_free (res, TRUE);
1611 break;
1616 static char*
1617 dump_retval (InterpFrame *inv)
1619 GString *str = g_string_new ("");
1620 MonoType *ret = mono_method_signature_internal (inv->imethod->method)->ret;
1622 if (ret->type != MONO_TYPE_VOID)
1623 dump_stackval (str, inv->retval, ret);
1625 return g_string_free (str, FALSE);
1628 static char*
1629 dump_args (InterpFrame *inv)
1631 GString *str = g_string_new ("");
1632 int i;
1633 MonoMethodSignature *signature = mono_method_signature_internal (inv->imethod->method);
1635 if (signature->param_count == 0 && !signature->hasthis)
1636 return g_string_free (str, FALSE);
1638 if (signature->hasthis) {
1639 MonoMethod *method = inv->imethod->method;
1640 dump_stackval (str, inv->stack_args, m_class_get_byval_arg (method->klass));
1643 for (i = 0; i < signature->param_count; ++i)
1644 dump_stackval (str, inv->stack_args + (!!signature->hasthis) + i, signature->params [i]);
1646 return g_string_free (str, FALSE);
1648 #endif
1650 #define CHECK_ADD_OVERFLOW(a,b) \
1651 (gint32)(b) >= 0 ? (gint32)(G_MAXINT32) - (gint32)(b) < (gint32)(a) ? -1 : 0 \
1652 : (gint32)(G_MININT32) - (gint32)(b) > (gint32)(a) ? +1 : 0
1654 #define CHECK_SUB_OVERFLOW(a,b) \
1655 (gint32)(b) < 0 ? (gint32)(G_MAXINT32) + (gint32)(b) < (gint32)(a) ? -1 : 0 \
1656 : (gint32)(G_MININT32) + (gint32)(b) > (gint32)(a) ? +1 : 0
1658 #define CHECK_ADD_OVERFLOW_UN(a,b) \
1659 (guint32)(G_MAXUINT32) - (guint32)(b) < (guint32)(a) ? -1 : 0
1661 #define CHECK_SUB_OVERFLOW_UN(a,b) \
1662 (guint32)(a) < (guint32)(b) ? -1 : 0
1664 #define CHECK_ADD_OVERFLOW64(a,b) \
1665 (gint64)(b) >= 0 ? (gint64)(G_MAXINT64) - (gint64)(b) < (gint64)(a) ? -1 : 0 \
1666 : (gint64)(G_MININT64) - (gint64)(b) > (gint64)(a) ? +1 : 0
1668 #define CHECK_SUB_OVERFLOW64(a,b) \
1669 (gint64)(b) < 0 ? (gint64)(G_MAXINT64) + (gint64)(b) < (gint64)(a) ? -1 : 0 \
1670 : (gint64)(G_MININT64) + (gint64)(b) > (gint64)(a) ? +1 : 0
1672 #define CHECK_ADD_OVERFLOW64_UN(a,b) \
1673 (guint64)(G_MAXUINT64) - (guint64)(b) < (guint64)(a) ? -1 : 0
1675 #define CHECK_SUB_OVERFLOW64_UN(a,b) \
1676 (guint64)(a) < (guint64)(b) ? -1 : 0
1678 #if SIZEOF_VOID_P == 4
1679 #define CHECK_ADD_OVERFLOW_NAT(a,b) CHECK_ADD_OVERFLOW(a,b)
1680 #define CHECK_ADD_OVERFLOW_NAT_UN(a,b) CHECK_ADD_OVERFLOW_UN(a,b)
1681 #else
1682 #define CHECK_ADD_OVERFLOW_NAT(a,b) CHECK_ADD_OVERFLOW64(a,b)
1683 #define CHECK_ADD_OVERFLOW_NAT_UN(a,b) CHECK_ADD_OVERFLOW64_UN(a,b)
1684 #endif
1686 /* Resolves to TRUE if the operands would overflow */
1687 #define CHECK_MUL_OVERFLOW(a,b) \
1688 ((gint32)(a) == 0) || ((gint32)(b) == 0) ? 0 : \
1689 (((gint32)(a) > 0) && ((gint32)(b) == -1)) ? FALSE : \
1690 (((gint32)(a) < 0) && ((gint32)(b) == -1)) ? (a == G_MININT32) : \
1691 (((gint32)(a) > 0) && ((gint32)(b) > 0)) ? (gint32)(a) > ((G_MAXINT32) / (gint32)(b)) : \
1692 (((gint32)(a) > 0) && ((gint32)(b) < 0)) ? (gint32)(a) > ((G_MININT32) / (gint32)(b)) : \
1693 (((gint32)(a) < 0) && ((gint32)(b) > 0)) ? (gint32)(a) < ((G_MININT32) / (gint32)(b)) : \
1694 (gint32)(a) < ((G_MAXINT32) / (gint32)(b))
1696 #define CHECK_MUL_OVERFLOW_UN(a,b) \
1697 ((guint32)(a) == 0) || ((guint32)(b) == 0) ? 0 : \
1698 (guint32)(b) > ((G_MAXUINT32) / (guint32)(a))
1700 #define CHECK_MUL_OVERFLOW64(a,b) \
1701 ((gint64)(a) == 0) || ((gint64)(b) == 0) ? 0 : \
1702 (((gint64)(a) > 0) && ((gint64)(b) == -1)) ? FALSE : \
1703 (((gint64)(a) < 0) && ((gint64)(b) == -1)) ? (a == G_MININT64) : \
1704 (((gint64)(a) > 0) && ((gint64)(b) > 0)) ? (gint64)(a) > ((G_MAXINT64) / (gint64)(b)) : \
1705 (((gint64)(a) > 0) && ((gint64)(b) < 0)) ? (gint64)(a) > ((G_MININT64) / (gint64)(b)) : \
1706 (((gint64)(a) < 0) && ((gint64)(b) > 0)) ? (gint64)(a) < ((G_MININT64) / (gint64)(b)) : \
1707 (gint64)(a) < ((G_MAXINT64) / (gint64)(b))
1709 #define CHECK_MUL_OVERFLOW64_UN(a,b) \
1710 ((guint64)(a) == 0) || ((guint64)(b) == 0) ? 0 : \
1711 (guint64)(b) > ((G_MAXUINT64) / (guint64)(a))
1713 #if SIZEOF_VOID_P == 4
1714 #define CHECK_MUL_OVERFLOW_NAT(a,b) CHECK_MUL_OVERFLOW(a,b)
1715 #define CHECK_MUL_OVERFLOW_NAT_UN(a,b) CHECK_MUL_OVERFLOW_UN(a,b)
1716 #else
1717 #define CHECK_MUL_OVERFLOW_NAT(a,b) CHECK_MUL_OVERFLOW64(a,b)
1718 #define CHECK_MUL_OVERFLOW_NAT_UN(a,b) CHECK_MUL_OVERFLOW64_UN(a,b)
1719 #endif
1721 static MonoObject*
1722 interp_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError *error)
1724 InterpFrame frame;
1725 ThreadContext *context = get_context ();
1726 MonoMethodSignature *sig = mono_method_signature_internal (method);
1727 MonoClass *klass = mono_class_from_mono_type_internal (sig->ret);
1728 stackval result;
1729 MonoMethod *target_method = method;
1731 error_init (error);
1732 if (exc)
1733 *exc = NULL;
1735 frame.ex = NULL;
1737 MonoDomain *domain = mono_domain_get ();
1739 if (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
1740 target_method = mono_marshal_get_native_wrapper (target_method, FALSE, FALSE);
1741 MonoMethod *invoke_wrapper = mono_marshal_get_runtime_invoke_full (target_method, FALSE, TRUE);
1743 //* <code>MonoObject *runtime_invoke (MonoObject *this_obj, void **params, MonoObject **exc, void* method)</code>
1745 result.data.vt = alloca (mono_class_instance_size (klass));
1746 stackval args [4];
1748 if (sig->hasthis)
1749 args [0].data.p = obj;
1750 else
1751 args [0].data.p = NULL;
1752 args [1].data.p = params;
1753 args [2].data.p = exc;
1754 args [3].data.p = target_method;
1756 InterpMethod *imethod = mono_interp_get_imethod (domain, invoke_wrapper, error);
1757 mono_error_assert_ok (error);
1758 init_frame (&frame, NULL, imethod, args, &result);
1760 interp_exec_method (&frame, context, error);
1762 if (frame.ex) {
1763 if (exc) {
1764 *exc = (MonoObject*) frame.ex;
1765 return NULL;
1767 mono_error_set_exception_instance (error, frame.ex);
1768 return NULL;
1770 return (MonoObject*)result.data.p;
1773 typedef struct {
1774 InterpMethod *rmethod;
1775 gpointer this_arg;
1776 gpointer res;
1777 gpointer args [16];
1778 gpointer *many_args;
1779 } InterpEntryData;
1781 /* Main function for entering the interpreter from compiled code */
1782 static void
1783 interp_entry (InterpEntryData *data)
1785 InterpFrame frame;
1786 InterpMethod *rmethod;
1787 ThreadContext *context;
1788 stackval result;
1789 stackval *args;
1790 MonoMethod *method;
1791 MonoMethodSignature *sig;
1792 MonoType *type;
1793 gpointer orig_domain = NULL, attach_cookie;
1794 int i;
1796 if ((gsize)data->rmethod & 1) {
1797 /* Unbox */
1798 data->this_arg = mono_object_unbox_internal ((MonoObject*)data->this_arg);
1799 data->rmethod = (InterpMethod*)(gpointer)((gsize)data->rmethod & ~1);
1801 rmethod = data->rmethod;
1803 if (rmethod->needs_thread_attach)
1804 orig_domain = mono_threads_attach_coop (mono_domain_get (), &attach_cookie);
1806 context = get_context ();
1808 method = rmethod->method;
1809 sig = mono_method_signature_internal (method);
1811 // FIXME: Optimize this
1813 //printf ("%s\n", mono_method_full_name (method, 1));
1815 frame.ex = NULL;
1817 args = g_newa (stackval, sig->param_count + (sig->hasthis ? 1 : 0));
1818 if (sig->hasthis)
1819 args [0].data.p = data->this_arg;
1821 gpointer *params;
1822 if (data->many_args)
1823 params = data->many_args;
1824 else
1825 params = data->args;
1826 for (i = 0; i < sig->param_count; ++i) {
1827 int a_index = i + (sig->hasthis ? 1 : 0);
1828 if (sig->params [i]->byref) {
1829 args [a_index].data.p = params [i];
1830 continue;
1832 type = rmethod->param_types [i];
1833 switch (type->type) {
1834 case MONO_TYPE_VALUETYPE:
1835 args [a_index].data.p = params [i];
1836 break;
1837 case MONO_TYPE_GENERICINST:
1838 if (MONO_TYPE_IS_REFERENCE (type))
1839 args [a_index].data.p = *(gpointer*)params [i];
1840 else
1841 args [a_index].data.vt = params [i];
1842 break;
1843 default:
1844 stackval_from_data (type, &args [a_index], params [i], FALSE);
1845 break;
1849 memset (&result, 0, sizeof (result));
1850 init_frame (&frame, NULL, data->rmethod, args, &result);
1852 type = rmethod->rtype;
1853 switch (type->type) {
1854 case MONO_TYPE_GENERICINST:
1855 if (!MONO_TYPE_IS_REFERENCE (type))
1856 frame.retval->data.vt = data->res;
1857 break;
1858 case MONO_TYPE_VALUETYPE:
1859 frame.retval->data.vt = data->res;
1860 break;
1861 default:
1862 break;
1865 ERROR_DECL (error);
1866 interp_exec_method (&frame, context, error);
1868 if (rmethod->needs_thread_attach)
1869 mono_threads_detach_coop (orig_domain, &attach_cookie);
1871 if (mono_llvm_only) {
1872 if (frame.ex)
1873 mono_llvm_reraise_exception (frame.ex);
1874 } else {
1875 g_assert (frame.ex == NULL);
1878 type = rmethod->rtype;
1879 switch (type->type) {
1880 case MONO_TYPE_VOID:
1881 break;
1882 case MONO_TYPE_OBJECT:
1883 /* No need for a write barrier */
1884 *(MonoObject**)data->res = (MonoObject*)frame.retval->data.p;
1885 break;
1886 case MONO_TYPE_GENERICINST:
1887 if (MONO_TYPE_IS_REFERENCE (type)) {
1888 *(MonoObject**)data->res = (MonoObject*)frame.retval->data.p;
1889 } else {
1890 /* Already set before the call */
1892 break;
1893 case MONO_TYPE_VALUETYPE:
1894 /* Already set before the call */
1895 break;
1896 default:
1897 stackval_to_data (type, frame.retval, data->res, FALSE);
1898 break;
1902 static stackval *
1903 do_icall (InterpFrame *frame, MonoMethodSignature *sig, int op, stackval *sp, gpointer ptr, gboolean save_last_error)
1905 #ifdef ENABLE_NETCORE
1906 if (save_last_error)
1907 mono_marshal_clear_last_error ();
1908 #endif
1910 switch (op) {
1911 case MINT_ICALL_V_V: {
1912 typedef void (*T)(void);
1913 T func = (T)ptr;
1914 func ();
1915 break;
1917 case MINT_ICALL_V_P: {
1918 typedef gpointer (*T)(void);
1919 T func = (T)ptr;
1920 sp++;
1921 sp [-1].data.p = func ();
1922 break;
1924 case MINT_ICALL_P_V: {
1925 typedef void (*T)(gpointer);
1926 T func = (T)ptr;
1927 func (sp [-1].data.p);
1928 sp --;
1929 break;
1931 case MINT_ICALL_P_P: {
1932 typedef gpointer (*T)(gpointer);
1933 T func = (T)ptr;
1934 sp [-1].data.p = func (sp [-1].data.p);
1935 break;
1937 case MINT_ICALL_PP_V: {
1938 typedef void (*T)(gpointer,gpointer);
1939 T func = (T)ptr;
1940 sp -= 2;
1941 func (sp [0].data.p, sp [1].data.p);
1942 break;
1944 case MINT_ICALL_PP_P: {
1945 typedef gpointer (*T)(gpointer,gpointer);
1946 T func = (T)ptr;
1947 --sp;
1948 sp [-1].data.p = func (sp [-1].data.p, sp [0].data.p);
1949 break;
1951 case MINT_ICALL_PPP_V: {
1952 typedef void (*T)(gpointer,gpointer,gpointer);
1953 T func = (T)ptr;
1954 sp -= 3;
1955 func (sp [0].data.p, sp [1].data.p, sp [2].data.p);
1956 break;
1958 case MINT_ICALL_PPP_P: {
1959 typedef gpointer (*T)(gpointer,gpointer,gpointer);
1960 T func = (T)ptr;
1961 sp -= 2;
1962 sp [-1].data.p = func (sp [-1].data.p, sp [0].data.p, sp [1].data.p);
1963 break;
1965 case MINT_ICALL_PPPP_V: {
1966 typedef void (*T)(gpointer,gpointer,gpointer,gpointer);
1967 T func = (T)ptr;
1968 sp -= 4;
1969 func (sp [0].data.p, sp [1].data.p, sp [2].data.p, sp [3].data.p);
1970 break;
1972 case MINT_ICALL_PPPP_P: {
1973 typedef gpointer (*T)(gpointer,gpointer,gpointer,gpointer);
1974 T func = (T)ptr;
1975 sp -= 3;
1976 sp [-1].data.p = func (sp [-1].data.p, sp [0].data.p, sp [1].data.p, sp [2].data.p);
1977 break;
1979 case MINT_ICALL_PPPPP_V: {
1980 typedef void (*T)(gpointer,gpointer,gpointer,gpointer,gpointer);
1981 T func = (T)ptr;
1982 sp -= 5;
1983 func (sp [0].data.p, sp [1].data.p, sp [2].data.p, sp [3].data.p, sp [4].data.p);
1984 break;
1986 case MINT_ICALL_PPPPP_P: {
1987 typedef gpointer (*T)(gpointer,gpointer,gpointer,gpointer,gpointer);
1988 T func = (T)ptr;
1989 sp -= 4;
1990 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);
1991 break;
1993 case MINT_ICALL_PPPPPP_V: {
1994 typedef void (*T)(gpointer,gpointer,gpointer,gpointer,gpointer,gpointer);
1995 T func = (T)ptr;
1996 sp -= 6;
1997 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);
1998 break;
2000 case MINT_ICALL_PPPPPP_P: {
2001 typedef gpointer (*T)(gpointer,gpointer,gpointer,gpointer,gpointer,gpointer);
2002 T func = (T)ptr;
2003 sp -= 5;
2004 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);
2005 break;
2007 default:
2008 g_assert_not_reached ();
2011 if (save_last_error)
2012 mono_marshal_set_last_error ();
2014 /* convert the native representation to the stackval representation */
2015 if (sig)
2016 stackval_from_data (sig->ret, &sp [-1], (char*) &sp [-1].data.p, sig->pinvoke);
2018 return sp;
2021 /* MONO_NO_OPTIMIATION is needed due to usage of INTERP_PUSH_LMF_WITH_CTX. */
2022 #ifdef _MSC_VER
2023 #pragma optimize ("", off)
2024 #endif
2025 static MONO_NO_OPTIMIZATION MONO_NEVER_INLINE stackval *
2026 do_icall_wrapper (InterpFrame *frame, MonoMethodSignature *sig, int op, stackval *sp, gpointer ptr, gboolean save_last_error)
2028 MonoLMFExt ext;
2029 INTERP_PUSH_LMF_WITH_CTX (frame, ext, exit_icall);
2031 sp = do_icall (frame, sig, op, sp, ptr, save_last_error);
2033 interp_pop_lmf (&ext);
2035 goto exit_icall; // prevent unused label warning in some configurations
2036 exit_icall:
2037 return sp;
2039 #ifdef _MSC_VER
2040 #pragma optimize ("", on)
2041 #endif
2043 typedef struct {
2044 int pindex;
2045 gpointer jit_wrapper;
2046 gpointer *args;
2047 MonoFtnDesc *ftndesc;
2048 } JitCallCbData;
2050 static void
2051 jit_call_cb (gpointer arg)
2053 JitCallCbData *cb_data = (JitCallCbData*)arg;
2054 gpointer jit_wrapper = cb_data->jit_wrapper;
2055 int pindex = cb_data->pindex;
2056 gpointer *args = cb_data->args;
2057 MonoFtnDesc ftndesc = *cb_data->ftndesc;
2059 switch (pindex) {
2060 case 0: {
2061 typedef void (*T)(gpointer);
2062 T func = (T)jit_wrapper;
2064 func (&ftndesc);
2065 break;
2067 case 1: {
2068 typedef void (*T)(gpointer, gpointer);
2069 T func = (T)jit_wrapper;
2071 func (args [0], &ftndesc);
2072 break;
2074 case 2: {
2075 typedef void (*T)(gpointer, gpointer, gpointer);
2076 T func = (T)jit_wrapper;
2078 func (args [0], args [1], &ftndesc);
2079 break;
2081 case 3: {
2082 typedef void (*T)(gpointer, gpointer, gpointer, gpointer);
2083 T func = (T)jit_wrapper;
2085 func (args [0], args [1], args [2], &ftndesc);
2086 break;
2088 case 4: {
2089 typedef void (*T)(gpointer, gpointer, gpointer, gpointer, gpointer);
2090 T func = (T)jit_wrapper;
2092 func (args [0], args [1], args [2], args [3], &ftndesc);
2093 break;
2095 case 5: {
2096 typedef void (*T)(gpointer, gpointer, gpointer, gpointer, gpointer, gpointer);
2097 T func = (T)jit_wrapper;
2099 func (args [0], args [1], args [2], args [3], args [4], &ftndesc);
2100 break;
2102 case 6: {
2103 typedef void (*T)(gpointer, gpointer, gpointer, gpointer, gpointer, gpointer, gpointer);
2104 T func = (T)jit_wrapper;
2106 func (args [0], args [1], args [2], args [3], args [4], args [5], &ftndesc);
2107 break;
2109 case 7: {
2110 typedef void (*T)(gpointer, gpointer, gpointer, gpointer, gpointer, gpointer, gpointer, gpointer);
2111 T func = (T)jit_wrapper;
2113 func (args [0], args [1], args [2], args [3], args [4], args [5], args [6], &ftndesc);
2114 break;
2116 case 8: {
2117 typedef void (*T)(gpointer, gpointer, gpointer, gpointer, gpointer, gpointer, gpointer, gpointer, gpointer);
2118 T func = (T)jit_wrapper;
2120 func (args [0], args [1], args [2], args [3], args [4], args [5], args [6], args [7], &ftndesc);
2121 break;
2123 default:
2124 g_assert_not_reached ();
2125 break;
2129 static MONO_NEVER_INLINE stackval *
2130 do_jit_call (stackval *sp, unsigned char *vt_sp, ThreadContext *context, InterpFrame *frame, InterpMethod *rmethod, MonoError *error)
2132 MonoMethodSignature *sig;
2133 MonoFtnDesc ftndesc;
2134 guint8 res_buf [256];
2135 MonoType *type;
2136 MonoLMFExt ext;
2138 //printf ("jit_call: %s\n", mono_method_full_name (rmethod->method, 1));
2141 * Call JITted code through a gsharedvt_out wrapper. These wrappers receive every argument
2142 * by ref and return a return value using an explicit return value argument.
2144 if (!rmethod->jit_wrapper) {
2145 MonoMethod *method = rmethod->method;
2147 sig = mono_method_signature_internal (method);
2148 g_assert (sig);
2150 MonoMethod *wrapper = mini_get_gsharedvt_out_sig_wrapper (sig);
2151 //printf ("J: %s %s\n", mono_method_full_name (method, 1), mono_method_full_name (wrapper, 1));
2153 gpointer jit_wrapper = mono_jit_compile_method_jit_only (wrapper, error);
2154 mono_error_assert_ok (error);
2156 gpointer addr = mono_jit_compile_method_jit_only (method, error);
2157 return_val_if_nok (error, NULL);
2158 g_assert (addr);
2160 rmethod->jit_addr = addr;
2161 rmethod->jit_sig = sig;
2162 mono_memory_barrier ();
2163 rmethod->jit_wrapper = jit_wrapper;
2165 } else {
2166 sig = rmethod->jit_sig;
2169 sp -= sig->param_count;
2170 if (sig->hasthis)
2171 --sp;
2173 ftndesc.addr = rmethod->jit_addr;
2174 ftndesc.arg = NULL;
2176 // FIXME: Optimize this
2178 gpointer args [32];
2179 int pindex = 0;
2180 int stack_index = 0;
2181 if (rmethod->hasthis) {
2182 args [pindex ++] = sp [0].data.p;
2183 stack_index ++;
2185 type = rmethod->rtype;
2186 if (type->type != MONO_TYPE_VOID) {
2187 if (MONO_TYPE_ISSTRUCT (type))
2188 args [pindex ++] = vt_sp;
2189 else
2190 args [pindex ++] = res_buf;
2192 for (int i = 0; i < rmethod->param_count; ++i) {
2193 MonoType *t = rmethod->param_types [i];
2194 stackval *sval = &sp [stack_index + i];
2195 if (sig->params [i]->byref) {
2196 args [pindex ++] = sval->data.p;
2197 } else if (MONO_TYPE_ISSTRUCT (t)) {
2198 args [pindex ++] = sval->data.p;
2199 } else if (MONO_TYPE_IS_REFERENCE (t)) {
2200 args [pindex ++] = &sval->data.p;
2201 } else {
2202 switch (t->type) {
2203 case MONO_TYPE_I1:
2204 case MONO_TYPE_U1:
2205 case MONO_TYPE_I2:
2206 case MONO_TYPE_U2:
2207 case MONO_TYPE_I4:
2208 case MONO_TYPE_U4:
2209 case MONO_TYPE_VALUETYPE:
2210 args [pindex ++] = &sval->data.i;
2211 break;
2212 case MONO_TYPE_PTR:
2213 case MONO_TYPE_FNPTR:
2214 case MONO_TYPE_I:
2215 case MONO_TYPE_U:
2216 case MONO_TYPE_OBJECT:
2217 args [pindex ++] = &sval->data.p;
2218 break;
2219 case MONO_TYPE_I8:
2220 case MONO_TYPE_U8:
2221 args [pindex ++] = &sval->data.l;
2222 break;
2223 case MONO_TYPE_R4:
2224 args [pindex ++] = &sval->data.f_r4;
2225 break;
2226 case MONO_TYPE_R8:
2227 args [pindex ++] = &sval->data.f;
2228 break;
2229 default:
2230 printf ("%s\n", mono_type_full_name (t));
2231 g_assert_not_reached ();
2236 interp_push_lmf (&ext, frame);
2238 JitCallCbData cb_data;
2239 memset (&cb_data, 0, sizeof (cb_data));
2240 cb_data.jit_wrapper = rmethod->jit_wrapper;
2241 cb_data.pindex = pindex;
2242 cb_data.args = args;
2243 cb_data.ftndesc = &ftndesc;
2245 if (mono_aot_mode == MONO_AOT_MODE_LLVMONLY_INTERP) {
2246 /* Catch the exception thrown by the native code using a try-catch */
2247 gboolean thrown = FALSE;
2248 mono_llvm_cpp_catch_exception (jit_call_cb, &cb_data, &thrown);
2249 interp_pop_lmf (&ext);
2250 if (thrown) {
2251 MonoObject *obj = mono_llvm_load_exception ();
2252 g_assert (obj);
2253 mono_error_set_exception_instance (error, (MonoException*)obj);
2254 return sp;
2256 } else {
2257 jit_call_cb (&cb_data);
2258 interp_pop_lmf (&ext);
2261 MonoType *rtype = rmethod->rtype;
2262 switch (rtype->type) {
2263 case MONO_TYPE_VOID:
2264 case MONO_TYPE_OBJECT:
2265 case MONO_TYPE_STRING:
2266 case MONO_TYPE_CLASS:
2267 case MONO_TYPE_ARRAY:
2268 case MONO_TYPE_SZARRAY:
2269 case MONO_TYPE_I:
2270 case MONO_TYPE_U:
2271 case MONO_TYPE_PTR:
2272 sp->data.p = *(gpointer*)res_buf;
2273 break;
2274 case MONO_TYPE_I1:
2275 sp->data.i = *(gint8*)res_buf;
2276 break;
2277 case MONO_TYPE_U1:
2278 sp->data.i = *(guint8*)res_buf;
2279 break;
2280 case MONO_TYPE_I2:
2281 sp->data.i = *(gint16*)res_buf;
2282 break;
2283 case MONO_TYPE_U2:
2284 sp->data.i = *(guint16*)res_buf;
2285 break;
2286 case MONO_TYPE_I4:
2287 sp->data.i = *(gint32*)res_buf;
2288 break;
2289 case MONO_TYPE_U4:
2290 sp->data.i = *(guint32*)res_buf;
2291 break;
2292 case MONO_TYPE_I8:
2293 sp->data.l = *(gint64*)res_buf;
2294 break;
2295 case MONO_TYPE_U8:
2296 sp->data.l = *(guint64*)res_buf;
2297 break;
2298 case MONO_TYPE_R4:
2299 sp->data.f_r4 = *(float*)res_buf;
2300 break;
2301 case MONO_TYPE_R8:
2302 sp->data.f = *(double*)res_buf;
2303 break;
2304 case MONO_TYPE_TYPEDBYREF:
2305 case MONO_TYPE_VALUETYPE:
2306 /* The result was written to vt_sp */
2307 sp->data.p = vt_sp;
2308 break;
2309 case MONO_TYPE_GENERICINST:
2310 if (MONO_TYPE_IS_REFERENCE (rtype)) {
2311 sp->data.p = *(gpointer*)res_buf;
2312 } else {
2313 /* The result was written to vt_sp */
2314 sp->data.p = vt_sp;
2316 break;
2317 default:
2318 g_print ("%s\n", mono_type_full_name (rtype));
2319 g_assert_not_reached ();
2320 break;
2323 return sp;
2326 static MONO_NEVER_INLINE void
2327 do_debugger_tramp (void (*tramp) (void), InterpFrame *frame)
2329 MonoLMFExt ext;
2330 interp_push_lmf (&ext, frame);
2331 tramp ();
2332 interp_pop_lmf (&ext);
2335 static MONO_NEVER_INLINE void
2336 do_transform_method (InterpFrame *frame, ThreadContext *context)
2338 MonoLMFExt ext;
2339 /* Don't push lmf if we have no interp data */
2340 gboolean push_lmf = frame->parent != NULL;
2341 ERROR_DECL (error);
2343 /* Use the parent frame as the current frame is not complete yet */
2344 if (push_lmf)
2345 interp_push_lmf (&ext, frame->parent);
2347 mono_interp_transform_method (frame->imethod, context, error);
2348 frame->ex = mono_error_convert_to_exception (error);
2350 if (push_lmf)
2351 interp_pop_lmf (&ext);
2354 static MONO_NEVER_INLINE guchar*
2355 copy_varargs_vtstack (MonoMethodSignature *csig, stackval *sp, guchar *vt_sp)
2357 stackval *first_arg = sp - csig->param_count;
2360 * We need to have the varargs linearly on the stack so the ArgIterator
2361 * can iterate over them. We pass the signature first and then copy them
2362 * one by one on the vtstack.
2364 *(gpointer*)vt_sp = csig;
2365 vt_sp += sizeof (gpointer);
2367 for (int i = csig->sentinelpos; i < csig->param_count; i++) {
2368 int align, arg_size;
2369 arg_size = mono_type_stack_size (csig->params [i], &align);
2370 vt_sp = (guchar*)ALIGN_PTR_TO (vt_sp, align);
2372 stackval_to_data (csig->params [i], &first_arg [i], vt_sp, FALSE);
2373 vt_sp += arg_size;
2376 return (guchar*)ALIGN_PTR_TO (vt_sp, MINT_VT_ALIGNMENT);
2380 * These functions are the entry points into the interpreter from compiled code.
2381 * They are called by the interp_in wrappers. They have the following signature:
2382 * void (<optional this_arg>, <optional retval pointer>, <arg1>, ..., <argn>, <method ptr>)
2383 * They pack up their arguments into an InterpEntryData structure and call interp_entry ().
2384 * It would be possible for the wrappers to pack up the arguments etc, but that would make them bigger, and there are
2385 * more wrappers then these functions.
2386 * this/static * ret/void * 16 arguments -> 64 functions.
2389 #define MAX_INTERP_ENTRY_ARGS 8
2391 #define INTERP_ENTRY_BASE(_method, _this_arg, _res) \
2392 InterpEntryData data; \
2393 (data).rmethod = (_method); \
2394 (data).res = (_res); \
2395 (data).this_arg = (_this_arg); \
2396 (data).many_args = NULL;
2398 #define INTERP_ENTRY0(_this_arg, _res, _method) { \
2399 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2400 interp_entry (&data); \
2402 #define INTERP_ENTRY1(_this_arg, _res, _method) { \
2403 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2404 (data).args [0] = arg1; \
2405 interp_entry (&data); \
2407 #define INTERP_ENTRY2(_this_arg, _res, _method) { \
2408 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2409 (data).args [0] = arg1; \
2410 (data).args [1] = arg2; \
2411 interp_entry (&data); \
2413 #define INTERP_ENTRY3(_this_arg, _res, _method) { \
2414 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2415 (data).args [0] = arg1; \
2416 (data).args [1] = arg2; \
2417 (data).args [2] = arg3; \
2418 interp_entry (&data); \
2420 #define INTERP_ENTRY4(_this_arg, _res, _method) { \
2421 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2422 (data).args [0] = arg1; \
2423 (data).args [1] = arg2; \
2424 (data).args [2] = arg3; \
2425 (data).args [3] = arg4; \
2426 interp_entry (&data); \
2428 #define INTERP_ENTRY5(_this_arg, _res, _method) { \
2429 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2430 (data).args [0] = arg1; \
2431 (data).args [1] = arg2; \
2432 (data).args [2] = arg3; \
2433 (data).args [3] = arg4; \
2434 (data).args [4] = arg5; \
2435 interp_entry (&data); \
2437 #define INTERP_ENTRY6(_this_arg, _res, _method) { \
2438 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2439 (data).args [0] = arg1; \
2440 (data).args [1] = arg2; \
2441 (data).args [2] = arg3; \
2442 (data).args [3] = arg4; \
2443 (data).args [4] = arg5; \
2444 (data).args [5] = arg6; \
2445 interp_entry (&data); \
2447 #define INTERP_ENTRY7(_this_arg, _res, _method) { \
2448 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2449 (data).args [0] = arg1; \
2450 (data).args [1] = arg2; \
2451 (data).args [2] = arg3; \
2452 (data).args [3] = arg4; \
2453 (data).args [4] = arg5; \
2454 (data).args [5] = arg6; \
2455 (data).args [6] = arg7; \
2456 interp_entry (&data); \
2458 #define INTERP_ENTRY8(_this_arg, _res, _method) { \
2459 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2460 (data).args [0] = arg1; \
2461 (data).args [1] = arg2; \
2462 (data).args [2] = arg3; \
2463 (data).args [3] = arg4; \
2464 (data).args [4] = arg5; \
2465 (data).args [5] = arg6; \
2466 (data).args [6] = arg7; \
2467 (data).args [7] = arg8; \
2468 interp_entry (&data); \
2471 #define ARGLIST0 InterpMethod *rmethod
2472 #define ARGLIST1 gpointer arg1, InterpMethod *rmethod
2473 #define ARGLIST2 gpointer arg1, gpointer arg2, InterpMethod *rmethod
2474 #define ARGLIST3 gpointer arg1, gpointer arg2, gpointer arg3, InterpMethod *rmethod
2475 #define ARGLIST4 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, InterpMethod *rmethod
2476 #define ARGLIST5 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, gpointer arg5, InterpMethod *rmethod
2477 #define ARGLIST6 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, gpointer arg5, gpointer arg6, InterpMethod *rmethod
2478 #define ARGLIST7 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, gpointer arg5, gpointer arg6, gpointer arg7, InterpMethod *rmethod
2479 #define ARGLIST8 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, gpointer arg5, gpointer arg6, gpointer arg7, gpointer arg8, InterpMethod *rmethod
2481 static void interp_entry_static_0 (ARGLIST0) INTERP_ENTRY0 (NULL, NULL, rmethod)
2482 static void interp_entry_static_1 (ARGLIST1) INTERP_ENTRY1 (NULL, NULL, rmethod)
2483 static void interp_entry_static_2 (ARGLIST2) INTERP_ENTRY2 (NULL, NULL, rmethod)
2484 static void interp_entry_static_3 (ARGLIST3) INTERP_ENTRY3 (NULL, NULL, rmethod)
2485 static void interp_entry_static_4 (ARGLIST4) INTERP_ENTRY4 (NULL, NULL, rmethod)
2486 static void interp_entry_static_5 (ARGLIST5) INTERP_ENTRY5 (NULL, NULL, rmethod)
2487 static void interp_entry_static_6 (ARGLIST6) INTERP_ENTRY6 (NULL, NULL, rmethod)
2488 static void interp_entry_static_7 (ARGLIST7) INTERP_ENTRY7 (NULL, NULL, rmethod)
2489 static void interp_entry_static_8 (ARGLIST8) INTERP_ENTRY8 (NULL, NULL, rmethod)
2490 static void interp_entry_static_ret_0 (gpointer res, ARGLIST0) INTERP_ENTRY0 (NULL, res, rmethod)
2491 static void interp_entry_static_ret_1 (gpointer res, ARGLIST1) INTERP_ENTRY1 (NULL, res, rmethod)
2492 static void interp_entry_static_ret_2 (gpointer res, ARGLIST2) INTERP_ENTRY2 (NULL, res, rmethod)
2493 static void interp_entry_static_ret_3 (gpointer res, ARGLIST3) INTERP_ENTRY3 (NULL, res, rmethod)
2494 static void interp_entry_static_ret_4 (gpointer res, ARGLIST4) INTERP_ENTRY4 (NULL, res, rmethod)
2495 static void interp_entry_static_ret_5 (gpointer res, ARGLIST5) INTERP_ENTRY5 (NULL, res, rmethod)
2496 static void interp_entry_static_ret_6 (gpointer res, ARGLIST6) INTERP_ENTRY6 (NULL, res, rmethod)
2497 static void interp_entry_static_ret_7 (gpointer res, ARGLIST7) INTERP_ENTRY7 (NULL, res, rmethod)
2498 static void interp_entry_static_ret_8 (gpointer res, ARGLIST8) INTERP_ENTRY8 (NULL, res, rmethod)
2499 static void interp_entry_instance_0 (gpointer this_arg, ARGLIST0) INTERP_ENTRY0 (this_arg, NULL, rmethod)
2500 static void interp_entry_instance_1 (gpointer this_arg, ARGLIST1) INTERP_ENTRY1 (this_arg, NULL, rmethod)
2501 static void interp_entry_instance_2 (gpointer this_arg, ARGLIST2) INTERP_ENTRY2 (this_arg, NULL, rmethod)
2502 static void interp_entry_instance_3 (gpointer this_arg, ARGLIST3) INTERP_ENTRY3 (this_arg, NULL, rmethod)
2503 static void interp_entry_instance_4 (gpointer this_arg, ARGLIST4) INTERP_ENTRY4 (this_arg, NULL, rmethod)
2504 static void interp_entry_instance_5 (gpointer this_arg, ARGLIST5) INTERP_ENTRY5 (this_arg, NULL, rmethod)
2505 static void interp_entry_instance_6 (gpointer this_arg, ARGLIST6) INTERP_ENTRY6 (this_arg, NULL, rmethod)
2506 static void interp_entry_instance_7 (gpointer this_arg, ARGLIST7) INTERP_ENTRY7 (this_arg, NULL, rmethod)
2507 static void interp_entry_instance_8 (gpointer this_arg, ARGLIST8) INTERP_ENTRY8 (this_arg, NULL, rmethod)
2508 static void interp_entry_instance_ret_0 (gpointer this_arg, gpointer res, ARGLIST0) INTERP_ENTRY0 (this_arg, res, rmethod)
2509 static void interp_entry_instance_ret_1 (gpointer this_arg, gpointer res, ARGLIST1) INTERP_ENTRY1 (this_arg, res, rmethod)
2510 static void interp_entry_instance_ret_2 (gpointer this_arg, gpointer res, ARGLIST2) INTERP_ENTRY2 (this_arg, res, rmethod)
2511 static void interp_entry_instance_ret_3 (gpointer this_arg, gpointer res, ARGLIST3) INTERP_ENTRY3 (this_arg, res, rmethod)
2512 static void interp_entry_instance_ret_4 (gpointer this_arg, gpointer res, ARGLIST4) INTERP_ENTRY4 (this_arg, res, rmethod)
2513 static void interp_entry_instance_ret_5 (gpointer this_arg, gpointer res, ARGLIST5) INTERP_ENTRY5 (this_arg, res, rmethod)
2514 static void interp_entry_instance_ret_6 (gpointer this_arg, gpointer res, ARGLIST6) INTERP_ENTRY6 (this_arg, res, rmethod)
2515 static void interp_entry_instance_ret_7 (gpointer this_arg, gpointer res, ARGLIST7) INTERP_ENTRY7 (this_arg, res, rmethod)
2516 static void interp_entry_instance_ret_8 (gpointer this_arg, gpointer res, ARGLIST8) INTERP_ENTRY8 (this_arg, res, rmethod)
2518 #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
2520 static gpointer entry_funcs_static [MAX_INTERP_ENTRY_ARGS + 1] = { INTERP_ENTRY_FUNCLIST (static) };
2521 static gpointer entry_funcs_static_ret [MAX_INTERP_ENTRY_ARGS + 1] = { INTERP_ENTRY_FUNCLIST (static_ret) };
2522 static gpointer entry_funcs_instance [MAX_INTERP_ENTRY_ARGS + 1] = { INTERP_ENTRY_FUNCLIST (instance) };
2523 static gpointer entry_funcs_instance_ret [MAX_INTERP_ENTRY_ARGS + 1] = { INTERP_ENTRY_FUNCLIST (instance_ret) };
2525 /* General version for methods with more than MAX_INTERP_ENTRY_ARGS arguments */
2526 static void
2527 interp_entry_general (gpointer this_arg, gpointer res, gpointer *args, gpointer rmethod)
2529 INTERP_ENTRY_BASE ((InterpMethod*)rmethod, this_arg, res);
2530 data.many_args = args;
2531 interp_entry (&data);
2534 #ifdef MONO_ARCH_HAVE_INTERP_ENTRY_TRAMPOLINE
2536 // inline so we can alloc on stack
2537 #define alloc_storage_for_stackval(s, t, p) do { \
2538 if ((t)->type == MONO_TYPE_GENERICINST && !MONO_TYPE_IS_REFERENCE (t)) { \
2539 (s)->data.vt = alloca (mono_class_value_size (mono_class_from_mono_type_internal (t), NULL)); \
2540 } else if ((t)->type == MONO_TYPE_VALUETYPE) { \
2541 if (p) \
2542 (s)->data.vt = alloca (mono_class_native_size ((t)->data.klass, NULL)); \
2543 else \
2544 (s)->data.vt = alloca (mono_class_value_size ((t)->data.klass, NULL)); \
2546 } while (0)
2548 static void
2549 interp_entry_from_trampoline (gpointer ccontext_untyped, gpointer rmethod_untyped)
2551 InterpFrame frame;
2552 ThreadContext *context;
2553 stackval result;
2554 stackval *args;
2555 MonoMethod *method;
2556 MonoMethodSignature *sig;
2557 CallContext *ccontext = (CallContext*) ccontext_untyped;
2558 InterpMethod *rmethod = (InterpMethod*) rmethod_untyped;
2559 gpointer orig_domain = NULL, attach_cookie;
2560 int i;
2562 if (rmethod->needs_thread_attach)
2563 orig_domain = mono_threads_attach_coop (mono_domain_get (), &attach_cookie);
2565 context = get_context ();
2567 method = rmethod->method;
2568 sig = mono_method_signature_internal (method);
2570 frame.ex = NULL;
2572 args = (stackval*)alloca (sizeof (stackval) * (sig->param_count + (sig->hasthis ? 1 : 0)));
2574 init_frame (&frame, NULL, rmethod, args, &result);
2576 /* Allocate storage for value types */
2577 for (i = 0; i < sig->param_count; i++) {
2578 MonoType *type = sig->params [i];
2579 alloc_storage_for_stackval (&frame.stack_args [i + sig->hasthis], type, sig->pinvoke);
2582 if (sig->ret->type != MONO_TYPE_VOID)
2583 alloc_storage_for_stackval (frame.retval, sig->ret, sig->pinvoke);
2585 /* Copy the args saved in the trampoline to the frame stack */
2586 mono_arch_get_native_call_context_args (ccontext, &frame, sig);
2588 ERROR_DECL (error);
2589 interp_exec_method (&frame, context, error);
2591 if (rmethod->needs_thread_attach)
2592 mono_threads_detach_coop (orig_domain, &attach_cookie);
2594 // FIXME:
2595 g_assert (frame.ex == NULL);
2597 /* Write back the return value */
2598 mono_arch_set_native_call_context_ret (ccontext, &frame, sig);
2601 #else
2603 static void
2604 interp_entry_from_trampoline (gpointer ccontext_untyped, gpointer rmethod_untyped)
2606 g_assert_not_reached ();
2609 #endif /* MONO_ARCH_HAVE_INTERP_ENTRY_TRAMPOLINE */
2611 static InterpMethod*
2612 lookup_method_pointer (gpointer addr)
2614 MonoDomain *domain = mono_domain_get ();
2615 MonoJitDomainInfo *info = domain_jit_info (domain);
2616 InterpMethod *res = NULL;
2618 mono_domain_lock (domain);
2619 if (info->interp_method_pointer_hash)
2620 res = (InterpMethod*)g_hash_table_lookup (info->interp_method_pointer_hash, addr);
2621 mono_domain_unlock (domain);
2623 return res;
2626 #ifndef MONO_ARCH_HAVE_INTERP_NATIVE_TO_MANAGED
2627 static void
2628 interp_no_native_to_managed (void)
2630 g_error ("interpreter: native-to-managed transition not available on this platform");
2632 #endif
2634 static void
2635 no_llvmonly_interp_method_pointer (void)
2637 g_assert_not_reached ();
2641 * interp_create_method_pointer_llvmonly:
2643 * Return an ftndesc for entering the interpreter and executing METHOD.
2645 static MonoFtnDesc*
2646 interp_create_method_pointer_llvmonly (MonoMethod *method, gboolean unbox, MonoError *error)
2648 MonoDomain *domain = mono_domain_get ();
2649 gpointer addr, entry_func, entry_wrapper;
2650 MonoMethodSignature *sig;
2651 MonoMethod *wrapper;
2652 MonoJitDomainInfo *info;
2653 InterpMethod *imethod;
2655 imethod = mono_interp_get_imethod (domain, method, error);
2656 return_val_if_nok (error, NULL);
2658 if (unbox) {
2659 if (imethod->llvmonly_unbox_entry)
2660 return (MonoFtnDesc*)imethod->llvmonly_unbox_entry;
2661 } else {
2662 if (imethod->jit_entry)
2663 return (MonoFtnDesc*)imethod->jit_entry;
2666 sig = mono_method_signature_internal (method);
2669 * The entry functions need access to the method to call, so we have
2670 * to use a ftndesc. The caller uses a normal signature, while the
2671 * entry functions use a gsharedvt_in signature, so wrap the entry function in
2672 * a gsharedvt_in_sig wrapper.
2674 wrapper = mini_get_gsharedvt_in_sig_wrapper (sig);
2676 entry_wrapper = mono_jit_compile_method_jit_only (wrapper, error);
2677 mono_error_assertf_ok (error, "couldn't compile wrapper \"%s\" for \"%s\"",
2678 mono_method_get_name_full (wrapper, TRUE, TRUE, MONO_TYPE_NAME_FORMAT_IL),
2679 mono_method_get_name_full (method, TRUE, TRUE, MONO_TYPE_NAME_FORMAT_IL));
2681 if (sig->param_count > MAX_INTERP_ENTRY_ARGS) {
2682 g_assert_not_reached ();
2683 //entry_func = (gpointer)interp_entry_general;
2684 } else if (sig->hasthis) {
2685 if (sig->ret->type == MONO_TYPE_VOID)
2686 entry_func = entry_funcs_instance [sig->param_count];
2687 else
2688 entry_func = entry_funcs_instance_ret [sig->param_count];
2689 } else {
2690 if (sig->ret->type == MONO_TYPE_VOID)
2691 entry_func = entry_funcs_static [sig->param_count];
2692 else
2693 entry_func = entry_funcs_static_ret [sig->param_count];
2695 g_assert (entry_func);
2697 /* Encode unbox in the lower bit of imethod */
2698 gpointer entry_arg = imethod;
2699 if (unbox)
2700 entry_arg = (gpointer)(((gsize)entry_arg) | 1);
2701 MonoFtnDesc *entry_ftndesc = mini_llvmonly_create_ftndesc (mono_domain_get (), entry_func, entry_arg);
2703 addr = mini_llvmonly_create_ftndesc (mono_domain_get (), entry_wrapper, entry_ftndesc);
2705 info = domain_jit_info (domain);
2706 mono_domain_lock (domain);
2707 if (!info->interp_method_pointer_hash)
2708 info->interp_method_pointer_hash = g_hash_table_new (NULL, NULL);
2709 g_hash_table_insert (info->interp_method_pointer_hash, addr, imethod);
2710 mono_domain_unlock (domain);
2712 mono_memory_barrier ();
2713 if (unbox)
2714 imethod->llvmonly_unbox_entry = addr;
2715 else
2716 imethod->jit_entry = addr;
2718 return (MonoFtnDesc*)addr;
2722 * interp_create_method_pointer:
2724 * Return a function pointer which can be used to call METHOD using the
2725 * interpreter. Return NULL for methods which are not supported.
2727 static gpointer
2728 interp_create_method_pointer (MonoMethod *method, gboolean compile, MonoError *error)
2730 #ifndef MONO_ARCH_HAVE_INTERP_NATIVE_TO_MANAGED
2731 if (mono_llvm_only)
2732 return (gpointer)no_llvmonly_interp_method_pointer;
2733 return (gpointer)interp_no_native_to_managed;
2734 #else
2735 gpointer addr, entry_func, entry_wrapper = NULL;
2736 MonoDomain *domain = mono_domain_get ();
2737 MonoJitDomainInfo *info;
2738 InterpMethod *imethod = mono_interp_get_imethod (domain, method, error);
2740 if (mono_llvm_only)
2741 return (gpointer)no_llvmonly_interp_method_pointer;
2743 if (imethod->jit_entry)
2744 return imethod->jit_entry;
2746 if (compile && !imethod->transformed) {
2747 /* Return any errors from method compilation */
2748 mono_interp_transform_method (imethod, get_context (), error);
2749 return_val_if_nok (error, NULL);
2752 MonoMethodSignature *sig = mono_method_signature_internal (method);
2754 if (mono_llvm_only)
2755 /* The caller should call interp_create_method_pointer_llvmonly */
2756 g_assert_not_reached ();
2758 if (method->wrapper_type && method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE)
2759 return imethod;
2761 #ifndef MONO_ARCH_HAVE_FTNPTR_ARG_TRAMPOLINE
2763 * Interp in wrappers get the argument in the rgctx register. If
2764 * MONO_ARCH_HAVE_FTNPTR_ARG_TRAMPOLINE is defined it means that
2765 * on that arch the rgctx register is not scratch, so we use a
2766 * separate temp register. We should update the wrappers for this
2767 * if we really care about those architectures (arm).
2769 MonoMethod *wrapper = mini_get_interp_in_wrapper (sig);
2771 entry_wrapper = mono_jit_compile_method_jit_only (wrapper, error);
2772 #endif
2773 if (entry_wrapper) {
2774 if (sig->param_count > MAX_INTERP_ENTRY_ARGS) {
2775 entry_func = (gpointer)interp_entry_general;
2776 } else if (sig->hasthis) {
2777 if (sig->ret->type == MONO_TYPE_VOID)
2778 entry_func = entry_funcs_instance [sig->param_count];
2779 else
2780 entry_func = entry_funcs_instance_ret [sig->param_count];
2781 } else {
2782 if (sig->ret->type == MONO_TYPE_VOID)
2783 entry_func = entry_funcs_static [sig->param_count];
2784 else
2785 entry_func = entry_funcs_static_ret [sig->param_count];
2787 } else {
2788 #ifndef MONO_ARCH_HAVE_INTERP_ENTRY_TRAMPOLINE
2789 mono_error_assertf_ok (error, "couldn't compile wrapper \"%s\" for \"%s\"",
2790 mono_method_get_name_full (wrapper, TRUE, TRUE, MONO_TYPE_NAME_FORMAT_IL),
2791 mono_method_get_name_full (method, TRUE, TRUE, MONO_TYPE_NAME_FORMAT_IL));
2792 #else
2793 mono_error_cleanup (error);
2794 error_init_reuse (error);
2795 if (!mono_native_to_interp_trampoline) {
2796 if (mono_aot_only) {
2797 mono_native_to_interp_trampoline = (MonoFuncV)mono_aot_get_trampoline ("native_to_interp_trampoline");
2798 } else {
2799 MonoTrampInfo *info;
2800 mono_native_to_interp_trampoline = (MonoFuncV)mono_arch_get_native_to_interp_trampoline (&info);
2801 mono_tramp_info_register (info, NULL);
2804 entry_wrapper = (gpointer)mono_native_to_interp_trampoline;
2805 /* We need the lmf wrapper only when being called from mixed mode */
2806 if (sig->pinvoke)
2807 entry_func = (gpointer)interp_entry_from_trampoline;
2808 else {
2809 static gpointer cached_func = NULL;
2810 if (!cached_func) {
2811 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);
2812 mono_memory_barrier ();
2814 entry_func = cached_func;
2816 #endif
2819 g_assert (entry_func);
2820 /* This is the argument passed to the interp_in wrapper by the static rgctx trampoline */
2821 MonoFtnDesc *ftndesc = g_new0 (MonoFtnDesc, 1);
2822 ftndesc->addr = entry_func;
2823 ftndesc->arg = imethod;
2824 mono_error_assert_ok (error);
2827 * The wrapper is called by compiled code, which doesn't pass the extra argument, so we pass it in the
2828 * rgctx register using a trampoline.
2831 addr = mono_create_ftnptr_arg_trampoline (ftndesc, entry_wrapper);
2833 info = domain_jit_info (domain);
2834 mono_domain_lock (domain);
2835 if (!info->interp_method_pointer_hash)
2836 info->interp_method_pointer_hash = g_hash_table_new (NULL, NULL);
2837 g_hash_table_insert (info->interp_method_pointer_hash, addr, imethod);
2838 mono_domain_unlock (domain);
2840 mono_memory_barrier ();
2841 imethod->jit_entry = addr;
2843 return addr;
2844 #endif
2847 #if COUNT_OPS
2848 static int opcode_counts[512];
2850 #define COUNT_OP(op) opcode_counts[op]++
2851 #else
2852 #define COUNT_OP(op)
2853 #endif
2855 #if DEBUG_INTERP
2856 #define DUMP_INSTR() \
2857 if (tracing > 1) { \
2858 char *ins; \
2859 if (sp > frame->stack) { \
2860 ins = dump_stack (frame->stack, sp); \
2861 } else { \
2862 ins = g_strdup (""); \
2864 sp->data.l = 0; \
2865 output_indent (); \
2866 char *mn = mono_method_full_name (frame->imethod->method, FALSE); \
2867 char *disasm = mono_interp_dis_mintop(imethod->code, ip); \
2868 g_print ("(%p) %s -> %s\t%d:%s\n", mono_thread_internal_current (), mn, disasm, vt_sp - vtalloc, ins); \
2869 g_free (mn); \
2870 g_free (ins); \
2871 g_free (disasm); \
2873 #else
2874 #define DUMP_INSTR()
2875 #endif
2877 #define INIT_VTABLE(vtable) do { \
2878 if (G_UNLIKELY (!(vtable)->initialized)) { \
2879 mono_runtime_class_init_full ((vtable), error); \
2880 if (!is_ok (error)) \
2881 THROW_EX (mono_error_convert_to_exception (error), ip); \
2883 } while (0);
2885 static MONO_NEVER_INLINE MonoObject*
2886 mono_interp_new (MonoDomain* domain, MonoClass* klass)
2888 ERROR_DECL (error);
2889 MonoObject* const object = mono_object_new_checked (domain, klass, error);
2890 mono_error_cleanup (error); // FIXME: do not swallow the error
2891 return object;
2894 static
2895 #ifndef DISABLE_REMOTING
2896 MONO_NEVER_INLINE // To reduce stack.
2897 #endif
2898 void
2899 mono_interp_load_remote_field (
2900 InterpMethod* imethod,
2901 MonoObject* o,
2902 const guint16* ip,
2903 stackval* sp)
2905 g_assert (o); // Caller checks and throws exception properly.
2907 void* addr;
2908 MonoClassField* const field = (MonoClassField*)imethod->data_items[* (guint16 *)(ip + 1)];
2910 #ifndef DISABLE_REMOTING
2911 gpointer tmp;
2912 if (mono_object_is_transparent_proxy (o)) {
2913 MonoClass * const klass = ((MonoTransparentProxy*)o)->remote_class->proxy_class;
2914 ERROR_DECL (error);
2915 addr = mono_load_remote_field_checked (o, klass, field, &tmp, error);
2916 mono_error_cleanup (error); /* FIXME: don't swallow the error */
2917 } else
2918 #endif
2919 addr = (char*)o + field->offset;
2920 stackval_from_data (field->type, &sp [-1], addr, FALSE);
2923 static
2924 #ifndef DISABLE_REMOTING
2925 MONO_NEVER_INLINE // To reduce stack.
2926 #endif
2927 guchar* // Return new vt_sp instead of take-address.
2928 mono_interp_load_remote_field_vt (
2929 InterpMethod* imethod,
2930 MonoObject* o,
2931 const guint16* ip,
2932 stackval* sp,
2933 guchar* vt_sp)
2935 g_assert (o); // Caller checks and throws exception properly.
2937 void* addr;
2938 MonoClassField* const field = (MonoClassField*)imethod->data_items[* (guint16 *)(ip + 1)];
2939 MonoClass* klass = mono_class_from_mono_type_internal (field->type);
2940 int const i32 = mono_class_value_size (klass, NULL);
2942 #ifndef DISABLE_REMOTING
2943 gpointer tmp;
2944 if (mono_object_is_transparent_proxy (o)) {
2945 klass = ((MonoTransparentProxy*)o)->remote_class->proxy_class;
2946 ERROR_DECL (error);
2947 addr = mono_load_remote_field_checked (o, klass, field, &tmp, error);
2948 mono_error_cleanup (error); /* FIXME: don't swallow the error */
2949 } else
2950 #endif
2951 addr = (char*)o + field->offset;
2952 sp [-1].data.p = vt_sp;
2953 memcpy (vt_sp, addr, i32);
2954 return vt_sp + ALIGN_TO (i32, MINT_VT_ALIGNMENT);
2957 static MONO_NEVER_INLINE gboolean
2958 mono_interp_isinst (MonoObject* object, MonoClass* klass)
2960 ERROR_DECL (error);
2961 const gboolean isinst = mono_object_isinst_checked (object, klass, error) != NULL;
2962 mono_error_cleanup (error); // FIXME: do not swallow the error
2963 return isinst;
2967 * GC SAFETY:
2969 * The interpreter executes in gc unsafe (non-preempt) mode. On wasm, the C stack is
2970 * scannable but the wasm stack is not, so to make the code GC safe, the following rules
2971 * should be followed:
2972 * - every objref handled by the code needs to have a copy stored inside InterpFrame,
2973 * in stackval->data.o. For objrefs which are not yet on the IL stack, they can be stored
2974 * in frame->o. This will ensure the objects are pinned. The 'frame' local is assumed
2975 * to be allocated to the C stack and not to registers.
2976 * - minimalize the number of MonoObject* locals/arguments.
2979 #ifdef TARGET_WASM
2980 #define frame_objref(frame) (frame)->o
2981 #else
2982 #define frame_objref(frame) o
2983 #endif
2985 // This function is outlined to help save stack in its caller, on the premise
2986 // that it is relatively rarely called. This also lets it use alloca.
2987 static MONO_NEVER_INLINE void
2988 mono_interp_calli_nat_dynamic_pinvoke (
2989 // Parameters are sorted by name.
2990 InterpFrame* child_frame,
2991 guchar* code,
2992 ThreadContext* context,
2993 MonoMethodSignature* csignature,
2994 MonoError* error)
2996 // Recompute to limit parameters, which can also contribute to caller stack.
2997 InterpMethod* const imethod = child_frame->parent->imethod;
2999 g_assert (imethod->method->dynamic && csignature->pinvoke);
3001 /* Pinvoke call is missing the wrapper. See mono_get_native_calli_wrapper */
3002 MonoMarshalSpec** mspecs = g_newa (MonoMarshalSpec*, csignature->param_count + 1);
3003 memset (mspecs, 0, sizeof (MonoMarshalSpec*) * (csignature->param_count + 1));
3005 MonoMethodPInvoke iinfo;
3006 memset (&iinfo, 0, sizeof (iinfo));
3008 MonoMethod* m = mono_marshal_get_native_func_wrapper (m_class_get_image (imethod->method->klass), csignature, &iinfo, mspecs, code);
3010 for (int i = csignature->param_count; i >= 0; i--)
3011 if (mspecs [i])
3012 mono_metadata_free_marshal_spec (mspecs [i]);
3015 ERROR_DECL (error);
3016 child_frame->imethod = mono_interp_get_imethod (imethod->domain, m, error);
3017 mono_error_cleanup (error); /* FIXME: don't swallow the error */
3020 interp_exec_method (child_frame, context, error);
3023 // Leave is split into pieces in order to consume less stack,
3024 // but not have to change how exception handling macros access labels and locals.
3025 static MONO_NEVER_INLINE MonoException*
3026 mono_interp_leave (InterpFrame* child_frame)
3028 stackval tmp_sp;
3030 * We need for mono_thread_get_undeniable_exception to be able to unwind
3031 * to check the abort threshold. For this to work we use child_frame as a
3032 * dummy frame that is stored in the lmf and serves as the transition frame
3034 do_icall_wrapper (child_frame, NULL, MINT_ICALL_V_P, &tmp_sp, (gpointer)mono_thread_get_undeniable_exception, FALSE);
3036 return (MonoException*)tmp_sp.data.p;
3039 static MONO_NEVER_INLINE void
3040 mono_interp_newobj_vt (
3041 // Parameters are sorted by name and parameter list is minimized
3042 // to reduce stack use in caller, on e.g. NT/AMD64 (up to 4 parameters
3043 // use no stack in caller).
3044 InterpFrame* child_frame,
3045 ThreadContext* context,
3046 MonoError* error)
3048 stackval* const sp = child_frame->stack_args;
3050 stackval valuetype_this;
3052 memset (&valuetype_this, 0, sizeof (stackval));
3053 sp->data.p = &valuetype_this;
3055 // FIXME It is unfortunate to outline a recursive case as it
3056 // increases its stack usage. We do this however as it conserves
3057 // stack for all the other recursive cases.
3058 interp_exec_method (child_frame, context, error);
3060 CHECK_RESUME_STATE (context);
3062 *sp = valuetype_this;
3063 resume:
3067 static MONO_NEVER_INLINE MonoException*
3068 mono_interp_newobj (
3069 // Parameters are sorted by name and parameter list is minimized
3070 // to reduce stack use in caller, on e.g. NT/AMD64 (up to 4 parameters
3071 // use no stack in caller).
3072 InterpFrame* child_frame,
3073 ThreadContext* context,
3074 MonoError* error,
3075 guchar* vt_sp)
3077 InterpFrame* const frame = child_frame->parent;
3078 InterpMethod* const imethod = frame->imethod;
3079 stackval* const sp = child_frame->stack_args;
3081 MonoObject* o = NULL; // See the comment about GC safety above.
3082 stackval valuetype_this;
3083 stackval retval;
3085 MonoClass * const newobj_class = child_frame->imethod->method->klass;
3086 /*if (profiling_classes) {
3087 guint count = GPOINTER_TO_UINT (g_hash_table_lookup (profiling_classes, newobj_class));
3088 count++;
3089 g_hash_table_insert (profiling_classes, newobj_class, GUINT_TO_POINTER (count));
3093 * First arg is the object.
3095 if (m_class_is_valuetype (newobj_class)) {
3096 MonoType *t = m_class_get_byval_arg (newobj_class);
3097 memset (&valuetype_this, 0, sizeof (stackval));
3098 if (!m_class_is_enumtype (newobj_class) && (t->type == MONO_TYPE_VALUETYPE || (t->type == MONO_TYPE_GENERICINST && mono_type_generic_inst_is_valuetype (t)))) {
3099 sp->data.p = vt_sp;
3100 valuetype_this.data.p = vt_sp;
3101 } else {
3102 sp->data.p = &valuetype_this;
3104 } else {
3105 if (newobj_class != mono_defaults.string_class) {
3106 MonoVTable *vtable = mono_class_vtable_checked (imethod->domain, newobj_class, error);
3107 if (!is_ok (error) || !mono_runtime_class_init_full (vtable, error)) {
3108 MonoException* const exc = mono_error_convert_to_exception (error);
3109 g_assert (exc);
3110 return exc;
3112 ERROR_DECL (error);
3113 frame_objref (frame) = mono_object_new_checked (imethod->domain, newobj_class, error);
3114 mono_error_cleanup (error); // FIXME: do not swallow the error
3115 EXCEPTION_CHECKPOINT_IN_HELPER_FUNCTION;
3116 sp->data.o = frame_objref (frame);
3117 #ifndef DISABLE_REMOTING
3118 if (mono_object_is_transparent_proxy (frame_objref (frame))) {
3119 MonoMethod *remoting_invoke_method = mono_marshal_get_remoting_invoke_with_check (child_frame->imethod->method, error);
3120 mono_error_assert_ok (error);
3121 child_frame->imethod = mono_interp_get_imethod (imethod->domain, remoting_invoke_method, error);
3122 mono_error_assert_ok (error);
3124 #endif
3125 } else {
3126 sp->data.p = NULL;
3127 child_frame->retval = &retval;
3131 interp_exec_method (child_frame, context, error);
3133 CHECK_RESUME_STATE (context);
3136 * a constructor returns void, but we need to return the object we created
3138 if (m_class_is_valuetype (newobj_class) && !m_class_is_enumtype (newobj_class)) {
3139 *sp = valuetype_this;
3140 } else if (newobj_class == mono_defaults.string_class) {
3141 *sp = retval;
3142 } else {
3143 sp->data.o = frame_objref (frame);
3145 resume:
3146 return NULL;
3149 static MONO_NEVER_INLINE void
3150 mono_interp_enum_hasflag (stackval* sp, MonoClass* klass)
3152 guint64 a_val = 0, b_val = 0;
3154 stackval_to_data (m_class_get_byval_arg (klass), --sp, &b_val, FALSE);
3155 stackval_to_data (m_class_get_byval_arg (klass), --sp, &a_val, FALSE);
3156 sp->data.i = (a_val & b_val) == b_val;
3159 static MONO_NEVER_INLINE int
3160 mono_interp_box_nullable (InterpFrame* frame, const guint16* ip, stackval* sp, MonoError* error)
3162 InterpMethod* const imethod = frame->imethod;
3163 MonoClass* const c = (MonoClass*)imethod->data_items [*(const guint16*)(ip + 1)];
3165 int const size = mono_class_value_size (c, NULL);
3167 guint16 offset = *(const guint16*)(ip + 2);
3168 gboolean const pop_vt_sp = !(offset & BOX_NOT_CLEAR_VT_SP);
3169 offset &= ~BOX_NOT_CLEAR_VT_SP;
3171 sp [-1 - offset].data.o = mono_nullable_box (sp [-1 - offset].data.p, c, error);
3172 mono_error_cleanup (error); /* FIXME: don't swallow the error */
3174 return pop_vt_sp ? ALIGN_TO (size, MINT_VT_ALIGNMENT) : 0;
3177 static MONO_NEVER_INLINE int
3178 mono_interp_box_vt (InterpFrame* frame, const guint16* ip, stackval* sp)
3180 InterpMethod* const imethod = frame->imethod;
3182 MonoObject* o; // See the comment about GC safety.
3183 MonoVTable * const vtable = (MonoVTable*)imethod->data_items [*(const guint16*)(ip + 1)];
3184 MonoClass* const c = vtable->klass;
3186 int const size = mono_class_value_size (c, NULL);
3188 guint16 offset = *(const guint16*)(ip + 2);
3189 gboolean const pop_vt_sp = !(offset & BOX_NOT_CLEAR_VT_SP);
3190 offset &= ~BOX_NOT_CLEAR_VT_SP;
3192 frame_objref (frame) = mono_gc_alloc_obj (vtable, m_class_get_instance_size (vtable->klass));
3193 mono_value_copy_internal (mono_object_get_data (frame_objref (frame)), sp [-1 - offset].data.p, c);
3195 sp [-1 - offset].data.p = frame_objref (frame);
3196 return pop_vt_sp ? ALIGN_TO (size, MINT_VT_ALIGNMENT) : 0;
3199 static MONO_NEVER_INLINE int
3200 mono_interp_store_remote_field_vt (InterpFrame* frame, const guint16* ip, stackval* sp, MonoError* error)
3202 InterpMethod* const imethod = frame->imethod;
3203 MonoClassField *field;
3205 MonoObject* const o = sp [-2].data.o;
3207 field = (MonoClassField*)imethod->data_items[* (guint16 *)(ip + 1)];
3208 MonoClass *klass = mono_class_from_mono_type_internal (field->type);
3209 int const i32 = mono_class_value_size (klass, NULL);
3211 #ifndef DISABLE_REMOTING
3212 if (mono_object_is_transparent_proxy (o)) {
3213 MonoClass *klass = ((MonoTransparentProxy*)o)->remote_class->proxy_class;
3214 mono_store_remote_field_checked (o, klass, field, sp [-1].data.p, error);
3215 mono_error_cleanup (error); /* FIXME: don't swallow the error */
3216 } else
3217 #endif
3218 mono_value_copy_internal ((char *) o + field->offset, sp [-1].data.p, klass);
3220 return ALIGN_TO (i32, MINT_VT_ALIGNMENT);
3224 * If EXIT_AT_FINALLY is not -1, exit after exiting the finally clause with that index.
3225 * If BASE_FRAME is not NULL, copy arguments/locals from BASE_FRAME.
3226 * The ERROR argument is used to avoid declaring an error object for every interp frame, its not used
3227 * to return error information.
3229 static void
3230 interp_exec_method_full (InterpFrame *frame, ThreadContext *context, FrameClauseArgs *clause_args, MonoError *error)
3232 InterpFrame child_frame;
3233 GSList *finally_ips = NULL;
3234 const guint16 *endfinally_ip = NULL;
3235 const guint16 *ip = NULL;
3236 stackval *sp;
3237 #if DEBUG_INTERP
3238 gint tracing = global_tracing;
3239 unsigned char *vtalloc;
3240 #endif
3241 unsigned char *vt_sp;
3242 unsigned char *locals = NULL;
3243 #if USE_COMPUTED_GOTO
3244 static void * const in_labels[] = {
3245 #define OPDEF(a,b,c,d) &&LAB_ ## a,
3246 #include "mintops.def"
3248 #endif
3250 frame->ex = NULL;
3251 #if DEBUG_INTERP
3252 debug_enter (frame, &tracing);
3253 #endif
3255 if (!frame->imethod->transformed) {
3256 #if DEBUG_INTERP
3257 char *mn = mono_method_full_name (frame->imethod->method, TRUE);
3258 g_print ("(%p) Transforming %s\n", mono_thread_internal_current (), mn);
3259 g_free (mn);
3260 #endif
3262 frame->ip = NULL;
3263 do_transform_method (frame, context);
3264 if (frame->ex)
3265 THROW_EX (frame->ex, NULL);
3266 EXCEPTION_CHECKPOINT;
3269 if (!clause_args) {
3270 frame->stack = (stackval*)g_alloca (frame->imethod->alloca_size);
3271 ip = frame->imethod->code;
3272 } else {
3273 ip = clause_args->start_with_ip;
3274 if (clause_args->base_frame) {
3275 frame->stack = (stackval*)g_alloca (frame->imethod->alloca_size);
3276 memcpy (frame->stack, clause_args->base_frame->stack, frame->imethod->alloca_size);
3279 sp = frame->stack;
3280 vt_sp = (unsigned char *) sp + frame->imethod->stack_size;
3281 #if DEBUG_INTERP
3282 vtalloc = vt_sp;
3283 #endif
3284 locals = frame_locals (frame);
3285 child_frame.parent = frame;
3287 if (clause_args && clause_args->filter_exception) {
3288 sp->data.p = clause_args->filter_exception;
3289 sp++;
3292 //g_print ("(%p) Call %s\n", mono_thread_internal_current (), mono_method_get_full_name (frame->imethod->method));
3295 * using while (ip < end) may result in a 15% performance drop,
3296 * but it may be useful for debug
3298 while (1) {
3299 main_loop:
3300 /* g_assert (sp >= frame->stack); */
3301 /* g_assert(vt_sp - vtalloc <= frame->imethod->vt_stack_size); */
3302 DUMP_INSTR();
3303 MINT_IN_SWITCH (*ip) {
3304 MINT_IN_CASE(MINT_INITLOCALS)
3305 memset (frame_locals (frame), 0, frame->imethod->locals_size);
3306 ++ip;
3307 MINT_IN_BREAK;
3308 MINT_IN_CASE(MINT_NOP)
3309 ++ip;
3310 MINT_IN_BREAK;
3311 MINT_IN_CASE(MINT_NIY)
3312 g_error ("mint_niy: instruction not implemented yet. This shouldn't happen.");
3313 MINT_IN_BREAK;
3314 MINT_IN_CASE(MINT_BREAK)
3315 ++ip;
3316 do_debugger_tramp (mini_get_dbg_callbacks ()->user_break, frame);
3317 MINT_IN_BREAK;
3318 MINT_IN_CASE(MINT_BREAKPOINT)
3319 ++ip;
3320 mono_break ();
3321 MINT_IN_BREAK;
3322 MINT_IN_CASE(MINT_LDNULL)
3323 sp->data.p = NULL;
3324 ++ip;
3325 ++sp;
3326 MINT_IN_BREAK;
3327 MINT_IN_CASE(MINT_ARGLIST)
3328 g_assert (frame->varargs);
3329 sp->data.p = vt_sp;
3330 *(gpointer*)sp->data.p = frame->varargs;
3331 vt_sp += ALIGN_TO (sizeof (gpointer), MINT_VT_ALIGNMENT);
3332 ++ip;
3333 ++sp;
3334 MINT_IN_BREAK;
3335 MINT_IN_CASE(MINT_VTRESULT) {
3336 int ret_size = * (guint16 *)(ip + 1);
3337 unsigned char *ret_vt_sp = vt_sp;
3338 vt_sp -= READ32(ip + 2);
3339 if (ret_size > 0) {
3340 memmove (vt_sp, ret_vt_sp, ret_size);
3341 sp [-1].data.p = vt_sp;
3342 vt_sp += ALIGN_TO (ret_size, MINT_VT_ALIGNMENT);
3344 ip += 4;
3345 MINT_IN_BREAK;
3347 #define LDC(n) do { sp->data.i = (n); ++ip; ++sp; } while (0)
3348 MINT_IN_CASE(MINT_LDC_I4_M1)
3349 LDC(-1);
3350 MINT_IN_BREAK;
3351 MINT_IN_CASE(MINT_LDC_I4_0)
3352 LDC(0);
3353 MINT_IN_BREAK;
3354 MINT_IN_CASE(MINT_LDC_I4_1)
3355 LDC(1);
3356 MINT_IN_BREAK;
3357 MINT_IN_CASE(MINT_LDC_I4_2)
3358 LDC(2);
3359 MINT_IN_BREAK;
3360 MINT_IN_CASE(MINT_LDC_I4_3)
3361 LDC(3);
3362 MINT_IN_BREAK;
3363 MINT_IN_CASE(MINT_LDC_I4_4)
3364 LDC(4);
3365 MINT_IN_BREAK;
3366 MINT_IN_CASE(MINT_LDC_I4_5)
3367 LDC(5);
3368 MINT_IN_BREAK;
3369 MINT_IN_CASE(MINT_LDC_I4_6)
3370 LDC(6);
3371 MINT_IN_BREAK;
3372 MINT_IN_CASE(MINT_LDC_I4_7)
3373 LDC(7);
3374 MINT_IN_BREAK;
3375 MINT_IN_CASE(MINT_LDC_I4_8)
3376 LDC(8);
3377 MINT_IN_BREAK;
3378 MINT_IN_CASE(MINT_LDC_I4_S)
3379 sp->data.i = *(const short *)(ip + 1);
3380 ip += 2;
3381 ++sp;
3382 MINT_IN_BREAK;
3383 MINT_IN_CASE(MINT_LDC_I4)
3384 ++ip;
3385 sp->data.i = READ32 (ip);
3386 ip += 2;
3387 ++sp;
3388 MINT_IN_BREAK;
3389 MINT_IN_CASE(MINT_LDC_I8)
3390 ++ip;
3391 sp->data.l = READ64 (ip);
3392 ip += 4;
3393 ++sp;
3394 MINT_IN_BREAK;
3395 MINT_IN_CASE(MINT_LDC_I8_S)
3396 sp->data.l = *(const short *)(ip + 1);
3397 ip += 2;
3398 ++sp;
3399 MINT_IN_BREAK;
3400 MINT_IN_CASE(MINT_LDC_R4) {
3401 guint32 val;
3402 ++ip;
3403 val = READ32(ip);
3404 sp->data.f_r4 = * (float *)&val;
3405 ip += 2;
3406 ++sp;
3407 MINT_IN_BREAK;
3409 MINT_IN_CASE(MINT_LDC_R8)
3410 sp->data.l = READ64 (ip + 1); /* note union usage */
3411 ip += 5;
3412 ++sp;
3413 MINT_IN_BREAK;
3414 MINT_IN_CASE(MINT_DUP)
3415 sp [0] = sp[-1];
3416 ++sp;
3417 ++ip;
3418 MINT_IN_BREAK;
3419 MINT_IN_CASE(MINT_DUP_VT) {
3420 int const i32 = READ32 (ip + 1);
3421 sp->data.p = vt_sp;
3422 memcpy(sp->data.p, sp [-1].data.p, i32);
3423 vt_sp += ALIGN_TO (i32, MINT_VT_ALIGNMENT);
3424 ++sp;
3425 ip += 3;
3426 MINT_IN_BREAK;
3428 MINT_IN_CASE(MINT_POP) {
3429 guint16 u16 = (* (guint16 *)(ip + 1)) + 1;
3430 if (u16 > 1)
3431 memmove (sp - u16, sp - 1, (u16 - 1) * sizeof (stackval));
3432 sp--;
3433 ip += 2;
3434 MINT_IN_BREAK;
3436 MINT_IN_CASE(MINT_JMP) {
3437 InterpMethod *new_method = (InterpMethod*)frame->imethod->data_items [* (guint16 *)(ip + 1)];
3439 if (frame->imethod->prof_flags & MONO_PROFILER_CALL_INSTRUMENTATION_TAIL_CALL)
3440 MONO_PROFILER_RAISE (method_tail_call, (frame->imethod->method, new_method->method));
3442 if (!new_method->transformed) {
3443 MONO_API_ERROR_INIT (error);
3445 frame->ip = ip;
3446 mono_interp_transform_method (new_method, context, error);
3447 frame->ex = mono_error_convert_to_exception (error);
3448 if (frame->ex)
3449 goto exit_frame;
3451 ip += 2;
3452 const gboolean realloc_frame = new_method->alloca_size > frame->imethod->alloca_size;
3453 frame->imethod = new_method;
3455 * We allocate the stack frame from scratch and store the arguments in the
3456 * locals again since it's possible for the caller stack frame to be smaller
3457 * than the callee stack frame (at the interp level)
3459 if (realloc_frame) {
3460 frame->stack = (stackval*)g_alloca (frame->imethod->alloca_size);
3461 memset (frame->stack, 0, frame->imethod->alloca_size);
3462 sp = frame->stack;
3464 vt_sp = (unsigned char *) sp + frame->imethod->stack_size;
3465 #if DEBUG_INTERP
3466 vtalloc = vt_sp;
3467 #endif
3468 locals = frame_locals (frame);
3469 ip = frame->imethod->code;
3470 MINT_IN_BREAK;
3472 MINT_IN_CASE(MINT_CALLI) {
3473 MonoMethodSignature *csignature;
3475 frame->ip = ip;
3477 csignature = (MonoMethodSignature*)frame->imethod->data_items [* (guint16 *)(ip + 1)];
3478 ip += 2;
3479 --sp;
3480 child_frame.imethod = (InterpMethod*)sp->data.p;
3482 sp->data.p = vt_sp;
3483 child_frame.retval = sp;
3484 /* decrement by the actual number of args */
3485 sp -= csignature->param_count;
3486 if (csignature->hasthis)
3487 --sp;
3488 child_frame.stack_args = sp;
3490 if (child_frame.imethod->method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) {
3491 child_frame.imethod = mono_interp_get_imethod (frame->imethod->domain, mono_marshal_get_native_wrapper (child_frame.imethod->method, FALSE, FALSE), error);
3492 mono_error_cleanup (error); /* FIXME: don't swallow the error */
3495 if (csignature->hasthis) {
3496 MonoObject *this_arg = (MonoObject*)sp->data.p;
3498 if (m_class_is_valuetype (this_arg->vtable->klass)) {
3499 gpointer unboxed = mono_object_unbox_internal (this_arg);
3500 sp [0].data.p = unboxed;
3504 interp_exec_method (&child_frame, context, error);
3506 CHECK_RESUME_STATE (context);
3508 /* need to handle typedbyref ... */
3509 if (csignature->ret->type != MONO_TYPE_VOID) {
3510 *sp = *child_frame.retval;
3511 sp++;
3513 MINT_IN_BREAK;
3515 MINT_IN_CASE(MINT_CALLI_NAT_FAST) {
3516 gpointer target_ip = sp [-1].data.p;
3517 MonoMethodSignature *csignature = (MonoMethodSignature*)frame->imethod->data_items [* (guint16 *)(ip + 1)];
3518 int opcode = *(guint16 *)(ip + 2);
3519 gboolean save_last_error = *(guint16 *)(ip + 3);
3521 sp--;
3522 frame->ip = ip;
3524 sp = do_icall_wrapper (frame, csignature, opcode, sp, target_ip, save_last_error);
3525 EXCEPTION_CHECKPOINT;
3526 CHECK_RESUME_STATE (context);
3527 ip += 4;
3528 MINT_IN_BREAK;
3530 MINT_IN_CASE(MINT_CALLI_NAT) {
3532 frame->ip = ip;
3534 MonoMethodSignature* csignature = (MonoMethodSignature*)frame->imethod->data_items [* (guint16 *)(ip + 1)];
3536 ip += 3;
3537 --sp;
3538 guchar* const code = (guchar*)sp->data.p;
3539 child_frame.imethod = NULL;
3541 sp->data.p = vt_sp;
3542 child_frame.retval = sp;
3543 /* decrement by the actual number of args */
3544 sp -= csignature->param_count;
3545 if (csignature->hasthis)
3546 --sp;
3547 child_frame.stack_args = sp;
3549 if (frame->imethod->method->dynamic && csignature->pinvoke) {
3550 mono_interp_calli_nat_dynamic_pinvoke (&child_frame, code, context, csignature, error);
3551 } else {
3552 const gboolean save_last_error = *(guint16 *)(ip - 3 + 2);
3553 ves_pinvoke_method (&child_frame, csignature, (MonoFuncV) code, FALSE, context, save_last_error);
3556 CHECK_RESUME_STATE (context);
3558 /* need to handle typedbyref ... */
3559 if (csignature->ret->type != MONO_TYPE_VOID) {
3560 *sp = *child_frame.retval;
3561 sp++;
3563 MINT_IN_BREAK;
3565 MINT_IN_CASE(MINT_CALLVIRT_FAST)
3566 MINT_IN_CASE(MINT_VCALLVIRT_FAST) {
3567 MonoObject *this_arg;
3568 InterpMethod *target_imethod;
3569 int slot;
3571 // FIXME Have it handle also remoting calls and use a single opcode for virtual calls
3573 frame->ip = ip;
3575 target_imethod = (InterpMethod*)frame->imethod->data_items [* (guint16 *)(ip + 1)];
3576 slot = *(gint16*)(ip + 2);
3577 ip += 3;
3578 sp->data.p = vt_sp;
3579 child_frame.retval = sp;
3581 /* decrement by the actual number of args */
3582 sp -= target_imethod->param_count + target_imethod->hasthis;
3583 child_frame.stack_args = sp;
3585 this_arg = (MonoObject*)sp->data.p;
3587 child_frame.imethod = get_virtual_method_fast (target_imethod, this_arg->vtable, slot);
3588 if (m_class_is_valuetype (this_arg->vtable->klass) && m_class_is_valuetype (child_frame.imethod->method->klass)) {
3589 /* unbox */
3590 gpointer unboxed = mono_object_unbox_internal (this_arg);
3591 sp [0].data.p = unboxed;
3594 interp_exec_method (&child_frame, context, error);
3596 CHECK_RESUME_STATE (context);
3598 const gboolean is_void = ip [-3] == MINT_VCALLVIRT_FAST;
3599 if (!is_void) {
3600 /* need to handle typedbyref ... */
3601 *sp = *child_frame.retval;
3602 sp++;
3604 MINT_IN_BREAK;
3606 MINT_IN_CASE(MINT_CALL_VARARG) {
3607 int num_varargs = 0;
3608 MonoMethodSignature *csig;
3610 frame->ip = ip;
3612 child_frame.imethod = (InterpMethod*)frame->imethod->data_items [* (guint16 *)(ip + 1)];
3613 /* The real signature for vararg calls */
3614 csig = (MonoMethodSignature*) frame->imethod->data_items [* (guint16*) (ip + 2)];
3615 /* Push all vararg arguments from normal sp to vt_sp together with the signature */
3616 num_varargs = csig->param_count - csig->sentinelpos;
3617 child_frame.varargs = (char*) vt_sp;
3618 vt_sp = copy_varargs_vtstack (csig, sp, vt_sp);
3620 ip += 3;
3621 sp->data.p = vt_sp;
3622 child_frame.retval = sp;
3624 /* decrement by the actual number of args */
3625 sp -= child_frame.imethod->param_count + child_frame.imethod->hasthis + num_varargs;
3626 child_frame.stack_args = sp;
3628 interp_exec_method (&child_frame, context, error);
3630 CHECK_RESUME_STATE (context);
3632 if (csig->ret->type != MONO_TYPE_VOID) {
3633 *sp = *child_frame.retval;
3634 sp++;
3636 MINT_IN_BREAK;
3638 MINT_IN_CASE(MINT_CALL)
3639 MINT_IN_CASE(MINT_VCALL)
3640 MINT_IN_CASE(MINT_CALLVIRT)
3641 MINT_IN_CASE(MINT_VCALLVIRT) {
3643 frame->ip = ip;
3645 child_frame.imethod = (InterpMethod*)frame->imethod->data_items [* (guint16 *)(ip + 1)];
3646 ip += 2;
3647 sp->data.p = vt_sp;
3648 child_frame.retval = sp;
3650 /* decrement by the actual number of args */
3651 sp -= child_frame.imethod->param_count + child_frame.imethod->hasthis;
3652 child_frame.stack_args = sp;
3654 const gboolean is_virtual = ip [-2] == MINT_CALLVIRT || ip [-2] == MINT_VCALLVIRT;
3655 if (is_virtual) {
3656 MonoObject *this_arg = (MonoObject*)sp->data.p;
3658 child_frame.imethod = get_virtual_method (child_frame.imethod, this_arg->vtable);
3659 if (m_class_is_valuetype (this_arg->vtable->klass) && m_class_is_valuetype (child_frame.imethod->method->klass)) {
3660 /* unbox */
3661 gpointer unboxed = mono_object_unbox_internal (this_arg);
3662 sp [0].data.p = unboxed;
3666 interp_exec_method (&child_frame, context, error);
3668 CHECK_RESUME_STATE (context);
3670 const gboolean is_void = ip [-2] == MINT_VCALL || ip [-2] == MINT_VCALLVIRT;
3671 if (!is_void) {
3672 /* need to handle typedbyref ... */
3673 *sp = *child_frame.retval;
3674 sp++;
3676 MINT_IN_BREAK;
3678 MINT_IN_CASE(MINT_JIT_CALL) {
3679 InterpMethod *rmethod = (InterpMethod*)frame->imethod->data_items [* (guint16 *)(ip + 1)];
3680 MONO_API_ERROR_INIT (error);
3681 frame->ip = ip;
3682 sp = do_jit_call (sp, vt_sp, context, frame, rmethod, error);
3683 if (!is_ok (error)) {
3684 MonoException *ex = mono_error_convert_to_exception (error);
3685 THROW_EX (ex, ip);
3687 ip += 2;
3689 CHECK_RESUME_STATE (context);
3691 if (rmethod->rtype->type != MONO_TYPE_VOID)
3692 sp++;
3694 MINT_IN_BREAK;
3696 MINT_IN_CASE(MINT_CALLRUN) {
3697 MonoMethod *target_method = (MonoMethod*) frame->imethod->data_items [* (guint16 *)(ip + 1)];
3698 MonoMethodSignature *sig = (MonoMethodSignature*) frame->imethod->data_items [* (guint16 *)(ip + 2)];
3699 stackval *retval;
3701 sp->data.p = vt_sp;
3702 retval = sp;
3704 sp -= sig->param_count;
3705 if (sig->hasthis)
3706 sp--;
3708 ves_imethod (frame, target_method, sig, sp, retval);
3709 if (frame->ex)
3710 THROW_EX (frame->ex, ip);
3712 if (sig->ret->type != MONO_TYPE_VOID) {
3713 *sp = *retval;
3714 sp++;
3716 ip += 3;
3717 MINT_IN_BREAK;
3719 MINT_IN_CASE(MINT_RET)
3720 --sp;
3721 *frame->retval = *sp;
3722 if (sp > frame->stack)
3723 g_warning ("ret: more values on stack: %d", sp-frame->stack);
3724 goto exit_frame;
3725 MINT_IN_CASE(MINT_RET_VOID)
3726 if (sp > frame->stack)
3727 g_warning ("ret.void: more values on stack: %d %s", sp-frame->stack, mono_method_full_name (frame->imethod->method, TRUE));
3728 goto exit_frame;
3729 MINT_IN_CASE(MINT_RET_VT) {
3730 int const i32 = READ32 (ip + 1);
3731 --sp;
3732 memcpy(frame->retval->data.p, sp->data.p, i32);
3733 if (sp > frame->stack)
3734 g_warning ("ret.vt: more values on stack: %d", sp-frame->stack);
3735 goto exit_frame;
3737 MINT_IN_CASE(MINT_BR_S)
3738 ip += (short) *(ip + 1);
3739 MINT_IN_BREAK;
3740 MINT_IN_CASE(MINT_BR)
3741 ip += (gint32) READ32(ip + 1);
3742 MINT_IN_BREAK;
3743 #define ZEROP_S(datamem, op) \
3744 --sp; \
3745 if (sp->data.datamem op 0) \
3746 ip += * (gint16 *)(ip + 1); \
3747 else \
3748 ip += 2;
3750 #define ZEROP(datamem, op) \
3751 --sp; \
3752 if (sp->data.datamem op 0) \
3753 ip += (gint32)READ32(ip + 1); \
3754 else \
3755 ip += 3;
3757 MINT_IN_CASE(MINT_BRFALSE_I4_S)
3758 ZEROP_S(i, ==);
3759 MINT_IN_BREAK;
3760 MINT_IN_CASE(MINT_BRFALSE_I8_S)
3761 ZEROP_S(l, ==);
3762 MINT_IN_BREAK;
3763 MINT_IN_CASE(MINT_BRFALSE_R4_S)
3764 ZEROP_S(f_r4, ==);
3765 MINT_IN_BREAK;
3766 MINT_IN_CASE(MINT_BRFALSE_R8_S)
3767 ZEROP_S(f, ==);
3768 MINT_IN_BREAK;
3769 MINT_IN_CASE(MINT_BRFALSE_I4)
3770 ZEROP(i, ==);
3771 MINT_IN_BREAK;
3772 MINT_IN_CASE(MINT_BRFALSE_I8)
3773 ZEROP(l, ==);
3774 MINT_IN_BREAK;
3775 MINT_IN_CASE(MINT_BRFALSE_R4)
3776 ZEROP_S(f_r4, ==);
3777 MINT_IN_BREAK;
3778 MINT_IN_CASE(MINT_BRFALSE_R8)
3779 ZEROP_S(f, ==);
3780 MINT_IN_BREAK;
3781 MINT_IN_CASE(MINT_BRTRUE_I4_S)
3782 ZEROP_S(i, !=);
3783 MINT_IN_BREAK;
3784 MINT_IN_CASE(MINT_BRTRUE_I8_S)
3785 ZEROP_S(l, !=);
3786 MINT_IN_BREAK;
3787 MINT_IN_CASE(MINT_BRTRUE_R4_S)
3788 ZEROP_S(f_r4, !=);
3789 MINT_IN_BREAK;
3790 MINT_IN_CASE(MINT_BRTRUE_R8_S)
3791 ZEROP_S(f, !=);
3792 MINT_IN_BREAK;
3793 MINT_IN_CASE(MINT_BRTRUE_I4)
3794 ZEROP(i, !=);
3795 MINT_IN_BREAK;
3796 MINT_IN_CASE(MINT_BRTRUE_I8)
3797 ZEROP(l, !=);
3798 MINT_IN_BREAK;
3799 MINT_IN_CASE(MINT_BRTRUE_R4)
3800 ZEROP(f_r4, !=);
3801 MINT_IN_BREAK;
3802 MINT_IN_CASE(MINT_BRTRUE_R8)
3803 ZEROP(f, !=);
3804 MINT_IN_BREAK;
3805 #define CONDBR_S(cond) \
3806 sp -= 2; \
3807 if (cond) \
3808 ip += * (gint16 *)(ip + 1); \
3809 else \
3810 ip += 2;
3811 #define BRELOP_S(datamem, op) \
3812 CONDBR_S(sp[0].data.datamem op sp[1].data.datamem)
3814 #define CONDBR(cond) \
3815 sp -= 2; \
3816 if (cond) \
3817 ip += (gint32)READ32(ip + 1); \
3818 else \
3819 ip += 3;
3821 #define BRELOP(datamem, op) \
3822 CONDBR(sp[0].data.datamem op sp[1].data.datamem)
3824 MINT_IN_CASE(MINT_BEQ_I4_S)
3825 BRELOP_S(i, ==)
3826 MINT_IN_BREAK;
3827 MINT_IN_CASE(MINT_BEQ_I8_S)
3828 BRELOP_S(l, ==)
3829 MINT_IN_BREAK;
3830 MINT_IN_CASE(MINT_BEQ_R4_S)
3831 CONDBR_S(!isunordered (sp [0].data.f_r4, sp [1].data.f_r4) && sp[0].data.f_r4 == sp[1].data.f_r4)
3832 MINT_IN_BREAK;
3833 MINT_IN_CASE(MINT_BEQ_R8_S)
3834 CONDBR_S(!mono_isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f == sp[1].data.f)
3835 MINT_IN_BREAK;
3836 MINT_IN_CASE(MINT_BEQ_I4)
3837 BRELOP(i, ==)
3838 MINT_IN_BREAK;
3839 MINT_IN_CASE(MINT_BEQ_I8)
3840 BRELOP(l, ==)
3841 MINT_IN_BREAK;
3842 MINT_IN_CASE(MINT_BEQ_R4)
3843 CONDBR(!isunordered (sp [0].data.f_r4, sp [1].data.f_r4) && sp[0].data.f_r4 == sp[1].data.f_r4)
3844 MINT_IN_BREAK;
3845 MINT_IN_CASE(MINT_BEQ_R8)
3846 CONDBR(!mono_isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f == sp[1].data.f)
3847 MINT_IN_BREAK;
3848 MINT_IN_CASE(MINT_BGE_I4_S)
3849 BRELOP_S(i, >=)
3850 MINT_IN_BREAK;
3851 MINT_IN_CASE(MINT_BGE_I8_S)
3852 BRELOP_S(l, >=)
3853 MINT_IN_BREAK;
3854 MINT_IN_CASE(MINT_BGE_R4_S)
3855 CONDBR_S(!isunordered (sp [0].data.f_r4, sp [1].data.f_r4) && sp[0].data.f_r4 >= sp[1].data.f_r4)
3856 MINT_IN_BREAK;
3857 MINT_IN_CASE(MINT_BGE_R8_S)
3858 CONDBR_S(!mono_isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f >= sp[1].data.f)
3859 MINT_IN_BREAK;
3860 MINT_IN_CASE(MINT_BGE_I4)
3861 BRELOP(i, >=)
3862 MINT_IN_BREAK;
3863 MINT_IN_CASE(MINT_BGE_I8)
3864 BRELOP(l, >=)
3865 MINT_IN_BREAK;
3866 MINT_IN_CASE(MINT_BGE_R4)
3867 CONDBR(!isunordered (sp [0].data.f_r4, sp [1].data.f_r4) && sp[0].data.f_r4 >= sp[1].data.f_r4)
3868 MINT_IN_BREAK;
3869 MINT_IN_CASE(MINT_BGE_R8)
3870 CONDBR(!mono_isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f >= sp[1].data.f)
3871 MINT_IN_BREAK;
3872 MINT_IN_CASE(MINT_BGT_I4_S)
3873 BRELOP_S(i, >)
3874 MINT_IN_BREAK;
3875 MINT_IN_CASE(MINT_BGT_I8_S)
3876 BRELOP_S(l, >)
3877 MINT_IN_BREAK;
3878 MINT_IN_CASE(MINT_BGT_R4_S)
3879 CONDBR_S(!isunordered (sp [0].data.f_r4, sp [1].data.f_r4) && sp[0].data.f_r4 > sp[1].data.f_r4)
3880 MINT_IN_BREAK;
3881 MINT_IN_CASE(MINT_BGT_R8_S)
3882 CONDBR_S(!mono_isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f > sp[1].data.f)
3883 MINT_IN_BREAK;
3884 MINT_IN_CASE(MINT_BGT_I4)
3885 BRELOP(i, >)
3886 MINT_IN_BREAK;
3887 MINT_IN_CASE(MINT_BGT_I8)
3888 BRELOP(l, >)
3889 MINT_IN_BREAK;
3890 MINT_IN_CASE(MINT_BGT_R4)
3891 CONDBR(!isunordered (sp [0].data.f_r4, sp [1].data.f_r4) && sp[0].data.f_r4 > sp[1].data.f_r4)
3892 MINT_IN_BREAK;
3893 MINT_IN_CASE(MINT_BGT_R8)
3894 CONDBR(!mono_isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f > sp[1].data.f)
3895 MINT_IN_BREAK;
3896 MINT_IN_CASE(MINT_BLT_I4_S)
3897 BRELOP_S(i, <)
3898 MINT_IN_BREAK;
3899 MINT_IN_CASE(MINT_BLT_I8_S)
3900 BRELOP_S(l, <)
3901 MINT_IN_BREAK;
3902 MINT_IN_CASE(MINT_BLT_R4_S)
3903 CONDBR_S(!isunordered (sp [0].data.f_r4, sp [1].data.f_r4) && sp[0].data.f_r4 < sp[1].data.f_r4)
3904 MINT_IN_BREAK;
3905 MINT_IN_CASE(MINT_BLT_R8_S)
3906 CONDBR_S(!mono_isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f < sp[1].data.f)
3907 MINT_IN_BREAK;
3908 MINT_IN_CASE(MINT_BLT_I4)
3909 BRELOP(i, <)
3910 MINT_IN_BREAK;
3911 MINT_IN_CASE(MINT_BLT_I8)
3912 BRELOP(l, <)
3913 MINT_IN_BREAK;
3914 MINT_IN_CASE(MINT_BLT_R4)
3915 CONDBR(!isunordered (sp [0].data.f_r4, sp [1].data.f_r4) && sp[0].data.f_r4 < sp[1].data.f_r4)
3916 MINT_IN_BREAK;
3917 MINT_IN_CASE(MINT_BLT_R8)
3918 CONDBR(!mono_isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f < sp[1].data.f)
3919 MINT_IN_BREAK;
3920 MINT_IN_CASE(MINT_BLE_I4_S)
3921 BRELOP_S(i, <=)
3922 MINT_IN_BREAK;
3923 MINT_IN_CASE(MINT_BLE_I8_S)
3924 BRELOP_S(l, <=)
3925 MINT_IN_BREAK;
3926 MINT_IN_CASE(MINT_BLE_R4_S)
3927 CONDBR_S(!isunordered (sp [0].data.f_r4, sp [1].data.f_r4) && sp[0].data.f_r4 <= sp[1].data.f_r4)
3928 MINT_IN_BREAK;
3929 MINT_IN_CASE(MINT_BLE_R8_S)
3930 CONDBR_S(!mono_isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f <= sp[1].data.f)
3931 MINT_IN_BREAK;
3932 MINT_IN_CASE(MINT_BLE_I4)
3933 BRELOP(i, <=)
3934 MINT_IN_BREAK;
3935 MINT_IN_CASE(MINT_BLE_I8)
3936 BRELOP(l, <=)
3937 MINT_IN_BREAK;
3938 MINT_IN_CASE(MINT_BLE_R4)
3939 CONDBR(!isunordered (sp [0].data.f_r4, sp [1].data.f_r4) && sp[0].data.f_r4 <= sp[1].data.f_r4)
3940 MINT_IN_BREAK;
3941 MINT_IN_CASE(MINT_BLE_R8)
3942 CONDBR(!mono_isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f <= sp[1].data.f)
3943 MINT_IN_BREAK;
3944 MINT_IN_CASE(MINT_BNE_UN_I4_S)
3945 BRELOP_S(i, !=)
3946 MINT_IN_BREAK;
3947 MINT_IN_CASE(MINT_BNE_UN_I8_S)
3948 BRELOP_S(l, !=)
3949 MINT_IN_BREAK;
3950 MINT_IN_CASE(MINT_BNE_UN_R4_S)
3951 CONDBR_S(isunordered (sp [0].data.f_r4, sp [1].data.f_r4) || sp[0].data.f_r4 != sp[1].data.f_r4)
3952 MINT_IN_BREAK;
3953 MINT_IN_CASE(MINT_BNE_UN_R8_S)
3954 CONDBR_S(mono_isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f != sp[1].data.f)
3955 MINT_IN_BREAK;
3956 MINT_IN_CASE(MINT_BNE_UN_I4)
3957 BRELOP(i, !=)
3958 MINT_IN_BREAK;
3959 MINT_IN_CASE(MINT_BNE_UN_I8)
3960 BRELOP(l, !=)
3961 MINT_IN_BREAK;
3962 MINT_IN_CASE(MINT_BNE_UN_R4)
3963 CONDBR(isunordered (sp [0].data.f_r4, sp [1].data.f_r4) || sp[0].data.f_r4 != sp[1].data.f_r4)
3964 MINT_IN_BREAK;
3965 MINT_IN_CASE(MINT_BNE_UN_R8)
3966 CONDBR(mono_isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f != sp[1].data.f)
3967 MINT_IN_BREAK;
3969 #define BRELOP_S_CAST(datamem, op, type) \
3970 sp -= 2; \
3971 if ((type) sp[0].data.datamem op (type) sp[1].data.datamem) \
3972 ip += * (gint16 *)(ip + 1); \
3973 else \
3974 ip += 2;
3976 #define BRELOP_CAST(datamem, op, type) \
3977 sp -= 2; \
3978 if ((type) sp[0].data.datamem op (type) sp[1].data.datamem) \
3979 ip += (gint32)READ32(ip + 1); \
3980 else \
3981 ip += 3;
3983 MINT_IN_CASE(MINT_BGE_UN_I4_S)
3984 BRELOP_S_CAST(i, >=, guint32);
3985 MINT_IN_BREAK;
3986 MINT_IN_CASE(MINT_BGE_UN_I8_S)
3987 BRELOP_S_CAST(l, >=, guint64);
3988 MINT_IN_BREAK;
3989 MINT_IN_CASE(MINT_BGE_UN_R4_S)
3990 CONDBR_S(isunordered (sp [0].data.f_r4, sp [1].data.f_r4) || sp[0].data.f_r4 >= sp[1].data.f_r4)
3991 MINT_IN_BREAK;
3992 MINT_IN_CASE(MINT_BGE_UN_R8_S)
3993 CONDBR_S(mono_isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f >= sp[1].data.f)
3994 MINT_IN_BREAK;
3995 MINT_IN_CASE(MINT_BGE_UN_I4)
3996 BRELOP_CAST(i, >=, guint32);
3997 MINT_IN_BREAK;
3998 MINT_IN_CASE(MINT_BGE_UN_I8)
3999 BRELOP_CAST(l, >=, guint64);
4000 MINT_IN_BREAK;
4001 MINT_IN_CASE(MINT_BGE_UN_R4)
4002 CONDBR(isunordered (sp [0].data.f_r4, sp [1].data.f_r4) || sp[0].data.f_r4 >= sp[1].data.f_r4)
4003 MINT_IN_BREAK;
4004 MINT_IN_CASE(MINT_BGE_UN_R8)
4005 CONDBR(mono_isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f >= sp[1].data.f)
4006 MINT_IN_BREAK;
4007 MINT_IN_CASE(MINT_BGT_UN_I4_S)
4008 BRELOP_S_CAST(i, >, guint32);
4009 MINT_IN_BREAK;
4010 MINT_IN_CASE(MINT_BGT_UN_I8_S)
4011 BRELOP_S_CAST(l, >, guint64);
4012 MINT_IN_BREAK;
4013 MINT_IN_CASE(MINT_BGT_UN_R4_S)
4014 CONDBR_S(isunordered (sp [0].data.f_r4, sp [1].data.f_r4) || sp[0].data.f_r4 > sp[1].data.f_r4)
4015 MINT_IN_BREAK;
4016 MINT_IN_CASE(MINT_BGT_UN_R8_S)
4017 CONDBR_S(mono_isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f > sp[1].data.f)
4018 MINT_IN_BREAK;
4019 MINT_IN_CASE(MINT_BGT_UN_I4)
4020 BRELOP_CAST(i, >, guint32);
4021 MINT_IN_BREAK;
4022 MINT_IN_CASE(MINT_BGT_UN_I8)
4023 BRELOP_CAST(l, >, guint64);
4024 MINT_IN_BREAK;
4025 MINT_IN_CASE(MINT_BGT_UN_R4)
4026 CONDBR(isunordered (sp [0].data.f_r4, sp [1].data.f_r4) || sp[0].data.f_r4 > sp[1].data.f_r4)
4027 MINT_IN_BREAK;
4028 MINT_IN_CASE(MINT_BGT_UN_R8)
4029 CONDBR(mono_isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f > sp[1].data.f)
4030 MINT_IN_BREAK;
4031 MINT_IN_CASE(MINT_BLE_UN_I4_S)
4032 BRELOP_S_CAST(i, <=, guint32);
4033 MINT_IN_BREAK;
4034 MINT_IN_CASE(MINT_BLE_UN_I8_S)
4035 BRELOP_S_CAST(l, <=, guint64);
4036 MINT_IN_BREAK;
4037 MINT_IN_CASE(MINT_BLE_UN_R4_S)
4038 CONDBR_S(isunordered (sp [0].data.f_r4, sp [1].data.f_r4) || sp[0].data.f_r4 <= sp[1].data.f_r4)
4039 MINT_IN_BREAK;
4040 MINT_IN_CASE(MINT_BLE_UN_R8_S)
4041 CONDBR_S(mono_isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f <= sp[1].data.f)
4042 MINT_IN_BREAK;
4043 MINT_IN_CASE(MINT_BLE_UN_I4)
4044 BRELOP_CAST(i, <=, guint32);
4045 MINT_IN_BREAK;
4046 MINT_IN_CASE(MINT_BLE_UN_I8)
4047 BRELOP_CAST(l, <=, guint64);
4048 MINT_IN_BREAK;
4049 MINT_IN_CASE(MINT_BLE_UN_R4)
4050 CONDBR(isunordered (sp [0].data.f_r4, sp [1].data.f_r4) || sp[0].data.f_r4 <= sp[1].data.f_r4)
4051 MINT_IN_BREAK;
4052 MINT_IN_CASE(MINT_BLE_UN_R8)
4053 CONDBR(mono_isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f <= sp[1].data.f)
4054 MINT_IN_BREAK;
4055 MINT_IN_CASE(MINT_BLT_UN_I4_S)
4056 BRELOP_S_CAST(i, <, guint32);
4057 MINT_IN_BREAK;
4058 MINT_IN_CASE(MINT_BLT_UN_I8_S)
4059 BRELOP_S_CAST(l, <, guint64);
4060 MINT_IN_BREAK;
4061 MINT_IN_CASE(MINT_BLT_UN_R4_S)
4062 CONDBR_S(isunordered (sp [0].data.f_r4, sp [1].data.f_r4) || sp[0].data.f_r4 < sp[1].data.f_r4)
4063 MINT_IN_BREAK;
4064 MINT_IN_CASE(MINT_BLT_UN_R8_S)
4065 CONDBR_S(mono_isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f < sp[1].data.f)
4066 MINT_IN_BREAK;
4067 MINT_IN_CASE(MINT_BLT_UN_I4)
4068 BRELOP_CAST(i, <, guint32);
4069 MINT_IN_BREAK;
4070 MINT_IN_CASE(MINT_BLT_UN_I8)
4071 BRELOP_CAST(l, <, guint64);
4072 MINT_IN_BREAK;
4073 MINT_IN_CASE(MINT_BLT_UN_R4)
4074 CONDBR(isunordered (sp [0].data.f_r4, sp [1].data.f_r4) || sp[0].data.f_r4 < sp[1].data.f_r4)
4075 MINT_IN_BREAK;
4076 MINT_IN_CASE(MINT_BLT_UN_R8)
4077 CONDBR(mono_isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f < sp[1].data.f)
4078 MINT_IN_BREAK;
4079 MINT_IN_CASE(MINT_SWITCH) {
4080 guint32 n;
4081 const unsigned short *st;
4082 ++ip;
4083 n = READ32 (ip);
4084 ip += 2;
4085 st = ip + 2 * n;
4086 --sp;
4087 if ((guint32)sp->data.i < n) {
4088 gint offset;
4089 ip += 2 * (guint32)sp->data.i;
4090 offset = READ32 (ip);
4091 ip = ip + offset;
4092 } else {
4093 ip = st;
4095 MINT_IN_BREAK;
4097 MINT_IN_CASE(MINT_LDIND_I1_CHECK)
4098 NULL_CHECK (sp [-1].data.p);
4099 ++ip;
4100 sp[-1].data.i = *(gint8*)sp[-1].data.p;
4101 MINT_IN_BREAK;
4102 MINT_IN_CASE(MINT_LDIND_U1_CHECK)
4103 NULL_CHECK (sp [-1].data.p);
4104 ++ip;
4105 sp[-1].data.i = *(guint8*)sp[-1].data.p;
4106 MINT_IN_BREAK;
4107 MINT_IN_CASE(MINT_LDIND_I2_CHECK)
4108 NULL_CHECK (sp [-1].data.p);
4109 ++ip;
4110 sp[-1].data.i = *(gint16*)sp[-1].data.p;
4111 MINT_IN_BREAK;
4112 MINT_IN_CASE(MINT_LDIND_U2_CHECK)
4113 NULL_CHECK (sp [-1].data.p);
4114 ++ip;
4115 sp[-1].data.i = *(guint16*)sp[-1].data.p;
4116 MINT_IN_BREAK;
4117 MINT_IN_CASE(MINT_LDIND_I4_CHECK) /* Fall through */
4118 MINT_IN_CASE(MINT_LDIND_U4_CHECK)
4119 NULL_CHECK (sp [-1].data.p);
4120 ++ip;
4121 sp[-1].data.i = *(gint32*)sp[-1].data.p;
4122 MINT_IN_BREAK;
4123 MINT_IN_CASE(MINT_LDIND_I8_CHECK)
4124 NULL_CHECK (sp [-1].data.p);
4125 ++ip;
4126 #ifdef NO_UNALIGNED_ACCESS
4127 if ((gsize)sp [-1].data.p % SIZEOF_VOID_P)
4128 memcpy (&sp [-1].data.l, sp [-1].data.p, sizeof (gint64));
4129 else
4130 #endif
4131 sp[-1].data.l = *(gint64*)sp[-1].data.p;
4132 MINT_IN_BREAK;
4133 MINT_IN_CASE(MINT_LDIND_I) {
4134 guint16 offset = * (guint16 *)(ip + 1);
4135 sp[-1 - offset].data.p = *(gpointer*)sp[-1 - offset].data.p;
4136 ip += 2;
4137 MINT_IN_BREAK;
4139 MINT_IN_CASE(MINT_LDIND_I8) {
4140 guint16 offset = * (guint16 *)(ip + 1);
4141 #ifdef NO_UNALIGNED_ACCESS
4142 if ((gsize)sp [-1 - offset].data.p % SIZEOF_VOID_P)
4143 memcpy (&sp [-1 - offset].data.l, sp [-1 - offset].data.p, sizeof (gint64));
4144 else
4145 #endif
4146 sp[-1 - offset].data.l = *(gint64*)sp[-1 - offset].data.p;
4147 ip += 2;
4148 MINT_IN_BREAK;
4150 MINT_IN_CASE(MINT_LDIND_R4_CHECK)
4151 NULL_CHECK (sp [-1].data.p);
4152 ++ip;
4153 sp[-1].data.f_r4 = *(gfloat*)sp[-1].data.p;
4154 MINT_IN_BREAK;
4155 MINT_IN_CASE(MINT_LDIND_R8_CHECK)
4156 NULL_CHECK (sp [-1].data.p);
4157 ++ip;
4158 #ifdef NO_UNALIGNED_ACCESS
4159 if ((gsize)sp [-1].data.p % SIZEOF_VOID_P)
4160 memcpy (&sp [-1].data.f, sp [-1].data.p, sizeof (gdouble));
4161 else
4162 #endif
4163 sp[-1].data.f = *(gdouble*)sp[-1].data.p;
4164 MINT_IN_BREAK;
4165 MINT_IN_CASE(MINT_LDIND_REF)
4166 ++ip;
4167 sp[-1].data.p = *(gpointer*)sp[-1].data.p;
4168 MINT_IN_BREAK;
4169 MINT_IN_CASE(MINT_LDIND_REF_CHECK) {
4170 NULL_CHECK (sp [-1].data.p);
4171 ++ip;
4172 sp [-1].data.p = *(gpointer*)sp [-1].data.p;
4173 MINT_IN_BREAK;
4175 MINT_IN_CASE(MINT_STIND_REF)
4176 ++ip;
4177 sp -= 2;
4178 mono_gc_wbarrier_generic_store_internal (sp->data.p, sp [1].data.o);
4179 MINT_IN_BREAK;
4180 MINT_IN_CASE(MINT_STIND_I1)
4181 ++ip;
4182 sp -= 2;
4183 * (gint8 *) sp->data.p = (gint8)sp[1].data.i;
4184 MINT_IN_BREAK;
4185 MINT_IN_CASE(MINT_STIND_I2)
4186 ++ip;
4187 sp -= 2;
4188 * (gint16 *) sp->data.p = (gint16)sp[1].data.i;
4189 MINT_IN_BREAK;
4190 MINT_IN_CASE(MINT_STIND_I4)
4191 ++ip;
4192 sp -= 2;
4193 * (gint32 *) sp->data.p = sp[1].data.i;
4194 MINT_IN_BREAK;
4195 MINT_IN_CASE(MINT_STIND_I)
4196 ++ip;
4197 sp -= 2;
4198 * (mono_i *) sp->data.p = (mono_i)sp[1].data.p;
4199 MINT_IN_BREAK;
4200 MINT_IN_CASE(MINT_STIND_I8)
4201 ++ip;
4202 sp -= 2;
4203 #ifdef NO_UNALIGNED_ACCESS
4204 if ((gsize)sp->data.p % SIZEOF_VOID_P)
4205 memcpy (sp->data.p, &sp [1].data.l, sizeof (gint64));
4206 else
4207 #endif
4208 * (gint64 *) sp->data.p = sp[1].data.l;
4209 MINT_IN_BREAK;
4210 MINT_IN_CASE(MINT_STIND_R4)
4211 ++ip;
4212 sp -= 2;
4213 * (float *) sp->data.p = sp[1].data.f_r4;
4214 MINT_IN_BREAK;
4215 MINT_IN_CASE(MINT_STIND_R8)
4216 ++ip;
4217 sp -= 2;
4218 #ifdef NO_UNALIGNED_ACCESS
4219 if ((gsize)sp->data.p % SIZEOF_VOID_P)
4220 memcpy (sp->data.p, &sp [1].data.f, sizeof (double));
4221 else
4222 #endif
4223 * (double *) sp->data.p = sp[1].data.f;
4224 MINT_IN_BREAK;
4225 MINT_IN_CASE(MINT_MONO_ATOMIC_STORE_I4)
4226 ++ip;
4227 sp -= 2;
4228 mono_atomic_store_i32 ((gint32 *) sp->data.p, sp [1].data.i);
4229 MINT_IN_BREAK;
4230 #define BINOP(datamem, op) \
4231 --sp; \
4232 sp [-1].data.datamem = sp [-1].data.datamem op sp [0].data.datamem; \
4233 ++ip;
4234 MINT_IN_CASE(MINT_ADD_I4)
4235 BINOP(i, +);
4236 MINT_IN_BREAK;
4237 MINT_IN_CASE(MINT_ADD_I8)
4238 BINOP(l, +);
4239 MINT_IN_BREAK;
4240 MINT_IN_CASE(MINT_ADD_R4)
4241 BINOP(f_r4, +);
4242 MINT_IN_BREAK;
4243 MINT_IN_CASE(MINT_ADD_R8)
4244 BINOP(f, +);
4245 MINT_IN_BREAK;
4246 MINT_IN_CASE(MINT_ADD1_I4)
4247 ++sp [-1].data.i;
4248 ++ip;
4249 MINT_IN_BREAK;
4250 MINT_IN_CASE(MINT_ADD1_I8)
4251 ++sp [-1].data.l;
4252 ++ip;
4253 MINT_IN_BREAK;
4254 MINT_IN_CASE(MINT_SUB_I4)
4255 BINOP(i, -);
4256 MINT_IN_BREAK;
4257 MINT_IN_CASE(MINT_SUB_I8)
4258 BINOP(l, -);
4259 MINT_IN_BREAK;
4260 MINT_IN_CASE(MINT_SUB_R4)
4261 BINOP(f_r4, -);
4262 MINT_IN_BREAK;
4263 MINT_IN_CASE(MINT_SUB_R8)
4264 BINOP(f, -);
4265 MINT_IN_BREAK;
4266 MINT_IN_CASE(MINT_SUB1_I4)
4267 --sp [-1].data.i;
4268 ++ip;
4269 MINT_IN_BREAK;
4270 MINT_IN_CASE(MINT_SUB1_I8)
4271 --sp [-1].data.l;
4272 ++ip;
4273 MINT_IN_BREAK;
4274 MINT_IN_CASE(MINT_MUL_I4)
4275 BINOP(i, *);
4276 MINT_IN_BREAK;
4277 MINT_IN_CASE(MINT_MUL_I8)
4278 BINOP(l, *);
4279 MINT_IN_BREAK;
4280 MINT_IN_CASE(MINT_MUL_R4)
4281 BINOP(f_r4, *);
4282 MINT_IN_BREAK;
4283 MINT_IN_CASE(MINT_MUL_R8)
4284 BINOP(f, *);
4285 MINT_IN_BREAK;
4286 MINT_IN_CASE(MINT_DIV_I4)
4287 if (sp [-1].data.i == 0)
4288 THROW_EX_DIV_ZERO (ip);
4289 if (sp [-1].data.i == (-1) && sp [-2].data.i == G_MININT32)
4290 THROW_EX_OVF (ip);
4291 BINOP(i, /);
4292 MINT_IN_BREAK;
4293 MINT_IN_CASE(MINT_DIV_I8)
4294 if (sp [-1].data.l == 0)
4295 THROW_EX_DIV_ZERO (ip);
4296 if (sp [-1].data.l == (-1) && sp [-2].data.l == G_MININT64)
4297 THROW_EX_OVF (ip);
4298 BINOP(l, /);
4299 MINT_IN_BREAK;
4300 MINT_IN_CASE(MINT_DIV_R4)
4301 BINOP(f_r4, /);
4302 MINT_IN_BREAK;
4303 MINT_IN_CASE(MINT_DIV_R8)
4304 BINOP(f, /);
4305 MINT_IN_BREAK;
4307 #define BINOP_CAST(datamem, op, type) \
4308 --sp; \
4309 sp [-1].data.datamem = (type)sp [-1].data.datamem op (type)sp [0].data.datamem; \
4310 ++ip;
4311 MINT_IN_CASE(MINT_DIV_UN_I4)
4312 if (sp [-1].data.i == 0)
4313 THROW_EX_DIV_ZERO (ip);
4314 BINOP_CAST(i, /, guint32);
4315 MINT_IN_BREAK;
4316 MINT_IN_CASE(MINT_DIV_UN_I8)
4317 if (sp [-1].data.l == 0)
4318 THROW_EX_DIV_ZERO (ip);
4319 BINOP_CAST(l, /, guint64);
4320 MINT_IN_BREAK;
4321 MINT_IN_CASE(MINT_REM_I4)
4322 if (sp [-1].data.i == 0)
4323 THROW_EX_DIV_ZERO (ip);
4324 if (sp [-1].data.i == (-1) && sp [-2].data.i == G_MININT32)
4325 THROW_EX_OVF (ip);
4326 BINOP(i, %);
4327 MINT_IN_BREAK;
4328 MINT_IN_CASE(MINT_REM_I8)
4329 if (sp [-1].data.l == 0)
4330 THROW_EX_DIV_ZERO (ip);
4331 if (sp [-1].data.l == (-1) && sp [-2].data.l == G_MININT64)
4332 THROW_EX_OVF (ip);
4333 BINOP(l, %);
4334 MINT_IN_BREAK;
4335 MINT_IN_CASE(MINT_REM_R4)
4336 /* FIXME: what do we actually do here? */
4337 --sp;
4338 sp [-1].data.f_r4 = fmodf (sp [-1].data.f_r4, sp [0].data.f_r4);
4339 ++ip;
4340 MINT_IN_BREAK;
4341 MINT_IN_CASE(MINT_REM_R8)
4342 /* FIXME: what do we actually do here? */
4343 --sp;
4344 sp [-1].data.f = fmod (sp [-1].data.f, sp [0].data.f);
4345 ++ip;
4346 MINT_IN_BREAK;
4347 MINT_IN_CASE(MINT_REM_UN_I4)
4348 if (sp [-1].data.i == 0)
4349 THROW_EX_DIV_ZERO (ip);
4350 BINOP_CAST(i, %, guint32);
4351 MINT_IN_BREAK;
4352 MINT_IN_CASE(MINT_REM_UN_I8)
4353 if (sp [-1].data.l == 0)
4354 THROW_EX_DIV_ZERO (ip);
4355 BINOP_CAST(l, %, guint64);
4356 MINT_IN_BREAK;
4357 MINT_IN_CASE(MINT_AND_I4)
4358 BINOP(i, &);
4359 MINT_IN_BREAK;
4360 MINT_IN_CASE(MINT_AND_I8)
4361 BINOP(l, &);
4362 MINT_IN_BREAK;
4363 MINT_IN_CASE(MINT_OR_I4)
4364 BINOP(i, |);
4365 MINT_IN_BREAK;
4366 MINT_IN_CASE(MINT_OR_I8)
4367 BINOP(l, |);
4368 MINT_IN_BREAK;
4369 MINT_IN_CASE(MINT_XOR_I4)
4370 BINOP(i, ^);
4371 MINT_IN_BREAK;
4372 MINT_IN_CASE(MINT_XOR_I8)
4373 BINOP(l, ^);
4374 MINT_IN_BREAK;
4376 #define SHIFTOP(datamem, op) \
4377 --sp; \
4378 sp [-1].data.datamem = sp [-1].data.datamem op sp [0].data.i; \
4379 ++ip;
4381 MINT_IN_CASE(MINT_SHL_I4)
4382 SHIFTOP(i, <<);
4383 MINT_IN_BREAK;
4384 MINT_IN_CASE(MINT_SHL_I8)
4385 SHIFTOP(l, <<);
4386 MINT_IN_BREAK;
4387 MINT_IN_CASE(MINT_SHR_I4)
4388 SHIFTOP(i, >>);
4389 MINT_IN_BREAK;
4390 MINT_IN_CASE(MINT_SHR_I8)
4391 SHIFTOP(l, >>);
4392 MINT_IN_BREAK;
4393 MINT_IN_CASE(MINT_SHR_UN_I4)
4394 --sp;
4395 sp [-1].data.i = (guint32)sp [-1].data.i >> sp [0].data.i;
4396 ++ip;
4397 MINT_IN_BREAK;
4398 MINT_IN_CASE(MINT_SHR_UN_I8)
4399 --sp;
4400 sp [-1].data.l = (guint64)sp [-1].data.l >> sp [0].data.i;
4401 ++ip;
4402 MINT_IN_BREAK;
4403 MINT_IN_CASE(MINT_NEG_I4)
4404 sp [-1].data.i = - sp [-1].data.i;
4405 ++ip;
4406 MINT_IN_BREAK;
4407 MINT_IN_CASE(MINT_NEG_I8)
4408 sp [-1].data.l = - sp [-1].data.l;
4409 ++ip;
4410 MINT_IN_BREAK;
4411 MINT_IN_CASE(MINT_NEG_R4)
4412 sp [-1].data.f_r4 = - sp [-1].data.f_r4;
4413 ++ip;
4414 MINT_IN_BREAK;
4415 MINT_IN_CASE(MINT_NEG_R8)
4416 sp [-1].data.f = - sp [-1].data.f;
4417 ++ip;
4418 MINT_IN_BREAK;
4419 MINT_IN_CASE(MINT_NOT_I4)
4420 sp [-1].data.i = ~ sp [-1].data.i;
4421 ++ip;
4422 MINT_IN_BREAK;
4423 MINT_IN_CASE(MINT_NOT_I8)
4424 sp [-1].data.l = ~ sp [-1].data.l;
4425 ++ip;
4426 MINT_IN_BREAK;
4427 MINT_IN_CASE(MINT_CONV_I1_I4)
4428 sp [-1].data.i = (gint8)sp [-1].data.i;
4429 ++ip;
4430 MINT_IN_BREAK;
4431 MINT_IN_CASE(MINT_CONV_I1_I8)
4432 sp [-1].data.i = (gint8)sp [-1].data.l;
4433 ++ip;
4434 MINT_IN_BREAK;
4435 MINT_IN_CASE(MINT_CONV_I1_R4)
4436 sp [-1].data.i = (gint8) (gint32) sp [-1].data.f_r4;
4437 ++ip;
4438 MINT_IN_BREAK;
4439 MINT_IN_CASE(MINT_CONV_I1_R8)
4440 /* without gint32 cast, C compiler is allowed to use undefined
4441 * behaviour if data.f is bigger than >255. See conv.fpint section
4442 * in C standard:
4443 * > The conversion truncates; that is, the fractional part
4444 * > is discarded. The behavior is undefined if the truncated
4445 * > value cannot be represented in the destination type.
4446 * */
4447 sp [-1].data.i = (gint8) (gint32) sp [-1].data.f;
4448 ++ip;
4449 MINT_IN_BREAK;
4450 MINT_IN_CASE(MINT_CONV_U1_I4)
4451 sp [-1].data.i = (guint8)sp [-1].data.i;
4452 ++ip;
4453 MINT_IN_BREAK;
4454 MINT_IN_CASE(MINT_CONV_U1_I8)
4455 sp [-1].data.i = (guint8)sp [-1].data.l;
4456 ++ip;
4457 MINT_IN_BREAK;
4458 MINT_IN_CASE(MINT_CONV_U1_R4)
4459 sp [-1].data.i = (guint8) (guint32) sp [-1].data.f_r4;
4460 ++ip;
4461 MINT_IN_BREAK;
4462 MINT_IN_CASE(MINT_CONV_U1_R8)
4463 sp [-1].data.i = (guint8) (guint32) sp [-1].data.f;
4464 ++ip;
4465 MINT_IN_BREAK;
4466 MINT_IN_CASE(MINT_CONV_I2_I4)
4467 sp [-1].data.i = (gint16)sp [-1].data.i;
4468 ++ip;
4469 MINT_IN_BREAK;
4470 MINT_IN_CASE(MINT_CONV_I2_I8)
4471 sp [-1].data.i = (gint16)sp [-1].data.l;
4472 ++ip;
4473 MINT_IN_BREAK;
4474 MINT_IN_CASE(MINT_CONV_I2_R4)
4475 sp [-1].data.i = (gint16) (gint32) sp [-1].data.f_r4;
4476 ++ip;
4477 MINT_IN_BREAK;
4478 MINT_IN_CASE(MINT_CONV_I2_R8)
4479 sp [-1].data.i = (gint16) (gint32) sp [-1].data.f;
4480 ++ip;
4481 MINT_IN_BREAK;
4482 MINT_IN_CASE(MINT_CONV_U2_I4)
4483 sp [-1].data.i = (guint16)sp [-1].data.i;
4484 ++ip;
4485 MINT_IN_BREAK;
4486 MINT_IN_CASE(MINT_CONV_U2_I8)
4487 sp [-1].data.i = (guint16)sp [-1].data.l;
4488 ++ip;
4489 MINT_IN_BREAK;
4490 MINT_IN_CASE(MINT_CONV_U2_R4)
4491 sp [-1].data.i = (guint16) (guint32) sp [-1].data.f_r4;
4492 ++ip;
4493 MINT_IN_BREAK;
4494 MINT_IN_CASE(MINT_CONV_U2_R8)
4495 sp [-1].data.i = (guint16) (guint32) sp [-1].data.f;
4496 ++ip;
4497 MINT_IN_BREAK;
4498 MINT_IN_CASE(MINT_CONV_I4_R4)
4499 sp [-1].data.i = (gint32) sp [-1].data.f_r4;
4500 ++ip;
4501 MINT_IN_BREAK;
4502 MINT_IN_CASE(MINT_CONV_I4_R8)
4503 sp [-1].data.i = (gint32)sp [-1].data.f;
4504 ++ip;
4505 MINT_IN_BREAK;
4506 MINT_IN_CASE(MINT_CONV_U4_I8)
4507 MINT_IN_CASE(MINT_CONV_I4_I8)
4508 sp [-1].data.i = (gint32)sp [-1].data.l;
4509 ++ip;
4510 MINT_IN_BREAK;
4511 MINT_IN_CASE(MINT_CONV_I4_I8_SP)
4512 sp [-2].data.i = (gint32)sp [-2].data.l;
4513 ++ip;
4514 MINT_IN_BREAK;
4515 MINT_IN_CASE(MINT_CONV_U4_R4)
4516 #ifdef MONO_ARCH_EMULATE_FCONV_TO_U4
4517 sp [-1].data.i = mono_rconv_u4 (sp [-1].data.f_r4);
4518 #else
4519 sp [-1].data.i = (guint32) sp [-1].data.f_r4;
4520 #endif
4521 ++ip;
4522 MINT_IN_BREAK;
4523 MINT_IN_CASE(MINT_CONV_U4_R8)
4524 #ifdef MONO_ARCH_EMULATE_FCONV_TO_U4
4525 sp [-1].data.i = mono_fconv_u4_2 (sp [-1].data.f);
4526 #else
4527 sp [-1].data.i = (guint32) sp [-1].data.f;
4528 #endif
4529 ++ip;
4530 MINT_IN_BREAK;
4531 MINT_IN_CASE(MINT_CONV_I8_I4)
4532 sp [-1].data.l = sp [-1].data.i;
4533 ++ip;
4534 MINT_IN_BREAK;
4535 MINT_IN_CASE(MINT_CONV_I8_I4_SP)
4536 sp [-2].data.l = sp [-2].data.i;
4537 ++ip;
4538 MINT_IN_BREAK;
4539 MINT_IN_CASE(MINT_CONV_I8_U4)
4540 sp [-1].data.l = (guint32)sp [-1].data.i;
4541 ++ip;
4542 MINT_IN_BREAK;
4543 MINT_IN_CASE(MINT_CONV_I8_R4)
4544 sp [-1].data.l = (gint64) sp [-1].data.f_r4;
4545 ++ip;
4546 MINT_IN_BREAK;
4547 MINT_IN_CASE(MINT_CONV_I8_R8)
4548 sp [-1].data.l = (gint64)sp [-1].data.f;
4549 ++ip;
4550 MINT_IN_BREAK;
4551 MINT_IN_CASE(MINT_CONV_R4_I4)
4552 sp [-1].data.f_r4 = (float)sp [-1].data.i;
4553 ++ip;
4554 MINT_IN_BREAK;
4555 MINT_IN_CASE(MINT_CONV_R4_I8)
4556 sp [-1].data.f_r4 = (float)sp [-1].data.l;
4557 ++ip;
4558 MINT_IN_BREAK;
4559 MINT_IN_CASE(MINT_CONV_R4_R8)
4560 sp [-1].data.f_r4 = (float)sp [-1].data.f;
4561 ++ip;
4562 MINT_IN_BREAK;
4563 MINT_IN_CASE(MINT_CONV_R8_I4)
4564 sp [-1].data.f = (double)sp [-1].data.i;
4565 ++ip;
4566 MINT_IN_BREAK;
4567 MINT_IN_CASE(MINT_CONV_R8_I8)
4568 sp [-1].data.f = (double)sp [-1].data.l;
4569 ++ip;
4570 MINT_IN_BREAK;
4571 MINT_IN_CASE(MINT_CONV_R8_R4)
4572 sp [-1].data.f = (double) sp [-1].data.f_r4;
4573 ++ip;
4574 MINT_IN_BREAK;
4575 MINT_IN_CASE(MINT_CONV_R8_R4_SP)
4576 sp [-2].data.f = (double) sp [-2].data.f_r4;
4577 ++ip;
4578 MINT_IN_BREAK;
4579 MINT_IN_CASE(MINT_CONV_U8_I4)
4580 sp [-1].data.l = sp [-1].data.i & 0xffffffff;
4581 ++ip;
4582 MINT_IN_BREAK;
4583 MINT_IN_CASE(MINT_CONV_U8_R4)
4584 #ifdef MONO_ARCH_EMULATE_FCONV_TO_U8
4585 sp [-1].data.l = mono_rconv_u8 (sp [-1].data.f_r4);
4586 #else
4587 sp [-1].data.l = (guint64) sp [-1].data.f_r4;
4588 #endif
4589 ++ip;
4590 MINT_IN_BREAK;
4591 MINT_IN_CASE(MINT_CONV_U8_R8)
4592 #ifdef MONO_ARCH_EMULATE_FCONV_TO_U8
4593 sp [-1].data.l = mono_fconv_u8_2 (sp [-1].data.f);
4594 #else
4595 sp [-1].data.l = (guint64)sp [-1].data.f;
4596 #endif
4597 ++ip;
4598 MINT_IN_BREAK;
4599 MINT_IN_CASE(MINT_CPOBJ) {
4600 MonoClass* const c = (MonoClass*)frame->imethod->data_items[* (guint16 *)(ip + 1)];
4601 g_assert (m_class_is_valuetype (c));
4602 /* if this assertion fails, we need to add a write barrier */
4603 g_assert (!MONO_TYPE_IS_REFERENCE (m_class_get_byval_arg (c)));
4604 stackval_from_data (m_class_get_byval_arg (c), (stackval*)sp [-2].data.p, sp [-1].data.p, FALSE);
4605 ip += 2;
4606 sp -= 2;
4607 MINT_IN_BREAK;
4609 MINT_IN_CASE(MINT_CPOBJ_VT) {
4610 MonoClass* const c = (MonoClass*)frame->imethod->data_items[* (guint16 *)(ip + 1)];
4611 mono_value_copy_internal (sp [-2].data.vt, sp [-1].data.vt, c);
4612 ip += 2;
4613 sp -= 2;
4614 MINT_IN_BREAK;
4616 MINT_IN_CASE(MINT_LDOBJ_VT) {
4617 int size = READ32(ip + 1);
4618 ip += 3;
4619 memcpy (vt_sp, sp [-1].data.p, size);
4620 sp [-1].data.p = vt_sp;
4621 vt_sp += ALIGN_TO (size, MINT_VT_ALIGNMENT);
4622 MINT_IN_BREAK;
4624 MINT_IN_CASE(MINT_LDSTR)
4625 sp->data.p = frame->imethod->data_items [* (guint16 *)(ip + 1)];
4626 ++sp;
4627 ip += 2;
4628 MINT_IN_BREAK;
4629 MINT_IN_CASE(MINT_LDSTR_TOKEN) {
4630 MonoString *s = NULL;
4631 guint32 strtoken = (guint32)(gsize)frame->imethod->data_items [* (guint16 *)(ip + 1)];
4633 MonoMethod *method = frame->imethod->method;
4634 if (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD) {
4635 s = (MonoString*)mono_method_get_wrapper_data (method, strtoken);
4636 } else if (method->wrapper_type != MONO_WRAPPER_NONE) {
4637 s = mono_string_new_wrapper_internal ((const char*)mono_method_get_wrapper_data (method, strtoken));
4638 } else {
4639 g_assert_not_reached ();
4641 sp->data.p = s;
4642 ++sp;
4643 ip += 2;
4644 MINT_IN_BREAK;
4646 MINT_IN_CASE(MINT_NEWOBJ_ARRAY) {
4647 MonoClass *newobj_class;
4648 guint32 token = * (guint16 *)(ip + 1);
4649 guint16 param_count = * (guint16 *)(ip + 2);
4651 newobj_class = (MonoClass*) frame->imethod->data_items [token];
4653 sp -= param_count;
4654 sp->data.o = ves_array_create (frame->imethod->domain, newobj_class, param_count, sp, error);
4655 if (!is_ok (error))
4656 THROW_EX (mono_error_convert_to_exception (error), ip);
4658 ++sp;
4659 ip += 3;
4660 MINT_IN_BREAK;
4662 MINT_IN_CASE(MINT_NEWOBJ_FAST) {
4664 MonoVTable *vtable = (MonoVTable*) frame->imethod->data_items [*(guint16*)(ip + 3)];
4665 INIT_VTABLE (vtable);
4667 MonoObject* o = NULL; // See the comment about GC safety above.
4668 guint16 param_count;
4669 guint16 imethod_index = *(guint16*) (ip + 1);
4671 const gboolean is_inlined = imethod_index == 0xffff;
4673 param_count = *(guint16*)(ip + 2);
4675 if (param_count) {
4676 sp -= param_count;
4677 memmove (sp + 1 + is_inlined, sp, param_count * sizeof (stackval));
4680 frame_objref (frame) = mono_gc_alloc_obj (vtable, m_class_get_instance_size (vtable->klass));
4681 if (G_UNLIKELY (!frame_objref (frame))) {
4682 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", m_class_get_instance_size (vtable->klass));
4683 THROW_EX (mono_error_convert_to_exception (error), ip);
4686 sp [0].data.o = frame_objref (frame);
4687 if (is_inlined) {
4688 sp [1].data.o = frame_objref (frame);
4689 sp += param_count + 2;
4690 } else {
4691 InterpMethod *ctor_method = (InterpMethod*) frame->imethod->data_items [imethod_index];
4692 frame->ip = ip;
4694 child_frame.imethod = ctor_method;
4695 child_frame.stack_args = sp;
4697 interp_exec_method (&child_frame, context, error);
4698 CHECK_RESUME_STATE (context);
4699 sp [0].data.o = frame_objref (frame);
4700 sp++;
4702 ip += 4;
4704 MINT_IN_BREAK;
4706 MINT_IN_CASE(MINT_NEWOBJ_VT_FAST)
4707 MINT_IN_CASE(MINT_NEWOBJ_VTST_FAST) {
4709 // This is split up to:
4710 // - conserve stack
4711 // - keep exception handling and resume mostly in the main function
4713 frame->ip = ip;
4714 child_frame.imethod = (InterpMethod*) frame->imethod->data_items [*(guint16*)(ip + 1)];
4715 guint16 const param_count = *(guint16*)(ip + 2);
4717 if (param_count) {
4718 sp -= param_count;
4719 memmove (sp + 1, sp, param_count * sizeof (stackval));
4721 child_frame.stack_args = sp;
4722 gboolean const vtst = *ip == MINT_NEWOBJ_VTST_FAST;
4723 if (vtst) {
4724 memset (vt_sp, 0, *(guint16*)(ip + 3));
4725 sp->data.p = vt_sp;
4726 ip += 4;
4728 interp_exec_method (&child_frame, context, error);
4730 CHECK_RESUME_STATE (context);
4731 sp->data.p = vt_sp;
4733 } else {
4734 ip += 3;
4735 mono_interp_newobj_vt (&child_frame, context, error);
4736 CHECK_RESUME_STATE (context);
4738 ++sp;
4739 MINT_IN_BREAK;
4742 MINT_IN_CASE(MINT_NEWOBJ) {
4744 // This is split up to:
4745 // - conserve stack
4746 // - keep exception handling and resume mostly in the main function
4748 frame->ip = ip;
4750 guint32 const token = * (guint16 *)(ip + 1);
4751 ip += 2; // FIXME: Do this after throw?
4753 child_frame.ip = NULL;
4754 child_frame.ex = NULL;
4756 child_frame.imethod = (InterpMethod*)frame->imethod->data_items [token];
4757 MonoMethodSignature* const csig = mono_method_signature_internal (child_frame.imethod->method);
4759 g_assert (csig->hasthis);
4760 if (csig->param_count) {
4761 sp -= csig->param_count;
4762 memmove (sp + 1, sp, csig->param_count * sizeof (stackval));
4765 child_frame.stack_args = sp;
4767 MonoException* const exc = mono_interp_newobj (&child_frame, context, error, vt_sp);
4768 if (exc)
4769 THROW_EX (exc, ip);
4770 CHECK_RESUME_STATE (context);
4771 ++sp;
4772 MINT_IN_BREAK;
4774 MINT_IN_CASE(MINT_NEWOBJ_MAGIC) {
4775 frame->ip = ip;
4776 ip += 2;
4778 MINT_IN_BREAK;
4780 MINT_IN_CASE(MINT_INTRINS_BYREFERENCE_CTOR) {
4781 MonoMethodSignature *csig;
4782 guint32 token;
4784 frame->ip = ip;
4785 token = * (guint16 *)(ip + 1);
4786 ip += 2;
4788 InterpMethod *cmethod = (InterpMethod*)frame->imethod->data_items [token];
4789 csig = mono_method_signature_internal (cmethod->method);
4791 g_assert (csig->hasthis);
4792 sp -= csig->param_count;
4794 gpointer arg0 = sp [0].data.p;
4796 gpointer *byreference_this = (gpointer*)vt_sp;
4797 *byreference_this = arg0;
4799 /* Followed by a VTRESULT opcode which will push the result on the stack */
4800 ++sp;
4801 MINT_IN_BREAK;
4803 MINT_IN_CASE(MINT_INTRINS_BYREFERENCE_GET_VALUE) {
4804 gpointer *byreference_this = (gpointer*)sp [-1].data.p;
4805 sp [-1].data.p = *byreference_this;
4806 ++ip;
4807 MINT_IN_BREAK;
4809 MINT_IN_CASE(MINT_INTRINS_UNSAFE_ADD_BYTE_OFFSET) {
4810 sp -= 2;
4811 sp [0].data.p = (guint8*)sp [0].data.p + sp [1].data.nati;
4812 sp ++;
4813 ++ip;
4814 MINT_IN_BREAK;
4816 MINT_IN_CASE(MINT_INTRINS_UNSAFE_BYTE_OFFSET) {
4817 sp -= 2;
4818 sp [0].data.nati = (guint8*)sp [1].data.p - (guint8*)sp [0].data.p;
4819 sp ++;
4820 ++ip;
4821 MINT_IN_BREAK;
4823 MINT_IN_CASE(MINT_INTRINS_RUNTIMEHELPERS_OBJECT_HAS_COMPONENT_SIZE) {
4824 sp -= 1;
4825 MonoObject *obj = sp [0].data.o;
4826 sp [0].data.i = (obj->vtable->flags & MONO_VT_FLAG_ARRAY_OR_STRING) != 0;
4827 sp ++;
4828 ++ip;
4829 MINT_IN_BREAK;
4831 MINT_IN_CASE(MINT_CASTCLASS_INTERFACE)
4832 MINT_IN_CASE(MINT_ISINST_INTERFACE) {
4833 MonoObject* const o = sp [-1].data.o; // See the comment about GC safety above.
4834 if (o) {
4835 MonoClass* const c = (MonoClass*)frame->imethod->data_items [*(guint16 *)(ip + 1)];
4836 gboolean isinst;
4837 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (o->vtable, m_class_get_interface_id (c))) {
4838 isinst = TRUE;
4839 } else if (m_class_is_array_special_interface (c) || mono_object_is_transparent_proxy (o)) {
4840 /* slow path */
4841 isinst = mono_interp_isinst (o, c); // FIXME: do not swallow the error
4842 } else {
4843 isinst = FALSE;
4846 if (!isinst) {
4847 gboolean const isinst_instr = *ip == MINT_ISINST_INTERFACE;
4848 if (isinst_instr)
4849 sp [-1].data.p = NULL;
4850 else
4851 THROW_EX (mono_get_exception_invalid_cast (), ip);
4854 ip += 2;
4855 MINT_IN_BREAK;
4857 MINT_IN_CASE(MINT_CASTCLASS_COMMON)
4858 MINT_IN_CASE(MINT_ISINST_COMMON) {
4859 MonoObject* const o = sp [-1].data.o; // See the comment about GC safety above
4860 if (o) {
4861 MonoClass* const c = (MonoClass*)frame->imethod->data_items [*(guint16 *)(ip + 1)];
4862 gboolean isinst = mono_class_has_parent_fast (o->vtable->klass, c);
4864 if (!isinst) {
4865 gboolean const isinst_instr = *ip == MINT_ISINST_COMMON;
4866 if (isinst_instr)
4867 sp [-1].data.p = NULL;
4868 else
4869 THROW_EX (mono_get_exception_invalid_cast (), ip);
4872 ip += 2;
4873 MINT_IN_BREAK;
4875 MINT_IN_CASE(MINT_CASTCLASS)
4876 MINT_IN_CASE(MINT_ISINST) {
4877 MonoObject* const o = sp [-1].data.o; // See the comment about GC safety above
4878 if (o) {
4879 MonoClass* const c = (MonoClass*)frame->imethod->data_items [*(guint16 *)(ip + 1)];
4880 if (!mono_interp_isinst (o, c)) { // FIXME: do not swallow the error
4881 gboolean const isinst_instr = *ip == MINT_ISINST;
4882 if (isinst_instr)
4883 sp [-1].data.p = NULL;
4884 else
4885 THROW_EX (mono_get_exception_invalid_cast (), ip);
4888 ip += 2;
4889 MINT_IN_BREAK;
4891 MINT_IN_CASE(MINT_CONV_R_UN_I4)
4892 sp [-1].data.f = (double)(guint32)sp [-1].data.i;
4893 ++ip;
4894 MINT_IN_BREAK;
4895 MINT_IN_CASE(MINT_CONV_R_UN_I8)
4896 sp [-1].data.f = (double)(guint64)sp [-1].data.l;
4897 ++ip;
4898 MINT_IN_BREAK;
4899 MINT_IN_CASE(MINT_UNBOX) {
4900 MonoObject* const o = sp [-1].data.o; // See the comment about GC safety above
4901 NULL_CHECK (o);
4902 MonoClass* const c = (MonoClass*)frame->imethod->data_items[*(guint16 *)(ip + 1)];
4904 if (!(m_class_get_rank (o->vtable->klass) == 0 && m_class_get_element_class (o->vtable->klass) == m_class_get_element_class (c)))
4905 THROW_EX (mono_get_exception_invalid_cast (), ip);
4907 sp [-1].data.p = mono_object_unbox_internal (o);
4908 ip += 2;
4909 MINT_IN_BREAK;
4911 MINT_IN_CASE(MINT_THROW)
4912 --sp;
4913 if (!sp->data.p)
4914 sp->data.p = mono_get_exception_null_reference ();
4916 THROW_EX ((MonoException *)sp->data.p, ip);
4917 MINT_IN_BREAK;
4918 MINT_IN_CASE(MINT_CHECKPOINT)
4919 /* Do synchronous checking of abort requests */
4920 EXCEPTION_CHECKPOINT;
4921 ++ip;
4922 MINT_IN_BREAK;
4923 MINT_IN_CASE(MINT_SAFEPOINT)
4924 /* Do synchronous checking of abort requests */
4925 EXCEPTION_CHECKPOINT;
4926 /* Poll safepoint */
4927 mono_threads_safepoint ();
4928 ++ip;
4929 MINT_IN_BREAK;
4930 MINT_IN_CASE(MINT_LDFLDA_UNSAFE) {
4931 sp[-1].data.p = (char*)sp [-1].data.o + * (guint16 *)(ip + 1);
4932 ip += 2;
4933 MINT_IN_BREAK;
4935 MINT_IN_CASE(MINT_LDFLDA) {
4936 MonoObject* const o = sp [-1].data.o; // See the comment about GC safety above.
4937 NULL_CHECK (o);
4938 sp[-1].data.p = (char *)o + * (guint16 *)(ip + 1);
4939 ip += 2;
4940 MINT_IN_BREAK;
4942 MINT_IN_CASE(MINT_CKNULL_N) {
4943 /* Same as CKNULL, but further down the stack */
4944 int const n = *(guint16*)(ip + 1);
4945 MonoObject* const o = sp [-n].data.o; // See the comment about GC safety above.
4946 NULL_CHECK (o);
4947 ip += 2;
4948 MINT_IN_BREAK;
4951 #define LDFLD_UNALIGNED(datamem, fieldtype, unaligned) do { \
4952 MonoObject* const o = sp [-1].data.o; \
4953 NULL_CHECK (o); \
4954 if (unaligned) \
4955 memcpy (&sp[-1].data.datamem, (char *)o + * (guint16 *)(ip + 1), sizeof (fieldtype)); \
4956 else \
4957 sp[-1].data.datamem = * (fieldtype *)((char *)o + * (guint16 *)(ip + 1)) ; \
4958 ip += 2; \
4959 } while (0)
4961 #define LDFLD(datamem, fieldtype) LDFLD_UNALIGNED(datamem, fieldtype, FALSE)
4963 MINT_IN_CASE(MINT_LDFLD_I1) LDFLD(i, gint8); MINT_IN_BREAK;
4964 MINT_IN_CASE(MINT_LDFLD_U1) LDFLD(i, guint8); MINT_IN_BREAK;
4965 MINT_IN_CASE(MINT_LDFLD_I2) LDFLD(i, gint16); MINT_IN_BREAK;
4966 MINT_IN_CASE(MINT_LDFLD_U2) LDFLD(i, guint16); MINT_IN_BREAK;
4967 MINT_IN_CASE(MINT_LDFLD_I4) LDFLD(i, gint32); MINT_IN_BREAK;
4968 MINT_IN_CASE(MINT_LDFLD_I8) LDFLD(l, gint64); MINT_IN_BREAK;
4969 MINT_IN_CASE(MINT_LDFLD_R4) LDFLD(f_r4, float); MINT_IN_BREAK;
4970 MINT_IN_CASE(MINT_LDFLD_R8) LDFLD(f, double); MINT_IN_BREAK;
4971 MINT_IN_CASE(MINT_LDFLD_O) LDFLD(p, gpointer); MINT_IN_BREAK;
4972 MINT_IN_CASE(MINT_LDFLD_P) LDFLD(p, gpointer); MINT_IN_BREAK;
4973 MINT_IN_CASE(MINT_LDFLD_I8_UNALIGNED) LDFLD_UNALIGNED(l, gint64, TRUE); MINT_IN_BREAK;
4974 MINT_IN_CASE(MINT_LDFLD_R8_UNALIGNED) LDFLD_UNALIGNED(f, double, TRUE); MINT_IN_BREAK;
4976 MINT_IN_CASE(MINT_LDFLD_VT) {
4977 MonoObject* const o = sp [-1].data.o; // See the comment about GC safety above.
4978 NULL_CHECK (o);
4980 int size = READ32(ip + 2);
4981 sp [-1].data.p = vt_sp;
4982 memcpy (sp [-1].data.p, (char *)o + * (guint16 *)(ip + 1), size);
4983 vt_sp += ALIGN_TO (size, MINT_VT_ALIGNMENT);
4984 ip += 4;
4985 MINT_IN_BREAK;
4988 MINT_IN_CASE(MINT_LDRMFLD) {
4989 MonoObject* const o = sp [-1].data.o; // See the comment about GC safety above.
4990 NULL_CHECK (o);
4991 mono_interp_load_remote_field (frame->imethod, o, ip, sp);
4992 ip += 2;
4993 MINT_IN_BREAK;
4995 MINT_IN_CASE(MINT_LDRMFLD_VT) {
4996 MonoObject* const o = sp [-1].data.o; // See the comment about GC safety above.
4997 NULL_CHECK (o);
4998 vt_sp = mono_interp_load_remote_field_vt (frame->imethod, o, ip, sp, vt_sp);
4999 ip += 2;
5000 MINT_IN_BREAK;
5003 #define STFLD_UNALIGNED(datamem, fieldtype, unaligned) do { \
5004 MonoObject* const o = sp [-2].data.o; /* See the comment about GC safety above. */ \
5005 NULL_CHECK (o); \
5006 sp -= 2; \
5007 if (unaligned) \
5008 memcpy ((char *)o + * (guint16 *)(ip + 1), &sp[1].data.datamem, sizeof (fieldtype)); \
5009 else \
5010 * (fieldtype *)((char *)o + * (guint16 *)(ip + 1)) = sp[1].data.datamem; \
5011 ip += 2; \
5012 } while (0)
5014 #define STFLD(datamem, fieldtype) STFLD_UNALIGNED(datamem, fieldtype, FALSE)
5016 MINT_IN_CASE(MINT_STFLD_I1) STFLD(i, gint8); MINT_IN_BREAK;
5017 MINT_IN_CASE(MINT_STFLD_U1) STFLD(i, guint8); MINT_IN_BREAK;
5018 MINT_IN_CASE(MINT_STFLD_I2) STFLD(i, gint16); MINT_IN_BREAK;
5019 MINT_IN_CASE(MINT_STFLD_U2) STFLD(i, guint16); MINT_IN_BREAK;
5020 MINT_IN_CASE(MINT_STFLD_I4) STFLD(i, gint32); MINT_IN_BREAK;
5021 MINT_IN_CASE(MINT_STFLD_I8) STFLD(l, gint64); MINT_IN_BREAK;
5022 MINT_IN_CASE(MINT_STFLD_R4) STFLD(f_r4, float); MINT_IN_BREAK;
5023 MINT_IN_CASE(MINT_STFLD_R8) STFLD(f, double); MINT_IN_BREAK;
5024 MINT_IN_CASE(MINT_STFLD_P) STFLD(p, gpointer); MINT_IN_BREAK;
5025 MINT_IN_CASE(MINT_STFLD_O) {
5026 MonoObject* const o = sp [-2].data.o; // See the comment about GC safety above.
5027 NULL_CHECK (o);
5028 sp -= 2;
5029 mono_gc_wbarrier_set_field_internal (o, (char *) o + * (guint16 *)(ip + 1), sp [1].data.o);
5030 ip += 2;
5031 MINT_IN_BREAK;
5033 MINT_IN_CASE(MINT_STFLD_I8_UNALIGNED) STFLD_UNALIGNED(l, gint64, TRUE); MINT_IN_BREAK;
5034 MINT_IN_CASE(MINT_STFLD_R8_UNALIGNED) STFLD_UNALIGNED(f, double, TRUE); MINT_IN_BREAK;
5036 MINT_IN_CASE(MINT_STFLD_VT) {
5037 MonoObject* const o = sp [-2].data.o; // See the comment about GC safety above.
5038 NULL_CHECK (o);
5039 sp -= 2;
5041 MonoClass *klass = (MonoClass*)frame->imethod->data_items[* (guint16 *)(ip + 2)];
5042 int const i32 = mono_class_value_size (klass, NULL);
5044 guint16 offset = * (guint16 *)(ip + 1);
5045 mono_value_copy_internal ((char *) o + offset, sp [1].data.p, klass);
5047 vt_sp -= ALIGN_TO (i32, MINT_VT_ALIGNMENT);
5048 ip += 3;
5049 MINT_IN_BREAK;
5051 MINT_IN_CASE(MINT_STRMFLD) {
5052 MonoClassField *field;
5054 MonoObject* const o = sp [-2].data.o; // See the comment about GC safety above.
5055 NULL_CHECK (o);
5057 field = (MonoClassField*)frame->imethod->data_items[* (guint16 *)(ip + 1)];
5058 ip += 2;
5060 #ifndef DISABLE_REMOTING
5061 if (mono_object_is_transparent_proxy (o)) {
5062 MonoClass *klass = ((MonoTransparentProxy*)o)->remote_class->proxy_class;
5063 mono_store_remote_field_checked (o, klass, field, &sp [-1].data, error);
5064 mono_error_cleanup (error); /* FIXME: don't swallow the error */
5065 } else
5066 #endif
5067 stackval_to_data (field->type, &sp [-1], (char*)o + field->offset, FALSE);
5069 sp -= 2;
5070 MINT_IN_BREAK;
5072 MINT_IN_CASE(MINT_STRMFLD_VT)
5074 NULL_CHECK (sp [-2].data.o);
5075 vt_sp -= mono_interp_store_remote_field_vt (frame, ip, sp, error);
5076 ip += 2;
5077 sp -= 2;
5078 MINT_IN_BREAK;
5080 MINT_IN_CASE(MINT_LDSFLDA) {
5081 MonoVTable *vtable = (MonoVTable*) frame->imethod->data_items [*(guint16*)(ip + 1)];
5082 INIT_VTABLE (vtable);
5083 sp->data.p = frame->imethod->data_items [*(guint16*)(ip + 2)];
5084 ip += 3;
5085 ++sp;
5086 MINT_IN_BREAK;
5089 MINT_IN_CASE(MINT_LDSSFLDA) {
5090 guint32 offset = READ32(ip + 1);
5091 sp->data.p = mono_get_special_static_data (offset);
5092 ip += 3;
5093 ++sp;
5094 MINT_IN_BREAK;
5097 /* We init class here to preserve cctor order */
5098 #define LDSFLD(datamem, fieldtype) { \
5099 MonoVTable *vtable = (MonoVTable*) frame->imethod->data_items [*(guint16*)(ip + 1)]; \
5100 INIT_VTABLE (vtable); \
5101 sp[0].data.datamem = * (fieldtype *)(frame->imethod->data_items [* (guint16 *)(ip + 2)]) ; \
5102 ip += 3; \
5103 sp++; \
5106 MINT_IN_CASE(MINT_LDSFLD_I1) LDSFLD(i, gint8); MINT_IN_BREAK;
5107 MINT_IN_CASE(MINT_LDSFLD_U1) LDSFLD(i, guint8); MINT_IN_BREAK;
5108 MINT_IN_CASE(MINT_LDSFLD_I2) LDSFLD(i, gint16); MINT_IN_BREAK;
5109 MINT_IN_CASE(MINT_LDSFLD_U2) LDSFLD(i, guint16); MINT_IN_BREAK;
5110 MINT_IN_CASE(MINT_LDSFLD_I4) LDSFLD(i, gint32); MINT_IN_BREAK;
5111 MINT_IN_CASE(MINT_LDSFLD_I8) LDSFLD(l, gint64); MINT_IN_BREAK;
5112 MINT_IN_CASE(MINT_LDSFLD_R4) LDSFLD(f_r4, float); MINT_IN_BREAK;
5113 MINT_IN_CASE(MINT_LDSFLD_R8) LDSFLD(f, double); MINT_IN_BREAK;
5114 MINT_IN_CASE(MINT_LDSFLD_O) LDSFLD(p, gpointer); MINT_IN_BREAK;
5115 MINT_IN_CASE(MINT_LDSFLD_P) LDSFLD(p, gpointer); MINT_IN_BREAK;
5117 MINT_IN_CASE(MINT_LDSFLD_VT) {
5118 MonoVTable *vtable = (MonoVTable*) frame->imethod->data_items [*(guint16*)(ip + 1)];
5119 INIT_VTABLE (vtable);
5120 sp->data.p = vt_sp;
5122 gpointer addr = frame->imethod->data_items [*(guint16*)(ip + 2)];
5123 int const i32 = READ32 (ip + 3);
5124 memcpy (vt_sp, addr, i32);
5125 vt_sp += ALIGN_TO (i32, MINT_VT_ALIGNMENT);
5126 ip += 5;
5127 ++sp;
5128 MINT_IN_BREAK;
5131 #define LDTSFLD(datamem, fieldtype) { \
5132 MonoInternalThread *thread = mono_thread_internal_current (); \
5133 guint32 offset = READ32 (ip + 1); \
5134 gpointer addr = ((char*)thread->static_data [offset & 0x3f]) + (offset >> 6); \
5135 sp[0].data.datamem = *(fieldtype*)addr; \
5136 ip += 3; \
5137 ++sp; \
5139 MINT_IN_CASE(MINT_LDTSFLD_I1) LDTSFLD(i, gint8); MINT_IN_BREAK;
5140 MINT_IN_CASE(MINT_LDTSFLD_U1) LDTSFLD(i, guint8); MINT_IN_BREAK;
5141 MINT_IN_CASE(MINT_LDTSFLD_I2) LDTSFLD(i, gint16); MINT_IN_BREAK;
5142 MINT_IN_CASE(MINT_LDTSFLD_U2) LDTSFLD(i, guint16); MINT_IN_BREAK;
5143 MINT_IN_CASE(MINT_LDTSFLD_I4) LDTSFLD(i, gint32); MINT_IN_BREAK;
5144 MINT_IN_CASE(MINT_LDTSFLD_I8) LDTSFLD(l, gint64); MINT_IN_BREAK;
5145 MINT_IN_CASE(MINT_LDTSFLD_R4) LDTSFLD(f_r4, float); MINT_IN_BREAK;
5146 MINT_IN_CASE(MINT_LDTSFLD_R8) LDTSFLD(f, double); MINT_IN_BREAK;
5147 MINT_IN_CASE(MINT_LDTSFLD_O) LDTSFLD(p, gpointer); MINT_IN_BREAK;
5148 MINT_IN_CASE(MINT_LDTSFLD_P) LDTSFLD(p, gpointer); MINT_IN_BREAK;
5150 MINT_IN_CASE(MINT_LDSSFLD) {
5151 guint32 offset = READ32(ip + 2);
5152 gpointer addr = mono_get_special_static_data (offset);
5153 MonoClassField *field = (MonoClassField*)frame->imethod->data_items [* (guint16 *)(ip + 1)];
5154 stackval_from_data (field->type, sp, addr, FALSE);
5155 ip += 4;
5156 ++sp;
5157 MINT_IN_BREAK;
5159 MINT_IN_CASE(MINT_LDSSFLD_VT) {
5160 guint32 offset = READ32(ip + 1);
5161 gpointer addr = mono_get_special_static_data (offset);
5163 int size = READ32 (ip + 3);
5164 memcpy (vt_sp, addr, size);
5165 sp->data.p = vt_sp;
5166 vt_sp += ALIGN_TO (size, MINT_VT_ALIGNMENT);
5167 ip += 5;
5168 ++sp;
5169 MINT_IN_BREAK;
5171 #define STSFLD(datamem, fieldtype) { \
5172 MonoVTable *vtable = (MonoVTable*) frame->imethod->data_items [*(guint16*)(ip + 1)]; \
5173 INIT_VTABLE (vtable); \
5174 sp --; \
5175 * (fieldtype *)(frame->imethod->data_items [* (guint16 *)(ip + 2)]) = sp[0].data.datamem; \
5176 ip += 3; \
5179 MINT_IN_CASE(MINT_STSFLD_I1) STSFLD(i, gint8); MINT_IN_BREAK;
5180 MINT_IN_CASE(MINT_STSFLD_U1) STSFLD(i, guint8); MINT_IN_BREAK;
5181 MINT_IN_CASE(MINT_STSFLD_I2) STSFLD(i, gint16); MINT_IN_BREAK;
5182 MINT_IN_CASE(MINT_STSFLD_U2) STSFLD(i, guint16); MINT_IN_BREAK;
5183 MINT_IN_CASE(MINT_STSFLD_I4) STSFLD(i, gint32); MINT_IN_BREAK;
5184 MINT_IN_CASE(MINT_STSFLD_I8) STSFLD(l, gint64); MINT_IN_BREAK;
5185 MINT_IN_CASE(MINT_STSFLD_R4) STSFLD(f_r4, float); MINT_IN_BREAK;
5186 MINT_IN_CASE(MINT_STSFLD_R8) STSFLD(f, double); MINT_IN_BREAK;
5187 MINT_IN_CASE(MINT_STSFLD_P) STSFLD(p, gpointer); MINT_IN_BREAK;
5188 MINT_IN_CASE(MINT_STSFLD_O) STSFLD(p, gpointer); MINT_IN_BREAK;
5190 MINT_IN_CASE(MINT_STSFLD_VT) {
5191 MonoVTable *vtable = (MonoVTable*) frame->imethod->data_items [*(guint16*)(ip + 1)];
5192 INIT_VTABLE (vtable);
5193 int const i32 = READ32 (ip + 3);
5194 gpointer addr = frame->imethod->data_items [*(guint16*)(ip + 2)];
5196 memcpy (addr, sp [-1].data.vt, i32);
5197 vt_sp -= ALIGN_TO (i32, MINT_VT_ALIGNMENT);
5198 ip += 4;
5199 --sp;
5200 MINT_IN_BREAK;
5203 #define STTSFLD(datamem, fieldtype) { \
5204 MonoInternalThread *thread = mono_thread_internal_current (); \
5205 guint32 offset = READ32 (ip + 1); \
5206 gpointer addr = ((char*)thread->static_data [offset & 0x3f]) + (offset >> 6); \
5207 sp--; \
5208 *(fieldtype*)addr = sp[0].data.datamem; \
5209 ip += 3; \
5212 MINT_IN_CASE(MINT_STTSFLD_I1) STTSFLD(i, gint8); MINT_IN_BREAK;
5213 MINT_IN_CASE(MINT_STTSFLD_U1) STTSFLD(i, guint8); MINT_IN_BREAK;
5214 MINT_IN_CASE(MINT_STTSFLD_I2) STTSFLD(i, gint16); MINT_IN_BREAK;
5215 MINT_IN_CASE(MINT_STTSFLD_U2) STTSFLD(i, guint16); MINT_IN_BREAK;
5216 MINT_IN_CASE(MINT_STTSFLD_I4) STTSFLD(i, gint32); MINT_IN_BREAK;
5217 MINT_IN_CASE(MINT_STTSFLD_I8) STTSFLD(l, gint64); MINT_IN_BREAK;
5218 MINT_IN_CASE(MINT_STTSFLD_R4) STTSFLD(f_r4, float); MINT_IN_BREAK;
5219 MINT_IN_CASE(MINT_STTSFLD_R8) STTSFLD(f, double); MINT_IN_BREAK;
5220 MINT_IN_CASE(MINT_STTSFLD_P) STTSFLD(p, gpointer); MINT_IN_BREAK;
5221 MINT_IN_CASE(MINT_STTSFLD_O) STTSFLD(p, gpointer); MINT_IN_BREAK;
5223 MINT_IN_CASE(MINT_STSSFLD) {
5224 guint32 offset = READ32(ip + 2);
5225 gpointer addr = mono_get_special_static_data (offset);
5226 MonoClassField *field = (MonoClassField*)frame->imethod->data_items [* (guint16 *)(ip + 1)];
5227 --sp;
5228 stackval_to_data (field->type, sp, addr, FALSE);
5229 ip += 4;
5230 MINT_IN_BREAK;
5232 MINT_IN_CASE(MINT_STSSFLD_VT) {
5233 guint32 offset = READ32(ip + 1);
5234 gpointer addr = mono_get_special_static_data (offset);
5235 --sp;
5236 int size = READ32 (ip + 3);
5237 memcpy (addr, sp->data.vt, size);
5238 vt_sp -= ALIGN_TO (size, MINT_VT_ALIGNMENT);
5239 ip += 5;
5240 MINT_IN_BREAK;
5243 MINT_IN_CASE(MINT_STOBJ_VT) {
5244 int size;
5245 MonoClass* const c = (MonoClass*)frame->imethod->data_items[* (guint16 *)(ip + 1)];
5246 ip += 2;
5247 size = mono_class_value_size (c, NULL);
5248 mono_value_copy_internal (sp [-2].data.p, sp [-1].data.p, c);
5249 vt_sp -= ALIGN_TO (size, MINT_VT_ALIGNMENT);
5250 sp -= 2;
5251 MINT_IN_BREAK;
5253 MINT_IN_CASE(MINT_CONV_OVF_I4_UN_R8)
5254 if (sp [-1].data.f < 0 || sp [-1].data.f > G_MAXINT32)
5255 THROW_EX_OVF (ip);
5256 sp [-1].data.i = (gint32)sp [-1].data.f;
5257 ++ip;
5258 MINT_IN_BREAK;
5259 MINT_IN_CASE(MINT_CONV_OVF_U8_I4)
5260 if (sp [-1].data.i < 0)
5261 THROW_EX_OVF (ip);
5262 sp [-1].data.l = sp [-1].data.i;
5263 ++ip;
5264 MINT_IN_BREAK;
5265 MINT_IN_CASE(MINT_CONV_OVF_U8_I8)
5266 if (sp [-1].data.l < 0)
5267 THROW_EX_OVF (ip);
5268 ++ip;
5269 MINT_IN_BREAK;
5270 MINT_IN_CASE(MINT_CONV_OVF_I8_U8)
5271 if ((guint64) sp [-1].data.l > G_MAXINT64)
5272 THROW_EX_OVF (ip);
5273 ++ip;
5274 MINT_IN_BREAK;
5275 MINT_IN_CASE(MINT_CONV_OVF_U8_R4)
5276 if (sp [-1].data.f_r4 < 0 || sp [-1].data.f_r4 > G_MAXUINT64 || isnan (sp [-1].data.f_r4))
5277 THROW_EX_OVF (ip);
5278 sp [-1].data.l = (guint64)sp [-1].data.f_r4;
5279 ++ip;
5280 MINT_IN_BREAK;
5281 MINT_IN_CASE(MINT_CONV_OVF_U8_R8)
5282 if (sp [-1].data.f < 0 || sp [-1].data.f > G_MAXUINT64 || isnan (sp [-1].data.f))
5283 THROW_EX_OVF (ip);
5284 sp [-1].data.l = (guint64)sp [-1].data.f;
5285 ++ip;
5286 MINT_IN_BREAK;
5287 MINT_IN_CASE(MINT_CONV_OVF_I8_UN_R8)
5288 if (sp [-1].data.f < 0 || sp [-1].data.f > G_MAXINT64)
5289 THROW_EX_OVF (ip);
5290 sp [-1].data.l = (gint64)sp [-1].data.f;
5291 ++ip;
5292 MINT_IN_BREAK;
5293 MINT_IN_CASE(MINT_CONV_OVF_I8_UN_R4)
5294 if (sp [-1].data.f_r4 < 0 || sp [-1].data.f_r4 > G_MAXINT64)
5295 THROW_EX_OVF (ip);
5296 sp [-1].data.l = (gint64)sp [-1].data.f_r4;
5297 ++ip;
5298 MINT_IN_BREAK;
5299 MINT_IN_CASE(MINT_CONV_OVF_I8_R4)
5300 if (sp [-1].data.f_r4 < G_MININT64 || sp [-1].data.f_r4 > G_MAXINT64 || isnan (sp [-1].data.f_r4))
5301 THROW_EX_OVF (ip);
5302 sp [-1].data.l = (gint64)sp [-1].data.f_r4;
5303 ++ip;
5304 MINT_IN_BREAK;
5305 MINT_IN_CASE(MINT_CONV_OVF_I8_R8)
5306 if (sp [-1].data.f < G_MININT64 || sp [-1].data.f > G_MAXINT64 || isnan (sp [-1].data.f))
5307 THROW_EX_OVF (ip);
5308 sp [-1].data.l = (gint64)sp [-1].data.f;
5309 ++ip;
5310 MINT_IN_BREAK;
5311 MINT_IN_CASE(MINT_CONV_OVF_I4_UN_I8)
5312 if ((guint64)sp [-1].data.l > G_MAXINT32)
5313 THROW_EX_OVF (ip);
5314 sp [-1].data.i = (gint32)sp [-1].data.l;
5315 ++ip;
5316 MINT_IN_BREAK;
5317 MINT_IN_CASE(MINT_BOX) {
5318 MonoObject* o; // See the comment about GC safety above.
5319 MonoVTable *vtable = (MonoVTable*)frame->imethod->data_items [* (guint16 *)(ip + 1)];
5321 frame_objref (frame) = mono_gc_alloc_obj (vtable, m_class_get_instance_size (vtable->klass));
5323 guint16 offset = * (guint16 *)(ip + 2);
5325 stackval_to_data (m_class_get_byval_arg (vtable->klass), &sp [-1 - offset], mono_object_get_data (frame_objref (frame)), FALSE);
5327 sp [-1 - offset].data.p = frame_objref (frame);
5329 ip += 3;
5330 MINT_IN_BREAK;
5332 MINT_IN_CASE(MINT_BOX_VT) {
5333 vt_sp -= mono_interp_box_vt (frame, ip, sp);
5334 ip += 3;
5335 MINT_IN_BREAK;
5337 MINT_IN_CASE(MINT_BOX_NULLABLE) {
5338 vt_sp -= mono_interp_box_nullable (frame, ip, sp, error);
5339 ip += 3;
5340 MINT_IN_BREAK;
5342 MINT_IN_CASE(MINT_NEWARR) {
5343 MonoVTable *vtable = (MonoVTable*)frame->imethod->data_items[*(guint16 *)(ip + 1)];
5344 sp [-1].data.o = (MonoObject*) mono_array_new_specific_checked (vtable, sp [-1].data.i, error);
5345 if (!is_ok (error)) {
5346 THROW_EX (mono_error_convert_to_exception (error), ip);
5348 mono_error_cleanup (error); /* FIXME: don't swallow the error */
5349 ip += 2;
5350 /*if (profiling_classes) {
5351 guint count = GPOINTER_TO_UINT (g_hash_table_lookup (profiling_classes, o->vtable->klass));
5352 count++;
5353 g_hash_table_insert (profiling_classes, o->vtable->klass, GUINT_TO_POINTER (count));
5356 MINT_IN_BREAK;
5358 MINT_IN_CASE(MINT_LDLEN) {
5359 MonoObject* const o = sp [-1].data.o; // See the comment about GC safety above.
5360 NULL_CHECK (o);
5361 sp [-1].data.nati = mono_array_length_internal ((MonoArray *)o);
5362 ++ip;
5363 MINT_IN_BREAK;
5365 MINT_IN_CASE(MINT_LDLEN_SPAN) {
5366 MonoObject* const o = sp [-1].data.o; // See the comment about GC safety above.
5367 NULL_CHECK (o);
5368 gsize offset_length = (gsize) *(gint16 *) (ip + 1);
5369 sp [-1].data.nati = *(gint32 *) ((guint8 *) o + offset_length);
5370 ip += 2;
5371 MINT_IN_BREAK;
5373 MINT_IN_CASE(MINT_GETCHR) {
5374 MonoString *s;
5375 s = (MonoString*)sp [-2].data.p;
5376 NULL_CHECK (s);
5377 int const i32 = sp [-1].data.i;
5378 if (i32 < 0 || i32 >= mono_string_length_internal (s))
5379 THROW_EX (mono_get_exception_index_out_of_range (), ip);
5380 --sp;
5381 sp [-1].data.i = mono_string_chars_internal (s)[i32];
5382 ++ip;
5383 MINT_IN_BREAK;
5385 MINT_IN_CASE(MINT_GETITEM_SPAN) {
5386 guint8 * const span = (guint8 *) sp [-2].data.p;
5387 const int index = sp [-1].data.i;
5388 sp--;
5390 NULL_CHECK (span);
5392 const gsize offset_length = (gsize) *(gint16 *) (ip + 2);
5394 const gint32 length = *(gint32 *) (span + offset_length);
5395 if (index < 0 || index >= length)
5396 THROW_EX (mono_get_exception_index_out_of_range (), ip);
5398 const gsize element_size = (gsize) *(gint16 *) (ip + 1);
5399 const gsize offset_pointer = (gsize) *(gint16 *) (ip + 3);
5401 const gpointer pointer = *(gpointer *)(span + offset_pointer);
5402 sp [-1].data.p = (guint8 *) pointer + index * element_size;
5404 ip += 4;
5405 MINT_IN_BREAK;
5407 MINT_IN_CASE(MINT_STRLEN) {
5408 ++ip;
5409 MonoObject* const o = sp [-1].data.o; // See the comment about GC safety above.
5410 NULL_CHECK (o);
5411 sp [-1].data.i = mono_string_length_internal ((MonoString*) o);
5412 MINT_IN_BREAK;
5414 MINT_IN_CASE(MINT_ARRAY_RANK) {
5415 MonoObject* const o = sp [-1].data.o; // See the comment about GC safety above.
5416 NULL_CHECK (o);
5417 sp [-1].data.i = m_class_get_rank (mono_object_class (sp [-1].data.p));
5418 ip++;
5419 MINT_IN_BREAK;
5421 MINT_IN_CASE(MINT_LDELEMA_FAST) {
5422 /* No bounds, one direction */
5423 MonoArray *ao = (MonoArray*)sp [-2].data.o;
5424 NULL_CHECK (ao);
5425 gint32 const index = sp [-1].data.i;
5426 if (index >= ao->max_length)
5427 THROW_EX (mono_get_exception_index_out_of_range (), ip);
5428 gint32 const size = READ32 (ip + 1);
5429 sp [-2].data.p = mono_array_addr_with_size_fast (ao, size, index);
5430 ip += 3;
5431 sp --;
5433 MINT_IN_BREAK;
5435 MINT_IN_CASE(MINT_LDELEMA)
5436 MINT_IN_CASE(MINT_LDELEMA_TC) {
5438 guint16 numargs = *(guint16 *) (ip + 2);
5439 ip += 3;
5440 sp -= numargs;
5442 MonoObject* const o = sp [0].data.o; // See the comment about GC safety above.
5443 NULL_CHECK (o);
5445 MonoClass *klass = (MonoClass*)frame->imethod->data_items [*(guint16 *) (ip - 3 + 1)];
5446 const gboolean needs_typecheck = ip [-3] == MINT_LDELEMA_TC;
5447 sp->data.p = ves_array_element_address (frame, klass, (MonoArray *) o, &sp [1], needs_typecheck);
5448 if (frame->ex)
5449 THROW_EX (frame->ex, ip);
5450 ++sp;
5452 MINT_IN_BREAK;
5454 MINT_IN_CASE(MINT_LDELEM_I1) /* fall through */
5455 MINT_IN_CASE(MINT_LDELEM_U1) /* fall through */
5456 MINT_IN_CASE(MINT_LDELEM_I2) /* fall through */
5457 MINT_IN_CASE(MINT_LDELEM_U2) /* fall through */
5458 MINT_IN_CASE(MINT_LDELEM_I4) /* fall through */
5459 MINT_IN_CASE(MINT_LDELEM_U4) /* fall through */
5460 MINT_IN_CASE(MINT_LDELEM_I8) /* fall through */
5461 MINT_IN_CASE(MINT_LDELEM_I) /* fall through */
5462 MINT_IN_CASE(MINT_LDELEM_R4) /* fall through */
5463 MINT_IN_CASE(MINT_LDELEM_R8) /* fall through */
5464 MINT_IN_CASE(MINT_LDELEM_REF) /* fall through */
5465 MINT_IN_CASE(MINT_LDELEM_VT) {
5466 MonoArray *o;
5467 mono_u aindex;
5469 sp -= 2;
5471 o = (MonoArray*)sp [0].data.p;
5472 NULL_CHECK (o);
5474 aindex = sp [1].data.i;
5475 if (aindex >= mono_array_length_internal (o))
5476 THROW_EX (mono_get_exception_index_out_of_range (), ip);
5479 * FIXME: throw mono_get_exception_array_type_mismatch () if needed
5481 switch (*ip) {
5482 case MINT_LDELEM_I1:
5483 sp [0].data.i = mono_array_get_fast (o, gint8, aindex);
5484 break;
5485 case MINT_LDELEM_U1:
5486 sp [0].data.i = mono_array_get_fast (o, guint8, aindex);
5487 break;
5488 case MINT_LDELEM_I2:
5489 sp [0].data.i = mono_array_get_fast (o, gint16, aindex);
5490 break;
5491 case MINT_LDELEM_U2:
5492 sp [0].data.i = mono_array_get_fast (o, guint16, aindex);
5493 break;
5494 case MINT_LDELEM_I:
5495 sp [0].data.nati = mono_array_get_fast (o, mono_i, aindex);
5496 break;
5497 case MINT_LDELEM_I4:
5498 sp [0].data.i = mono_array_get_fast (o, gint32, aindex);
5499 break;
5500 case MINT_LDELEM_U4:
5501 sp [0].data.i = mono_array_get_fast (o, guint32, aindex);
5502 break;
5503 case MINT_LDELEM_I8:
5504 sp [0].data.l = mono_array_get_fast (o, guint64, aindex);
5505 break;
5506 case MINT_LDELEM_R4:
5507 sp [0].data.f_r4 = mono_array_get_fast (o, float, aindex);
5508 break;
5509 case MINT_LDELEM_R8:
5510 sp [0].data.f = mono_array_get_fast (o, double, aindex);
5511 break;
5512 case MINT_LDELEM_REF:
5513 sp [0].data.p = mono_array_get_fast (o, gpointer, aindex);
5514 break;
5515 case MINT_LDELEM_VT: {
5516 int const i32 = READ32 (ip + 1);
5517 char *src_addr = mono_array_addr_with_size_fast ((MonoArray *) o, i32, aindex);
5518 sp [0].data.vt = vt_sp;
5519 // Copying to vtstack. No wbarrier needed
5520 memcpy (sp [0].data.vt, src_addr, i32);
5521 vt_sp += ALIGN_TO (i32, MINT_VT_ALIGNMENT);
5522 ip += 2;
5523 break;
5525 default:
5526 ves_abort();
5529 ++ip;
5530 ++sp;
5531 MINT_IN_BREAK;
5533 MINT_IN_CASE(MINT_STELEM_I) /* fall through */
5534 MINT_IN_CASE(MINT_STELEM_I1) /* fall through */
5535 MINT_IN_CASE(MINT_STELEM_U1) /* fall through */
5536 MINT_IN_CASE(MINT_STELEM_I2) /* fall through */
5537 MINT_IN_CASE(MINT_STELEM_U2) /* fall through */
5538 MINT_IN_CASE(MINT_STELEM_I4) /* fall through */
5539 MINT_IN_CASE(MINT_STELEM_I8) /* fall through */
5540 MINT_IN_CASE(MINT_STELEM_R4) /* fall through */
5541 MINT_IN_CASE(MINT_STELEM_R8) /* fall through */
5542 MINT_IN_CASE(MINT_STELEM_REF) /* fall through */
5543 MINT_IN_CASE(MINT_STELEM_VT) {
5544 mono_u aindex;
5546 sp -= 3;
5548 MonoObject* const o = sp [0].data.o; // See the comment about GC safety above.
5549 NULL_CHECK (o);
5551 aindex = sp [1].data.i;
5552 if (aindex >= mono_array_length_internal ((MonoArray *)o))
5553 THROW_EX (mono_get_exception_index_out_of_range (), ip);
5555 switch (*ip) {
5556 case MINT_STELEM_I:
5557 mono_array_set_fast ((MonoArray *)o, mono_i, aindex, sp [2].data.nati);
5558 break;
5559 case MINT_STELEM_I1:
5560 mono_array_set_fast ((MonoArray *)o, gint8, aindex, sp [2].data.i);
5561 break;
5562 case MINT_STELEM_U1:
5563 mono_array_set_fast ((MonoArray *) o, guint8, aindex, sp [2].data.i);
5564 break;
5565 case MINT_STELEM_I2:
5566 mono_array_set_fast ((MonoArray *)o, gint16, aindex, sp [2].data.i);
5567 break;
5568 case MINT_STELEM_U2:
5569 mono_array_set_fast ((MonoArray *)o, guint16, aindex, sp [2].data.i);
5570 break;
5571 case MINT_STELEM_I4:
5572 mono_array_set_fast ((MonoArray *)o, gint32, aindex, sp [2].data.i);
5573 break;
5574 case MINT_STELEM_I8:
5575 mono_array_set_fast ((MonoArray *)o, gint64, aindex, sp [2].data.l);
5576 break;
5577 case MINT_STELEM_R4:
5578 mono_array_set_fast ((MonoArray *)o, float, aindex, sp [2].data.f_r4);
5579 break;
5580 case MINT_STELEM_R8:
5581 mono_array_set_fast ((MonoArray *)o, double, aindex, sp [2].data.f);
5582 break;
5583 case MINT_STELEM_REF: {
5584 if (sp [2].data.p) {
5585 MonoObject *isinst_obj = mono_object_isinst_checked (sp [2].data.o, m_class_get_element_class (mono_object_class (o)), error);
5586 mono_error_cleanup (error); /* FIXME: don't swallow the error */
5587 if (!isinst_obj)
5588 THROW_EX (mono_get_exception_array_type_mismatch (), ip);
5590 mono_array_setref_fast ((MonoArray *) o, aindex, sp [2].data.p);
5591 break;
5593 case MINT_STELEM_VT: {
5594 MonoClass *klass_vt = (MonoClass*)frame->imethod->data_items [*(guint16 *) (ip + 1)];
5595 int const i32 = READ32 (ip + 2);
5596 char *dst_addr = mono_array_addr_with_size_fast ((MonoArray *) o, i32, aindex);
5598 mono_value_copy_internal (dst_addr, sp [2].data.vt, klass_vt);
5599 vt_sp -= ALIGN_TO (i32, MINT_VT_ALIGNMENT);
5600 ip += 3;
5601 break;
5603 default:
5604 ves_abort();
5607 ++ip;
5608 MINT_IN_BREAK;
5610 MINT_IN_CASE(MINT_CONV_OVF_I4_U4)
5611 if (sp [-1].data.i < 0)
5612 THROW_EX_OVF (ip);
5613 ++ip;
5614 MINT_IN_BREAK;
5615 MINT_IN_CASE(MINT_CONV_OVF_I4_I8)
5616 if (sp [-1].data.l < G_MININT32 || sp [-1].data.l > G_MAXINT32)
5617 THROW_EX_OVF (ip);
5618 sp [-1].data.i = (gint32) sp [-1].data.l;
5619 ++ip;
5620 MINT_IN_BREAK;
5621 MINT_IN_CASE(MINT_CONV_OVF_I4_U8)
5622 if (sp [-1].data.l < 0 || sp [-1].data.l > G_MAXINT32)
5623 THROW_EX_OVF (ip);
5624 sp [-1].data.i = (gint32) sp [-1].data.l;
5625 ++ip;
5626 MINT_IN_BREAK;
5627 MINT_IN_CASE(MINT_CONV_OVF_I4_R4)
5628 if (sp [-1].data.f_r4 < G_MININT32 || sp [-1].data.f_r4 > G_MAXINT32)
5629 THROW_EX_OVF (ip);
5630 sp [-1].data.i = (gint32) sp [-1].data.f_r4;
5631 ++ip;
5632 MINT_IN_BREAK;
5633 MINT_IN_CASE(MINT_CONV_OVF_I4_R8)
5634 if (sp [-1].data.f < G_MININT32 || sp [-1].data.f > G_MAXINT32)
5635 THROW_EX_OVF (ip);
5636 sp [-1].data.i = (gint32) sp [-1].data.f;
5637 ++ip;
5638 MINT_IN_BREAK;
5639 MINT_IN_CASE(MINT_CONV_OVF_U4_I4)
5640 if (sp [-1].data.i < 0)
5641 THROW_EX_OVF (ip);
5642 ++ip;
5643 MINT_IN_BREAK;
5644 MINT_IN_CASE(MINT_CONV_OVF_U4_I8)
5645 if (sp [-1].data.l < 0 || sp [-1].data.l > G_MAXUINT32)
5646 THROW_EX_OVF (ip);
5647 sp [-1].data.i = (guint32) sp [-1].data.l;
5648 ++ip;
5649 MINT_IN_BREAK;
5650 MINT_IN_CASE(MINT_CONV_OVF_U4_R4)
5651 if (sp [-1].data.f_r4 < 0 || sp [-1].data.f_r4 > G_MAXUINT32)
5652 THROW_EX_OVF (ip);
5653 sp [-1].data.i = (guint32) sp [-1].data.f_r4;
5654 ++ip;
5655 MINT_IN_BREAK;
5656 MINT_IN_CASE(MINT_CONV_OVF_U4_R8)
5657 if (sp [-1].data.f < 0 || sp [-1].data.f > G_MAXUINT32)
5658 THROW_EX_OVF (ip);
5659 sp [-1].data.i = (guint32) sp [-1].data.f;
5660 ++ip;
5661 MINT_IN_BREAK;
5662 MINT_IN_CASE(MINT_CONV_OVF_I2_I4)
5663 if (sp [-1].data.i < G_MININT16 || sp [-1].data.i > G_MAXINT16)
5664 THROW_EX_OVF (ip);
5665 ++ip;
5666 MINT_IN_BREAK;
5667 MINT_IN_CASE(MINT_CONV_OVF_I2_U4)
5668 if (sp [-1].data.i < 0 || sp [-1].data.i > G_MAXINT16)
5669 THROW_EX_OVF (ip);
5670 ++ip;
5671 MINT_IN_BREAK;
5672 MINT_IN_CASE(MINT_CONV_OVF_I2_I8)
5673 if (sp [-1].data.l < G_MININT16 || sp [-1].data.l > G_MAXINT16)
5674 THROW_EX_OVF (ip);
5675 sp [-1].data.i = (gint16) sp [-1].data.l;
5676 ++ip;
5677 MINT_IN_BREAK;
5678 MINT_IN_CASE(MINT_CONV_OVF_I2_U8)
5679 if (sp [-1].data.l < 0 || sp [-1].data.l > G_MAXINT16)
5680 THROW_EX_OVF (ip);
5681 sp [-1].data.i = (gint16) sp [-1].data.l;
5682 ++ip;
5683 MINT_IN_BREAK;
5684 MINT_IN_CASE(MINT_CONV_OVF_I2_R8)
5685 if (sp [-1].data.f < G_MININT16 || sp [-1].data.f > G_MAXINT16)
5686 THROW_EX_OVF (ip);
5687 sp [-1].data.i = (gint16) sp [-1].data.f;
5688 ++ip;
5689 MINT_IN_BREAK;
5690 MINT_IN_CASE(MINT_CONV_OVF_I2_UN_R8)
5691 if (sp [-1].data.f < 0 || sp [-1].data.f > G_MAXINT16)
5692 THROW_EX_OVF (ip);
5693 sp [-1].data.i = (gint16) sp [-1].data.f;
5694 ++ip;
5695 MINT_IN_BREAK;
5696 MINT_IN_CASE(MINT_CONV_OVF_U2_I4)
5697 if (sp [-1].data.i < 0 || sp [-1].data.i > G_MAXUINT16)
5698 THROW_EX_OVF (ip);
5699 ++ip;
5700 MINT_IN_BREAK;
5701 MINT_IN_CASE(MINT_CONV_OVF_U2_I8)
5702 if (sp [-1].data.l < 0 || sp [-1].data.l > G_MAXUINT16)
5703 THROW_EX_OVF (ip);
5704 sp [-1].data.i = (guint16) sp [-1].data.l;
5705 ++ip;
5706 MINT_IN_BREAK;
5707 MINT_IN_CASE(MINT_CONV_OVF_U2_R8)
5708 if (sp [-1].data.f < 0 || sp [-1].data.f > G_MAXUINT16)
5709 THROW_EX_OVF (ip);
5710 sp [-1].data.i = (guint16) sp [-1].data.f;
5711 ++ip;
5712 MINT_IN_BREAK;
5713 MINT_IN_CASE(MINT_CONV_OVF_I1_I4)
5714 if (sp [-1].data.i < G_MININT8 || sp [-1].data.i > G_MAXINT8)
5715 THROW_EX_OVF (ip);
5716 ++ip;
5717 MINT_IN_BREAK;
5718 MINT_IN_CASE(MINT_CONV_OVF_I1_U4)
5719 if (sp [-1].data.i < 0 || sp [-1].data.i > G_MAXINT8)
5720 THROW_EX_OVF (ip);
5721 ++ip;
5722 MINT_IN_BREAK;
5723 MINT_IN_CASE(MINT_CONV_OVF_I1_I8)
5724 if (sp [-1].data.l < G_MININT8 || sp [-1].data.l > G_MAXINT8)
5725 THROW_EX_OVF (ip);
5726 sp [-1].data.i = (gint8) sp [-1].data.l;
5727 ++ip;
5728 MINT_IN_BREAK;
5729 MINT_IN_CASE(MINT_CONV_OVF_I1_U8)
5730 if (sp [-1].data.l < 0 || sp [-1].data.l > G_MAXINT8)
5731 THROW_EX_OVF (ip);
5732 sp [-1].data.i = (gint8) sp [-1].data.l;
5733 ++ip;
5734 MINT_IN_BREAK;
5735 MINT_IN_CASE(MINT_CONV_OVF_I1_R8)
5736 if (sp [-1].data.f < G_MININT8 || sp [-1].data.f > G_MAXINT8)
5737 THROW_EX_OVF (ip);
5738 sp [-1].data.i = (gint8) sp [-1].data.f;
5739 ++ip;
5740 MINT_IN_BREAK;
5741 MINT_IN_CASE(MINT_CONV_OVF_I1_UN_R8)
5742 if (sp [-1].data.f < 0 || sp [-1].data.f > G_MAXINT8)
5743 THROW_EX_OVF (ip);
5744 sp [-1].data.i = (gint8) sp [-1].data.f;
5745 ++ip;
5746 MINT_IN_BREAK;
5747 MINT_IN_CASE(MINT_CONV_OVF_U1_I4)
5748 if (sp [-1].data.i < 0 || sp [-1].data.i > G_MAXUINT8)
5749 THROW_EX_OVF (ip);
5750 ++ip;
5751 MINT_IN_BREAK;
5752 MINT_IN_CASE(MINT_CONV_OVF_U1_I8)
5753 if (sp [-1].data.l < 0 || sp [-1].data.l > G_MAXUINT8)
5754 THROW_EX_OVF (ip);
5755 sp [-1].data.i = (guint8) sp [-1].data.l;
5756 ++ip;
5757 MINT_IN_BREAK;
5758 MINT_IN_CASE(MINT_CONV_OVF_U1_R8)
5759 if (sp [-1].data.f < 0 || sp [-1].data.f > G_MAXUINT8)
5760 THROW_EX_OVF (ip);
5761 sp [-1].data.i = (guint8) sp [-1].data.f;
5762 ++ip;
5763 MINT_IN_BREAK;
5764 MINT_IN_CASE(MINT_CKFINITE)
5765 if (!mono_isfinite (sp [-1].data.f))
5766 THROW_EX (mono_get_exception_arithmetic (), ip);
5767 ++ip;
5768 MINT_IN_BREAK;
5769 MINT_IN_CASE(MINT_MKREFANY) {
5770 MonoClass* const c = (MonoClass*)frame->imethod->data_items [*(guint16 *)(ip + 1)];
5772 /* The value address is on the stack */
5773 gpointer addr = sp [-1].data.p;
5774 /* Push the typedref value on the stack */
5775 sp [-1].data.p = vt_sp;
5776 vt_sp += ALIGN_TO (sizeof (MonoTypedRef), MINT_VT_ALIGNMENT);
5778 MonoTypedRef *tref = (MonoTypedRef*)sp [-1].data.p;
5779 tref->klass = c;
5780 tref->type = m_class_get_byval_arg (c);
5781 tref->value = addr;
5783 ip += 2;
5784 MINT_IN_BREAK;
5786 MINT_IN_CASE(MINT_REFANYTYPE) {
5787 MonoTypedRef *tref = (MonoTypedRef*)sp [-1].data.p;
5788 MonoType *type = tref->type;
5790 vt_sp -= ALIGN_TO (sizeof (MonoTypedRef), MINT_VT_ALIGNMENT);
5791 sp [-1].data.p = vt_sp;
5792 vt_sp += 8;
5793 *(gpointer*)sp [-1].data.p = type;
5794 ip ++;
5795 MINT_IN_BREAK;
5797 MINT_IN_CASE(MINT_REFANYVAL) {
5798 MonoTypedRef *tref = (MonoTypedRef*)sp [-1].data.p;
5799 gpointer addr = tref->value;
5801 MonoClass* const c = (MonoClass*)frame->imethod->data_items [*(guint16 *)(ip + 1)];
5802 if (c != tref->klass)
5803 THROW_EX (mono_get_exception_invalid_cast (), ip);
5805 vt_sp -= ALIGN_TO (sizeof (MonoTypedRef), MINT_VT_ALIGNMENT);
5807 sp [-1].data.p = addr;
5808 ip += 2;
5809 MINT_IN_BREAK;
5811 MINT_IN_CASE(MINT_LDTOKEN)
5812 sp->data.p = vt_sp;
5813 vt_sp += 8;
5814 * (gpointer *)sp->data.p = frame->imethod->data_items[*(guint16 *)(ip + 1)];
5815 ip += 2;
5816 ++sp;
5817 MINT_IN_BREAK;
5818 MINT_IN_CASE(MINT_ADD_OVF_I4)
5819 if (CHECK_ADD_OVERFLOW (sp [-2].data.i, sp [-1].data.i))
5820 THROW_EX_OVF (ip);
5821 BINOP(i, +);
5822 MINT_IN_BREAK;
5823 MINT_IN_CASE(MINT_ADD_OVF_I8)
5824 if (CHECK_ADD_OVERFLOW64 (sp [-2].data.l, sp [-1].data.l))
5825 THROW_EX_OVF (ip);
5826 BINOP(l, +);
5827 MINT_IN_BREAK;
5828 MINT_IN_CASE(MINT_ADD_OVF_UN_I4)
5829 if (CHECK_ADD_OVERFLOW_UN (sp [-2].data.i, sp [-1].data.i))
5830 THROW_EX_OVF (ip);
5831 BINOP_CAST(i, +, guint32);
5832 MINT_IN_BREAK;
5833 MINT_IN_CASE(MINT_ADD_OVF_UN_I8)
5834 if (CHECK_ADD_OVERFLOW64_UN (sp [-2].data.l, sp [-1].data.l))
5835 THROW_EX_OVF (ip);
5836 BINOP_CAST(l, +, guint64);
5837 MINT_IN_BREAK;
5838 MINT_IN_CASE(MINT_MUL_OVF_I4)
5839 if (CHECK_MUL_OVERFLOW (sp [-2].data.i, sp [-1].data.i))
5840 THROW_EX_OVF (ip);
5841 BINOP(i, *);
5842 MINT_IN_BREAK;
5843 MINT_IN_CASE(MINT_MUL_OVF_I8)
5844 if (CHECK_MUL_OVERFLOW64 (sp [-2].data.l, sp [-1].data.l))
5845 THROW_EX_OVF (ip);
5846 BINOP(l, *);
5847 MINT_IN_BREAK;
5848 MINT_IN_CASE(MINT_MUL_OVF_UN_I4)
5849 if (CHECK_MUL_OVERFLOW_UN (sp [-2].data.i, sp [-1].data.i))
5850 THROW_EX_OVF (ip);
5851 BINOP_CAST(i, *, guint32);
5852 MINT_IN_BREAK;
5853 MINT_IN_CASE(MINT_MUL_OVF_UN_I8)
5854 if (CHECK_MUL_OVERFLOW64_UN (sp [-2].data.l, sp [-1].data.l))
5855 THROW_EX_OVF (ip);
5856 BINOP_CAST(l, *, guint64);
5857 MINT_IN_BREAK;
5858 MINT_IN_CASE(MINT_SUB_OVF_I4)
5859 if (CHECK_SUB_OVERFLOW (sp [-2].data.i, sp [-1].data.i))
5860 THROW_EX_OVF (ip);
5861 BINOP(i, -);
5862 MINT_IN_BREAK;
5863 MINT_IN_CASE(MINT_SUB_OVF_I8)
5864 if (CHECK_SUB_OVERFLOW64 (sp [-2].data.l, sp [-1].data.l))
5865 THROW_EX_OVF (ip);
5866 BINOP(l, -);
5867 MINT_IN_BREAK;
5868 MINT_IN_CASE(MINT_SUB_OVF_UN_I4)
5869 if (CHECK_SUB_OVERFLOW_UN (sp [-2].data.i, sp [-1].data.i))
5870 THROW_EX_OVF (ip);
5871 BINOP_CAST(i, -, guint32);
5872 MINT_IN_BREAK;
5873 MINT_IN_CASE(MINT_SUB_OVF_UN_I8)
5874 if (CHECK_SUB_OVERFLOW64_UN (sp [-2].data.l, sp [-1].data.l))
5875 THROW_EX_OVF (ip);
5876 BINOP_CAST(l, -, guint64);
5877 MINT_IN_BREAK;
5878 MINT_IN_CASE(MINT_START_ABORT_PROT)
5879 mono_threads_begin_abort_protected_block ();
5880 ip ++;
5881 MINT_IN_BREAK;
5882 MINT_IN_CASE(MINT_ENDFINALLY) {
5883 ip ++;
5884 gboolean pending_abort = mono_threads_end_abort_protected_block ();
5886 // After mono_threads_end_abort_protected_block to conserve stack.
5887 const int clause_index = *ip;
5889 if (clause_args && clause_index == clause_args->exit_clause)
5890 goto exit_frame;
5892 g_assert (sp >= frame->stack);
5893 sp = frame->stack;
5895 if (finally_ips) {
5896 ip = (const guint16*)finally_ips->data;
5897 finally_ips = g_slist_remove (finally_ips, ip);
5898 /* Throw abort after the last finally block to avoid confusing EH */
5899 if (pending_abort && !finally_ips)
5900 EXCEPTION_CHECKPOINT;
5901 // goto main_loop instead of MINT_IN_DISPATCH helps the compiler and therefore conserves stack.
5902 // This is a slow/rare path and conserving stack is preferred over its performance otherwise.
5903 goto main_loop;
5905 ves_abort();
5906 MINT_IN_BREAK;
5909 MINT_IN_CASE(MINT_LEAVE)
5910 MINT_IN_CASE(MINT_LEAVE_S)
5911 MINT_IN_CASE(MINT_LEAVE_CHECK)
5912 MINT_IN_CASE(MINT_LEAVE_S_CHECK) {
5914 // Leave is split into pieces in order to consume less stack,
5915 // but not have to change how exception handling macros access labels and locals.
5917 g_assert (sp >= frame->stack);
5918 sp = frame->stack;
5919 frame->ip = ip;
5921 int opcode = *ip;
5922 gboolean const check = opcode == MINT_LEAVE_CHECK || opcode == MINT_LEAVE_S_CHECK;
5924 if (check && frame->imethod->method->wrapper_type != MONO_WRAPPER_RUNTIME_INVOKE) {
5925 child_frame.parent = frame;
5926 child_frame.imethod = NULL;
5927 MonoException *abort_exc = mono_interp_leave (&child_frame);
5928 if (abort_exc)
5929 THROW_EX (abort_exc, frame->ip);
5932 opcode = *ip; // Refetch to avoid register/stack pressure.
5933 gboolean const short_offset = opcode == MINT_LEAVE_S || opcode == MINT_LEAVE_S_CHECK;
5934 ip += short_offset ? (short)*(ip + 1) : (gint32)READ32 (ip + 1);
5935 endfinally_ip = ip;
5936 GSList *old_list = finally_ips;
5937 MonoMethod *method = frame->imethod->method;
5938 #if DEBUG_INTERP
5939 if (tracing)
5940 g_print ("* Handle finally IL_%04x\n", endfinally_ip == NULL ? 0 : endfinally_ip - frame->imethod->code);
5941 #endif
5942 // FIXME Null check for frame->imethod follows deref.
5943 if (frame->imethod == NULL || (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
5944 || (method->iflags & (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL | METHOD_IMPL_ATTRIBUTE_RUNTIME))) {
5945 goto exit_frame;
5947 guint32 const ip_offset = frame->ip - frame->imethod->code;
5949 if (endfinally_ip != NULL)
5950 finally_ips = g_slist_prepend (finally_ips, (void *)endfinally_ip);
5952 for (int i = frame->imethod->num_clauses - 1; i >= 0; i--) {
5953 MonoExceptionClause* const clause = &frame->imethod->clauses [i];
5954 if (MONO_OFFSET_IN_CLAUSE (clause, ip_offset) && (endfinally_ip == NULL || !(MONO_OFFSET_IN_CLAUSE (clause, endfinally_ip - frame->imethod->code)))) {
5955 if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY) {
5956 ip = frame->imethod->code + clause->handler_offset;
5957 finally_ips = g_slist_prepend (finally_ips, (gpointer) ip);
5958 #if DEBUG_INTERP
5959 if (tracing)
5960 g_print ("* Found finally at IL_%04x with exception: %s\n", clause->handler_offset, frame->ex? "yes": "no");
5961 #endif
5966 endfinally_ip = NULL;
5968 if (old_list != finally_ips && finally_ips) {
5969 ip = (const guint16*)finally_ips->data;
5970 finally_ips = g_slist_remove (finally_ips, ip);
5971 sp = frame->stack; /* spec says stack should be empty at endfinally so it should be at the start too */
5972 vt_sp = (unsigned char *) sp + frame->imethod->stack_size;
5973 // goto main_loop instead of MINT_IN_DISPATCH helps the compiler and therefore conserves stack.
5974 // This is a slow/rare path and conserving stack is preferred over its performance otherwise.
5975 goto main_loop;
5978 ves_abort();
5979 MINT_IN_BREAK;
5981 MINT_IN_CASE(MINT_ICALL_V_V)
5982 MINT_IN_CASE(MINT_ICALL_V_P)
5983 MINT_IN_CASE(MINT_ICALL_P_V)
5984 MINT_IN_CASE(MINT_ICALL_P_P)
5985 MINT_IN_CASE(MINT_ICALL_PP_V)
5986 MINT_IN_CASE(MINT_ICALL_PP_P)
5987 MINT_IN_CASE(MINT_ICALL_PPP_V)
5988 MINT_IN_CASE(MINT_ICALL_PPP_P)
5989 MINT_IN_CASE(MINT_ICALL_PPPP_V)
5990 MINT_IN_CASE(MINT_ICALL_PPPP_P)
5991 MINT_IN_CASE(MINT_ICALL_PPPPP_V)
5992 MINT_IN_CASE(MINT_ICALL_PPPPP_P)
5993 MINT_IN_CASE(MINT_ICALL_PPPPPP_V)
5994 MINT_IN_CASE(MINT_ICALL_PPPPPP_P)
5995 frame->ip = ip;
5996 sp = do_icall_wrapper (frame, NULL, *ip, sp, frame->imethod->data_items [*(guint16 *)(ip + 1)], FALSE);
5997 EXCEPTION_CHECKPOINT;
5998 CHECK_RESUME_STATE (context);
5999 ip += 2;
6000 MINT_IN_BREAK;
6001 MINT_IN_CASE(MINT_MONO_LDPTR)
6002 sp->data.p = frame->imethod->data_items [*(guint16 *)(ip + 1)];
6003 ip += 2;
6004 ++sp;
6005 MINT_IN_BREAK;
6006 MINT_IN_CASE(MINT_MONO_NEWOBJ)
6007 sp->data.o = mono_interp_new (frame->imethod->domain, (MonoClass*)frame->imethod->data_items [*(guint16 *)(ip + 1)]); // FIXME: do not swallow the error
6008 ip += 2;
6009 sp++;
6010 MINT_IN_BREAK;
6011 MINT_IN_CASE(MINT_MONO_FREE)
6012 ++ip;
6013 --sp;
6014 g_error ("that doesn't seem right");
6015 g_free (sp->data.p);
6016 MINT_IN_BREAK;
6017 MINT_IN_CASE(MINT_MONO_RETOBJ)
6018 ++ip;
6019 sp--;
6020 stackval_from_data (mono_method_signature_internal (frame->imethod->method)->ret, frame->retval, sp->data.p,
6021 mono_method_signature_internal (frame->imethod->method)->pinvoke);
6022 if (sp > frame->stack)
6023 g_warning ("retobj: more values on stack: %d", sp-frame->stack);
6024 goto exit_frame;
6025 MINT_IN_CASE(MINT_MONO_SGEN_THREAD_INFO)
6026 sp->data.p = mono_tls_get_sgen_thread_info ();
6027 sp++;
6028 ++ip;
6029 MINT_IN_BREAK;
6030 MINT_IN_CASE(MINT_MONO_MEMORY_BARRIER) {
6031 ++ip;
6032 mono_memory_barrier ();
6033 MINT_IN_BREAK;
6035 MINT_IN_CASE(MINT_MONO_LDDOMAIN)
6036 sp->data.p = mono_domain_get ();
6037 ++sp;
6038 ++ip;
6039 MINT_IN_BREAK;
6040 MINT_IN_CASE(MINT_SDB_INTR_LOC)
6041 if (G_UNLIKELY (ss_enabled)) {
6042 typedef void (*T) (void);
6043 static T ss_tramp;
6045 if (!ss_tramp) {
6046 void *tramp = mini_get_single_step_trampoline ();
6047 mono_memory_barrier ();
6048 ss_tramp = (T)tramp;
6052 * Make this point to the MINT_SDB_SEQ_POINT instruction which follows this since
6053 * the address of that instruction is stored as the seq point address.
6055 frame->ip = ip + 1;
6058 * Use the same trampoline as the JIT. This ensures that
6059 * the debugger has the context for the last interpreter
6060 * native frame.
6062 do_debugger_tramp (ss_tramp, frame);
6064 CHECK_RESUME_STATE (context);
6066 ++ip;
6067 MINT_IN_BREAK;
6068 MINT_IN_CASE(MINT_SDB_SEQ_POINT)
6069 /* Just a placeholder for a breakpoint */
6070 ++ip;
6071 MINT_IN_BREAK;
6072 MINT_IN_CASE(MINT_SDB_BREAKPOINT) {
6073 typedef void (*T) (void);
6074 static T bp_tramp;
6075 if (!bp_tramp) {
6076 void *tramp = mini_get_breakpoint_trampoline ();
6077 mono_memory_barrier ();
6078 bp_tramp = (T)tramp;
6081 frame->ip = ip;
6083 /* Use the same trampoline as the JIT */
6084 do_debugger_tramp (bp_tramp, frame);
6086 CHECK_RESUME_STATE (context);
6088 ++ip;
6089 MINT_IN_BREAK;
6092 #define RELOP(datamem, op) \
6093 --sp; \
6094 sp [-1].data.i = sp [-1].data.datamem op sp [0].data.datamem; \
6095 ++ip;
6097 #define RELOP_FP(datamem, op, noorder) \
6098 --sp; \
6099 if (mono_isunordered (sp [-1].data.datamem, sp [0].data.datamem)) \
6100 sp [-1].data.i = noorder; \
6101 else \
6102 sp [-1].data.i = sp [-1].data.datamem op sp [0].data.datamem; \
6103 ++ip;
6105 MINT_IN_CASE(MINT_CEQ_I4)
6106 RELOP(i, ==);
6107 MINT_IN_BREAK;
6108 MINT_IN_CASE(MINT_CEQ0_I4)
6109 sp [-1].data.i = (sp [-1].data.i == 0);
6110 ++ip;
6111 MINT_IN_BREAK;
6112 MINT_IN_CASE(MINT_CEQ_I8)
6113 RELOP(l, ==);
6114 MINT_IN_BREAK;
6115 MINT_IN_CASE(MINT_CEQ_R4)
6116 RELOP_FP(f_r4, ==, 0);
6117 MINT_IN_BREAK;
6118 MINT_IN_CASE(MINT_CEQ_R8)
6119 RELOP_FP(f, ==, 0);
6120 MINT_IN_BREAK;
6121 MINT_IN_CASE(MINT_CNE_I4)
6122 RELOP(i, !=);
6123 MINT_IN_BREAK;
6124 MINT_IN_CASE(MINT_CNE_I8)
6125 RELOP(l, !=);
6126 MINT_IN_BREAK;
6127 MINT_IN_CASE(MINT_CNE_R4)
6128 RELOP_FP(f_r4, !=, 1);
6129 MINT_IN_BREAK;
6130 MINT_IN_CASE(MINT_CNE_R8)
6131 RELOP_FP(f, !=, 1);
6132 MINT_IN_BREAK;
6133 MINT_IN_CASE(MINT_CGT_I4)
6134 RELOP(i, >);
6135 MINT_IN_BREAK;
6136 MINT_IN_CASE(MINT_CGT_I8)
6137 RELOP(l, >);
6138 MINT_IN_BREAK;
6139 MINT_IN_CASE(MINT_CGT_R4)
6140 RELOP_FP(f_r4, >, 0);
6141 MINT_IN_BREAK;
6142 MINT_IN_CASE(MINT_CGT_R8)
6143 RELOP_FP(f, >, 0);
6144 MINT_IN_BREAK;
6145 MINT_IN_CASE(MINT_CGE_I4)
6146 RELOP(i, >=);
6147 MINT_IN_BREAK;
6148 MINT_IN_CASE(MINT_CGE_I8)
6149 RELOP(l, >=);
6150 MINT_IN_BREAK;
6151 MINT_IN_CASE(MINT_CGE_R4)
6152 RELOP_FP(f_r4, >=, 0);
6153 MINT_IN_BREAK;
6154 MINT_IN_CASE(MINT_CGE_R8)
6155 RELOP_FP(f, >=, 0);
6156 MINT_IN_BREAK;
6158 #define RELOP_CAST(datamem, op, type) \
6159 --sp; \
6160 sp [-1].data.i = (type)sp [-1].data.datamem op (type)sp [0].data.datamem; \
6161 ++ip;
6163 MINT_IN_CASE(MINT_CGE_UN_I4)
6164 RELOP_CAST(l, >=, guint32);
6165 MINT_IN_BREAK;
6166 MINT_IN_CASE(MINT_CGE_UN_I8)
6167 RELOP_CAST(l, >=, guint64);
6168 MINT_IN_BREAK;
6170 MINT_IN_CASE(MINT_CGT_UN_I4)
6171 RELOP_CAST(i, >, guint32);
6172 MINT_IN_BREAK;
6173 MINT_IN_CASE(MINT_CGT_UN_I8)
6174 RELOP_CAST(l, >, guint64);
6175 MINT_IN_BREAK;
6176 MINT_IN_CASE(MINT_CGT_UN_R4)
6177 RELOP_FP(f_r4, >, 1);
6178 MINT_IN_BREAK;
6179 MINT_IN_CASE(MINT_CGT_UN_R8)
6180 RELOP_FP(f, >, 1);
6181 MINT_IN_BREAK;
6182 MINT_IN_CASE(MINT_CLT_I4)
6183 RELOP(i, <);
6184 MINT_IN_BREAK;
6185 MINT_IN_CASE(MINT_CLT_I8)
6186 RELOP(l, <);
6187 MINT_IN_BREAK;
6188 MINT_IN_CASE(MINT_CLT_R4)
6189 RELOP_FP(f_r4, <, 0);
6190 MINT_IN_BREAK;
6191 MINT_IN_CASE(MINT_CLT_R8)
6192 RELOP_FP(f, <, 0);
6193 MINT_IN_BREAK;
6194 MINT_IN_CASE(MINT_CLT_UN_I4)
6195 RELOP_CAST(i, <, guint32);
6196 MINT_IN_BREAK;
6197 MINT_IN_CASE(MINT_CLT_UN_I8)
6198 RELOP_CAST(l, <, guint64);
6199 MINT_IN_BREAK;
6200 MINT_IN_CASE(MINT_CLT_UN_R4)
6201 RELOP_FP(f_r4, <, 1);
6202 MINT_IN_BREAK;
6203 MINT_IN_CASE(MINT_CLT_UN_R8)
6204 RELOP_FP(f, <, 1);
6205 MINT_IN_BREAK;
6206 MINT_IN_CASE(MINT_CLE_I4)
6207 RELOP(i, <=);
6208 MINT_IN_BREAK;
6209 MINT_IN_CASE(MINT_CLE_I8)
6210 RELOP(l, <=);
6211 MINT_IN_BREAK;
6212 MINT_IN_CASE(MINT_CLE_UN_I4)
6213 RELOP_CAST(l, <=, guint32);
6214 MINT_IN_BREAK;
6215 MINT_IN_CASE(MINT_CLE_UN_I8)
6216 RELOP_CAST(l, <=, guint64);
6217 MINT_IN_BREAK;
6218 MINT_IN_CASE(MINT_CLE_R4)
6219 RELOP_FP(f_r4, <=, 0);
6220 MINT_IN_BREAK;
6221 MINT_IN_CASE(MINT_CLE_R8)
6222 RELOP_FP(f, <=, 0);
6223 MINT_IN_BREAK;
6225 #undef RELOP
6226 #undef RELOP_FP
6227 #undef RELOP_CAST
6229 MINT_IN_CASE(MINT_LDFTN) {
6230 sp->data.p = frame->imethod->data_items [* (guint16 *)(ip + 1)];
6231 ++sp;
6232 ip += 2;
6233 MINT_IN_BREAK;
6235 MINT_IN_CASE(MINT_LDVIRTFTN) {
6236 InterpMethod *m = (InterpMethod*)frame->imethod->data_items [* (guint16 *)(ip + 1)];
6237 --sp;
6238 NULL_CHECK (sp->data.p);
6240 sp->data.p = get_virtual_method (m, sp->data.o->vtable);
6241 ip += 2;
6242 ++sp;
6243 MINT_IN_BREAK;
6245 MINT_IN_CASE(MINT_LDFTN_DYNAMIC) {
6246 MONO_API_ERROR_INIT (error);
6247 InterpMethod *m = mono_interp_get_imethod (mono_domain_get (), (MonoMethod*) sp [-1].data.p, error);
6248 mono_error_assert_ok (error);
6249 sp [-1].data.p = m;
6250 ip++;
6251 MINT_IN_BREAK;
6254 #define LDARG(datamem, argtype) \
6255 sp->data.datamem = (argtype) frame->stack_args [*(guint16 *)(ip + 1)].data.datamem; \
6256 ip += 2; \
6257 ++sp;
6259 MINT_IN_CASE(MINT_LDARG_I1) LDARG(i, gint8); MINT_IN_BREAK;
6260 MINT_IN_CASE(MINT_LDARG_U1) LDARG(i, guint8); MINT_IN_BREAK;
6261 MINT_IN_CASE(MINT_LDARG_I2) LDARG(i, gint16); MINT_IN_BREAK;
6262 MINT_IN_CASE(MINT_LDARG_U2) LDARG(i, guint16); MINT_IN_BREAK;
6263 MINT_IN_CASE(MINT_LDARG_I4) LDARG(i, gint32); MINT_IN_BREAK;
6264 MINT_IN_CASE(MINT_LDARG_I8) LDARG(l, gint64); MINT_IN_BREAK;
6265 MINT_IN_CASE(MINT_LDARG_R4) LDARG(f_r4, float); MINT_IN_BREAK;
6266 MINT_IN_CASE(MINT_LDARG_R8) LDARG(f, double); MINT_IN_BREAK;
6267 MINT_IN_CASE(MINT_LDARG_O) LDARG(p, gpointer); MINT_IN_BREAK;
6268 MINT_IN_CASE(MINT_LDARG_P) LDARG(p, gpointer); MINT_IN_BREAK;
6270 MINT_IN_CASE(MINT_LDARG_VT) {
6271 sp->data.p = vt_sp;
6272 int const i32 = READ32 (ip + 2);
6273 memcpy(sp->data.p, frame->stack_args [* (guint16 *)(ip + 1)].data.p, i32);
6274 vt_sp += ALIGN_TO (i32, MINT_VT_ALIGNMENT);
6275 ip += 4;
6276 ++sp;
6277 MINT_IN_BREAK;
6280 #define STARG(datamem, argtype) \
6281 --sp; \
6282 frame->stack_args [*(guint16 *)(ip + 1)].data.datamem = (argtype) sp->data.datamem; \
6283 ip += 2; \
6285 MINT_IN_CASE(MINT_STARG_I1) STARG(i, gint8); MINT_IN_BREAK;
6286 MINT_IN_CASE(MINT_STARG_U1) STARG(i, guint8); MINT_IN_BREAK;
6287 MINT_IN_CASE(MINT_STARG_I2) STARG(i, gint16); MINT_IN_BREAK;
6288 MINT_IN_CASE(MINT_STARG_U2) STARG(i, guint16); MINT_IN_BREAK;
6289 MINT_IN_CASE(MINT_STARG_I4) STARG(i, gint32); MINT_IN_BREAK;
6290 MINT_IN_CASE(MINT_STARG_I8) STARG(l, gint64); MINT_IN_BREAK;
6291 MINT_IN_CASE(MINT_STARG_R4) STARG(f_r4, float); MINT_IN_BREAK;
6292 MINT_IN_CASE(MINT_STARG_R8) STARG(f, double); MINT_IN_BREAK;
6293 MINT_IN_CASE(MINT_STARG_O) STARG(p, gpointer); MINT_IN_BREAK;
6294 MINT_IN_CASE(MINT_STARG_P) STARG(p, gpointer); MINT_IN_BREAK;
6296 MINT_IN_CASE(MINT_STARG_VT) {
6297 int const i32 = READ32 (ip + 2);
6298 --sp;
6299 memcpy(frame->stack_args [* (guint16 *)(ip + 1)].data.p, sp->data.p, i32);
6300 vt_sp -= ALIGN_TO (i32, MINT_VT_ALIGNMENT);
6301 ip += 4;
6302 MINT_IN_BREAK;
6304 MINT_IN_CASE(MINT_PROF_ENTER) {
6305 ip += 1;
6307 if (MONO_PROFILER_ENABLED (method_enter)) {
6308 MonoProfilerCallContext *prof_ctx = NULL;
6310 if (frame->imethod->prof_flags & MONO_PROFILER_CALL_INSTRUMENTATION_ENTER_CONTEXT) {
6311 prof_ctx = g_new0 (MonoProfilerCallContext, 1);
6312 prof_ctx->interp_frame = frame;
6313 prof_ctx->method = frame->imethod->method;
6316 MONO_PROFILER_RAISE (method_enter, (frame->imethod->method, prof_ctx));
6318 g_free (prof_ctx);
6321 MINT_IN_BREAK;
6324 MINT_IN_CASE(MINT_TRACE_ENTER) {
6325 ip += 1;
6327 MonoProfilerCallContext *prof_ctx = g_alloca (sizeof (MonoProfilerCallContext));
6328 prof_ctx->interp_frame = frame;
6329 prof_ctx->method = frame->imethod->method;
6331 mono_trace_enter_method (frame->imethod->method, prof_ctx);
6332 MINT_IN_BREAK;
6335 MINT_IN_CASE(MINT_TRACE_EXIT) {
6336 // Set retval
6337 int const i32 = READ32 (ip + 1);
6338 --sp;
6339 if (i32 == -1)
6341 else if (i32)
6342 memcpy(frame->retval->data.p, sp->data.p, i32);
6343 else
6344 *frame->retval = *sp;
6346 MonoProfilerCallContext *prof_ctx = g_alloca (sizeof (MonoProfilerCallContext));
6347 prof_ctx->interp_frame = frame;
6348 prof_ctx->method = frame->imethod->method;
6350 mono_trace_leave_method (frame->imethod->method, prof_ctx);
6351 ip += 3;
6352 goto exit_frame;
6355 MINT_IN_CASE(MINT_LDARGA)
6356 sp->data.p = &frame->stack_args [* (guint16 *)(ip + 1)];
6357 ip += 2;
6358 ++sp;
6359 MINT_IN_BREAK;
6361 MINT_IN_CASE(MINT_LDARGA_VT)
6362 sp->data.p = frame->stack_args [* (guint16 *)(ip + 1)].data.p;
6363 ip += 2;
6364 ++sp;
6365 MINT_IN_BREAK;
6367 #define LDLOC(datamem, argtype) \
6368 sp->data.datamem = * (argtype *)(locals + * (guint16 *)(ip + 1)); \
6369 ip += 2; \
6370 ++sp;
6372 MINT_IN_CASE(MINT_LDLOC_I1) LDLOC(i, gint8); MINT_IN_BREAK;
6373 MINT_IN_CASE(MINT_LDLOC_U1) LDLOC(i, guint8); MINT_IN_BREAK;
6374 MINT_IN_CASE(MINT_LDLOC_I2) LDLOC(i, gint16); MINT_IN_BREAK;
6375 MINT_IN_CASE(MINT_LDLOC_U2) LDLOC(i, guint16); MINT_IN_BREAK;
6376 MINT_IN_CASE(MINT_LDLOC_I4) LDLOC(i, gint32); MINT_IN_BREAK;
6377 MINT_IN_CASE(MINT_LDLOC_I8) LDLOC(l, gint64); MINT_IN_BREAK;
6378 MINT_IN_CASE(MINT_LDLOC_R4) LDLOC(f_r4, float); MINT_IN_BREAK;
6379 MINT_IN_CASE(MINT_LDLOC_R8) LDLOC(f, double); MINT_IN_BREAK;
6380 MINT_IN_CASE(MINT_LDLOC_O) LDLOC(p, gpointer); MINT_IN_BREAK;
6381 MINT_IN_CASE(MINT_LDLOC_P) LDLOC(p, gpointer); MINT_IN_BREAK;
6383 MINT_IN_CASE(MINT_LDLOC_VT) {
6384 sp->data.p = vt_sp;
6385 int const i32 = READ32 (ip + 2);
6386 memcpy(sp->data.p, locals + * (guint16 *)(ip + 1), i32);
6387 vt_sp += ALIGN_TO (i32, MINT_VT_ALIGNMENT);
6388 ip += 4;
6389 ++sp;
6390 MINT_IN_BREAK;
6392 MINT_IN_CASE(MINT_LDLOCA_S)
6393 sp->data.p = locals + * (guint16 *)(ip + 1);
6394 ip += 2;
6395 ++sp;
6396 MINT_IN_BREAK;
6398 #define STLOC(datamem, argtype) \
6399 --sp; \
6400 * (argtype *)(locals + * (guint16 *)(ip + 1)) = sp->data.datamem; \
6401 ip += 2;
6403 MINT_IN_CASE(MINT_STLOC_I1) STLOC(i, gint8); MINT_IN_BREAK;
6404 MINT_IN_CASE(MINT_STLOC_U1) STLOC(i, guint8); MINT_IN_BREAK;
6405 MINT_IN_CASE(MINT_STLOC_I2) STLOC(i, gint16); MINT_IN_BREAK;
6406 MINT_IN_CASE(MINT_STLOC_U2) STLOC(i, guint16); MINT_IN_BREAK;
6407 MINT_IN_CASE(MINT_STLOC_I4) STLOC(i, gint32); MINT_IN_BREAK;
6408 MINT_IN_CASE(MINT_STLOC_I8) STLOC(l, gint64); MINT_IN_BREAK;
6409 MINT_IN_CASE(MINT_STLOC_R4) STLOC(f_r4, float); MINT_IN_BREAK;
6410 MINT_IN_CASE(MINT_STLOC_R8) STLOC(f, double); MINT_IN_BREAK;
6411 MINT_IN_CASE(MINT_STLOC_O) STLOC(p, gpointer); MINT_IN_BREAK;
6412 MINT_IN_CASE(MINT_STLOC_P) STLOC(p, gpointer); MINT_IN_BREAK;
6414 #define STLOC_NP(datamem, argtype) \
6415 * (argtype *)(locals + * (guint16 *)(ip + 1)) = sp [-1].data.datamem; \
6416 ip += 2;
6418 MINT_IN_CASE(MINT_STLOC_NP_I4) STLOC_NP(i, gint32); MINT_IN_BREAK;
6419 MINT_IN_CASE(MINT_STLOC_NP_O) STLOC_NP(p, gpointer); MINT_IN_BREAK;
6421 MINT_IN_CASE(MINT_STLOC_VT) {
6422 int const i32 = READ32 (ip + 2);
6423 --sp;
6424 memcpy(locals + * (guint16 *)(ip + 1), sp->data.p, i32);
6425 vt_sp -= ALIGN_TO (i32, MINT_VT_ALIGNMENT);
6426 ip += 4;
6427 MINT_IN_BREAK;
6429 MINT_IN_CASE(MINT_LOCALLOC) {
6430 if (sp != frame->stack + 1) /*FIX?*/
6431 THROW_EX (mono_get_exception_execution_engine (NULL), ip);
6433 int len = sp [-1].data.i;
6434 sp [-1].data.p = alloca (len);
6436 if (frame->imethod->init_locals)
6437 memset (sp [-1].data.p, 0, len);
6438 ++ip;
6439 MINT_IN_BREAK;
6441 MINT_IN_CASE(MINT_ENDFILTER)
6442 /* top of stack is result of filter */
6443 frame->retval = &sp [-1];
6444 goto exit_frame;
6445 MINT_IN_CASE(MINT_INITOBJ)
6446 --sp;
6447 memset (sp->data.vt, 0, READ32(ip + 1));
6448 ip += 3;
6449 MINT_IN_BREAK;
6450 MINT_IN_CASE(MINT_CPBLK)
6451 sp -= 3;
6452 if (!sp [0].data.p || !sp [1].data.p)
6453 THROW_EX (mono_get_exception_null_reference(), ip - 1);
6454 ++ip;
6455 /* FIXME: value and size may be int64... */
6456 memcpy (sp [0].data.p, sp [1].data.p, sp [2].data.i);
6457 MINT_IN_BREAK;
6458 #if 0
6459 MINT_IN_CASE(MINT_CONSTRAINED_) {
6460 guint32 token;
6461 /* FIXME: implement */
6462 ++ip;
6463 token = READ32 (ip);
6464 ip += 2;
6465 MINT_IN_BREAK;
6467 #endif
6468 MINT_IN_CASE(MINT_INITBLK)
6469 sp -= 3;
6470 NULL_CHECK (sp [0].data.p);
6471 ++ip;
6472 /* FIXME: value and size may be int64... */
6473 memset (sp [0].data.p, sp [1].data.i, sp [2].data.i);
6474 MINT_IN_BREAK;
6475 #if 0
6476 MINT_IN_CASE(MINT_NO_)
6477 /* FIXME: implement */
6478 ip += 2;
6479 MINT_IN_BREAK;
6480 #endif
6481 MINT_IN_CASE(MINT_RETHROW) {
6482 int exvar_offset = *(guint16*)(ip + 1);
6483 THROW_EX_GENERAL (*(MonoException**)(frame_locals (frame) + exvar_offset), ip, TRUE);
6484 MINT_IN_BREAK;
6486 MINT_IN_CASE(MINT_MONO_RETHROW) {
6488 * need to clarify what this should actually do:
6490 * Takes an exception from the stack and rethrows it.
6491 * This is useful for wrappers that don't want to have to
6492 * use CEE_THROW and lose the exception stacktrace.
6495 --sp;
6496 if (!sp->data.p)
6497 sp->data.p = mono_get_exception_null_reference ();
6499 THROW_EX_GENERAL ((MonoException *)sp->data.p, ip, TRUE);
6500 MINT_IN_BREAK;
6502 MINT_IN_CASE(MINT_LD_DELEGATE_METHOD_PTR) {
6503 MonoDelegate *del;
6505 --sp;
6506 del = (MonoDelegate*)sp->data.p;
6507 if (!del->interp_method) {
6508 /* Not created from interpreted code */
6509 MONO_API_ERROR_INIT (error);
6510 g_assert (del->method);
6511 del->interp_method = mono_interp_get_imethod (del->object.vtable->domain, del->method, error);
6512 mono_error_assert_ok (error);
6514 g_assert (del->interp_method);
6515 sp->data.p = del->interp_method;
6516 ++sp;
6517 ip += 1;
6518 MINT_IN_BREAK;
6520 MINT_IN_CASE(MINT_LD_DELEGATE_INVOKE_IMPL) {
6521 MonoDelegate *del;
6522 int n = *(guint16*)(ip + 1);
6523 del = (MonoDelegate*)sp [-n].data.p;
6524 if (!del->interp_invoke_impl) {
6526 * First time we are called. Set up the invoke wrapper. We might be able to do this
6527 * in ctor but we would need to handle AllocDelegateLike_internal separately
6529 MONO_API_ERROR_INIT (error);
6530 MonoMethod *invoke = mono_get_delegate_invoke_internal (del->object.vtable->klass);
6531 del->interp_invoke_impl = mono_interp_get_imethod (del->object.vtable->domain, mono_marshal_get_delegate_invoke (invoke, del), error);
6532 mono_error_assert_ok (error);
6534 sp ++;
6535 sp [-1].data.p = del->interp_invoke_impl;
6536 ip += 2;
6537 MINT_IN_BREAK;
6540 #define MATH_UNOP(mathfunc) \
6541 sp [-1].data.f = mathfunc (sp [-1].data.f); \
6542 ++ip;
6544 MINT_IN_CASE(MINT_ABS) MATH_UNOP(fabs); MINT_IN_BREAK;
6545 MINT_IN_CASE(MINT_ASIN) MATH_UNOP(asin); MINT_IN_BREAK;
6546 MINT_IN_CASE(MINT_ASINH) MATH_UNOP(asinh); MINT_IN_BREAK;
6547 MINT_IN_CASE(MINT_ACOS) MATH_UNOP(acos); MINT_IN_BREAK;
6548 MINT_IN_CASE(MINT_ACOSH) MATH_UNOP(acosh); MINT_IN_BREAK;
6549 MINT_IN_CASE(MINT_ATAN) MATH_UNOP(atan); MINT_IN_BREAK;
6550 MINT_IN_CASE(MINT_ATANH) MATH_UNOP(atanh); MINT_IN_BREAK;
6551 MINT_IN_CASE(MINT_COS) MATH_UNOP(cos); MINT_IN_BREAK;
6552 MINT_IN_CASE(MINT_CBRT) MATH_UNOP(cbrt); MINT_IN_BREAK;
6553 MINT_IN_CASE(MINT_COSH) MATH_UNOP(cosh); MINT_IN_BREAK;
6554 MINT_IN_CASE(MINT_SIN) MATH_UNOP(sin); MINT_IN_BREAK;
6555 MINT_IN_CASE(MINT_SQRT) MATH_UNOP(sqrt); MINT_IN_BREAK;
6556 MINT_IN_CASE(MINT_SINH) MATH_UNOP(sinh); MINT_IN_BREAK;
6557 MINT_IN_CASE(MINT_TAN) MATH_UNOP(tan); MINT_IN_BREAK;
6558 MINT_IN_CASE(MINT_TANH) MATH_UNOP(tanh); MINT_IN_BREAK;
6560 MINT_IN_CASE(MINT_INTRINS_ENUM_HASFLAG) {
6561 MonoClass *klass = (MonoClass*)frame->imethod->data_items[* (guint16 *)(ip + 1)];
6562 mono_interp_enum_hasflag (sp, klass);
6563 sp--;
6564 ip += 2;
6565 MINT_IN_BREAK;
6567 MINT_IN_CASE(MINT_INTRINS_GET_HASHCODE) {
6568 sp [-1].data.i = mono_object_hash_internal (sp [-1].data.o);
6569 ip++;
6570 MINT_IN_BREAK;
6572 MINT_IN_CASE(MINT_INTRINS_GET_TYPE) {
6573 NULL_CHECK (sp [-1].data.p);
6574 sp [-1].data.o = (MonoObject*) sp [-1].data.o->vtable->type;
6575 ip++;
6576 MINT_IN_BREAK;
6579 MINT_IN_DEFAULT
6580 g_error ("Unimplemented opcode: %04x %s at 0x%x\n", *ip, mono_interp_opname[*ip], ip-frame->imethod->code);
6584 g_assert_not_reached ();
6586 resume:
6587 g_assert (context->has_resume_state);
6589 if (frame == context->handler_frame && (!clause_args || context->handler_ip < clause_args->end_at_ip)) {
6590 /* Set the current execution state to the resume state in context */
6592 ip = context->handler_ip;
6593 /* spec says stack should be empty at endfinally so it should be at the start too */
6594 sp = frame->stack;
6595 vt_sp = (guchar*)sp + frame->imethod->stack_size;
6596 if (frame->ex) {
6597 sp->data.p = frame->ex;
6598 ++sp;
6601 // FIXME Reevaluate if this should be inlined.
6602 finally_ips = set_resume_state (context, frame, finally_ips);
6603 // goto main_loop instead of MINT_IN_DISPATCH helps the compiler and therefore conserves stack.
6604 // This is a slow/rare path and conserving stack is preferred over its performance otherwise.
6606 goto main_loop;
6608 // fall through
6609 exit_frame:
6610 error_init_reuse (error);
6612 if (clause_args && clause_args->base_frame)
6613 memcpy (clause_args->base_frame->stack, frame->stack, frame->imethod->alloca_size);
6615 if (!frame->ex && MONO_PROFILER_ENABLED (method_leave) &&
6616 frame->imethod->prof_flags & MONO_PROFILER_CALL_INSTRUMENTATION_LEAVE) {
6617 MonoProfilerCallContext *prof_ctx = NULL;
6619 if (frame->imethod->prof_flags & MONO_PROFILER_CALL_INSTRUMENTATION_LEAVE_CONTEXT) {
6620 prof_ctx = g_new0 (MonoProfilerCallContext, 1);
6621 prof_ctx->interp_frame = frame;
6622 prof_ctx->method = frame->imethod->method;
6624 MonoType *rtype = mono_method_signature_internal (frame->imethod->method)->ret;
6626 switch (rtype->type) {
6627 case MONO_TYPE_VOID:
6628 break;
6629 case MONO_TYPE_VALUETYPE:
6630 prof_ctx->return_value = frame->retval->data.p;
6631 break;
6632 default:
6633 prof_ctx->return_value = frame->retval;
6634 break;
6638 MONO_PROFILER_RAISE (method_leave, (frame->imethod->method, prof_ctx));
6640 g_free (prof_ctx);
6641 } else if (frame->ex && frame->imethod->prof_flags & MONO_PROFILER_CALL_INSTRUMENTATION_EXCEPTION_LEAVE)
6642 MONO_PROFILER_RAISE (method_exception_leave, (frame->imethod->method, &frame->ex->object));
6644 DEBUG_LEAVE ();
6647 static void
6648 interp_parse_options (const char *options)
6650 char **args, **ptr;
6652 if (!options)
6653 return;
6655 args = g_strsplit (options, ",", -1);
6656 for (ptr = args; ptr && *ptr; ptr ++) {
6657 char *arg = *ptr;
6659 if (strncmp (arg, "jit=", 4) == 0)
6660 mono_interp_jit_classes = g_slist_prepend (mono_interp_jit_classes, arg + 4);
6661 if (strncmp (arg, "interp-only=", 4) == 0)
6662 mono_interp_only_classes = g_slist_prepend (mono_interp_only_classes, arg + strlen ("interp-only="));
6663 if (strncmp (arg, "-inline", 7) == 0)
6664 mono_interp_opt &= ~INTERP_OPT_INLINE;
6669 * interp_set_resume_state:
6671 * Set the state the interpeter will continue to execute from after execution returns to the interpreter.
6673 static void
6674 interp_set_resume_state (MonoJitTlsData *jit_tls, MonoException *ex, MonoJitExceptionInfo *ei, MonoInterpFrameHandle interp_frame, gpointer handler_ip)
6676 ThreadContext *context;
6678 g_assert (jit_tls);
6679 context = (ThreadContext*)jit_tls->interp_context;
6680 g_assert (context);
6682 context->has_resume_state = TRUE;
6683 context->handler_frame = (InterpFrame*)interp_frame;
6684 context->handler_ei = ei;
6685 /* This is on the stack, so it doesn't need a wbarrier */
6686 context->handler_frame->ex = ex;
6687 /* Ditto */
6688 if (ei)
6689 *(MonoException**)(frame_locals (context->handler_frame) + ei->exvar_offset) = ex;
6690 context->handler_ip = (const guint16*)handler_ip;
6693 static void
6694 interp_get_resume_state (const MonoJitTlsData *jit_tls, gboolean *has_resume_state, MonoInterpFrameHandle *interp_frame, gpointer *handler_ip)
6696 g_assert (jit_tls);
6697 ThreadContext *context = (ThreadContext*)jit_tls->interp_context;
6698 g_assert (context);
6699 *has_resume_state = context->has_resume_state;
6700 if (context->has_resume_state) {
6701 *interp_frame = context->handler_frame;
6702 *handler_ip = (gpointer)context->handler_ip;
6707 * interp_run_finally:
6709 * Run the finally clause identified by CLAUSE_INDEX in the intepreter frame given by
6710 * frame->interp_frame.
6711 * Return TRUE if the finally clause threw an exception.
6713 static gboolean
6714 interp_run_finally (StackFrameInfo *frame, int clause_index, gpointer handler_ip, gpointer handler_ip_end)
6716 InterpFrame *iframe = (InterpFrame*)frame->interp_frame;
6717 ThreadContext *context = get_context ();
6718 const unsigned short *old_ip = iframe->ip;
6719 FrameClauseArgs clause_args;
6721 memset (&clause_args, 0, sizeof (FrameClauseArgs));
6722 clause_args.start_with_ip = (const guint16*)handler_ip;
6723 clause_args.end_at_ip = (const guint16*)handler_ip_end;
6724 clause_args.exit_clause = clause_index;
6726 ERROR_DECL (error);
6727 interp_exec_method_full (iframe, context, &clause_args, error);
6728 if (context->has_resume_state) {
6729 return TRUE;
6730 } else {
6731 iframe->ip = old_ip;
6732 return FALSE;
6737 * interp_run_filter:
6739 * Run the filter clause identified by CLAUSE_INDEX in the intepreter frame given by
6740 * frame->interp_frame.
6742 static gboolean
6743 interp_run_filter (StackFrameInfo *frame, MonoException *ex, int clause_index, gpointer handler_ip, gpointer handler_ip_end)
6745 InterpFrame *iframe = (InterpFrame*)frame->interp_frame;
6746 ThreadContext *context = get_context ();
6747 InterpFrame child_frame;
6748 stackval retval;
6749 FrameClauseArgs clause_args;
6752 * Have to run the clause in a new frame which is a copy of IFRAME, since
6753 * during debugging, there are two copies of the frame on the stack.
6755 memset (&child_frame, 0, sizeof (InterpFrame));
6756 child_frame.imethod = iframe->imethod;
6757 child_frame.retval = &retval;
6758 child_frame.parent = iframe;
6759 child_frame.stack_args = iframe->stack_args;
6761 memset (&clause_args, 0, sizeof (FrameClauseArgs));
6762 clause_args.start_with_ip = (const guint16*)handler_ip;
6763 clause_args.end_at_ip = (const guint16*)handler_ip_end;
6764 clause_args.filter_exception = ex;
6765 clause_args.base_frame = iframe;
6767 ERROR_DECL (error);
6768 interp_exec_method_full (&child_frame, context, &clause_args, error);
6769 /* ENDFILTER stores the result into child_frame->retval */
6770 return child_frame.retval->data.i ? TRUE : FALSE;
6773 typedef struct {
6774 InterpFrame *current;
6775 } StackIter;
6778 * interp_frame_iter_init:
6780 * Initialize an iterator for iterating through interpreted frames.
6782 static void
6783 interp_frame_iter_init (MonoInterpStackIter *iter, gpointer interp_exit_data)
6785 StackIter *stack_iter = (StackIter*)iter;
6787 stack_iter->current = (InterpFrame*)interp_exit_data;
6791 * interp_frame_iter_next:
6793 * Fill out FRAME with date for the next interpreter frame.
6795 static gboolean
6796 interp_frame_iter_next (MonoInterpStackIter *iter, StackFrameInfo *frame)
6798 StackIter *stack_iter = (StackIter*)iter;
6799 InterpFrame *iframe = stack_iter->current;
6801 memset (frame, 0, sizeof (StackFrameInfo));
6802 /* pinvoke frames doesn't have imethod set */
6803 while (iframe && !(iframe->imethod && iframe->imethod->code && iframe->imethod->jinfo))
6804 iframe = iframe->parent;
6805 if (!iframe)
6806 return FALSE;
6808 MonoMethod *method = iframe->imethod->method;
6809 frame->domain = iframe->imethod->domain;
6810 frame->interp_frame = iframe;
6811 frame->method = method;
6812 frame->actual_method = method;
6813 if (method && ((method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) || (method->iflags & (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL | METHOD_IMPL_ATTRIBUTE_RUNTIME)))) {
6814 frame->native_offset = -1;
6815 frame->type = FRAME_TYPE_MANAGED_TO_NATIVE;
6816 } else {
6817 frame->type = FRAME_TYPE_INTERP;
6818 /* This is the offset in the interpreter IR */
6819 frame->native_offset = (guint8*)iframe->ip - (guint8*)iframe->imethod->code;
6820 if (!method->wrapper_type || method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD)
6821 frame->managed = TRUE;
6823 frame->ji = iframe->imethod->jinfo;
6824 frame->frame_addr = iframe;
6826 stack_iter->current = iframe->parent;
6828 return TRUE;
6831 static MonoJitInfo*
6832 interp_find_jit_info (MonoDomain *domain, MonoMethod *method)
6834 InterpMethod* imethod;
6836 imethod = lookup_imethod (domain, method);
6837 if (imethod)
6838 return imethod->jinfo;
6839 else
6840 return NULL;
6843 static void
6844 interp_set_breakpoint (MonoJitInfo *jinfo, gpointer ip)
6846 guint16 *code = (guint16*)ip;
6847 g_assert (*code == MINT_SDB_SEQ_POINT);
6848 *code = MINT_SDB_BREAKPOINT;
6851 static void
6852 interp_clear_breakpoint (MonoJitInfo *jinfo, gpointer ip)
6854 guint16 *code = (guint16*)ip;
6855 g_assert (*code == MINT_SDB_BREAKPOINT);
6856 *code = MINT_SDB_SEQ_POINT;
6859 static MonoJitInfo*
6860 interp_frame_get_jit_info (MonoInterpFrameHandle frame)
6862 InterpFrame *iframe = (InterpFrame*)frame;
6864 g_assert (iframe->imethod);
6865 return iframe->imethod->jinfo;
6868 static gpointer
6869 interp_frame_get_ip (MonoInterpFrameHandle frame)
6871 InterpFrame *iframe = (InterpFrame*)frame;
6873 g_assert (iframe->imethod);
6874 return (gpointer)iframe->ip;
6877 static gpointer
6878 interp_frame_get_arg (MonoInterpFrameHandle frame, int pos)
6880 InterpFrame *iframe = (InterpFrame*)frame;
6881 MonoMethodSignature *sig;
6883 g_assert (iframe->imethod);
6885 sig = mono_method_signature_internal (iframe->imethod->method);
6886 return stackval_to_data_addr (sig->params [pos], &iframe->stack_args [pos + !!iframe->imethod->hasthis]);
6889 static gpointer
6890 interp_frame_get_local (MonoInterpFrameHandle frame, int pos)
6892 InterpFrame *iframe = (InterpFrame*)frame;
6894 g_assert (iframe->imethod);
6896 return frame_locals (iframe) + iframe->imethod->local_offsets [pos];
6899 static gpointer
6900 interp_frame_get_this (MonoInterpFrameHandle frame)
6902 InterpFrame *iframe = (InterpFrame*)frame;
6904 g_assert (iframe->imethod);
6905 g_assert (iframe->imethod->hasthis);
6906 return &iframe->stack_args [0].data.p;
6909 static MonoInterpFrameHandle
6910 interp_frame_get_parent (MonoInterpFrameHandle frame)
6912 InterpFrame *iframe = (InterpFrame*)frame;
6914 return iframe->parent;
6917 static gpointer
6918 interp_frame_get_res (MonoInterpFrameHandle frame)
6920 InterpFrame *iframe = (InterpFrame*)frame;
6921 MonoMethodSignature *sig;
6923 g_assert (iframe->imethod);
6924 sig = mono_method_signature_internal (iframe->imethod->method);
6925 if (sig->ret->type == MONO_TYPE_VOID)
6926 return NULL;
6927 else
6928 return stackval_to_data_addr (sig->ret, iframe->retval);
6931 static void
6932 interp_start_single_stepping (void)
6934 ss_enabled = TRUE;
6937 static void
6938 interp_stop_single_stepping (void)
6940 ss_enabled = FALSE;
6943 static void
6944 register_interp_stats (void)
6946 mono_counters_init ();
6947 mono_counters_register ("Total transform time", MONO_COUNTER_INTERP | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_interp_stats.transform_time);
6948 mono_counters_register ("Methods inlined", MONO_COUNTER_INTERP | MONO_COUNTER_INT, &mono_interp_stats.inlined_methods);
6949 mono_counters_register ("Inline failures", MONO_COUNTER_INTERP | MONO_COUNTER_INT, &mono_interp_stats.inline_failures);
6952 #undef MONO_EE_CALLBACK
6953 #define MONO_EE_CALLBACK(ret, name, sig) interp_ ## name,
6955 static const MonoEECallbacks mono_interp_callbacks = {
6956 MONO_EE_CALLBACKS
6959 void
6960 mono_ee_interp_init (const char *opts)
6962 g_assert (mono_ee_api_version () == MONO_EE_API_VERSION);
6963 g_assert (!interp_init_done);
6964 interp_init_done = TRUE;
6966 mono_native_tls_alloc (&thread_context_id, NULL);
6967 set_context (NULL);
6969 interp_parse_options (opts);
6970 if (mini_get_debug_options ()->mdb_optimizations)
6971 mono_interp_opt &= ~INTERP_OPT_INLINE;
6972 mono_interp_transform_init ();
6974 mini_install_interp_callbacks (&mono_interp_callbacks);
6976 register_interp_stats ();