interp/interp.c: In function 'interp_entry.constprop':
[mono-project.git] / mono / mini / interp / interp.c
blobd346b426e44c566d902cfacce5a673161bf6e96f
1 /**
2 * \file
3 * PLEASE NOTE: This is a research prototype.
6 * interp.c: Interpreter for CIL byte codes
8 * Authors:
9 * Paolo Molaro (lupus@ximian.com)
10 * Miguel de Icaza (miguel@ximian.com)
11 * Dietmar Maurer (dietmar@ximian.com)
13 * (C) 2001, 2002 Ximian, Inc.
15 #ifndef __USE_ISOC99
16 #define __USE_ISOC99
17 #endif
18 #include "config.h"
20 #include <stdio.h>
21 #include <string.h>
22 #include <stdlib.h>
23 #include <glib.h>
24 #include <math.h>
25 #include <locale.h>
27 #include <mono/utils/gc_wrapper.h>
28 #include <mono/utils/mono-math.h>
29 #include <mono/utils/mono-counters.h>
31 #ifdef HAVE_ALLOCA_H
32 # include <alloca.h>
33 #else
34 # ifdef __CYGWIN__
35 # define alloca __builtin_alloca
36 # endif
37 #endif
39 /* trim excessive headers */
40 #include <mono/metadata/image.h>
41 #include <mono/metadata/assembly-internals.h>
42 #include <mono/metadata/cil-coff.h>
43 #include <mono/metadata/mono-endian.h>
44 #include <mono/metadata/tabledefs.h>
45 #include <mono/metadata/tokentype.h>
46 #include <mono/metadata/loader.h>
47 #include <mono/metadata/threads.h>
48 #include <mono/metadata/threadpool.h>
49 #include <mono/metadata/profiler-private.h>
50 #include <mono/metadata/appdomain.h>
51 #include <mono/metadata/reflection.h>
52 #include <mono/metadata/exception.h>
53 #include <mono/metadata/verify.h>
54 #include <mono/metadata/opcodes.h>
55 #include <mono/metadata/debug-helpers.h>
56 #include <mono/metadata/mono-config.h>
57 #include <mono/metadata/marshal.h>
58 #include <mono/metadata/environment.h>
59 #include <mono/metadata/mono-debug.h>
60 #include <mono/metadata/gc-internals.h>
61 #include <mono/utils/atomic.h>
63 #include "interp.h"
64 #include "interp-internals.h"
65 #include "mintops.h"
67 #include <mono/mini/mini.h>
68 #include <mono/mini/mini-runtime.h>
69 #include <mono/mini/aot-runtime.h>
70 #include <mono/mini/llvm-runtime.h>
71 #include <mono/mini/llvmonly-runtime.h>
72 #include <mono/mini/jit-icalls.h>
73 #include <mono/mini/debugger-agent.h>
74 #include <mono/mini/ee.h>
75 #include <mono/mini/trace.h>
77 #ifdef TARGET_ARM
78 #include <mono/mini/mini-arm.h>
79 #endif
80 #include <mono/metadata/icall-decl.h>
82 #ifdef _MSC_VER
83 #pragma warning(disable:4102) // label' : unreferenced label
84 #endif
86 /* Arguments that are passed when invoking only a finally/filter clause from the frame */
87 typedef struct {
88 /* Where we start the frame execution from */
89 guint16 *start_with_ip;
91 * End ip of the exit_clause. We need it so we know whether the resume
92 * state is for this frame (which is called from EH) or for the original
93 * frame further down the stack.
95 guint16 *end_at_ip;
96 /* When exiting this clause we also exit the frame */
97 int exit_clause;
98 /* Exception that we are filtering */
99 MonoException *filter_exception;
100 InterpFrame *base_frame;
101 } FrameClauseArgs;
103 static inline void
104 init_frame (InterpFrame *frame, InterpFrame *parent_frame, InterpMethod *rmethod, stackval *method_args, stackval *method_retval)
106 frame->parent = parent_frame;
107 frame->stack_args = method_args;
108 frame->retval = method_retval;
109 frame->imethod = rmethod;
110 frame->ex = NULL;
111 frame->ip = NULL;
112 frame->invoke_trap = 0;
115 #define INIT_FRAME(frame,parent_frame,method_args,method_retval,domain,mono_method,error) do { \
116 InterpMethod *_rmethod = mono_interp_get_imethod ((domain), (mono_method), (error)); \
117 init_frame ((frame), (parent_frame), _rmethod, (method_args), (method_retval)); \
118 } while (0)
120 #define interp_exec_method(frame, context) interp_exec_method_full ((frame), (context), NULL)
123 * List of classes whose methods will be executed by transitioning to JITted code.
124 * Used for testing.
126 GSList *mono_interp_jit_classes;
127 /* Optimizations enabled with interpreter */
128 int mono_interp_opt = INTERP_OPT_INLINE;
129 /* If TRUE, interpreted code will be interrupted at function entry/backward branches */
130 static gboolean ss_enabled;
132 static gboolean interp_init_done = FALSE;
134 static void interp_exec_method_full (InterpFrame *frame, ThreadContext *context, FrameClauseArgs *clause_args);
135 static InterpMethod* lookup_method_pointer (gpointer addr);
137 typedef void (*ICallMethod) (InterpFrame *frame);
139 static MonoNativeTlsKey thread_context_id;
141 #define DEBUG_INTERP 0
142 #define COUNT_OPS 0
143 #if DEBUG_INTERP
144 int mono_interp_traceopt = 2;
145 /* If true, then we output the opcodes as we interpret them */
146 static int global_tracing = 2;
148 static int debug_indent_level = 0;
150 static int break_on_method = 0;
151 static int nested_trace = 0;
152 static GList *db_methods = NULL;
153 static char* dump_args (InterpFrame *inv);
155 static void
156 output_indent (void)
158 int h;
160 for (h = 0; h < debug_indent_level; h++)
161 g_print (" ");
164 static void
165 db_match_method (gpointer data, gpointer user_data)
167 MonoMethod *m = (MonoMethod*)user_data;
168 MonoMethodDesc *desc = data;
170 if (mono_method_desc_full_match (desc, m))
171 break_on_method = 1;
174 static void
175 debug_enter (InterpFrame *frame, int *tracing)
177 if (db_methods) {
178 g_list_foreach (db_methods, db_match_method, (gpointer)frame->imethod->method);
179 if (break_on_method)
180 *tracing = nested_trace ? (global_tracing = 2, 3) : 2;
181 break_on_method = 0;
183 if (*tracing) {
184 MonoMethod *method = frame->imethod->method;
185 char *mn, *args = dump_args (frame);
186 debug_indent_level++;
187 output_indent ();
188 mn = mono_method_full_name (method, FALSE);
189 g_print ("(%p) Entering %s (", mono_thread_internal_current (), mn);
190 g_free (mn);
191 g_print ("%s)\n", args);
192 g_free (args);
197 #define DEBUG_LEAVE() \
198 if (tracing) { \
199 char *mn, *args; \
200 args = dump_retval (frame); \
201 output_indent (); \
202 mn = mono_method_full_name (frame->imethod->method, FALSE); \
203 g_print ("(%p) Leaving %s", mono_thread_internal_current (), mn); \
204 g_free (mn); \
205 g_print (" => %s\n", args); \
206 g_free (args); \
207 debug_indent_level--; \
208 if (tracing == 3) global_tracing = 0; \
211 #else
213 int mono_interp_traceopt = 0;
214 static void debug_enter (InterpFrame *frame, int *tracing)
217 #define DEBUG_LEAVE()
219 #endif
221 static void
222 set_resume_state (ThreadContext *context, InterpFrame *frame)
224 frame->ex = NULL;
225 context->has_resume_state = 0;
226 context->handler_frame = NULL;
227 context->handler_ei = NULL;
230 /* Set the current execution state to the resume state in context */
231 #define SET_RESUME_STATE(context) do { \
232 ip = (const guint16*)(context)->handler_ip; \
233 /* spec says stack should be empty at endfinally so it should be at the start too */ \
234 sp = frame->stack; \
235 vt_sp = (unsigned char *) sp + imethod->stack_size; \
236 if (frame->ex) { \
237 sp->data.p = frame->ex; \
238 ++sp; \
240 /* We have thrown an exception from a finally block. Some of the leave targets were unwinded already */ \
241 while (finally_ips && \
242 finally_ips->data >= (context)->handler_ei->try_start && \
243 finally_ips->data < (context)->handler_ei->try_end) \
244 finally_ips = g_slist_remove (finally_ips, finally_ips->data); \
245 set_resume_state ((context), (frame)); \
246 goto main_loop; \
247 } while (0)
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 if (frame == (context)->handler_frame && (!clause_args || (context)->handler_ip < clause_args->end_at_ip)) \
258 SET_RESUME_STATE (context); \
259 else \
260 goto exit_frame; \
262 } while (0);
264 static void
265 set_context (ThreadContext *context)
267 mono_native_tls_set_value (thread_context_id, context);
269 if (!context)
270 return;
272 MonoJitTlsData *jit_tls = mono_tls_get_jit_tls ();
273 g_assertf (jit_tls, "ThreadContext needs initialized JIT TLS");
275 /* jit_tls assumes ownership of 'context' */
276 jit_tls->interp_context = context;
279 static ThreadContext *
280 get_context (void)
282 ThreadContext *context = (ThreadContext *) mono_native_tls_get_value (thread_context_id);
283 if (context == NULL) {
284 context = g_new0 (ThreadContext, 1);
285 set_context (context);
287 return context;
290 static void
291 ves_real_abort (int line, MonoMethod *mh,
292 const unsigned short *ip, stackval *stack, stackval *sp)
294 ERROR_DECL (error);
295 MonoMethodHeader *header = mono_method_get_header_checked (mh, error);
296 mono_error_cleanup (error); /* FIXME: don't swallow the error */
297 g_printerr ("Execution aborted in method: %s::%s\n", m_class_get_name (mh->klass), mh->name);
298 g_printerr ("Line=%d IP=0x%04lx, Aborted execution\n", line, ip-(const unsigned short *) header->code);
299 g_printerr ("0x%04x %02x\n", ip-(const unsigned short *) header->code, *ip);
300 mono_metadata_free_mh (header);
303 #define ves_abort() \
304 do {\
305 ves_real_abort(__LINE__, frame->imethod->method, ip, frame->stack, sp); \
306 THROW_EX (mono_get_exception_execution_engine (NULL), ip); \
307 } while (0);
309 static InterpMethod*
310 lookup_imethod (MonoDomain *domain, MonoMethod *method)
312 InterpMethod *imethod;
313 MonoJitDomainInfo *info;
315 info = domain_jit_info (domain);
316 mono_domain_jit_code_hash_lock (domain);
317 imethod = (InterpMethod*)mono_internal_hash_table_lookup (&info->interp_code_hash, method);
318 mono_domain_jit_code_hash_unlock (domain);
319 return imethod;
322 static gpointer
323 interp_get_remoting_invoke (MonoMethod *method, gpointer addr, MonoError *error)
325 #ifndef DISABLE_REMOTING
326 InterpMethod *imethod;
328 if (addr) {
329 imethod = lookup_method_pointer (addr);
330 } else {
331 g_assert (method);
332 imethod = mono_interp_get_imethod (mono_domain_get (), method, error);
333 return_val_if_nok (error, NULL);
335 g_assert (imethod);
336 g_assert (mono_use_interpreter);
338 MonoMethod *remoting_invoke_method = mono_marshal_get_remoting_invoke (imethod->method, error);
339 return_val_if_nok (error, NULL);
340 return mono_interp_get_imethod (mono_domain_get (), remoting_invoke_method, error);
341 #else
342 g_assert_not_reached ();
343 return NULL;
344 #endif
347 InterpMethod*
348 mono_interp_get_imethod (MonoDomain *domain, MonoMethod *method, MonoError *error)
350 InterpMethod *imethod;
351 MonoJitDomainInfo *info;
352 MonoMethodSignature *sig;
353 int i;
355 error_init (error);
357 info = domain_jit_info (domain);
358 mono_domain_jit_code_hash_lock (domain);
359 imethod = (InterpMethod*)mono_internal_hash_table_lookup (&info->interp_code_hash, method);
360 mono_domain_jit_code_hash_unlock (domain);
361 if (imethod)
362 return imethod;
364 sig = mono_method_signature_internal (method);
366 imethod = (InterpMethod*)mono_domain_alloc0 (domain, sizeof (InterpMethod));
367 imethod->method = method;
368 imethod->domain = domain;
369 imethod->param_count = sig->param_count;
370 imethod->hasthis = sig->hasthis;
371 imethod->vararg = sig->call_convention == MONO_CALL_VARARG;
372 imethod->rtype = mini_get_underlying_type (sig->ret);
373 imethod->param_types = (MonoType**)mono_domain_alloc0 (domain, sizeof (MonoType*) * sig->param_count);
374 for (i = 0; i < sig->param_count; ++i)
375 imethod->param_types [i] = mini_get_underlying_type (sig->params [i]);
377 mono_domain_jit_code_hash_lock (domain);
378 if (!mono_internal_hash_table_lookup (&info->interp_code_hash, method))
379 mono_internal_hash_table_insert (&info->interp_code_hash, method, imethod);
380 mono_domain_jit_code_hash_unlock (domain);
382 imethod->prof_flags = mono_profiler_get_call_instrumentation_flags (imethod->method);
384 return imethod;
387 #if defined (MONO_CROSS_COMPILE) || defined (HOST_WASM)
388 #define INTERP_PUSH_LMF_WITH_CTX_BODY(ext, exit_label) \
389 (ext).kind = MONO_LMFEXT_INTERP_EXIT;
391 #elif defined(MONO_ARCH_HAS_NO_PROPER_MONOCTX)
392 /* some platforms, e.g. appleTV, don't provide us a precise MonoContext
393 * (registers are not accurate), thus resuming to the label does not work. */
394 #define INTERP_PUSH_LMF_WITH_CTX_BODY(ext, exit_label) \
395 (ext).kind = MONO_LMFEXT_INTERP_EXIT;
396 #elif defined (_MSC_VER)
397 #define INTERP_PUSH_LMF_WITH_CTX_BODY(ext, exit_label) \
398 (ext).kind = MONO_LMFEXT_INTERP_EXIT_WITH_CTX; \
399 (ext).interp_exit_label_set = FALSE; \
400 MONO_CONTEXT_GET_CURRENT ((ext).ctx); \
401 if ((ext).interp_exit_label_set == FALSE) \
402 mono_arch_do_ip_adjustment (&(ext).ctx); \
403 if ((ext).interp_exit_label_set == TRUE) \
404 goto exit_label; \
405 (ext).interp_exit_label_set = TRUE;
406 #elif defined(MONO_ARCH_HAS_MONO_CONTEXT)
407 #define INTERP_PUSH_LMF_WITH_CTX_BODY(ext, exit_label) \
408 (ext).kind = MONO_LMFEXT_INTERP_EXIT_WITH_CTX; \
409 MONO_CONTEXT_GET_CURRENT ((ext).ctx); \
410 MONO_CONTEXT_SET_IP (&(ext).ctx, (&&exit_label)); \
411 mono_arch_do_ip_adjustment (&(ext).ctx);
412 #else
413 #define INTERP_PUSH_LMF_WITH_CTX_BODY(ext, exit_label) g_error ("requires working mono-context");
414 #endif
416 /* INTERP_PUSH_LMF_WITH_CTX:
418 * same as interp_push_lmf, but retrieving and attaching MonoContext to it.
419 * This is needed to resume into the interp when the exception is thrown from
420 * native code (see ./mono/tests/install_eh_callback.exe).
422 * This must be a macro in order to retrieve the right register values for
423 * MonoContext.
425 #define INTERP_PUSH_LMF_WITH_CTX(frame, ext, exit_label) \
426 memset (&(ext), 0, sizeof (MonoLMFExt)); \
427 (ext).interp_exit_data = (frame); \
428 INTERP_PUSH_LMF_WITH_CTX_BODY ((ext), exit_label); \
429 mono_push_lmf (&(ext));
432 * interp_push_lmf:
434 * Push an LMF frame on the LMF stack
435 * to mark the transition to native code.
436 * This is needed for the native code to
437 * be able to do stack walks.
439 static void
440 interp_push_lmf (MonoLMFExt *ext, InterpFrame *frame)
442 memset (ext, 0, sizeof (MonoLMFExt));
443 ext->kind = MONO_LMFEXT_INTERP_EXIT;
444 ext->interp_exit_data = frame;
446 mono_push_lmf (ext);
449 static void
450 interp_pop_lmf (MonoLMFExt *ext)
452 mono_pop_lmf (&ext->lmf);
455 static InterpMethod*
456 get_virtual_method (InterpMethod *imethod, MonoObject *obj)
458 MonoMethod *m = imethod->method;
459 MonoDomain *domain = imethod->domain;
460 InterpMethod *ret = NULL;
461 ERROR_DECL (error);
463 #ifndef DISABLE_REMOTING
464 if (mono_object_is_transparent_proxy (obj)) {
465 MonoMethod *remoting_invoke_method = mono_marshal_get_remoting_invoke_with_check (m, error);
466 mono_error_assert_ok (error);
467 ret = mono_interp_get_imethod (domain, remoting_invoke_method, error);
468 mono_error_assert_ok (error);
469 return ret;
471 #endif
473 if ((m->flags & METHOD_ATTRIBUTE_FINAL) || !(m->flags & METHOD_ATTRIBUTE_VIRTUAL)) {
474 if (m->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED) {
475 ret = mono_interp_get_imethod (domain, mono_marshal_get_synchronized_wrapper (m), error);
476 mono_error_cleanup (error); /* FIXME: don't swallow the error */
477 } else {
478 ret = imethod;
480 return ret;
483 mono_class_setup_vtable (obj->vtable->klass);
485 int slot = mono_method_get_vtable_slot (m);
486 if (mono_class_is_interface (m->klass)) {
487 g_assert (obj->vtable->klass != m->klass);
488 /* TODO: interface offset lookup is slow, go through IMT instead */
489 gboolean non_exact_match;
490 slot += mono_class_interface_offset_with_variance (obj->vtable->klass, m->klass, &non_exact_match);
493 MonoMethod *virtual_method = m_class_get_vtable (mono_object_class (obj)) [slot];
494 if (m->is_inflated && mono_method_get_context (m)->method_inst) {
495 MonoGenericContext context = { NULL, NULL };
497 if (mono_class_is_ginst (virtual_method->klass))
498 context.class_inst = mono_class_get_generic_class (virtual_method->klass)->context.class_inst;
499 else if (mono_class_is_gtd (virtual_method->klass))
500 context.class_inst = mono_class_get_generic_container (virtual_method->klass)->context.class_inst;
501 context.method_inst = mono_method_get_context (m)->method_inst;
503 virtual_method = mono_class_inflate_generic_method_checked (virtual_method, &context, error);
504 mono_error_cleanup (error); /* FIXME: don't swallow the error */
507 if (virtual_method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) {
508 virtual_method = mono_marshal_get_native_wrapper (virtual_method, FALSE, FALSE);
511 if (virtual_method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED) {
512 virtual_method = mono_marshal_get_synchronized_wrapper (virtual_method);
515 InterpMethod *virtual_imethod = mono_interp_get_imethod (domain, virtual_method, error);
516 mono_error_cleanup (error); /* FIXME: don't swallow the error */
517 return virtual_imethod;
520 typedef struct {
521 InterpMethod *imethod;
522 InterpMethod *target_imethod;
523 } InterpVTableEntry;
525 /* domain lock must be held */
526 static GSList*
527 append_imethod (MonoDomain *domain, GSList *list, InterpMethod *imethod, InterpMethod *target_imethod)
529 GSList *ret;
530 InterpVTableEntry *entry;
532 entry = (InterpVTableEntry*) mono_mempool_alloc (domain->mp, sizeof (InterpVTableEntry));
533 entry->imethod = imethod;
534 entry->target_imethod = target_imethod;
535 ret = g_slist_append_mempool (domain->mp, list, entry);
537 return ret;
540 static InterpMethod*
541 get_target_imethod (GSList *list, InterpMethod *imethod)
543 while (list != NULL) {
544 InterpVTableEntry *entry = (InterpVTableEntry*) list->data;
545 if (entry->imethod == imethod)
546 return entry->target_imethod;
547 list = list->next;
549 return NULL;
552 static gpointer*
553 get_method_table (MonoObject *obj, int offset)
555 if (offset >= 0) {
556 return obj->vtable->interp_vtable;
557 } else {
558 return (gpointer*)obj->vtable;
562 static gpointer*
563 alloc_method_table (MonoObject *obj, int offset)
565 gpointer *table;
567 if (offset >= 0) {
568 table = mono_domain_alloc0 (obj->vtable->domain, m_class_get_vtable_size (obj->vtable->klass) * sizeof (gpointer));
569 obj->vtable->interp_vtable = table;
570 } else {
571 table = (gpointer*)obj->vtable;
574 return table;
577 static InterpMethod*
578 get_virtual_method_fast (MonoObject *obj, InterpMethod *imethod, int offset)
580 gpointer *table;
582 #ifndef DISABLE_REMOTING
583 /* FIXME Remoting */
584 if (mono_object_is_transparent_proxy (obj))
585 return get_virtual_method (imethod, obj);
586 #endif
588 table = get_method_table (obj, offset);
590 if (!table) {
591 /* Lazily allocate method table */
592 mono_domain_lock (obj->vtable->domain);
593 table = get_method_table (obj, offset);
594 if (!table)
595 table = alloc_method_table (obj, offset);
596 mono_domain_unlock (obj->vtable->domain);
599 if (!table [offset]) {
600 InterpMethod *target_imethod = get_virtual_method (imethod, obj);
601 /* Lazily initialize the method table slot */
602 mono_domain_lock (obj->vtable->domain);
603 if (!table [offset]) {
604 if (imethod->method->is_inflated || offset < 0)
605 table [offset] = append_imethod (obj->vtable->domain, NULL, imethod, target_imethod);
606 else
607 table [offset] = (gpointer) ((gsize)target_imethod | 0x1);
609 mono_domain_unlock (obj->vtable->domain);
612 if ((gsize)table [offset] & 0x1) {
613 /* Non generic virtual call. Only one method in slot */
614 return (InterpMethod*) ((gsize)table [offset] & ~0x1);
615 } else {
616 /* Virtual generic or interface call. Multiple methods in slot */
617 InterpMethod *target_imethod = get_target_imethod ((GSList*)table [offset], imethod);
619 if (!target_imethod) {
620 target_imethod = get_virtual_method (imethod, obj);
621 mono_domain_lock (obj->vtable->domain);
622 if (!get_target_imethod ((GSList*)table [offset], imethod))
623 table [offset] = append_imethod (obj->vtable->domain, (GSList*)table [offset], imethod, target_imethod);
624 mono_domain_unlock (obj->vtable->domain);
626 return target_imethod;
630 static void inline
631 stackval_from_data (MonoType *type_, stackval *result, void *data, gboolean pinvoke)
633 MonoType *type = mini_native_type_replace_type (type_);
634 if (type->byref) {
635 switch (type->type) {
636 case MONO_TYPE_OBJECT:
637 case MONO_TYPE_CLASS:
638 case MONO_TYPE_STRING:
639 case MONO_TYPE_ARRAY:
640 case MONO_TYPE_SZARRAY:
641 break;
642 default:
643 break;
645 result->data.p = *(gpointer*)data;
646 return;
648 switch (type->type) {
649 case MONO_TYPE_VOID:
650 return;
651 case MONO_TYPE_I1:
652 result->data.i = *(gint8*)data;
653 return;
654 case MONO_TYPE_U1:
655 case MONO_TYPE_BOOLEAN:
656 result->data.i = *(guint8*)data;
657 return;
658 case MONO_TYPE_I2:
659 result->data.i = *(gint16*)data;
660 return;
661 case MONO_TYPE_U2:
662 case MONO_TYPE_CHAR:
663 result->data.i = *(guint16*)data;
664 return;
665 case MONO_TYPE_I4:
666 result->data.i = *(gint32*)data;
667 return;
668 case MONO_TYPE_U:
669 case MONO_TYPE_I:
670 result->data.nati = *(mono_i*)data;
671 return;
672 case MONO_TYPE_PTR:
673 result->data.p = *(gpointer*)data;
674 return;
675 case MONO_TYPE_U4:
676 result->data.i = *(guint32*)data;
677 return;
678 case MONO_TYPE_R4:
679 /* memmove handles unaligned case */
680 memmove (&result->data.f_r4, data, sizeof (float));
681 return;
682 case MONO_TYPE_I8:
683 case MONO_TYPE_U8:
684 memmove (&result->data.l, data, sizeof (gint64));
685 return;
686 case MONO_TYPE_R8:
687 memmove (&result->data.f, data, sizeof (double));
688 return;
689 case MONO_TYPE_STRING:
690 case MONO_TYPE_SZARRAY:
691 case MONO_TYPE_CLASS:
692 case MONO_TYPE_OBJECT:
693 case MONO_TYPE_ARRAY:
694 result->data.p = *(gpointer*)data;
695 return;
696 case MONO_TYPE_VALUETYPE:
697 if (m_class_is_enumtype (type->data.klass)) {
698 stackval_from_data (mono_class_enum_basetype_internal (type->data.klass), result, data, pinvoke);
699 return;
700 } else if (pinvoke) {
701 memcpy (result->data.vt, data, mono_class_native_size (type->data.klass, NULL));
702 } else {
703 mono_value_copy_internal (result->data.vt, data, type->data.klass);
705 return;
706 case MONO_TYPE_GENERICINST: {
707 if (mono_type_generic_inst_is_valuetype (type)) {
708 mono_value_copy_internal (result->data.vt, data, mono_class_from_mono_type_internal (type));
709 return;
711 stackval_from_data (m_class_get_byval_arg (type->data.generic_class->container_class), result, data, pinvoke);
712 return;
714 default:
715 g_error ("got type 0x%02x", type->type);
719 static void inline
720 stackval_to_data (MonoType *type_, stackval *val, void *data, gboolean pinvoke)
722 MonoType *type = mini_native_type_replace_type (type_);
723 if (type->byref) {
724 gpointer *p = (gpointer*)data;
725 *p = val->data.p;
726 return;
728 /* printf ("TODAT0 %p\n", data); */
729 switch (type->type) {
730 case MONO_TYPE_I1:
731 case MONO_TYPE_U1: {
732 guint8 *p = (guint8*)data;
733 *p = val->data.i;
734 return;
736 case MONO_TYPE_BOOLEAN: {
737 guint8 *p = (guint8*)data;
738 *p = (val->data.i != 0);
739 return;
741 case MONO_TYPE_I2:
742 case MONO_TYPE_U2:
743 case MONO_TYPE_CHAR: {
744 guint16 *p = (guint16*)data;
745 *p = val->data.i;
746 return;
748 case MONO_TYPE_I: {
749 mono_i *p = (mono_i*)data;
750 /* In theory the value used by stloc should match the local var type
751 but in practice it sometimes doesn't (a int32 gets dup'd and stloc'd into
752 a native int - both by csc and mcs). Not sure what to do about sign extension
753 as it is outside the spec... doing the obvious */
754 *p = (mono_i)val->data.nati;
755 return;
757 case MONO_TYPE_U: {
758 mono_u *p = (mono_u*)data;
759 /* see above. */
760 *p = (mono_u)val->data.nati;
761 return;
763 case MONO_TYPE_I4:
764 case MONO_TYPE_U4: {
765 gint32 *p = (gint32*)data;
766 *p = val->data.i;
767 return;
769 case MONO_TYPE_I8:
770 case MONO_TYPE_U8: {
771 memmove (data, &val->data.l, sizeof (gint64));
772 return;
774 case MONO_TYPE_R4: {
775 /* memmove handles unaligned case */
776 memmove (data, &val->data.f_r4, sizeof (float));
777 return;
779 case MONO_TYPE_R8: {
780 memmove (data, &val->data.f, sizeof (double));
781 return;
783 case MONO_TYPE_STRING:
784 case MONO_TYPE_SZARRAY:
785 case MONO_TYPE_CLASS:
786 case MONO_TYPE_OBJECT:
787 case MONO_TYPE_ARRAY: {
788 gpointer *p = (gpointer *) data;
789 mono_gc_wbarrier_generic_store_internal (p, val->data.o);
790 return;
792 case MONO_TYPE_PTR: {
793 gpointer *p = (gpointer *) data;
794 *p = val->data.p;
795 return;
797 case MONO_TYPE_VALUETYPE:
798 if (m_class_is_enumtype (type->data.klass)) {
799 stackval_to_data (mono_class_enum_basetype_internal (type->data.klass), val, data, pinvoke);
800 return;
801 } else if (pinvoke) {
802 memcpy (data, val->data.vt, mono_class_native_size (type->data.klass, NULL));
803 } else {
804 mono_value_copy_internal (data, val->data.vt, type->data.klass);
806 return;
807 case MONO_TYPE_GENERICINST: {
808 MonoClass *container_class = type->data.generic_class->container_class;
810 if (m_class_is_valuetype (container_class) && !m_class_is_enumtype (container_class)) {
811 mono_value_copy_internal (data, val->data.vt, mono_class_from_mono_type_internal (type));
812 return;
814 stackval_to_data (m_class_get_byval_arg (type->data.generic_class->container_class), val, data, pinvoke);
815 return;
817 default:
818 g_error ("got type %x", type->type);
823 * Same as stackval_to_data but return address of storage instead
824 * of copying the value.
826 static gpointer
827 stackval_to_data_addr (MonoType *type_, stackval *val)
829 MonoType *type = mini_native_type_replace_type (type_);
830 if (type->byref)
831 return &val->data.p;
833 switch (type->type) {
834 case MONO_TYPE_I1:
835 case MONO_TYPE_U1:
836 case MONO_TYPE_BOOLEAN:
837 case MONO_TYPE_I2:
838 case MONO_TYPE_U2:
839 case MONO_TYPE_CHAR:
840 case MONO_TYPE_I4:
841 case MONO_TYPE_U4:
842 return &val->data.i;
843 case MONO_TYPE_I:
844 case MONO_TYPE_U:
845 return &val->data.nati;
846 case MONO_TYPE_I8:
847 case MONO_TYPE_U8:
848 return &val->data.l;
849 case MONO_TYPE_R4:
850 return &val->data.f_r4;
851 case MONO_TYPE_R8:
852 return &val->data.f;
853 case MONO_TYPE_STRING:
854 case MONO_TYPE_SZARRAY:
855 case MONO_TYPE_CLASS:
856 case MONO_TYPE_OBJECT:
857 case MONO_TYPE_ARRAY:
858 case MONO_TYPE_PTR:
859 return &val->data.p;
860 case MONO_TYPE_VALUETYPE:
861 if (m_class_is_enumtype (type->data.klass))
862 return stackval_to_data_addr (mono_class_enum_basetype_internal (type->data.klass), val);
863 else
864 return val->data.vt;
865 case MONO_TYPE_TYPEDBYREF:
866 return val->data.vt;
867 case MONO_TYPE_GENERICINST: {
868 MonoClass *container_class = type->data.generic_class->container_class;
870 if (m_class_is_valuetype (container_class) && !m_class_is_enumtype (container_class))
871 return val->data.vt;
872 return stackval_to_data_addr (m_class_get_byval_arg (type->data.generic_class->container_class), val);
874 default:
875 g_error ("got type %x", type->type);
880 * interp_throw:
881 * Throw an exception from the interpreter.
883 static MONO_NEVER_INLINE void
884 interp_throw (ThreadContext *context, MonoException *ex, InterpFrame *frame, gconstpointer ip, gboolean rethrow)
886 ERROR_DECL (error);
887 MonoLMFExt ext;
889 interp_push_lmf (&ext, frame);
890 frame->ip = (const guint16*)ip;
891 frame->ex = ex;
893 if (mono_object_isinst_checked ((MonoObject *) ex, mono_defaults.exception_class, error)) {
894 MonoException *mono_ex = (MonoException *) ex;
895 if (!rethrow) {
896 mono_ex->stack_trace = NULL;
897 mono_ex->trace_ips = NULL;
900 mono_error_assert_ok (error);
902 MonoContext ctx;
903 memset (&ctx, 0, sizeof (MonoContext));
904 MONO_CONTEXT_SET_SP (&ctx, frame);
907 * Call the JIT EH code. The EH code will call back to us using:
908 * - mono_interp_set_resume_state ()/run_finally ()/run_filter ().
909 * Since ctx.ip is 0, this will start unwinding from the LMF frame
910 * pushed above, which points to our frames.
912 mono_handle_exception (&ctx, (MonoObject*)ex);
913 if (MONO_CONTEXT_GET_IP (&ctx) != 0) {
914 /* We need to unwind into non-interpreter code */
915 mono_restore_context (&ctx);
916 g_assert_not_reached ();
919 interp_pop_lmf (&ext);
921 g_assert (context->has_resume_state);
924 #define THROW_EX_GENERAL(exception,ex_ip, rethrow) \
925 do { \
926 interp_throw (context, (exception), (frame), (ex_ip), (rethrow)); \
927 CHECK_RESUME_STATE(context); \
928 } while (0)
930 #define THROW_EX(exception,ex_ip) THROW_EX_GENERAL ((exception), (ex_ip), FALSE)
932 #define EXCEPTION_CHECKPOINT \
933 do { \
934 if (*mono_thread_interruption_request_flag () && !mono_threads_is_critical_method (imethod->method)) { \
935 MonoException *exc = mono_thread_interruption_checkpoint (); \
936 if (exc) \
937 THROW_EX (exc, ip); \
939 } while (0)
942 static MonoObject*
943 ves_array_create (MonoDomain *domain, MonoClass *klass, int param_count, stackval *values, MonoError *error)
945 uintptr_t *lengths;
946 intptr_t *lower_bounds;
947 MonoObject *obj;
948 int i;
950 lengths = g_newa (uintptr_t, m_class_get_rank (klass) * 2);
951 for (i = 0; i < param_count; ++i) {
952 lengths [i] = values->data.i;
953 values ++;
955 if (m_class_get_rank (klass) == param_count) {
956 /* Only lengths provided. */
957 lower_bounds = NULL;
958 } else {
959 /* lower bounds are first. */
960 lower_bounds = (intptr_t *) lengths;
961 lengths += m_class_get_rank (klass);
963 obj = (MonoObject*) mono_array_new_full_checked (domain, klass, lengths, lower_bounds, error);
964 return obj;
967 static gint32
968 ves_array_calculate_index (MonoArray *ao, stackval *sp, InterpFrame *frame, gboolean safe)
970 g_assert (!frame->ex);
971 MonoClass *ac = ((MonoObject *) ao)->vtable->klass;
973 guint32 pos = 0;
974 if (ao->bounds) {
975 for (gint32 i = 0; i < m_class_get_rank (ac); i++) {
976 guint32 idx = sp [i].data.i;
977 guint32 lower = ao->bounds [i].lower_bound;
978 guint32 len = ao->bounds [i].length;
979 if (safe && (idx < lower || (idx - lower) >= len)) {
980 frame->ex = mono_get_exception_index_out_of_range ();
981 return -1;
983 pos = (pos * len) + idx - lower;
985 } else {
986 pos = sp [0].data.i;
987 if (safe && pos >= ao->max_length) {
988 frame->ex = mono_get_exception_index_out_of_range ();
989 return -1;
992 return pos;
995 static void
996 ves_array_set (InterpFrame *frame, stackval *sp, MonoMethodSignature *sig)
998 MonoObject *o = sp->data.o;
999 MonoArray *ao = (MonoArray *) o;
1000 MonoClass *ac = o->vtable->klass;
1002 g_assert (m_class_get_rank (ac) >= 1);
1004 gint32 pos = ves_array_calculate_index (ao, sp + 1, frame, TRUE);
1005 if (frame->ex)
1006 return;
1008 int val_index = 1 + m_class_get_rank (ac);
1009 if (sp [val_index].data.p && !m_class_is_valuetype (m_class_get_element_class (mono_object_class (o)))) {
1010 ERROR_DECL (error);
1011 MonoObject *isinst = mono_object_isinst_checked (sp [val_index].data.o, m_class_get_element_class (mono_object_class (o)), error);
1012 mono_error_cleanup (error);
1013 if (!isinst) {
1014 frame->ex = mono_get_exception_array_type_mismatch ();
1015 return;
1019 gint32 esize = mono_array_element_size (ac);
1020 gpointer ea = mono_array_addr_with_size_fast (ao, esize, pos);
1022 MonoType *mt = sig->params [m_class_get_rank (ac)];
1023 stackval_to_data (mt, &sp [val_index], ea, FALSE);
1026 static void
1027 ves_array_get (InterpFrame *frame, stackval *sp, stackval *retval, MonoMethodSignature *sig, gboolean safe)
1029 MonoObject *o = sp->data.o;
1030 MonoArray *ao = (MonoArray *) o;
1031 MonoClass *ac = o->vtable->klass;
1033 g_assert (m_class_get_rank (ac) >= 1);
1035 gint32 pos = ves_array_calculate_index (ao, sp + 1, frame, safe);
1036 if (frame->ex)
1037 return;
1039 gint32 esize = mono_array_element_size (ac);
1040 gpointer ea = mono_array_addr_with_size_fast (ao, esize, pos);
1042 MonoType *mt = sig->ret;
1043 stackval_from_data (mt, retval, ea, FALSE);
1046 static gpointer
1047 ves_array_element_address (InterpFrame *frame, MonoClass *required_type, MonoArray *ao, stackval *sp, gboolean needs_typecheck)
1049 MonoClass *ac = ((MonoObject *) ao)->vtable->klass;
1051 g_assert (m_class_get_rank (ac) >= 1);
1053 gint32 pos = ves_array_calculate_index (ao, sp, frame, TRUE);
1054 if (frame->ex)
1055 return NULL;
1057 if (needs_typecheck && !mono_class_is_assignable_from_internal (m_class_get_element_class (mono_object_class ((MonoObject *) ao)), required_type)) {
1058 frame->ex = mono_get_exception_array_type_mismatch ();
1059 return NULL;
1061 gint32 esize = mono_array_element_size (ac);
1062 return mono_array_addr_with_size_fast (ao, esize, pos);
1065 #ifdef MONO_ARCH_HAVE_INTERP_ENTRY_TRAMPOLINE
1066 static MonoFuncV mono_native_to_interp_trampoline = NULL;
1067 #endif
1069 #ifndef MONO_ARCH_HAVE_INTERP_PINVOKE_TRAMP
1070 static InterpMethodArguments* build_args_from_sig (MonoMethodSignature *sig, InterpFrame *frame)
1072 InterpMethodArguments *margs = g_malloc0 (sizeof (InterpMethodArguments));
1074 #ifdef TARGET_ARM
1075 g_assert (mono_arm_eabi_supported ());
1076 int i8_align = mono_arm_i8_align ();
1077 #endif
1079 #ifdef TARGET_WASM
1080 margs->sig = sig;
1081 #endif
1083 if (sig->hasthis)
1084 margs->ilen++;
1086 for (int i = 0; i < sig->param_count; i++) {
1087 guint32 ptype = sig->params [i]->byref ? MONO_TYPE_PTR : sig->params [i]->type;
1088 switch (ptype) {
1089 case MONO_TYPE_BOOLEAN:
1090 case MONO_TYPE_CHAR:
1091 case MONO_TYPE_I1:
1092 case MONO_TYPE_U1:
1093 case MONO_TYPE_I2:
1094 case MONO_TYPE_U2:
1095 case MONO_TYPE_I4:
1096 case MONO_TYPE_U4:
1097 case MONO_TYPE_I:
1098 case MONO_TYPE_U:
1099 case MONO_TYPE_PTR:
1100 case MONO_TYPE_SZARRAY:
1101 case MONO_TYPE_CLASS:
1102 case MONO_TYPE_OBJECT:
1103 case MONO_TYPE_STRING:
1104 case MONO_TYPE_VALUETYPE:
1105 case MONO_TYPE_GENERICINST:
1106 #if SIZEOF_VOID_P == 8
1107 case MONO_TYPE_I8:
1108 case MONO_TYPE_U8:
1109 #endif
1110 margs->ilen++;
1111 break;
1112 #if SIZEOF_VOID_P == 4
1113 case MONO_TYPE_I8:
1114 case MONO_TYPE_U8:
1115 #ifdef TARGET_ARM
1116 /* pairs begin at even registers */
1117 if (i8_align == 8 && margs->ilen & 1)
1118 margs->ilen++;
1119 #endif
1120 margs->ilen += 2;
1121 break;
1122 #endif
1123 case MONO_TYPE_R4:
1124 #if SIZEOF_VOID_P == 8
1125 case MONO_TYPE_R8:
1126 #endif
1127 margs->flen++;
1128 break;
1129 #if SIZEOF_VOID_P == 4
1130 case MONO_TYPE_R8:
1131 margs->flen += 2;
1132 break;
1133 #endif
1134 default:
1135 g_error ("build_args_from_sig: not implemented yet (1): 0x%x\n", ptype);
1139 if (margs->ilen > 0)
1140 margs->iargs = g_malloc0 (sizeof (gpointer) * margs->ilen);
1142 if (margs->flen > 0)
1143 margs->fargs = g_malloc0 (sizeof (double) * margs->flen);
1145 if (margs->ilen > INTERP_ICALL_TRAMP_IARGS)
1146 g_error ("build_args_from_sig: TODO, allocate gregs: %d\n", margs->ilen);
1148 if (margs->flen > INTERP_ICALL_TRAMP_FARGS)
1149 g_error ("build_args_from_sig: TODO, allocate fregs: %d\n", margs->flen);
1152 size_t int_i = 0;
1153 size_t int_f = 0;
1155 if (sig->hasthis) {
1156 margs->iargs [0] = frame->stack_args->data.p;
1157 int_i++;
1160 for (int i = 0; i < sig->param_count; i++) {
1161 guint32 ptype = sig->params [i]->byref ? MONO_TYPE_PTR : sig->params [i]->type;
1162 switch (ptype) {
1163 case MONO_TYPE_BOOLEAN:
1164 case MONO_TYPE_CHAR:
1165 case MONO_TYPE_I1:
1166 case MONO_TYPE_U1:
1167 case MONO_TYPE_I2:
1168 case MONO_TYPE_U2:
1169 case MONO_TYPE_I4:
1170 case MONO_TYPE_U4:
1171 case MONO_TYPE_I:
1172 case MONO_TYPE_U:
1173 case MONO_TYPE_PTR:
1174 case MONO_TYPE_SZARRAY:
1175 case MONO_TYPE_CLASS:
1176 case MONO_TYPE_OBJECT:
1177 case MONO_TYPE_STRING:
1178 case MONO_TYPE_VALUETYPE:
1179 case MONO_TYPE_GENERICINST:
1180 #if SIZEOF_VOID_P == 8
1181 case MONO_TYPE_I8:
1182 case MONO_TYPE_U8:
1183 #endif
1184 margs->iargs [int_i] = frame->stack_args [i].data.p;
1185 #if DEBUG_INTERP
1186 g_print ("build_args_from_sig: margs->iargs [%d]: %p (frame @ %d)\n", int_i, margs->iargs [int_i], i);
1187 #endif
1188 int_i++;
1189 break;
1190 #if SIZEOF_VOID_P == 4
1191 case MONO_TYPE_I8:
1192 case MONO_TYPE_U8: {
1193 stackval *sarg = &frame->stack_args [i];
1194 #ifdef TARGET_ARM
1195 /* pairs begin at even registers */
1196 if (i8_align == 8 && int_i & 1)
1197 int_i++;
1198 #endif
1199 margs->iargs [int_i] = (gpointer) sarg->data.pair.lo;
1200 int_i++;
1201 margs->iargs [int_i] = (gpointer) sarg->data.pair.hi;
1202 #if DEBUG_INTERP
1203 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);
1204 #endif
1205 int_i++;
1206 break;
1208 #endif
1209 case MONO_TYPE_R4:
1210 case MONO_TYPE_R8:
1211 if (ptype == MONO_TYPE_R4)
1212 * (float *) &(margs->fargs [int_f]) = frame->stack_args [i].data.f_r4;
1213 else
1214 margs->fargs [int_f] = frame->stack_args [i].data.f;
1215 #if DEBUG_INTERP
1216 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);
1217 #endif
1218 #if SIZEOF_VOID_P == 4
1219 int_f += 2;
1220 #else
1221 int_f++;
1222 #endif
1223 break;
1224 default:
1225 g_error ("build_args_from_sig: not implemented yet (2): 0x%x\n", ptype);
1229 switch (sig->ret->type) {
1230 case MONO_TYPE_BOOLEAN:
1231 case MONO_TYPE_CHAR:
1232 case MONO_TYPE_I1:
1233 case MONO_TYPE_U1:
1234 case MONO_TYPE_I2:
1235 case MONO_TYPE_U2:
1236 case MONO_TYPE_I4:
1237 case MONO_TYPE_U4:
1238 case MONO_TYPE_I:
1239 case MONO_TYPE_U:
1240 case MONO_TYPE_PTR:
1241 case MONO_TYPE_SZARRAY:
1242 case MONO_TYPE_CLASS:
1243 case MONO_TYPE_OBJECT:
1244 case MONO_TYPE_STRING:
1245 case MONO_TYPE_I8:
1246 case MONO_TYPE_U8:
1247 case MONO_TYPE_VALUETYPE:
1248 case MONO_TYPE_GENERICINST:
1249 margs->retval = &(frame->retval->data.p);
1250 margs->is_float_ret = 0;
1251 break;
1252 case MONO_TYPE_R4:
1253 case MONO_TYPE_R8:
1254 margs->retval = &(frame->retval->data.p);
1255 margs->is_float_ret = 1;
1256 break;
1257 case MONO_TYPE_VOID:
1258 margs->retval = NULL;
1259 break;
1260 default:
1261 g_error ("build_args_from_sig: ret type not implemented yet: 0x%x\n", sig->ret->type);
1264 return margs;
1266 #endif
1268 static void
1269 interp_frame_arg_to_data (MonoInterpFrameHandle frame, MonoMethodSignature *sig, int index, gpointer data)
1271 InterpFrame *iframe = (InterpFrame*)frame;
1273 if (index == -1)
1274 stackval_to_data (sig->ret, iframe->retval, data, sig->pinvoke);
1275 else
1276 stackval_to_data (sig->params [index], &iframe->stack_args [index], data, sig->pinvoke);
1279 static void
1280 interp_data_to_frame_arg (MonoInterpFrameHandle frame, MonoMethodSignature *sig, int index, gpointer data)
1282 InterpFrame *iframe = (InterpFrame*)frame;
1284 if (index == -1)
1285 stackval_from_data (sig->ret, iframe->retval, data, sig->pinvoke);
1286 else if (sig->hasthis && index == 0)
1287 iframe->stack_args [index].data.p = *(gpointer*)data;
1288 else
1289 stackval_from_data (sig->params [index - sig->hasthis], &iframe->stack_args [index], data, sig->pinvoke);
1292 static gpointer
1293 interp_frame_arg_to_storage (MonoInterpFrameHandle frame, MonoMethodSignature *sig, int index)
1295 InterpFrame *iframe = (InterpFrame*)frame;
1297 if (index == -1)
1298 return stackval_to_data_addr (sig->ret, iframe->retval);
1299 else
1300 return stackval_to_data_addr (sig->params [index], &iframe->stack_args [index]);
1303 static void
1304 interp_frame_arg_set_storage (MonoInterpFrameHandle frame, MonoMethodSignature *sig, int index, gpointer storage)
1306 InterpFrame *iframe = (InterpFrame*)frame;
1307 stackval *val = (index == -1) ? iframe->retval : &iframe->stack_args [index];
1308 MonoType *type = (index == -1) ? sig->ret : sig->params [index];
1310 switch (type->type) {
1311 case MONO_TYPE_GENERICINST:
1312 if (!MONO_TYPE_IS_REFERENCE (type))
1313 val->data.vt = storage;
1314 break;
1315 case MONO_TYPE_VALUETYPE:
1316 val->data.vt = storage;
1317 break;
1318 default:
1319 g_assert_not_reached ();
1323 static MonoPIFunc
1324 get_interp_to_native_trampoline (void)
1326 static MonoPIFunc trampoline = NULL;
1328 if (!trampoline) {
1329 if (mono_ee_features.use_aot_trampolines) {
1330 trampoline = (MonoPIFunc) mono_aot_get_trampoline ("interp_to_native_trampoline");
1331 } else {
1332 MonoTrampInfo *info;
1333 trampoline = (MonoPIFunc) mono_arch_get_interp_to_native_trampoline (&info);
1334 mono_tramp_info_register (info, NULL);
1336 mono_memory_barrier ();
1338 return trampoline;
1341 static void
1342 interp_to_native_trampoline (gpointer addr, gpointer ccontext)
1344 get_interp_to_native_trampoline () (addr, ccontext);
1347 /* MONO_NO_OPTIMIATION is needed due to usage of INTERP_PUSH_LMF_WITH_CTX. */
1348 #ifdef _MSC_VER
1349 #pragma optimize ("", off)
1350 #endif
1351 static MONO_NO_OPTIMIZATION MONO_NEVER_INLINE void
1352 ves_pinvoke_method (InterpFrame *frame, MonoMethodSignature *sig, MonoFuncV addr, gboolean string_ctor, ThreadContext *context)
1354 MonoLMFExt ext;
1355 gpointer args;
1357 frame->ex = NULL;
1359 g_assert (!frame->imethod);
1361 static MonoPIFunc entry_func = NULL;
1362 if (!entry_func) {
1363 #ifdef MONO_ARCH_HAS_NO_PROPER_MONOCTX
1364 ERROR_DECL (error);
1365 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);
1366 mono_error_assert_ok (error);
1367 #else
1368 entry_func = get_interp_to_native_trampoline ();
1369 #endif
1370 mono_memory_barrier ();
1373 #ifdef MONO_ARCH_HAVE_INTERP_PINVOKE_TRAMP
1374 CallContext ccontext;
1375 mono_arch_set_native_call_context_args (&ccontext, frame, sig);
1376 args = &ccontext;
1377 #else
1378 InterpMethodArguments *margs = build_args_from_sig (sig, frame);
1379 args = margs;
1380 #endif
1382 INTERP_PUSH_LMF_WITH_CTX (frame, ext, exit_pinvoke);
1383 entry_func ((gpointer) addr, args);
1384 interp_pop_lmf (&ext);
1386 #ifdef MONO_ARCH_HAVE_INTERP_PINVOKE_TRAMP
1387 if (!frame->ex)
1388 mono_arch_get_native_call_context_ret (&ccontext, frame, sig);
1390 if (ccontext.stack != NULL)
1391 g_free (ccontext.stack);
1392 #else
1393 if (!frame->ex && !MONO_TYPE_ISSTRUCT (sig->ret))
1394 stackval_from_data (sig->ret, frame->retval, (char*)&frame->retval->data.p, sig->pinvoke);
1396 g_free (margs->iargs);
1397 g_free (margs->fargs);
1398 g_free (margs);
1399 #endif
1400 goto exit_pinvoke; // prevent unused label warning in some configurations
1401 exit_pinvoke:
1402 return;
1404 #ifdef _MSC_VER
1405 #pragma optimize ("", on)
1406 #endif
1409 * interp_init_delegate:
1411 * Initialize del->interp_method.
1413 static void
1414 interp_init_delegate (MonoDelegate *del, MonoError *error)
1416 MonoMethod *method;
1418 if (del->interp_method) {
1419 /* Delegate created by a call to ves_icall_mono_delegate_ctor_interp () */
1420 del->method = ((InterpMethod *)del->interp_method)->method;
1421 } else if (del->method) {
1422 /* Delegate created dynamically */
1423 del->interp_method = mono_interp_get_imethod (del->object.vtable->domain, del->method, error);
1424 } else {
1425 /* Created from JITted code */
1426 g_assert_not_reached ();
1429 method = ((InterpMethod*)del->interp_method)->method;
1430 if (del->target &&
1431 method &&
1432 method->flags & METHOD_ATTRIBUTE_VIRTUAL &&
1433 method->flags & METHOD_ATTRIBUTE_ABSTRACT &&
1434 mono_class_is_abstract (method->klass))
1435 del->interp_method = get_virtual_method ((InterpMethod*)del->interp_method, del->target);
1437 method = ((InterpMethod*)del->interp_method)->method;
1438 if (method && m_class_get_parent (method->klass) == mono_defaults.multicastdelegate_class) {
1439 const char *name = method->name;
1440 if (*name == 'I' && (strcmp (name, "Invoke") == 0)) {
1442 * When invoking the delegate interp_method is executed directly. If it's an
1443 * invoke make sure we replace it with the appropriate delegate invoke wrapper.
1445 * FIXME We should do this later, when we also know the delegate on which the
1446 * target method is called.
1448 del->interp_method = mono_interp_get_imethod (del->object.vtable->domain, mono_marshal_get_delegate_invoke (method, NULL), error);
1449 mono_error_assert_ok (error);
1453 if (!((InterpMethod *) del->interp_method)->transformed && method_is_dynamic (method)) {
1454 /* Return any errors from method compilation */
1455 mono_interp_transform_method ((InterpMethod *) del->interp_method, get_context (), error);
1456 return_if_nok (error);
1460 static void
1461 interp_delegate_ctor (MonoObjectHandle this_obj, MonoObjectHandle target, gpointer addr, MonoError *error)
1464 * addr is the result of an LDFTN opcode, i.e. an InterpMethod
1466 InterpMethod *imethod = (InterpMethod*)addr;
1468 if (!(imethod->method->flags & METHOD_ATTRIBUTE_STATIC)) {
1469 MonoMethod *invoke = mono_get_delegate_invoke_internal (mono_handle_class (this_obj));
1470 /* virtual invoke delegates must not have null check */
1471 if (mono_method_signature_internal (imethod->method)->param_count == mono_method_signature_internal (invoke)->param_count
1472 && MONO_HANDLE_IS_NULL (target)) {
1473 mono_error_set_argument (error, "this", "Delegate to an instance method cannot have null 'this'");
1474 return;
1478 g_assert (imethod->method);
1479 gpointer entry = mini_get_interp_callbacks ()->create_method_pointer (imethod->method, FALSE, error);
1480 return_if_nok (error);
1482 MONO_HANDLE_SETVAL (MONO_HANDLE_CAST (MonoDelegate, this_obj), interp_method, gpointer, imethod);
1484 mono_delegate_ctor (this_obj, target, entry, error);
1488 * From the spec:
1489 * runtime specifies that the implementation of the method is automatically
1490 * provided by the runtime and is primarily used for the methods of delegates.
1492 static MONO_NEVER_INLINE void
1493 ves_imethod (InterpFrame *frame, MonoMethod *method, MonoMethodSignature *sig, stackval *sp, stackval *retval)
1495 const char *name = method->name;
1496 mono_class_init_internal (method->klass);
1498 if (method->klass == mono_defaults.array_class) {
1499 if (!strcmp (name, "UnsafeMov")) {
1500 /* TODO: layout checks */
1501 stackval_from_data (sig->ret, retval, (char*) sp, FALSE);
1502 return;
1504 if (!strcmp (name, "UnsafeLoad")) {
1505 ves_array_get (frame, sp, retval, sig, FALSE);
1506 return;
1508 } else if (mini_class_is_system_array (method->klass)) {
1509 MonoObject *obj = (MonoObject*) sp->data.p;
1510 if (!obj) {
1511 frame->ex = mono_get_exception_null_reference ();
1512 return;
1514 if (*name == 'S' && (strcmp (name, "Set") == 0)) {
1515 ves_array_set (frame, sp, sig);
1516 return;
1518 if (*name == 'G' && (strcmp (name, "Get") == 0)) {
1519 ves_array_get (frame, sp, retval, sig, TRUE);
1520 return;
1524 g_error ("Don't know how to exec runtime method %s.%s::%s",
1525 m_class_get_name_space (method->klass), m_class_get_name (method->klass),
1526 method->name);
1529 #if DEBUG_INTERP
1530 static char*
1531 dump_stack (stackval *stack, stackval *sp)
1533 stackval *s = stack;
1534 GString *str = g_string_new ("");
1536 if (sp == stack)
1537 return g_string_free (str, FALSE);
1539 while (s < sp) {
1540 g_string_append_printf (str, "[%p (%lld)] ", s->data.l, s->data.l);
1541 ++s;
1543 return g_string_free (str, FALSE);
1546 static void
1547 dump_stackval (GString *str, stackval *s, MonoType *type)
1549 switch (type->type) {
1550 case MONO_TYPE_I1:
1551 case MONO_TYPE_U1:
1552 case MONO_TYPE_I2:
1553 case MONO_TYPE_U2:
1554 case MONO_TYPE_I4:
1555 case MONO_TYPE_U4:
1556 case MONO_TYPE_CHAR:
1557 case MONO_TYPE_BOOLEAN:
1558 g_string_append_printf (str, "[%d] ", s->data.i);
1559 break;
1560 case MONO_TYPE_STRING:
1561 case MONO_TYPE_SZARRAY:
1562 case MONO_TYPE_CLASS:
1563 case MONO_TYPE_OBJECT:
1564 case MONO_TYPE_ARRAY:
1565 case MONO_TYPE_PTR:
1566 case MONO_TYPE_I:
1567 case MONO_TYPE_U:
1568 g_string_append_printf (str, "[%p] ", s->data.p);
1569 break;
1570 case MONO_TYPE_VALUETYPE:
1571 if (m_class_is_enumtype (type->data.klass))
1572 g_string_append_printf (str, "[%d] ", s->data.i);
1573 else
1574 g_string_append_printf (str, "[vt:%p] ", s->data.p);
1575 break;
1576 case MONO_TYPE_R4:
1577 g_string_append_printf (str, "[%g] ", s->data.f_r4);
1578 break;
1579 case MONO_TYPE_R8:
1580 g_string_append_printf (str, "[%g] ", s->data.f);
1581 break;
1582 case MONO_TYPE_I8:
1583 case MONO_TYPE_U8:
1584 default: {
1585 GString *res = g_string_new ("");
1586 mono_type_get_desc (res, type, TRUE);
1587 g_string_append_printf (str, "[{%s} %lld/0x%0llx] ", res->str, s->data.l, s->data.l);
1588 g_string_free (res, TRUE);
1589 break;
1594 static char*
1595 dump_retval (InterpFrame *inv)
1597 GString *str = g_string_new ("");
1598 MonoType *ret = mono_method_signature_internal (inv->imethod->method)->ret;
1600 if (ret->type != MONO_TYPE_VOID)
1601 dump_stackval (str, inv->retval, ret);
1603 return g_string_free (str, FALSE);
1606 static char*
1607 dump_args (InterpFrame *inv)
1609 GString *str = g_string_new ("");
1610 int i;
1611 MonoMethodSignature *signature = mono_method_signature_internal (inv->imethod->method);
1613 if (signature->param_count == 0 && !signature->hasthis)
1614 return g_string_free (str, FALSE);
1616 if (signature->hasthis) {
1617 MonoMethod *method = inv->imethod->method;
1618 dump_stackval (str, inv->stack_args, m_class_get_byval_arg (method->klass));
1621 for (i = 0; i < signature->param_count; ++i)
1622 dump_stackval (str, inv->stack_args + (!!signature->hasthis) + i, signature->params [i]);
1624 return g_string_free (str, FALSE);
1626 #endif
1628 #define CHECK_ADD_OVERFLOW(a,b) \
1629 (gint32)(b) >= 0 ? (gint32)(G_MAXINT32) - (gint32)(b) < (gint32)(a) ? -1 : 0 \
1630 : (gint32)(G_MININT32) - (gint32)(b) > (gint32)(a) ? +1 : 0
1632 #define CHECK_SUB_OVERFLOW(a,b) \
1633 (gint32)(b) < 0 ? (gint32)(G_MAXINT32) + (gint32)(b) < (gint32)(a) ? -1 : 0 \
1634 : (gint32)(G_MININT32) + (gint32)(b) > (gint32)(a) ? +1 : 0
1636 #define CHECK_ADD_OVERFLOW_UN(a,b) \
1637 (guint32)(G_MAXUINT32) - (guint32)(b) < (guint32)(a) ? -1 : 0
1639 #define CHECK_SUB_OVERFLOW_UN(a,b) \
1640 (guint32)(a) < (guint32)(b) ? -1 : 0
1642 #define CHECK_ADD_OVERFLOW64(a,b) \
1643 (gint64)(b) >= 0 ? (gint64)(G_MAXINT64) - (gint64)(b) < (gint64)(a) ? -1 : 0 \
1644 : (gint64)(G_MININT64) - (gint64)(b) > (gint64)(a) ? +1 : 0
1646 #define CHECK_SUB_OVERFLOW64(a,b) \
1647 (gint64)(b) < 0 ? (gint64)(G_MAXINT64) + (gint64)(b) < (gint64)(a) ? -1 : 0 \
1648 : (gint64)(G_MININT64) + (gint64)(b) > (gint64)(a) ? +1 : 0
1650 #define CHECK_ADD_OVERFLOW64_UN(a,b) \
1651 (guint64)(G_MAXUINT64) - (guint64)(b) < (guint64)(a) ? -1 : 0
1653 #define CHECK_SUB_OVERFLOW64_UN(a,b) \
1654 (guint64)(a) < (guint64)(b) ? -1 : 0
1656 #if SIZEOF_VOID_P == 4
1657 #define CHECK_ADD_OVERFLOW_NAT(a,b) CHECK_ADD_OVERFLOW(a,b)
1658 #define CHECK_ADD_OVERFLOW_NAT_UN(a,b) CHECK_ADD_OVERFLOW_UN(a,b)
1659 #else
1660 #define CHECK_ADD_OVERFLOW_NAT(a,b) CHECK_ADD_OVERFLOW64(a,b)
1661 #define CHECK_ADD_OVERFLOW_NAT_UN(a,b) CHECK_ADD_OVERFLOW64_UN(a,b)
1662 #endif
1664 /* Resolves to TRUE if the operands would overflow */
1665 #define CHECK_MUL_OVERFLOW(a,b) \
1666 ((gint32)(a) == 0) || ((gint32)(b) == 0) ? 0 : \
1667 (((gint32)(a) > 0) && ((gint32)(b) == -1)) ? FALSE : \
1668 (((gint32)(a) < 0) && ((gint32)(b) == -1)) ? (a == G_MININT32) : \
1669 (((gint32)(a) > 0) && ((gint32)(b) > 0)) ? (gint32)(a) > ((G_MAXINT32) / (gint32)(b)) : \
1670 (((gint32)(a) > 0) && ((gint32)(b) < 0)) ? (gint32)(a) > ((G_MININT32) / (gint32)(b)) : \
1671 (((gint32)(a) < 0) && ((gint32)(b) > 0)) ? (gint32)(a) < ((G_MININT32) / (gint32)(b)) : \
1672 (gint32)(a) < ((G_MAXINT32) / (gint32)(b))
1674 #define CHECK_MUL_OVERFLOW_UN(a,b) \
1675 ((guint32)(a) == 0) || ((guint32)(b) == 0) ? 0 : \
1676 (guint32)(b) > ((G_MAXUINT32) / (guint32)(a))
1678 #define CHECK_MUL_OVERFLOW64(a,b) \
1679 ((gint64)(a) == 0) || ((gint64)(b) == 0) ? 0 : \
1680 (((gint64)(a) > 0) && ((gint64)(b) == -1)) ? FALSE : \
1681 (((gint64)(a) < 0) && ((gint64)(b) == -1)) ? (a == G_MININT64) : \
1682 (((gint64)(a) > 0) && ((gint64)(b) > 0)) ? (gint64)(a) > ((G_MAXINT64) / (gint64)(b)) : \
1683 (((gint64)(a) > 0) && ((gint64)(b) < 0)) ? (gint64)(a) > ((G_MININT64) / (gint64)(b)) : \
1684 (((gint64)(a) < 0) && ((gint64)(b) > 0)) ? (gint64)(a) < ((G_MININT64) / (gint64)(b)) : \
1685 (gint64)(a) < ((G_MAXINT64) / (gint64)(b))
1687 #define CHECK_MUL_OVERFLOW64_UN(a,b) \
1688 ((guint64)(a) == 0) || ((guint64)(b) == 0) ? 0 : \
1689 (guint64)(b) > ((G_MAXUINT64) / (guint64)(a))
1691 #if SIZEOF_VOID_P == 4
1692 #define CHECK_MUL_OVERFLOW_NAT(a,b) CHECK_MUL_OVERFLOW(a,b)
1693 #define CHECK_MUL_OVERFLOW_NAT_UN(a,b) CHECK_MUL_OVERFLOW_UN(a,b)
1694 #else
1695 #define CHECK_MUL_OVERFLOW_NAT(a,b) CHECK_MUL_OVERFLOW64(a,b)
1696 #define CHECK_MUL_OVERFLOW_NAT_UN(a,b) CHECK_MUL_OVERFLOW64_UN(a,b)
1697 #endif
1699 static MonoObject*
1700 interp_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError *error)
1702 InterpFrame frame;
1703 ThreadContext *context = get_context ();
1704 MonoMethodSignature *sig = mono_method_signature_internal (method);
1705 MonoClass *klass = mono_class_from_mono_type_internal (sig->ret);
1706 stackval result;
1707 MonoMethod *target_method = method;
1709 error_init (error);
1710 if (exc)
1711 *exc = NULL;
1713 frame.ex = NULL;
1715 MonoDomain *domain = mono_domain_get ();
1717 if (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
1718 target_method = mono_marshal_get_native_wrapper (target_method, FALSE, FALSE);
1719 MonoMethod *invoke_wrapper = mono_marshal_get_runtime_invoke_full (target_method, FALSE, TRUE);
1721 //* <code>MonoObject *runtime_invoke (MonoObject *this_obj, void **params, MonoObject **exc, void* method)</code>
1723 result.data.vt = alloca (mono_class_instance_size (klass));
1724 stackval args [4];
1726 if (sig->hasthis)
1727 args [0].data.p = obj;
1728 else
1729 args [0].data.p = NULL;
1730 args [1].data.p = params;
1731 args [2].data.p = exc;
1732 args [3].data.p = target_method;
1734 INIT_FRAME (&frame, NULL, args, &result, domain, invoke_wrapper, error);
1736 if (exc)
1737 frame.invoke_trap = 1;
1739 interp_exec_method (&frame, context);
1741 if (frame.ex) {
1742 if (exc) {
1743 *exc = (MonoObject*) frame.ex;
1744 return NULL;
1746 mono_error_set_exception_instance (error, frame.ex);
1747 return NULL;
1749 return (MonoObject*)result.data.p;
1752 typedef struct {
1753 InterpMethod *rmethod;
1754 gpointer this_arg;
1755 gpointer res;
1756 gpointer args [16];
1757 gpointer *many_args;
1758 } InterpEntryData;
1760 /* Main function for entering the interpreter from compiled code */
1761 static void
1762 interp_entry (InterpEntryData *data)
1764 InterpFrame frame;
1765 InterpMethod *rmethod;
1766 ThreadContext *context;
1767 stackval result;
1768 stackval *args;
1769 MonoMethod *method;
1770 MonoMethodSignature *sig;
1771 MonoType *type;
1772 gpointer orig_domain = NULL, attach_cookie;
1773 int i;
1775 if ((gsize)data->rmethod & 1) {
1776 /* Unbox */
1777 data->this_arg = mono_object_unbox_internal ((MonoObject*)data->this_arg);
1778 data->rmethod = (InterpMethod*)(gpointer)((gsize)data->rmethod & ~1);
1780 rmethod = data->rmethod;
1782 if (rmethod->needs_thread_attach)
1783 orig_domain = mono_threads_attach_coop (mono_domain_get (), &attach_cookie);
1785 context = get_context ();
1787 method = rmethod->method;
1788 sig = mono_method_signature_internal (method);
1790 // FIXME: Optimize this
1792 //printf ("%s\n", mono_method_full_name (method, 1));
1794 frame.ex = NULL;
1796 args = g_newa (stackval, sig->param_count + (sig->hasthis ? 1 : 0));
1797 if (sig->hasthis)
1798 args [0].data.p = data->this_arg;
1800 gpointer *params;
1801 if (data->many_args)
1802 params = data->many_args;
1803 else
1804 params = data->args;
1805 for (i = 0; i < sig->param_count; ++i) {
1806 int a_index = i + (sig->hasthis ? 1 : 0);
1807 if (sig->params [i]->byref) {
1808 args [a_index].data.p = params [i];
1809 continue;
1811 type = rmethod->param_types [i];
1812 switch (type->type) {
1813 case MONO_TYPE_VALUETYPE:
1814 args [a_index].data.p = params [i];
1815 break;
1816 case MONO_TYPE_GENERICINST:
1817 if (MONO_TYPE_IS_REFERENCE (type))
1818 args [a_index].data.p = *(gpointer*)params [i];
1819 else
1820 args [a_index].data.vt = params [i];
1821 break;
1822 default:
1823 stackval_from_data (type, &args [a_index], params [i], FALSE);
1824 break;
1828 memset (&result, 0, sizeof (result));
1829 init_frame (&frame, NULL, data->rmethod, args, &result);
1831 type = rmethod->rtype;
1832 switch (type->type) {
1833 case MONO_TYPE_GENERICINST:
1834 if (!MONO_TYPE_IS_REFERENCE (type))
1835 frame.retval->data.vt = data->res;
1836 break;
1837 case MONO_TYPE_VALUETYPE:
1838 frame.retval->data.vt = data->res;
1839 break;
1840 default:
1841 break;
1844 interp_exec_method (&frame, context);
1846 if (rmethod->needs_thread_attach)
1847 mono_threads_detach_coop (orig_domain, &attach_cookie);
1849 if (mono_llvm_only) {
1850 if (frame.ex)
1851 mono_llvm_reraise_exception (frame.ex);
1852 } else {
1853 g_assert (frame.ex == NULL);
1856 type = rmethod->rtype;
1857 switch (type->type) {
1858 case MONO_TYPE_VOID:
1859 break;
1860 case MONO_TYPE_OBJECT:
1861 /* No need for a write barrier */
1862 *(MonoObject**)data->res = (MonoObject*)frame.retval->data.p;
1863 break;
1864 case MONO_TYPE_GENERICINST:
1865 if (MONO_TYPE_IS_REFERENCE (type)) {
1866 *(MonoObject**)data->res = (MonoObject*)frame.retval->data.p;
1867 } else {
1868 /* Already set before the call */
1870 break;
1871 case MONO_TYPE_VALUETYPE:
1872 /* Already set before the call */
1873 break;
1874 default:
1875 stackval_to_data (type, frame.retval, data->res, FALSE);
1876 break;
1880 static stackval *
1881 do_icall (InterpFrame *frame, MonoMethodSignature *sig, int op, stackval *sp, gpointer ptr)
1883 switch (op) {
1884 case MINT_ICALL_V_V: {
1885 typedef void (*T)(void);
1886 T func = (T)ptr;
1887 func ();
1888 break;
1890 case MINT_ICALL_V_P: {
1891 typedef gpointer (*T)(void);
1892 T func = (T)ptr;
1893 sp++;
1894 sp [-1].data.p = func ();
1895 break;
1897 case MINT_ICALL_P_V: {
1898 typedef void (*T)(gpointer);
1899 T func = (T)ptr;
1900 func (sp [-1].data.p);
1901 sp --;
1902 break;
1904 case MINT_ICALL_P_P: {
1905 typedef gpointer (*T)(gpointer);
1906 T func = (T)ptr;
1907 sp [-1].data.p = func (sp [-1].data.p);
1908 break;
1910 case MINT_ICALL_PP_V: {
1911 typedef void (*T)(gpointer,gpointer);
1912 T func = (T)ptr;
1913 sp -= 2;
1914 func (sp [0].data.p, sp [1].data.p);
1915 break;
1917 case MINT_ICALL_PP_P: {
1918 typedef gpointer (*T)(gpointer,gpointer);
1919 T func = (T)ptr;
1920 --sp;
1921 sp [-1].data.p = func (sp [-1].data.p, sp [0].data.p);
1922 break;
1924 case MINT_ICALL_PPP_V: {
1925 typedef void (*T)(gpointer,gpointer,gpointer);
1926 T func = (T)ptr;
1927 sp -= 3;
1928 func (sp [0].data.p, sp [1].data.p, sp [2].data.p);
1929 break;
1931 case MINT_ICALL_PPP_P: {
1932 typedef gpointer (*T)(gpointer,gpointer,gpointer);
1933 T func = (T)ptr;
1934 sp -= 2;
1935 sp [-1].data.p = func (sp [-1].data.p, sp [0].data.p, sp [1].data.p);
1936 break;
1938 case MINT_ICALL_PPPP_V: {
1939 typedef void (*T)(gpointer,gpointer,gpointer,gpointer);
1940 T func = (T)ptr;
1941 sp -= 4;
1942 func (sp [0].data.p, sp [1].data.p, sp [2].data.p, sp [3].data.p);
1943 break;
1945 case MINT_ICALL_PPPP_P: {
1946 typedef gpointer (*T)(gpointer,gpointer,gpointer,gpointer);
1947 T func = (T)ptr;
1948 sp -= 3;
1949 sp [-1].data.p = func (sp [-1].data.p, sp [0].data.p, sp [1].data.p, sp [2].data.p);
1950 break;
1952 case MINT_ICALL_PPPPP_V: {
1953 typedef void (*T)(gpointer,gpointer,gpointer,gpointer,gpointer);
1954 T func = (T)ptr;
1955 sp -= 5;
1956 func (sp [0].data.p, sp [1].data.p, sp [2].data.p, sp [3].data.p, sp [4].data.p);
1957 break;
1959 case MINT_ICALL_PPPPP_P: {
1960 typedef gpointer (*T)(gpointer,gpointer,gpointer,gpointer,gpointer);
1961 T func = (T)ptr;
1962 sp -= 4;
1963 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);
1964 break;
1966 case MINT_ICALL_PPPPPP_V: {
1967 typedef void (*T)(gpointer,gpointer,gpointer,gpointer,gpointer,gpointer);
1968 T func = (T)ptr;
1969 sp -= 6;
1970 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);
1971 break;
1973 case MINT_ICALL_PPPPPP_P: {
1974 typedef gpointer (*T)(gpointer,gpointer,gpointer,gpointer,gpointer,gpointer);
1975 T func = (T)ptr;
1976 sp -= 5;
1977 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);
1978 break;
1980 default:
1981 g_assert_not_reached ();
1984 /* convert the native representation to the stackval representation */
1985 if (sig)
1986 stackval_from_data (sig->ret, &sp [-1], (char*) &sp [-1].data.p, sig->pinvoke);
1988 return sp;
1991 /* MONO_NO_OPTIMIATION is needed due to usage of INTERP_PUSH_LMF_WITH_CTX. */
1992 #ifdef _MSC_VER
1993 #pragma optimize ("", off)
1994 #endif
1995 static MONO_NO_OPTIMIZATION MONO_NEVER_INLINE stackval *
1996 do_icall_wrapper (InterpFrame *frame, MonoMethodSignature *sig, int op, stackval *sp, gpointer ptr)
1998 MonoLMFExt ext;
1999 INTERP_PUSH_LMF_WITH_CTX (frame, ext, exit_icall);
2001 sp = do_icall (frame, sig, op, sp, ptr);
2003 interp_pop_lmf (&ext);
2005 goto exit_icall; // prevent unused label warning in some configurations
2006 exit_icall:
2007 return sp;
2009 #ifdef _MSC_VER
2010 #pragma optimize ("", on)
2011 #endif
2013 typedef struct {
2014 int pindex;
2015 gpointer jit_wrapper;
2016 gpointer *args;
2017 MonoFtnDesc *ftndesc;
2018 } JitCallCbData;
2020 static void
2021 jit_call_cb (gpointer arg)
2023 JitCallCbData *cb_data = (JitCallCbData*)arg;
2024 gpointer jit_wrapper = cb_data->jit_wrapper;
2025 int pindex = cb_data->pindex;
2026 gpointer *args = cb_data->args;
2027 MonoFtnDesc ftndesc = *cb_data->ftndesc;
2029 switch (pindex) {
2030 case 0: {
2031 typedef void (*T)(gpointer);
2032 T func = (T)jit_wrapper;
2034 func (&ftndesc);
2035 break;
2037 case 1: {
2038 typedef void (*T)(gpointer, gpointer);
2039 T func = (T)jit_wrapper;
2041 func (args [0], &ftndesc);
2042 break;
2044 case 2: {
2045 typedef void (*T)(gpointer, gpointer, gpointer);
2046 T func = (T)jit_wrapper;
2048 func (args [0], args [1], &ftndesc);
2049 break;
2051 case 3: {
2052 typedef void (*T)(gpointer, gpointer, gpointer, gpointer);
2053 T func = (T)jit_wrapper;
2055 func (args [0], args [1], args [2], &ftndesc);
2056 break;
2058 case 4: {
2059 typedef void (*T)(gpointer, gpointer, gpointer, gpointer, gpointer);
2060 T func = (T)jit_wrapper;
2062 func (args [0], args [1], args [2], args [3], &ftndesc);
2063 break;
2065 case 5: {
2066 typedef void (*T)(gpointer, gpointer, gpointer, gpointer, gpointer, gpointer);
2067 T func = (T)jit_wrapper;
2069 func (args [0], args [1], args [2], args [3], args [4], &ftndesc);
2070 break;
2072 case 6: {
2073 typedef void (*T)(gpointer, gpointer, gpointer, gpointer, gpointer, gpointer, gpointer);
2074 T func = (T)jit_wrapper;
2076 func (args [0], args [1], args [2], args [3], args [4], args [5], &ftndesc);
2077 break;
2079 case 7: {
2080 typedef void (*T)(gpointer, gpointer, gpointer, gpointer, gpointer, gpointer, gpointer, gpointer);
2081 T func = (T)jit_wrapper;
2083 func (args [0], args [1], args [2], args [3], args [4], args [5], args [6], &ftndesc);
2084 break;
2086 case 8: {
2087 typedef void (*T)(gpointer, gpointer, gpointer, gpointer, gpointer, gpointer, gpointer, gpointer, gpointer);
2088 T func = (T)jit_wrapper;
2090 func (args [0], args [1], args [2], args [3], args [4], args [5], args [6], args [7], &ftndesc);
2091 break;
2093 default:
2094 g_assert_not_reached ();
2095 break;
2099 static MONO_NEVER_INLINE stackval *
2100 do_jit_call (stackval *sp, unsigned char *vt_sp, ThreadContext *context, InterpFrame *frame, InterpMethod *rmethod, MonoError *error)
2102 MonoMethodSignature *sig;
2103 MonoFtnDesc ftndesc;
2104 guint8 res_buf [256];
2105 MonoType *type;
2106 MonoLMFExt ext;
2108 //printf ("jit_call: %s\n", mono_method_full_name (rmethod->method, 1));
2111 * Call JITted code through a gsharedvt_out wrapper. These wrappers receive every argument
2112 * by ref and return a return value using an explicit return value argument.
2114 if (!rmethod->jit_wrapper) {
2115 MonoMethod *method = rmethod->method;
2117 sig = mono_method_signature_internal (method);
2118 g_assert (sig);
2120 MonoMethod *wrapper = mini_get_gsharedvt_out_sig_wrapper (sig);
2121 //printf ("J: %s %s\n", mono_method_full_name (method, 1), mono_method_full_name (wrapper, 1));
2123 gpointer jit_wrapper = mono_jit_compile_method_jit_only (wrapper, error);
2124 mono_error_assert_ok (error);
2126 gpointer addr = mono_jit_compile_method_jit_only (method, error);
2127 return_val_if_nok (error, NULL);
2128 g_assert (addr);
2130 rmethod->jit_addr = addr;
2131 rmethod->jit_sig = sig;
2132 mono_memory_barrier ();
2133 rmethod->jit_wrapper = jit_wrapper;
2135 } else {
2136 sig = rmethod->jit_sig;
2139 sp -= sig->param_count;
2140 if (sig->hasthis)
2141 --sp;
2143 ftndesc.addr = rmethod->jit_addr;
2144 ftndesc.arg = NULL;
2146 // FIXME: Optimize this
2148 gpointer args [32];
2149 int pindex = 0;
2150 int stack_index = 0;
2151 if (rmethod->hasthis) {
2152 args [pindex ++] = sp [0].data.p;
2153 stack_index ++;
2155 type = rmethod->rtype;
2156 if (type->type != MONO_TYPE_VOID) {
2157 if (MONO_TYPE_ISSTRUCT (type))
2158 args [pindex ++] = vt_sp;
2159 else
2160 args [pindex ++] = res_buf;
2162 for (int i = 0; i < rmethod->param_count; ++i) {
2163 MonoType *t = rmethod->param_types [i];
2164 stackval *sval = &sp [stack_index + i];
2165 if (sig->params [i]->byref) {
2166 args [pindex ++] = sval->data.p;
2167 } else if (MONO_TYPE_ISSTRUCT (t)) {
2168 args [pindex ++] = sval->data.p;
2169 } else if (MONO_TYPE_IS_REFERENCE (t)) {
2170 args [pindex ++] = &sval->data.p;
2171 } else {
2172 switch (t->type) {
2173 case MONO_TYPE_I1:
2174 case MONO_TYPE_U1:
2175 case MONO_TYPE_I2:
2176 case MONO_TYPE_U2:
2177 case MONO_TYPE_I4:
2178 case MONO_TYPE_U4:
2179 case MONO_TYPE_VALUETYPE:
2180 args [pindex ++] = &sval->data.i;
2181 break;
2182 case MONO_TYPE_PTR:
2183 case MONO_TYPE_FNPTR:
2184 case MONO_TYPE_I:
2185 case MONO_TYPE_U:
2186 case MONO_TYPE_OBJECT:
2187 args [pindex ++] = &sval->data.p;
2188 break;
2189 case MONO_TYPE_I8:
2190 case MONO_TYPE_U8:
2191 args [pindex ++] = &sval->data.l;
2192 break;
2193 case MONO_TYPE_R4:
2194 args [pindex ++] = &sval->data.f_r4;
2195 break;
2196 case MONO_TYPE_R8:
2197 args [pindex ++] = &sval->data.f;
2198 break;
2199 default:
2200 printf ("%s\n", mono_type_full_name (t));
2201 g_assert_not_reached ();
2206 interp_push_lmf (&ext, frame);
2208 JitCallCbData cb_data;
2209 memset (&cb_data, 0, sizeof (cb_data));
2210 cb_data.jit_wrapper = rmethod->jit_wrapper;
2211 cb_data.pindex = pindex;
2212 cb_data.args = args;
2213 cb_data.ftndesc = &ftndesc;
2215 if (mono_aot_mode == MONO_AOT_MODE_LLVMONLY_INTERP) {
2216 /* Catch the exception thrown by the native code using a try-catch */
2217 gboolean thrown = FALSE;
2218 mono_llvm_cpp_catch_exception (jit_call_cb, &cb_data, &thrown);
2219 interp_pop_lmf (&ext);
2220 if (thrown) {
2221 MonoObject *obj = mono_llvm_load_exception ();
2222 g_assert (obj);
2223 mono_error_set_exception_instance (error, (MonoException*)obj);
2224 return sp;
2226 } else {
2227 jit_call_cb (&cb_data);
2228 interp_pop_lmf (&ext);
2231 MonoType *rtype = rmethod->rtype;
2232 switch (rtype->type) {
2233 case MONO_TYPE_VOID:
2234 case MONO_TYPE_OBJECT:
2235 case MONO_TYPE_STRING:
2236 case MONO_TYPE_CLASS:
2237 case MONO_TYPE_ARRAY:
2238 case MONO_TYPE_SZARRAY:
2239 case MONO_TYPE_I:
2240 case MONO_TYPE_U:
2241 case MONO_TYPE_PTR:
2242 sp->data.p = *(gpointer*)res_buf;
2243 break;
2244 case MONO_TYPE_I1:
2245 sp->data.i = *(gint8*)res_buf;
2246 break;
2247 case MONO_TYPE_U1:
2248 sp->data.i = *(guint8*)res_buf;
2249 break;
2250 case MONO_TYPE_I2:
2251 sp->data.i = *(gint16*)res_buf;
2252 break;
2253 case MONO_TYPE_U2:
2254 sp->data.i = *(guint16*)res_buf;
2255 break;
2256 case MONO_TYPE_I4:
2257 sp->data.i = *(gint32*)res_buf;
2258 break;
2259 case MONO_TYPE_U4:
2260 sp->data.i = *(guint32*)res_buf;
2261 break;
2262 case MONO_TYPE_I8:
2263 sp->data.l = *(gint64*)res_buf;
2264 break;
2265 case MONO_TYPE_U8:
2266 sp->data.l = *(guint64*)res_buf;
2267 break;
2268 case MONO_TYPE_R4:
2269 sp->data.f_r4 = *(float*)res_buf;
2270 break;
2271 case MONO_TYPE_R8:
2272 sp->data.f = *(double*)res_buf;
2273 break;
2274 case MONO_TYPE_TYPEDBYREF:
2275 case MONO_TYPE_VALUETYPE:
2276 /* The result was written to vt_sp */
2277 sp->data.p = vt_sp;
2278 break;
2279 case MONO_TYPE_GENERICINST:
2280 if (MONO_TYPE_IS_REFERENCE (rtype)) {
2281 sp->data.p = *(gpointer*)res_buf;
2282 } else {
2283 /* The result was written to vt_sp */
2284 sp->data.p = vt_sp;
2286 break;
2287 default:
2288 g_print ("%s\n", mono_type_full_name (rtype));
2289 g_assert_not_reached ();
2290 break;
2293 return sp;
2296 static MONO_NEVER_INLINE void
2297 do_debugger_tramp (void (*tramp) (void), InterpFrame *frame)
2299 MonoLMFExt ext;
2300 interp_push_lmf (&ext, frame);
2301 tramp ();
2302 interp_pop_lmf (&ext);
2305 static MONO_NEVER_INLINE void
2306 do_transform_method (InterpFrame *frame, ThreadContext *context)
2308 MonoLMFExt ext;
2309 /* Don't push lmf if we have no interp data */
2310 gboolean push_lmf = frame->parent != NULL;
2311 ERROR_DECL (error);
2313 /* Use the parent frame as the current frame is not complete yet */
2314 if (push_lmf)
2315 interp_push_lmf (&ext, frame->parent);
2317 mono_interp_transform_method (frame->imethod, context, error);
2318 frame->ex = mono_error_convert_to_exception (error);
2320 if (push_lmf)
2321 interp_pop_lmf (&ext);
2324 static void
2325 copy_varargs_vtstack (MonoMethodSignature *csig, stackval *sp, unsigned char **vt_sp)
2327 char *vt = *(char**)vt_sp;
2328 stackval *first_arg = sp - csig->param_count;
2331 * We need to have the varargs linearly on the stack so the ArgIterator
2332 * can iterate over them. We pass the signature first and then copy them
2333 * one by one on the vtstack.
2335 *(gpointer*)vt = csig;
2336 vt += sizeof (gpointer);
2338 for (int i = csig->sentinelpos; i < csig->param_count; i++) {
2339 int align, arg_size;
2340 arg_size = mono_type_stack_size (csig->params [i], &align);
2341 vt = (char*)ALIGN_PTR_TO (vt, align);
2343 stackval_to_data (csig->params [i], &first_arg [i], vt, FALSE);
2344 vt += arg_size;
2347 vt = (char*)ALIGN_PTR_TO (vt, MINT_VT_ALIGNMENT);
2349 *(char**)vt_sp = vt;
2353 * These functions are the entry points into the interpreter from compiled code.
2354 * They are called by the interp_in wrappers. They have the following signature:
2355 * void (<optional this_arg>, <optional retval pointer>, <arg1>, ..., <argn>, <method ptr>)
2356 * They pack up their arguments into an InterpEntryData structure and call interp_entry ().
2357 * It would be possible for the wrappers to pack up the arguments etc, but that would make them bigger, and there are
2358 * more wrappers then these functions.
2359 * this/static * ret/void * 16 arguments -> 64 functions.
2362 #define MAX_INTERP_ENTRY_ARGS 8
2364 #define INTERP_ENTRY_BASE(_method, _this_arg, _res) \
2365 InterpEntryData data; \
2366 (data).rmethod = (_method); \
2367 (data).res = (_res); \
2368 (data).this_arg = (_this_arg); \
2369 (data).many_args = NULL;
2371 #define INTERP_ENTRY0(_this_arg, _res, _method) { \
2372 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2373 interp_entry (&data); \
2375 #define INTERP_ENTRY1(_this_arg, _res, _method) { \
2376 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2377 (data).args [0] = arg1; \
2378 interp_entry (&data); \
2380 #define INTERP_ENTRY2(_this_arg, _res, _method) { \
2381 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2382 (data).args [0] = arg1; \
2383 (data).args [1] = arg2; \
2384 interp_entry (&data); \
2386 #define INTERP_ENTRY3(_this_arg, _res, _method) { \
2387 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2388 (data).args [0] = arg1; \
2389 (data).args [1] = arg2; \
2390 (data).args [2] = arg3; \
2391 interp_entry (&data); \
2393 #define INTERP_ENTRY4(_this_arg, _res, _method) { \
2394 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2395 (data).args [0] = arg1; \
2396 (data).args [1] = arg2; \
2397 (data).args [2] = arg3; \
2398 (data).args [3] = arg4; \
2399 interp_entry (&data); \
2401 #define INTERP_ENTRY5(_this_arg, _res, _method) { \
2402 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2403 (data).args [0] = arg1; \
2404 (data).args [1] = arg2; \
2405 (data).args [2] = arg3; \
2406 (data).args [3] = arg4; \
2407 (data).args [4] = arg5; \
2408 interp_entry (&data); \
2410 #define INTERP_ENTRY6(_this_arg, _res, _method) { \
2411 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2412 (data).args [0] = arg1; \
2413 (data).args [1] = arg2; \
2414 (data).args [2] = arg3; \
2415 (data).args [3] = arg4; \
2416 (data).args [4] = arg5; \
2417 (data).args [5] = arg6; \
2418 interp_entry (&data); \
2420 #define INTERP_ENTRY7(_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 (data).args [4] = arg5; \
2427 (data).args [5] = arg6; \
2428 (data).args [6] = arg7; \
2429 interp_entry (&data); \
2431 #define INTERP_ENTRY8(_this_arg, _res, _method) { \
2432 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2433 (data).args [0] = arg1; \
2434 (data).args [1] = arg2; \
2435 (data).args [2] = arg3; \
2436 (data).args [3] = arg4; \
2437 (data).args [4] = arg5; \
2438 (data).args [5] = arg6; \
2439 (data).args [6] = arg7; \
2440 (data).args [7] = arg8; \
2441 interp_entry (&data); \
2444 #define ARGLIST0 InterpMethod *rmethod
2445 #define ARGLIST1 gpointer arg1, InterpMethod *rmethod
2446 #define ARGLIST2 gpointer arg1, gpointer arg2, InterpMethod *rmethod
2447 #define ARGLIST3 gpointer arg1, gpointer arg2, gpointer arg3, InterpMethod *rmethod
2448 #define ARGLIST4 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, InterpMethod *rmethod
2449 #define ARGLIST5 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, gpointer arg5, InterpMethod *rmethod
2450 #define ARGLIST6 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, gpointer arg5, gpointer arg6, InterpMethod *rmethod
2451 #define ARGLIST7 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, gpointer arg5, gpointer arg6, gpointer arg7, InterpMethod *rmethod
2452 #define ARGLIST8 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, gpointer arg5, gpointer arg6, gpointer arg7, gpointer arg8, InterpMethod *rmethod
2454 static void interp_entry_static_0 (ARGLIST0) INTERP_ENTRY0 (NULL, NULL, rmethod)
2455 static void interp_entry_static_1 (ARGLIST1) INTERP_ENTRY1 (NULL, NULL, rmethod)
2456 static void interp_entry_static_2 (ARGLIST2) INTERP_ENTRY2 (NULL, NULL, rmethod)
2457 static void interp_entry_static_3 (ARGLIST3) INTERP_ENTRY3 (NULL, NULL, rmethod)
2458 static void interp_entry_static_4 (ARGLIST4) INTERP_ENTRY4 (NULL, NULL, rmethod)
2459 static void interp_entry_static_5 (ARGLIST5) INTERP_ENTRY5 (NULL, NULL, rmethod)
2460 static void interp_entry_static_6 (ARGLIST6) INTERP_ENTRY6 (NULL, NULL, rmethod)
2461 static void interp_entry_static_7 (ARGLIST7) INTERP_ENTRY7 (NULL, NULL, rmethod)
2462 static void interp_entry_static_8 (ARGLIST8) INTERP_ENTRY8 (NULL, NULL, rmethod)
2463 static void interp_entry_static_ret_0 (gpointer res, ARGLIST0) INTERP_ENTRY0 (NULL, res, rmethod)
2464 static void interp_entry_static_ret_1 (gpointer res, ARGLIST1) INTERP_ENTRY1 (NULL, res, rmethod)
2465 static void interp_entry_static_ret_2 (gpointer res, ARGLIST2) INTERP_ENTRY2 (NULL, res, rmethod)
2466 static void interp_entry_static_ret_3 (gpointer res, ARGLIST3) INTERP_ENTRY3 (NULL, res, rmethod)
2467 static void interp_entry_static_ret_4 (gpointer res, ARGLIST4) INTERP_ENTRY4 (NULL, res, rmethod)
2468 static void interp_entry_static_ret_5 (gpointer res, ARGLIST5) INTERP_ENTRY5 (NULL, res, rmethod)
2469 static void interp_entry_static_ret_6 (gpointer res, ARGLIST6) INTERP_ENTRY6 (NULL, res, rmethod)
2470 static void interp_entry_static_ret_7 (gpointer res, ARGLIST7) INTERP_ENTRY7 (NULL, res, rmethod)
2471 static void interp_entry_static_ret_8 (gpointer res, ARGLIST8) INTERP_ENTRY8 (NULL, res, rmethod)
2472 static void interp_entry_instance_0 (gpointer this_arg, ARGLIST0) INTERP_ENTRY0 (this_arg, NULL, rmethod)
2473 static void interp_entry_instance_1 (gpointer this_arg, ARGLIST1) INTERP_ENTRY1 (this_arg, NULL, rmethod)
2474 static void interp_entry_instance_2 (gpointer this_arg, ARGLIST2) INTERP_ENTRY2 (this_arg, NULL, rmethod)
2475 static void interp_entry_instance_3 (gpointer this_arg, ARGLIST3) INTERP_ENTRY3 (this_arg, NULL, rmethod)
2476 static void interp_entry_instance_4 (gpointer this_arg, ARGLIST4) INTERP_ENTRY4 (this_arg, NULL, rmethod)
2477 static void interp_entry_instance_5 (gpointer this_arg, ARGLIST5) INTERP_ENTRY5 (this_arg, NULL, rmethod)
2478 static void interp_entry_instance_6 (gpointer this_arg, ARGLIST6) INTERP_ENTRY6 (this_arg, NULL, rmethod)
2479 static void interp_entry_instance_7 (gpointer this_arg, ARGLIST7) INTERP_ENTRY7 (this_arg, NULL, rmethod)
2480 static void interp_entry_instance_8 (gpointer this_arg, ARGLIST8) INTERP_ENTRY8 (this_arg, NULL, rmethod)
2481 static void interp_entry_instance_ret_0 (gpointer this_arg, gpointer res, ARGLIST0) INTERP_ENTRY0 (this_arg, res, rmethod)
2482 static void interp_entry_instance_ret_1 (gpointer this_arg, gpointer res, ARGLIST1) INTERP_ENTRY1 (this_arg, res, rmethod)
2483 static void interp_entry_instance_ret_2 (gpointer this_arg, gpointer res, ARGLIST2) INTERP_ENTRY2 (this_arg, res, rmethod)
2484 static void interp_entry_instance_ret_3 (gpointer this_arg, gpointer res, ARGLIST3) INTERP_ENTRY3 (this_arg, res, rmethod)
2485 static void interp_entry_instance_ret_4 (gpointer this_arg, gpointer res, ARGLIST4) INTERP_ENTRY4 (this_arg, res, rmethod)
2486 static void interp_entry_instance_ret_5 (gpointer this_arg, gpointer res, ARGLIST5) INTERP_ENTRY5 (this_arg, res, rmethod)
2487 static void interp_entry_instance_ret_6 (gpointer this_arg, gpointer res, ARGLIST6) INTERP_ENTRY6 (this_arg, res, rmethod)
2488 static void interp_entry_instance_ret_7 (gpointer this_arg, gpointer res, ARGLIST7) INTERP_ENTRY7 (this_arg, res, rmethod)
2489 static void interp_entry_instance_ret_8 (gpointer this_arg, gpointer res, ARGLIST8) INTERP_ENTRY8 (this_arg, res, rmethod)
2491 #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
2493 static gpointer entry_funcs_static [MAX_INTERP_ENTRY_ARGS + 1] = { INTERP_ENTRY_FUNCLIST (static) };
2494 static gpointer entry_funcs_static_ret [MAX_INTERP_ENTRY_ARGS + 1] = { INTERP_ENTRY_FUNCLIST (static_ret) };
2495 static gpointer entry_funcs_instance [MAX_INTERP_ENTRY_ARGS + 1] = { INTERP_ENTRY_FUNCLIST (instance) };
2496 static gpointer entry_funcs_instance_ret [MAX_INTERP_ENTRY_ARGS + 1] = { INTERP_ENTRY_FUNCLIST (instance_ret) };
2498 /* General version for methods with more than MAX_INTERP_ENTRY_ARGS arguments */
2499 static void
2500 interp_entry_general (gpointer this_arg, gpointer res, gpointer *args, gpointer rmethod)
2502 INTERP_ENTRY_BASE ((InterpMethod*)rmethod, this_arg, res);
2503 data.many_args = args;
2504 interp_entry (&data);
2507 #ifdef MONO_ARCH_HAVE_INTERP_ENTRY_TRAMPOLINE
2509 // inline so we can alloc on stack
2510 #define alloc_storage_for_stackval(s, t, p) do { \
2511 if ((t)->type == MONO_TYPE_GENERICINST && !MONO_TYPE_IS_REFERENCE (t)) { \
2512 (s)->data.vt = alloca (mono_class_value_size (mono_class_from_mono_type_internal (t), NULL)); \
2513 } else if ((t)->type == MONO_TYPE_VALUETYPE) { \
2514 if (p) \
2515 (s)->data.vt = alloca (mono_class_native_size ((t)->data.klass, NULL)); \
2516 else \
2517 (s)->data.vt = alloca (mono_class_value_size ((t)->data.klass, NULL)); \
2519 } while (0)
2521 static void
2522 interp_entry_from_trampoline (gpointer ccontext_untyped, gpointer rmethod_untyped)
2524 InterpFrame frame;
2525 ThreadContext *context;
2526 stackval result;
2527 stackval *args;
2528 MonoMethod *method;
2529 MonoMethodSignature *sig;
2530 CallContext *ccontext = (CallContext*) ccontext_untyped;
2531 InterpMethod *rmethod = (InterpMethod*) rmethod_untyped;
2532 gpointer orig_domain = NULL, attach_cookie;
2533 int i;
2535 if (rmethod->needs_thread_attach)
2536 orig_domain = mono_threads_attach_coop (mono_domain_get (), &attach_cookie);
2538 context = get_context ();
2540 method = rmethod->method;
2541 sig = mono_method_signature_internal (method);
2543 frame.ex = NULL;
2545 args = (stackval*)alloca (sizeof (stackval) * (sig->param_count + (sig->hasthis ? 1 : 0)));
2547 init_frame (&frame, NULL, rmethod, args, &result);
2549 /* Allocate storage for value types */
2550 for (i = 0; i < sig->param_count; i++) {
2551 MonoType *type = sig->params [i];
2552 alloc_storage_for_stackval (&frame.stack_args [i + sig->hasthis], type, sig->pinvoke);
2555 if (sig->ret->type != MONO_TYPE_VOID)
2556 alloc_storage_for_stackval (frame.retval, sig->ret, sig->pinvoke);
2558 /* Copy the args saved in the trampoline to the frame stack */
2559 mono_arch_get_native_call_context_args (ccontext, &frame, sig);
2561 interp_exec_method (&frame, context);
2563 if (rmethod->needs_thread_attach)
2564 mono_threads_detach_coop (orig_domain, &attach_cookie);
2566 // FIXME:
2567 g_assert (frame.ex == NULL);
2569 /* Write back the return value */
2570 mono_arch_set_native_call_context_ret (ccontext, &frame, sig);
2573 #else
2575 static void
2576 interp_entry_from_trampoline (gpointer ccontext_untyped, gpointer rmethod_untyped)
2578 g_assert_not_reached ();
2581 #endif /* MONO_ARCH_HAVE_INTERP_ENTRY_TRAMPOLINE */
2583 static InterpMethod*
2584 lookup_method_pointer (gpointer addr)
2586 MonoDomain *domain = mono_domain_get ();
2587 MonoJitDomainInfo *info = domain_jit_info (domain);
2588 InterpMethod *res = NULL;
2590 mono_domain_lock (domain);
2591 if (info->interp_method_pointer_hash)
2592 res = (InterpMethod*)g_hash_table_lookup (info->interp_method_pointer_hash, addr);
2593 mono_domain_unlock (domain);
2595 return res;
2598 #ifndef MONO_ARCH_HAVE_INTERP_NATIVE_TO_MANAGED
2599 static void
2600 interp_no_native_to_managed (void)
2602 g_error ("interpreter: native-to-managed transition not available on this platform");
2604 #endif
2606 static void
2607 no_llvmonly_interp_method_pointer (void)
2609 g_assert_not_reached ();
2613 * interp_create_method_pointer_llvmonly:
2615 * Return an ftndesc for entering the interpreter and executing METHOD.
2617 static MonoFtnDesc*
2618 interp_create_method_pointer_llvmonly (MonoMethod *method, gboolean unbox, MonoError *error)
2620 MonoDomain *domain = mono_domain_get ();
2621 gpointer addr, entry_func, entry_wrapper;
2622 MonoMethodSignature *sig;
2623 MonoMethod *wrapper;
2624 MonoJitDomainInfo *info;
2625 InterpMethod *imethod;
2627 imethod = mono_interp_get_imethod (domain, method, error);
2628 return_val_if_nok (error, NULL);
2630 if (unbox) {
2631 if (imethod->llvmonly_unbox_entry)
2632 return (MonoFtnDesc*)imethod->llvmonly_unbox_entry;
2633 } else {
2634 if (imethod->jit_entry)
2635 return (MonoFtnDesc*)imethod->jit_entry;
2638 sig = mono_method_signature_internal (method);
2641 * The entry functions need access to the method to call, so we have
2642 * to use a ftndesc. The caller uses a normal signature, while the
2643 * entry functions use a gsharedvt_in signature, so wrap the entry function in
2644 * a gsharedvt_in_sig wrapper.
2646 wrapper = mini_get_gsharedvt_in_sig_wrapper (sig);
2648 entry_wrapper = mono_jit_compile_method_jit_only (wrapper, error);
2649 mono_error_assertf_ok (error, "couldn't compile wrapper \"%s\" for \"%s\"",
2650 mono_method_get_name_full (wrapper, TRUE, TRUE, MONO_TYPE_NAME_FORMAT_IL),
2651 mono_method_get_name_full (method, TRUE, TRUE, MONO_TYPE_NAME_FORMAT_IL));
2653 if (sig->param_count > MAX_INTERP_ENTRY_ARGS) {
2654 g_assert_not_reached ();
2655 //entry_func = (gpointer)interp_entry_general;
2656 } else if (sig->hasthis) {
2657 if (sig->ret->type == MONO_TYPE_VOID)
2658 entry_func = entry_funcs_instance [sig->param_count];
2659 else
2660 entry_func = entry_funcs_instance_ret [sig->param_count];
2661 } else {
2662 if (sig->ret->type == MONO_TYPE_VOID)
2663 entry_func = entry_funcs_static [sig->param_count];
2664 else
2665 entry_func = entry_funcs_static_ret [sig->param_count];
2667 g_assert (entry_func);
2669 /* Encode unbox in the lower bit of imethod */
2670 gpointer entry_arg = imethod;
2671 if (unbox)
2672 entry_arg = (gpointer)(((gsize)entry_arg) | 1);
2673 MonoFtnDesc *entry_ftndesc = mini_llvmonly_create_ftndesc (mono_domain_get (), entry_func, entry_arg);
2675 addr = mini_llvmonly_create_ftndesc (mono_domain_get (), entry_wrapper, entry_ftndesc);
2677 info = domain_jit_info (domain);
2678 mono_domain_lock (domain);
2679 if (!info->interp_method_pointer_hash)
2680 info->interp_method_pointer_hash = g_hash_table_new (NULL, NULL);
2681 g_hash_table_insert (info->interp_method_pointer_hash, addr, imethod);
2682 mono_domain_unlock (domain);
2684 mono_memory_barrier ();
2685 if (unbox)
2686 imethod->llvmonly_unbox_entry = addr;
2687 else
2688 imethod->jit_entry = addr;
2690 return (MonoFtnDesc*)addr;
2694 * interp_create_method_pointer:
2696 * Return a function pointer which can be used to call METHOD using the
2697 * interpreter. Return NULL for methods which are not supported.
2699 static gpointer
2700 interp_create_method_pointer (MonoMethod *method, gboolean compile, MonoError *error)
2702 #ifndef MONO_ARCH_HAVE_INTERP_NATIVE_TO_MANAGED
2703 if (mono_llvm_only)
2704 return (gpointer)no_llvmonly_interp_method_pointer;
2705 return (gpointer)interp_no_native_to_managed;
2706 #else
2707 gpointer addr, entry_func, entry_wrapper = NULL;
2708 MonoDomain *domain = mono_domain_get ();
2709 MonoJitDomainInfo *info;
2710 InterpMethod *imethod = mono_interp_get_imethod (domain, method, error);
2712 if (mono_llvm_only)
2713 return (gpointer)no_llvmonly_interp_method_pointer;
2715 if (imethod->jit_entry)
2716 return imethod->jit_entry;
2718 if (compile && !imethod->transformed) {
2719 /* Return any errors from method compilation */
2720 mono_interp_transform_method (imethod, get_context (), error);
2721 return_val_if_nok (error, NULL);
2724 MonoMethodSignature *sig = mono_method_signature_internal (method);
2726 if (mono_llvm_only)
2727 /* The caller should call interp_create_method_pointer_llvmonly */
2728 g_assert_not_reached ();
2730 if (method->wrapper_type && method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE)
2731 return imethod;
2733 #ifndef MONO_ARCH_HAVE_FTNPTR_ARG_TRAMPOLINE
2735 * Interp in wrappers get the argument in the rgctx register. If
2736 * MONO_ARCH_HAVE_FTNPTR_ARG_TRAMPOLINE is defined it means that
2737 * on that arch the rgctx register is not scratch, so we use a
2738 * separate temp register. We should update the wrappers for this
2739 * if we really care about those architectures (arm).
2741 MonoMethod *wrapper = mini_get_interp_in_wrapper (sig);
2743 entry_wrapper = mono_jit_compile_method_jit_only (wrapper, error);
2744 #endif
2745 if (entry_wrapper) {
2746 if (sig->param_count > MAX_INTERP_ENTRY_ARGS) {
2747 entry_func = (gpointer)interp_entry_general;
2748 } else if (sig->hasthis) {
2749 if (sig->ret->type == MONO_TYPE_VOID)
2750 entry_func = entry_funcs_instance [sig->param_count];
2751 else
2752 entry_func = entry_funcs_instance_ret [sig->param_count];
2753 } else {
2754 if (sig->ret->type == MONO_TYPE_VOID)
2755 entry_func = entry_funcs_static [sig->param_count];
2756 else
2757 entry_func = entry_funcs_static_ret [sig->param_count];
2759 } else {
2760 #ifndef MONO_ARCH_HAVE_INTERP_ENTRY_TRAMPOLINE
2761 mono_error_assertf_ok (error, "couldn't compile wrapper \"%s\" for \"%s\"",
2762 mono_method_get_name_full (wrapper, TRUE, TRUE, MONO_TYPE_NAME_FORMAT_IL),
2763 mono_method_get_name_full (method, TRUE, TRUE, MONO_TYPE_NAME_FORMAT_IL));
2764 #else
2765 mono_error_cleanup (error);
2766 error_init_reuse (error);
2767 if (!mono_native_to_interp_trampoline) {
2768 if (mono_aot_only) {
2769 mono_native_to_interp_trampoline = (MonoFuncV)mono_aot_get_trampoline ("native_to_interp_trampoline");
2770 } else {
2771 MonoTrampInfo *info;
2772 mono_native_to_interp_trampoline = (MonoFuncV)mono_arch_get_native_to_interp_trampoline (&info);
2773 mono_tramp_info_register (info, NULL);
2776 entry_wrapper = (gpointer)mono_native_to_interp_trampoline;
2777 /* We need the lmf wrapper only when being called from mixed mode */
2778 if (sig->pinvoke)
2779 entry_func = (gpointer)interp_entry_from_trampoline;
2780 else {
2781 static gpointer cached_func = NULL;
2782 if (!cached_func) {
2783 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);
2784 mono_memory_barrier ();
2786 entry_func = cached_func;
2788 #endif
2791 g_assert (entry_func);
2792 /* This is the argument passed to the interp_in wrapper by the static rgctx trampoline */
2793 MonoFtnDesc *ftndesc = g_new0 (MonoFtnDesc, 1);
2794 ftndesc->addr = entry_func;
2795 ftndesc->arg = imethod;
2796 mono_error_assert_ok (error);
2799 * The wrapper is called by compiled code, which doesn't pass the extra argument, so we pass it in the
2800 * rgctx register using a trampoline.
2803 addr = mono_create_ftnptr_arg_trampoline (ftndesc, entry_wrapper);
2805 info = domain_jit_info (domain);
2806 mono_domain_lock (domain);
2807 if (!info->interp_method_pointer_hash)
2808 info->interp_method_pointer_hash = g_hash_table_new (NULL, NULL);
2809 g_hash_table_insert (info->interp_method_pointer_hash, addr, imethod);
2810 mono_domain_unlock (domain);
2812 mono_memory_barrier ();
2813 imethod->jit_entry = addr;
2815 return addr;
2816 #endif
2819 #if COUNT_OPS
2820 static int opcode_counts[512];
2822 #define COUNT_OP(op) opcode_counts[op]++
2823 #else
2824 #define COUNT_OP(op)
2825 #endif
2827 #if DEBUG_INTERP
2828 #define DUMP_INSTR() \
2829 if (tracing > 1) { \
2830 char *ins; \
2831 if (sp > frame->stack) { \
2832 ins = dump_stack (frame->stack, sp); \
2833 } else { \
2834 ins = g_strdup (""); \
2836 sp->data.l = 0; \
2837 output_indent (); \
2838 char *mn = mono_method_full_name (frame->imethod->method, FALSE); \
2839 char *disasm = mono_interp_dis_mintop(imethod->code, ip); \
2840 g_print ("(%p) %s -> %s\t%d:%s\n", mono_thread_internal_current (), mn, disasm, vt_sp - vtalloc, ins); \
2841 g_free (mn); \
2842 g_free (ins); \
2843 g_free (disasm); \
2845 #else
2846 #define DUMP_INSTR()
2847 #endif
2849 #if defined(__GNUC__) && !defined(TARGET_WASM)
2850 #define USE_COMPUTED_GOTO 1
2851 #endif
2852 #if USE_COMPUTED_GOTO
2853 #define MINT_IN_SWITCH(op) COUNT_OP(op); goto *in_labels[op];
2854 #define MINT_IN_CASE(x) LAB_ ## x:
2855 #if DEBUG_INTERP
2856 #define MINT_IN_BREAK if (tracing > 1) goto main_loop; else { COUNT_OP(*ip); goto *in_labels[*ip]; }
2857 #else
2858 #define MINT_IN_BREAK { COUNT_OP(*ip); goto *in_labels[*ip]; }
2859 #endif
2860 #define MINT_IN_DEFAULT mint_default: if (0) goto mint_default; /* make gcc shut up */
2861 #else
2862 #define MINT_IN_SWITCH(op) switch (op)
2863 #define MINT_IN_CASE(x) case x:
2864 #define MINT_IN_BREAK break
2865 #define MINT_IN_DEFAULT default:
2866 #endif
2868 #define INIT_VTABLE(vtable) do { \
2869 if (G_UNLIKELY (!(vtable)->initialized)) { \
2870 mono_runtime_class_init_full ((vtable), error); \
2871 if (!mono_error_ok (error)) \
2872 THROW_EX (mono_error_convert_to_exception (error), ip); \
2874 } while (0);
2877 * If EXIT_AT_FINALLY is not -1, exit after exiting the finally clause with that index.
2878 * If BASE_FRAME is not NULL, copy arguments/locals from BASE_FRAME.
2880 static void
2881 interp_exec_method_full (InterpFrame *frame, ThreadContext *context, FrameClauseArgs *clause_args)
2883 InterpFrame child_frame;
2884 GSList *finally_ips = NULL;
2885 const unsigned short *endfinally_ip = NULL;
2886 const unsigned short *ip = NULL;
2887 stackval *sp;
2888 InterpMethod *imethod = NULL;
2889 #if DEBUG_INTERP
2890 gint tracing = global_tracing;
2891 unsigned char *vtalloc;
2892 #else
2893 gint tracing = 0;
2894 #endif
2895 int i32;
2896 unsigned char *vt_sp;
2897 unsigned char *locals = NULL;
2898 ERROR_DECL (error);
2899 MonoObject *o = NULL;
2900 MonoClass *c;
2901 #if USE_COMPUTED_GOTO
2902 static void *in_labels[] = {
2903 #define OPDEF(a,b,c,d) \
2904 &&LAB_ ## a,
2905 #include "mintops.def"
2906 0 };
2907 #endif
2909 frame->ex = NULL;
2910 debug_enter (frame, &tracing);
2912 imethod = frame->imethod;
2913 if (!imethod->transformed) {
2914 #if DEBUG_INTERP
2915 char *mn = mono_method_full_name (imethod->method, TRUE);
2916 g_print ("(%p) Transforming %s\n", mono_thread_internal_current (), mn);
2917 g_free (mn);
2918 #endif
2920 frame->ip = NULL;
2921 do_transform_method (frame, context);
2922 if (frame->ex)
2923 THROW_EX (frame->ex, NULL);
2924 EXCEPTION_CHECKPOINT;
2927 if (!clause_args) {
2928 frame->args = g_newa (char, imethod->alloca_size);
2929 ip = imethod->code;
2930 } else {
2931 ip = clause_args->start_with_ip;
2932 if (clause_args->base_frame) {
2933 frame->args = g_newa (char, imethod->alloca_size);
2934 memcpy (frame->args, clause_args->base_frame->args, imethod->alloca_size);
2937 sp = frame->stack = (stackval *) (char *) frame->args;
2938 vt_sp = (unsigned char *) sp + imethod->stack_size;
2939 #if DEBUG_INTERP
2940 vtalloc = vt_sp;
2941 #endif
2942 locals = (unsigned char *) vt_sp + imethod->vt_stack_size;
2943 frame->locals = locals;
2944 child_frame.parent = frame;
2946 if (clause_args && clause_args->filter_exception) {
2947 sp->data.p = clause_args->filter_exception;
2948 sp++;
2951 //g_print ("(%p) Call %s\n", mono_thread_internal_current (), mono_method_get_full_name (frame->imethod->method));
2954 * using while (ip < end) may result in a 15% performance drop,
2955 * but it may be useful for debug
2957 while (1) {
2958 main_loop:
2959 /* g_assert (sp >= frame->stack); */
2960 /* g_assert(vt_sp - vtalloc <= imethod->vt_stack_size); */
2961 DUMP_INSTR();
2962 MINT_IN_SWITCH (*ip) {
2963 MINT_IN_CASE(MINT_INITLOCALS)
2964 memset (locals, 0, imethod->locals_size);
2965 ++ip;
2966 MINT_IN_BREAK;
2967 MINT_IN_CASE(MINT_NOP)
2968 ++ip;
2969 MINT_IN_BREAK;
2970 MINT_IN_CASE(MINT_NIY)
2971 g_error ("mint_niy: instruction not implemented yet. This shouldn't happen.");
2972 MINT_IN_BREAK;
2973 MINT_IN_CASE(MINT_BREAK)
2974 ++ip;
2975 do_debugger_tramp (mini_get_dbg_callbacks ()->user_break, frame);
2976 MINT_IN_BREAK;
2977 MINT_IN_CASE(MINT_BREAKPOINT)
2978 ++ip;
2979 mono_break ();
2980 MINT_IN_BREAK;
2981 MINT_IN_CASE(MINT_LDNULL)
2982 sp->data.p = NULL;
2983 ++ip;
2984 ++sp;
2985 MINT_IN_BREAK;
2986 MINT_IN_CASE(MINT_ARGLIST)
2987 g_assert (frame->varargs);
2988 sp->data.p = vt_sp;
2989 *(gpointer*)sp->data.p = frame->varargs;
2990 vt_sp += ALIGN_TO (sizeof (gpointer), MINT_VT_ALIGNMENT);
2991 ++ip;
2992 ++sp;
2993 MINT_IN_BREAK;
2994 MINT_IN_CASE(MINT_VTRESULT) {
2995 int ret_size = * (guint16 *)(ip + 1);
2996 unsigned char *ret_vt_sp = vt_sp;
2997 vt_sp -= READ32(ip + 2);
2998 if (ret_size > 0) {
2999 memmove (vt_sp, ret_vt_sp, ret_size);
3000 sp [-1].data.p = vt_sp;
3001 vt_sp += ALIGN_TO (ret_size, MINT_VT_ALIGNMENT);
3003 ip += 4;
3004 MINT_IN_BREAK;
3006 #define LDC(n) do { sp->data.i = (n); ++ip; ++sp; } while (0)
3007 MINT_IN_CASE(MINT_LDC_I4_M1)
3008 LDC(-1);
3009 MINT_IN_BREAK;
3010 MINT_IN_CASE(MINT_LDC_I4_0)
3011 LDC(0);
3012 MINT_IN_BREAK;
3013 MINT_IN_CASE(MINT_LDC_I4_1)
3014 LDC(1);
3015 MINT_IN_BREAK;
3016 MINT_IN_CASE(MINT_LDC_I4_2)
3017 LDC(2);
3018 MINT_IN_BREAK;
3019 MINT_IN_CASE(MINT_LDC_I4_3)
3020 LDC(3);
3021 MINT_IN_BREAK;
3022 MINT_IN_CASE(MINT_LDC_I4_4)
3023 LDC(4);
3024 MINT_IN_BREAK;
3025 MINT_IN_CASE(MINT_LDC_I4_5)
3026 LDC(5);
3027 MINT_IN_BREAK;
3028 MINT_IN_CASE(MINT_LDC_I4_6)
3029 LDC(6);
3030 MINT_IN_BREAK;
3031 MINT_IN_CASE(MINT_LDC_I4_7)
3032 LDC(7);
3033 MINT_IN_BREAK;
3034 MINT_IN_CASE(MINT_LDC_I4_8)
3035 LDC(8);
3036 MINT_IN_BREAK;
3037 MINT_IN_CASE(MINT_LDC_I4_S)
3038 sp->data.i = *(const short *)(ip + 1);
3039 ip += 2;
3040 ++sp;
3041 MINT_IN_BREAK;
3042 MINT_IN_CASE(MINT_LDC_I4)
3043 ++ip;
3044 sp->data.i = READ32 (ip);
3045 ip += 2;
3046 ++sp;
3047 MINT_IN_BREAK;
3048 MINT_IN_CASE(MINT_LDC_I8)
3049 ++ip;
3050 sp->data.l = READ64 (ip);
3051 ip += 4;
3052 ++sp;
3053 MINT_IN_BREAK;
3054 MINT_IN_CASE(MINT_LDC_I8_S)
3055 sp->data.l = *(const short *)(ip + 1);
3056 ip += 2;
3057 ++sp;
3058 MINT_IN_BREAK;
3059 MINT_IN_CASE(MINT_LDC_R4) {
3060 guint32 val;
3061 ++ip;
3062 val = READ32(ip);
3063 sp->data.f_r4 = * (float *)&val;
3064 ip += 2;
3065 ++sp;
3066 MINT_IN_BREAK;
3068 MINT_IN_CASE(MINT_LDC_R8)
3069 sp->data.l = READ64 (ip + 1); /* note union usage */
3070 ip += 5;
3071 ++sp;
3072 MINT_IN_BREAK;
3073 MINT_IN_CASE(MINT_DUP)
3074 sp [0] = sp[-1];
3075 ++sp;
3076 ++ip;
3077 MINT_IN_BREAK;
3078 MINT_IN_CASE(MINT_DUP_VT)
3079 i32 = READ32 (ip + 1);
3080 sp->data.p = vt_sp;
3081 memcpy(sp->data.p, sp [-1].data.p, i32);
3082 vt_sp += ALIGN_TO (i32, MINT_VT_ALIGNMENT);
3083 ++sp;
3084 ip += 3;
3085 MINT_IN_BREAK;
3086 MINT_IN_CASE(MINT_POP) {
3087 guint16 u16 = (* (guint16 *)(ip + 1)) + 1;
3088 if (u16 > 1)
3089 memmove (sp - u16, sp - 1, (u16 - 1) * sizeof (stackval));
3090 sp--;
3091 ip += 2;
3092 MINT_IN_BREAK;
3094 MINT_IN_CASE(MINT_JMP) {
3095 InterpMethod *new_method = (InterpMethod*)imethod->data_items [* (guint16 *)(ip + 1)];
3096 gboolean realloc_frame = new_method->alloca_size > imethod->alloca_size;
3098 if (imethod->prof_flags & MONO_PROFILER_CALL_INSTRUMENTATION_TAIL_CALL)
3099 MONO_PROFILER_RAISE (method_tail_call, (imethod->method, new_method->method));
3101 if (!new_method->transformed) {
3102 MONO_API_ERROR_INIT (error);
3104 frame->ip = ip;
3105 mono_interp_transform_method (new_method, context, error);
3106 frame->ex = mono_error_convert_to_exception (error);
3107 if (frame->ex)
3108 goto exit_frame;
3110 ip += 2;
3111 imethod = frame->imethod = new_method;
3113 * We allocate the stack frame from scratch and store the arguments in the
3114 * locals again since it's possible for the caller stack frame to be smaller
3115 * than the callee stack frame (at the interp level)
3117 if (realloc_frame) {
3118 frame->args = g_newa (char, imethod->alloca_size);
3119 memset (frame->args, 0, imethod->alloca_size);
3120 sp = frame->stack = (stackval *) frame->args;
3122 vt_sp = (unsigned char *) sp + imethod->stack_size;
3123 #if DEBUG_INTERP
3124 vtalloc = vt_sp;
3125 #endif
3126 locals = vt_sp + imethod->vt_stack_size;
3127 frame->locals = locals;
3128 ip = imethod->code;
3129 MINT_IN_BREAK;
3131 MINT_IN_CASE(MINT_CALLI) {
3132 MonoMethodSignature *csignature;
3133 stackval *endsp = sp;
3135 frame->ip = ip;
3137 csignature = (MonoMethodSignature*)imethod->data_items [* (guint16 *)(ip + 1)];
3138 ip += 2;
3139 --sp;
3140 --endsp;
3141 child_frame.imethod = (InterpMethod*)sp->data.p;
3143 sp->data.p = vt_sp;
3144 child_frame.retval = sp;
3145 /* decrement by the actual number of args */
3146 sp -= csignature->param_count;
3147 if (csignature->hasthis)
3148 --sp;
3149 child_frame.stack_args = sp;
3151 if (child_frame.imethod->method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) {
3152 child_frame.imethod = mono_interp_get_imethod (imethod->domain, mono_marshal_get_native_wrapper (child_frame.imethod->method, FALSE, FALSE), error);
3153 mono_error_cleanup (error); /* FIXME: don't swallow the error */
3156 if (csignature->hasthis) {
3157 MonoObject *this_arg = (MonoObject*)sp->data.p;
3159 if (m_class_is_valuetype (this_arg->vtable->klass)) {
3160 gpointer unboxed = mono_object_unbox_internal (this_arg);
3161 sp [0].data.p = unboxed;
3165 interp_exec_method (&child_frame, context);
3167 CHECK_RESUME_STATE (context);
3169 /* need to handle typedbyref ... */
3170 if (csignature->ret->type != MONO_TYPE_VOID) {
3171 *sp = *endsp;
3172 sp++;
3174 MINT_IN_BREAK;
3176 MINT_IN_CASE(MINT_CALLI_NAT_FAST) {
3177 gpointer target_ip = sp [-1].data.p;
3178 MonoMethodSignature *csignature = (MonoMethodSignature*)imethod->data_items [* (guint16 *)(ip + 1)];
3179 int opcode = *(guint16 *)(ip + 2);
3181 sp--;
3182 frame->ip = ip;
3184 sp = do_icall_wrapper (frame, csignature, opcode, sp, target_ip);
3185 EXCEPTION_CHECKPOINT;
3186 CHECK_RESUME_STATE (context);
3187 ip += 3;
3188 MINT_IN_BREAK;
3190 MINT_IN_CASE(MINT_CALLI_NAT) {
3191 MonoMethodSignature *csignature;
3192 stackval *endsp = sp;
3193 unsigned char *code = NULL;
3195 frame->ip = ip;
3197 csignature = (MonoMethodSignature*)imethod->data_items [* (guint16 *)(ip + 1)];
3198 ip += 2;
3199 --sp;
3200 --endsp;
3201 code = (guchar*)sp->data.p;
3202 child_frame.imethod = NULL;
3204 sp->data.p = vt_sp;
3205 child_frame.retval = sp;
3206 /* decrement by the actual number of args */
3207 sp -= csignature->param_count;
3208 if (csignature->hasthis)
3209 --sp;
3210 child_frame.stack_args = sp;
3211 if (imethod->method->dynamic && csignature->pinvoke) {
3212 MonoMarshalSpec **mspecs;
3213 MonoMethodPInvoke piinfo;
3214 MonoMethod *m;
3216 /* Pinvoke call is missing the wrapper. See mono_get_native_calli_wrapper */
3217 mspecs = g_new0 (MonoMarshalSpec*, csignature->param_count + 1);
3218 memset (&piinfo, 0, sizeof (piinfo));
3220 m = mono_marshal_get_native_func_wrapper (m_class_get_image (imethod->method->klass), csignature, &piinfo, mspecs, code);
3222 for (int i = csignature->param_count; i >= 0; i--)
3223 if (mspecs [i])
3224 mono_metadata_free_marshal_spec (mspecs [i]);
3225 g_free (mspecs);
3227 child_frame.imethod = mono_interp_get_imethod (imethod->domain, m, error);
3228 mono_error_cleanup (error); /* FIXME: don't swallow the error */
3230 interp_exec_method (&child_frame, context);
3231 } else {
3232 ves_pinvoke_method (&child_frame, csignature, (MonoFuncV) code, FALSE, context);
3235 CHECK_RESUME_STATE (context);
3237 /* need to handle typedbyref ... */
3238 if (csignature->ret->type != MONO_TYPE_VOID) {
3239 *sp = *endsp;
3240 sp++;
3242 MINT_IN_BREAK;
3244 MINT_IN_CASE(MINT_CALLVIRT_FAST)
3245 MINT_IN_CASE(MINT_VCALLVIRT_FAST) {
3246 MonoObject *this_arg;
3247 MonoClass *this_class;
3248 gboolean is_void = *ip == MINT_VCALLVIRT_FAST;
3249 InterpMethod *target_imethod;
3250 stackval *endsp = sp;
3251 int slot;
3253 // FIXME Have it handle also remoting calls and use a single opcode for virtual calls
3255 frame->ip = ip;
3257 target_imethod = (InterpMethod*)imethod->data_items [* (guint16 *)(ip + 1)];
3258 slot = *(gint16*)(ip + 2);
3259 ip += 3;
3260 sp->data.p = vt_sp;
3261 child_frame.retval = sp;
3263 /* decrement by the actual number of args */
3264 sp -= target_imethod->param_count + target_imethod->hasthis;
3265 child_frame.stack_args = sp;
3267 this_arg = (MonoObject*)sp->data.p;
3268 this_class = this_arg->vtable->klass;
3270 child_frame.imethod = get_virtual_method_fast (this_arg, target_imethod, slot);
3271 if (m_class_is_valuetype (this_class) && m_class_is_valuetype (child_frame.imethod->method->klass)) {
3272 /* unbox */
3273 gpointer unboxed = mono_object_unbox_internal (this_arg);
3274 sp [0].data.p = unboxed;
3277 interp_exec_method (&child_frame, context);
3279 CHECK_RESUME_STATE (context);
3281 if (!is_void) {
3282 /* need to handle typedbyref ... */
3283 *sp = *endsp;
3284 sp++;
3286 MINT_IN_BREAK;
3288 MINT_IN_CASE(MINT_CALL_VARARG) {
3289 stackval *endsp = sp;
3290 int num_varargs = 0;
3291 MonoMethodSignature *csig;
3293 frame->ip = ip;
3295 child_frame.imethod = (InterpMethod*)imethod->data_items [* (guint16 *)(ip + 1)];
3296 /* The real signature for vararg calls */
3297 csig = (MonoMethodSignature*) imethod->data_items [* (guint16*) (ip + 2)];
3298 /* Push all vararg arguments from normal sp to vt_sp together with the signature */
3299 num_varargs = csig->param_count - csig->sentinelpos;
3300 child_frame.varargs = (char*) vt_sp;
3301 copy_varargs_vtstack (csig, sp, &vt_sp);
3303 ip += 3;
3304 sp->data.p = vt_sp;
3305 child_frame.retval = sp;
3307 /* decrement by the actual number of args */
3308 sp -= child_frame.imethod->param_count + child_frame.imethod->hasthis + num_varargs;
3309 child_frame.stack_args = sp;
3311 interp_exec_method (&child_frame, context);
3313 CHECK_RESUME_STATE (context);
3315 if (csig->ret->type != MONO_TYPE_VOID) {
3316 *sp = *endsp;
3317 sp++;
3319 MINT_IN_BREAK;
3321 MINT_IN_CASE(MINT_CALL)
3322 MINT_IN_CASE(MINT_VCALL)
3323 MINT_IN_CASE(MINT_CALLVIRT)
3324 MINT_IN_CASE(MINT_VCALLVIRT) {
3325 gboolean is_void = *ip == MINT_VCALL || *ip == MINT_VCALLVIRT;
3326 gboolean is_virtual = *ip == MINT_CALLVIRT || *ip == MINT_VCALLVIRT;
3327 stackval *endsp = sp;
3329 frame->ip = ip;
3331 child_frame.imethod = (InterpMethod*)imethod->data_items [* (guint16 *)(ip + 1)];
3332 ip += 2;
3333 sp->data.p = vt_sp;
3334 child_frame.retval = sp;
3336 /* decrement by the actual number of args */
3337 sp -= child_frame.imethod->param_count + child_frame.imethod->hasthis;
3338 child_frame.stack_args = sp;
3340 if (is_virtual) {
3341 MonoObject *this_arg = (MonoObject*)sp->data.p;
3342 MonoClass *this_class = this_arg->vtable->klass;
3344 child_frame.imethod = get_virtual_method (child_frame.imethod, this_arg);
3345 if (m_class_is_valuetype (this_class) && m_class_is_valuetype (child_frame.imethod->method->klass)) {
3346 /* unbox */
3347 gpointer unboxed = mono_object_unbox_internal (this_arg);
3348 sp [0].data.p = unboxed;
3352 interp_exec_method (&child_frame, context);
3354 CHECK_RESUME_STATE (context);
3356 if (!is_void) {
3357 /* need to handle typedbyref ... */
3358 *sp = *endsp;
3359 sp++;
3361 MINT_IN_BREAK;
3363 MINT_IN_CASE(MINT_JIT_CALL) {
3364 InterpMethod *rmethod = (InterpMethod*)imethod->data_items [* (guint16 *)(ip + 1)];
3365 MONO_API_ERROR_INIT (error);
3366 frame->ip = ip;
3367 sp = do_jit_call (sp, vt_sp, context, frame, rmethod, error);
3368 if (!is_ok (error)) {
3369 MonoException *ex = mono_error_convert_to_exception (error);
3370 THROW_EX (ex, ip);
3372 ip += 2;
3374 CHECK_RESUME_STATE (context);
3376 if (rmethod->rtype->type != MONO_TYPE_VOID)
3377 sp++;
3379 MINT_IN_BREAK;
3381 MINT_IN_CASE(MINT_CALLRUN) {
3382 MonoMethod *target_method = (MonoMethod*) imethod->data_items [* (guint16 *)(ip + 1)];
3383 MonoMethodSignature *sig = (MonoMethodSignature*) imethod->data_items [* (guint16 *)(ip + 2)];
3384 stackval *retval;
3386 sp->data.p = vt_sp;
3387 retval = sp;
3389 sp -= sig->param_count;
3390 if (sig->hasthis)
3391 sp--;
3393 ves_imethod (frame, target_method, sig, sp, retval);
3394 if (frame->ex)
3395 THROW_EX (frame->ex, ip);
3397 if (sig->ret->type != MONO_TYPE_VOID) {
3398 *sp = *retval;
3399 sp++;
3401 ip += 3;
3402 MINT_IN_BREAK;
3404 MINT_IN_CASE(MINT_RET)
3405 --sp;
3406 *frame->retval = *sp;
3407 if (sp > frame->stack)
3408 g_warning ("ret: more values on stack: %d", sp-frame->stack);
3409 goto exit_frame;
3410 MINT_IN_CASE(MINT_RET_VOID)
3411 if (sp > frame->stack)
3412 g_warning ("ret.void: more values on stack: %d %s", sp-frame->stack, mono_method_full_name (imethod->method, TRUE));
3413 goto exit_frame;
3414 MINT_IN_CASE(MINT_RET_VT)
3415 i32 = READ32(ip + 1);
3416 --sp;
3417 memcpy(frame->retval->data.p, sp->data.p, i32);
3418 if (sp > frame->stack)
3419 g_warning ("ret.vt: more values on stack: %d", sp-frame->stack);
3420 goto exit_frame;
3421 MINT_IN_CASE(MINT_BR_S)
3422 ip += (short) *(ip + 1);
3423 MINT_IN_BREAK;
3424 MINT_IN_CASE(MINT_BR)
3425 ip += (gint32) READ32(ip + 1);
3426 MINT_IN_BREAK;
3427 #define ZEROP_S(datamem, op) \
3428 --sp; \
3429 if (sp->data.datamem op 0) \
3430 ip += * (gint16 *)(ip + 1); \
3431 else \
3432 ip += 2;
3434 #define ZEROP(datamem, op) \
3435 --sp; \
3436 if (sp->data.datamem op 0) \
3437 ip += (gint32)READ32(ip + 1); \
3438 else \
3439 ip += 3;
3441 MINT_IN_CASE(MINT_BRFALSE_I4_S)
3442 ZEROP_S(i, ==);
3443 MINT_IN_BREAK;
3444 MINT_IN_CASE(MINT_BRFALSE_I8_S)
3445 ZEROP_S(l, ==);
3446 MINT_IN_BREAK;
3447 MINT_IN_CASE(MINT_BRFALSE_R4_S)
3448 ZEROP_S(f_r4, ==);
3449 MINT_IN_BREAK;
3450 MINT_IN_CASE(MINT_BRFALSE_R8_S)
3451 ZEROP_S(f, ==);
3452 MINT_IN_BREAK;
3453 MINT_IN_CASE(MINT_BRFALSE_I4)
3454 ZEROP(i, ==);
3455 MINT_IN_BREAK;
3456 MINT_IN_CASE(MINT_BRFALSE_I8)
3457 ZEROP(l, ==);
3458 MINT_IN_BREAK;
3459 MINT_IN_CASE(MINT_BRFALSE_R4)
3460 ZEROP_S(f_r4, ==);
3461 MINT_IN_BREAK;
3462 MINT_IN_CASE(MINT_BRFALSE_R8)
3463 ZEROP_S(f, ==);
3464 MINT_IN_BREAK;
3465 MINT_IN_CASE(MINT_BRTRUE_I4_S)
3466 ZEROP_S(i, !=);
3467 MINT_IN_BREAK;
3468 MINT_IN_CASE(MINT_BRTRUE_I8_S)
3469 ZEROP_S(l, !=);
3470 MINT_IN_BREAK;
3471 MINT_IN_CASE(MINT_BRTRUE_R4_S)
3472 ZEROP_S(f_r4, !=);
3473 MINT_IN_BREAK;
3474 MINT_IN_CASE(MINT_BRTRUE_R8_S)
3475 ZEROP_S(f, !=);
3476 MINT_IN_BREAK;
3477 MINT_IN_CASE(MINT_BRTRUE_I4)
3478 ZEROP(i, !=);
3479 MINT_IN_BREAK;
3480 MINT_IN_CASE(MINT_BRTRUE_I8)
3481 ZEROP(l, !=);
3482 MINT_IN_BREAK;
3483 MINT_IN_CASE(MINT_BRTRUE_R4)
3484 ZEROP(f_r4, !=);
3485 MINT_IN_BREAK;
3486 MINT_IN_CASE(MINT_BRTRUE_R8)
3487 ZEROP(f, !=);
3488 MINT_IN_BREAK;
3489 #define CONDBR_S(cond) \
3490 sp -= 2; \
3491 if (cond) \
3492 ip += * (gint16 *)(ip + 1); \
3493 else \
3494 ip += 2;
3495 #define BRELOP_S(datamem, op) \
3496 CONDBR_S(sp[0].data.datamem op sp[1].data.datamem)
3498 #define CONDBR(cond) \
3499 sp -= 2; \
3500 if (cond) \
3501 ip += (gint32)READ32(ip + 1); \
3502 else \
3503 ip += 3;
3505 #define BRELOP(datamem, op) \
3506 CONDBR(sp[0].data.datamem op sp[1].data.datamem)
3508 MINT_IN_CASE(MINT_BEQ_I4_S)
3509 BRELOP_S(i, ==)
3510 MINT_IN_BREAK;
3511 MINT_IN_CASE(MINT_BEQ_I8_S)
3512 BRELOP_S(l, ==)
3513 MINT_IN_BREAK;
3514 MINT_IN_CASE(MINT_BEQ_R4_S)
3515 CONDBR_S(!isunordered (sp [0].data.f_r4, sp [1].data.f_r4) && sp[0].data.f_r4 == sp[1].data.f_r4)
3516 MINT_IN_BREAK;
3517 MINT_IN_CASE(MINT_BEQ_R8_S)
3518 CONDBR_S(!mono_isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f == sp[1].data.f)
3519 MINT_IN_BREAK;
3520 MINT_IN_CASE(MINT_BEQ_I4)
3521 BRELOP(i, ==)
3522 MINT_IN_BREAK;
3523 MINT_IN_CASE(MINT_BEQ_I8)
3524 BRELOP(l, ==)
3525 MINT_IN_BREAK;
3526 MINT_IN_CASE(MINT_BEQ_R4)
3527 CONDBR(!isunordered (sp [0].data.f_r4, sp [1].data.f_r4) && sp[0].data.f_r4 == sp[1].data.f_r4)
3528 MINT_IN_BREAK;
3529 MINT_IN_CASE(MINT_BEQ_R8)
3530 CONDBR(!mono_isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f == sp[1].data.f)
3531 MINT_IN_BREAK;
3532 MINT_IN_CASE(MINT_BGE_I4_S)
3533 BRELOP_S(i, >=)
3534 MINT_IN_BREAK;
3535 MINT_IN_CASE(MINT_BGE_I8_S)
3536 BRELOP_S(l, >=)
3537 MINT_IN_BREAK;
3538 MINT_IN_CASE(MINT_BGE_R4_S)
3539 CONDBR_S(!isunordered (sp [0].data.f_r4, sp [1].data.f_r4) && sp[0].data.f_r4 >= sp[1].data.f_r4)
3540 MINT_IN_BREAK;
3541 MINT_IN_CASE(MINT_BGE_R8_S)
3542 CONDBR_S(!mono_isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f >= sp[1].data.f)
3543 MINT_IN_BREAK;
3544 MINT_IN_CASE(MINT_BGE_I4)
3545 BRELOP(i, >=)
3546 MINT_IN_BREAK;
3547 MINT_IN_CASE(MINT_BGE_I8)
3548 BRELOP(l, >=)
3549 MINT_IN_BREAK;
3550 MINT_IN_CASE(MINT_BGE_R4)
3551 CONDBR(!isunordered (sp [0].data.f_r4, sp [1].data.f_r4) && sp[0].data.f_r4 >= sp[1].data.f_r4)
3552 MINT_IN_BREAK;
3553 MINT_IN_CASE(MINT_BGE_R8)
3554 CONDBR(!mono_isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f >= sp[1].data.f)
3555 MINT_IN_BREAK;
3556 MINT_IN_CASE(MINT_BGT_I4_S)
3557 BRELOP_S(i, >)
3558 MINT_IN_BREAK;
3559 MINT_IN_CASE(MINT_BGT_I8_S)
3560 BRELOP_S(l, >)
3561 MINT_IN_BREAK;
3562 MINT_IN_CASE(MINT_BGT_R4_S)
3563 CONDBR_S(!isunordered (sp [0].data.f_r4, sp [1].data.f_r4) && sp[0].data.f_r4 > sp[1].data.f_r4)
3564 MINT_IN_BREAK;
3565 MINT_IN_CASE(MINT_BGT_R8_S)
3566 CONDBR_S(!mono_isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f > sp[1].data.f)
3567 MINT_IN_BREAK;
3568 MINT_IN_CASE(MINT_BGT_I4)
3569 BRELOP(i, >)
3570 MINT_IN_BREAK;
3571 MINT_IN_CASE(MINT_BGT_I8)
3572 BRELOP(l, >)
3573 MINT_IN_BREAK;
3574 MINT_IN_CASE(MINT_BGT_R4)
3575 CONDBR(!isunordered (sp [0].data.f_r4, sp [1].data.f_r4) && sp[0].data.f_r4 > sp[1].data.f_r4)
3576 MINT_IN_BREAK;
3577 MINT_IN_CASE(MINT_BGT_R8)
3578 CONDBR(!mono_isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f > sp[1].data.f)
3579 MINT_IN_BREAK;
3580 MINT_IN_CASE(MINT_BLT_I4_S)
3581 BRELOP_S(i, <)
3582 MINT_IN_BREAK;
3583 MINT_IN_CASE(MINT_BLT_I8_S)
3584 BRELOP_S(l, <)
3585 MINT_IN_BREAK;
3586 MINT_IN_CASE(MINT_BLT_R4_S)
3587 CONDBR_S(!isunordered (sp [0].data.f_r4, sp [1].data.f_r4) && sp[0].data.f_r4 < sp[1].data.f_r4)
3588 MINT_IN_BREAK;
3589 MINT_IN_CASE(MINT_BLT_R8_S)
3590 CONDBR_S(!mono_isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f < sp[1].data.f)
3591 MINT_IN_BREAK;
3592 MINT_IN_CASE(MINT_BLT_I4)
3593 BRELOP(i, <)
3594 MINT_IN_BREAK;
3595 MINT_IN_CASE(MINT_BLT_I8)
3596 BRELOP(l, <)
3597 MINT_IN_BREAK;
3598 MINT_IN_CASE(MINT_BLT_R4)
3599 CONDBR(!isunordered (sp [0].data.f_r4, sp [1].data.f_r4) && sp[0].data.f_r4 < sp[1].data.f_r4)
3600 MINT_IN_BREAK;
3601 MINT_IN_CASE(MINT_BLT_R8)
3602 CONDBR(!mono_isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f < sp[1].data.f)
3603 MINT_IN_BREAK;
3604 MINT_IN_CASE(MINT_BLE_I4_S)
3605 BRELOP_S(i, <=)
3606 MINT_IN_BREAK;
3607 MINT_IN_CASE(MINT_BLE_I8_S)
3608 BRELOP_S(l, <=)
3609 MINT_IN_BREAK;
3610 MINT_IN_CASE(MINT_BLE_R4_S)
3611 CONDBR_S(!isunordered (sp [0].data.f_r4, sp [1].data.f_r4) && sp[0].data.f_r4 <= sp[1].data.f_r4)
3612 MINT_IN_BREAK;
3613 MINT_IN_CASE(MINT_BLE_R8_S)
3614 CONDBR_S(!mono_isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f <= sp[1].data.f)
3615 MINT_IN_BREAK;
3616 MINT_IN_CASE(MINT_BLE_I4)
3617 BRELOP(i, <=)
3618 MINT_IN_BREAK;
3619 MINT_IN_CASE(MINT_BLE_I8)
3620 BRELOP(l, <=)
3621 MINT_IN_BREAK;
3622 MINT_IN_CASE(MINT_BLE_R4)
3623 CONDBR(!isunordered (sp [0].data.f_r4, sp [1].data.f_r4) && sp[0].data.f_r4 <= sp[1].data.f_r4)
3624 MINT_IN_BREAK;
3625 MINT_IN_CASE(MINT_BLE_R8)
3626 CONDBR(!mono_isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f <= sp[1].data.f)
3627 MINT_IN_BREAK;
3628 MINT_IN_CASE(MINT_BNE_UN_I4_S)
3629 BRELOP_S(i, !=)
3630 MINT_IN_BREAK;
3631 MINT_IN_CASE(MINT_BNE_UN_I8_S)
3632 BRELOP_S(l, !=)
3633 MINT_IN_BREAK;
3634 MINT_IN_CASE(MINT_BNE_UN_R4_S)
3635 CONDBR_S(isunordered (sp [0].data.f_r4, sp [1].data.f_r4) || sp[0].data.f_r4 != sp[1].data.f_r4)
3636 MINT_IN_BREAK;
3637 MINT_IN_CASE(MINT_BNE_UN_R8_S)
3638 CONDBR_S(mono_isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f != sp[1].data.f)
3639 MINT_IN_BREAK;
3640 MINT_IN_CASE(MINT_BNE_UN_I4)
3641 BRELOP(i, !=)
3642 MINT_IN_BREAK;
3643 MINT_IN_CASE(MINT_BNE_UN_I8)
3644 BRELOP(l, !=)
3645 MINT_IN_BREAK;
3646 MINT_IN_CASE(MINT_BNE_UN_R4)
3647 CONDBR(isunordered (sp [0].data.f_r4, sp [1].data.f_r4) || sp[0].data.f_r4 != sp[1].data.f_r4)
3648 MINT_IN_BREAK;
3649 MINT_IN_CASE(MINT_BNE_UN_R8)
3650 CONDBR(mono_isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f != sp[1].data.f)
3651 MINT_IN_BREAK;
3653 #define BRELOP_S_CAST(datamem, op, type) \
3654 sp -= 2; \
3655 if ((type) sp[0].data.datamem op (type) sp[1].data.datamem) \
3656 ip += * (gint16 *)(ip + 1); \
3657 else \
3658 ip += 2;
3660 #define BRELOP_CAST(datamem, op, type) \
3661 sp -= 2; \
3662 if ((type) sp[0].data.datamem op (type) sp[1].data.datamem) \
3663 ip += (gint32)READ32(ip + 1); \
3664 else \
3665 ip += 3;
3667 MINT_IN_CASE(MINT_BGE_UN_I4_S)
3668 BRELOP_S_CAST(i, >=, guint32);
3669 MINT_IN_BREAK;
3670 MINT_IN_CASE(MINT_BGE_UN_I8_S)
3671 BRELOP_S_CAST(l, >=, guint64);
3672 MINT_IN_BREAK;
3673 MINT_IN_CASE(MINT_BGE_UN_R4_S)
3674 CONDBR_S(isunordered (sp [0].data.f_r4, sp [1].data.f_r4) || sp[0].data.f_r4 >= sp[1].data.f_r4)
3675 MINT_IN_BREAK;
3676 MINT_IN_CASE(MINT_BGE_UN_R8_S)
3677 CONDBR_S(mono_isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f >= sp[1].data.f)
3678 MINT_IN_BREAK;
3679 MINT_IN_CASE(MINT_BGE_UN_I4)
3680 BRELOP_CAST(i, >=, guint32);
3681 MINT_IN_BREAK;
3682 MINT_IN_CASE(MINT_BGE_UN_I8)
3683 BRELOP_CAST(l, >=, guint64);
3684 MINT_IN_BREAK;
3685 MINT_IN_CASE(MINT_BGE_UN_R4)
3686 CONDBR(isunordered (sp [0].data.f_r4, sp [1].data.f_r4) || sp[0].data.f_r4 >= sp[1].data.f_r4)
3687 MINT_IN_BREAK;
3688 MINT_IN_CASE(MINT_BGE_UN_R8)
3689 CONDBR(mono_isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f >= sp[1].data.f)
3690 MINT_IN_BREAK;
3691 MINT_IN_CASE(MINT_BGT_UN_I4_S)
3692 BRELOP_S_CAST(i, >, guint32);
3693 MINT_IN_BREAK;
3694 MINT_IN_CASE(MINT_BGT_UN_I8_S)
3695 BRELOP_S_CAST(l, >, guint64);
3696 MINT_IN_BREAK;
3697 MINT_IN_CASE(MINT_BGT_UN_R4_S)
3698 CONDBR_S(isunordered (sp [0].data.f_r4, sp [1].data.f_r4) || sp[0].data.f_r4 > sp[1].data.f_r4)
3699 MINT_IN_BREAK;
3700 MINT_IN_CASE(MINT_BGT_UN_R8_S)
3701 CONDBR_S(mono_isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f > sp[1].data.f)
3702 MINT_IN_BREAK;
3703 MINT_IN_CASE(MINT_BGT_UN_I4)
3704 BRELOP_CAST(i, >, guint32);
3705 MINT_IN_BREAK;
3706 MINT_IN_CASE(MINT_BGT_UN_I8)
3707 BRELOP_CAST(l, >, guint64);
3708 MINT_IN_BREAK;
3709 MINT_IN_CASE(MINT_BGT_UN_R4)
3710 CONDBR(isunordered (sp [0].data.f_r4, sp [1].data.f_r4) || sp[0].data.f_r4 > sp[1].data.f_r4)
3711 MINT_IN_BREAK;
3712 MINT_IN_CASE(MINT_BGT_UN_R8)
3713 CONDBR(mono_isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f > sp[1].data.f)
3714 MINT_IN_BREAK;
3715 MINT_IN_CASE(MINT_BLE_UN_I4_S)
3716 BRELOP_S_CAST(i, <=, guint32);
3717 MINT_IN_BREAK;
3718 MINT_IN_CASE(MINT_BLE_UN_I8_S)
3719 BRELOP_S_CAST(l, <=, guint64);
3720 MINT_IN_BREAK;
3721 MINT_IN_CASE(MINT_BLE_UN_R4_S)
3722 CONDBR_S(isunordered (sp [0].data.f_r4, sp [1].data.f_r4) || sp[0].data.f_r4 <= sp[1].data.f_r4)
3723 MINT_IN_BREAK;
3724 MINT_IN_CASE(MINT_BLE_UN_R8_S)
3725 CONDBR_S(mono_isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f <= sp[1].data.f)
3726 MINT_IN_BREAK;
3727 MINT_IN_CASE(MINT_BLE_UN_I4)
3728 BRELOP_CAST(i, <=, guint32);
3729 MINT_IN_BREAK;
3730 MINT_IN_CASE(MINT_BLE_UN_I8)
3731 BRELOP_CAST(l, <=, guint64);
3732 MINT_IN_BREAK;
3733 MINT_IN_CASE(MINT_BLE_UN_R4)
3734 CONDBR(isunordered (sp [0].data.f_r4, sp [1].data.f_r4) || sp[0].data.f_r4 <= sp[1].data.f_r4)
3735 MINT_IN_BREAK;
3736 MINT_IN_CASE(MINT_BLE_UN_R8)
3737 CONDBR(mono_isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f <= sp[1].data.f)
3738 MINT_IN_BREAK;
3739 MINT_IN_CASE(MINT_BLT_UN_I4_S)
3740 BRELOP_S_CAST(i, <, guint32);
3741 MINT_IN_BREAK;
3742 MINT_IN_CASE(MINT_BLT_UN_I8_S)
3743 BRELOP_S_CAST(l, <, guint64);
3744 MINT_IN_BREAK;
3745 MINT_IN_CASE(MINT_BLT_UN_R4_S)
3746 CONDBR_S(isunordered (sp [0].data.f_r4, sp [1].data.f_r4) || sp[0].data.f_r4 < sp[1].data.f_r4)
3747 MINT_IN_BREAK;
3748 MINT_IN_CASE(MINT_BLT_UN_R8_S)
3749 CONDBR_S(mono_isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f < sp[1].data.f)
3750 MINT_IN_BREAK;
3751 MINT_IN_CASE(MINT_BLT_UN_I4)
3752 BRELOP_CAST(i, <, guint32);
3753 MINT_IN_BREAK;
3754 MINT_IN_CASE(MINT_BLT_UN_I8)
3755 BRELOP_CAST(l, <, guint64);
3756 MINT_IN_BREAK;
3757 MINT_IN_CASE(MINT_BLT_UN_R4)
3758 CONDBR(isunordered (sp [0].data.f_r4, sp [1].data.f_r4) || sp[0].data.f_r4 < sp[1].data.f_r4)
3759 MINT_IN_BREAK;
3760 MINT_IN_CASE(MINT_BLT_UN_R8)
3761 CONDBR(mono_isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f < sp[1].data.f)
3762 MINT_IN_BREAK;
3763 MINT_IN_CASE(MINT_SWITCH) {
3764 guint32 n;
3765 const unsigned short *st;
3766 ++ip;
3767 n = READ32 (ip);
3768 ip += 2;
3769 st = ip + 2 * n;
3770 --sp;
3771 if ((guint32)sp->data.i < n) {
3772 gint offset;
3773 ip += 2 * (guint32)sp->data.i;
3774 offset = READ32 (ip);
3775 ip = ip + offset;
3776 } else {
3777 ip = st;
3779 MINT_IN_BREAK;
3781 MINT_IN_CASE(MINT_LDIND_I1_CHECK)
3782 if (!sp[-1].data.p)
3783 THROW_EX (mono_get_exception_null_reference (), ip);
3784 ++ip;
3785 sp[-1].data.i = *(gint8*)sp[-1].data.p;
3786 MINT_IN_BREAK;
3787 MINT_IN_CASE(MINT_LDIND_U1_CHECK)
3788 if (!sp[-1].data.p)
3789 THROW_EX (mono_get_exception_null_reference (), ip);
3790 ++ip;
3791 sp[-1].data.i = *(guint8*)sp[-1].data.p;
3792 MINT_IN_BREAK;
3793 MINT_IN_CASE(MINT_LDIND_I2_CHECK)
3794 if (!sp[-1].data.p)
3795 THROW_EX (mono_get_exception_null_reference (), ip);
3796 ++ip;
3797 sp[-1].data.i = *(gint16*)sp[-1].data.p;
3798 MINT_IN_BREAK;
3799 MINT_IN_CASE(MINT_LDIND_U2_CHECK)
3800 if (!sp[-1].data.p)
3801 THROW_EX (mono_get_exception_null_reference (), ip);
3802 ++ip;
3803 sp[-1].data.i = *(guint16*)sp[-1].data.p;
3804 MINT_IN_BREAK;
3805 MINT_IN_CASE(MINT_LDIND_I4_CHECK) /* Fall through */
3806 MINT_IN_CASE(MINT_LDIND_U4_CHECK)
3807 if (!sp[-1].data.p)
3808 THROW_EX (mono_get_exception_null_reference (), ip);
3809 ++ip;
3810 sp[-1].data.i = *(gint32*)sp[-1].data.p;
3811 MINT_IN_BREAK;
3812 MINT_IN_CASE(MINT_LDIND_I8_CHECK)
3813 if (!sp[-1].data.p)
3814 THROW_EX (mono_get_exception_null_reference (), ip);
3815 ++ip;
3816 #ifdef NO_UNALIGNED_ACCESS
3817 if ((gsize)sp [-1].data.p % SIZEOF_VOID_P)
3818 memcpy (&sp [-1].data.l, sp [-1].data.p, sizeof (gint64));
3819 else
3820 #endif
3821 sp[-1].data.l = *(gint64*)sp[-1].data.p;
3822 MINT_IN_BREAK;
3823 MINT_IN_CASE(MINT_LDIND_I) {
3824 guint16 offset = * (guint16 *)(ip + 1);
3825 sp[-1 - offset].data.p = *(gpointer*)sp[-1 - offset].data.p;
3826 ip += 2;
3827 MINT_IN_BREAK;
3829 MINT_IN_CASE(MINT_LDIND_I8) {
3830 guint16 offset = * (guint16 *)(ip + 1);
3831 #ifdef NO_UNALIGNED_ACCESS
3832 if ((gsize)sp [-1 - offset].data.p % SIZEOF_VOID_P)
3833 memcpy (&sp [-1 - offset].data.l, sp [-1 - offset].data.p, sizeof (gint64));
3834 else
3835 #endif
3836 sp[-1 - offset].data.l = *(gint64*)sp[-1 - offset].data.p;
3837 ip += 2;
3838 MINT_IN_BREAK;
3840 MINT_IN_CASE(MINT_LDIND_R4_CHECK)
3841 if (!sp[-1].data.p)
3842 THROW_EX (mono_get_exception_null_reference (), ip);
3843 ++ip;
3844 sp[-1].data.f_r4 = *(gfloat*)sp[-1].data.p;
3845 MINT_IN_BREAK;
3846 MINT_IN_CASE(MINT_LDIND_R8_CHECK)
3847 if (!sp[-1].data.p)
3848 THROW_EX (mono_get_exception_null_reference (), ip);
3849 ++ip;
3850 #ifdef NO_UNALIGNED_ACCESS
3851 if ((gsize)sp [-1].data.p % SIZEOF_VOID_P)
3852 memcpy (&sp [-1].data.f, sp [-1].data.p, sizeof (gdouble));
3853 else
3854 #endif
3855 sp[-1].data.f = *(gdouble*)sp[-1].data.p;
3856 MINT_IN_BREAK;
3857 MINT_IN_CASE(MINT_LDIND_REF)
3858 ++ip;
3859 sp[-1].data.p = *(gpointer*)sp[-1].data.p;
3860 MINT_IN_BREAK;
3861 MINT_IN_CASE(MINT_LDIND_REF_CHECK) {
3862 if (!sp [-1].data.p)
3863 THROW_EX (mono_get_exception_null_reference (), ip);
3864 ++ip;
3865 sp [-1].data.p = *(gpointer*)sp [-1].data.p;
3866 MINT_IN_BREAK;
3868 MINT_IN_CASE(MINT_STIND_REF)
3869 ++ip;
3870 sp -= 2;
3871 mono_gc_wbarrier_generic_store_internal (sp->data.p, sp [1].data.o);
3872 MINT_IN_BREAK;
3873 MINT_IN_CASE(MINT_STIND_I1)
3874 ++ip;
3875 sp -= 2;
3876 * (gint8 *) sp->data.p = (gint8)sp[1].data.i;
3877 MINT_IN_BREAK;
3878 MINT_IN_CASE(MINT_STIND_I2)
3879 ++ip;
3880 sp -= 2;
3881 * (gint16 *) sp->data.p = (gint16)sp[1].data.i;
3882 MINT_IN_BREAK;
3883 MINT_IN_CASE(MINT_STIND_I4)
3884 ++ip;
3885 sp -= 2;
3886 * (gint32 *) sp->data.p = sp[1].data.i;
3887 MINT_IN_BREAK;
3888 MINT_IN_CASE(MINT_STIND_I)
3889 ++ip;
3890 sp -= 2;
3891 * (mono_i *) sp->data.p = (mono_i)sp[1].data.p;
3892 MINT_IN_BREAK;
3893 MINT_IN_CASE(MINT_STIND_I8)
3894 ++ip;
3895 sp -= 2;
3896 #ifdef NO_UNALIGNED_ACCESS
3897 if ((gsize)sp->data.p % SIZEOF_VOID_P)
3898 memcpy (sp->data.p, &sp [1].data.l, sizeof (gint64));
3899 else
3900 #endif
3901 * (gint64 *) sp->data.p = sp[1].data.l;
3902 MINT_IN_BREAK;
3903 MINT_IN_CASE(MINT_STIND_R4)
3904 ++ip;
3905 sp -= 2;
3906 * (float *) sp->data.p = sp[1].data.f_r4;
3907 MINT_IN_BREAK;
3908 MINT_IN_CASE(MINT_STIND_R8)
3909 ++ip;
3910 sp -= 2;
3911 #ifdef NO_UNALIGNED_ACCESS
3912 if ((gsize)sp->data.p % SIZEOF_VOID_P)
3913 memcpy (sp->data.p, &sp [1].data.f, sizeof (double));
3914 else
3915 #endif
3916 * (double *) sp->data.p = sp[1].data.f;
3917 MINT_IN_BREAK;
3918 MINT_IN_CASE(MINT_MONO_ATOMIC_STORE_I4)
3919 ++ip;
3920 sp -= 2;
3921 mono_atomic_store_i32 ((gint32 *) sp->data.p, sp [1].data.i);
3922 MINT_IN_BREAK;
3923 #define BINOP(datamem, op) \
3924 --sp; \
3925 sp [-1].data.datamem = sp [-1].data.datamem op sp [0].data.datamem; \
3926 ++ip;
3927 MINT_IN_CASE(MINT_ADD_I4)
3928 BINOP(i, +);
3929 MINT_IN_BREAK;
3930 MINT_IN_CASE(MINT_ADD_I8)
3931 BINOP(l, +);
3932 MINT_IN_BREAK;
3933 MINT_IN_CASE(MINT_ADD_R4)
3934 BINOP(f_r4, +);
3935 MINT_IN_BREAK;
3936 MINT_IN_CASE(MINT_ADD_R8)
3937 BINOP(f, +);
3938 MINT_IN_BREAK;
3939 MINT_IN_CASE(MINT_ADD1_I4)
3940 ++sp [-1].data.i;
3941 ++ip;
3942 MINT_IN_BREAK;
3943 MINT_IN_CASE(MINT_ADD1_I8)
3944 ++sp [-1].data.l;
3945 ++ip;
3946 MINT_IN_BREAK;
3947 MINT_IN_CASE(MINT_SUB_I4)
3948 BINOP(i, -);
3949 MINT_IN_BREAK;
3950 MINT_IN_CASE(MINT_SUB_I8)
3951 BINOP(l, -);
3952 MINT_IN_BREAK;
3953 MINT_IN_CASE(MINT_SUB_R4)
3954 BINOP(f_r4, -);
3955 MINT_IN_BREAK;
3956 MINT_IN_CASE(MINT_SUB_R8)
3957 BINOP(f, -);
3958 MINT_IN_BREAK;
3959 MINT_IN_CASE(MINT_SUB1_I4)
3960 --sp [-1].data.i;
3961 ++ip;
3962 MINT_IN_BREAK;
3963 MINT_IN_CASE(MINT_SUB1_I8)
3964 --sp [-1].data.l;
3965 ++ip;
3966 MINT_IN_BREAK;
3967 MINT_IN_CASE(MINT_MUL_I4)
3968 BINOP(i, *);
3969 MINT_IN_BREAK;
3970 MINT_IN_CASE(MINT_MUL_I8)
3971 BINOP(l, *);
3972 MINT_IN_BREAK;
3973 MINT_IN_CASE(MINT_MUL_R4)
3974 BINOP(f_r4, *);
3975 MINT_IN_BREAK;
3976 MINT_IN_CASE(MINT_MUL_R8)
3977 BINOP(f, *);
3978 MINT_IN_BREAK;
3979 MINT_IN_CASE(MINT_DIV_I4)
3980 if (sp [-1].data.i == 0)
3981 THROW_EX (mono_get_exception_divide_by_zero (), ip);
3982 if (sp [-1].data.i == (-1) && sp [-2].data.i == G_MININT32)
3983 THROW_EX (mono_get_exception_overflow (), ip);
3984 BINOP(i, /);
3985 MINT_IN_BREAK;
3986 MINT_IN_CASE(MINT_DIV_I8)
3987 if (sp [-1].data.l == 0)
3988 THROW_EX (mono_get_exception_divide_by_zero (), ip);
3989 if (sp [-1].data.l == (-1) && sp [-2].data.l == G_MININT64)
3990 THROW_EX (mono_get_exception_overflow (), ip);
3991 BINOP(l, /);
3992 MINT_IN_BREAK;
3993 MINT_IN_CASE(MINT_DIV_R4)
3994 BINOP(f_r4, /);
3995 MINT_IN_BREAK;
3996 MINT_IN_CASE(MINT_DIV_R8)
3997 BINOP(f, /);
3998 MINT_IN_BREAK;
4000 #define BINOP_CAST(datamem, op, type) \
4001 --sp; \
4002 sp [-1].data.datamem = (type)sp [-1].data.datamem op (type)sp [0].data.datamem; \
4003 ++ip;
4004 MINT_IN_CASE(MINT_DIV_UN_I4)
4005 if (sp [-1].data.i == 0)
4006 THROW_EX (mono_get_exception_divide_by_zero (), ip);
4007 BINOP_CAST(i, /, guint32);
4008 MINT_IN_BREAK;
4009 MINT_IN_CASE(MINT_DIV_UN_I8)
4010 if (sp [-1].data.l == 0)
4011 THROW_EX (mono_get_exception_divide_by_zero (), ip);
4012 BINOP_CAST(l, /, guint64);
4013 MINT_IN_BREAK;
4014 MINT_IN_CASE(MINT_REM_I4)
4015 if (sp [-1].data.i == 0)
4016 THROW_EX (mono_get_exception_divide_by_zero (), ip);
4017 if (sp [-1].data.i == (-1) && sp [-2].data.i == G_MININT32)
4018 THROW_EX (mono_get_exception_overflow (), ip);
4019 BINOP(i, %);
4020 MINT_IN_BREAK;
4021 MINT_IN_CASE(MINT_REM_I8)
4022 if (sp [-1].data.l == 0)
4023 THROW_EX (mono_get_exception_divide_by_zero (), ip);
4024 if (sp [-1].data.l == (-1) && sp [-2].data.l == G_MININT64)
4025 THROW_EX (mono_get_exception_overflow (), ip);
4026 BINOP(l, %);
4027 MINT_IN_BREAK;
4028 MINT_IN_CASE(MINT_REM_R4)
4029 /* FIXME: what do we actually do here? */
4030 --sp;
4031 sp [-1].data.f_r4 = fmodf (sp [-1].data.f_r4, sp [0].data.f_r4);
4032 ++ip;
4033 MINT_IN_BREAK;
4034 MINT_IN_CASE(MINT_REM_R8)
4035 /* FIXME: what do we actually do here? */
4036 --sp;
4037 sp [-1].data.f = fmod (sp [-1].data.f, sp [0].data.f);
4038 ++ip;
4039 MINT_IN_BREAK;
4040 MINT_IN_CASE(MINT_REM_UN_I4)
4041 if (sp [-1].data.i == 0)
4042 THROW_EX (mono_get_exception_divide_by_zero (), ip);
4043 BINOP_CAST(i, %, guint32);
4044 MINT_IN_BREAK;
4045 MINT_IN_CASE(MINT_REM_UN_I8)
4046 if (sp [-1].data.l == 0)
4047 THROW_EX (mono_get_exception_divide_by_zero (), ip);
4048 BINOP_CAST(l, %, guint64);
4049 MINT_IN_BREAK;
4050 MINT_IN_CASE(MINT_AND_I4)
4051 BINOP(i, &);
4052 MINT_IN_BREAK;
4053 MINT_IN_CASE(MINT_AND_I8)
4054 BINOP(l, &);
4055 MINT_IN_BREAK;
4056 MINT_IN_CASE(MINT_OR_I4)
4057 BINOP(i, |);
4058 MINT_IN_BREAK;
4059 MINT_IN_CASE(MINT_OR_I8)
4060 BINOP(l, |);
4061 MINT_IN_BREAK;
4062 MINT_IN_CASE(MINT_XOR_I4)
4063 BINOP(i, ^);
4064 MINT_IN_BREAK;
4065 MINT_IN_CASE(MINT_XOR_I8)
4066 BINOP(l, ^);
4067 MINT_IN_BREAK;
4069 #define SHIFTOP(datamem, op) \
4070 --sp; \
4071 sp [-1].data.datamem = sp [-1].data.datamem op sp [0].data.i; \
4072 ++ip;
4074 MINT_IN_CASE(MINT_SHL_I4)
4075 SHIFTOP(i, <<);
4076 MINT_IN_BREAK;
4077 MINT_IN_CASE(MINT_SHL_I8)
4078 SHIFTOP(l, <<);
4079 MINT_IN_BREAK;
4080 MINT_IN_CASE(MINT_SHR_I4)
4081 SHIFTOP(i, >>);
4082 MINT_IN_BREAK;
4083 MINT_IN_CASE(MINT_SHR_I8)
4084 SHIFTOP(l, >>);
4085 MINT_IN_BREAK;
4086 MINT_IN_CASE(MINT_SHR_UN_I4)
4087 --sp;
4088 sp [-1].data.i = (guint32)sp [-1].data.i >> sp [0].data.i;
4089 ++ip;
4090 MINT_IN_BREAK;
4091 MINT_IN_CASE(MINT_SHR_UN_I8)
4092 --sp;
4093 sp [-1].data.l = (guint64)sp [-1].data.l >> sp [0].data.i;
4094 ++ip;
4095 MINT_IN_BREAK;
4096 MINT_IN_CASE(MINT_NEG_I4)
4097 sp [-1].data.i = - sp [-1].data.i;
4098 ++ip;
4099 MINT_IN_BREAK;
4100 MINT_IN_CASE(MINT_NEG_I8)
4101 sp [-1].data.l = - sp [-1].data.l;
4102 ++ip;
4103 MINT_IN_BREAK;
4104 MINT_IN_CASE(MINT_NEG_R4)
4105 sp [-1].data.f_r4 = - sp [-1].data.f_r4;
4106 ++ip;
4107 MINT_IN_BREAK;
4108 MINT_IN_CASE(MINT_NEG_R8)
4109 sp [-1].data.f = - sp [-1].data.f;
4110 ++ip;
4111 MINT_IN_BREAK;
4112 MINT_IN_CASE(MINT_NOT_I4)
4113 sp [-1].data.i = ~ sp [-1].data.i;
4114 ++ip;
4115 MINT_IN_BREAK;
4116 MINT_IN_CASE(MINT_NOT_I8)
4117 sp [-1].data.l = ~ sp [-1].data.l;
4118 ++ip;
4119 MINT_IN_BREAK;
4120 MINT_IN_CASE(MINT_CONV_I1_I4)
4121 sp [-1].data.i = (gint8)sp [-1].data.i;
4122 ++ip;
4123 MINT_IN_BREAK;
4124 MINT_IN_CASE(MINT_CONV_I1_I8)
4125 sp [-1].data.i = (gint8)sp [-1].data.l;
4126 ++ip;
4127 MINT_IN_BREAK;
4128 MINT_IN_CASE(MINT_CONV_I1_R4)
4129 sp [-1].data.i = (gint8) (gint32) sp [-1].data.f_r4;
4130 ++ip;
4131 MINT_IN_BREAK;
4132 MINT_IN_CASE(MINT_CONV_I1_R8)
4133 /* without gint32 cast, C compiler is allowed to use undefined
4134 * behaviour if data.f is bigger than >255. See conv.fpint section
4135 * in C standard:
4136 * > The conversion truncates; that is, the fractional part
4137 * > is discarded. The behavior is undefined if the truncated
4138 * > value cannot be represented in the destination type.
4139 * */
4140 sp [-1].data.i = (gint8) (gint32) sp [-1].data.f;
4141 ++ip;
4142 MINT_IN_BREAK;
4143 MINT_IN_CASE(MINT_CONV_U1_I4)
4144 sp [-1].data.i = (guint8)sp [-1].data.i;
4145 ++ip;
4146 MINT_IN_BREAK;
4147 MINT_IN_CASE(MINT_CONV_U1_I8)
4148 sp [-1].data.i = (guint8)sp [-1].data.l;
4149 ++ip;
4150 MINT_IN_BREAK;
4151 MINT_IN_CASE(MINT_CONV_U1_R4)
4152 sp [-1].data.i = (guint8) (guint32) sp [-1].data.f_r4;
4153 ++ip;
4154 MINT_IN_BREAK;
4155 MINT_IN_CASE(MINT_CONV_U1_R8)
4156 sp [-1].data.i = (guint8) (guint32) sp [-1].data.f;
4157 ++ip;
4158 MINT_IN_BREAK;
4159 MINT_IN_CASE(MINT_CONV_I2_I4)
4160 sp [-1].data.i = (gint16)sp [-1].data.i;
4161 ++ip;
4162 MINT_IN_BREAK;
4163 MINT_IN_CASE(MINT_CONV_I2_I8)
4164 sp [-1].data.i = (gint16)sp [-1].data.l;
4165 ++ip;
4166 MINT_IN_BREAK;
4167 MINT_IN_CASE(MINT_CONV_I2_R4)
4168 sp [-1].data.i = (gint16) (gint32) sp [-1].data.f_r4;
4169 ++ip;
4170 MINT_IN_BREAK;
4171 MINT_IN_CASE(MINT_CONV_I2_R8)
4172 sp [-1].data.i = (gint16) (gint32) sp [-1].data.f;
4173 ++ip;
4174 MINT_IN_BREAK;
4175 MINT_IN_CASE(MINT_CONV_U2_I4)
4176 sp [-1].data.i = (guint16)sp [-1].data.i;
4177 ++ip;
4178 MINT_IN_BREAK;
4179 MINT_IN_CASE(MINT_CONV_U2_I8)
4180 sp [-1].data.i = (guint16)sp [-1].data.l;
4181 ++ip;
4182 MINT_IN_BREAK;
4183 MINT_IN_CASE(MINT_CONV_U2_R4)
4184 sp [-1].data.i = (guint16) (guint32) sp [-1].data.f_r4;
4185 ++ip;
4186 MINT_IN_BREAK;
4187 MINT_IN_CASE(MINT_CONV_U2_R8)
4188 sp [-1].data.i = (guint16) (guint32) sp [-1].data.f;
4189 ++ip;
4190 MINT_IN_BREAK;
4191 MINT_IN_CASE(MINT_CONV_I4_R4)
4192 sp [-1].data.i = (gint32) sp [-1].data.f_r4;
4193 ++ip;
4194 MINT_IN_BREAK;
4195 MINT_IN_CASE(MINT_CONV_I4_R8)
4196 sp [-1].data.i = (gint32)sp [-1].data.f;
4197 ++ip;
4198 MINT_IN_BREAK;
4199 MINT_IN_CASE(MINT_CONV_U4_I8)
4200 MINT_IN_CASE(MINT_CONV_I4_I8)
4201 sp [-1].data.i = (gint32)sp [-1].data.l;
4202 ++ip;
4203 MINT_IN_BREAK;
4204 MINT_IN_CASE(MINT_CONV_I4_I8_SP)
4205 sp [-2].data.i = (gint32)sp [-2].data.l;
4206 ++ip;
4207 MINT_IN_BREAK;
4208 MINT_IN_CASE(MINT_CONV_U4_R4)
4209 /* needed on arm64 */
4210 if (isinf (sp [-1].data.f_r4))
4211 sp [-1].data.i = 0;
4212 /* needed by wasm */
4213 else if (isnan (sp [-1].data.f_r4))
4214 sp [-1].data.i = 0;
4215 else
4216 sp [-1].data.i = (guint32) sp [-1].data.f_r4;
4217 ++ip;
4218 MINT_IN_BREAK;
4219 MINT_IN_CASE(MINT_CONV_U4_R8)
4220 /* needed on arm64 */
4221 if (mono_isinf (sp [-1].data.f))
4222 sp [-1].data.i = 0;
4223 /* needed by wasm */
4224 else if (isnan (sp [-1].data.f))
4225 sp [-1].data.i = 0;
4226 else
4227 sp [-1].data.i = (guint32)sp [-1].data.f;
4228 ++ip;
4229 MINT_IN_BREAK;
4230 MINT_IN_CASE(MINT_CONV_I8_I4)
4231 sp [-1].data.l = sp [-1].data.i;
4232 ++ip;
4233 MINT_IN_BREAK;
4234 MINT_IN_CASE(MINT_CONV_I8_I4_SP)
4235 sp [-2].data.l = sp [-2].data.i;
4236 ++ip;
4237 MINT_IN_BREAK;
4238 MINT_IN_CASE(MINT_CONV_I8_U4)
4239 sp [-1].data.l = (guint32)sp [-1].data.i;
4240 ++ip;
4241 MINT_IN_BREAK;
4242 MINT_IN_CASE(MINT_CONV_I8_R4)
4243 sp [-1].data.l = (gint64) sp [-1].data.f_r4;
4244 ++ip;
4245 MINT_IN_BREAK;
4246 MINT_IN_CASE(MINT_CONV_I8_R8)
4247 sp [-1].data.l = (gint64)sp [-1].data.f;
4248 ++ip;
4249 MINT_IN_BREAK;
4250 MINT_IN_CASE(MINT_CONV_R4_I4)
4251 sp [-1].data.f_r4 = (float)sp [-1].data.i;
4252 ++ip;
4253 MINT_IN_BREAK;
4254 MINT_IN_CASE(MINT_CONV_R4_I8)
4255 sp [-1].data.f_r4 = (float)sp [-1].data.l;
4256 ++ip;
4257 MINT_IN_BREAK;
4258 MINT_IN_CASE(MINT_CONV_R4_R8)
4259 sp [-1].data.f_r4 = (float)sp [-1].data.f;
4260 ++ip;
4261 MINT_IN_BREAK;
4262 MINT_IN_CASE(MINT_CONV_R8_I4)
4263 sp [-1].data.f = (double)sp [-1].data.i;
4264 ++ip;
4265 MINT_IN_BREAK;
4266 MINT_IN_CASE(MINT_CONV_R8_I8)
4267 sp [-1].data.f = (double)sp [-1].data.l;
4268 ++ip;
4269 MINT_IN_BREAK;
4270 MINT_IN_CASE(MINT_CONV_R8_R4)
4271 sp [-1].data.f = (double) sp [-1].data.f_r4;
4272 ++ip;
4273 MINT_IN_BREAK;
4274 MINT_IN_CASE(MINT_CONV_R8_R4_SP)
4275 sp [-2].data.f = (double) sp [-2].data.f_r4;
4276 ++ip;
4277 MINT_IN_BREAK;
4278 MINT_IN_CASE(MINT_CONV_U8_I4)
4279 sp [-1].data.l = sp [-1].data.i & 0xffffffff;
4280 ++ip;
4281 MINT_IN_BREAK;
4282 MINT_IN_CASE(MINT_CONV_U8_R4)
4283 sp [-1].data.l = (guint64) sp [-1].data.f_r4;
4284 ++ip;
4285 MINT_IN_BREAK;
4286 MINT_IN_CASE(MINT_CONV_U8_R8)
4287 sp [-1].data.l = (guint64)sp [-1].data.f;
4288 ++ip;
4289 MINT_IN_BREAK;
4290 MINT_IN_CASE(MINT_CPOBJ) {
4291 c = (MonoClass*)imethod->data_items[* (guint16 *)(ip + 1)];
4292 g_assert (m_class_is_valuetype (c));
4293 /* if this assertion fails, we need to add a write barrier */
4294 g_assert (!MONO_TYPE_IS_REFERENCE (m_class_get_byval_arg (c)));
4295 stackval_from_data (m_class_get_byval_arg (c), (stackval*)sp [-2].data.p, sp [-1].data.p, FALSE);
4296 ip += 2;
4297 sp -= 2;
4298 MINT_IN_BREAK;
4300 MINT_IN_CASE(MINT_CPOBJ_VT) {
4301 c = (MonoClass*)imethod->data_items[* (guint16 *)(ip + 1)];
4302 mono_value_copy_internal (sp [-2].data.vt, sp [-1].data.vt, c);
4303 ip += 2;
4304 sp -= 2;
4305 MINT_IN_BREAK;
4307 MINT_IN_CASE(MINT_LDOBJ_VT) {
4308 int size = READ32(ip + 1);
4309 ip += 3;
4310 memcpy (vt_sp, sp [-1].data.p, size);
4311 sp [-1].data.p = vt_sp;
4312 vt_sp += ALIGN_TO (size, MINT_VT_ALIGNMENT);
4313 MINT_IN_BREAK;
4315 MINT_IN_CASE(MINT_LDSTR)
4316 sp->data.p = imethod->data_items [* (guint16 *)(ip + 1)];
4317 ++sp;
4318 ip += 2;
4319 MINT_IN_BREAK;
4320 MINT_IN_CASE(MINT_LDSTR_TOKEN) {
4321 MonoString *s = NULL;
4322 guint32 strtoken = (guint32)(gsize)imethod->data_items [* (guint16 *)(ip + 1)];
4324 MonoMethod *method = imethod->method;
4325 if (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD) {
4326 s = (MonoString*)mono_method_get_wrapper_data (method, strtoken);
4327 } else if (method->wrapper_type != MONO_WRAPPER_NONE) {
4328 s = mono_string_new_wrapper_internal ((const char*)mono_method_get_wrapper_data (method, strtoken));
4329 } else {
4330 g_assert_not_reached ();
4332 sp->data.p = s;
4333 ++sp;
4334 ip += 2;
4335 MINT_IN_BREAK;
4337 MINT_IN_CASE(MINT_NEWOBJ_ARRAY) {
4338 MonoClass *newobj_class;
4339 guint32 token = * (guint16 *)(ip + 1);
4340 guint16 param_count = * (guint16 *)(ip + 2);
4342 newobj_class = ((InterpMethod*) imethod->data_items [token])->method->klass;
4344 sp -= param_count;
4345 sp->data.p = ves_array_create (imethod->domain, newobj_class, param_count, sp, error);
4346 if (!mono_error_ok (error))
4347 THROW_EX (mono_error_convert_to_exception (error), ip);
4349 ++sp;
4350 ip += 3;
4351 MINT_IN_BREAK;
4353 MINT_IN_CASE(MINT_NEWOBJ_FAST)
4354 MINT_IN_CASE(MINT_NEWOBJ_VT_FAST)
4355 MINT_IN_CASE(MINT_NEWOBJ_VTST_FAST) {
4356 guint16 param_count;
4357 gboolean vt = *ip != MINT_NEWOBJ_FAST;
4358 stackval valuetype_this;
4360 frame->ip = ip;
4362 child_frame.imethod = (InterpMethod*) imethod->data_items [*(guint16*)(ip + 1)];
4363 param_count = *(guint16*)(ip + 2);
4365 if (param_count) {
4366 sp -= param_count;
4367 memmove (sp + 1, sp, param_count * sizeof (stackval));
4369 child_frame.stack_args = sp;
4371 if (vt) {
4372 gboolean vtst = *ip == MINT_NEWOBJ_VTST_FAST;
4373 if (vtst) {
4374 memset (vt_sp, 0, *(guint16*)(ip + 3));
4375 sp->data.p = vt_sp;
4376 valuetype_this.data.p = vt_sp;
4377 ip += 4;
4378 } else {
4379 memset (&valuetype_this, 0, sizeof (stackval));
4380 sp->data.p = &valuetype_this;
4381 ip += 3;
4383 } else {
4384 MonoVTable *vtable = (MonoVTable*) imethod->data_items [*(guint16*)(ip + 3)];
4385 if (G_UNLIKELY (!vtable->initialized)) {
4386 mono_runtime_class_init_full (vtable, error);
4387 if (!mono_error_ok (error))
4388 THROW_EX (mono_error_convert_to_exception (error), ip);
4390 o = mono_gc_alloc_obj (vtable, m_class_get_instance_size (vtable->klass));
4391 if (G_UNLIKELY (!o)) {
4392 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", m_class_get_instance_size (vtable->klass));
4393 THROW_EX (mono_error_convert_to_exception (error), ip);
4395 sp->data.p = o;
4396 ip += 4;
4399 interp_exec_method (&child_frame, context);
4401 CHECK_RESUME_STATE (context);
4403 if (vt)
4404 *sp = valuetype_this;
4405 else
4406 sp->data.p = o;
4407 ++sp;
4408 MINT_IN_BREAK;
4410 MINT_IN_CASE(MINT_NEWOBJ) {
4411 MonoClass *newobj_class;
4412 MonoMethodSignature *csig;
4413 stackval valuetype_this;
4414 guint32 token;
4415 stackval retval;
4417 frame->ip = ip;
4419 token = * (guint16 *)(ip + 1);
4420 ip += 2;
4422 child_frame.ip = NULL;
4423 child_frame.ex = NULL;
4425 child_frame.imethod = (InterpMethod*)imethod->data_items [token];
4426 csig = mono_method_signature_internal (child_frame.imethod->method);
4427 newobj_class = child_frame.imethod->method->klass;
4428 /*if (profiling_classes) {
4429 guint count = GPOINTER_TO_UINT (g_hash_table_lookup (profiling_classes, newobj_class));
4430 count++;
4431 g_hash_table_insert (profiling_classes, newobj_class, GUINT_TO_POINTER (count));
4434 g_assert (csig->hasthis);
4435 if (csig->param_count) {
4436 sp -= csig->param_count;
4437 memmove (sp + 1, sp, csig->param_count * sizeof (stackval));
4439 child_frame.stack_args = sp;
4442 * First arg is the object.
4444 if (m_class_is_valuetype (newobj_class)) {
4445 MonoType *t = m_class_get_byval_arg (newobj_class);
4446 memset (&valuetype_this, 0, sizeof (stackval));
4447 if (!m_class_is_enumtype (newobj_class) && (t->type == MONO_TYPE_VALUETYPE || (t->type == MONO_TYPE_GENERICINST && mono_type_generic_inst_is_valuetype (t)))) {
4448 sp->data.p = vt_sp;
4449 valuetype_this.data.p = vt_sp;
4450 } else {
4451 sp->data.p = &valuetype_this;
4453 } else {
4454 if (newobj_class != mono_defaults.string_class) {
4455 MonoVTable *vtable = mono_class_vtable_checked (imethod->domain, newobj_class, error);
4456 if (!mono_error_ok (error) || !mono_runtime_class_init_full (vtable, error))
4457 THROW_EX (mono_error_convert_to_exception (error), ip);
4458 o = mono_object_new_checked (imethod->domain, newobj_class, error);
4459 mono_error_cleanup (error); /* FIXME: don't swallow the error */
4460 EXCEPTION_CHECKPOINT;
4461 sp->data.p = o;
4462 #ifndef DISABLE_REMOTING
4463 if (mono_object_is_transparent_proxy (o)) {
4464 MonoMethod *remoting_invoke_method = mono_marshal_get_remoting_invoke_with_check (child_frame.imethod->method, error);
4465 mono_error_assert_ok (error);
4466 child_frame.imethod = mono_interp_get_imethod (imethod->domain, remoting_invoke_method, error);
4467 mono_error_assert_ok (error);
4469 #endif
4470 } else {
4471 sp->data.p = NULL;
4472 child_frame.retval = &retval;
4476 interp_exec_method (&child_frame, context);
4478 CHECK_RESUME_STATE (context);
4481 * a constructor returns void, but we need to return the object we created
4483 if (m_class_is_valuetype (newobj_class) && !m_class_is_enumtype (newobj_class)) {
4484 *sp = valuetype_this;
4485 } else if (newobj_class == mono_defaults.string_class) {
4486 *sp = retval;
4487 } else {
4488 sp->data.p = o;
4490 ++sp;
4491 MINT_IN_BREAK;
4493 MINT_IN_CASE(MINT_NEWOBJ_MAGIC) {
4494 frame->ip = ip;
4495 ip += 2;
4497 MINT_IN_BREAK;
4499 MINT_IN_CASE(MINT_INTRINS_BYREFERENCE_CTOR) {
4500 MonoMethodSignature *csig;
4501 guint32 token;
4503 frame->ip = ip;
4504 token = * (guint16 *)(ip + 1);
4505 ip += 2;
4507 InterpMethod *cmethod = (InterpMethod*)imethod->data_items [token];
4508 csig = mono_method_signature_internal (cmethod->method);
4510 g_assert (csig->hasthis);
4511 sp -= csig->param_count;
4513 gpointer arg0 = sp [0].data.p;
4515 gpointer *byreference_this = (gpointer*)vt_sp;
4516 *byreference_this = arg0;
4518 /* Followed by a VTRESULT opcode which will push the result on the stack */
4519 ++sp;
4520 MINT_IN_BREAK;
4522 MINT_IN_CASE(MINT_INTRINS_BYREFERENCE_GET_VALUE) {
4523 gpointer *byreference_this = (gpointer*)sp [-1].data.p;
4524 sp [-1].data.p = *byreference_this;
4525 ++ip;
4526 MINT_IN_BREAK;
4528 MINT_IN_CASE(MINT_INTRINS_UNSAFE_ADD_BYTE_OFFSET) {
4529 sp -= 2;
4530 sp [0].data.p = (guint8*)sp [0].data.p + sp [1].data.i;
4531 sp ++;
4532 ++ip;
4533 MINT_IN_BREAK;
4535 MINT_IN_CASE(MINT_INTRINS_UNSAFE_BYTE_OFFSET) {
4536 sp -= 2;
4537 sp [0].data.i = (guint8*)sp [1].data.p - (guint8*)sp [0].data.p;
4538 sp ++;
4539 ++ip;
4540 MINT_IN_BREAK;
4542 MINT_IN_CASE(MINT_INTRINS_RUNTIMEHELPERS_OBJECT_HAS_COMPONENT_SIZE) {
4543 sp -= 1;
4544 MonoObject *obj = sp [0].data.o;
4545 sp [0].data.i = (obj->vtable->flags & MONO_VT_FLAG_ARRAY_OR_STRING) != 0;
4546 sp ++;
4547 ++ip;
4548 MINT_IN_BREAK;
4550 MINT_IN_CASE(MINT_CASTCLASS_INTERFACE)
4551 MINT_IN_CASE(MINT_ISINST_INTERFACE) {
4552 gboolean isinst_instr = *ip == MINT_ISINST_INTERFACE;
4553 c = (MonoClass*)imethod->data_items [*(guint16 *)(ip + 1)];
4554 if ((o = sp [-1].data.o)) {
4555 gboolean isinst;
4556 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (o->vtable, m_class_get_interface_id (c))) {
4557 isinst = TRUE;
4558 } else if (m_class_is_array_special_interface (c) || mono_object_is_transparent_proxy (o)) {
4559 /* slow path */
4560 isinst = mono_object_isinst_checked (o, c, error) != NULL;
4561 mono_error_cleanup (error); /* FIXME: don't swallow the error */
4562 } else {
4563 isinst = FALSE;
4566 if (!isinst) {
4567 if (isinst_instr)
4568 sp [-1].data.p = NULL;
4569 else
4570 THROW_EX (mono_get_exception_invalid_cast (), ip);
4573 ip += 2;
4574 MINT_IN_BREAK;
4576 MINT_IN_CASE(MINT_CASTCLASS_COMMON)
4577 MINT_IN_CASE(MINT_ISINST_COMMON) {
4578 gboolean isinst_instr = *ip == MINT_ISINST_COMMON;
4579 c = (MonoClass*)imethod->data_items [*(guint16 *)(ip + 1)];
4580 if ((o = sp [-1].data.o)) {
4581 gboolean isinst = mono_class_has_parent_fast (o->vtable->klass, c);
4583 if (!isinst) {
4584 if (isinst_instr)
4585 sp [-1].data.p = NULL;
4586 else
4587 THROW_EX (mono_get_exception_invalid_cast (), ip);
4590 ip += 2;
4591 MINT_IN_BREAK;
4593 MINT_IN_CASE(MINT_CASTCLASS)
4594 MINT_IN_CASE(MINT_ISINST) {
4595 gboolean isinst_instr = *ip == MINT_ISINST;
4596 c = (MonoClass*)imethod->data_items [*(guint16 *)(ip + 1)];
4597 if ((o = sp [-1].data.o)) {
4598 MonoObject *isinst_obj = mono_object_isinst_checked (o, c, error);
4599 mono_error_cleanup (error); /* FIXME: don't swallow the error */
4600 if (!isinst_obj) {
4601 if (isinst_instr)
4602 sp [-1].data.p = NULL;
4603 else
4604 THROW_EX (mono_get_exception_invalid_cast (), ip);
4607 ip += 2;
4608 MINT_IN_BREAK;
4610 MINT_IN_CASE(MINT_CONV_R_UN_I4)
4611 sp [-1].data.f = (double)(guint32)sp [-1].data.i;
4612 ++ip;
4613 MINT_IN_BREAK;
4614 MINT_IN_CASE(MINT_CONV_R_UN_I8)
4615 sp [-1].data.f = (double)(guint64)sp [-1].data.l;
4616 ++ip;
4617 MINT_IN_BREAK;
4618 MINT_IN_CASE(MINT_UNBOX)
4619 c = (MonoClass*)imethod->data_items[*(guint16 *)(ip + 1)];
4621 o = sp [-1].data.o;
4622 if (!o)
4623 THROW_EX (mono_get_exception_null_reference (), ip);
4625 if (!(m_class_get_rank (o->vtable->klass) == 0 && m_class_get_element_class (o->vtable->klass) == m_class_get_element_class (c)))
4626 THROW_EX (mono_get_exception_invalid_cast (), ip);
4628 sp [-1].data.p = mono_object_unbox_internal (o);
4629 ip += 2;
4630 MINT_IN_BREAK;
4631 MINT_IN_CASE(MINT_THROW)
4632 --sp;
4633 if (!sp->data.p)
4634 sp->data.p = mono_get_exception_null_reference ();
4636 THROW_EX ((MonoException *)sp->data.p, ip);
4637 MINT_IN_BREAK;
4638 MINT_IN_CASE(MINT_CHECKPOINT)
4639 /* Do synchronous checking of abort requests */
4640 EXCEPTION_CHECKPOINT;
4641 ++ip;
4642 MINT_IN_BREAK;
4643 MINT_IN_CASE(MINT_SAFEPOINT)
4644 /* Do synchronous checking of abort requests */
4645 EXCEPTION_CHECKPOINT;
4646 /* Poll safepoint */
4647 mono_threads_safepoint ();
4648 ++ip;
4649 MINT_IN_BREAK;
4650 MINT_IN_CASE(MINT_LDFLDA_UNSAFE)
4651 o = sp [-1].data.o;
4652 sp[-1].data.p = (char *)o + * (guint16 *)(ip + 1);
4653 ip += 2;
4654 MINT_IN_BREAK;
4655 MINT_IN_CASE(MINT_LDFLDA)
4656 o = sp [-1].data.o;
4657 if (!o)
4658 THROW_EX (mono_get_exception_null_reference (), ip);
4659 sp[-1].data.p = (char *)o + * (guint16 *)(ip + 1);
4660 ip += 2;
4661 MINT_IN_BREAK;
4662 MINT_IN_CASE(MINT_CKNULL_N) {
4663 /* Same as CKNULL, but further down the stack */
4664 int n = *(guint16*)(ip + 1);
4665 o = sp [-n].data.o;
4666 if (!o)
4667 THROW_EX (mono_get_exception_null_reference (), ip);
4668 ip += 2;
4669 MINT_IN_BREAK;
4672 #define LDFLD_UNALIGNED(datamem, fieldtype, unaligned) \
4673 o = sp [-1].data.o; \
4674 if (!o) \
4675 THROW_EX (mono_get_exception_null_reference (), ip); \
4676 if (unaligned) \
4677 memcpy (&sp[-1].data.datamem, (char *)o + * (guint16 *)(ip + 1), sizeof (fieldtype)); \
4678 else \
4679 sp[-1].data.datamem = * (fieldtype *)((char *)o + * (guint16 *)(ip + 1)) ; \
4680 ip += 2;
4682 #define LDFLD(datamem, fieldtype) LDFLD_UNALIGNED(datamem, fieldtype, FALSE)
4684 MINT_IN_CASE(MINT_LDFLD_I1) LDFLD(i, gint8); MINT_IN_BREAK;
4685 MINT_IN_CASE(MINT_LDFLD_U1) LDFLD(i, guint8); MINT_IN_BREAK;
4686 MINT_IN_CASE(MINT_LDFLD_I2) LDFLD(i, gint16); MINT_IN_BREAK;
4687 MINT_IN_CASE(MINT_LDFLD_U2) LDFLD(i, guint16); MINT_IN_BREAK;
4688 MINT_IN_CASE(MINT_LDFLD_I4) LDFLD(i, gint32); MINT_IN_BREAK;
4689 MINT_IN_CASE(MINT_LDFLD_I8) LDFLD(l, gint64); MINT_IN_BREAK;
4690 MINT_IN_CASE(MINT_LDFLD_R4) LDFLD(f_r4, float); MINT_IN_BREAK;
4691 MINT_IN_CASE(MINT_LDFLD_R8) LDFLD(f, double); MINT_IN_BREAK;
4692 MINT_IN_CASE(MINT_LDFLD_O) LDFLD(p, gpointer); MINT_IN_BREAK;
4693 MINT_IN_CASE(MINT_LDFLD_P) LDFLD(p, gpointer); MINT_IN_BREAK;
4694 MINT_IN_CASE(MINT_LDFLD_I8_UNALIGNED) LDFLD_UNALIGNED(l, gint64, TRUE); MINT_IN_BREAK;
4695 MINT_IN_CASE(MINT_LDFLD_R8_UNALIGNED) LDFLD_UNALIGNED(f, double, TRUE); MINT_IN_BREAK;
4697 MINT_IN_CASE(MINT_LDFLD_VT) {
4698 o = sp [-1].data.o;
4699 if (!o)
4700 THROW_EX (mono_get_exception_null_reference (), ip);
4702 int size = READ32(ip + 2);
4703 sp [-1].data.p = vt_sp;
4704 memcpy (sp [-1].data.p, (char *)o + * (guint16 *)(ip + 1), size);
4705 vt_sp += ALIGN_TO (size, MINT_VT_ALIGNMENT);
4706 ip += 4;
4707 MINT_IN_BREAK;
4710 MINT_IN_CASE(MINT_LDRMFLD) {
4711 MonoClassField *field;
4712 char *addr;
4714 o = sp [-1].data.o;
4715 if (!o)
4716 THROW_EX (mono_get_exception_null_reference (), ip);
4717 field = (MonoClassField*)imethod->data_items[* (guint16 *)(ip + 1)];
4718 ip += 2;
4719 #ifndef DISABLE_REMOTING
4720 if (mono_object_is_transparent_proxy (o)) {
4721 gpointer tmp;
4722 MonoClass *klass = ((MonoTransparentProxy*)o)->remote_class->proxy_class;
4724 addr = (char*)mono_load_remote_field_checked (o, klass, field, &tmp, error);
4725 mono_error_cleanup (error); /* FIXME: don't swallow the error */
4726 } else
4727 #endif
4728 addr = (char*)o + field->offset;
4730 stackval_from_data (field->type, &sp [-1], addr, FALSE);
4731 MINT_IN_BREAK;
4734 MINT_IN_CASE(MINT_LDRMFLD_VT) {
4735 MonoClassField *field;
4736 char *addr;
4738 o = sp [-1].data.o;
4739 if (!o)
4740 THROW_EX (mono_get_exception_null_reference (), ip);
4742 field = (MonoClassField*)imethod->data_items[* (guint16 *)(ip + 1)];
4743 MonoClass *klass = mono_class_from_mono_type_internal (field->type);
4744 i32 = mono_class_value_size (klass, NULL);
4746 ip += 2;
4747 #ifndef DISABLE_REMOTING
4748 if (mono_object_is_transparent_proxy (o)) {
4749 gpointer tmp;
4750 MonoClass *klass = ((MonoTransparentProxy*)o)->remote_class->proxy_class;
4751 addr = (char*)mono_load_remote_field_checked (o, klass, field, &tmp, error);
4752 mono_error_cleanup (error); /* FIXME: don't swallow the error */
4753 } else
4754 #endif
4755 addr = (char*)o + field->offset;
4757 sp [-1].data.p = vt_sp;
4758 vt_sp += ALIGN_TO (i32, MINT_VT_ALIGNMENT);
4759 memcpy(sp [-1].data.p, addr, i32);
4760 MINT_IN_BREAK;
4763 #define STFLD_UNALIGNED(datamem, fieldtype, unaligned) \
4764 o = sp [-2].data.o; \
4765 if (!o) \
4766 THROW_EX (mono_get_exception_null_reference (), ip); \
4767 sp -= 2; \
4768 if (unaligned) \
4769 memcpy ((char *)o + * (guint16 *)(ip + 1), &sp[1].data.datamem, sizeof (fieldtype)); \
4770 else \
4771 * (fieldtype *)((char *)o + * (guint16 *)(ip + 1)) = sp[1].data.datamem; \
4772 ip += 2;
4774 #define STFLD(datamem, fieldtype) STFLD_UNALIGNED(datamem, fieldtype, FALSE)
4776 MINT_IN_CASE(MINT_STFLD_I1) STFLD(i, gint8); MINT_IN_BREAK;
4777 MINT_IN_CASE(MINT_STFLD_U1) STFLD(i, guint8); MINT_IN_BREAK;
4778 MINT_IN_CASE(MINT_STFLD_I2) STFLD(i, gint16); MINT_IN_BREAK;
4779 MINT_IN_CASE(MINT_STFLD_U2) STFLD(i, guint16); MINT_IN_BREAK;
4780 MINT_IN_CASE(MINT_STFLD_I4) STFLD(i, gint32); MINT_IN_BREAK;
4781 MINT_IN_CASE(MINT_STFLD_I8) STFLD(l, gint64); MINT_IN_BREAK;
4782 MINT_IN_CASE(MINT_STFLD_R4) STFLD(f_r4, float); MINT_IN_BREAK;
4783 MINT_IN_CASE(MINT_STFLD_R8) STFLD(f, double); MINT_IN_BREAK;
4784 MINT_IN_CASE(MINT_STFLD_P) STFLD(p, gpointer); MINT_IN_BREAK;
4785 MINT_IN_CASE(MINT_STFLD_O)
4786 o = sp [-2].data.o;
4787 if (!o)
4788 THROW_EX (mono_get_exception_null_reference (), ip);
4789 sp -= 2;
4790 mono_gc_wbarrier_set_field_internal (o, (char *) o + * (guint16 *)(ip + 1), sp [1].data.o);
4791 ip += 2;
4792 MINT_IN_BREAK;
4793 MINT_IN_CASE(MINT_STFLD_I8_UNALIGNED) STFLD_UNALIGNED(l, gint64, TRUE); MINT_IN_BREAK;
4794 MINT_IN_CASE(MINT_STFLD_R8_UNALIGNED) STFLD_UNALIGNED(f, double, TRUE); MINT_IN_BREAK;
4796 MINT_IN_CASE(MINT_STFLD_VT) {
4797 o = sp [-2].data.o;
4798 if (!o)
4799 THROW_EX (mono_get_exception_null_reference (), ip);
4800 sp -= 2;
4802 MonoClass *klass = (MonoClass*)imethod->data_items[* (guint16 *)(ip + 2)];
4803 i32 = mono_class_value_size (klass, NULL);
4805 guint16 offset = * (guint16 *)(ip + 1);
4806 mono_value_copy_internal ((char *) o + offset, sp [1].data.p, klass);
4808 vt_sp -= ALIGN_TO (i32, MINT_VT_ALIGNMENT);
4809 ip += 3;
4810 MINT_IN_BREAK;
4812 MINT_IN_CASE(MINT_STRMFLD) {
4813 MonoClassField *field;
4815 o = sp [-2].data.o;
4816 if (!o)
4817 THROW_EX (mono_get_exception_null_reference (), ip);
4819 field = (MonoClassField*)imethod->data_items[* (guint16 *)(ip + 1)];
4820 ip += 2;
4822 #ifndef DISABLE_REMOTING
4823 if (mono_object_is_transparent_proxy (o)) {
4824 MonoClass *klass = ((MonoTransparentProxy*)o)->remote_class->proxy_class;
4825 mono_store_remote_field_checked (o, klass, field, &sp [-1].data, error);
4826 mono_error_cleanup (error); /* FIXME: don't swallow the error */
4827 } else
4828 #endif
4829 stackval_to_data (field->type, &sp [-1], (char*)o + field->offset, FALSE);
4831 sp -= 2;
4832 MINT_IN_BREAK;
4834 MINT_IN_CASE(MINT_STRMFLD_VT) {
4835 MonoClassField *field;
4837 o = sp [-2].data.o;
4838 if (!o)
4839 THROW_EX (mono_get_exception_null_reference (), ip);
4840 field = (MonoClassField*)imethod->data_items[* (guint16 *)(ip + 1)];
4841 MonoClass *klass = mono_class_from_mono_type_internal (field->type);
4842 i32 = mono_class_value_size (klass, NULL);
4843 ip += 2;
4845 #ifndef DISABLE_REMOTING
4846 if (mono_object_is_transparent_proxy (o)) {
4847 MonoClass *klass = ((MonoTransparentProxy*)o)->remote_class->proxy_class;
4848 mono_store_remote_field_checked (o, klass, field, sp [-1].data.p, error);
4849 mono_error_cleanup (error); /* FIXME: don't swallow the error */
4850 } else
4851 #endif
4852 mono_value_copy_internal ((char *) o + field->offset, sp [-1].data.p, klass);
4854 sp -= 2;
4855 vt_sp -= ALIGN_TO (i32, MINT_VT_ALIGNMENT);
4856 MINT_IN_BREAK;
4858 MINT_IN_CASE(MINT_LDSFLDA) {
4859 MonoVTable *vtable = (MonoVTable*) imethod->data_items [*(guint16*)(ip + 1)];
4860 INIT_VTABLE (vtable);
4861 sp->data.p = imethod->data_items [*(guint16*)(ip + 2)];
4862 ip += 3;
4863 ++sp;
4864 MINT_IN_BREAK;
4867 MINT_IN_CASE(MINT_LDSSFLDA) {
4868 guint32 offset = READ32(ip + 1);
4869 sp->data.p = mono_get_special_static_data (offset);
4870 ip += 3;
4871 ++sp;
4872 MINT_IN_BREAK;
4875 /* We init class here to preserve cctor order */
4876 #define LDSFLD(datamem, fieldtype) { \
4877 MonoVTable *vtable = (MonoVTable*) imethod->data_items [*(guint16*)(ip + 1)]; \
4878 INIT_VTABLE (vtable); \
4879 sp[0].data.datamem = * (fieldtype *)(imethod->data_items [* (guint16 *)(ip + 2)]) ; \
4880 ip += 3; \
4881 sp++; \
4884 MINT_IN_CASE(MINT_LDSFLD_I1) LDSFLD(i, gint8); MINT_IN_BREAK;
4885 MINT_IN_CASE(MINT_LDSFLD_U1) LDSFLD(i, guint8); MINT_IN_BREAK;
4886 MINT_IN_CASE(MINT_LDSFLD_I2) LDSFLD(i, gint16); MINT_IN_BREAK;
4887 MINT_IN_CASE(MINT_LDSFLD_U2) LDSFLD(i, guint16); MINT_IN_BREAK;
4888 MINT_IN_CASE(MINT_LDSFLD_I4) LDSFLD(i, gint32); MINT_IN_BREAK;
4889 MINT_IN_CASE(MINT_LDSFLD_I8) LDSFLD(l, gint64); MINT_IN_BREAK;
4890 MINT_IN_CASE(MINT_LDSFLD_R4) LDSFLD(f_r4, float); MINT_IN_BREAK;
4891 MINT_IN_CASE(MINT_LDSFLD_R8) LDSFLD(f, double); MINT_IN_BREAK;
4892 MINT_IN_CASE(MINT_LDSFLD_O) LDSFLD(p, gpointer); MINT_IN_BREAK;
4893 MINT_IN_CASE(MINT_LDSFLD_P) LDSFLD(p, gpointer); MINT_IN_BREAK;
4895 MINT_IN_CASE(MINT_LDSFLD_VT) {
4896 MonoVTable *vtable = (MonoVTable*) imethod->data_items [*(guint16*)(ip + 1)];
4897 gpointer addr = imethod->data_items [*(guint16*)(ip + 2)];
4898 i32 = READ32(ip + 3);
4899 INIT_VTABLE (vtable);
4900 sp->data.p = vt_sp;
4902 memcpy (vt_sp, addr, i32);
4903 vt_sp += ALIGN_TO (i32, MINT_VT_ALIGNMENT);
4904 ip += 5;
4905 ++sp;
4906 MINT_IN_BREAK;
4909 #define LDTSFLD(datamem, fieldtype) { \
4910 guint32 offset = READ32(ip + 1); \
4911 MonoInternalThread *thread = mono_thread_internal_current (); \
4912 gpointer addr = ((char*)thread->static_data [offset & 0x3f]) + (offset >> 6); \
4913 sp[0].data.datamem = *(fieldtype*)addr; \
4914 ip += 3; \
4915 ++sp; \
4917 MINT_IN_CASE(MINT_LDTSFLD_I1) LDTSFLD(i, gint8); MINT_IN_BREAK;
4918 MINT_IN_CASE(MINT_LDTSFLD_U1) LDTSFLD(i, guint8); MINT_IN_BREAK;
4919 MINT_IN_CASE(MINT_LDTSFLD_I2) LDTSFLD(i, gint16); MINT_IN_BREAK;
4920 MINT_IN_CASE(MINT_LDTSFLD_U2) LDTSFLD(i, guint16); MINT_IN_BREAK;
4921 MINT_IN_CASE(MINT_LDTSFLD_I4) LDTSFLD(i, gint32); MINT_IN_BREAK;
4922 MINT_IN_CASE(MINT_LDTSFLD_I8) LDTSFLD(l, gint64); MINT_IN_BREAK;
4923 MINT_IN_CASE(MINT_LDTSFLD_R4) LDTSFLD(f_r4, float); MINT_IN_BREAK;
4924 MINT_IN_CASE(MINT_LDTSFLD_R8) LDTSFLD(f, double); MINT_IN_BREAK;
4925 MINT_IN_CASE(MINT_LDTSFLD_O) LDTSFLD(p, gpointer); MINT_IN_BREAK;
4926 MINT_IN_CASE(MINT_LDTSFLD_P) LDTSFLD(p, gpointer); MINT_IN_BREAK;
4928 MINT_IN_CASE(MINT_LDSSFLD) {
4929 MonoClassField *field = (MonoClassField*)imethod->data_items [* (guint16 *)(ip + 1)];
4930 guint32 offset = READ32(ip + 2);
4931 gpointer addr = mono_get_special_static_data (offset);
4932 stackval_from_data (field->type, sp, addr, FALSE);
4933 ip += 4;
4934 ++sp;
4935 MINT_IN_BREAK;
4937 MINT_IN_CASE(MINT_LDSSFLD_VT) {
4938 guint32 offset = READ32(ip + 1);
4939 gpointer addr = mono_get_special_static_data (offset);
4941 int size = READ32 (ip + 3);
4942 memcpy (vt_sp, addr, size);
4943 sp->data.p = vt_sp;
4944 vt_sp += ALIGN_TO (size, MINT_VT_ALIGNMENT);
4945 ip += 5;
4946 ++sp;
4947 MINT_IN_BREAK;
4949 #define STSFLD(datamem, fieldtype) { \
4950 MonoVTable *vtable = (MonoVTable*) imethod->data_items [*(guint16*)(ip + 1)]; \
4951 INIT_VTABLE (vtable); \
4952 sp --; \
4953 * (fieldtype *)(imethod->data_items [* (guint16 *)(ip + 2)]) = sp[0].data.datamem; \
4954 ip += 3; \
4957 MINT_IN_CASE(MINT_STSFLD_I1) STSFLD(i, gint8); MINT_IN_BREAK;
4958 MINT_IN_CASE(MINT_STSFLD_U1) STSFLD(i, guint8); MINT_IN_BREAK;
4959 MINT_IN_CASE(MINT_STSFLD_I2) STSFLD(i, gint16); MINT_IN_BREAK;
4960 MINT_IN_CASE(MINT_STSFLD_U2) STSFLD(i, guint16); MINT_IN_BREAK;
4961 MINT_IN_CASE(MINT_STSFLD_I4) STSFLD(i, gint32); MINT_IN_BREAK;
4962 MINT_IN_CASE(MINT_STSFLD_I8) STSFLD(l, gint64); MINT_IN_BREAK;
4963 MINT_IN_CASE(MINT_STSFLD_R4) STSFLD(f_r4, float); MINT_IN_BREAK;
4964 MINT_IN_CASE(MINT_STSFLD_R8) STSFLD(f, double); MINT_IN_BREAK;
4965 MINT_IN_CASE(MINT_STSFLD_P) STSFLD(p, gpointer); MINT_IN_BREAK;
4966 MINT_IN_CASE(MINT_STSFLD_O) STSFLD(p, gpointer); MINT_IN_BREAK;
4968 MINT_IN_CASE(MINT_STSFLD_VT) {
4969 MonoVTable *vtable = (MonoVTable*) imethod->data_items [*(guint16*)(ip + 1)];
4970 gpointer addr = imethod->data_items [*(guint16*)(ip + 2)];
4971 i32 = READ32(ip + 3);
4972 INIT_VTABLE (vtable);
4974 memcpy (addr, sp [-1].data.vt, i32);
4975 vt_sp -= ALIGN_TO (i32, MINT_VT_ALIGNMENT);
4976 ip += 4;
4977 --sp;
4978 MINT_IN_BREAK;
4981 #define STTSFLD(datamem, fieldtype) { \
4982 guint32 offset = READ32(ip + 1); \
4983 MonoInternalThread *thread = mono_thread_internal_current (); \
4984 gpointer addr = ((char*)thread->static_data [offset & 0x3f]) + (offset >> 6); \
4985 sp--; \
4986 *(fieldtype*)addr = sp[0].data.datamem; \
4987 ip += 3; \
4990 MINT_IN_CASE(MINT_STTSFLD_I1) STTSFLD(i, gint8); MINT_IN_BREAK;
4991 MINT_IN_CASE(MINT_STTSFLD_U1) STTSFLD(i, guint8); MINT_IN_BREAK;
4992 MINT_IN_CASE(MINT_STTSFLD_I2) STTSFLD(i, gint16); MINT_IN_BREAK;
4993 MINT_IN_CASE(MINT_STTSFLD_U2) STTSFLD(i, guint16); MINT_IN_BREAK;
4994 MINT_IN_CASE(MINT_STTSFLD_I4) STTSFLD(i, gint32); MINT_IN_BREAK;
4995 MINT_IN_CASE(MINT_STTSFLD_I8) STTSFLD(l, gint64); MINT_IN_BREAK;
4996 MINT_IN_CASE(MINT_STTSFLD_R4) STTSFLD(f_r4, float); MINT_IN_BREAK;
4997 MINT_IN_CASE(MINT_STTSFLD_R8) STTSFLD(f, double); MINT_IN_BREAK;
4998 MINT_IN_CASE(MINT_STTSFLD_P) STTSFLD(p, gpointer); MINT_IN_BREAK;
4999 MINT_IN_CASE(MINT_STTSFLD_O) STTSFLD(p, gpointer); MINT_IN_BREAK;
5001 MINT_IN_CASE(MINT_STSSFLD) {
5002 MonoClassField *field = (MonoClassField*)imethod->data_items [* (guint16 *)(ip + 1)];
5003 guint32 offset = READ32(ip + 2);
5004 gpointer addr = mono_get_special_static_data (offset);
5005 --sp;
5006 stackval_to_data (field->type, sp, addr, FALSE);
5007 ip += 4;
5008 MINT_IN_BREAK;
5010 MINT_IN_CASE(MINT_STSSFLD_VT) {
5011 guint32 offset = READ32(ip + 1);
5012 gpointer addr = mono_get_special_static_data (offset);
5013 --sp;
5014 int size = READ32 (ip + 3);
5015 memcpy (addr, sp->data.vt, size);
5016 vt_sp -= ALIGN_TO (size, MINT_VT_ALIGNMENT);
5017 ip += 5;
5018 MINT_IN_BREAK;
5021 MINT_IN_CASE(MINT_STOBJ_VT) {
5022 int size;
5023 c = (MonoClass*)imethod->data_items[* (guint16 *)(ip + 1)];
5024 ip += 2;
5025 size = mono_class_value_size (c, NULL);
5026 mono_value_copy_internal (sp [-2].data.p, sp [-1].data.p, c);
5027 vt_sp -= ALIGN_TO (size, MINT_VT_ALIGNMENT);
5028 sp -= 2;
5029 MINT_IN_BREAK;
5031 MINT_IN_CASE(MINT_CONV_OVF_I4_UN_R8)
5032 if (sp [-1].data.f < 0 || sp [-1].data.f > G_MAXINT32)
5033 THROW_EX (mono_get_exception_overflow (), ip);
5034 sp [-1].data.i = (gint32)sp [-1].data.f;
5035 ++ip;
5036 MINT_IN_BREAK;
5037 MINT_IN_CASE(MINT_CONV_OVF_U8_I4)
5038 if (sp [-1].data.i < 0)
5039 THROW_EX (mono_get_exception_overflow (), ip);
5040 sp [-1].data.l = sp [-1].data.i;
5041 ++ip;
5042 MINT_IN_BREAK;
5043 MINT_IN_CASE(MINT_CONV_OVF_U8_I8)
5044 if (sp [-1].data.l < 0)
5045 THROW_EX (mono_get_exception_overflow (), ip);
5046 ++ip;
5047 MINT_IN_BREAK;
5048 MINT_IN_CASE(MINT_CONV_OVF_I8_U8)
5049 if ((guint64) sp [-1].data.l > G_MAXINT64)
5050 THROW_EX (mono_get_exception_overflow (), ip);
5051 ++ip;
5052 MINT_IN_BREAK;
5053 MINT_IN_CASE(MINT_CONV_OVF_U8_R4)
5054 if (sp [-1].data.f_r4 < 0 || sp [-1].data.f_r4 > G_MAXUINT64 || isnan (sp [-1].data.f_r4))
5055 THROW_EX (mono_get_exception_overflow (), ip);
5056 sp [-1].data.l = (guint64)sp [-1].data.f_r4;
5057 ++ip;
5058 MINT_IN_BREAK;
5059 MINT_IN_CASE(MINT_CONV_OVF_U8_R8)
5060 if (sp [-1].data.f < 0 || sp [-1].data.f > G_MAXUINT64 || isnan (sp [-1].data.f))
5061 THROW_EX (mono_get_exception_overflow (), ip);
5062 sp [-1].data.l = (guint64)sp [-1].data.f;
5063 ++ip;
5064 MINT_IN_BREAK;
5065 MINT_IN_CASE(MINT_CONV_OVF_I8_UN_R8)
5066 if (sp [-1].data.f < 0 || sp [-1].data.f > G_MAXINT64)
5067 THROW_EX (mono_get_exception_overflow (), ip);
5068 sp [-1].data.l = (gint64)sp [-1].data.f;
5069 ++ip;
5070 MINT_IN_BREAK;
5071 MINT_IN_CASE(MINT_CONV_OVF_I8_R4)
5072 if (sp [-1].data.f_r4 < G_MININT64 || sp [-1].data.f_r4 > G_MAXINT64 || isnan (sp [-1].data.f_r4))
5073 THROW_EX (mono_get_exception_overflow (), ip);
5074 sp [-1].data.l = (gint64)sp [-1].data.f_r4;
5075 ++ip;
5076 MINT_IN_BREAK;
5077 MINT_IN_CASE(MINT_CONV_OVF_I8_R8)
5078 if (sp [-1].data.f < G_MININT64 || sp [-1].data.f > G_MAXINT64 || isnan (sp [-1].data.f))
5079 THROW_EX (mono_get_exception_overflow (), ip);
5080 sp [-1].data.l = (gint64)sp [-1].data.f;
5081 ++ip;
5082 MINT_IN_BREAK;
5083 MINT_IN_CASE(MINT_CONV_OVF_I4_UN_I8)
5084 if ((guint64)sp [-1].data.l > G_MAXINT32)
5085 THROW_EX (mono_get_exception_overflow (), ip);
5086 sp [-1].data.i = (gint32)sp [-1].data.l;
5087 ++ip;
5088 MINT_IN_BREAK;
5089 MINT_IN_CASE(MINT_BOX) {
5090 MonoVTable *vtable = (MonoVTable*)imethod->data_items [* (guint16 *)(ip + 1)];
5091 guint16 offset = * (guint16 *)(ip + 2);
5093 MonoObject *obj = mono_gc_alloc_obj (vtable, m_class_get_instance_size (vtable->klass));
5094 stackval_to_data (m_class_get_byval_arg (vtable->klass), &sp [-1 - offset], mono_object_get_data (obj), FALSE);
5096 sp [-1 - offset].data.p = obj;
5098 ip += 3;
5099 MINT_IN_BREAK;
5101 MINT_IN_CASE(MINT_BOX_VT) {
5102 MonoVTable *vtable = (MonoVTable*)imethod->data_items [* (guint16 *)(ip + 1)];
5103 c = vtable->klass;
5104 guint16 offset = * (guint16 *)(ip + 2);
5105 gboolean pop_vt_sp = !(offset & BOX_NOT_CLEAR_VT_SP);
5106 offset &= ~BOX_NOT_CLEAR_VT_SP;
5108 int size = mono_class_value_size (c, NULL);
5109 MonoObject *obj = mono_gc_alloc_obj (vtable, m_class_get_instance_size (vtable->klass));
5110 mono_value_copy_internal (mono_object_get_data (obj), sp [-1 - offset].data.p, c);
5112 sp [-1 - offset].data.p = obj;
5113 size = ALIGN_TO (size, MINT_VT_ALIGNMENT);
5114 if (pop_vt_sp)
5115 vt_sp -= size;
5117 ip += 3;
5118 MINT_IN_BREAK;
5120 MINT_IN_CASE(MINT_BOX_NULLABLE) {
5121 c = (MonoClass*)imethod->data_items [* (guint16 *)(ip + 1)];
5122 guint16 offset = * (guint16 *)(ip + 2);
5123 gboolean pop_vt_sp = !(offset & BOX_NOT_CLEAR_VT_SP);
5124 offset &= ~BOX_NOT_CLEAR_VT_SP;
5126 int size = mono_class_value_size (c, NULL);
5128 sp [-1 - offset].data.p = mono_nullable_box (sp [-1 - offset].data.p, c, error);
5129 mono_error_cleanup (error); /* FIXME: don't swallow the error */
5131 size = ALIGN_TO (size, MINT_VT_ALIGNMENT);
5132 if (pop_vt_sp)
5133 vt_sp -= size;
5135 ip += 3;
5136 MINT_IN_BREAK;
5138 MINT_IN_CASE(MINT_NEWARR)
5139 sp [-1].data.p = (MonoObject*) mono_array_new_checked (imethod->domain, (MonoClass*)imethod->data_items[*(guint16 *)(ip + 1)], sp [-1].data.i, error);
5140 if (!mono_error_ok (error)) {
5141 THROW_EX (mono_error_convert_to_exception (error), ip);
5143 mono_error_cleanup (error); /* FIXME: don't swallow the error */
5144 ip += 2;
5145 /*if (profiling_classes) {
5146 guint count = GPOINTER_TO_UINT (g_hash_table_lookup (profiling_classes, o->vtable->klass));
5147 count++;
5148 g_hash_table_insert (profiling_classes, o->vtable->klass, GUINT_TO_POINTER (count));
5151 MINT_IN_BREAK;
5152 MINT_IN_CASE(MINT_LDLEN)
5153 o = sp [-1].data.o;
5154 if (!o)
5155 THROW_EX (mono_get_exception_null_reference (), ip);
5156 sp [-1].data.nati = mono_array_length_internal ((MonoArray *)o);
5157 ++ip;
5158 MINT_IN_BREAK;
5159 MINT_IN_CASE(MINT_LDLEN_SPAN) {
5160 o = sp [-1].data.o;
5161 gsize offset_length = (gsize) *(gint16 *) (ip + 1);
5162 if (!o)
5163 THROW_EX (mono_get_exception_null_reference (), ip);
5164 sp [-1].data.nati = *(gint32 *) ((guint8 *) o + offset_length);
5165 ip += 2;
5166 MINT_IN_BREAK;
5168 MINT_IN_CASE(MINT_GETCHR) {
5169 MonoString *s;
5170 s = (MonoString*)sp [-2].data.p;
5171 if (!s)
5172 THROW_EX (mono_get_exception_null_reference (), ip);
5173 i32 = sp [-1].data.i;
5174 if (i32 < 0 || i32 >= mono_string_length_internal (s))
5175 THROW_EX (mono_get_exception_index_out_of_range (), ip);
5176 --sp;
5177 sp [-1].data.i = mono_string_chars_internal (s)[i32];
5178 ++ip;
5179 MINT_IN_BREAK;
5181 MINT_IN_CASE(MINT_GETITEM_SPAN) {
5182 guint8 *span = (guint8 *) sp [-2].data.p;
5183 int index = sp [-1].data.i;
5184 gsize element_size = (gsize) *(gint16 *) (ip + 1);
5185 gsize offset_length = (gsize) *(gint16 *) (ip + 2);
5186 gsize offset_pointer = (gsize) *(gint16 *) (ip + 3);
5187 sp--;
5189 if (!span)
5190 THROW_EX (mono_get_exception_null_reference (), ip);
5192 gint32 length = *(gint32 *) (span + offset_length);
5193 if (index < 0 || index >= length)
5194 THROW_EX (mono_get_exception_index_out_of_range (), ip);
5196 gpointer pointer = *(gpointer *)(span + offset_pointer);
5197 sp [-1].data.p = (guint8 *) pointer + index * element_size;
5199 ip += 4;
5200 MINT_IN_BREAK;
5202 MINT_IN_CASE(MINT_STRLEN)
5203 ++ip;
5204 o = sp [-1].data.o;
5205 if (!o)
5206 THROW_EX (mono_get_exception_null_reference (), ip);
5207 sp [-1].data.i = mono_string_length_internal ((MonoString*) o);
5208 MINT_IN_BREAK;
5209 MINT_IN_CASE(MINT_ARRAY_RANK)
5210 o = sp [-1].data.o;
5211 if (!o)
5212 THROW_EX (mono_get_exception_null_reference (), ip);
5213 sp [-1].data.i = m_class_get_rank (mono_object_class (sp [-1].data.p));
5214 ip++;
5215 MINT_IN_BREAK;
5216 MINT_IN_CASE(MINT_LDELEMA)
5217 MINT_IN_CASE(MINT_LDELEMA_TC) {
5218 gboolean needs_typecheck = *ip == MINT_LDELEMA_TC;
5220 MonoClass *klass = (MonoClass*)imethod->data_items [*(guint16 *) (ip + 1)];
5221 guint16 numargs = *(guint16 *) (ip + 2);
5222 ip += 3;
5223 sp -= numargs;
5225 o = sp [0].data.o;
5226 if (!o)
5227 THROW_EX (mono_get_exception_null_reference (), ip);
5228 sp->data.p = ves_array_element_address (frame, klass, (MonoArray *) o, &sp [1], needs_typecheck);
5229 if (frame->ex)
5230 THROW_EX (frame->ex, ip);
5231 ++sp;
5233 MINT_IN_BREAK;
5235 MINT_IN_CASE(MINT_LDELEM_I1) /* fall through */
5236 MINT_IN_CASE(MINT_LDELEM_U1) /* fall through */
5237 MINT_IN_CASE(MINT_LDELEM_I2) /* fall through */
5238 MINT_IN_CASE(MINT_LDELEM_U2) /* fall through */
5239 MINT_IN_CASE(MINT_LDELEM_I4) /* fall through */
5240 MINT_IN_CASE(MINT_LDELEM_U4) /* fall through */
5241 MINT_IN_CASE(MINT_LDELEM_I8) /* fall through */
5242 MINT_IN_CASE(MINT_LDELEM_I) /* fall through */
5243 MINT_IN_CASE(MINT_LDELEM_R4) /* fall through */
5244 MINT_IN_CASE(MINT_LDELEM_R8) /* fall through */
5245 MINT_IN_CASE(MINT_LDELEM_REF) /* fall through */
5246 MINT_IN_CASE(MINT_LDELEM_VT) {
5247 MonoArray *o;
5248 mono_u aindex;
5250 sp -= 2;
5252 o = (MonoArray*)sp [0].data.p;
5253 if (!o)
5254 THROW_EX (mono_get_exception_null_reference (), ip);
5256 aindex = sp [1].data.i;
5257 if (aindex >= mono_array_length_internal (o))
5258 THROW_EX (mono_get_exception_index_out_of_range (), ip);
5261 * FIXME: throw mono_get_exception_array_type_mismatch () if needed
5263 switch (*ip) {
5264 case MINT_LDELEM_I1:
5265 sp [0].data.i = mono_array_get_fast (o, gint8, aindex);
5266 break;
5267 case MINT_LDELEM_U1:
5268 sp [0].data.i = mono_array_get_fast (o, guint8, aindex);
5269 break;
5270 case MINT_LDELEM_I2:
5271 sp [0].data.i = mono_array_get_fast (o, gint16, aindex);
5272 break;
5273 case MINT_LDELEM_U2:
5274 sp [0].data.i = mono_array_get_fast (o, guint16, aindex);
5275 break;
5276 case MINT_LDELEM_I:
5277 sp [0].data.nati = mono_array_get_fast (o, mono_i, aindex);
5278 break;
5279 case MINT_LDELEM_I4:
5280 sp [0].data.i = mono_array_get_fast (o, gint32, aindex);
5281 break;
5282 case MINT_LDELEM_U4:
5283 sp [0].data.i = mono_array_get_fast (o, guint32, aindex);
5284 break;
5285 case MINT_LDELEM_I8:
5286 sp [0].data.l = mono_array_get_fast (o, guint64, aindex);
5287 break;
5288 case MINT_LDELEM_R4:
5289 sp [0].data.f_r4 = mono_array_get_fast (o, float, aindex);
5290 break;
5291 case MINT_LDELEM_R8:
5292 sp [0].data.f = mono_array_get_fast (o, double, aindex);
5293 break;
5294 case MINT_LDELEM_REF:
5295 sp [0].data.p = mono_array_get_fast (o, gpointer, aindex);
5296 break;
5297 case MINT_LDELEM_VT: {
5298 i32 = READ32 (ip + 1);
5299 char *src_addr = mono_array_addr_with_size_fast ((MonoArray *) o, i32, aindex);
5300 sp [0].data.vt = vt_sp;
5301 // Copying to vtstack. No wbarrier needed
5302 memcpy (sp [0].data.vt, src_addr, i32);
5303 vt_sp += ALIGN_TO (i32, MINT_VT_ALIGNMENT);
5304 ip += 2;
5305 break;
5307 default:
5308 ves_abort();
5311 ++ip;
5312 ++sp;
5313 MINT_IN_BREAK;
5315 MINT_IN_CASE(MINT_STELEM_I) /* fall through */
5316 MINT_IN_CASE(MINT_STELEM_I1) /* fall through */
5317 MINT_IN_CASE(MINT_STELEM_U1) /* fall through */
5318 MINT_IN_CASE(MINT_STELEM_I2) /* fall through */
5319 MINT_IN_CASE(MINT_STELEM_U2) /* fall through */
5320 MINT_IN_CASE(MINT_STELEM_I4) /* fall through */
5321 MINT_IN_CASE(MINT_STELEM_I8) /* fall through */
5322 MINT_IN_CASE(MINT_STELEM_R4) /* fall through */
5323 MINT_IN_CASE(MINT_STELEM_R8) /* fall through */
5324 MINT_IN_CASE(MINT_STELEM_REF) /* fall through */
5325 MINT_IN_CASE(MINT_STELEM_VT) {
5326 mono_u aindex;
5328 sp -= 3;
5330 o = sp [0].data.o;
5331 if (!o)
5332 THROW_EX (mono_get_exception_null_reference (), ip);
5334 aindex = sp [1].data.i;
5335 if (aindex >= mono_array_length_internal ((MonoArray *)o))
5336 THROW_EX (mono_get_exception_index_out_of_range (), ip);
5338 switch (*ip) {
5339 case MINT_STELEM_I:
5340 mono_array_set_fast ((MonoArray *)o, mono_i, aindex, sp [2].data.nati);
5341 break;
5342 case MINT_STELEM_I1:
5343 mono_array_set_fast ((MonoArray *)o, gint8, aindex, sp [2].data.i);
5344 break;
5345 case MINT_STELEM_U1:
5346 mono_array_set_fast ((MonoArray *) o, guint8, aindex, sp [2].data.i);
5347 break;
5348 case MINT_STELEM_I2:
5349 mono_array_set_fast ((MonoArray *)o, gint16, aindex, sp [2].data.i);
5350 break;
5351 case MINT_STELEM_U2:
5352 mono_array_set_fast ((MonoArray *)o, guint16, aindex, sp [2].data.i);
5353 break;
5354 case MINT_STELEM_I4:
5355 mono_array_set_fast ((MonoArray *)o, gint32, aindex, sp [2].data.i);
5356 break;
5357 case MINT_STELEM_I8:
5358 mono_array_set_fast ((MonoArray *)o, gint64, aindex, sp [2].data.l);
5359 break;
5360 case MINT_STELEM_R4:
5361 mono_array_set_fast ((MonoArray *)o, float, aindex, sp [2].data.f_r4);
5362 break;
5363 case MINT_STELEM_R8:
5364 mono_array_set_fast ((MonoArray *)o, double, aindex, sp [2].data.f);
5365 break;
5366 case MINT_STELEM_REF: {
5367 MonoObject *isinst_obj = mono_object_isinst_checked (sp [2].data.o, m_class_get_element_class (mono_object_class (o)), error);
5368 mono_error_cleanup (error); /* FIXME: don't swallow the error */
5369 if (sp [2].data.p && !isinst_obj)
5370 THROW_EX (mono_get_exception_array_type_mismatch (), ip);
5371 mono_array_setref_fast ((MonoArray *) o, aindex, sp [2].data.p);
5372 break;
5374 case MINT_STELEM_VT: {
5375 MonoClass *klass_vt = (MonoClass*)imethod->data_items [*(guint16 *) (ip + 1)];
5376 i32 = READ32 (ip + 2);
5377 char *dst_addr = mono_array_addr_with_size_fast ((MonoArray *) o, i32, aindex);
5379 mono_value_copy_internal (dst_addr, sp [2].data.vt, klass_vt);
5380 vt_sp -= ALIGN_TO (i32, MINT_VT_ALIGNMENT);
5381 ip += 3;
5382 break;
5384 default:
5385 ves_abort();
5388 ++ip;
5389 MINT_IN_BREAK;
5391 MINT_IN_CASE(MINT_CONV_OVF_I4_U4)
5392 if (sp [-1].data.i < 0)
5393 THROW_EX (mono_get_exception_overflow (), ip);
5394 ++ip;
5395 MINT_IN_BREAK;
5396 MINT_IN_CASE(MINT_CONV_OVF_I4_I8)
5397 if (sp [-1].data.l < G_MININT32 || sp [-1].data.l > G_MAXINT32)
5398 THROW_EX (mono_get_exception_overflow (), ip);
5399 sp [-1].data.i = (gint32) sp [-1].data.l;
5400 ++ip;
5401 MINT_IN_BREAK;
5402 MINT_IN_CASE(MINT_CONV_OVF_I4_U8)
5403 if (sp [-1].data.l < 0 || sp [-1].data.l > G_MAXINT32)
5404 THROW_EX (mono_get_exception_overflow (), ip);
5405 sp [-1].data.i = (gint32) sp [-1].data.l;
5406 ++ip;
5407 MINT_IN_BREAK;
5408 MINT_IN_CASE(MINT_CONV_OVF_I4_R4)
5409 if (sp [-1].data.f_r4 < G_MININT32 || sp [-1].data.f_r4 > G_MAXINT32)
5410 THROW_EX (mono_get_exception_overflow (), ip);
5411 sp [-1].data.i = (gint32) sp [-1].data.f_r4;
5412 ++ip;
5413 MINT_IN_BREAK;
5414 MINT_IN_CASE(MINT_CONV_OVF_I4_R8)
5415 if (sp [-1].data.f < G_MININT32 || sp [-1].data.f > G_MAXINT32)
5416 THROW_EX (mono_get_exception_overflow (), ip);
5417 sp [-1].data.i = (gint32) sp [-1].data.f;
5418 ++ip;
5419 MINT_IN_BREAK;
5420 MINT_IN_CASE(MINT_CONV_OVF_U4_I4)
5421 if (sp [-1].data.i < 0)
5422 THROW_EX (mono_get_exception_overflow (), ip);
5423 ++ip;
5424 MINT_IN_BREAK;
5425 MINT_IN_CASE(MINT_CONV_OVF_U4_I8)
5426 if (sp [-1].data.l < 0 || sp [-1].data.l > G_MAXUINT32)
5427 THROW_EX (mono_get_exception_overflow (), ip);
5428 sp [-1].data.i = (guint32) sp [-1].data.l;
5429 ++ip;
5430 MINT_IN_BREAK;
5431 MINT_IN_CASE(MINT_CONV_OVF_U4_R4)
5432 if (sp [-1].data.f_r4 < 0 || sp [-1].data.f_r4 > G_MAXUINT32)
5433 THROW_EX (mono_get_exception_overflow (), ip);
5434 sp [-1].data.i = (guint32) sp [-1].data.f_r4;
5435 ++ip;
5436 MINT_IN_BREAK;
5437 MINT_IN_CASE(MINT_CONV_OVF_U4_R8)
5438 if (sp [-1].data.f < 0 || sp [-1].data.f > G_MAXUINT32)
5439 THROW_EX (mono_get_exception_overflow (), ip);
5440 sp [-1].data.i = (guint32) sp [-1].data.f;
5441 ++ip;
5442 MINT_IN_BREAK;
5443 MINT_IN_CASE(MINT_CONV_OVF_I2_I4)
5444 if (sp [-1].data.i < G_MININT16 || sp [-1].data.i > G_MAXINT16)
5445 THROW_EX (mono_get_exception_overflow (), ip);
5446 ++ip;
5447 MINT_IN_BREAK;
5448 MINT_IN_CASE(MINT_CONV_OVF_I2_U4)
5449 if (sp [-1].data.i < 0 || sp [-1].data.i > G_MAXINT16)
5450 THROW_EX (mono_get_exception_overflow (), ip);
5451 ++ip;
5452 MINT_IN_BREAK;
5453 MINT_IN_CASE(MINT_CONV_OVF_I2_I8)
5454 if (sp [-1].data.l < G_MININT16 || sp [-1].data.l > G_MAXINT16)
5455 THROW_EX (mono_get_exception_overflow (), ip);
5456 sp [-1].data.i = (gint16) sp [-1].data.l;
5457 ++ip;
5458 MINT_IN_BREAK;
5459 MINT_IN_CASE(MINT_CONV_OVF_I2_U8)
5460 if (sp [-1].data.l < 0 || sp [-1].data.l > G_MAXINT16)
5461 THROW_EX (mono_get_exception_overflow (), ip);
5462 sp [-1].data.i = (gint16) sp [-1].data.l;
5463 ++ip;
5464 MINT_IN_BREAK;
5465 MINT_IN_CASE(MINT_CONV_OVF_I2_R8)
5466 if (sp [-1].data.f < G_MININT16 || sp [-1].data.f > G_MAXINT16)
5467 THROW_EX (mono_get_exception_overflow (), ip);
5468 sp [-1].data.i = (gint16) sp [-1].data.f;
5469 ++ip;
5470 MINT_IN_BREAK;
5471 MINT_IN_CASE(MINT_CONV_OVF_I2_UN_R8)
5472 if (sp [-1].data.f < 0 || sp [-1].data.f > G_MAXINT16)
5473 THROW_EX (mono_get_exception_overflow (), ip);
5474 sp [-1].data.i = (gint16) sp [-1].data.f;
5475 ++ip;
5476 MINT_IN_BREAK;
5477 MINT_IN_CASE(MINT_CONV_OVF_U2_I4)
5478 if (sp [-1].data.i < 0 || sp [-1].data.i > G_MAXUINT16)
5479 THROW_EX (mono_get_exception_overflow (), ip);
5480 ++ip;
5481 MINT_IN_BREAK;
5482 MINT_IN_CASE(MINT_CONV_OVF_U2_I8)
5483 if (sp [-1].data.l < 0 || sp [-1].data.l > G_MAXUINT16)
5484 THROW_EX (mono_get_exception_overflow (), ip);
5485 sp [-1].data.i = (guint16) sp [-1].data.l;
5486 ++ip;
5487 MINT_IN_BREAK;
5488 MINT_IN_CASE(MINT_CONV_OVF_U2_R8)
5489 if (sp [-1].data.f < 0 || sp [-1].data.f > G_MAXUINT16)
5490 THROW_EX (mono_get_exception_overflow (), ip);
5491 sp [-1].data.i = (guint16) sp [-1].data.f;
5492 ++ip;
5493 MINT_IN_BREAK;
5494 MINT_IN_CASE(MINT_CONV_OVF_I1_I4)
5495 if (sp [-1].data.i < G_MININT8 || sp [-1].data.i > G_MAXINT8)
5496 THROW_EX (mono_get_exception_overflow (), ip);
5497 ++ip;
5498 MINT_IN_BREAK;
5499 MINT_IN_CASE(MINT_CONV_OVF_I1_U4)
5500 if (sp [-1].data.i < 0 || sp [-1].data.i > G_MAXINT8)
5501 THROW_EX (mono_get_exception_overflow (), ip);
5502 ++ip;
5503 MINT_IN_BREAK;
5504 MINT_IN_CASE(MINT_CONV_OVF_I1_I8)
5505 if (sp [-1].data.l < G_MININT8 || sp [-1].data.l > G_MAXINT8)
5506 THROW_EX (mono_get_exception_overflow (), ip);
5507 sp [-1].data.i = (gint8) sp [-1].data.l;
5508 ++ip;
5509 MINT_IN_BREAK;
5510 MINT_IN_CASE(MINT_CONV_OVF_I1_U8)
5511 if (sp [-1].data.l < 0 || sp [-1].data.l > G_MAXINT8)
5512 THROW_EX (mono_get_exception_overflow (), ip);
5513 sp [-1].data.i = (gint8) sp [-1].data.l;
5514 ++ip;
5515 MINT_IN_BREAK;
5516 MINT_IN_CASE(MINT_CONV_OVF_I1_R8)
5517 if (sp [-1].data.f < G_MININT8 || sp [-1].data.f > G_MAXINT8)
5518 THROW_EX (mono_get_exception_overflow (), ip);
5519 sp [-1].data.i = (gint8) sp [-1].data.f;
5520 ++ip;
5521 MINT_IN_BREAK;
5522 MINT_IN_CASE(MINT_CONV_OVF_I1_UN_R8)
5523 if (sp [-1].data.f < 0 || sp [-1].data.f > G_MAXINT8)
5524 THROW_EX (mono_get_exception_overflow (), ip);
5525 sp [-1].data.i = (gint8) sp [-1].data.f;
5526 ++ip;
5527 MINT_IN_BREAK;
5528 MINT_IN_CASE(MINT_CONV_OVF_U1_I4)
5529 if (sp [-1].data.i < 0 || sp [-1].data.i > G_MAXUINT8)
5530 THROW_EX (mono_get_exception_overflow (), ip);
5531 ++ip;
5532 MINT_IN_BREAK;
5533 MINT_IN_CASE(MINT_CONV_OVF_U1_I8)
5534 if (sp [-1].data.l < 0 || sp [-1].data.l > G_MAXUINT8)
5535 THROW_EX (mono_get_exception_overflow (), ip);
5536 sp [-1].data.i = (guint8) sp [-1].data.l;
5537 ++ip;
5538 MINT_IN_BREAK;
5539 MINT_IN_CASE(MINT_CONV_OVF_U1_R8)
5540 if (sp [-1].data.f < 0 || sp [-1].data.f > G_MAXUINT8)
5541 THROW_EX (mono_get_exception_overflow (), ip);
5542 sp [-1].data.i = (guint8) sp [-1].data.f;
5543 ++ip;
5544 MINT_IN_BREAK;
5545 MINT_IN_CASE(MINT_CKFINITE)
5546 if (!mono_isfinite (sp [-1].data.f))
5547 THROW_EX (mono_get_exception_arithmetic (), ip);
5548 ++ip;
5549 MINT_IN_BREAK;
5550 MINT_IN_CASE(MINT_MKREFANY) {
5551 c = (MonoClass*)imethod->data_items [*(guint16 *)(ip + 1)];
5553 /* The value address is on the stack */
5554 gpointer addr = sp [-1].data.p;
5555 /* Push the typedref value on the stack */
5556 sp [-1].data.p = vt_sp;
5557 vt_sp += ALIGN_TO (sizeof (MonoTypedRef), MINT_VT_ALIGNMENT);
5559 MonoTypedRef *tref = (MonoTypedRef*)sp [-1].data.p;
5560 tref->klass = c;
5561 tref->type = m_class_get_byval_arg (c);
5562 tref->value = addr;
5564 ip += 2;
5565 MINT_IN_BREAK;
5567 MINT_IN_CASE(MINT_REFANYTYPE) {
5568 MonoTypedRef *tref = (MonoTypedRef*)sp [-1].data.p;
5569 MonoType *type = tref->type;
5571 vt_sp -= ALIGN_TO (sizeof (MonoTypedRef), MINT_VT_ALIGNMENT);
5572 sp [-1].data.p = vt_sp;
5573 vt_sp += 8;
5574 *(gpointer*)sp [-1].data.p = type;
5575 ip ++;
5576 MINT_IN_BREAK;
5578 MINT_IN_CASE(MINT_REFANYVAL) {
5579 MonoTypedRef *tref = (MonoTypedRef*)sp [-1].data.p;
5580 gpointer addr = tref->value;
5582 c = (MonoClass*)imethod->data_items [*(guint16 *)(ip + 1)];
5583 if (c != tref->klass)
5584 THROW_EX (mono_get_exception_invalid_cast (), ip);
5586 vt_sp -= ALIGN_TO (sizeof (MonoTypedRef), MINT_VT_ALIGNMENT);
5588 sp [-1].data.p = addr;
5589 ip += 2;
5590 MINT_IN_BREAK;
5592 MINT_IN_CASE(MINT_LDTOKEN)
5593 sp->data.p = vt_sp;
5594 vt_sp += 8;
5595 * (gpointer *)sp->data.p = imethod->data_items[*(guint16 *)(ip + 1)];
5596 ip += 2;
5597 ++sp;
5598 MINT_IN_BREAK;
5599 MINT_IN_CASE(MINT_ADD_OVF_I4)
5600 if (CHECK_ADD_OVERFLOW (sp [-2].data.i, sp [-1].data.i))
5601 THROW_EX (mono_get_exception_overflow (), ip);
5602 BINOP(i, +);
5603 MINT_IN_BREAK;
5604 MINT_IN_CASE(MINT_ADD_OVF_I8)
5605 if (CHECK_ADD_OVERFLOW64 (sp [-2].data.l, sp [-1].data.l))
5606 THROW_EX (mono_get_exception_overflow (), ip);
5607 BINOP(l, +);
5608 MINT_IN_BREAK;
5609 MINT_IN_CASE(MINT_ADD_OVF_UN_I4)
5610 if (CHECK_ADD_OVERFLOW_UN (sp [-2].data.i, sp [-1].data.i))
5611 THROW_EX (mono_get_exception_overflow (), ip);
5612 BINOP_CAST(i, +, guint32);
5613 MINT_IN_BREAK;
5614 MINT_IN_CASE(MINT_ADD_OVF_UN_I8)
5615 if (CHECK_ADD_OVERFLOW64_UN (sp [-2].data.l, sp [-1].data.l))
5616 THROW_EX (mono_get_exception_overflow (), ip);
5617 BINOP_CAST(l, +, guint64);
5618 MINT_IN_BREAK;
5619 MINT_IN_CASE(MINT_MUL_OVF_I4)
5620 if (CHECK_MUL_OVERFLOW (sp [-2].data.i, sp [-1].data.i))
5621 THROW_EX (mono_get_exception_overflow (), ip);
5622 BINOP(i, *);
5623 MINT_IN_BREAK;
5624 MINT_IN_CASE(MINT_MUL_OVF_I8)
5625 if (CHECK_MUL_OVERFLOW64 (sp [-2].data.l, sp [-1].data.l))
5626 THROW_EX (mono_get_exception_overflow (), ip);
5627 BINOP(l, *);
5628 MINT_IN_BREAK;
5629 MINT_IN_CASE(MINT_MUL_OVF_UN_I4)
5630 if (CHECK_MUL_OVERFLOW_UN (sp [-2].data.i, sp [-1].data.i))
5631 THROW_EX (mono_get_exception_overflow (), ip);
5632 BINOP_CAST(i, *, guint32);
5633 MINT_IN_BREAK;
5634 MINT_IN_CASE(MINT_MUL_OVF_UN_I8)
5635 if (CHECK_MUL_OVERFLOW64_UN (sp [-2].data.l, sp [-1].data.l))
5636 THROW_EX (mono_get_exception_overflow (), ip);
5637 BINOP_CAST(l, *, guint64);
5638 MINT_IN_BREAK;
5639 MINT_IN_CASE(MINT_SUB_OVF_I4)
5640 if (CHECK_SUB_OVERFLOW (sp [-2].data.i, sp [-1].data.i))
5641 THROW_EX (mono_get_exception_overflow (), ip);
5642 BINOP(i, -);
5643 MINT_IN_BREAK;
5644 MINT_IN_CASE(MINT_SUB_OVF_I8)
5645 if (CHECK_SUB_OVERFLOW64 (sp [-2].data.l, sp [-1].data.l))
5646 THROW_EX (mono_get_exception_overflow (), ip);
5647 BINOP(l, -);
5648 MINT_IN_BREAK;
5649 MINT_IN_CASE(MINT_SUB_OVF_UN_I4)
5650 if (CHECK_SUB_OVERFLOW_UN (sp [-2].data.i, sp [-1].data.i))
5651 THROW_EX (mono_get_exception_overflow (), ip);
5652 BINOP_CAST(i, -, guint32);
5653 MINT_IN_BREAK;
5654 MINT_IN_CASE(MINT_SUB_OVF_UN_I8)
5655 if (CHECK_SUB_OVERFLOW64_UN (sp [-2].data.l, sp [-1].data.l))
5656 THROW_EX (mono_get_exception_overflow (), ip);
5657 BINOP_CAST(l, -, guint64);
5658 MINT_IN_BREAK;
5659 MINT_IN_CASE(MINT_START_ABORT_PROT)
5660 mono_threads_begin_abort_protected_block ();
5661 ip ++;
5662 MINT_IN_BREAK;
5663 MINT_IN_CASE(MINT_ENDFINALLY) {
5664 ip ++;
5665 int clause_index = *ip;
5666 gboolean pending_abort = mono_threads_end_abort_protected_block ();
5668 if (clause_args && clause_index == clause_args->exit_clause)
5669 goto exit_frame;
5670 while (sp > frame->stack) {
5671 --sp;
5673 if (finally_ips) {
5674 ip = (const guint16*)finally_ips->data;
5675 finally_ips = g_slist_remove (finally_ips, ip);
5676 /* Throw abort after the last finally block to avoid confusing EH */
5677 if (pending_abort && !finally_ips)
5678 EXCEPTION_CHECKPOINT;
5679 goto main_loop;
5681 ves_abort();
5682 MINT_IN_BREAK;
5685 MINT_IN_CASE(MINT_LEAVE) /* Fall through */
5686 MINT_IN_CASE(MINT_LEAVE_S)
5687 while (sp > frame->stack) {
5688 --sp;
5690 frame->ip = ip;
5692 if (*ip == MINT_LEAVE_S) {
5693 ip += (short) *(ip + 1);
5694 } else {
5695 ip += (gint32) READ32 (ip + 1);
5697 endfinally_ip = ip;
5698 goto handle_finally;
5699 MINT_IN_BREAK;
5700 MINT_IN_CASE(MINT_LEAVE_CHECK)
5701 MINT_IN_CASE(MINT_LEAVE_S_CHECK)
5702 while (sp > frame->stack) {
5703 --sp;
5705 frame->ip = ip;
5707 if (imethod->method->wrapper_type != MONO_WRAPPER_RUNTIME_INVOKE) {
5708 stackval tmp_sp;
5710 child_frame.parent = frame;
5711 child_frame.imethod = NULL;
5713 * We need for mono_thread_get_undeniable_exception to be able to unwind
5714 * to check the abort threshold. For this to work we use child_frame as a
5715 * dummy frame that is stored in the lmf and serves as the transition frame
5717 do_icall_wrapper (&child_frame, NULL, MINT_ICALL_V_P, &tmp_sp, (gpointer)mono_thread_get_undeniable_exception);
5719 MonoException *abort_exc = (MonoException*)tmp_sp.data.p;
5720 if (abort_exc)
5721 THROW_EX (abort_exc, frame->ip);
5724 if (*ip == MINT_LEAVE_S_CHECK) {
5725 ip += (short) *(ip + 1);
5726 } else {
5727 ip += (gint32) READ32 (ip + 1);
5729 endfinally_ip = ip;
5730 goto handle_finally;
5731 MINT_IN_BREAK;
5732 MINT_IN_CASE(MINT_ICALL_V_V)
5733 MINT_IN_CASE(MINT_ICALL_V_P)
5734 MINT_IN_CASE(MINT_ICALL_P_V)
5735 MINT_IN_CASE(MINT_ICALL_P_P)
5736 MINT_IN_CASE(MINT_ICALL_PP_V)
5737 MINT_IN_CASE(MINT_ICALL_PP_P)
5738 MINT_IN_CASE(MINT_ICALL_PPP_V)
5739 MINT_IN_CASE(MINT_ICALL_PPP_P)
5740 MINT_IN_CASE(MINT_ICALL_PPPP_V)
5741 MINT_IN_CASE(MINT_ICALL_PPPP_P)
5742 MINT_IN_CASE(MINT_ICALL_PPPPP_V)
5743 MINT_IN_CASE(MINT_ICALL_PPPPP_P)
5744 MINT_IN_CASE(MINT_ICALL_PPPPPP_V)
5745 MINT_IN_CASE(MINT_ICALL_PPPPPP_P)
5746 frame->ip = ip;
5747 sp = do_icall_wrapper (frame, NULL, *ip, sp, imethod->data_items [*(guint16 *)(ip + 1)]);
5748 EXCEPTION_CHECKPOINT;
5749 CHECK_RESUME_STATE (context);
5750 ip += 2;
5751 MINT_IN_BREAK;
5752 MINT_IN_CASE(MINT_MONO_LDPTR)
5753 sp->data.p = imethod->data_items [*(guint16 *)(ip + 1)];
5754 ip += 2;
5755 ++sp;
5756 MINT_IN_BREAK;
5757 MINT_IN_CASE(MINT_MONO_NEWOBJ)
5758 sp->data.p = mono_object_new_checked (imethod->domain, (MonoClass*)imethod->data_items [*(guint16 *)(ip + 1)], error);
5759 mono_error_cleanup (error); /* FIXME: don't swallow the error */
5760 ip += 2;
5761 sp++;
5762 MINT_IN_BREAK;
5763 MINT_IN_CASE(MINT_MONO_FREE)
5764 ++ip;
5765 --sp;
5766 g_error ("that doesn't seem right");
5767 g_free (sp->data.p);
5768 MINT_IN_BREAK;
5769 MINT_IN_CASE(MINT_MONO_RETOBJ)
5770 ++ip;
5771 sp--;
5772 stackval_from_data (mono_method_signature_internal (imethod->method)->ret, frame->retval, sp->data.p,
5773 mono_method_signature_internal (imethod->method)->pinvoke);
5774 if (sp > frame->stack)
5775 g_warning ("retobj: more values on stack: %d", sp-frame->stack);
5776 goto exit_frame;
5777 MINT_IN_CASE(MINT_MONO_TLS) {
5778 MonoTlsKey key = (MonoTlsKey)*(gint32 *)(ip + 1);
5779 sp->data.p = mono_tls_get_tls_getter (key) (); // get function pointer and call it
5780 sp++;
5781 ip += 3;
5782 MINT_IN_BREAK;
5784 MINT_IN_CASE(MINT_MONO_MEMORY_BARRIER) {
5785 ++ip;
5786 mono_memory_barrier ();
5787 MINT_IN_BREAK;
5789 MINT_IN_CASE(MINT_MONO_LDDOMAIN)
5790 sp->data.p = mono_domain_get ();
5791 ++sp;
5792 ++ip;
5793 MINT_IN_BREAK;
5794 MINT_IN_CASE(MINT_SDB_INTR_LOC)
5795 if (G_UNLIKELY (ss_enabled)) {
5796 typedef void (*T) (void);
5797 static T ss_tramp;
5799 if (!ss_tramp) {
5800 void *tramp = mini_get_single_step_trampoline ();
5801 mono_memory_barrier ();
5802 ss_tramp = (T)tramp;
5806 * Make this point to the MINT_SDB_SEQ_POINT instruction which follows this since
5807 * the address of that instruction is stored as the seq point address.
5809 frame->ip = ip + 1;
5812 * Use the same trampoline as the JIT. This ensures that
5813 * the debugger has the context for the last interpreter
5814 * native frame.
5816 do_debugger_tramp (ss_tramp, frame);
5818 CHECK_RESUME_STATE (context);
5820 ++ip;
5821 MINT_IN_BREAK;
5822 MINT_IN_CASE(MINT_SDB_SEQ_POINT)
5823 /* Just a placeholder for a breakpoint */
5824 ++ip;
5825 MINT_IN_BREAK;
5826 MINT_IN_CASE(MINT_SDB_BREAKPOINT) {
5827 typedef void (*T) (void);
5828 static T bp_tramp;
5829 if (!bp_tramp) {
5830 void *tramp = mini_get_breakpoint_trampoline ();
5831 mono_memory_barrier ();
5832 bp_tramp = (T)tramp;
5835 frame->ip = ip;
5837 /* Use the same trampoline as the JIT */
5838 do_debugger_tramp (bp_tramp, frame);
5840 CHECK_RESUME_STATE (context);
5842 ++ip;
5843 MINT_IN_BREAK;
5846 #define RELOP(datamem, op) \
5847 --sp; \
5848 sp [-1].data.i = sp [-1].data.datamem op sp [0].data.datamem; \
5849 ++ip;
5851 #define RELOP_FP(datamem, op, noorder) \
5852 --sp; \
5853 if (mono_isunordered (sp [-1].data.datamem, sp [0].data.datamem)) \
5854 sp [-1].data.i = noorder; \
5855 else \
5856 sp [-1].data.i = sp [-1].data.datamem op sp [0].data.datamem; \
5857 ++ip;
5859 MINT_IN_CASE(MINT_CEQ_I4)
5860 RELOP(i, ==);
5861 MINT_IN_BREAK;
5862 MINT_IN_CASE(MINT_CEQ0_I4)
5863 sp [-1].data.i = (sp [-1].data.i == 0);
5864 ++ip;
5865 MINT_IN_BREAK;
5866 MINT_IN_CASE(MINT_CEQ_I8)
5867 RELOP(l, ==);
5868 MINT_IN_BREAK;
5869 MINT_IN_CASE(MINT_CEQ_R4)
5870 RELOP_FP(f_r4, ==, 0);
5871 MINT_IN_BREAK;
5872 MINT_IN_CASE(MINT_CEQ_R8)
5873 RELOP_FP(f, ==, 0);
5874 MINT_IN_BREAK;
5875 MINT_IN_CASE(MINT_CNE_I4)
5876 RELOP(i, !=);
5877 MINT_IN_BREAK;
5878 MINT_IN_CASE(MINT_CNE_I8)
5879 RELOP(l, !=);
5880 MINT_IN_BREAK;
5881 MINT_IN_CASE(MINT_CNE_R4)
5882 RELOP_FP(f_r4, !=, 1);
5883 MINT_IN_BREAK;
5884 MINT_IN_CASE(MINT_CNE_R8)
5885 RELOP_FP(f, !=, 1);
5886 MINT_IN_BREAK;
5887 MINT_IN_CASE(MINT_CGT_I4)
5888 RELOP(i, >);
5889 MINT_IN_BREAK;
5890 MINT_IN_CASE(MINT_CGT_I8)
5891 RELOP(l, >);
5892 MINT_IN_BREAK;
5893 MINT_IN_CASE(MINT_CGT_R4)
5894 RELOP_FP(f_r4, >, 0);
5895 MINT_IN_BREAK;
5896 MINT_IN_CASE(MINT_CGT_R8)
5897 RELOP_FP(f, >, 0);
5898 MINT_IN_BREAK;
5899 MINT_IN_CASE(MINT_CGE_I4)
5900 RELOP(i, >=);
5901 MINT_IN_BREAK;
5902 MINT_IN_CASE(MINT_CGE_I8)
5903 RELOP(l, >=);
5904 MINT_IN_BREAK;
5905 MINT_IN_CASE(MINT_CGE_R4)
5906 RELOP_FP(f_r4, >=, 0);
5907 MINT_IN_BREAK;
5908 MINT_IN_CASE(MINT_CGE_R8)
5909 RELOP_FP(f, >=, 0);
5910 MINT_IN_BREAK;
5912 #define RELOP_CAST(datamem, op, type) \
5913 --sp; \
5914 sp [-1].data.i = (type)sp [-1].data.datamem op (type)sp [0].data.datamem; \
5915 ++ip;
5917 MINT_IN_CASE(MINT_CGE_UN_I4)
5918 RELOP_CAST(l, >=, guint32);
5919 MINT_IN_BREAK;
5920 MINT_IN_CASE(MINT_CGE_UN_I8)
5921 RELOP_CAST(l, >=, guint64);
5922 MINT_IN_BREAK;
5924 MINT_IN_CASE(MINT_CGT_UN_I4)
5925 RELOP_CAST(i, >, guint32);
5926 MINT_IN_BREAK;
5927 MINT_IN_CASE(MINT_CGT_UN_I8)
5928 RELOP_CAST(l, >, guint64);
5929 MINT_IN_BREAK;
5930 MINT_IN_CASE(MINT_CGT_UN_R4)
5931 RELOP_FP(f_r4, >, 1);
5932 MINT_IN_BREAK;
5933 MINT_IN_CASE(MINT_CGT_UN_R8)
5934 RELOP_FP(f, >, 1);
5935 MINT_IN_BREAK;
5936 MINT_IN_CASE(MINT_CLT_I4)
5937 RELOP(i, <);
5938 MINT_IN_BREAK;
5939 MINT_IN_CASE(MINT_CLT_I8)
5940 RELOP(l, <);
5941 MINT_IN_BREAK;
5942 MINT_IN_CASE(MINT_CLT_R4)
5943 RELOP_FP(f_r4, <, 0);
5944 MINT_IN_BREAK;
5945 MINT_IN_CASE(MINT_CLT_R8)
5946 RELOP_FP(f, <, 0);
5947 MINT_IN_BREAK;
5948 MINT_IN_CASE(MINT_CLT_UN_I4)
5949 RELOP_CAST(i, <, guint32);
5950 MINT_IN_BREAK;
5951 MINT_IN_CASE(MINT_CLT_UN_I8)
5952 RELOP_CAST(l, <, guint64);
5953 MINT_IN_BREAK;
5954 MINT_IN_CASE(MINT_CLT_UN_R4)
5955 RELOP_FP(f_r4, <, 1);
5956 MINT_IN_BREAK;
5957 MINT_IN_CASE(MINT_CLT_UN_R8)
5958 RELOP_FP(f, <, 1);
5959 MINT_IN_BREAK;
5960 MINT_IN_CASE(MINT_CLE_I4)
5961 RELOP(i, <=);
5962 MINT_IN_BREAK;
5963 MINT_IN_CASE(MINT_CLE_I8)
5964 RELOP(l, <=);
5965 MINT_IN_BREAK;
5966 MINT_IN_CASE(MINT_CLE_UN_I4)
5967 RELOP_CAST(l, <=, guint32);
5968 MINT_IN_BREAK;
5969 MINT_IN_CASE(MINT_CLE_UN_I8)
5970 RELOP_CAST(l, <=, guint64);
5971 MINT_IN_BREAK;
5972 MINT_IN_CASE(MINT_CLE_R4)
5973 RELOP_FP(f_r4, <=, 0);
5974 MINT_IN_BREAK;
5975 MINT_IN_CASE(MINT_CLE_R8)
5976 RELOP_FP(f, <=, 0);
5977 MINT_IN_BREAK;
5979 #undef RELOP
5980 #undef RELOP_FP
5981 #undef RELOP_CAST
5983 MINT_IN_CASE(MINT_LDFTN) {
5984 sp->data.p = imethod->data_items [* (guint16 *)(ip + 1)];
5985 ++sp;
5986 ip += 2;
5987 MINT_IN_BREAK;
5989 MINT_IN_CASE(MINT_LDVIRTFTN) {
5990 InterpMethod *m = (InterpMethod*)imethod->data_items [* (guint16 *)(ip + 1)];
5991 ip += 2;
5992 --sp;
5993 if (!sp->data.p)
5994 THROW_EX (mono_get_exception_null_reference (), ip - 2);
5996 sp->data.p = get_virtual_method (m, sp->data.o);
5997 ++sp;
5998 MINT_IN_BREAK;
6000 MINT_IN_CASE(MINT_LDFTN_DYNAMIC) {
6001 MONO_API_ERROR_INIT (error);
6002 InterpMethod *m = mono_interp_get_imethod (mono_domain_get (), (MonoMethod*) sp [-1].data.p, error);
6003 mono_error_assert_ok (error);
6004 sp [-1].data.p = m;
6005 ip++;
6006 MINT_IN_BREAK;
6009 #define LDARG(datamem, argtype) \
6010 sp->data.datamem = (argtype) frame->stack_args [*(guint16 *)(ip + 1)].data.datamem; \
6011 ip += 2; \
6012 ++sp;
6014 MINT_IN_CASE(MINT_LDARG_I1) LDARG(i, gint8); MINT_IN_BREAK;
6015 MINT_IN_CASE(MINT_LDARG_U1) LDARG(i, guint8); MINT_IN_BREAK;
6016 MINT_IN_CASE(MINT_LDARG_I2) LDARG(i, gint16); MINT_IN_BREAK;
6017 MINT_IN_CASE(MINT_LDARG_U2) LDARG(i, guint16); MINT_IN_BREAK;
6018 MINT_IN_CASE(MINT_LDARG_I4) LDARG(i, gint32); MINT_IN_BREAK;
6019 MINT_IN_CASE(MINT_LDARG_I8) LDARG(l, gint64); MINT_IN_BREAK;
6020 MINT_IN_CASE(MINT_LDARG_R4) LDARG(f_r4, float); MINT_IN_BREAK;
6021 MINT_IN_CASE(MINT_LDARG_R8) LDARG(f, double); MINT_IN_BREAK;
6022 MINT_IN_CASE(MINT_LDARG_O) LDARG(p, gpointer); MINT_IN_BREAK;
6023 MINT_IN_CASE(MINT_LDARG_P) LDARG(p, gpointer); MINT_IN_BREAK;
6025 MINT_IN_CASE(MINT_LDARG_VT)
6026 sp->data.p = vt_sp;
6027 i32 = READ32(ip + 2);
6028 memcpy(sp->data.p, frame->stack_args [* (guint16 *)(ip + 1)].data.p, i32);
6029 vt_sp += ALIGN_TO (i32, MINT_VT_ALIGNMENT);
6030 ip += 4;
6031 ++sp;
6032 MINT_IN_BREAK;
6034 #define STARG(datamem, argtype) \
6035 --sp; \
6036 frame->stack_args [*(guint16 *)(ip + 1)].data.datamem = (argtype) sp->data.datamem; \
6037 ip += 2; \
6039 MINT_IN_CASE(MINT_STARG_I1) STARG(i, gint8); MINT_IN_BREAK;
6040 MINT_IN_CASE(MINT_STARG_U1) STARG(i, guint8); MINT_IN_BREAK;
6041 MINT_IN_CASE(MINT_STARG_I2) STARG(i, gint16); MINT_IN_BREAK;
6042 MINT_IN_CASE(MINT_STARG_U2) STARG(i, guint16); MINT_IN_BREAK;
6043 MINT_IN_CASE(MINT_STARG_I4) STARG(i, gint32); MINT_IN_BREAK;
6044 MINT_IN_CASE(MINT_STARG_I8) STARG(l, gint64); MINT_IN_BREAK;
6045 MINT_IN_CASE(MINT_STARG_R4) STARG(f_r4, float); MINT_IN_BREAK;
6046 MINT_IN_CASE(MINT_STARG_R8) STARG(f, double); MINT_IN_BREAK;
6047 MINT_IN_CASE(MINT_STARG_O) STARG(p, gpointer); MINT_IN_BREAK;
6048 MINT_IN_CASE(MINT_STARG_P) STARG(p, gpointer); MINT_IN_BREAK;
6050 MINT_IN_CASE(MINT_STARG_VT)
6051 i32 = READ32(ip + 2);
6052 --sp;
6053 memcpy(frame->stack_args [* (guint16 *)(ip + 1)].data.p, sp->data.p, i32);
6054 vt_sp -= ALIGN_TO (i32, MINT_VT_ALIGNMENT);
6055 ip += 4;
6056 MINT_IN_BREAK;
6058 MINT_IN_CASE(MINT_PROF_ENTER) {
6059 ip += 1;
6061 if (MONO_PROFILER_ENABLED (method_enter)) {
6062 MonoProfilerCallContext *prof_ctx = NULL;
6064 if (imethod->prof_flags & MONO_PROFILER_CALL_INSTRUMENTATION_ENTER_CONTEXT) {
6065 prof_ctx = g_new0 (MonoProfilerCallContext, 1);
6066 prof_ctx->interp_frame = frame;
6067 prof_ctx->method = imethod->method;
6070 MONO_PROFILER_RAISE (method_enter, (imethod->method, prof_ctx));
6072 g_free (prof_ctx);
6075 MINT_IN_BREAK;
6078 MINT_IN_CASE(MINT_TRACE_ENTER) {
6079 ip += 1;
6081 MonoProfilerCallContext *prof_ctx = g_alloca (sizeof (MonoProfilerCallContext));
6082 prof_ctx->interp_frame = frame;
6083 prof_ctx->method = imethod->method;
6085 mono_trace_enter_method (imethod->method, prof_ctx);
6086 MINT_IN_BREAK;
6089 MINT_IN_CASE(MINT_TRACE_EXIT) {
6090 ip += 1;
6092 MonoProfilerCallContext *prof_ctx = g_alloca (sizeof (MonoProfilerCallContext));
6093 prof_ctx->interp_frame = frame;
6094 prof_ctx->method = imethod->method;
6096 mono_trace_leave_method (imethod->method, prof_ctx);
6097 MINT_IN_BREAK;
6100 MINT_IN_CASE(MINT_LDARGA)
6101 sp->data.p = &frame->stack_args [* (guint16 *)(ip + 1)];
6102 ip += 2;
6103 ++sp;
6104 MINT_IN_BREAK;
6106 MINT_IN_CASE(MINT_LDARGA_VT)
6107 sp->data.p = frame->stack_args [* (guint16 *)(ip + 1)].data.p;
6108 ip += 2;
6109 ++sp;
6110 MINT_IN_BREAK;
6112 #define LDLOC(datamem, argtype) \
6113 sp->data.datamem = * (argtype *)(locals + * (guint16 *)(ip + 1)); \
6114 ip += 2; \
6115 ++sp;
6117 MINT_IN_CASE(MINT_LDLOC_I1) LDLOC(i, gint8); MINT_IN_BREAK;
6118 MINT_IN_CASE(MINT_LDLOC_U1) LDLOC(i, guint8); MINT_IN_BREAK;
6119 MINT_IN_CASE(MINT_LDLOC_I2) LDLOC(i, gint16); MINT_IN_BREAK;
6120 MINT_IN_CASE(MINT_LDLOC_U2) LDLOC(i, guint16); MINT_IN_BREAK;
6121 MINT_IN_CASE(MINT_LDLOC_I4) LDLOC(i, gint32); MINT_IN_BREAK;
6122 MINT_IN_CASE(MINT_LDLOC_I8) LDLOC(l, gint64); MINT_IN_BREAK;
6123 MINT_IN_CASE(MINT_LDLOC_R4) LDLOC(f_r4, float); MINT_IN_BREAK;
6124 MINT_IN_CASE(MINT_LDLOC_R8) LDLOC(f, double); MINT_IN_BREAK;
6125 MINT_IN_CASE(MINT_LDLOC_O) LDLOC(p, gpointer); MINT_IN_BREAK;
6126 MINT_IN_CASE(MINT_LDLOC_P) LDLOC(p, gpointer); MINT_IN_BREAK;
6128 MINT_IN_CASE(MINT_LDLOC_VT)
6129 sp->data.p = vt_sp;
6130 i32 = READ32(ip + 2);
6131 memcpy(sp->data.p, locals + * (guint16 *)(ip + 1), i32);
6132 vt_sp += ALIGN_TO (i32, MINT_VT_ALIGNMENT);
6133 ip += 4;
6134 ++sp;
6135 MINT_IN_BREAK;
6137 MINT_IN_CASE(MINT_LDLOCA_S)
6138 sp->data.p = locals + * (guint16 *)(ip + 1);
6139 ip += 2;
6140 ++sp;
6141 MINT_IN_BREAK;
6143 #define STLOC(datamem, argtype) \
6144 --sp; \
6145 * (argtype *)(locals + * (guint16 *)(ip + 1)) = sp->data.datamem; \
6146 ip += 2;
6148 MINT_IN_CASE(MINT_STLOC_I1) STLOC(i, gint8); MINT_IN_BREAK;
6149 MINT_IN_CASE(MINT_STLOC_U1) STLOC(i, guint8); MINT_IN_BREAK;
6150 MINT_IN_CASE(MINT_STLOC_I2) STLOC(i, gint16); MINT_IN_BREAK;
6151 MINT_IN_CASE(MINT_STLOC_U2) STLOC(i, guint16); MINT_IN_BREAK;
6152 MINT_IN_CASE(MINT_STLOC_I4) STLOC(i, gint32); MINT_IN_BREAK;
6153 MINT_IN_CASE(MINT_STLOC_I8) STLOC(l, gint64); MINT_IN_BREAK;
6154 MINT_IN_CASE(MINT_STLOC_R4) STLOC(f_r4, float); MINT_IN_BREAK;
6155 MINT_IN_CASE(MINT_STLOC_R8) STLOC(f, double); MINT_IN_BREAK;
6156 MINT_IN_CASE(MINT_STLOC_O) STLOC(p, gpointer); MINT_IN_BREAK;
6157 MINT_IN_CASE(MINT_STLOC_P) STLOC(p, gpointer); MINT_IN_BREAK;
6159 #define STLOC_NP(datamem, argtype) \
6160 * (argtype *)(locals + * (guint16 *)(ip + 1)) = sp [-1].data.datamem; \
6161 ip += 2;
6163 MINT_IN_CASE(MINT_STLOC_NP_I4) STLOC_NP(i, gint32); MINT_IN_BREAK;
6164 MINT_IN_CASE(MINT_STLOC_NP_O) STLOC_NP(p, gpointer); MINT_IN_BREAK;
6166 MINT_IN_CASE(MINT_STLOC_VT)
6167 i32 = READ32(ip + 2);
6168 --sp;
6169 memcpy(locals + * (guint16 *)(ip + 1), sp->data.p, i32);
6170 vt_sp -= ALIGN_TO (i32, MINT_VT_ALIGNMENT);
6171 ip += 4;
6172 MINT_IN_BREAK;
6174 MINT_IN_CASE(MINT_LOCALLOC) {
6175 if (sp != frame->stack + 1) /*FIX?*/
6176 THROW_EX (mono_get_exception_execution_engine (NULL), ip);
6178 int len = sp [-1].data.i;
6179 sp [-1].data.p = alloca (len);
6181 if (imethod->init_locals)
6182 memset (sp [-1].data.p, 0, len);
6183 ++ip;
6184 MINT_IN_BREAK;
6186 MINT_IN_CASE(MINT_ENDFILTER)
6187 /* top of stack is result of filter */
6188 frame->retval = &sp [-1];
6189 goto exit_frame;
6190 MINT_IN_CASE(MINT_INITOBJ)
6191 --sp;
6192 memset (sp->data.vt, 0, READ32(ip + 1));
6193 ip += 3;
6194 MINT_IN_BREAK;
6195 MINT_IN_CASE(MINT_CPBLK)
6196 sp -= 3;
6197 if (!sp [0].data.p || !sp [1].data.p)
6198 THROW_EX (mono_get_exception_null_reference(), ip - 1);
6199 ++ip;
6200 /* FIXME: value and size may be int64... */
6201 memcpy (sp [0].data.p, sp [1].data.p, sp [2].data.i);
6202 MINT_IN_BREAK;
6203 #if 0
6204 MINT_IN_CASE(MINT_CONSTRAINED_) {
6205 guint32 token;
6206 /* FIXME: implement */
6207 ++ip;
6208 token = READ32 (ip);
6209 ip += 2;
6210 MINT_IN_BREAK;
6212 #endif
6213 MINT_IN_CASE(MINT_INITBLK)
6214 sp -= 3;
6215 if (!sp [0].data.p)
6216 THROW_EX (mono_get_exception_null_reference(), ip - 1);
6217 ++ip;
6218 /* FIXME: value and size may be int64... */
6219 memset (sp [0].data.p, sp [1].data.i, sp [2].data.i);
6220 MINT_IN_BREAK;
6221 #if 0
6222 MINT_IN_CASE(MINT_NO_)
6223 /* FIXME: implement */
6224 ip += 2;
6225 MINT_IN_BREAK;
6226 #endif
6227 MINT_IN_CASE(MINT_RETHROW) {
6228 int exvar_offset = *(guint16*)(ip + 1);
6229 THROW_EX_GENERAL (*(MonoException**)(frame->locals + exvar_offset), ip, TRUE);
6230 MINT_IN_BREAK;
6232 MINT_IN_CASE(MINT_MONO_RETHROW) {
6234 * need to clarify what this should actually do:
6236 * Takes an exception from the stack and rethrows it.
6237 * This is useful for wrappers that don't want to have to
6238 * use CEE_THROW and lose the exception stacktrace.
6241 --sp;
6242 if (!sp->data.p)
6243 sp->data.p = mono_get_exception_null_reference ();
6245 THROW_EX_GENERAL ((MonoException *)sp->data.p, ip, TRUE);
6246 MINT_IN_BREAK;
6248 MINT_IN_CASE(MINT_LD_DELEGATE_METHOD_PTR) {
6249 MonoDelegate *del;
6251 --sp;
6252 del = (MonoDelegate*)sp->data.p;
6253 if (!del->interp_method) {
6254 /* Not created from interpreted code */
6255 MONO_API_ERROR_INIT (error);
6256 g_assert (del->method);
6257 del->interp_method = mono_interp_get_imethod (del->object.vtable->domain, del->method, error);
6258 mono_error_assert_ok (error);
6260 g_assert (del->interp_method);
6261 sp->data.p = del->interp_method;
6262 ++sp;
6263 ip += 1;
6264 MINT_IN_BREAK;
6266 MINT_IN_CASE(MINT_LD_DELEGATE_INVOKE_IMPL) {
6267 MonoDelegate *del;
6268 int n = *(guint16*)(ip + 1);
6269 del = (MonoDelegate*)sp [-n].data.p;
6270 if (!del->interp_invoke_impl) {
6272 * First time we are called. Set up the invoke wrapper. We might be able to do this
6273 * in ctor but we would need to handle AllocDelegateLike_internal separately
6275 MONO_API_ERROR_INIT (error);
6276 MonoMethod *invoke = mono_get_delegate_invoke_internal (del->object.vtable->klass);
6277 del->interp_invoke_impl = mono_interp_get_imethod (del->object.vtable->domain, mono_marshal_get_delegate_invoke (invoke, del), error);
6278 mono_error_assert_ok (error);
6280 sp ++;
6281 sp [-1].data.p = del->interp_invoke_impl;
6282 ip += 2;
6283 MINT_IN_BREAK;
6286 #define MATH_UNOP(mathfunc) \
6287 sp [-1].data.f = mathfunc (sp [-1].data.f); \
6288 ++ip;
6290 MINT_IN_CASE(MINT_ABS) MATH_UNOP(fabs); MINT_IN_BREAK;
6291 MINT_IN_CASE(MINT_ASIN) MATH_UNOP(asin); MINT_IN_BREAK;
6292 MINT_IN_CASE(MINT_ASINH) MATH_UNOP(asinh); MINT_IN_BREAK;
6293 MINT_IN_CASE(MINT_ACOS) MATH_UNOP(acos); MINT_IN_BREAK;
6294 MINT_IN_CASE(MINT_ACOSH) MATH_UNOP(acosh); MINT_IN_BREAK;
6295 MINT_IN_CASE(MINT_ATAN) MATH_UNOP(atan); MINT_IN_BREAK;
6296 MINT_IN_CASE(MINT_ATANH) MATH_UNOP(atanh); MINT_IN_BREAK;
6297 MINT_IN_CASE(MINT_COS) MATH_UNOP(cos); MINT_IN_BREAK;
6298 MINT_IN_CASE(MINT_CBRT) MATH_UNOP(cbrt); MINT_IN_BREAK;
6299 MINT_IN_CASE(MINT_COSH) MATH_UNOP(cosh); MINT_IN_BREAK;
6300 MINT_IN_CASE(MINT_SIN) MATH_UNOP(sin); MINT_IN_BREAK;
6301 MINT_IN_CASE(MINT_SQRT) MATH_UNOP(sqrt); MINT_IN_BREAK;
6302 MINT_IN_CASE(MINT_SINH) MATH_UNOP(sinh); MINT_IN_BREAK;
6303 MINT_IN_CASE(MINT_TAN) MATH_UNOP(tan); MINT_IN_BREAK;
6304 MINT_IN_CASE(MINT_TANH) MATH_UNOP(tanh); MINT_IN_BREAK;
6306 MINT_IN_CASE(MINT_INTRINS_ENUM_HASFLAG) {
6307 MonoClass *klass = (MonoClass*)imethod->data_items[* (guint16 *)(ip + 1)];
6308 guint64 a_val = 0, b_val = 0;
6310 stackval_to_data (m_class_get_byval_arg (klass), &sp [-2], &a_val, FALSE);
6311 stackval_to_data (m_class_get_byval_arg (klass), &sp [-1], &b_val, FALSE);
6312 sp--;
6313 sp [-1].data.i = (a_val & b_val) == b_val;
6314 ip += 2;
6315 MINT_IN_BREAK;
6317 MINT_IN_CASE(MINT_INTRINS_GET_HASHCODE) {
6318 sp [-1].data.i = mono_object_hash_internal (sp [-1].data.o);
6319 ip++;
6320 MINT_IN_BREAK;
6322 MINT_IN_CASE(MINT_INTRINS_GET_TYPE) {
6323 if (!sp[-1].data.o)
6324 THROW_EX (mono_get_exception_null_reference (), ip);
6325 sp [-1].data.o = (MonoObject*) sp [-1].data.o->vtable->type;
6326 ip++;
6327 MINT_IN_BREAK;
6330 MINT_IN_DEFAULT
6331 g_print ("Unimplemented opcode: %04x %s at 0x%x\n", *ip, mono_interp_opname[*ip], ip-imethod->code);
6332 THROW_EX (mono_get_exception_execution_engine ("Unimplemented opcode"), ip);
6336 g_assert_not_reached ();
6337 handle_finally:
6339 int i;
6340 guint32 ip_offset;
6341 MonoExceptionClause *clause;
6342 GSList *old_list = finally_ips;
6343 MonoMethod *method = imethod->method;
6345 #if DEBUG_INTERP
6346 if (tracing)
6347 g_print ("* Handle finally IL_%04x\n", endfinally_ip == NULL ? 0 : endfinally_ip - imethod->code);
6348 #endif
6349 if (imethod == NULL || (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
6350 || (method->iflags & (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL | METHOD_IMPL_ATTRIBUTE_RUNTIME))) {
6351 goto exit_frame;
6353 ip_offset = frame->ip - imethod->code;
6355 if (endfinally_ip != NULL)
6356 finally_ips = g_slist_prepend(finally_ips, (void *)endfinally_ip);
6358 for (i = imethod->num_clauses - 1; i >= 0; i--) {
6359 clause = &imethod->clauses [i];
6360 if (MONO_OFFSET_IN_CLAUSE (clause, ip_offset) && (endfinally_ip == NULL || !(MONO_OFFSET_IN_CLAUSE (clause, endfinally_ip - imethod->code)))) {
6361 if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY) {
6362 ip = imethod->code + clause->handler_offset;
6363 finally_ips = g_slist_prepend (finally_ips, (gpointer) ip);
6364 #if DEBUG_INTERP
6365 if (tracing)
6366 g_print ("* Found finally at IL_%04x with exception: %s\n", clause->handler_offset, frame->ex? "yes": "no");
6367 #endif
6372 endfinally_ip = NULL;
6374 if (old_list != finally_ips && finally_ips) {
6375 ip = (const guint16*)finally_ips->data;
6376 finally_ips = g_slist_remove (finally_ips, ip);
6377 sp = frame->stack; /* spec says stack should be empty at endfinally so it should be at the start too */
6378 vt_sp = (unsigned char *) sp + imethod->stack_size;
6379 goto main_loop;
6382 ves_abort();
6385 exit_frame:
6387 if (clause_args && clause_args->base_frame)
6388 memcpy (clause_args->base_frame->args, frame->args, imethod->alloca_size);
6390 if (!frame->ex && MONO_PROFILER_ENABLED (method_leave) &&
6391 imethod->prof_flags & MONO_PROFILER_CALL_INSTRUMENTATION_LEAVE) {
6392 MonoProfilerCallContext *prof_ctx = NULL;
6394 if (imethod->prof_flags & MONO_PROFILER_CALL_INSTRUMENTATION_LEAVE_CONTEXT) {
6395 prof_ctx = g_new0 (MonoProfilerCallContext, 1);
6396 prof_ctx->interp_frame = frame;
6397 prof_ctx->method = imethod->method;
6399 MonoType *rtype = mono_method_signature_internal (imethod->method)->ret;
6401 switch (rtype->type) {
6402 case MONO_TYPE_VOID:
6403 break;
6404 case MONO_TYPE_VALUETYPE:
6405 prof_ctx->return_value = frame->retval->data.p;
6406 break;
6407 default:
6408 prof_ctx->return_value = frame->retval;
6409 break;
6413 MONO_PROFILER_RAISE (method_leave, (imethod->method, prof_ctx));
6415 g_free (prof_ctx);
6416 } else if (frame->ex && imethod->prof_flags & MONO_PROFILER_CALL_INSTRUMENTATION_EXCEPTION_LEAVE)
6417 MONO_PROFILER_RAISE (method_exception_leave, (imethod->method, &frame->ex->object));
6419 DEBUG_LEAVE ();
6422 static void
6423 interp_parse_options (const char *options)
6425 char **args, **ptr;
6427 if (!options)
6428 return;
6430 args = g_strsplit (options, ",", -1);
6431 for (ptr = args; ptr && *ptr; ptr ++) {
6432 char *arg = *ptr;
6434 if (strncmp (arg, "jit=", 4) == 0)
6435 mono_interp_jit_classes = g_slist_prepend (mono_interp_jit_classes, arg + 4);
6436 if (strncmp (arg, "interp-only=", 4) == 0)
6437 mono_interp_only_classes = g_slist_prepend (mono_interp_only_classes, arg + strlen ("interp-only="));
6438 if (strncmp (arg, "-inline", 7) == 0)
6439 mono_interp_opt &= ~INTERP_OPT_INLINE;
6443 typedef int (*TestMethod) (void);
6446 * interp_set_resume_state:
6448 * Set the state the interpeter will continue to execute from after execution returns to the interpreter.
6450 static void
6451 interp_set_resume_state (MonoJitTlsData *jit_tls, MonoException *ex, MonoJitExceptionInfo *ei, MonoInterpFrameHandle interp_frame, gpointer handler_ip)
6453 ThreadContext *context;
6455 g_assert (jit_tls);
6456 context = (ThreadContext*)jit_tls->interp_context;
6457 g_assert (context);
6459 context->has_resume_state = TRUE;
6460 context->handler_frame = (InterpFrame*)interp_frame;
6461 context->handler_ei = ei;
6462 /* This is on the stack, so it doesn't need a wbarrier */
6463 context->handler_frame->ex = ex;
6464 /* Ditto */
6465 if (ei)
6466 *(MonoException**)(context->handler_frame->locals + ei->exvar_offset) = ex;
6467 context->handler_ip = (guint16*) handler_ip;
6471 * interp_run_finally:
6473 * Run the finally clause identified by CLAUSE_INDEX in the intepreter frame given by
6474 * frame->interp_frame.
6475 * Return TRUE if the finally clause threw an exception.
6477 static gboolean
6478 interp_run_finally (StackFrameInfo *frame, int clause_index, gpointer handler_ip, gpointer handler_ip_end)
6480 InterpFrame *iframe = (InterpFrame*)frame->interp_frame;
6481 ThreadContext *context = get_context ();
6482 const unsigned short *old_ip = iframe->ip;
6483 FrameClauseArgs clause_args;
6485 memset (&clause_args, 0, sizeof (FrameClauseArgs));
6486 clause_args.start_with_ip = (guint16*) handler_ip;
6487 clause_args.end_at_ip = (guint16*) handler_ip_end;
6488 clause_args.exit_clause = clause_index;
6490 interp_exec_method_full (iframe, context, &clause_args);
6491 if (context->has_resume_state) {
6492 return TRUE;
6493 } else {
6494 iframe->ip = old_ip;
6495 return FALSE;
6500 * interp_run_filter:
6502 * Run the filter clause identified by CLAUSE_INDEX in the intepreter frame given by
6503 * frame->interp_frame.
6505 static gboolean
6506 interp_run_filter (StackFrameInfo *frame, MonoException *ex, int clause_index, gpointer handler_ip, gpointer handler_ip_end)
6508 InterpFrame *iframe = (InterpFrame*)frame->interp_frame;
6509 ThreadContext *context = get_context ();
6510 InterpFrame child_frame;
6511 stackval retval;
6512 FrameClauseArgs clause_args;
6515 * Have to run the clause in a new frame which is a copy of IFRAME, since
6516 * during debugging, there are two copies of the frame on the stack.
6518 memset (&child_frame, 0, sizeof (InterpFrame));
6519 child_frame.imethod = iframe->imethod;
6520 child_frame.retval = &retval;
6521 child_frame.parent = iframe;
6522 child_frame.stack_args = iframe->stack_args;
6524 memset (&clause_args, 0, sizeof (FrameClauseArgs));
6525 clause_args.start_with_ip = (guint16*) handler_ip;
6526 clause_args.end_at_ip = (guint16*) handler_ip_end;
6527 clause_args.filter_exception = ex;
6528 clause_args.base_frame = iframe;
6530 interp_exec_method_full (&child_frame, context, &clause_args);
6531 /* ENDFILTER stores the result into child_frame->retval */
6532 return child_frame.retval->data.i ? TRUE : FALSE;
6535 typedef struct {
6536 InterpFrame *current;
6537 } StackIter;
6540 * interp_frame_iter_init:
6542 * Initialize an iterator for iterating through interpreted frames.
6544 static void
6545 interp_frame_iter_init (MonoInterpStackIter *iter, gpointer interp_exit_data)
6547 StackIter *stack_iter = (StackIter*)iter;
6549 stack_iter->current = (InterpFrame*)interp_exit_data;
6553 * interp_frame_iter_next:
6555 * Fill out FRAME with date for the next interpreter frame.
6557 static gboolean
6558 interp_frame_iter_next (MonoInterpStackIter *iter, StackFrameInfo *frame)
6560 StackIter *stack_iter = (StackIter*)iter;
6561 InterpFrame *iframe = stack_iter->current;
6563 memset (frame, 0, sizeof (StackFrameInfo));
6564 /* pinvoke frames doesn't have imethod set */
6565 while (iframe && !(iframe->imethod && iframe->imethod->code && iframe->imethod->jinfo))
6566 iframe = iframe->parent;
6567 if (!iframe)
6568 return FALSE;
6570 MonoMethod *method = iframe->imethod->method;
6571 frame->domain = iframe->imethod->domain;
6572 frame->interp_frame = iframe;
6573 frame->method = method;
6574 frame->actual_method = method;
6575 if (method && ((method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) || (method->iflags & (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL | METHOD_IMPL_ATTRIBUTE_RUNTIME)))) {
6576 frame->native_offset = -1;
6577 frame->type = FRAME_TYPE_MANAGED_TO_NATIVE;
6578 } else {
6579 frame->type = FRAME_TYPE_INTERP;
6580 /* This is the offset in the interpreter IR */
6581 frame->native_offset = (guint8*)iframe->ip - (guint8*)iframe->imethod->code;
6582 if (!method->wrapper_type || method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD)
6583 frame->managed = TRUE;
6585 frame->ji = iframe->imethod->jinfo;
6586 frame->frame_addr = iframe;
6588 stack_iter->current = iframe->parent;
6590 return TRUE;
6593 static MonoJitInfo*
6594 interp_find_jit_info (MonoDomain *domain, MonoMethod *method)
6596 InterpMethod* imethod;
6598 imethod = lookup_imethod (domain, method);
6599 if (imethod)
6600 return imethod->jinfo;
6601 else
6602 return NULL;
6605 static void
6606 interp_set_breakpoint (MonoJitInfo *jinfo, gpointer ip)
6608 guint16 *code = (guint16*)ip;
6609 g_assert (*code == MINT_SDB_SEQ_POINT);
6610 *code = MINT_SDB_BREAKPOINT;
6613 static void
6614 interp_clear_breakpoint (MonoJitInfo *jinfo, gpointer ip)
6616 guint16 *code = (guint16*)ip;
6617 g_assert (*code == MINT_SDB_BREAKPOINT);
6618 *code = MINT_SDB_SEQ_POINT;
6621 static MonoJitInfo*
6622 interp_frame_get_jit_info (MonoInterpFrameHandle frame)
6624 InterpFrame *iframe = (InterpFrame*)frame;
6626 g_assert (iframe->imethod);
6627 return iframe->imethod->jinfo;
6630 static gpointer
6631 interp_frame_get_ip (MonoInterpFrameHandle frame)
6633 InterpFrame *iframe = (InterpFrame*)frame;
6635 g_assert (iframe->imethod);
6636 return (gpointer)iframe->ip;
6639 static gpointer
6640 interp_frame_get_arg (MonoInterpFrameHandle frame, int pos)
6642 InterpFrame *iframe = (InterpFrame*)frame;
6643 MonoMethodSignature *sig;
6645 g_assert (iframe->imethod);
6647 sig = mono_method_signature_internal (iframe->imethod->method);
6648 return stackval_to_data_addr (sig->params [pos], &iframe->stack_args [pos + !!iframe->imethod->hasthis]);
6651 static gpointer
6652 interp_frame_get_local (MonoInterpFrameHandle frame, int pos)
6654 InterpFrame *iframe = (InterpFrame*)frame;
6656 g_assert (iframe->imethod);
6658 return iframe->locals + iframe->imethod->local_offsets [pos];
6661 static gpointer
6662 interp_frame_get_this (MonoInterpFrameHandle frame)
6664 InterpFrame *iframe = (InterpFrame*)frame;
6666 g_assert (iframe->imethod);
6667 g_assert (iframe->imethod->hasthis);
6668 return &iframe->stack_args [0].data.p;
6671 static MonoInterpFrameHandle
6672 interp_frame_get_parent (MonoInterpFrameHandle frame)
6674 InterpFrame *iframe = (InterpFrame*)frame;
6676 return iframe->parent;
6679 static void
6680 interp_start_single_stepping (void)
6682 ss_enabled = TRUE;
6685 static void
6686 interp_stop_single_stepping (void)
6688 ss_enabled = FALSE;
6691 static void
6692 register_interp_stats (void)
6694 mono_counters_init ();
6695 mono_counters_register ("Total transform time", MONO_COUNTER_INTERP | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_interp_stats.transform_time);
6696 mono_counters_register ("Methods inlined", MONO_COUNTER_INTERP | MONO_COUNTER_INT, &mono_interp_stats.inlined_methods);
6697 mono_counters_register ("Inline failures", MONO_COUNTER_INTERP | MONO_COUNTER_INT, &mono_interp_stats.inline_failures);
6700 #undef MONO_EE_CALLBACK
6701 #define MONO_EE_CALLBACK(ret, name, sig) interp_ ## name,
6703 static const MonoEECallbacks mono_interp_callbacks = {
6704 MONO_EE_CALLBACKS
6707 void
6708 mono_ee_interp_init (const char *opts)
6710 g_assert (mono_ee_api_version () == MONO_EE_API_VERSION);
6711 g_assert (!interp_init_done);
6712 interp_init_done = TRUE;
6714 mono_native_tls_alloc (&thread_context_id, NULL);
6715 set_context (NULL);
6717 interp_parse_options (opts);
6718 if (mini_get_debug_options ()->mdb_optimizations)
6719 mono_interp_opt &= ~INTERP_OPT_INLINE;
6720 mono_interp_transform_init ();
6722 mini_install_interp_callbacks (&mono_interp_callbacks);
6724 register_interp_stats ();