[interp] Add missing write barrier (#12772)
[mono-project.git] / mono / mini / interp / interp.c
blob529274d5a93485c71c2d2af5c4984af5619c9fc5
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>
30 #ifdef HAVE_ALLOCA_H
31 # include <alloca.h>
32 #else
33 # ifdef __CYGWIN__
34 # define alloca __builtin_alloca
35 # endif
36 #endif
38 /* trim excessive headers */
39 #include <mono/metadata/image.h>
40 #include <mono/metadata/assembly-internals.h>
41 #include <mono/metadata/cil-coff.h>
42 #include <mono/metadata/mono-endian.h>
43 #include <mono/metadata/tabledefs.h>
44 #include <mono/metadata/tokentype.h>
45 #include <mono/metadata/loader.h>
46 #include <mono/metadata/threads.h>
47 #include <mono/metadata/threadpool.h>
48 #include <mono/metadata/profiler-private.h>
49 #include <mono/metadata/appdomain.h>
50 #include <mono/metadata/reflection.h>
51 #include <mono/metadata/exception.h>
52 #include <mono/metadata/verify.h>
53 #include <mono/metadata/opcodes.h>
54 #include <mono/metadata/debug-helpers.h>
55 #include <mono/metadata/mono-config.h>
56 #include <mono/metadata/marshal.h>
57 #include <mono/metadata/environment.h>
58 #include <mono/metadata/mono-debug.h>
59 #include <mono/metadata/gc-internals.h>
60 #include <mono/utils/atomic.h>
62 #include "interp.h"
63 #include "interp-internals.h"
64 #include "mintops.h"
66 #include <mono/mini/mini.h>
67 #include <mono/mini/mini-runtime.h>
68 #include <mono/mini/aot-runtime.h>
69 #include <mono/mini/llvm-runtime.h>
70 #include <mono/mini/llvmonly-runtime.h>
71 #include <mono/mini/jit-icalls.h>
72 #include <mono/mini/debugger-agent.h>
73 #include <mono/mini/ee.h>
75 #ifdef TARGET_ARM
76 #include <mono/mini/mini-arm.h>
77 #endif
78 #include <mono/metadata/icall-decl.h>
80 #ifdef _MSC_VER
81 #pragma warning(disable:4102) // label' : unreferenced label
82 #endif
84 /* Arguments that are passed when invoking only a finally/filter clause from the frame */
85 typedef struct {
86 /* Where we start the frame execution from */
87 guint16 *start_with_ip;
89 * End ip of the exit_clause. We need it so we know whether the resume
90 * state is for this frame (which is called from EH) or for the original
91 * frame further down the stack.
93 guint16 *end_at_ip;
94 /* When exiting this clause we also exit the frame */
95 int exit_clause;
96 /* Exception that we are filtering */
97 MonoException *filter_exception;
98 InterpFrame *base_frame;
99 } FrameClauseArgs;
101 static inline void
102 init_frame (InterpFrame *frame, InterpFrame *parent_frame, InterpMethod *rmethod, stackval *method_args, stackval *method_retval)
104 frame->parent = parent_frame;
105 frame->stack_args = method_args;
106 frame->retval = method_retval;
107 frame->imethod = rmethod;
108 frame->ex = NULL;
109 frame->ip = NULL;
110 frame->invoke_trap = 0;
113 #define INIT_FRAME(frame,parent_frame,method_args,method_retval,domain,mono_method,error) do { \
114 InterpMethod *_rmethod = mono_interp_get_imethod ((domain), (mono_method), (error)); \
115 init_frame ((frame), (parent_frame), _rmethod, (method_args), (method_retval)); \
116 } while (0)
118 #define interp_exec_method(frame, context) interp_exec_method_full ((frame), (context), NULL)
121 * List of classes whose methods will be executed by transitioning to JITted code.
122 * Used for testing.
124 GSList *mono_interp_jit_classes;
125 /* Optimizations enabled with interpreter */
126 int mono_interp_opt = INTERP_OPT_INLINE;
127 /* If TRUE, interpreted code will be interrupted at function entry/backward branches */
128 static gboolean ss_enabled;
130 static gboolean interp_init_done = FALSE;
132 static char* dump_frame (InterpFrame *inv);
133 static MonoArray *get_trace_ips (MonoDomain *domain, InterpFrame *top);
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 static char* dump_args (InterpFrame *inv);
143 #define DEBUG_INTERP 0
144 #define COUNT_OPS 0
145 #if DEBUG_INTERP
146 int mono_interp_traceopt = 2;
147 /* If true, then we output the opcodes as we interpret them */
148 static int global_tracing = 2;
150 static int debug_indent_level = 0;
152 static int break_on_method = 0;
153 static int nested_trace = 0;
154 static GList *db_methods = NULL;
156 static void
157 output_indent (void)
159 int h;
161 for (h = 0; h < debug_indent_level; h++)
162 g_print (" ");
165 static void
166 db_match_method (gpointer data, gpointer user_data)
168 MonoMethod *m = (MonoMethod*)user_data;
169 MonoMethodDesc *desc = data;
171 if (mono_method_desc_full_match (desc, m))
172 break_on_method = 1;
175 static void
176 debug_enter (InterpFrame *frame, int *tracing)
178 if (db_methods) {
179 g_list_foreach (db_methods, db_match_method, (gpointer)frame->imethod->method);
180 if (break_on_method)
181 *tracing = nested_trace ? (global_tracing = 2, 3) : 2;
182 break_on_method = 0;
184 if (*tracing) {
185 MonoMethod *method = frame->imethod->method;
186 char *mn, *args = dump_args (frame);
187 debug_indent_level++;
188 output_indent ();
189 mn = mono_method_full_name (method, FALSE);
190 g_print ("(%p) Entering %s (", mono_thread_internal_current (), mn);
191 g_free (mn);
192 g_print ("%s)\n", args);
193 g_free (args);
198 #define DEBUG_LEAVE() \
199 if (tracing) { \
200 char *mn, *args; \
201 args = dump_retval (frame); \
202 output_indent (); \
203 mn = mono_method_full_name (frame->imethod->method, FALSE); \
204 g_print ("(%p) Leaving %s", mono_thread_internal_current (), mn); \
205 g_free (mn); \
206 g_print (" => %s\n", args); \
207 g_free (args); \
208 debug_indent_level--; \
209 if (tracing == 3) global_tracing = 0; \
212 #else
214 int mono_interp_traceopt = 0;
215 static void debug_enter (InterpFrame *frame, int *tracing)
218 #define DEBUG_LEAVE()
220 #endif
222 static void
223 set_resume_state (ThreadContext *context, InterpFrame *frame)
225 frame->ex = NULL;
226 context->has_resume_state = 0;
227 context->handler_frame = NULL;
228 context->handler_ei = NULL;
231 /* Set the current execution state to the resume state in context */
232 #define SET_RESUME_STATE(context) do { \
233 ip = (const guint16*)(context)->handler_ip; \
234 /* spec says stack should be empty at endfinally so it should be at the start too */ \
235 sp = frame->stack; \
236 vt_sp = (unsigned char *) sp + rtm->stack_size; \
237 if (frame->ex) { \
238 sp->data.p = frame->ex; \
239 ++sp; \
241 /* We have thrown an exception from a finally block. Some of the leave targets were unwinded already */ \
242 while (finally_ips && \
243 finally_ips->data >= (context)->handler_ei->try_start && \
244 finally_ips->data < (context)->handler_ei->try_end) \
245 finally_ips = g_slist_remove (finally_ips, finally_ips->data); \
246 set_resume_state ((context), (frame)); \
247 goto main_loop; \
248 } while (0)
251 * If this bit is set, it means the call has thrown the exception, and we
252 * reached this point because the EH code in mono_handle_exception ()
253 * unwound all the JITted frames below us. mono_interp_set_resume_state ()
254 * has set the fields in context to indicate where we have to resume execution.
256 #define CHECK_RESUME_STATE(context) do { \
257 if ((context)->has_resume_state) { \
258 if (frame == (context)->handler_frame && (!clause_args || (context)->handler_ip < clause_args->end_at_ip)) \
259 SET_RESUME_STATE (context); \
260 else \
261 goto exit_frame; \
263 } while (0);
265 static void
266 set_context (ThreadContext *context)
268 mono_native_tls_set_value (thread_context_id, context);
270 if (!context)
271 return;
273 MonoJitTlsData *jit_tls = mono_tls_get_jit_tls ();
274 g_assertf (jit_tls, "ThreadContext needs initialized JIT TLS");
276 /* jit_tls assumes ownership of 'context' */
277 jit_tls->interp_context = context;
280 static ThreadContext *
281 get_context (void)
283 ThreadContext *context = (ThreadContext *) mono_native_tls_get_value (thread_context_id);
284 if (context == NULL) {
285 context = g_new0 (ThreadContext, 1);
286 set_context (context);
288 return context;
291 static void
292 ves_real_abort (int line, MonoMethod *mh,
293 const unsigned short *ip, stackval *stack, stackval *sp)
295 ERROR_DECL (error);
296 MonoMethodHeader *header = mono_method_get_header_checked (mh, error);
297 mono_error_cleanup (error); /* FIXME: don't swallow the error */
298 g_printerr ("Execution aborted in method: %s::%s\n", m_class_get_name (mh->klass), mh->name);
299 g_printerr ("Line=%d IP=0x%04lx, Aborted execution\n", line, ip-(const unsigned short *) header->code);
300 g_printerr ("0x%04x %02x\n", ip-(const unsigned short *) header->code, *ip);
301 mono_metadata_free_mh (header);
304 #define ves_abort() \
305 do {\
306 ves_real_abort(__LINE__, frame->imethod->method, ip, frame->stack, sp); \
307 THROW_EX (mono_get_exception_execution_engine (NULL), ip); \
308 } while (0);
310 static InterpMethod*
311 lookup_imethod (MonoDomain *domain, MonoMethod *method)
313 InterpMethod *rtm;
314 MonoJitDomainInfo *info;
316 info = domain_jit_info (domain);
317 mono_domain_jit_code_hash_lock (domain);
318 rtm = (InterpMethod*)mono_internal_hash_table_lookup (&info->interp_code_hash, method);
319 mono_domain_jit_code_hash_unlock (domain);
320 return rtm;
323 static gpointer
324 interp_get_remoting_invoke (MonoMethod *method, gpointer addr, MonoError *error)
326 #ifndef DISABLE_REMOTING
327 InterpMethod *imethod;
329 if (addr) {
330 imethod = lookup_method_pointer (addr);
331 } else {
332 g_assert (method);
333 imethod = mono_interp_get_imethod (mono_domain_get (), method, error);
334 return_val_if_nok (error, NULL);
336 g_assert (imethod);
337 g_assert (mono_use_interpreter);
339 MonoMethod *remoting_invoke_method = mono_marshal_get_remoting_invoke (imethod->method, error);
340 return_val_if_nok (error, NULL);
341 return mono_interp_get_imethod (mono_domain_get (), remoting_invoke_method, error);
342 #else
343 g_assert_not_reached ();
344 return NULL;
345 #endif
348 InterpMethod*
349 mono_interp_get_imethod (MonoDomain *domain, MonoMethod *method, MonoError *error)
351 InterpMethod *rtm;
352 MonoJitDomainInfo *info;
353 MonoMethodSignature *sig;
354 int i;
356 error_init (error);
358 info = domain_jit_info (domain);
359 mono_domain_jit_code_hash_lock (domain);
360 rtm = (InterpMethod*)mono_internal_hash_table_lookup (&info->interp_code_hash, method);
361 mono_domain_jit_code_hash_unlock (domain);
362 if (rtm)
363 return rtm;
365 sig = mono_method_signature_internal (method);
367 rtm = (InterpMethod*)mono_domain_alloc0 (domain, sizeof (InterpMethod));
368 rtm->method = method;
369 rtm->domain = domain;
370 rtm->param_count = sig->param_count;
371 rtm->hasthis = sig->hasthis;
372 rtm->vararg = sig->call_convention == MONO_CALL_VARARG;
373 rtm->rtype = mini_get_underlying_type (sig->ret);
374 rtm->param_types = (MonoType**)mono_domain_alloc0 (domain, sizeof (MonoType*) * sig->param_count);
375 for (i = 0; i < sig->param_count; ++i)
376 rtm->param_types [i] = mini_get_underlying_type (sig->params [i]);
378 mono_domain_jit_code_hash_lock (domain);
379 if (!mono_internal_hash_table_lookup (&info->interp_code_hash, method))
380 mono_internal_hash_table_insert (&info->interp_code_hash, method, rtm);
381 mono_domain_jit_code_hash_unlock (domain);
383 rtm->prof_flags = mono_profiler_get_call_instrumentation_flags (rtm->method);
385 return rtm;
388 #if defined (MONO_CROSS_COMPILE) || defined (HOST_WASM) || defined (_MSC_VER)
389 #define INTERP_PUSH_LMF_WITH_CTX_BODY(ext, exit_addr) \
390 (ext).kind = MONO_LMFEXT_INTERP_EXIT;
392 #elif defined(MONO_ARCH_HAS_NO_PROPER_MONOCTX)
393 /* some platforms, e.g. appleTV, don't provide us a precise MonoContext
394 * (registers are not accurate), thus resuming to the label does not work. */
395 #define INTERP_PUSH_LMF_WITH_CTX_BODY(ext, exit_addr) \
396 (ext).kind = MONO_LMFEXT_INTERP_EXIT;
398 #elif defined(MONO_ARCH_HAS_MONO_CONTEXT)
399 #define INTERP_PUSH_LMF_WITH_CTX_BODY(ext, exit_addr) \
400 (ext).kind = MONO_LMFEXT_INTERP_EXIT_WITH_CTX; \
401 MONO_CONTEXT_GET_CURRENT ((ext).ctx); \
402 MONO_CONTEXT_SET_IP (&(ext).ctx, (exit_addr)); \
403 mono_arch_do_ip_adjustment (&(ext).ctx);
404 #else
405 #define INTERP_PUSH_LMF_WITH_CTX_BODY(ext, exit_addr) g_error ("requires working mono-context");
406 #endif
408 /* INTERP_PUSH_LMF_WITH_CTX:
410 * same as interp_push_lmf, but retrieving and attaching MonoContext to it.
411 * This is needed to resume into the interp when the exception is thrown from
412 * native code (see ./mono/tests/install_eh_callback.exe).
414 * This must be a macro in order to retrieve the right register values for
415 * MonoContext.
417 #define INTERP_PUSH_LMF_WITH_CTX(frame, ext, exit_addr) \
418 memset (&(ext), 0, sizeof (MonoLMFExt)); \
419 (ext).interp_exit_data = (frame); \
420 INTERP_PUSH_LMF_WITH_CTX_BODY ((ext), (exit_addr)); \
421 mono_push_lmf (&(ext));
424 * interp_push_lmf:
426 * Push an LMF frame on the LMF stack
427 * to mark the transition to native code.
428 * This is needed for the native code to
429 * be able to do stack walks.
431 static void
432 interp_push_lmf (MonoLMFExt *ext, InterpFrame *frame)
434 memset (ext, 0, sizeof (MonoLMFExt));
435 ext->kind = MONO_LMFEXT_INTERP_EXIT;
436 ext->interp_exit_data = frame;
438 mono_push_lmf (ext);
441 static void
442 interp_pop_lmf (MonoLMFExt *ext)
444 mono_pop_lmf (&ext->lmf);
447 static InterpMethod*
448 get_virtual_method (InterpMethod *imethod, MonoObject *obj)
450 MonoMethod *m = imethod->method;
451 MonoDomain *domain = imethod->domain;
452 InterpMethod *ret = NULL;
453 ERROR_DECL (error);
455 #ifndef DISABLE_REMOTING
456 if (mono_object_is_transparent_proxy (obj)) {
457 MonoMethod *remoting_invoke_method = mono_marshal_get_remoting_invoke_with_check (m, error);
458 mono_error_assert_ok (error);
459 ret = mono_interp_get_imethod (domain, remoting_invoke_method, error);
460 mono_error_assert_ok (error);
461 return ret;
463 #endif
465 if ((m->flags & METHOD_ATTRIBUTE_FINAL) || !(m->flags & METHOD_ATTRIBUTE_VIRTUAL)) {
466 if (m->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED) {
467 ret = mono_interp_get_imethod (domain, mono_marshal_get_synchronized_wrapper (m), error);
468 mono_error_cleanup (error); /* FIXME: don't swallow the error */
469 } else {
470 ret = imethod;
472 return ret;
475 mono_class_setup_vtable (obj->vtable->klass);
477 int slot = mono_method_get_vtable_slot (m);
478 if (mono_class_is_interface (m->klass)) {
479 g_assert (obj->vtable->klass != m->klass);
480 /* TODO: interface offset lookup is slow, go through IMT instead */
481 gboolean non_exact_match;
482 slot += mono_class_interface_offset_with_variance (obj->vtable->klass, m->klass, &non_exact_match);
485 MonoMethod *virtual_method = m_class_get_vtable (mono_object_class (obj)) [slot];
486 if (m->is_inflated && mono_method_get_context (m)->method_inst) {
487 MonoGenericContext context = { NULL, NULL };
489 if (mono_class_is_ginst (virtual_method->klass))
490 context.class_inst = mono_class_get_generic_class (virtual_method->klass)->context.class_inst;
491 else if (mono_class_is_gtd (virtual_method->klass))
492 context.class_inst = mono_class_get_generic_container (virtual_method->klass)->context.class_inst;
493 context.method_inst = mono_method_get_context (m)->method_inst;
495 virtual_method = mono_class_inflate_generic_method_checked (virtual_method, &context, error);
496 mono_error_cleanup (error); /* FIXME: don't swallow the error */
499 if (virtual_method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED) {
500 virtual_method = mono_marshal_get_synchronized_wrapper (virtual_method);
503 InterpMethod *virtual_imethod = mono_interp_get_imethod (domain, virtual_method, error);
504 mono_error_cleanup (error); /* FIXME: don't swallow the error */
505 return virtual_imethod;
508 typedef struct {
509 InterpMethod *imethod;
510 InterpMethod *target_imethod;
511 } InterpVTableEntry;
513 /* domain lock must be held */
514 static GSList*
515 append_imethod (MonoDomain *domain, GSList *list, InterpMethod *imethod, InterpMethod *target_imethod)
517 GSList *ret;
518 InterpVTableEntry *entry;
520 entry = (InterpVTableEntry*) mono_mempool_alloc (domain->mp, sizeof (InterpVTableEntry));
521 entry->imethod = imethod;
522 entry->target_imethod = target_imethod;
523 ret = g_slist_append_mempool (domain->mp, list, entry);
525 return ret;
528 static InterpMethod*
529 get_target_imethod (GSList *list, InterpMethod *imethod)
531 while (list != NULL) {
532 InterpVTableEntry *entry = (InterpVTableEntry*) list->data;
533 if (entry->imethod == imethod)
534 return entry->target_imethod;
535 list = list->next;
537 return NULL;
540 static gpointer*
541 get_method_table (MonoObject *obj, int offset)
543 if (offset >= 0) {
544 return obj->vtable->interp_vtable;
545 } else {
546 return (gpointer*)obj->vtable;
550 static gpointer*
551 alloc_method_table (MonoObject *obj, int offset)
553 gpointer *table;
555 if (offset >= 0) {
556 table = mono_domain_alloc0 (obj->vtable->domain, m_class_get_vtable_size (obj->vtable->klass) * sizeof (gpointer));
557 obj->vtable->interp_vtable = table;
558 } else {
559 table = (gpointer*)obj->vtable;
562 return table;
565 static InterpMethod*
566 get_virtual_method_fast (MonoObject *obj, InterpMethod *imethod, int offset)
568 gpointer *table;
570 #ifndef DISABLE_REMOTING
571 /* FIXME Remoting */
572 if (mono_object_is_transparent_proxy (obj))
573 return get_virtual_method (imethod, obj);
574 #endif
576 table = get_method_table (obj, offset);
578 if (!table) {
579 /* Lazily allocate method table */
580 mono_domain_lock (obj->vtable->domain);
581 table = get_method_table (obj, offset);
582 if (!table)
583 table = alloc_method_table (obj, offset);
584 mono_domain_unlock (obj->vtable->domain);
587 if (!table [offset]) {
588 InterpMethod *target_imethod = get_virtual_method (imethod, obj);
589 /* Lazily initialize the method table slot */
590 mono_domain_lock (obj->vtable->domain);
591 if (!table [offset]) {
592 if (imethod->method->is_inflated || offset < 0)
593 table [offset] = append_imethod (obj->vtable->domain, NULL, imethod, target_imethod);
594 else
595 table [offset] = (gpointer) ((gsize)target_imethod | 0x1);
597 mono_domain_unlock (obj->vtable->domain);
600 if ((gsize)table [offset] & 0x1) {
601 /* Non generic virtual call. Only one method in slot */
602 return (InterpMethod*) ((gsize)table [offset] & ~0x1);
603 } else {
604 /* Virtual generic or interface call. Multiple methods in slot */
605 InterpMethod *target_imethod = get_target_imethod ((GSList*)table [offset], imethod);
607 if (!target_imethod) {
608 target_imethod = get_virtual_method (imethod, obj);
609 mono_domain_lock (obj->vtable->domain);
610 if (!get_target_imethod ((GSList*)table [offset], imethod))
611 table [offset] = append_imethod (obj->vtable->domain, (GSList*)table [offset], imethod, target_imethod);
612 mono_domain_unlock (obj->vtable->domain);
614 return target_imethod;
618 static void inline
619 stackval_from_data (MonoType *type_, stackval *result, void *data, gboolean pinvoke)
621 MonoType *type = mini_native_type_replace_type (type_);
622 if (type->byref) {
623 switch (type->type) {
624 case MONO_TYPE_OBJECT:
625 case MONO_TYPE_CLASS:
626 case MONO_TYPE_STRING:
627 case MONO_TYPE_ARRAY:
628 case MONO_TYPE_SZARRAY:
629 break;
630 default:
631 break;
633 result->data.p = *(gpointer*)data;
634 return;
636 switch (type->type) {
637 case MONO_TYPE_VOID:
638 return;
639 case MONO_TYPE_I1:
640 result->data.i = *(gint8*)data;
641 return;
642 case MONO_TYPE_U1:
643 case MONO_TYPE_BOOLEAN:
644 result->data.i = *(guint8*)data;
645 return;
646 case MONO_TYPE_I2:
647 result->data.i = *(gint16*)data;
648 return;
649 case MONO_TYPE_U2:
650 case MONO_TYPE_CHAR:
651 result->data.i = *(guint16*)data;
652 return;
653 case MONO_TYPE_I4:
654 result->data.i = *(gint32*)data;
655 return;
656 case MONO_TYPE_U:
657 case MONO_TYPE_I:
658 result->data.nati = *(mono_i*)data;
659 return;
660 case MONO_TYPE_PTR:
661 result->data.p = *(gpointer*)data;
662 return;
663 case MONO_TYPE_U4:
664 result->data.i = *(guint32*)data;
665 return;
666 case MONO_TYPE_R4:
667 /* memmove handles unaligned case */
668 memmove (&result->data.f_r4, data, sizeof (float));
669 return;
670 case MONO_TYPE_I8:
671 case MONO_TYPE_U8:
672 memmove (&result->data.l, data, sizeof (gint64));
673 return;
674 case MONO_TYPE_R8:
675 memmove (&result->data.f, data, sizeof (double));
676 return;
677 case MONO_TYPE_STRING:
678 case MONO_TYPE_SZARRAY:
679 case MONO_TYPE_CLASS:
680 case MONO_TYPE_OBJECT:
681 case MONO_TYPE_ARRAY:
682 result->data.p = *(gpointer*)data;
683 return;
684 case MONO_TYPE_VALUETYPE:
685 if (m_class_is_enumtype (type->data.klass)) {
686 stackval_from_data (mono_class_enum_basetype_internal (type->data.klass), result, data, pinvoke);
687 return;
688 } else if (pinvoke) {
689 memcpy (result->data.vt, data, mono_class_native_size (type->data.klass, NULL));
690 } else {
691 mono_value_copy_internal (result->data.vt, data, type->data.klass);
693 return;
694 case MONO_TYPE_GENERICINST: {
695 if (mono_type_generic_inst_is_valuetype (type)) {
696 mono_value_copy_internal (result->data.vt, data, mono_class_from_mono_type_internal (type));
697 return;
699 stackval_from_data (m_class_get_byval_arg (type->data.generic_class->container_class), result, data, pinvoke);
700 return;
702 default:
703 g_error ("got type 0x%02x", type->type);
707 static void inline
708 stackval_to_data (MonoType *type_, stackval *val, void *data, gboolean pinvoke)
710 MonoType *type = mini_native_type_replace_type (type_);
711 if (type->byref) {
712 gpointer *p = (gpointer*)data;
713 *p = val->data.p;
714 return;
716 /* printf ("TODAT0 %p\n", data); */
717 switch (type->type) {
718 case MONO_TYPE_I1:
719 case MONO_TYPE_U1: {
720 guint8 *p = (guint8*)data;
721 *p = val->data.i;
722 return;
724 case MONO_TYPE_BOOLEAN: {
725 guint8 *p = (guint8*)data;
726 *p = (val->data.i != 0);
727 return;
729 case MONO_TYPE_I2:
730 case MONO_TYPE_U2:
731 case MONO_TYPE_CHAR: {
732 guint16 *p = (guint16*)data;
733 *p = val->data.i;
734 return;
736 case MONO_TYPE_I: {
737 mono_i *p = (mono_i*)data;
738 /* In theory the value used by stloc should match the local var type
739 but in practice it sometimes doesn't (a int32 gets dup'd and stloc'd into
740 a native int - both by csc and mcs). Not sure what to do about sign extension
741 as it is outside the spec... doing the obvious */
742 *p = (mono_i)val->data.nati;
743 return;
745 case MONO_TYPE_U: {
746 mono_u *p = (mono_u*)data;
747 /* see above. */
748 *p = (mono_u)val->data.nati;
749 return;
751 case MONO_TYPE_I4:
752 case MONO_TYPE_U4: {
753 gint32 *p = (gint32*)data;
754 *p = val->data.i;
755 return;
757 case MONO_TYPE_I8:
758 case MONO_TYPE_U8: {
759 memmove (data, &val->data.l, sizeof (gint64));
760 return;
762 case MONO_TYPE_R4: {
763 /* memmove handles unaligned case */
764 memmove (data, &val->data.f_r4, sizeof (float));
765 return;
767 case MONO_TYPE_R8: {
768 memmove (data, &val->data.f, sizeof (double));
769 return;
771 case MONO_TYPE_STRING:
772 case MONO_TYPE_SZARRAY:
773 case MONO_TYPE_CLASS:
774 case MONO_TYPE_OBJECT:
775 case MONO_TYPE_ARRAY: {
776 gpointer *p = (gpointer *) data;
777 mono_gc_wbarrier_generic_store_internal (p, val->data.o);
778 return;
780 case MONO_TYPE_PTR: {
781 gpointer *p = (gpointer *) data;
782 *p = val->data.p;
783 return;
785 case MONO_TYPE_VALUETYPE:
786 if (m_class_is_enumtype (type->data.klass)) {
787 stackval_to_data (mono_class_enum_basetype_internal (type->data.klass), val, data, pinvoke);
788 return;
789 } else if (pinvoke) {
790 memcpy (data, val->data.vt, mono_class_native_size (type->data.klass, NULL));
791 } else {
792 mono_value_copy_internal (data, val->data.vt, type->data.klass);
794 return;
795 case MONO_TYPE_GENERICINST: {
796 MonoClass *container_class = type->data.generic_class->container_class;
798 if (m_class_is_valuetype (container_class) && !m_class_is_enumtype (container_class)) {
799 mono_value_copy_internal (data, val->data.vt, mono_class_from_mono_type_internal (type));
800 return;
802 stackval_to_data (m_class_get_byval_arg (type->data.generic_class->container_class), val, data, pinvoke);
803 return;
805 default:
806 g_error ("got type %x", type->type);
811 * Same as stackval_to_data but return address of storage instead
812 * of copying the value.
814 static gpointer
815 stackval_to_data_addr (MonoType *type_, stackval *val)
817 MonoType *type = mini_native_type_replace_type (type_);
818 if (type->byref)
819 return &val->data.p;
821 switch (type->type) {
822 case MONO_TYPE_I1:
823 case MONO_TYPE_U1:
824 case MONO_TYPE_BOOLEAN:
825 case MONO_TYPE_I2:
826 case MONO_TYPE_U2:
827 case MONO_TYPE_CHAR:
828 case MONO_TYPE_I4:
829 case MONO_TYPE_U4:
830 return &val->data.i;
831 case MONO_TYPE_I:
832 case MONO_TYPE_U:
833 return &val->data.nati;
834 case MONO_TYPE_I8:
835 case MONO_TYPE_U8:
836 return &val->data.l;
837 case MONO_TYPE_R4:
838 return &val->data.f_r4;
839 case MONO_TYPE_R8:
840 return &val->data.f;
841 case MONO_TYPE_STRING:
842 case MONO_TYPE_SZARRAY:
843 case MONO_TYPE_CLASS:
844 case MONO_TYPE_OBJECT:
845 case MONO_TYPE_ARRAY:
846 case MONO_TYPE_PTR:
847 return &val->data.p;
848 case MONO_TYPE_VALUETYPE:
849 if (m_class_is_enumtype (type->data.klass))
850 return stackval_to_data_addr (mono_class_enum_basetype_internal (type->data.klass), val);
851 else
852 return val->data.vt;
853 case MONO_TYPE_TYPEDBYREF:
854 return val->data.vt;
855 case MONO_TYPE_GENERICINST: {
856 MonoClass *container_class = type->data.generic_class->container_class;
858 if (m_class_is_valuetype (container_class) && !m_class_is_enumtype (container_class))
859 return val->data.vt;
860 return stackval_to_data_addr (m_class_get_byval_arg (type->data.generic_class->container_class), val);
862 default:
863 g_error ("got type %x", type->type);
868 * interp_throw:
869 * Throw an exception from the interpreter.
871 static MONO_NEVER_INLINE void
872 interp_throw (ThreadContext *context, MonoException *ex, InterpFrame *frame, gconstpointer ip, gboolean rethrow)
874 ERROR_DECL (error);
875 MonoLMFExt ext;
877 interp_push_lmf (&ext, frame);
878 frame->ip = (const guint16*)ip;
879 frame->ex = ex;
881 if (mono_object_isinst_checked ((MonoObject *) ex, mono_defaults.exception_class, error)) {
882 MonoException *mono_ex = (MonoException *) ex;
883 if (!rethrow) {
884 mono_ex->stack_trace = NULL;
885 mono_ex->trace_ips = NULL;
888 mono_error_assert_ok (error);
890 MonoContext ctx;
891 memset (&ctx, 0, sizeof (MonoContext));
892 MONO_CONTEXT_SET_SP (&ctx, frame);
895 * Call the JIT EH code. The EH code will call back to us using:
896 * - mono_interp_set_resume_state ()/run_finally ()/run_filter ().
897 * Since ctx.ip is 0, this will start unwinding from the LMF frame
898 * pushed above, which points to our frames.
900 mono_handle_exception (&ctx, (MonoObject*)ex);
901 if (MONO_CONTEXT_GET_IP (&ctx) != 0) {
902 /* We need to unwind into non-interpreter code */
903 mono_restore_context (&ctx);
904 g_assert_not_reached ();
907 interp_pop_lmf (&ext);
909 g_assert (context->has_resume_state);
912 static void
913 fill_in_trace (MonoException *exception, InterpFrame *frame)
915 ERROR_DECL (error);
916 char *stack_trace = dump_frame (frame);
917 MonoDomain *domain = frame->imethod->domain;
918 (exception)->stack_trace = mono_string_new_checked (domain, stack_trace, error);
919 mono_error_cleanup (error); /* FIXME: don't swallow the error */
920 (exception)->trace_ips = get_trace_ips (domain, frame);
921 g_free (stack_trace);
924 #define FILL_IN_TRACE(exception, frame) fill_in_trace(exception, frame)
926 #define THROW_EX_GENERAL(exception,ex_ip, rethrow) \
927 do { \
928 interp_throw (context, (exception), (frame), (ex_ip), (rethrow)); \
929 CHECK_RESUME_STATE(context); \
930 } while (0)
932 #define THROW_EX(exception,ex_ip) THROW_EX_GENERAL ((exception), (ex_ip), FALSE)
934 #define EXCEPTION_CHECKPOINT \
935 do { \
936 if (*mono_thread_interruption_request_flag () && !mono_threads_is_critical_method (rtm->method)) { \
937 MonoException *exc = mono_thread_interruption_checkpoint (); \
938 if (exc) \
939 THROW_EX (exc, ip); \
941 } while (0)
944 static MonoObject*
945 ves_array_create (MonoDomain *domain, MonoClass *klass, int param_count, stackval *values, MonoError *error)
947 uintptr_t *lengths;
948 intptr_t *lower_bounds;
949 MonoObject *obj;
950 int i;
952 lengths = g_newa (uintptr_t, m_class_get_rank (klass) * 2);
953 for (i = 0; i < param_count; ++i) {
954 lengths [i] = values->data.i;
955 values ++;
957 if (m_class_get_rank (klass) == param_count) {
958 /* Only lengths provided. */
959 lower_bounds = NULL;
960 } else {
961 /* lower bounds are first. */
962 lower_bounds = (intptr_t *) lengths;
963 lengths += m_class_get_rank (klass);
965 obj = (MonoObject*) mono_array_new_full_checked (domain, klass, lengths, lower_bounds, error);
966 return obj;
969 static gint32
970 ves_array_calculate_index (MonoArray *ao, stackval *sp, InterpFrame *frame, gboolean safe)
972 g_assert (!frame->ex);
973 MonoClass *ac = ((MonoObject *) ao)->vtable->klass;
975 guint32 pos = 0;
976 if (ao->bounds) {
977 for (gint32 i = 0; i < m_class_get_rank (ac); i++) {
978 guint32 idx = sp [i].data.i;
979 guint32 lower = ao->bounds [i].lower_bound;
980 guint32 len = ao->bounds [i].length;
981 if (safe && (idx < lower || (idx - lower) >= len)) {
982 frame->ex = mono_get_exception_index_out_of_range ();
983 FILL_IN_TRACE (frame->ex, frame);
984 return -1;
986 pos = (pos * len) + idx - lower;
988 } else {
989 pos = sp [0].data.i;
990 if (safe && pos >= ao->max_length) {
991 frame->ex = mono_get_exception_index_out_of_range ();
992 FILL_IN_TRACE (frame->ex, frame);
993 return -1;
996 return pos;
999 static void
1000 ves_array_set (InterpFrame *frame, stackval *sp, MonoMethodSignature *sig)
1002 MonoObject *o = sp->data.o;
1003 MonoArray *ao = (MonoArray *) o;
1004 MonoClass *ac = o->vtable->klass;
1006 g_assert (m_class_get_rank (ac) >= 1);
1008 gint32 pos = ves_array_calculate_index (ao, sp + 1, frame, TRUE);
1009 if (frame->ex)
1010 return;
1012 int val_index = 1 + m_class_get_rank (ac);
1013 if (sp [val_index].data.p && !m_class_is_valuetype (m_class_get_element_class (mono_object_class (o)))) {
1014 ERROR_DECL (error);
1015 MonoObject *isinst = mono_object_isinst_checked (sp [val_index].data.o, m_class_get_element_class (mono_object_class (o)), error);
1016 mono_error_cleanup (error);
1017 if (!isinst) {
1018 frame->ex = mono_get_exception_array_type_mismatch ();
1019 FILL_IN_TRACE (frame->ex, frame);
1020 return;
1024 gint32 esize = mono_array_element_size (ac);
1025 gpointer ea = mono_array_addr_with_size_fast (ao, esize, pos);
1027 MonoType *mt = sig->params [m_class_get_rank (ac)];
1028 stackval_to_data (mt, &sp [val_index], ea, FALSE);
1031 static void
1032 ves_array_get (InterpFrame *frame, stackval *sp, stackval *retval, MonoMethodSignature *sig, gboolean safe)
1034 MonoObject *o = sp->data.o;
1035 MonoArray *ao = (MonoArray *) o;
1036 MonoClass *ac = o->vtable->klass;
1038 g_assert (m_class_get_rank (ac) >= 1);
1040 gint32 pos = ves_array_calculate_index (ao, sp + 1, frame, safe);
1041 if (frame->ex)
1042 return;
1044 gint32 esize = mono_array_element_size (ac);
1045 gpointer ea = mono_array_addr_with_size_fast (ao, esize, pos);
1047 MonoType *mt = sig->ret;
1048 stackval_from_data (mt, retval, ea, FALSE);
1051 static gpointer
1052 ves_array_element_address (InterpFrame *frame, MonoClass *required_type, MonoArray *ao, stackval *sp, gboolean needs_typecheck)
1054 MonoClass *ac = ((MonoObject *) ao)->vtable->klass;
1056 g_assert (m_class_get_rank (ac) >= 1);
1058 gint32 pos = ves_array_calculate_index (ao, sp, frame, TRUE);
1059 if (frame->ex)
1060 return NULL;
1062 if (needs_typecheck && !mono_class_is_assignable_from_internal (m_class_get_element_class (mono_object_class ((MonoObject *) ao)), m_class_get_element_class (required_type))) {
1063 frame->ex = mono_get_exception_array_type_mismatch ();
1064 FILL_IN_TRACE (frame->ex, frame);
1065 return NULL;
1067 gint32 esize = mono_array_element_size (ac);
1068 return mono_array_addr_with_size_fast (ao, esize, pos);
1071 #ifdef MONO_ARCH_HAVE_INTERP_ENTRY_TRAMPOLINE
1072 static MonoFuncV mono_native_to_interp_trampoline = NULL;
1073 #endif
1075 #ifndef MONO_ARCH_HAVE_INTERP_PINVOKE_TRAMP
1076 static InterpMethodArguments* build_args_from_sig (MonoMethodSignature *sig, InterpFrame *frame)
1078 InterpMethodArguments *margs = g_malloc0 (sizeof (InterpMethodArguments));
1080 #ifdef TARGET_ARM
1081 g_assert (mono_arm_eabi_supported ());
1082 int i8_align = mono_arm_i8_align ();
1083 #endif
1085 #ifdef TARGET_WASM
1086 margs->sig = sig;
1087 #endif
1089 if (sig->hasthis)
1090 margs->ilen++;
1092 for (int i = 0; i < sig->param_count; i++) {
1093 guint32 ptype = sig->params [i]->byref ? MONO_TYPE_PTR : sig->params [i]->type;
1094 switch (ptype) {
1095 case MONO_TYPE_BOOLEAN:
1096 case MONO_TYPE_CHAR:
1097 case MONO_TYPE_I1:
1098 case MONO_TYPE_U1:
1099 case MONO_TYPE_I2:
1100 case MONO_TYPE_U2:
1101 case MONO_TYPE_I4:
1102 case MONO_TYPE_U4:
1103 case MONO_TYPE_I:
1104 case MONO_TYPE_U:
1105 case MONO_TYPE_PTR:
1106 case MONO_TYPE_SZARRAY:
1107 case MONO_TYPE_CLASS:
1108 case MONO_TYPE_OBJECT:
1109 case MONO_TYPE_STRING:
1110 case MONO_TYPE_VALUETYPE:
1111 case MONO_TYPE_GENERICINST:
1112 #if SIZEOF_VOID_P == 8
1113 case MONO_TYPE_I8:
1114 case MONO_TYPE_U8:
1115 #endif
1116 margs->ilen++;
1117 break;
1118 #if SIZEOF_VOID_P == 4
1119 case MONO_TYPE_I8:
1120 case MONO_TYPE_U8:
1121 #ifdef TARGET_ARM
1122 /* pairs begin at even registers */
1123 if (i8_align == 8 && margs->ilen & 1)
1124 margs->ilen++;
1125 #endif
1126 margs->ilen += 2;
1127 break;
1128 #endif
1129 case MONO_TYPE_R4:
1130 #if SIZEOF_VOID_P == 8
1131 case MONO_TYPE_R8:
1132 #endif
1133 margs->flen++;
1134 break;
1135 #if SIZEOF_VOID_P == 4
1136 case MONO_TYPE_R8:
1137 margs->flen += 2;
1138 break;
1139 #endif
1140 default:
1141 g_error ("build_args_from_sig: not implemented yet (1): 0x%x\n", ptype);
1145 if (margs->ilen > 0)
1146 margs->iargs = g_malloc0 (sizeof (gpointer) * margs->ilen);
1148 if (margs->flen > 0)
1149 margs->fargs = g_malloc0 (sizeof (double) * margs->flen);
1151 if (margs->ilen > INTERP_ICALL_TRAMP_IARGS)
1152 g_error ("build_args_from_sig: TODO, allocate gregs: %d\n", margs->ilen);
1154 if (margs->flen > INTERP_ICALL_TRAMP_FARGS)
1155 g_error ("build_args_from_sig: TODO, allocate fregs: %d\n", margs->flen);
1158 size_t int_i = 0;
1159 size_t int_f = 0;
1161 if (sig->hasthis) {
1162 margs->iargs [0] = frame->stack_args->data.p;
1163 int_i++;
1166 for (int i = 0; i < sig->param_count; i++) {
1167 guint32 ptype = sig->params [i]->byref ? MONO_TYPE_PTR : sig->params [i]->type;
1168 switch (ptype) {
1169 case MONO_TYPE_BOOLEAN:
1170 case MONO_TYPE_CHAR:
1171 case MONO_TYPE_I1:
1172 case MONO_TYPE_U1:
1173 case MONO_TYPE_I2:
1174 case MONO_TYPE_U2:
1175 case MONO_TYPE_I4:
1176 case MONO_TYPE_U4:
1177 case MONO_TYPE_I:
1178 case MONO_TYPE_U:
1179 case MONO_TYPE_PTR:
1180 case MONO_TYPE_SZARRAY:
1181 case MONO_TYPE_CLASS:
1182 case MONO_TYPE_OBJECT:
1183 case MONO_TYPE_STRING:
1184 case MONO_TYPE_VALUETYPE:
1185 case MONO_TYPE_GENERICINST:
1186 #if SIZEOF_VOID_P == 8
1187 case MONO_TYPE_I8:
1188 case MONO_TYPE_U8:
1189 #endif
1190 margs->iargs [int_i] = frame->stack_args [i].data.p;
1191 #if DEBUG_INTERP
1192 g_print ("build_args_from_sig: margs->iargs [%d]: %p (frame @ %d)\n", int_i, margs->iargs [int_i], i);
1193 #endif
1194 int_i++;
1195 break;
1196 #if SIZEOF_VOID_P == 4
1197 case MONO_TYPE_I8:
1198 case MONO_TYPE_U8: {
1199 stackval *sarg = &frame->stack_args [i];
1200 #ifdef TARGET_ARM
1201 /* pairs begin at even registers */
1202 if (i8_align == 8 && int_i & 1)
1203 int_i++;
1204 #endif
1205 margs->iargs [int_i] = (gpointer) sarg->data.pair.lo;
1206 int_i++;
1207 margs->iargs [int_i] = (gpointer) sarg->data.pair.hi;
1208 #if DEBUG_INTERP
1209 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);
1210 #endif
1211 int_i++;
1212 break;
1214 #endif
1215 case MONO_TYPE_R4:
1216 case MONO_TYPE_R8:
1217 if (ptype == MONO_TYPE_R4)
1218 * (float *) &(margs->fargs [int_f]) = frame->stack_args [i].data.f_r4;
1219 else
1220 margs->fargs [int_f] = frame->stack_args [i].data.f;
1221 #if DEBUG_INTERP
1222 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);
1223 #endif
1224 #if SIZEOF_VOID_P == 4
1225 int_f += 2;
1226 #else
1227 int_f++;
1228 #endif
1229 break;
1230 default:
1231 g_error ("build_args_from_sig: not implemented yet (2): 0x%x\n", ptype);
1235 switch (sig->ret->type) {
1236 case MONO_TYPE_BOOLEAN:
1237 case MONO_TYPE_CHAR:
1238 case MONO_TYPE_I1:
1239 case MONO_TYPE_U1:
1240 case MONO_TYPE_I2:
1241 case MONO_TYPE_U2:
1242 case MONO_TYPE_I4:
1243 case MONO_TYPE_U4:
1244 case MONO_TYPE_I:
1245 case MONO_TYPE_U:
1246 case MONO_TYPE_PTR:
1247 case MONO_TYPE_SZARRAY:
1248 case MONO_TYPE_CLASS:
1249 case MONO_TYPE_OBJECT:
1250 case MONO_TYPE_STRING:
1251 case MONO_TYPE_I8:
1252 case MONO_TYPE_U8:
1253 case MONO_TYPE_VALUETYPE:
1254 case MONO_TYPE_GENERICINST:
1255 margs->retval = &(frame->retval->data.p);
1256 margs->is_float_ret = 0;
1257 break;
1258 case MONO_TYPE_R4:
1259 case MONO_TYPE_R8:
1260 margs->retval = &(frame->retval->data.p);
1261 margs->is_float_ret = 1;
1262 break;
1263 case MONO_TYPE_VOID:
1264 margs->retval = NULL;
1265 break;
1266 default:
1267 g_error ("build_args_from_sig: ret type not implemented yet: 0x%x\n", sig->ret->type);
1270 return margs;
1272 #endif
1274 static void
1275 interp_frame_arg_to_data (MonoInterpFrameHandle frame, MonoMethodSignature *sig, int index, gpointer data)
1277 InterpFrame *iframe = (InterpFrame*)frame;
1279 if (index == -1)
1280 stackval_to_data (sig->ret, iframe->retval, data, sig->pinvoke);
1281 else
1282 stackval_to_data (sig->params [index], &iframe->stack_args [index], data, sig->pinvoke);
1285 static void
1286 interp_data_to_frame_arg (MonoInterpFrameHandle frame, MonoMethodSignature *sig, int index, gpointer data)
1288 InterpFrame *iframe = (InterpFrame*)frame;
1290 if (index == -1)
1291 stackval_from_data (sig->ret, iframe->retval, data, sig->pinvoke);
1292 else if (sig->hasthis && index == 0)
1293 iframe->stack_args [index].data.p = *(gpointer*)data;
1294 else
1295 stackval_from_data (sig->params [index - sig->hasthis], &iframe->stack_args [index], data, sig->pinvoke);
1298 static gpointer
1299 interp_frame_arg_to_storage (MonoInterpFrameHandle frame, MonoMethodSignature *sig, int index)
1301 InterpFrame *iframe = (InterpFrame*)frame;
1303 if (index == -1)
1304 return stackval_to_data_addr (sig->ret, iframe->retval);
1305 else
1306 return stackval_to_data_addr (sig->params [index], &iframe->stack_args [index]);
1309 static void
1310 interp_frame_arg_set_storage (MonoInterpFrameHandle frame, MonoMethodSignature *sig, int index, gpointer storage)
1312 InterpFrame *iframe = (InterpFrame*)frame;
1313 stackval *val = (index == -1) ? iframe->retval : &iframe->stack_args [index];
1314 MonoType *type = (index == -1) ? sig->ret : sig->params [index];
1316 switch (type->type) {
1317 case MONO_TYPE_GENERICINST:
1318 if (!MONO_TYPE_IS_REFERENCE (type))
1319 val->data.vt = storage;
1320 break;
1321 case MONO_TYPE_VALUETYPE:
1322 val->data.vt = storage;
1323 break;
1324 default:
1325 g_assert_not_reached ();
1329 static MonoPIFunc
1330 get_interp_to_native_trampoline (void)
1332 static MonoPIFunc trampoline = NULL;
1334 if (!trampoline) {
1335 if (mono_ee_features.use_aot_trampolines) {
1336 trampoline = (MonoPIFunc) mono_aot_get_trampoline ("interp_to_native_trampoline");
1337 } else {
1338 MonoTrampInfo *info;
1339 trampoline = (MonoPIFunc) mono_arch_get_interp_to_native_trampoline (&info);
1340 // TODO:
1341 // mono_tramp_info_register (info, NULL);
1343 mono_memory_barrier ();
1345 return trampoline;
1348 static void
1349 interp_to_native_trampoline (gpointer addr, gpointer ccontext)
1351 get_interp_to_native_trampoline () (addr, ccontext);
1354 /* MONO_NO_OPTIMIATION is needed due to usage of INTERP_PUSH_LMF_WITH_CTX. */
1355 static MONO_NO_OPTIMIZATION MONO_NEVER_INLINE void
1356 ves_pinvoke_method (InterpFrame *frame, MonoMethodSignature *sig, MonoFuncV addr, gboolean string_ctor, ThreadContext *context)
1358 MonoLMFExt ext;
1359 gpointer args;
1361 frame->ex = NULL;
1363 g_assert (!frame->imethod);
1365 static MonoPIFunc entry_func = NULL;
1366 if (!entry_func) {
1367 #ifdef MONO_ARCH_HAS_NO_PROPER_MONOCTX
1368 ERROR_DECL (error);
1369 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);
1370 mono_error_assert_ok (error);
1371 #else
1372 entry_func = get_interp_to_native_trampoline ();
1373 #endif
1374 mono_memory_barrier ();
1377 #ifdef MONO_ARCH_HAVE_INTERP_PINVOKE_TRAMP
1378 CallContext ccontext;
1379 mono_arch_set_native_call_context_args (&ccontext, frame, sig);
1380 args = &ccontext;
1381 #else
1382 InterpMethodArguments *margs = build_args_from_sig (sig, frame);
1383 args = margs;
1384 #endif
1386 INTERP_PUSH_LMF_WITH_CTX (frame, ext, &&exit_pinvoke);
1387 entry_func ((gpointer) addr, args);
1388 interp_pop_lmf (&ext);
1390 #ifdef MONO_ARCH_HAVE_INTERP_PINVOKE_TRAMP
1391 if (!frame->ex)
1392 mono_arch_get_native_call_context_ret (&ccontext, frame, sig);
1393 #else
1394 if (!frame->ex && !MONO_TYPE_ISSTRUCT (sig->ret))
1395 stackval_from_data (sig->ret, frame->retval, (char*)&frame->retval->data.p, sig->pinvoke);
1397 g_free (margs->iargs);
1398 g_free (margs->fargs);
1399 g_free (margs);
1400 #endif
1401 goto exit_pinvoke; // prevent unused label warning in some configurations
1402 exit_pinvoke:
1403 return;
1407 * interp_init_delegate:
1409 * Initialize del->interp_method.
1411 static void
1412 interp_init_delegate (MonoDelegate *del)
1414 MonoMethod *method;
1415 ERROR_DECL (error);
1417 if (del->interp_method) {
1418 /* Delegate created by a call to ves_icall_mono_delegate_ctor_interp () */
1419 del->method = ((InterpMethod *)del->interp_method)->method;
1420 } else if (del->method) {
1421 /* Delegate created dynamically */
1422 del->interp_method = mono_interp_get_imethod (del->object.vtable->domain, del->method, error);
1423 } else {
1424 /* Created from JITted code */
1425 g_assert (del->method_ptr);
1426 del->interp_method = lookup_method_pointer (del->method_ptr);
1427 g_assert (del->interp_method);
1430 method = ((InterpMethod*)del->interp_method)->method;
1431 if (del->target &&
1432 method &&
1433 method->flags & METHOD_ATTRIBUTE_VIRTUAL &&
1434 method->flags & METHOD_ATTRIBUTE_ABSTRACT &&
1435 mono_class_is_abstract (method->klass))
1436 del->interp_method = get_virtual_method ((InterpMethod*)del->interp_method, del->target);
1438 method = ((InterpMethod*)del->interp_method)->method;
1439 if (method && m_class_get_parent (method->klass) == mono_defaults.multicastdelegate_class) {
1440 const char *name = method->name;
1441 if (*name == 'I' && (strcmp (name, "Invoke") == 0)) {
1443 * When invoking the delegate interp_method is executed directly. If it's an
1444 * invoke make sure we replace it with the appropriate delegate invoke wrapper.
1446 * FIXME We should do this later, when we also know the delegate on which the
1447 * target method is called.
1449 del->interp_method = mono_interp_get_imethod (del->object.vtable->domain, mono_marshal_get_delegate_invoke (method, NULL), error);
1450 mono_error_assert_ok (error);
1455 static void
1456 interp_delegate_ctor (MonoObjectHandle this_obj, MonoObjectHandle target, gpointer addr, MonoError *error)
1459 * addr is the result of an LDFTN opcode, i.e. an InterpMethod
1461 InterpMethod *imethod = (InterpMethod*)addr;
1463 if (!(imethod->method->flags & METHOD_ATTRIBUTE_STATIC)) {
1464 MonoMethod *invoke = mono_get_delegate_invoke_internal (mono_handle_class (this_obj));
1465 /* virtual invoke delegates must not have null check */
1466 if (mono_method_signature_internal (imethod->method)->param_count == mono_method_signature_internal (invoke)->param_count
1467 && MONO_HANDLE_IS_NULL (target)) {
1468 mono_error_set_argument (error, "this", "Delegate to an instance method cannot have null 'this'");
1469 return;
1473 g_assert (imethod->method);
1474 gpointer entry = mini_get_interp_callbacks ()->create_method_pointer (imethod->method, FALSE, error);
1475 return_if_nok (error);
1477 MONO_HANDLE_SETVAL (MONO_HANDLE_CAST (MonoDelegate, this_obj), interp_method, gpointer, imethod);
1479 mono_delegate_ctor (this_obj, target, entry, error);
1483 * From the spec:
1484 * runtime specifies that the implementation of the method is automatically
1485 * provided by the runtime and is primarily used for the methods of delegates.
1487 static MONO_NEVER_INLINE void
1488 ves_imethod (InterpFrame *frame, MonoMethod *method, MonoMethodSignature *sig, stackval *sp, stackval *retval)
1490 const char *name = method->name;
1491 mono_class_init_internal (method->klass);
1493 if (method->klass == mono_defaults.array_class) {
1494 if (!strcmp (name, "UnsafeMov")) {
1495 /* TODO: layout checks */
1496 stackval_from_data (sig->ret, retval, (char*) sp, FALSE);
1497 return;
1499 if (!strcmp (name, "UnsafeLoad")) {
1500 ves_array_get (frame, sp, retval, sig, FALSE);
1501 return;
1503 } else if (mini_class_is_system_array (method->klass)) {
1504 MonoObject *obj = (MonoObject*) sp->data.p;
1505 if (!obj) {
1506 frame->ex = mono_get_exception_null_reference ();
1507 FILL_IN_TRACE (frame->ex, frame);
1508 return;
1510 if (*name == 'S' && (strcmp (name, "Set") == 0)) {
1511 ves_array_set (frame, sp, sig);
1512 return;
1514 if (*name == 'G' && (strcmp (name, "Get") == 0)) {
1515 ves_array_get (frame, sp, retval, sig, TRUE);
1516 return;
1520 g_error ("Don't know how to exec runtime method %s.%s::%s",
1521 m_class_get_name_space (method->klass), m_class_get_name (method->klass),
1522 method->name);
1525 #if DEBUG_INTERP
1526 static char*
1527 dump_stack (stackval *stack, stackval *sp)
1529 stackval *s = stack;
1530 GString *str = g_string_new ("");
1532 if (sp == stack)
1533 return g_string_free (str, FALSE);
1535 while (s < sp) {
1536 g_string_append_printf (str, "[%p (%lld)] ", s->data.l, s->data.l);
1537 ++s;
1539 return g_string_free (str, FALSE);
1541 #endif
1543 static void
1544 dump_stackval (GString *str, stackval *s, MonoType *type)
1546 switch (type->type) {
1547 case MONO_TYPE_I1:
1548 case MONO_TYPE_U1:
1549 case MONO_TYPE_I2:
1550 case MONO_TYPE_U2:
1551 case MONO_TYPE_I4:
1552 case MONO_TYPE_U4:
1553 case MONO_TYPE_CHAR:
1554 case MONO_TYPE_BOOLEAN:
1555 g_string_append_printf (str, "[%d] ", s->data.i);
1556 break;
1557 case MONO_TYPE_STRING:
1558 case MONO_TYPE_SZARRAY:
1559 case MONO_TYPE_CLASS:
1560 case MONO_TYPE_OBJECT:
1561 case MONO_TYPE_ARRAY:
1562 case MONO_TYPE_PTR:
1563 case MONO_TYPE_I:
1564 case MONO_TYPE_U:
1565 g_string_append_printf (str, "[%p] ", s->data.p);
1566 break;
1567 case MONO_TYPE_VALUETYPE:
1568 if (m_class_is_enumtype (type->data.klass))
1569 g_string_append_printf (str, "[%d] ", s->data.i);
1570 else
1571 g_string_append_printf (str, "[vt:%p] ", s->data.p);
1572 break;
1573 case MONO_TYPE_R4:
1574 g_string_append_printf (str, "[%g] ", s->data.f_r4);
1575 break;
1576 case MONO_TYPE_R8:
1577 g_string_append_printf (str, "[%g] ", s->data.f);
1578 break;
1579 case MONO_TYPE_I8:
1580 case MONO_TYPE_U8:
1581 default: {
1582 GString *res = g_string_new ("");
1583 mono_type_get_desc (res, type, TRUE);
1584 g_string_append_printf (str, "[{%s} %lld/0x%0llx] ", res->str, s->data.l, s->data.l);
1585 g_string_free (res, TRUE);
1586 break;
1591 #if DEBUG_INTERP
1592 static char*
1593 dump_retval (InterpFrame *inv)
1595 GString *str = g_string_new ("");
1596 MonoType *ret = mono_method_signature_internal (inv->imethod->method)->ret;
1598 if (ret->type != MONO_TYPE_VOID)
1599 dump_stackval (str, inv->retval, ret);
1601 return g_string_free (str, FALSE);
1603 #endif
1605 static char*
1606 dump_args (InterpFrame *inv)
1608 GString *str = g_string_new ("");
1609 int i;
1610 MonoMethodSignature *signature = mono_method_signature_internal (inv->imethod->method);
1612 if (signature->param_count == 0 && !signature->hasthis)
1613 return g_string_free (str, FALSE);
1615 if (signature->hasthis) {
1616 MonoMethod *method = inv->imethod->method;
1617 dump_stackval (str, inv->stack_args, m_class_get_byval_arg (method->klass));
1620 for (i = 0; i < signature->param_count; ++i)
1621 dump_stackval (str, inv->stack_args + (!!signature->hasthis) + i, signature->params [i]);
1623 return g_string_free (str, FALSE);
1626 static char*
1627 dump_frame (InterpFrame *inv)
1629 GString *str = g_string_new ("");
1630 int i;
1631 char *args;
1632 ERROR_DECL (error);
1634 for (i = 0; inv; inv = inv->parent) {
1635 if (inv->imethod != NULL) {
1636 MonoMethod *method = inv->imethod->method;
1638 int codep = 0;
1639 const char * opname = "";
1640 char *name;
1641 gchar *source = NULL;
1643 if ((method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) == 0 &&
1644 (method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) == 0) {
1645 MonoMethodHeader *hd = mono_method_get_header_checked (method, error);
1646 mono_error_cleanup (error); /* FIXME: don't swallow the error */
1648 if (hd != NULL) {
1649 if (inv->ip) {
1650 opname = mono_interp_opname [*inv->ip];
1651 codep = inv->ip - inv->imethod->code;
1652 source = g_strdup_printf ("%s:%d // (TODO: proper stacktrace)", method->name, codep);
1653 } else
1654 opname = "";
1656 #if 0
1657 MonoDebugSourceLocation *minfo = mono_debug_lookup_method (method);
1658 source = mono_debug_method_lookup_location (minfo, codep);
1659 #endif
1660 mono_metadata_free_mh (hd);
1663 args = dump_args (inv);
1664 name = mono_method_full_name (method, TRUE);
1665 if (source)
1666 g_string_append_printf (str, "#%d: 0x%05x %-10s in %s (%s) at %s\n", i, codep, opname, name, args, source);
1667 else
1668 g_string_append_printf (str, "#%d: 0x%05x %-10s in %s (%s)\n", i, codep, opname, name, args);
1669 g_free (name);
1670 g_free (args);
1671 g_free (source);
1672 ++i;
1675 return g_string_free (str, FALSE);
1678 static MonoArray *
1679 get_trace_ips (MonoDomain *domain, InterpFrame *top)
1681 int i;
1682 MonoArray *res;
1683 InterpFrame *inv;
1684 ERROR_DECL (error);
1686 for (i = 0, inv = top; inv; inv = inv->parent)
1687 if (inv->imethod != NULL)
1688 ++i;
1690 res = mono_array_new_checked (domain, mono_defaults.int_class, 3 * i, error);
1691 mono_error_cleanup (error); /* FIXME: don't swallow the error */
1693 for (i = 0, inv = top; inv; inv = inv->parent)
1694 if (inv->imethod != NULL) {
1695 mono_array_set_fast (res, gpointer, i, inv->imethod);
1696 ++i;
1697 mono_array_set_fast (res, gpointer, i, (gpointer)inv->ip);
1698 ++i;
1699 mono_array_set_fast (res, gpointer, i, NULL);
1700 ++i;
1703 return res;
1706 #define CHECK_ADD_OVERFLOW(a,b) \
1707 (gint32)(b) >= 0 ? (gint32)(G_MAXINT32) - (gint32)(b) < (gint32)(a) ? -1 : 0 \
1708 : (gint32)(G_MININT32) - (gint32)(b) > (gint32)(a) ? +1 : 0
1710 #define CHECK_SUB_OVERFLOW(a,b) \
1711 (gint32)(b) < 0 ? (gint32)(G_MAXINT32) + (gint32)(b) < (gint32)(a) ? -1 : 0 \
1712 : (gint32)(G_MININT32) + (gint32)(b) > (gint32)(a) ? +1 : 0
1714 #define CHECK_ADD_OVERFLOW_UN(a,b) \
1715 (guint32)(G_MAXUINT32) - (guint32)(b) < (guint32)(a) ? -1 : 0
1717 #define CHECK_SUB_OVERFLOW_UN(a,b) \
1718 (guint32)(a) < (guint32)(b) ? -1 : 0
1720 #define CHECK_ADD_OVERFLOW64(a,b) \
1721 (gint64)(b) >= 0 ? (gint64)(G_MAXINT64) - (gint64)(b) < (gint64)(a) ? -1 : 0 \
1722 : (gint64)(G_MININT64) - (gint64)(b) > (gint64)(a) ? +1 : 0
1724 #define CHECK_SUB_OVERFLOW64(a,b) \
1725 (gint64)(b) < 0 ? (gint64)(G_MAXINT64) + (gint64)(b) < (gint64)(a) ? -1 : 0 \
1726 : (gint64)(G_MININT64) + (gint64)(b) > (gint64)(a) ? +1 : 0
1728 #define CHECK_ADD_OVERFLOW64_UN(a,b) \
1729 (guint64)(G_MAXUINT64) - (guint64)(b) < (guint64)(a) ? -1 : 0
1731 #define CHECK_SUB_OVERFLOW64_UN(a,b) \
1732 (guint64)(a) < (guint64)(b) ? -1 : 0
1734 #if SIZEOF_VOID_P == 4
1735 #define CHECK_ADD_OVERFLOW_NAT(a,b) CHECK_ADD_OVERFLOW(a,b)
1736 #define CHECK_ADD_OVERFLOW_NAT_UN(a,b) CHECK_ADD_OVERFLOW_UN(a,b)
1737 #else
1738 #define CHECK_ADD_OVERFLOW_NAT(a,b) CHECK_ADD_OVERFLOW64(a,b)
1739 #define CHECK_ADD_OVERFLOW_NAT_UN(a,b) CHECK_ADD_OVERFLOW64_UN(a,b)
1740 #endif
1742 /* Resolves to TRUE if the operands would overflow */
1743 #define CHECK_MUL_OVERFLOW(a,b) \
1744 ((gint32)(a) == 0) || ((gint32)(b) == 0) ? 0 : \
1745 (((gint32)(a) > 0) && ((gint32)(b) == -1)) ? FALSE : \
1746 (((gint32)(a) < 0) && ((gint32)(b) == -1)) ? (a == G_MININT32) : \
1747 (((gint32)(a) > 0) && ((gint32)(b) > 0)) ? (gint32)(a) > ((G_MAXINT32) / (gint32)(b)) : \
1748 (((gint32)(a) > 0) && ((gint32)(b) < 0)) ? (gint32)(a) > ((G_MININT32) / (gint32)(b)) : \
1749 (((gint32)(a) < 0) && ((gint32)(b) > 0)) ? (gint32)(a) < ((G_MININT32) / (gint32)(b)) : \
1750 (gint32)(a) < ((G_MAXINT32) / (gint32)(b))
1752 #define CHECK_MUL_OVERFLOW_UN(a,b) \
1753 ((guint32)(a) == 0) || ((guint32)(b) == 0) ? 0 : \
1754 (guint32)(b) > ((G_MAXUINT32) / (guint32)(a))
1756 #define CHECK_MUL_OVERFLOW64(a,b) \
1757 ((gint64)(a) == 0) || ((gint64)(b) == 0) ? 0 : \
1758 (((gint64)(a) > 0) && ((gint64)(b) == -1)) ? FALSE : \
1759 (((gint64)(a) < 0) && ((gint64)(b) == -1)) ? (a == G_MININT64) : \
1760 (((gint64)(a) > 0) && ((gint64)(b) > 0)) ? (gint64)(a) > ((G_MAXINT64) / (gint64)(b)) : \
1761 (((gint64)(a) > 0) && ((gint64)(b) < 0)) ? (gint64)(a) > ((G_MININT64) / (gint64)(b)) : \
1762 (((gint64)(a) < 0) && ((gint64)(b) > 0)) ? (gint64)(a) < ((G_MININT64) / (gint64)(b)) : \
1763 (gint64)(a) < ((G_MAXINT64) / (gint64)(b))
1765 #define CHECK_MUL_OVERFLOW64_UN(a,b) \
1766 ((guint64)(a) == 0) || ((guint64)(b) == 0) ? 0 : \
1767 (guint64)(b) > ((G_MAXUINT64) / (guint64)(a))
1769 #if SIZEOF_VOID_P == 4
1770 #define CHECK_MUL_OVERFLOW_NAT(a,b) CHECK_MUL_OVERFLOW(a,b)
1771 #define CHECK_MUL_OVERFLOW_NAT_UN(a,b) CHECK_MUL_OVERFLOW_UN(a,b)
1772 #else
1773 #define CHECK_MUL_OVERFLOW_NAT(a,b) CHECK_MUL_OVERFLOW64(a,b)
1774 #define CHECK_MUL_OVERFLOW_NAT_UN(a,b) CHECK_MUL_OVERFLOW64_UN(a,b)
1775 #endif
1777 static MonoObject*
1778 interp_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError *error)
1780 InterpFrame frame;
1781 ThreadContext *context = get_context ();
1782 MonoMethodSignature *sig = mono_method_signature_internal (method);
1783 MonoClass *klass = mono_class_from_mono_type_internal (sig->ret);
1784 stackval result;
1785 MonoMethod *target_method = method;
1787 error_init (error);
1788 if (exc)
1789 *exc = NULL;
1791 frame.ex = NULL;
1793 MonoDomain *domain = mono_domain_get ();
1795 if (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
1796 target_method = mono_marshal_get_native_wrapper (target_method, FALSE, FALSE);
1797 MonoMethod *invoke_wrapper = mono_marshal_get_runtime_invoke_full (target_method, FALSE, TRUE);
1799 //* <code>MonoObject *runtime_invoke (MonoObject *this_obj, void **params, MonoObject **exc, void* method)</code>
1801 result.data.vt = alloca (mono_class_instance_size (klass));
1802 stackval args [4];
1804 if (sig->hasthis)
1805 args [0].data.p = obj;
1806 else
1807 args [0].data.p = NULL;
1808 args [1].data.p = params;
1809 args [2].data.p = exc;
1810 args [3].data.p = target_method;
1812 INIT_FRAME (&frame, NULL, args, &result, domain, invoke_wrapper, error);
1814 if (exc)
1815 frame.invoke_trap = 1;
1817 interp_exec_method (&frame, context);
1819 if (frame.ex) {
1820 if (exc) {
1821 *exc = (MonoObject*) frame.ex;
1822 return NULL;
1824 mono_error_set_exception_instance (error, frame.ex);
1825 return NULL;
1827 return (MonoObject*)result.data.p;
1830 typedef struct {
1831 InterpMethod *rmethod;
1832 gpointer this_arg;
1833 gpointer res;
1834 gpointer args [16];
1835 gpointer *many_args;
1836 } InterpEntryData;
1838 /* Main function for entering the interpreter from compiled code */
1839 static void
1840 interp_entry (InterpEntryData *data)
1842 InterpFrame frame;
1843 InterpMethod *rmethod;
1844 ThreadContext *context;
1845 stackval result;
1846 stackval *args;
1847 MonoMethod *method;
1848 MonoMethodSignature *sig;
1849 MonoType *type;
1850 gpointer orig_domain, attach_cookie;
1851 int i;
1853 if ((gsize)data->rmethod & 1) {
1854 /* Unbox */
1855 data->this_arg = mono_object_unbox_internal ((MonoObject*)data->this_arg);
1856 data->rmethod = (InterpMethod*)(gpointer)((gsize)data->rmethod & ~1);
1858 rmethod = data->rmethod;
1860 if (rmethod->needs_thread_attach)
1861 orig_domain = mono_threads_attach_coop (mono_domain_get (), &attach_cookie);
1863 context = get_context ();
1865 method = rmethod->method;
1866 sig = mono_method_signature_internal (method);
1868 // FIXME: Optimize this
1870 //printf ("%s\n", mono_method_full_name (method, 1));
1872 frame.ex = NULL;
1874 args = g_newa (stackval, sig->param_count + (sig->hasthis ? 1 : 0));
1875 if (sig->hasthis)
1876 args [0].data.p = data->this_arg;
1878 gpointer *params;
1879 if (data->many_args)
1880 params = data->many_args;
1881 else
1882 params = data->args;
1883 for (i = 0; i < sig->param_count; ++i) {
1884 int a_index = i + (sig->hasthis ? 1 : 0);
1885 if (sig->params [i]->byref) {
1886 args [a_index].data.p = params [i];
1887 continue;
1889 type = rmethod->param_types [i];
1890 switch (type->type) {
1891 case MONO_TYPE_VALUETYPE:
1892 args [a_index].data.p = params [i];
1893 break;
1894 case MONO_TYPE_GENERICINST:
1895 if (MONO_TYPE_IS_REFERENCE (type))
1896 args [a_index].data.p = *(gpointer*)params [i];
1897 else
1898 args [a_index].data.vt = params [i];
1899 break;
1900 default:
1901 stackval_from_data (type, &args [a_index], params [i], FALSE);
1902 break;
1906 memset (&result, 0, sizeof (result));
1907 init_frame (&frame, NULL, data->rmethod, args, &result);
1909 type = rmethod->rtype;
1910 switch (type->type) {
1911 case MONO_TYPE_GENERICINST:
1912 if (!MONO_TYPE_IS_REFERENCE (type))
1913 frame.retval->data.vt = data->res;
1914 break;
1915 case MONO_TYPE_VALUETYPE:
1916 frame.retval->data.vt = data->res;
1917 break;
1918 default:
1919 break;
1922 interp_exec_method (&frame, context);
1924 if (rmethod->needs_thread_attach)
1925 mono_threads_detach_coop (orig_domain, &attach_cookie);
1927 // FIXME:
1928 g_assert (frame.ex == NULL);
1930 type = rmethod->rtype;
1931 switch (type->type) {
1932 case MONO_TYPE_VOID:
1933 break;
1934 case MONO_TYPE_OBJECT:
1935 /* No need for a write barrier */
1936 *(MonoObject**)data->res = (MonoObject*)frame.retval->data.p;
1937 break;
1938 case MONO_TYPE_GENERICINST:
1939 if (MONO_TYPE_IS_REFERENCE (type)) {
1940 *(MonoObject**)data->res = (MonoObject*)frame.retval->data.p;
1941 } else {
1942 /* Already set before the call */
1944 break;
1945 case MONO_TYPE_VALUETYPE:
1946 /* Already set before the call */
1947 break;
1948 default:
1949 stackval_to_data (type, frame.retval, data->res, FALSE);
1950 break;
1954 /* MONO_NO_OPTIMIATION is needed due to usage of INTERP_PUSH_LMF_WITH_CTX. */
1955 static MONO_NO_OPTIMIZATION MONO_NEVER_INLINE stackval *
1956 do_icall (InterpFrame *frame, MonoMethodSignature *sig, int op, stackval *sp, gpointer ptr)
1958 MonoLMFExt ext;
1959 INTERP_PUSH_LMF_WITH_CTX (frame, ext, &&exit_icall);
1961 switch (op) {
1962 case MINT_ICALL_V_V: {
1963 typedef void (*T)(void);
1964 T func = (T)ptr;
1965 func ();
1966 break;
1968 case MINT_ICALL_V_P: {
1969 typedef gpointer (*T)(void);
1970 T func = (T)ptr;
1971 sp++;
1972 sp [-1].data.p = func ();
1973 break;
1975 case MINT_ICALL_P_V: {
1976 typedef void (*T)(gpointer);
1977 T func = (T)ptr;
1978 func (sp [-1].data.p);
1979 sp --;
1980 break;
1982 case MINT_ICALL_P_P: {
1983 typedef gpointer (*T)(gpointer);
1984 T func = (T)ptr;
1985 sp [-1].data.p = func (sp [-1].data.p);
1986 break;
1988 case MINT_ICALL_PP_V: {
1989 typedef void (*T)(gpointer,gpointer);
1990 T func = (T)ptr;
1991 sp -= 2;
1992 func (sp [0].data.p, sp [1].data.p);
1993 break;
1995 case MINT_ICALL_PP_P: {
1996 typedef gpointer (*T)(gpointer,gpointer);
1997 T func = (T)ptr;
1998 --sp;
1999 sp [-1].data.p = func (sp [-1].data.p, sp [0].data.p);
2000 break;
2002 case MINT_ICALL_PPP_V: {
2003 typedef void (*T)(gpointer,gpointer,gpointer);
2004 T func = (T)ptr;
2005 sp -= 3;
2006 func (sp [0].data.p, sp [1].data.p, sp [2].data.p);
2007 break;
2009 case MINT_ICALL_PPP_P: {
2010 typedef gpointer (*T)(gpointer,gpointer,gpointer);
2011 T func = (T)ptr;
2012 sp -= 2;
2013 sp [-1].data.p = func (sp [-1].data.p, sp [0].data.p, sp [1].data.p);
2014 break;
2016 case MINT_ICALL_PPPP_V: {
2017 typedef void (*T)(gpointer,gpointer,gpointer,gpointer);
2018 T func = (T)ptr;
2019 sp -= 4;
2020 func (sp [0].data.p, sp [1].data.p, sp [2].data.p, sp [3].data.p);
2021 break;
2023 case MINT_ICALL_PPPP_P: {
2024 typedef gpointer (*T)(gpointer,gpointer,gpointer,gpointer);
2025 T func = (T)ptr;
2026 sp -= 3;
2027 sp [-1].data.p = func (sp [-1].data.p, sp [0].data.p, sp [1].data.p, sp [2].data.p);
2028 break;
2030 case MINT_ICALL_PPPPP_V: {
2031 typedef void (*T)(gpointer,gpointer,gpointer,gpointer,gpointer);
2032 T func = (T)ptr;
2033 sp -= 5;
2034 func (sp [0].data.p, sp [1].data.p, sp [2].data.p, sp [3].data.p, sp [4].data.p);
2035 break;
2037 case MINT_ICALL_PPPPP_P: {
2038 typedef gpointer (*T)(gpointer,gpointer,gpointer,gpointer,gpointer);
2039 T func = (T)ptr;
2040 sp -= 4;
2041 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);
2042 break;
2044 case MINT_ICALL_PPPPPP_V: {
2045 typedef void (*T)(gpointer,gpointer,gpointer,gpointer,gpointer,gpointer);
2046 T func = (T)ptr;
2047 sp -= 6;
2048 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);
2049 break;
2051 case MINT_ICALL_PPPPPP_P: {
2052 typedef gpointer (*T)(gpointer,gpointer,gpointer,gpointer,gpointer,gpointer);
2053 T func = (T)ptr;
2054 sp -= 5;
2055 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);
2056 break;
2058 default:
2059 g_assert_not_reached ();
2062 /* convert the native representation to the stackval representation */
2063 if (sig)
2064 stackval_from_data (sig->ret, &sp [-1], (char*) &sp [-1].data.p, sig->pinvoke);
2066 interp_pop_lmf (&ext);
2068 goto exit_icall; // prevent unused label warning in some configurations
2069 exit_icall:
2070 return sp;
2073 typedef struct {
2074 int pindex;
2075 gpointer jit_wrapper;
2076 gpointer *args;
2077 MonoFtnDesc *ftndesc;
2078 } JitCallCbData;
2080 static void
2081 jit_call_cb (gpointer arg)
2083 JitCallCbData *cb_data = (JitCallCbData*)arg;
2084 gpointer jit_wrapper = cb_data->jit_wrapper;
2085 int pindex = cb_data->pindex;
2086 gpointer *args = cb_data->args;
2087 MonoFtnDesc ftndesc = *cb_data->ftndesc;
2089 switch (pindex) {
2090 case 0: {
2091 typedef void (*T)(gpointer);
2092 T func = (T)jit_wrapper;
2094 func (&ftndesc);
2095 break;
2097 case 1: {
2098 typedef void (*T)(gpointer, gpointer);
2099 T func = (T)jit_wrapper;
2101 func (args [0], &ftndesc);
2102 break;
2104 case 2: {
2105 typedef void (*T)(gpointer, gpointer, gpointer);
2106 T func = (T)jit_wrapper;
2108 func (args [0], args [1], &ftndesc);
2109 break;
2111 case 3: {
2112 typedef void (*T)(gpointer, gpointer, gpointer, gpointer);
2113 T func = (T)jit_wrapper;
2115 func (args [0], args [1], args [2], &ftndesc);
2116 break;
2118 case 4: {
2119 typedef void (*T)(gpointer, gpointer, gpointer, gpointer, gpointer);
2120 T func = (T)jit_wrapper;
2122 func (args [0], args [1], args [2], args [3], &ftndesc);
2123 break;
2125 case 5: {
2126 typedef void (*T)(gpointer, gpointer, gpointer, gpointer, gpointer, gpointer);
2127 T func = (T)jit_wrapper;
2129 func (args [0], args [1], args [2], args [3], args [4], &ftndesc);
2130 break;
2132 case 6: {
2133 typedef void (*T)(gpointer, gpointer, gpointer, gpointer, gpointer, gpointer, gpointer);
2134 T func = (T)jit_wrapper;
2136 func (args [0], args [1], args [2], args [3], args [4], args [5], &ftndesc);
2137 break;
2139 case 7: {
2140 typedef void (*T)(gpointer, gpointer, gpointer, gpointer, gpointer, gpointer, gpointer, gpointer);
2141 T func = (T)jit_wrapper;
2143 func (args [0], args [1], args [2], args [3], args [4], args [5], args [6], &ftndesc);
2144 break;
2146 case 8: {
2147 typedef void (*T)(gpointer, gpointer, gpointer, gpointer, gpointer, gpointer, gpointer, gpointer, gpointer);
2148 T func = (T)jit_wrapper;
2150 func (args [0], args [1], args [2], args [3], args [4], args [5], args [6], args [7], &ftndesc);
2151 break;
2153 default:
2154 g_assert_not_reached ();
2155 break;
2159 static MONO_NEVER_INLINE stackval *
2160 do_jit_call (stackval *sp, unsigned char *vt_sp, ThreadContext *context, InterpFrame *frame, InterpMethod *rmethod, MonoError *error)
2162 MonoMethodSignature *sig;
2163 MonoFtnDesc ftndesc;
2164 guint8 res_buf [256];
2165 MonoType *type;
2166 MonoLMFExt ext;
2168 //printf ("jit_call: %s\n", mono_method_full_name (rmethod->method, 1));
2171 * Call JITted code through a gsharedvt_out wrapper. These wrappers receive every argument
2172 * by ref and return a return value using an explicit return value argument.
2174 if (!rmethod->jit_wrapper) {
2175 MonoMethod *method = rmethod->method;
2177 sig = mono_method_signature_internal (method);
2178 g_assert (sig);
2180 MonoMethod *wrapper = mini_get_gsharedvt_out_sig_wrapper (sig);
2181 //printf ("J: %s %s\n", mono_method_full_name (method, 1), mono_method_full_name (wrapper, 1));
2183 gpointer jit_wrapper = mono_jit_compile_method_jit_only (wrapper, error);
2184 mono_error_assert_ok (error);
2186 gpointer addr = mono_jit_compile_method_jit_only (method, error);
2187 return_val_if_nok (error, NULL);
2188 g_assert (addr);
2190 rmethod->jit_addr = addr;
2191 rmethod->jit_sig = sig;
2192 mono_memory_barrier ();
2193 rmethod->jit_wrapper = jit_wrapper;
2195 } else {
2196 sig = rmethod->jit_sig;
2199 sp -= sig->param_count;
2200 if (sig->hasthis)
2201 --sp;
2203 ftndesc.addr = rmethod->jit_addr;
2204 ftndesc.arg = NULL;
2206 // FIXME: Optimize this
2208 gpointer args [32];
2209 int pindex = 0;
2210 int stack_index = 0;
2211 if (rmethod->hasthis) {
2212 args [pindex ++] = sp [0].data.p;
2213 stack_index ++;
2215 type = rmethod->rtype;
2216 if (type->type != MONO_TYPE_VOID) {
2217 if (MONO_TYPE_ISSTRUCT (type))
2218 args [pindex ++] = vt_sp;
2219 else
2220 args [pindex ++] = res_buf;
2222 for (int i = 0; i < rmethod->param_count; ++i) {
2223 MonoType *t = rmethod->param_types [i];
2224 stackval *sval = &sp [stack_index + i];
2225 if (sig->params [i]->byref) {
2226 args [pindex ++] = sval->data.p;
2227 } else if (MONO_TYPE_ISSTRUCT (t)) {
2228 args [pindex ++] = sval->data.p;
2229 } else if (MONO_TYPE_IS_REFERENCE (t)) {
2230 args [pindex ++] = &sval->data.p;
2231 } else {
2232 switch (t->type) {
2233 case MONO_TYPE_I1:
2234 case MONO_TYPE_U1:
2235 case MONO_TYPE_I2:
2236 case MONO_TYPE_U2:
2237 case MONO_TYPE_I4:
2238 case MONO_TYPE_U4:
2239 case MONO_TYPE_VALUETYPE:
2240 args [pindex ++] = &sval->data.i;
2241 break;
2242 case MONO_TYPE_PTR:
2243 case MONO_TYPE_FNPTR:
2244 case MONO_TYPE_I:
2245 case MONO_TYPE_U:
2246 case MONO_TYPE_OBJECT:
2247 args [pindex ++] = &sval->data.p;
2248 break;
2249 case MONO_TYPE_I8:
2250 case MONO_TYPE_U8:
2251 args [pindex ++] = &sval->data.l;
2252 break;
2253 case MONO_TYPE_R4:
2254 args [pindex ++] = &sval->data.f_r4;
2255 break;
2256 case MONO_TYPE_R8:
2257 args [pindex ++] = &sval->data.f;
2258 break;
2259 default:
2260 printf ("%s\n", mono_type_full_name (t));
2261 g_assert_not_reached ();
2266 interp_push_lmf (&ext, frame);
2268 JitCallCbData cb_data;
2269 memset (&cb_data, 0, sizeof (cb_data));
2270 cb_data.jit_wrapper = rmethod->jit_wrapper;
2271 cb_data.pindex = pindex;
2272 cb_data.args = args;
2273 cb_data.ftndesc = &ftndesc;
2275 if (mono_aot_mode == MONO_AOT_MODE_LLVMONLY_INTERP) {
2276 /* Catch the exception thrown by the native code using a try-catch */
2277 gboolean thrown = FALSE;
2278 mono_llvm_cpp_catch_exception (jit_call_cb, &cb_data, &thrown);
2279 interp_pop_lmf (&ext);
2280 if (thrown) {
2281 MonoObject *obj = mono_llvm_load_exception ();
2282 g_assert (obj);
2283 mono_error_set_exception_instance (error, (MonoException*)obj);
2284 return sp;
2286 } else {
2287 jit_call_cb (&cb_data);
2288 interp_pop_lmf (&ext);
2291 MonoType *rtype = rmethod->rtype;
2292 switch (rtype->type) {
2293 case MONO_TYPE_VOID:
2294 case MONO_TYPE_OBJECT:
2295 case MONO_TYPE_STRING:
2296 case MONO_TYPE_CLASS:
2297 case MONO_TYPE_ARRAY:
2298 case MONO_TYPE_SZARRAY:
2299 case MONO_TYPE_I:
2300 case MONO_TYPE_U:
2301 case MONO_TYPE_PTR:
2302 sp->data.p = *(gpointer*)res_buf;
2303 break;
2304 case MONO_TYPE_I1:
2305 sp->data.i = *(gint8*)res_buf;
2306 break;
2307 case MONO_TYPE_U1:
2308 sp->data.i = *(guint8*)res_buf;
2309 break;
2310 case MONO_TYPE_I2:
2311 sp->data.i = *(gint16*)res_buf;
2312 break;
2313 case MONO_TYPE_U2:
2314 sp->data.i = *(guint16*)res_buf;
2315 break;
2316 case MONO_TYPE_I4:
2317 sp->data.i = *(gint32*)res_buf;
2318 break;
2319 case MONO_TYPE_U4:
2320 sp->data.i = *(guint32*)res_buf;
2321 break;
2322 case MONO_TYPE_I8:
2323 sp->data.l = *(gint64*)res_buf;
2324 break;
2325 case MONO_TYPE_U8:
2326 sp->data.l = *(guint64*)res_buf;
2327 break;
2328 case MONO_TYPE_R4:
2329 sp->data.f_r4 = *(float*)res_buf;
2330 break;
2331 case MONO_TYPE_R8:
2332 sp->data.f = *(double*)res_buf;
2333 break;
2334 case MONO_TYPE_TYPEDBYREF:
2335 case MONO_TYPE_VALUETYPE:
2336 /* The result was written to vt_sp */
2337 sp->data.p = vt_sp;
2338 break;
2339 case MONO_TYPE_GENERICINST:
2340 if (MONO_TYPE_IS_REFERENCE (rtype)) {
2341 sp->data.p = *(gpointer*)res_buf;
2342 } else {
2343 /* The result was written to vt_sp */
2344 sp->data.p = vt_sp;
2346 break;
2347 default:
2348 g_print ("%s\n", mono_type_full_name (rtype));
2349 g_assert_not_reached ();
2350 break;
2353 return sp;
2356 static MONO_NEVER_INLINE void
2357 do_debugger_tramp (void (*tramp) (void), InterpFrame *frame)
2359 MonoLMFExt ext;
2360 interp_push_lmf (&ext, frame);
2361 tramp ();
2362 interp_pop_lmf (&ext);
2365 static MONO_NEVER_INLINE void
2366 do_transform_method (InterpFrame *frame, ThreadContext *context)
2368 MonoLMFExt ext;
2369 /* Don't push lmf if we have no interp data */
2370 gboolean push_lmf = frame->parent != NULL;
2371 ERROR_DECL (error);
2373 /* Use the parent frame as the current frame is not complete yet */
2374 if (push_lmf)
2375 interp_push_lmf (&ext, frame->parent);
2377 mono_interp_transform_method (frame->imethod, context, error);
2378 frame->ex = mono_error_convert_to_exception (error);
2380 if (push_lmf)
2381 interp_pop_lmf (&ext);
2384 static void
2385 copy_varargs_vtstack (MonoMethodSignature *csig, stackval *sp, unsigned char **vt_sp)
2387 char *vt = *(char**)vt_sp;
2388 stackval *first_arg = sp - csig->param_count;
2391 * We need to have the varargs linearly on the stack so the ArgIterator
2392 * can iterate over them. We pass the signature first and then copy them
2393 * one by one on the vtstack.
2395 *(gpointer*)vt = csig;
2396 vt += sizeof (gpointer);
2398 for (int i = csig->sentinelpos; i < csig->param_count; i++) {
2399 int align, arg_size;
2400 arg_size = mono_type_stack_size (csig->params [i], &align);
2401 vt = (char*)ALIGN_PTR_TO (vt, align);
2403 stackval_to_data (csig->params [i], &first_arg [i], vt, FALSE);
2404 vt += arg_size;
2407 vt = (char*)ALIGN_PTR_TO (vt, MINT_VT_ALIGNMENT);
2409 *(char**)vt_sp = vt;
2413 * These functions are the entry points into the interpreter from compiled code.
2414 * They are called by the interp_in wrappers. They have the following signature:
2415 * void (<optional this_arg>, <optional retval pointer>, <arg1>, ..., <argn>, <method ptr>)
2416 * They pack up their arguments into an InterpEntryData structure and call interp_entry ().
2417 * It would be possible for the wrappers to pack up the arguments etc, but that would make them bigger, and there are
2418 * more wrappers then these functions.
2419 * this/static * ret/void * 16 arguments -> 64 functions.
2422 #define MAX_INTERP_ENTRY_ARGS 8
2424 #define INTERP_ENTRY_BASE(_method, _this_arg, _res) \
2425 InterpEntryData data; \
2426 (data).rmethod = (_method); \
2427 (data).res = (_res); \
2428 (data).this_arg = (_this_arg); \
2429 (data).many_args = NULL;
2431 #define INTERP_ENTRY0(_this_arg, _res, _method) { \
2432 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2433 interp_entry (&data); \
2435 #define INTERP_ENTRY1(_this_arg, _res, _method) { \
2436 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2437 (data).args [0] = arg1; \
2438 interp_entry (&data); \
2440 #define INTERP_ENTRY2(_this_arg, _res, _method) { \
2441 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2442 (data).args [0] = arg1; \
2443 (data).args [1] = arg2; \
2444 interp_entry (&data); \
2446 #define INTERP_ENTRY3(_this_arg, _res, _method) { \
2447 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2448 (data).args [0] = arg1; \
2449 (data).args [1] = arg2; \
2450 (data).args [2] = arg3; \
2451 interp_entry (&data); \
2453 #define INTERP_ENTRY4(_this_arg, _res, _method) { \
2454 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2455 (data).args [0] = arg1; \
2456 (data).args [1] = arg2; \
2457 (data).args [2] = arg3; \
2458 (data).args [3] = arg4; \
2459 interp_entry (&data); \
2461 #define INTERP_ENTRY5(_this_arg, _res, _method) { \
2462 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2463 (data).args [0] = arg1; \
2464 (data).args [1] = arg2; \
2465 (data).args [2] = arg3; \
2466 (data).args [3] = arg4; \
2467 (data).args [4] = arg5; \
2468 interp_entry (&data); \
2470 #define INTERP_ENTRY6(_this_arg, _res, _method) { \
2471 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2472 (data).args [0] = arg1; \
2473 (data).args [1] = arg2; \
2474 (data).args [2] = arg3; \
2475 (data).args [3] = arg4; \
2476 (data).args [4] = arg5; \
2477 (data).args [5] = arg6; \
2478 interp_entry (&data); \
2480 #define INTERP_ENTRY7(_this_arg, _res, _method) { \
2481 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2482 (data).args [0] = arg1; \
2483 (data).args [1] = arg2; \
2484 (data).args [2] = arg3; \
2485 (data).args [3] = arg4; \
2486 (data).args [4] = arg5; \
2487 (data).args [5] = arg6; \
2488 (data).args [6] = arg7; \
2489 interp_entry (&data); \
2491 #define INTERP_ENTRY8(_this_arg, _res, _method) { \
2492 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2493 (data).args [0] = arg1; \
2494 (data).args [1] = arg2; \
2495 (data).args [2] = arg3; \
2496 (data).args [3] = arg4; \
2497 (data).args [4] = arg5; \
2498 (data).args [5] = arg6; \
2499 (data).args [6] = arg7; \
2500 (data).args [7] = arg8; \
2501 interp_entry (&data); \
2504 #define ARGLIST0 InterpMethod *rmethod
2505 #define ARGLIST1 gpointer arg1, InterpMethod *rmethod
2506 #define ARGLIST2 gpointer arg1, gpointer arg2, InterpMethod *rmethod
2507 #define ARGLIST3 gpointer arg1, gpointer arg2, gpointer arg3, InterpMethod *rmethod
2508 #define ARGLIST4 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, InterpMethod *rmethod
2509 #define ARGLIST5 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, gpointer arg5, InterpMethod *rmethod
2510 #define ARGLIST6 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, gpointer arg5, gpointer arg6, InterpMethod *rmethod
2511 #define ARGLIST7 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, gpointer arg5, gpointer arg6, gpointer arg7, InterpMethod *rmethod
2512 #define ARGLIST8 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, gpointer arg5, gpointer arg6, gpointer arg7, gpointer arg8, InterpMethod *rmethod
2514 static void interp_entry_static_0 (ARGLIST0) INTERP_ENTRY0 (NULL, NULL, rmethod)
2515 static void interp_entry_static_1 (ARGLIST1) INTERP_ENTRY1 (NULL, NULL, rmethod)
2516 static void interp_entry_static_2 (ARGLIST2) INTERP_ENTRY2 (NULL, NULL, rmethod)
2517 static void interp_entry_static_3 (ARGLIST3) INTERP_ENTRY3 (NULL, NULL, rmethod)
2518 static void interp_entry_static_4 (ARGLIST4) INTERP_ENTRY4 (NULL, NULL, rmethod)
2519 static void interp_entry_static_5 (ARGLIST5) INTERP_ENTRY5 (NULL, NULL, rmethod)
2520 static void interp_entry_static_6 (ARGLIST6) INTERP_ENTRY6 (NULL, NULL, rmethod)
2521 static void interp_entry_static_7 (ARGLIST7) INTERP_ENTRY7 (NULL, NULL, rmethod)
2522 static void interp_entry_static_8 (ARGLIST8) INTERP_ENTRY8 (NULL, NULL, rmethod)
2523 static void interp_entry_static_ret_0 (gpointer res, ARGLIST0) INTERP_ENTRY0 (NULL, res, rmethod)
2524 static void interp_entry_static_ret_1 (gpointer res, ARGLIST1) INTERP_ENTRY1 (NULL, res, rmethod)
2525 static void interp_entry_static_ret_2 (gpointer res, ARGLIST2) INTERP_ENTRY2 (NULL, res, rmethod)
2526 static void interp_entry_static_ret_3 (gpointer res, ARGLIST3) INTERP_ENTRY3 (NULL, res, rmethod)
2527 static void interp_entry_static_ret_4 (gpointer res, ARGLIST4) INTERP_ENTRY4 (NULL, res, rmethod)
2528 static void interp_entry_static_ret_5 (gpointer res, ARGLIST5) INTERP_ENTRY5 (NULL, res, rmethod)
2529 static void interp_entry_static_ret_6 (gpointer res, ARGLIST6) INTERP_ENTRY6 (NULL, res, rmethod)
2530 static void interp_entry_static_ret_7 (gpointer res, ARGLIST7) INTERP_ENTRY7 (NULL, res, rmethod)
2531 static void interp_entry_static_ret_8 (gpointer res, ARGLIST8) INTERP_ENTRY8 (NULL, res, rmethod)
2532 static void interp_entry_instance_0 (gpointer this_arg, ARGLIST0) INTERP_ENTRY0 (this_arg, NULL, rmethod)
2533 static void interp_entry_instance_1 (gpointer this_arg, ARGLIST1) INTERP_ENTRY1 (this_arg, NULL, rmethod)
2534 static void interp_entry_instance_2 (gpointer this_arg, ARGLIST2) INTERP_ENTRY2 (this_arg, NULL, rmethod)
2535 static void interp_entry_instance_3 (gpointer this_arg, ARGLIST3) INTERP_ENTRY3 (this_arg, NULL, rmethod)
2536 static void interp_entry_instance_4 (gpointer this_arg, ARGLIST4) INTERP_ENTRY4 (this_arg, NULL, rmethod)
2537 static void interp_entry_instance_5 (gpointer this_arg, ARGLIST5) INTERP_ENTRY5 (this_arg, NULL, rmethod)
2538 static void interp_entry_instance_6 (gpointer this_arg, ARGLIST6) INTERP_ENTRY6 (this_arg, NULL, rmethod)
2539 static void interp_entry_instance_7 (gpointer this_arg, ARGLIST7) INTERP_ENTRY7 (this_arg, NULL, rmethod)
2540 static void interp_entry_instance_8 (gpointer this_arg, ARGLIST8) INTERP_ENTRY8 (this_arg, NULL, rmethod)
2541 static void interp_entry_instance_ret_0 (gpointer this_arg, gpointer res, ARGLIST0) INTERP_ENTRY0 (this_arg, res, rmethod)
2542 static void interp_entry_instance_ret_1 (gpointer this_arg, gpointer res, ARGLIST1) INTERP_ENTRY1 (this_arg, res, rmethod)
2543 static void interp_entry_instance_ret_2 (gpointer this_arg, gpointer res, ARGLIST2) INTERP_ENTRY2 (this_arg, res, rmethod)
2544 static void interp_entry_instance_ret_3 (gpointer this_arg, gpointer res, ARGLIST3) INTERP_ENTRY3 (this_arg, res, rmethod)
2545 static void interp_entry_instance_ret_4 (gpointer this_arg, gpointer res, ARGLIST4) INTERP_ENTRY4 (this_arg, res, rmethod)
2546 static void interp_entry_instance_ret_5 (gpointer this_arg, gpointer res, ARGLIST5) INTERP_ENTRY5 (this_arg, res, rmethod)
2547 static void interp_entry_instance_ret_6 (gpointer this_arg, gpointer res, ARGLIST6) INTERP_ENTRY6 (this_arg, res, rmethod)
2548 static void interp_entry_instance_ret_7 (gpointer this_arg, gpointer res, ARGLIST7) INTERP_ENTRY7 (this_arg, res, rmethod)
2549 static void interp_entry_instance_ret_8 (gpointer this_arg, gpointer res, ARGLIST8) INTERP_ENTRY8 (this_arg, res, rmethod)
2551 #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
2553 static gpointer entry_funcs_static [MAX_INTERP_ENTRY_ARGS + 1] = { INTERP_ENTRY_FUNCLIST (static) };
2554 static gpointer entry_funcs_static_ret [MAX_INTERP_ENTRY_ARGS + 1] = { INTERP_ENTRY_FUNCLIST (static_ret) };
2555 static gpointer entry_funcs_instance [MAX_INTERP_ENTRY_ARGS + 1] = { INTERP_ENTRY_FUNCLIST (instance) };
2556 static gpointer entry_funcs_instance_ret [MAX_INTERP_ENTRY_ARGS + 1] = { INTERP_ENTRY_FUNCLIST (instance_ret) };
2558 /* General version for methods with more than MAX_INTERP_ENTRY_ARGS arguments */
2559 static void
2560 interp_entry_general (gpointer this_arg, gpointer res, gpointer *args, gpointer rmethod)
2562 INTERP_ENTRY_BASE ((InterpMethod*)rmethod, this_arg, res);
2563 data.many_args = args;
2564 interp_entry (&data);
2567 #ifdef MONO_ARCH_HAVE_INTERP_ENTRY_TRAMPOLINE
2569 // inline so we can alloc on stack
2570 #define alloc_storage_for_stackval(s, t, p) do { \
2571 if ((t)->type == MONO_TYPE_GENERICINST && !MONO_TYPE_IS_REFERENCE (t)) { \
2572 (s)->data.vt = alloca (mono_class_value_size ((t)->data.generic_class->container_class, NULL)); \
2573 } else if ((t)->type == MONO_TYPE_VALUETYPE) { \
2574 if (p) \
2575 (s)->data.vt = alloca (mono_class_native_size ((t)->data.klass, NULL)); \
2576 else \
2577 (s)->data.vt = alloca (mono_class_value_size ((t)->data.klass, NULL)); \
2579 } while (0)
2581 static void
2582 interp_entry_from_trampoline (gpointer ccontext_untyped, gpointer rmethod_untyped)
2584 InterpFrame frame;
2585 ThreadContext *context;
2586 stackval result;
2587 stackval *args;
2588 MonoMethod *method;
2589 MonoMethodSignature *sig;
2590 CallContext *ccontext = (CallContext*) ccontext_untyped;
2591 InterpMethod *rmethod = (InterpMethod*) rmethod_untyped;
2592 gpointer orig_domain = NULL, attach_cookie;
2593 int i;
2595 if (rmethod->needs_thread_attach)
2596 orig_domain = mono_threads_attach_coop (mono_domain_get (), &attach_cookie);
2598 context = get_context ();
2600 method = rmethod->method;
2601 sig = mono_method_signature_internal (method);
2603 frame.ex = NULL;
2605 args = (stackval*)alloca (sizeof (stackval) * (sig->param_count + (sig->hasthis ? 1 : 0)));
2607 init_frame (&frame, NULL, rmethod, args, &result);
2609 /* Allocate storage for value types */
2610 for (i = 0; i < sig->param_count; i++) {
2611 MonoType *type = sig->params [i];
2612 alloc_storage_for_stackval (&frame.stack_args [i + sig->hasthis], type, sig->pinvoke);
2615 if (sig->ret->type != MONO_TYPE_VOID)
2616 alloc_storage_for_stackval (frame.retval, sig->ret, sig->pinvoke);
2618 /* Copy the args saved in the trampoline to the frame stack */
2619 mono_arch_get_native_call_context_args (ccontext, &frame, sig);
2621 interp_exec_method (&frame, context);
2623 if (rmethod->needs_thread_attach)
2624 mono_threads_detach_coop (orig_domain, &attach_cookie);
2626 // FIXME:
2627 g_assert (frame.ex == NULL);
2629 /* Write back the return value */
2630 mono_arch_set_native_call_context_ret (ccontext, &frame, sig);
2632 #endif /* MONO_ARCH_HAVE_INTERP_ENTRY_TRAMPOLINE */
2634 static InterpMethod*
2635 lookup_method_pointer (gpointer addr)
2637 MonoDomain *domain = mono_domain_get ();
2638 MonoJitDomainInfo *info = domain_jit_info (domain);
2639 InterpMethod *res = NULL;
2641 mono_domain_lock (domain);
2642 if (info->interp_method_pointer_hash)
2643 res = (InterpMethod*)g_hash_table_lookup (info->interp_method_pointer_hash, addr);
2644 mono_domain_unlock (domain);
2646 return res;
2649 #ifndef MONO_ARCH_HAVE_INTERP_NATIVE_TO_MANAGED
2650 static void
2651 interp_no_native_to_managed (void)
2653 g_error ("interpreter: native-to-managed transition not available on this platform");
2655 #endif
2657 static void
2658 no_llvmonly_interp_method_pointer (void)
2660 g_assert_not_reached ();
2664 * interp_create_method_pointer_llvmonly:
2666 * Return an ftndesc for entering the interpreter and executing METHOD.
2668 static MonoFtnDesc*
2669 interp_create_method_pointer_llvmonly (MonoMethod *method, gboolean unbox, MonoError *error)
2671 MonoDomain *domain = mono_domain_get ();
2672 gpointer addr, entry_func, entry_wrapper;
2673 MonoMethodSignature *sig;
2674 MonoMethod *wrapper;
2675 MonoJitDomainInfo *info;
2676 InterpMethod *imethod;
2678 imethod = mono_interp_get_imethod (domain, method, error);
2679 return_val_if_nok (error, NULL);
2681 if (unbox) {
2682 if (imethod->llvmonly_unbox_entry)
2683 return (MonoFtnDesc*)imethod->llvmonly_unbox_entry;
2684 } else {
2685 if (imethod->jit_entry)
2686 return (MonoFtnDesc*)imethod->jit_entry;
2689 sig = mono_method_signature_internal (method);
2692 * The entry functions need access to the method to call, so we have
2693 * to use a ftndesc. The caller uses a normal signature, while the
2694 * entry functions use a gsharedvt_in signature, so wrap the entry function in
2695 * a gsharedvt_in_sig wrapper.
2697 wrapper = mini_get_gsharedvt_in_sig_wrapper (sig);
2699 entry_wrapper = mono_jit_compile_method_jit_only (wrapper, error);
2700 mono_error_assertf_ok (error, "couldn't compile wrapper \"%s\" for \"%s\"",
2701 mono_method_get_name_full (wrapper, TRUE, TRUE, MONO_TYPE_NAME_FORMAT_IL),
2702 mono_method_get_name_full (method, TRUE, TRUE, MONO_TYPE_NAME_FORMAT_IL));
2704 if (sig->param_count > MAX_INTERP_ENTRY_ARGS) {
2705 g_assert_not_reached ();
2706 //entry_func = (gpointer)interp_entry_general;
2707 } else if (sig->hasthis) {
2708 if (sig->ret->type == MONO_TYPE_VOID)
2709 entry_func = entry_funcs_instance [sig->param_count];
2710 else
2711 entry_func = entry_funcs_instance_ret [sig->param_count];
2712 } else {
2713 if (sig->ret->type == MONO_TYPE_VOID)
2714 entry_func = entry_funcs_static [sig->param_count];
2715 else
2716 entry_func = entry_funcs_static_ret [sig->param_count];
2718 g_assert (entry_func);
2720 /* Encode unbox in the lower bit of imethod */
2721 gpointer entry_arg = imethod;
2722 if (unbox)
2723 entry_arg = (gpointer)(((gsize)entry_arg) | 1);
2724 MonoFtnDesc *entry_ftndesc = mini_llvmonly_create_ftndesc (mono_domain_get (), entry_func, entry_arg);
2726 addr = mini_llvmonly_create_ftndesc (mono_domain_get (), entry_wrapper, entry_ftndesc);
2728 info = domain_jit_info (domain);
2729 mono_domain_lock (domain);
2730 if (!info->interp_method_pointer_hash)
2731 info->interp_method_pointer_hash = g_hash_table_new (NULL, NULL);
2732 g_hash_table_insert (info->interp_method_pointer_hash, addr, imethod);
2733 mono_domain_unlock (domain);
2735 mono_memory_barrier ();
2736 if (unbox)
2737 imethod->llvmonly_unbox_entry = addr;
2738 else
2739 imethod->jit_entry = addr;
2741 return (MonoFtnDesc*)addr;
2745 * interp_create_method_pointer:
2747 * Return a function pointer which can be used to call METHOD using the
2748 * interpreter. Return NULL for methods which are not supported.
2750 static gpointer
2751 interp_create_method_pointer (MonoMethod *method, gboolean compile, MonoError *error)
2753 #ifndef MONO_ARCH_HAVE_INTERP_NATIVE_TO_MANAGED
2754 if (mono_llvm_only)
2755 return (gpointer)no_llvmonly_interp_method_pointer;
2756 return (gpointer)interp_no_native_to_managed;
2757 #else
2758 gpointer addr, entry_func, entry_wrapper;
2759 MonoDomain *domain = mono_domain_get ();
2760 MonoJitDomainInfo *info;
2761 InterpMethod *imethod = mono_interp_get_imethod (domain, method, error);
2763 if (mono_llvm_only)
2764 return (gpointer)no_llvmonly_interp_method_pointer;
2766 if (compile) {
2767 /* Return any errors from method compilation */
2768 mono_interp_transform_method (imethod, get_context (), error);
2769 return_val_if_nok (error, NULL);
2772 if (imethod->jit_entry)
2773 return imethod->jit_entry;
2775 MonoMethodSignature *sig = mono_method_signature_internal (method);
2777 if (mono_llvm_only)
2778 /* The caller should call interp_create_method_pointer_llvmonly */
2779 g_assert_not_reached ();
2781 /* HACK: method_ptr of delegate should point to a runtime method*/
2782 if (method->wrapper_type && (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD ||
2783 (method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE)))
2784 return imethod;
2786 #ifndef MONO_ARCH_HAVE_INTERP_ENTRY_TRAMPOLINE
2787 MonoMethod *wrapper = mini_get_interp_in_wrapper (sig);
2789 entry_wrapper = mono_jit_compile_method_jit_only (wrapper, error);
2790 mono_error_assertf_ok (error, "couldn't compile wrapper \"%s\" for \"%s\"",
2791 mono_method_get_name_full (wrapper, TRUE, TRUE, MONO_TYPE_NAME_FORMAT_IL),
2792 mono_method_get_name_full (method, TRUE, TRUE, MONO_TYPE_NAME_FORMAT_IL));
2794 if (sig->param_count > MAX_INTERP_ENTRY_ARGS) {
2795 entry_func = (gpointer)interp_entry_general;
2796 } else if (sig->hasthis) {
2797 if (sig->ret->type == MONO_TYPE_VOID)
2798 entry_func = entry_funcs_instance [sig->param_count];
2799 else
2800 entry_func = entry_funcs_instance_ret [sig->param_count];
2801 } else {
2802 if (sig->ret->type == MONO_TYPE_VOID)
2803 entry_func = entry_funcs_static [sig->param_count];
2804 else
2805 entry_func = entry_funcs_static_ret [sig->param_count];
2807 g_assert (entry_func);
2808 #else
2809 if (!mono_native_to_interp_trampoline) {
2810 if (mono_aot_only) {
2811 mono_native_to_interp_trampoline = (MonoFuncV)mono_aot_get_trampoline ("native_to_interp_trampoline");
2812 } else {
2813 MonoTrampInfo *info;
2814 mono_native_to_interp_trampoline = (MonoFuncV)mono_arch_get_native_to_interp_trampoline (&info);
2815 mono_tramp_info_register (info, NULL);
2818 entry_wrapper = (gpointer)mono_native_to_interp_trampoline;
2819 /* We need the lmf wrapper only when being called from mixed mode */
2820 if (sig->pinvoke)
2821 entry_func = (gpointer)interp_entry_from_trampoline;
2822 else {
2823 static gpointer cached_func = NULL;
2824 if (!cached_func) {
2825 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);
2826 mono_memory_barrier ();
2828 entry_func = cached_func;
2830 #endif
2831 /* This is the argument passed to the interp_in wrapper by the static rgctx trampoline */
2832 MonoFtnDesc *ftndesc = g_new0 (MonoFtnDesc, 1);
2833 ftndesc->addr = entry_func;
2834 ftndesc->arg = imethod;
2835 mono_error_assert_ok (error);
2838 * The wrapper is called by compiled code, which doesn't pass the extra argument, so we pass it in the
2839 * rgctx register using a trampoline.
2842 addr = mono_create_ftnptr_arg_trampoline (ftndesc, entry_wrapper);
2844 info = domain_jit_info (domain);
2845 mono_domain_lock (domain);
2846 if (!info->interp_method_pointer_hash)
2847 info->interp_method_pointer_hash = g_hash_table_new (NULL, NULL);
2848 g_hash_table_insert (info->interp_method_pointer_hash, addr, imethod);
2849 mono_domain_unlock (domain);
2851 mono_memory_barrier ();
2852 imethod->jit_entry = addr;
2854 return addr;
2855 #endif
2858 #if COUNT_OPS
2859 static int opcode_counts[512];
2861 #define COUNT_OP(op) opcode_counts[op]++
2862 #else
2863 #define COUNT_OP(op)
2864 #endif
2866 #if DEBUG_INTERP
2867 #define DUMP_INSTR() \
2868 if (tracing > 1) { \
2869 char *ins; \
2870 if (sp > frame->stack) { \
2871 ins = dump_stack (frame->stack, sp); \
2872 } else { \
2873 ins = g_strdup (""); \
2875 sp->data.l = 0; \
2876 output_indent (); \
2877 char *mn = mono_method_full_name (frame->imethod->method, FALSE); \
2878 char *disasm = mono_interp_dis_mintop(rtm->code, ip); \
2879 g_print ("(%p) %s -> %s\t%d:%s\n", mono_thread_internal_current (), mn, disasm, vt_sp - vtalloc, ins); \
2880 g_free (mn); \
2881 g_free (ins); \
2882 g_free (disasm); \
2884 #else
2885 #define DUMP_INSTR()
2886 #endif
2888 #ifdef __GNUC__
2889 #define USE_COMPUTED_GOTO 1
2890 #endif
2891 #if USE_COMPUTED_GOTO
2892 #define MINT_IN_SWITCH(op) COUNT_OP(op); goto *in_labels[op];
2893 #define MINT_IN_CASE(x) LAB_ ## x:
2894 #if DEBUG_INTERP
2895 #define MINT_IN_BREAK if (tracing > 1) goto main_loop; else { COUNT_OP(*ip); goto *in_labels[*ip]; }
2896 #else
2897 #define MINT_IN_BREAK { COUNT_OP(*ip); goto *in_labels[*ip]; }
2898 #endif
2899 #define MINT_IN_DEFAULT mint_default: if (0) goto mint_default; /* make gcc shut up */
2900 #else
2901 #define MINT_IN_SWITCH(op) switch (op)
2902 #define MINT_IN_CASE(x) case x:
2903 #define MINT_IN_BREAK break
2904 #define MINT_IN_DEFAULT default:
2905 #endif
2908 * If EXIT_AT_FINALLY is not -1, exit after exiting the finally clause with that index.
2909 * If BASE_FRAME is not NULL, copy arguments/locals from BASE_FRAME.
2911 static void
2912 interp_exec_method_full (InterpFrame *frame, ThreadContext *context, FrameClauseArgs *clause_args)
2914 InterpFrame child_frame;
2915 GSList *finally_ips = NULL;
2916 const unsigned short *endfinally_ip = NULL;
2917 const unsigned short *ip = NULL;
2918 stackval *sp;
2919 InterpMethod *rtm = NULL;
2920 #if DEBUG_INTERP
2921 gint tracing = global_tracing;
2922 unsigned char *vtalloc;
2923 #else
2924 gint tracing = 0;
2925 #endif
2926 int i32;
2927 unsigned char *vt_sp;
2928 unsigned char *locals = NULL;
2929 ERROR_DECL (error);
2930 MonoObject *o = NULL;
2931 MonoClass *c;
2932 #if USE_COMPUTED_GOTO
2933 static void *in_labels[] = {
2934 #define OPDEF(a,b,c,d) \
2935 &&LAB_ ## a,
2936 #include "mintops.def"
2937 0 };
2938 #endif
2941 frame->ex = NULL;
2942 frame->ip = NULL;
2943 debug_enter (frame, &tracing);
2945 rtm = frame->imethod;
2946 if (!frame->imethod->transformed) {
2947 #if DEBUG_INTERP
2948 char *mn = mono_method_full_name (frame->imethod->method, TRUE);
2949 g_print ("(%p) Transforming %s\n", mono_thread_internal_current (), mn);
2950 g_free (mn);
2951 #endif
2953 do_transform_method (frame, context);
2954 if (frame->ex)
2955 THROW_EX (frame->ex, NULL);
2956 EXCEPTION_CHECKPOINT;
2959 if (!clause_args) {
2960 frame->args = g_newa (char, rtm->alloca_size);
2961 memset (frame->args, 0, rtm->alloca_size);
2963 ip = rtm->code;
2964 } else {
2965 ip = clause_args->start_with_ip;
2966 if (clause_args->base_frame) {
2967 frame->args = g_newa (char, rtm->alloca_size);
2968 memcpy (frame->args, clause_args->base_frame->args, rtm->alloca_size);
2971 sp = frame->stack = (stackval *) ((char *) frame->args + rtm->args_size);
2972 vt_sp = (unsigned char *) sp + rtm->stack_size;
2973 #if DEBUG_INTERP
2974 vtalloc = vt_sp;
2975 #endif
2976 locals = (unsigned char *) vt_sp + rtm->vt_stack_size;
2977 frame->locals = locals;
2978 child_frame.parent = frame;
2980 if (clause_args && clause_args->filter_exception) {
2981 sp->data.p = clause_args->filter_exception;
2982 sp++;
2985 //g_print ("(%p) Call %s\n", mono_thread_internal_current (), mono_method_get_full_name (frame->imethod->method));
2988 * using while (ip < end) may result in a 15% performance drop,
2989 * but it may be useful for debug
2991 while (1) {
2992 main_loop:
2993 /* g_assert (sp >= frame->stack); */
2994 /* g_assert(vt_sp - vtalloc <= rtm->vt_stack_size); */
2995 DUMP_INSTR();
2996 MINT_IN_SWITCH (*ip) {
2997 MINT_IN_CASE(MINT_INITLOCALS)
2998 memset (locals, 0, rtm->locals_size);
2999 ++ip;
3000 MINT_IN_BREAK;
3001 MINT_IN_CASE(MINT_NOP)
3002 ++ip;
3003 MINT_IN_BREAK;
3004 MINT_IN_CASE(MINT_NIY)
3005 g_error ("mint_niy: instruction not implemented yet. This shouldn't happen.");
3006 MINT_IN_BREAK;
3007 MINT_IN_CASE(MINT_BREAK)
3008 ++ip;
3009 do_debugger_tramp (mini_get_dbg_callbacks ()->user_break, frame);
3010 MINT_IN_BREAK;
3011 MINT_IN_CASE(MINT_BREAKPOINT)
3012 ++ip;
3013 mono_break ();
3014 MINT_IN_BREAK;
3015 MINT_IN_CASE(MINT_LDNULL)
3016 sp->data.p = NULL;
3017 ++ip;
3018 ++sp;
3019 MINT_IN_BREAK;
3020 MINT_IN_CASE(MINT_ARGLIST)
3021 g_assert (frame->varargs);
3022 sp->data.p = vt_sp;
3023 *(gpointer*)sp->data.p = frame->varargs;
3024 vt_sp += ALIGN_TO (sizeof (gpointer), MINT_VT_ALIGNMENT);
3025 ++ip;
3026 ++sp;
3027 MINT_IN_BREAK;
3028 MINT_IN_CASE(MINT_VTRESULT) {
3029 int ret_size = * (guint16 *)(ip + 1);
3030 unsigned char *ret_vt_sp = vt_sp;
3031 vt_sp -= READ32(ip + 2);
3032 if (ret_size > 0) {
3033 memmove (vt_sp, ret_vt_sp, ret_size);
3034 sp [-1].data.p = vt_sp;
3035 vt_sp += ALIGN_TO (ret_size, MINT_VT_ALIGNMENT);
3037 ip += 4;
3038 MINT_IN_BREAK;
3040 #define LDC(n) do { sp->data.i = (n); ++ip; ++sp; } while (0)
3041 MINT_IN_CASE(MINT_LDC_I4_M1)
3042 LDC(-1);
3043 MINT_IN_BREAK;
3044 MINT_IN_CASE(MINT_LDC_I4_0)
3045 LDC(0);
3046 MINT_IN_BREAK;
3047 MINT_IN_CASE(MINT_LDC_I4_1)
3048 LDC(1);
3049 MINT_IN_BREAK;
3050 MINT_IN_CASE(MINT_LDC_I4_2)
3051 LDC(2);
3052 MINT_IN_BREAK;
3053 MINT_IN_CASE(MINT_LDC_I4_3)
3054 LDC(3);
3055 MINT_IN_BREAK;
3056 MINT_IN_CASE(MINT_LDC_I4_4)
3057 LDC(4);
3058 MINT_IN_BREAK;
3059 MINT_IN_CASE(MINT_LDC_I4_5)
3060 LDC(5);
3061 MINT_IN_BREAK;
3062 MINT_IN_CASE(MINT_LDC_I4_6)
3063 LDC(6);
3064 MINT_IN_BREAK;
3065 MINT_IN_CASE(MINT_LDC_I4_7)
3066 LDC(7);
3067 MINT_IN_BREAK;
3068 MINT_IN_CASE(MINT_LDC_I4_8)
3069 LDC(8);
3070 MINT_IN_BREAK;
3071 MINT_IN_CASE(MINT_LDC_I4_S)
3072 sp->data.i = *(const short *)(ip + 1);
3073 ip += 2;
3074 ++sp;
3075 MINT_IN_BREAK;
3076 MINT_IN_CASE(MINT_LDC_I4)
3077 ++ip;
3078 sp->data.i = READ32 (ip);
3079 ip += 2;
3080 ++sp;
3081 MINT_IN_BREAK;
3082 MINT_IN_CASE(MINT_LDC_I8)
3083 ++ip;
3084 sp->data.l = READ64 (ip);
3085 ip += 4;
3086 ++sp;
3087 MINT_IN_BREAK;
3088 MINT_IN_CASE(MINT_LDC_R4) {
3089 guint32 val;
3090 ++ip;
3091 val = READ32(ip);
3092 sp->data.f_r4 = * (float *)&val;
3093 ip += 2;
3094 ++sp;
3095 MINT_IN_BREAK;
3097 MINT_IN_CASE(MINT_LDC_R8)
3098 sp->data.l = READ64 (ip + 1); /* note union usage */
3099 ip += 5;
3100 ++sp;
3101 MINT_IN_BREAK;
3102 MINT_IN_CASE(MINT_DUP)
3103 sp [0] = sp[-1];
3104 ++sp;
3105 ++ip;
3106 MINT_IN_BREAK;
3107 MINT_IN_CASE(MINT_DUP_VT)
3108 i32 = READ32 (ip + 1);
3109 sp->data.p = vt_sp;
3110 memcpy(sp->data.p, sp [-1].data.p, i32);
3111 vt_sp += ALIGN_TO (i32, MINT_VT_ALIGNMENT);
3112 ++sp;
3113 ip += 3;
3114 MINT_IN_BREAK;
3115 MINT_IN_CASE(MINT_POP) {
3116 guint16 u16 = (* (guint16 *)(ip + 1)) + 1;
3117 if (u16 > 1)
3118 memmove (sp - u16, sp - 1, (u16 - 1) * sizeof (stackval));
3119 sp--;
3120 ip += 2;
3121 MINT_IN_BREAK;
3123 MINT_IN_CASE(MINT_JMP) {
3124 InterpMethod *new_method = (InterpMethod*)rtm->data_items [* (guint16 *)(ip + 1)];
3125 gboolean realloc_frame = new_method->alloca_size > rtm->alloca_size;
3127 if (frame->imethod->prof_flags & MONO_PROFILER_CALL_INSTRUMENTATION_TAIL_CALL)
3128 MONO_PROFILER_RAISE (method_tail_call, (frame->imethod->method, new_method->method));
3130 if (!new_method->transformed) {
3131 ERROR_DECL (error);
3133 frame->ip = ip;
3134 mono_interp_transform_method (new_method, context, error);
3135 frame->ex = mono_error_convert_to_exception (error);
3136 if (frame->ex)
3137 goto exit_frame;
3139 ip += 2;
3140 rtm = frame->imethod = new_method;
3142 * We allocate the stack frame from scratch and store the arguments in the
3143 * locals again since it's possible for the caller stack frame to be smaller
3144 * than the callee stack frame (at the interp level)
3146 if (realloc_frame) {
3147 frame->args = g_newa (char, rtm->alloca_size);
3148 memset (frame->args, 0, rtm->alloca_size);
3149 sp = frame->stack = (stackval *) ((char *) frame->args + rtm->args_size);
3151 vt_sp = (unsigned char *) sp + rtm->stack_size;
3152 #if DEBUG_INTERP
3153 vtalloc = vt_sp;
3154 #endif
3155 locals = vt_sp + rtm->vt_stack_size;
3156 frame->locals = locals;
3157 if (realloc_frame)
3158 ip = rtm->code;
3159 else
3160 ip = rtm->new_body_start; /* bypass storing input args from callers frame */
3161 MINT_IN_BREAK;
3163 MINT_IN_CASE(MINT_CALLI) {
3164 MonoMethodSignature *csignature;
3165 stackval *endsp = sp;
3167 frame->ip = ip;
3169 csignature = (MonoMethodSignature*)rtm->data_items [* (guint16 *)(ip + 1)];
3170 ip += 2;
3171 --sp;
3172 --endsp;
3173 child_frame.imethod = (InterpMethod*)sp->data.p;
3175 sp->data.p = vt_sp;
3176 child_frame.retval = sp;
3177 /* decrement by the actual number of args */
3178 sp -= csignature->param_count;
3179 if (csignature->hasthis)
3180 --sp;
3181 child_frame.stack_args = sp;
3183 if (child_frame.imethod->method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) {
3184 child_frame.imethod = mono_interp_get_imethod (rtm->domain, mono_marshal_get_native_wrapper (child_frame.imethod->method, FALSE, FALSE), error);
3185 mono_error_cleanup (error); /* FIXME: don't swallow the error */
3188 if (csignature->hasthis) {
3189 MonoObject *this_arg = (MonoObject*)sp->data.p;
3191 if (m_class_is_valuetype (this_arg->vtable->klass)) {
3192 gpointer unboxed = mono_object_unbox_internal (this_arg);
3193 sp [0].data.p = unboxed;
3197 interp_exec_method (&child_frame, context);
3199 CHECK_RESUME_STATE (context);
3201 /* need to handle typedbyref ... */
3202 if (csignature->ret->type != MONO_TYPE_VOID) {
3203 *sp = *endsp;
3204 sp++;
3206 MINT_IN_BREAK;
3208 MINT_IN_CASE(MINT_CALLI_NAT_FAST) {
3209 gpointer target_ip = sp [-1].data.p;
3210 MonoMethodSignature *csignature = (MonoMethodSignature*)rtm->data_items [* (guint16 *)(ip + 1)];
3211 int opcode = *(guint16 *)(ip + 2);
3213 sp--;
3214 frame->ip = ip;
3216 sp = do_icall (frame, csignature, opcode, sp, target_ip);
3217 EXCEPTION_CHECKPOINT;
3218 CHECK_RESUME_STATE (context);
3219 ip += 3;
3220 MINT_IN_BREAK;
3222 MINT_IN_CASE(MINT_CALLI_NAT) {
3223 MonoMethodSignature *csignature;
3224 stackval *endsp = sp;
3225 unsigned char *code = NULL;
3227 frame->ip = ip;
3229 csignature = (MonoMethodSignature*)rtm->data_items [* (guint16 *)(ip + 1)];
3230 ip += 2;
3231 --sp;
3232 --endsp;
3233 code = (guchar*)sp->data.p;
3234 child_frame.imethod = NULL;
3236 sp->data.p = vt_sp;
3237 child_frame.retval = sp;
3238 /* decrement by the actual number of args */
3239 sp -= csignature->param_count;
3240 if (csignature->hasthis)
3241 --sp;
3242 child_frame.stack_args = sp;
3243 if (frame->imethod->method->dynamic && csignature->pinvoke) {
3244 MonoMarshalSpec **mspecs;
3245 MonoMethodPInvoke piinfo;
3246 MonoMethod *m;
3248 /* Pinvoke call is missing the wrapper. See mono_get_native_calli_wrapper */
3249 mspecs = g_new0 (MonoMarshalSpec*, csignature->param_count + 1);
3250 memset (&piinfo, 0, sizeof (piinfo));
3252 m = mono_marshal_get_native_func_wrapper (m_class_get_image (frame->imethod->method->klass), csignature, &piinfo, mspecs, code);
3254 for (int i = csignature->param_count; i >= 0; i--)
3255 if (mspecs [i])
3256 mono_metadata_free_marshal_spec (mspecs [i]);
3257 g_free (mspecs);
3259 child_frame.imethod = mono_interp_get_imethod (rtm->domain, m, error);
3260 mono_error_cleanup (error); /* FIXME: don't swallow the error */
3262 interp_exec_method (&child_frame, context);
3263 } else {
3264 ves_pinvoke_method (&child_frame, csignature, (MonoFuncV) code, FALSE, context);
3267 CHECK_RESUME_STATE (context);
3269 /* need to handle typedbyref ... */
3270 if (csignature->ret->type != MONO_TYPE_VOID) {
3271 *sp = *endsp;
3272 sp++;
3274 MINT_IN_BREAK;
3276 MINT_IN_CASE(MINT_CALLVIRT_FAST)
3277 MINT_IN_CASE(MINT_VCALLVIRT_FAST) {
3278 MonoObject *this_arg;
3279 MonoClass *this_class;
3280 gboolean is_void = *ip == MINT_VCALLVIRT_FAST;
3281 InterpMethod *imethod;
3282 stackval *endsp = sp;
3283 int slot;
3285 // FIXME Have it handle also remoting calls and use a single opcode for virtual calls
3287 frame->ip = ip;
3289 imethod = (InterpMethod*)rtm->data_items [* (guint16 *)(ip + 1)];
3290 slot = *(gint16*)(ip + 2);
3291 ip += 3;
3292 sp->data.p = vt_sp;
3293 child_frame.retval = sp;
3295 /* decrement by the actual number of args */
3296 sp -= imethod->param_count + imethod->hasthis;
3297 child_frame.stack_args = sp;
3299 this_arg = (MonoObject*)sp->data.p;
3300 this_class = this_arg->vtable->klass;
3302 child_frame.imethod = get_virtual_method_fast (this_arg, imethod, slot);
3303 if (m_class_is_valuetype (this_class) && m_class_is_valuetype (child_frame.imethod->method->klass)) {
3304 /* unbox */
3305 gpointer unboxed = mono_object_unbox_internal (this_arg);
3306 sp [0].data.p = unboxed;
3309 interp_exec_method (&child_frame, context);
3311 CHECK_RESUME_STATE (context);
3313 if (!is_void) {
3314 /* need to handle typedbyref ... */
3315 *sp = *endsp;
3316 sp++;
3318 MINT_IN_BREAK;
3320 MINT_IN_CASE(MINT_CALL)
3321 MINT_IN_CASE(MINT_VCALL)
3322 MINT_IN_CASE(MINT_CALLVIRT)
3323 MINT_IN_CASE(MINT_VCALLVIRT) {
3324 gboolean is_void = *ip == MINT_VCALL || *ip == MINT_VCALLVIRT;
3325 gboolean is_virtual = *ip == MINT_CALLVIRT || *ip == MINT_VCALLVIRT;
3326 stackval *endsp = sp;
3327 int num_varargs = 0;;
3329 frame->ip = ip;
3331 child_frame.imethod = (InterpMethod*)rtm->data_items [* (guint16 *)(ip + 1)];
3332 if (child_frame.imethod->vararg) {
3333 /* The real signature for vararg calls */
3334 MonoMethodSignature *csig = (MonoMethodSignature*) rtm->data_items [* (guint16*) (ip + 2)];
3335 /* Push all vararg arguments from normal sp to vt_sp together with the signature */
3336 num_varargs = csig->param_count - csig->sentinelpos;
3337 child_frame.varargs = (char*) vt_sp;
3338 copy_varargs_vtstack (csig, sp, &vt_sp);
3340 ip += 2 + child_frame.imethod->vararg;
3341 sp->data.p = vt_sp;
3342 child_frame.retval = sp;
3344 /* decrement by the actual number of args */
3345 sp -= child_frame.imethod->param_count + child_frame.imethod->hasthis + num_varargs;
3346 child_frame.stack_args = sp;
3348 if (is_virtual) {
3349 MonoObject *this_arg = (MonoObject*)sp->data.p;
3350 MonoClass *this_class = this_arg->vtable->klass;
3352 child_frame.imethod = get_virtual_method (child_frame.imethod, this_arg);
3353 if (m_class_is_valuetype (this_class) && m_class_is_valuetype (child_frame.imethod->method->klass)) {
3354 /* unbox */
3355 gpointer unboxed = mono_object_unbox_internal (this_arg);
3356 sp [0].data.p = unboxed;
3360 interp_exec_method (&child_frame, context);
3362 CHECK_RESUME_STATE (context);
3364 if (!is_void) {
3365 /* need to handle typedbyref ... */
3366 *sp = *endsp;
3367 sp++;
3369 MINT_IN_BREAK;
3371 MINT_IN_CASE(MINT_JIT_CALL) {
3372 InterpMethod *rmethod = (InterpMethod*)rtm->data_items [* (guint16 *)(ip + 1)];
3373 ERROR_DECL (error);
3374 frame->ip = ip;
3375 ip += 2;
3376 sp = do_jit_call (sp, vt_sp, context, frame, rmethod, error);
3377 if (!is_ok (error)) {
3378 MonoException *ex = mono_error_convert_to_exception (error);
3379 THROW_EX (ex, ip);
3382 CHECK_RESUME_STATE (context);
3384 if (rmethod->rtype->type != MONO_TYPE_VOID)
3385 sp++;
3387 MINT_IN_BREAK;
3389 MINT_IN_CASE(MINT_CALLRUN) {
3390 MonoMethod *target_method = (MonoMethod*) rtm->data_items [* (guint16 *)(ip + 1)];
3391 MonoMethodSignature *sig = (MonoMethodSignature*) rtm->data_items [* (guint16 *)(ip + 2)];
3392 stackval *retval;
3394 sp->data.p = vt_sp;
3395 retval = sp;
3397 sp -= sig->param_count;
3398 if (sig->hasthis)
3399 sp--;
3401 ves_imethod (frame, target_method, sig, sp, retval);
3402 if (frame->ex)
3403 THROW_EX (frame->ex, ip);
3405 if (sig->ret->type != MONO_TYPE_VOID) {
3406 *sp = *retval;
3407 sp++;
3409 ip += 3;
3410 MINT_IN_BREAK;
3412 MINT_IN_CASE(MINT_RET)
3413 --sp;
3414 *frame->retval = *sp;
3415 if (sp > frame->stack)
3416 g_warning ("ret: more values on stack: %d", sp-frame->stack);
3417 goto exit_frame;
3418 MINT_IN_CASE(MINT_RET_VOID)
3419 if (sp > frame->stack)
3420 g_warning ("ret.void: more values on stack: %d %s", sp-frame->stack, mono_method_full_name (frame->imethod->method, TRUE));
3421 goto exit_frame;
3422 MINT_IN_CASE(MINT_RET_VT)
3423 i32 = READ32(ip + 1);
3424 --sp;
3425 memcpy(frame->retval->data.p, sp->data.p, i32);
3426 if (sp > frame->stack)
3427 g_warning ("ret.vt: more values on stack: %d", sp-frame->stack);
3428 goto exit_frame;
3429 MINT_IN_CASE(MINT_BR_S)
3430 ip += (short) *(ip + 1);
3431 MINT_IN_BREAK;
3432 MINT_IN_CASE(MINT_BR)
3433 ip += (gint32) READ32(ip + 1);
3434 MINT_IN_BREAK;
3435 #define ZEROP_S(datamem, op) \
3436 --sp; \
3437 if (sp->data.datamem op 0) \
3438 ip += * (gint16 *)(ip + 1); \
3439 else \
3440 ip += 2;
3442 #define ZEROP(datamem, op) \
3443 --sp; \
3444 if (sp->data.datamem op 0) \
3445 ip += READ32(ip + 1); \
3446 else \
3447 ip += 3;
3449 MINT_IN_CASE(MINT_BRFALSE_I4_S)
3450 ZEROP_S(i, ==);
3451 MINT_IN_BREAK;
3452 MINT_IN_CASE(MINT_BRFALSE_I8_S)
3453 ZEROP_S(l, ==);
3454 MINT_IN_BREAK;
3455 MINT_IN_CASE(MINT_BRFALSE_R4_S)
3456 ZEROP_S(f_r4, ==);
3457 MINT_IN_BREAK;
3458 MINT_IN_CASE(MINT_BRFALSE_R8_S)
3459 ZEROP_S(f, ==);
3460 MINT_IN_BREAK;
3461 MINT_IN_CASE(MINT_BRFALSE_I4)
3462 ZEROP(i, ==);
3463 MINT_IN_BREAK;
3464 MINT_IN_CASE(MINT_BRFALSE_I8)
3465 ZEROP(l, ==);
3466 MINT_IN_BREAK;
3467 MINT_IN_CASE(MINT_BRFALSE_R4)
3468 ZEROP_S(f_r4, ==);
3469 MINT_IN_BREAK;
3470 MINT_IN_CASE(MINT_BRFALSE_R8)
3471 ZEROP_S(f, ==);
3472 MINT_IN_BREAK;
3473 MINT_IN_CASE(MINT_BRTRUE_I4_S)
3474 ZEROP_S(i, !=);
3475 MINT_IN_BREAK;
3476 MINT_IN_CASE(MINT_BRTRUE_I8_S)
3477 ZEROP_S(l, !=);
3478 MINT_IN_BREAK;
3479 MINT_IN_CASE(MINT_BRTRUE_R4_S)
3480 ZEROP_S(f_r4, !=);
3481 MINT_IN_BREAK;
3482 MINT_IN_CASE(MINT_BRTRUE_R8_S)
3483 ZEROP_S(f, !=);
3484 MINT_IN_BREAK;
3485 MINT_IN_CASE(MINT_BRTRUE_I4)
3486 ZEROP(i, !=);
3487 MINT_IN_BREAK;
3488 MINT_IN_CASE(MINT_BRTRUE_I8)
3489 ZEROP(l, !=);
3490 MINT_IN_BREAK;
3491 MINT_IN_CASE(MINT_BRTRUE_R4)
3492 ZEROP(f_r4, !=);
3493 MINT_IN_BREAK;
3494 MINT_IN_CASE(MINT_BRTRUE_R8)
3495 ZEROP(f, !=);
3496 MINT_IN_BREAK;
3497 #define CONDBR_S(cond) \
3498 sp -= 2; \
3499 if (cond) \
3500 ip += * (gint16 *)(ip + 1); \
3501 else \
3502 ip += 2;
3503 #define BRELOP_S(datamem, op) \
3504 CONDBR_S(sp[0].data.datamem op sp[1].data.datamem)
3506 #define CONDBR(cond) \
3507 sp -= 2; \
3508 if (cond) \
3509 ip += READ32(ip + 1); \
3510 else \
3511 ip += 3;
3513 #define BRELOP(datamem, op) \
3514 CONDBR(sp[0].data.datamem op sp[1].data.datamem)
3516 MINT_IN_CASE(MINT_BEQ_I4_S)
3517 BRELOP_S(i, ==)
3518 MINT_IN_BREAK;
3519 MINT_IN_CASE(MINT_BEQ_I8_S)
3520 BRELOP_S(l, ==)
3521 MINT_IN_BREAK;
3522 MINT_IN_CASE(MINT_BEQ_R4_S)
3523 CONDBR_S(!isunordered (sp [0].data.f_r4, sp [1].data.f_r4) && sp[0].data.f_r4 == sp[1].data.f_r4)
3524 MINT_IN_BREAK;
3525 MINT_IN_CASE(MINT_BEQ_R8_S)
3526 CONDBR_S(!mono_isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f == sp[1].data.f)
3527 MINT_IN_BREAK;
3528 MINT_IN_CASE(MINT_BEQ_I4)
3529 BRELOP(i, ==)
3530 MINT_IN_BREAK;
3531 MINT_IN_CASE(MINT_BEQ_I8)
3532 BRELOP(l, ==)
3533 MINT_IN_BREAK;
3534 MINT_IN_CASE(MINT_BEQ_R4)
3535 CONDBR(!isunordered (sp [0].data.f_r4, sp [1].data.f_r4) && sp[0].data.f_r4 == sp[1].data.f_r4)
3536 MINT_IN_BREAK;
3537 MINT_IN_CASE(MINT_BEQ_R8)
3538 CONDBR(!mono_isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f == sp[1].data.f)
3539 MINT_IN_BREAK;
3540 MINT_IN_CASE(MINT_BGE_I4_S)
3541 BRELOP_S(i, >=)
3542 MINT_IN_BREAK;
3543 MINT_IN_CASE(MINT_BGE_I8_S)
3544 BRELOP_S(l, >=)
3545 MINT_IN_BREAK;
3546 MINT_IN_CASE(MINT_BGE_R4_S)
3547 CONDBR_S(!isunordered (sp [0].data.f_r4, sp [1].data.f_r4) && sp[0].data.f_r4 >= sp[1].data.f_r4)
3548 MINT_IN_BREAK;
3549 MINT_IN_CASE(MINT_BGE_R8_S)
3550 CONDBR_S(!mono_isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f >= sp[1].data.f)
3551 MINT_IN_BREAK;
3552 MINT_IN_CASE(MINT_BGE_I4)
3553 BRELOP(i, >=)
3554 MINT_IN_BREAK;
3555 MINT_IN_CASE(MINT_BGE_I8)
3556 BRELOP(l, >=)
3557 MINT_IN_BREAK;
3558 MINT_IN_CASE(MINT_BGE_R4)
3559 CONDBR(!isunordered (sp [0].data.f_r4, sp [1].data.f_r4) && sp[0].data.f_r4 >= sp[1].data.f_r4)
3560 MINT_IN_BREAK;
3561 MINT_IN_CASE(MINT_BGE_R8)
3562 CONDBR(!mono_isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f >= sp[1].data.f)
3563 MINT_IN_BREAK;
3564 MINT_IN_CASE(MINT_BGT_I4_S)
3565 BRELOP_S(i, >)
3566 MINT_IN_BREAK;
3567 MINT_IN_CASE(MINT_BGT_I8_S)
3568 BRELOP_S(l, >)
3569 MINT_IN_BREAK;
3570 MINT_IN_CASE(MINT_BGT_R4_S)
3571 CONDBR_S(!isunordered (sp [0].data.f_r4, sp [1].data.f_r4) && sp[0].data.f_r4 > sp[1].data.f_r4)
3572 MINT_IN_BREAK;
3573 MINT_IN_CASE(MINT_BGT_R8_S)
3574 CONDBR_S(!mono_isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f > sp[1].data.f)
3575 MINT_IN_BREAK;
3576 MINT_IN_CASE(MINT_BGT_I4)
3577 BRELOP(i, >)
3578 MINT_IN_BREAK;
3579 MINT_IN_CASE(MINT_BGT_I8)
3580 BRELOP(l, >)
3581 MINT_IN_BREAK;
3582 MINT_IN_CASE(MINT_BGT_R4)
3583 CONDBR(!isunordered (sp [0].data.f_r4, sp [1].data.f_r4) && sp[0].data.f_r4 > sp[1].data.f_r4)
3584 MINT_IN_BREAK;
3585 MINT_IN_CASE(MINT_BGT_R8)
3586 CONDBR(!mono_isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f > sp[1].data.f)
3587 MINT_IN_BREAK;
3588 MINT_IN_CASE(MINT_BLT_I4_S)
3589 BRELOP_S(i, <)
3590 MINT_IN_BREAK;
3591 MINT_IN_CASE(MINT_BLT_I8_S)
3592 BRELOP_S(l, <)
3593 MINT_IN_BREAK;
3594 MINT_IN_CASE(MINT_BLT_R4_S)
3595 CONDBR_S(!isunordered (sp [0].data.f_r4, sp [1].data.f_r4) && sp[0].data.f_r4 < sp[1].data.f_r4)
3596 MINT_IN_BREAK;
3597 MINT_IN_CASE(MINT_BLT_R8_S)
3598 CONDBR_S(!mono_isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f < sp[1].data.f)
3599 MINT_IN_BREAK;
3600 MINT_IN_CASE(MINT_BLT_I4)
3601 BRELOP(i, <)
3602 MINT_IN_BREAK;
3603 MINT_IN_CASE(MINT_BLT_I8)
3604 BRELOP(l, <)
3605 MINT_IN_BREAK;
3606 MINT_IN_CASE(MINT_BLT_R4)
3607 CONDBR(!isunordered (sp [0].data.f_r4, sp [1].data.f_r4) && sp[0].data.f_r4 < sp[1].data.f_r4)
3608 MINT_IN_BREAK;
3609 MINT_IN_CASE(MINT_BLT_R8)
3610 CONDBR(!mono_isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f < sp[1].data.f)
3611 MINT_IN_BREAK;
3612 MINT_IN_CASE(MINT_BLE_I4_S)
3613 BRELOP_S(i, <=)
3614 MINT_IN_BREAK;
3615 MINT_IN_CASE(MINT_BLE_I8_S)
3616 BRELOP_S(l, <=)
3617 MINT_IN_BREAK;
3618 MINT_IN_CASE(MINT_BLE_R4_S)
3619 CONDBR_S(!isunordered (sp [0].data.f_r4, sp [1].data.f_r4) && sp[0].data.f_r4 <= sp[1].data.f_r4)
3620 MINT_IN_BREAK;
3621 MINT_IN_CASE(MINT_BLE_R8_S)
3622 CONDBR_S(!mono_isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f <= sp[1].data.f)
3623 MINT_IN_BREAK;
3624 MINT_IN_CASE(MINT_BLE_I4)
3625 BRELOP(i, <=)
3626 MINT_IN_BREAK;
3627 MINT_IN_CASE(MINT_BLE_I8)
3628 BRELOP(l, <=)
3629 MINT_IN_BREAK;
3630 MINT_IN_CASE(MINT_BLE_R4)
3631 CONDBR(!isunordered (sp [0].data.f_r4, sp [1].data.f_r4) && sp[0].data.f_r4 <= sp[1].data.f_r4)
3632 MINT_IN_BREAK;
3633 MINT_IN_CASE(MINT_BLE_R8)
3634 CONDBR(!mono_isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f <= sp[1].data.f)
3635 MINT_IN_BREAK;
3636 MINT_IN_CASE(MINT_BNE_UN_I4_S)
3637 BRELOP_S(i, !=)
3638 MINT_IN_BREAK;
3639 MINT_IN_CASE(MINT_BNE_UN_I8_S)
3640 BRELOP_S(l, !=)
3641 MINT_IN_BREAK;
3642 MINT_IN_CASE(MINT_BNE_UN_R4_S)
3643 CONDBR_S(isunordered (sp [0].data.f_r4, sp [1].data.f_r4) || sp[0].data.f_r4 != sp[1].data.f_r4)
3644 MINT_IN_BREAK;
3645 MINT_IN_CASE(MINT_BNE_UN_R8_S)
3646 CONDBR_S(mono_isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f != sp[1].data.f)
3647 MINT_IN_BREAK;
3648 MINT_IN_CASE(MINT_BNE_UN_I4)
3649 BRELOP(i, !=)
3650 MINT_IN_BREAK;
3651 MINT_IN_CASE(MINT_BNE_UN_I8)
3652 BRELOP(l, !=)
3653 MINT_IN_BREAK;
3654 MINT_IN_CASE(MINT_BNE_UN_R4)
3655 CONDBR(isunordered (sp [0].data.f_r4, sp [1].data.f_r4) || sp[0].data.f_r4 != sp[1].data.f_r4)
3656 MINT_IN_BREAK;
3657 MINT_IN_CASE(MINT_BNE_UN_R8)
3658 CONDBR(mono_isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f != sp[1].data.f)
3659 MINT_IN_BREAK;
3661 #define BRELOP_S_CAST(datamem, op, type) \
3662 sp -= 2; \
3663 if ((type) sp[0].data.datamem op (type) sp[1].data.datamem) \
3664 ip += * (gint16 *)(ip + 1); \
3665 else \
3666 ip += 2;
3668 #define BRELOP_CAST(datamem, op, type) \
3669 sp -= 2; \
3670 if ((type) sp[0].data.datamem op (type) sp[1].data.datamem) \
3671 ip += READ32(ip + 1); \
3672 else \
3673 ip += 3;
3675 MINT_IN_CASE(MINT_BGE_UN_I4_S)
3676 BRELOP_S_CAST(i, >=, guint32);
3677 MINT_IN_BREAK;
3678 MINT_IN_CASE(MINT_BGE_UN_I8_S)
3679 BRELOP_S_CAST(l, >=, guint64);
3680 MINT_IN_BREAK;
3681 MINT_IN_CASE(MINT_BGE_UN_R4_S)
3682 CONDBR_S(isunordered (sp [0].data.f_r4, sp [1].data.f_r4) || sp[0].data.f_r4 >= sp[1].data.f_r4)
3683 MINT_IN_BREAK;
3684 MINT_IN_CASE(MINT_BGE_UN_R8_S)
3685 CONDBR_S(mono_isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f >= sp[1].data.f)
3686 MINT_IN_BREAK;
3687 MINT_IN_CASE(MINT_BGE_UN_I4)
3688 BRELOP_CAST(i, >=, guint32);
3689 MINT_IN_BREAK;
3690 MINT_IN_CASE(MINT_BGE_UN_I8)
3691 BRELOP_CAST(l, >=, guint64);
3692 MINT_IN_BREAK;
3693 MINT_IN_CASE(MINT_BGE_UN_R4)
3694 CONDBR(isunordered (sp [0].data.f_r4, sp [1].data.f_r4) || sp[0].data.f_r4 >= sp[1].data.f_r4)
3695 MINT_IN_BREAK;
3696 MINT_IN_CASE(MINT_BGE_UN_R8)
3697 CONDBR(mono_isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f >= sp[1].data.f)
3698 MINT_IN_BREAK;
3699 MINT_IN_CASE(MINT_BGT_UN_I4_S)
3700 BRELOP_S_CAST(i, >, guint32);
3701 MINT_IN_BREAK;
3702 MINT_IN_CASE(MINT_BGT_UN_I8_S)
3703 BRELOP_S_CAST(l, >, guint64);
3704 MINT_IN_BREAK;
3705 MINT_IN_CASE(MINT_BGT_UN_R4_S)
3706 CONDBR_S(isunordered (sp [0].data.f_r4, sp [1].data.f_r4) || sp[0].data.f_r4 > sp[1].data.f_r4)
3707 MINT_IN_BREAK;
3708 MINT_IN_CASE(MINT_BGT_UN_R8_S)
3709 CONDBR_S(mono_isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f > sp[1].data.f)
3710 MINT_IN_BREAK;
3711 MINT_IN_CASE(MINT_BGT_UN_I4)
3712 BRELOP_CAST(i, >, guint32);
3713 MINT_IN_BREAK;
3714 MINT_IN_CASE(MINT_BGT_UN_I8)
3715 BRELOP_CAST(l, >, guint64);
3716 MINT_IN_BREAK;
3717 MINT_IN_CASE(MINT_BGT_UN_R4)
3718 CONDBR(isunordered (sp [0].data.f_r4, sp [1].data.f_r4) || sp[0].data.f_r4 > sp[1].data.f_r4)
3719 MINT_IN_BREAK;
3720 MINT_IN_CASE(MINT_BGT_UN_R8)
3721 CONDBR(mono_isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f > sp[1].data.f)
3722 MINT_IN_BREAK;
3723 MINT_IN_CASE(MINT_BLE_UN_I4_S)
3724 BRELOP_S_CAST(i, <=, guint32);
3725 MINT_IN_BREAK;
3726 MINT_IN_CASE(MINT_BLE_UN_I8_S)
3727 BRELOP_S_CAST(l, <=, guint64);
3728 MINT_IN_BREAK;
3729 MINT_IN_CASE(MINT_BLE_UN_R4_S)
3730 CONDBR_S(isunordered (sp [0].data.f_r4, sp [1].data.f_r4) || sp[0].data.f_r4 <= sp[1].data.f_r4)
3731 MINT_IN_BREAK;
3732 MINT_IN_CASE(MINT_BLE_UN_R8_S)
3733 CONDBR_S(mono_isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f <= sp[1].data.f)
3734 MINT_IN_BREAK;
3735 MINT_IN_CASE(MINT_BLE_UN_I4)
3736 BRELOP_CAST(i, <=, guint32);
3737 MINT_IN_BREAK;
3738 MINT_IN_CASE(MINT_BLE_UN_I8)
3739 BRELOP_CAST(l, <=, guint64);
3740 MINT_IN_BREAK;
3741 MINT_IN_CASE(MINT_BLE_UN_R4)
3742 CONDBR(isunordered (sp [0].data.f_r4, sp [1].data.f_r4) || sp[0].data.f_r4 <= sp[1].data.f_r4)
3743 MINT_IN_BREAK;
3744 MINT_IN_CASE(MINT_BLE_UN_R8)
3745 CONDBR(mono_isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f <= sp[1].data.f)
3746 MINT_IN_BREAK;
3747 MINT_IN_CASE(MINT_BLT_UN_I4_S)
3748 BRELOP_S_CAST(i, <, guint32);
3749 MINT_IN_BREAK;
3750 MINT_IN_CASE(MINT_BLT_UN_I8_S)
3751 BRELOP_S_CAST(l, <, guint64);
3752 MINT_IN_BREAK;
3753 MINT_IN_CASE(MINT_BLT_UN_R4_S)
3754 CONDBR_S(isunordered (sp [0].data.f_r4, sp [1].data.f_r4) || sp[0].data.f_r4 < sp[1].data.f_r4)
3755 MINT_IN_BREAK;
3756 MINT_IN_CASE(MINT_BLT_UN_R8_S)
3757 CONDBR_S(mono_isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f < sp[1].data.f)
3758 MINT_IN_BREAK;
3759 MINT_IN_CASE(MINT_BLT_UN_I4)
3760 BRELOP_CAST(i, <, guint32);
3761 MINT_IN_BREAK;
3762 MINT_IN_CASE(MINT_BLT_UN_I8)
3763 BRELOP_CAST(l, <, guint64);
3764 MINT_IN_BREAK;
3765 MINT_IN_CASE(MINT_BLT_UN_R4)
3766 CONDBR(isunordered (sp [0].data.f_r4, sp [1].data.f_r4) || sp[0].data.f_r4 < sp[1].data.f_r4)
3767 MINT_IN_BREAK;
3768 MINT_IN_CASE(MINT_BLT_UN_R8)
3769 CONDBR(mono_isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f < sp[1].data.f)
3770 MINT_IN_BREAK;
3771 MINT_IN_CASE(MINT_SWITCH) {
3772 guint32 n;
3773 const unsigned short *st;
3774 ++ip;
3775 n = READ32 (ip);
3776 ip += 2;
3777 st = ip + 2 * n;
3778 --sp;
3779 if ((guint32)sp->data.i < n) {
3780 gint offset;
3781 ip += 2 * (guint32)sp->data.i;
3782 offset = READ32 (ip);
3783 ip = ip + offset;
3784 } else {
3785 ip = st;
3787 MINT_IN_BREAK;
3789 MINT_IN_CASE(MINT_LDIND_I1_CHECK)
3790 if (!sp[-1].data.p)
3791 THROW_EX (mono_get_exception_null_reference (), ip);
3792 ++ip;
3793 sp[-1].data.i = *(gint8*)sp[-1].data.p;
3794 MINT_IN_BREAK;
3795 MINT_IN_CASE(MINT_LDIND_U1_CHECK)
3796 if (!sp[-1].data.p)
3797 THROW_EX (mono_get_exception_null_reference (), ip);
3798 ++ip;
3799 sp[-1].data.i = *(guint8*)sp[-1].data.p;
3800 MINT_IN_BREAK;
3801 MINT_IN_CASE(MINT_LDIND_I2_CHECK)
3802 if (!sp[-1].data.p)
3803 THROW_EX (mono_get_exception_null_reference (), ip);
3804 ++ip;
3805 sp[-1].data.i = *(gint16*)sp[-1].data.p;
3806 MINT_IN_BREAK;
3807 MINT_IN_CASE(MINT_LDIND_U2_CHECK)
3808 if (!sp[-1].data.p)
3809 THROW_EX (mono_get_exception_null_reference (), ip);
3810 ++ip;
3811 sp[-1].data.i = *(guint16*)sp[-1].data.p;
3812 MINT_IN_BREAK;
3813 MINT_IN_CASE(MINT_LDIND_I4_CHECK) /* Fall through */
3814 MINT_IN_CASE(MINT_LDIND_U4_CHECK)
3815 if (!sp[-1].data.p)
3816 THROW_EX (mono_get_exception_null_reference (), ip);
3817 ++ip;
3818 sp[-1].data.i = *(gint32*)sp[-1].data.p;
3819 MINT_IN_BREAK;
3820 MINT_IN_CASE(MINT_LDIND_I8_CHECK)
3821 if (!sp[-1].data.p)
3822 THROW_EX (mono_get_exception_null_reference (), ip);
3823 ++ip;
3824 /* memmove handles unaligned case */
3825 memmove (&sp [-1].data.l, sp [-1].data.p, sizeof (gint64));
3826 MINT_IN_BREAK;
3827 MINT_IN_CASE(MINT_LDIND_I) {
3828 guint16 offset = * (guint16 *)(ip + 1);
3829 sp[-1 - offset].data.p = *(gpointer*)sp[-1 - offset].data.p;
3830 ip += 2;
3831 MINT_IN_BREAK;
3833 MINT_IN_CASE(MINT_LDIND_R4_CHECK)
3834 if (!sp[-1].data.p)
3835 THROW_EX (mono_get_exception_null_reference (), ip);
3836 ++ip;
3837 sp[-1].data.f_r4 = *(gfloat*)sp[-1].data.p;
3838 MINT_IN_BREAK;
3839 MINT_IN_CASE(MINT_LDIND_R8_CHECK)
3840 if (!sp[-1].data.p)
3841 THROW_EX (mono_get_exception_null_reference (), ip);
3842 ++ip;
3843 sp[-1].data.f = *(gdouble*)sp[-1].data.p;
3844 MINT_IN_BREAK;
3845 MINT_IN_CASE(MINT_LDIND_REF)
3846 ++ip;
3847 sp[-1].data.p = *(gpointer*)sp[-1].data.p;
3848 MINT_IN_BREAK;
3849 MINT_IN_CASE(MINT_STIND_REF)
3850 ++ip;
3851 sp -= 2;
3852 mono_gc_wbarrier_generic_store_internal (sp->data.p, sp [1].data.o);
3853 MINT_IN_BREAK;
3854 MINT_IN_CASE(MINT_STIND_I1)
3855 ++ip;
3856 sp -= 2;
3857 * (gint8 *) sp->data.p = (gint8)sp[1].data.i;
3858 MINT_IN_BREAK;
3859 MINT_IN_CASE(MINT_STIND_I2)
3860 ++ip;
3861 sp -= 2;
3862 * (gint16 *) sp->data.p = (gint16)sp[1].data.i;
3863 MINT_IN_BREAK;
3864 MINT_IN_CASE(MINT_STIND_I4)
3865 ++ip;
3866 sp -= 2;
3867 * (gint32 *) sp->data.p = sp[1].data.i;
3868 MINT_IN_BREAK;
3869 MINT_IN_CASE(MINT_STIND_I)
3870 ++ip;
3871 sp -= 2;
3872 * (mono_i *) sp->data.p = (mono_i)sp[1].data.p;
3873 MINT_IN_BREAK;
3874 MINT_IN_CASE(MINT_STIND_I8)
3875 ++ip;
3876 sp -= 2;
3877 * (gint64 *) sp->data.p = sp[1].data.l;
3878 MINT_IN_BREAK;
3879 MINT_IN_CASE(MINT_STIND_R4)
3880 ++ip;
3881 sp -= 2;
3882 * (float *) sp->data.p = sp[1].data.f_r4;
3883 MINT_IN_BREAK;
3884 MINT_IN_CASE(MINT_STIND_R8)
3885 ++ip;
3886 sp -= 2;
3887 * (double *) sp->data.p = sp[1].data.f;
3888 MINT_IN_BREAK;
3889 MINT_IN_CASE(MINT_MONO_ATOMIC_STORE_I4)
3890 ++ip;
3891 sp -= 2;
3892 mono_atomic_store_i32 ((gint32 *) sp->data.p, sp [1].data.i);
3893 MINT_IN_BREAK;
3894 #define BINOP(datamem, op) \
3895 --sp; \
3896 sp [-1].data.datamem = sp [-1].data.datamem op sp [0].data.datamem; \
3897 ++ip;
3898 MINT_IN_CASE(MINT_ADD_I4)
3899 BINOP(i, +);
3900 MINT_IN_BREAK;
3901 MINT_IN_CASE(MINT_ADD_I8)
3902 BINOP(l, +);
3903 MINT_IN_BREAK;
3904 MINT_IN_CASE(MINT_ADD_R4)
3905 BINOP(f_r4, +);
3906 MINT_IN_BREAK;
3907 MINT_IN_CASE(MINT_ADD_R8)
3908 BINOP(f, +);
3909 MINT_IN_BREAK;
3910 MINT_IN_CASE(MINT_ADD1_I4)
3911 ++sp [-1].data.i;
3912 ++ip;
3913 MINT_IN_BREAK;
3914 MINT_IN_CASE(MINT_ADD1_I8)
3915 ++sp [-1].data.l;
3916 ++ip;
3917 MINT_IN_BREAK;
3918 MINT_IN_CASE(MINT_SUB_I4)
3919 BINOP(i, -);
3920 MINT_IN_BREAK;
3921 MINT_IN_CASE(MINT_SUB_I8)
3922 BINOP(l, -);
3923 MINT_IN_BREAK;
3924 MINT_IN_CASE(MINT_SUB_R4)
3925 BINOP(f_r4, -);
3926 MINT_IN_BREAK;
3927 MINT_IN_CASE(MINT_SUB_R8)
3928 BINOP(f, -);
3929 MINT_IN_BREAK;
3930 MINT_IN_CASE(MINT_SUB1_I4)
3931 --sp [-1].data.i;
3932 ++ip;
3933 MINT_IN_BREAK;
3934 MINT_IN_CASE(MINT_SUB1_I8)
3935 --sp [-1].data.l;
3936 ++ip;
3937 MINT_IN_BREAK;
3938 MINT_IN_CASE(MINT_MUL_I4)
3939 BINOP(i, *);
3940 MINT_IN_BREAK;
3941 MINT_IN_CASE(MINT_MUL_I8)
3942 BINOP(l, *);
3943 MINT_IN_BREAK;
3944 MINT_IN_CASE(MINT_MUL_R4)
3945 BINOP(f_r4, *);
3946 MINT_IN_BREAK;
3947 MINT_IN_CASE(MINT_MUL_R8)
3948 BINOP(f, *);
3949 MINT_IN_BREAK;
3950 MINT_IN_CASE(MINT_DIV_I4)
3951 if (sp [-1].data.i == 0)
3952 THROW_EX (mono_get_exception_divide_by_zero (), ip);
3953 if (sp [-1].data.i == (-1) && sp [-2].data.i == G_MININT32)
3954 THROW_EX (mono_get_exception_overflow (), ip);
3955 BINOP(i, /);
3956 MINT_IN_BREAK;
3957 MINT_IN_CASE(MINT_DIV_I8)
3958 if (sp [-1].data.l == 0)
3959 THROW_EX (mono_get_exception_divide_by_zero (), ip);
3960 if (sp [-1].data.l == (-1) && sp [-2].data.l == G_MININT64)
3961 THROW_EX (mono_get_exception_overflow (), ip);
3962 BINOP(l, /);
3963 MINT_IN_BREAK;
3964 MINT_IN_CASE(MINT_DIV_R4)
3965 BINOP(f_r4, /);
3966 MINT_IN_BREAK;
3967 MINT_IN_CASE(MINT_DIV_R8)
3968 BINOP(f, /);
3969 MINT_IN_BREAK;
3971 #define BINOP_CAST(datamem, op, type) \
3972 --sp; \
3973 sp [-1].data.datamem = (type)sp [-1].data.datamem op (type)sp [0].data.datamem; \
3974 ++ip;
3975 MINT_IN_CASE(MINT_DIV_UN_I4)
3976 if (sp [-1].data.i == 0)
3977 THROW_EX (mono_get_exception_divide_by_zero (), ip);
3978 BINOP_CAST(i, /, guint32);
3979 MINT_IN_BREAK;
3980 MINT_IN_CASE(MINT_DIV_UN_I8)
3981 if (sp [-1].data.l == 0)
3982 THROW_EX (mono_get_exception_divide_by_zero (), ip);
3983 BINOP_CAST(l, /, guint64);
3984 MINT_IN_BREAK;
3985 MINT_IN_CASE(MINT_REM_I4)
3986 if (sp [-1].data.i == 0)
3987 THROW_EX (mono_get_exception_divide_by_zero (), ip);
3988 if (sp [-1].data.i == (-1) && sp [-2].data.i == G_MININT32)
3989 THROW_EX (mono_get_exception_overflow (), ip);
3990 BINOP(i, %);
3991 MINT_IN_BREAK;
3992 MINT_IN_CASE(MINT_REM_I8)
3993 if (sp [-1].data.l == 0)
3994 THROW_EX (mono_get_exception_divide_by_zero (), ip);
3995 if (sp [-1].data.l == (-1) && sp [-2].data.l == G_MININT64)
3996 THROW_EX (mono_get_exception_overflow (), ip);
3997 BINOP(l, %);
3998 MINT_IN_BREAK;
3999 MINT_IN_CASE(MINT_REM_R4)
4000 /* FIXME: what do we actually do here? */
4001 --sp;
4002 sp [-1].data.f_r4 = fmodf (sp [-1].data.f_r4, sp [0].data.f_r4);
4003 ++ip;
4004 MINT_IN_BREAK;
4005 MINT_IN_CASE(MINT_REM_R8)
4006 /* FIXME: what do we actually do here? */
4007 --sp;
4008 sp [-1].data.f = fmod (sp [-1].data.f, sp [0].data.f);
4009 ++ip;
4010 MINT_IN_BREAK;
4011 MINT_IN_CASE(MINT_REM_UN_I4)
4012 if (sp [-1].data.i == 0)
4013 THROW_EX (mono_get_exception_divide_by_zero (), ip);
4014 BINOP_CAST(i, %, guint32);
4015 MINT_IN_BREAK;
4016 MINT_IN_CASE(MINT_REM_UN_I8)
4017 if (sp [-1].data.l == 0)
4018 THROW_EX (mono_get_exception_divide_by_zero (), ip);
4019 BINOP_CAST(l, %, guint64);
4020 MINT_IN_BREAK;
4021 MINT_IN_CASE(MINT_AND_I4)
4022 BINOP(i, &);
4023 MINT_IN_BREAK;
4024 MINT_IN_CASE(MINT_AND_I8)
4025 BINOP(l, &);
4026 MINT_IN_BREAK;
4027 MINT_IN_CASE(MINT_OR_I4)
4028 BINOP(i, |);
4029 MINT_IN_BREAK;
4030 MINT_IN_CASE(MINT_OR_I8)
4031 BINOP(l, |);
4032 MINT_IN_BREAK;
4033 MINT_IN_CASE(MINT_XOR_I4)
4034 BINOP(i, ^);
4035 MINT_IN_BREAK;
4036 MINT_IN_CASE(MINT_XOR_I8)
4037 BINOP(l, ^);
4038 MINT_IN_BREAK;
4040 #define SHIFTOP(datamem, op) \
4041 --sp; \
4042 sp [-1].data.datamem = sp [-1].data.datamem op sp [0].data.i; \
4043 ++ip;
4045 MINT_IN_CASE(MINT_SHL_I4)
4046 SHIFTOP(i, <<);
4047 MINT_IN_BREAK;
4048 MINT_IN_CASE(MINT_SHL_I8)
4049 SHIFTOP(l, <<);
4050 MINT_IN_BREAK;
4051 MINT_IN_CASE(MINT_SHR_I4)
4052 SHIFTOP(i, >>);
4053 MINT_IN_BREAK;
4054 MINT_IN_CASE(MINT_SHR_I8)
4055 SHIFTOP(l, >>);
4056 MINT_IN_BREAK;
4057 MINT_IN_CASE(MINT_SHR_UN_I4)
4058 --sp;
4059 sp [-1].data.i = (guint32)sp [-1].data.i >> sp [0].data.i;
4060 ++ip;
4061 MINT_IN_BREAK;
4062 MINT_IN_CASE(MINT_SHR_UN_I8)
4063 --sp;
4064 sp [-1].data.l = (guint64)sp [-1].data.l >> sp [0].data.i;
4065 ++ip;
4066 MINT_IN_BREAK;
4067 MINT_IN_CASE(MINT_NEG_I4)
4068 sp [-1].data.i = - sp [-1].data.i;
4069 ++ip;
4070 MINT_IN_BREAK;
4071 MINT_IN_CASE(MINT_NEG_I8)
4072 sp [-1].data.l = - sp [-1].data.l;
4073 ++ip;
4074 MINT_IN_BREAK;
4075 MINT_IN_CASE(MINT_NEG_R4)
4076 sp [-1].data.f_r4 = - sp [-1].data.f_r4;
4077 ++ip;
4078 MINT_IN_BREAK;
4079 MINT_IN_CASE(MINT_NEG_R8)
4080 sp [-1].data.f = - sp [-1].data.f;
4081 ++ip;
4082 MINT_IN_BREAK;
4083 MINT_IN_CASE(MINT_NOT_I4)
4084 sp [-1].data.i = ~ sp [-1].data.i;
4085 ++ip;
4086 MINT_IN_BREAK;
4087 MINT_IN_CASE(MINT_NOT_I8)
4088 sp [-1].data.l = ~ sp [-1].data.l;
4089 ++ip;
4090 MINT_IN_BREAK;
4091 MINT_IN_CASE(MINT_CONV_I1_I4)
4092 sp [-1].data.i = (gint8)sp [-1].data.i;
4093 ++ip;
4094 MINT_IN_BREAK;
4095 MINT_IN_CASE(MINT_CONV_I1_I8)
4096 sp [-1].data.i = (gint8)sp [-1].data.l;
4097 ++ip;
4098 MINT_IN_BREAK;
4099 MINT_IN_CASE(MINT_CONV_I1_R4)
4100 sp [-1].data.i = (gint8) (gint32) sp [-1].data.f_r4;
4101 ++ip;
4102 MINT_IN_BREAK;
4103 MINT_IN_CASE(MINT_CONV_I1_R8)
4104 /* without gint32 cast, C compiler is allowed to use undefined
4105 * behaviour if data.f is bigger than >255. See conv.fpint section
4106 * in C standard:
4107 * > The conversion truncates; that is, the fractional part
4108 * > is discarded. The behavior is undefined if the truncated
4109 * > value cannot be represented in the destination type.
4110 * */
4111 sp [-1].data.i = (gint8) (gint32) sp [-1].data.f;
4112 ++ip;
4113 MINT_IN_BREAK;
4114 MINT_IN_CASE(MINT_CONV_U1_I4)
4115 sp [-1].data.i = (guint8)sp [-1].data.i;
4116 ++ip;
4117 MINT_IN_BREAK;
4118 MINT_IN_CASE(MINT_CONV_U1_I8)
4119 sp [-1].data.i = (guint8)sp [-1].data.l;
4120 ++ip;
4121 MINT_IN_BREAK;
4122 MINT_IN_CASE(MINT_CONV_U1_R4)
4123 sp [-1].data.i = (guint8) (guint32) sp [-1].data.f_r4;
4124 ++ip;
4125 MINT_IN_BREAK;
4126 MINT_IN_CASE(MINT_CONV_U1_R8)
4127 sp [-1].data.i = (guint8) (guint32) sp [-1].data.f;
4128 ++ip;
4129 MINT_IN_BREAK;
4130 MINT_IN_CASE(MINT_CONV_I2_I4)
4131 sp [-1].data.i = (gint16)sp [-1].data.i;
4132 ++ip;
4133 MINT_IN_BREAK;
4134 MINT_IN_CASE(MINT_CONV_I2_I8)
4135 sp [-1].data.i = (gint16)sp [-1].data.l;
4136 ++ip;
4137 MINT_IN_BREAK;
4138 MINT_IN_CASE(MINT_CONV_I2_R4)
4139 sp [-1].data.i = (gint16) (gint32) sp [-1].data.f_r4;
4140 ++ip;
4141 MINT_IN_BREAK;
4142 MINT_IN_CASE(MINT_CONV_I2_R8)
4143 sp [-1].data.i = (gint16) (gint32) sp [-1].data.f;
4144 ++ip;
4145 MINT_IN_BREAK;
4146 MINT_IN_CASE(MINT_CONV_U2_I4)
4147 sp [-1].data.i = (guint16)sp [-1].data.i;
4148 ++ip;
4149 MINT_IN_BREAK;
4150 MINT_IN_CASE(MINT_CONV_U2_I8)
4151 sp [-1].data.i = (guint16)sp [-1].data.l;
4152 ++ip;
4153 MINT_IN_BREAK;
4154 MINT_IN_CASE(MINT_CONV_U2_R4)
4155 sp [-1].data.i = (guint16) (guint32) sp [-1].data.f_r4;
4156 ++ip;
4157 MINT_IN_BREAK;
4158 MINT_IN_CASE(MINT_CONV_U2_R8)
4159 sp [-1].data.i = (guint16) (guint32) sp [-1].data.f;
4160 ++ip;
4161 MINT_IN_BREAK;
4162 MINT_IN_CASE(MINT_CONV_I4_R4)
4163 sp [-1].data.i = (gint32) sp [-1].data.f_r4;
4164 ++ip;
4165 MINT_IN_BREAK;
4166 MINT_IN_CASE(MINT_CONV_I4_R8)
4167 sp [-1].data.i = (gint32)sp [-1].data.f;
4168 ++ip;
4169 MINT_IN_BREAK;
4170 MINT_IN_CASE(MINT_CONV_U4_I8)
4171 MINT_IN_CASE(MINT_CONV_I4_I8)
4172 sp [-1].data.i = (gint32)sp [-1].data.l;
4173 ++ip;
4174 MINT_IN_BREAK;
4175 MINT_IN_CASE(MINT_CONV_I4_I8_SP)
4176 sp [-2].data.i = (gint32)sp [-2].data.l;
4177 ++ip;
4178 MINT_IN_BREAK;
4179 MINT_IN_CASE(MINT_CONV_U4_R4)
4180 /* needed on arm64 */
4181 if (isinf (sp [-1].data.f_r4))
4182 sp [-1].data.i = 0;
4183 /* needed by wasm */
4184 else if (isnan (sp [-1].data.f_r4))
4185 sp [-1].data.i = 0;
4186 else
4187 sp [-1].data.i = (guint32) sp [-1].data.f_r4;
4188 ++ip;
4189 MINT_IN_BREAK;
4190 MINT_IN_CASE(MINT_CONV_U4_R8)
4191 /* needed on arm64 */
4192 if (mono_isinf (sp [-1].data.f))
4193 sp [-1].data.i = 0;
4194 /* needed by wasm */
4195 else if (isnan (sp [-1].data.f))
4196 sp [-1].data.i = 0;
4197 else
4198 sp [-1].data.i = (guint32)sp [-1].data.f;
4199 ++ip;
4200 MINT_IN_BREAK;
4201 MINT_IN_CASE(MINT_CONV_I8_I4)
4202 sp [-1].data.l = sp [-1].data.i;
4203 ++ip;
4204 MINT_IN_BREAK;
4205 MINT_IN_CASE(MINT_CONV_I8_I4_SP)
4206 sp [-2].data.l = sp [-2].data.i;
4207 ++ip;
4208 MINT_IN_BREAK;
4209 MINT_IN_CASE(MINT_CONV_I8_U4)
4210 sp [-1].data.l = (guint32)sp [-1].data.i;
4211 ++ip;
4212 MINT_IN_BREAK;
4213 MINT_IN_CASE(MINT_CONV_I8_R4)
4214 sp [-1].data.l = (gint64) sp [-1].data.f_r4;
4215 ++ip;
4216 MINT_IN_BREAK;
4217 MINT_IN_CASE(MINT_CONV_I8_R8)
4218 sp [-1].data.l = (gint64)sp [-1].data.f;
4219 ++ip;
4220 MINT_IN_BREAK;
4221 MINT_IN_CASE(MINT_CONV_R4_I4)
4222 sp [-1].data.f_r4 = (float)sp [-1].data.i;
4223 ++ip;
4224 MINT_IN_BREAK;
4225 MINT_IN_CASE(MINT_CONV_R4_I8)
4226 sp [-1].data.f_r4 = (float)sp [-1].data.l;
4227 ++ip;
4228 MINT_IN_BREAK;
4229 MINT_IN_CASE(MINT_CONV_R4_R8)
4230 sp [-1].data.f_r4 = (float)sp [-1].data.f;
4231 ++ip;
4232 MINT_IN_BREAK;
4233 MINT_IN_CASE(MINT_CONV_R8_I4)
4234 sp [-1].data.f = (double)sp [-1].data.i;
4235 ++ip;
4236 MINT_IN_BREAK;
4237 MINT_IN_CASE(MINT_CONV_R8_I8)
4238 sp [-1].data.f = (double)sp [-1].data.l;
4239 ++ip;
4240 MINT_IN_BREAK;
4241 MINT_IN_CASE(MINT_CONV_R8_R4)
4242 sp [-1].data.f = (double) sp [-1].data.f_r4;
4243 ++ip;
4244 MINT_IN_BREAK;
4245 MINT_IN_CASE(MINT_CONV_R8_R4_SP)
4246 sp [-2].data.f = (double) sp [-2].data.f_r4;
4247 ++ip;
4248 MINT_IN_BREAK;
4249 MINT_IN_CASE(MINT_CONV_U8_I4)
4250 sp [-1].data.l = sp [-1].data.i & 0xffffffff;
4251 ++ip;
4252 MINT_IN_BREAK;
4253 MINT_IN_CASE(MINT_CONV_U8_R4)
4254 sp [-1].data.l = (guint64) sp [-1].data.f_r4;
4255 ++ip;
4256 MINT_IN_BREAK;
4257 MINT_IN_CASE(MINT_CONV_U8_R8)
4258 sp [-1].data.l = (guint64)sp [-1].data.f;
4259 ++ip;
4260 MINT_IN_BREAK;
4261 MINT_IN_CASE(MINT_CPOBJ) {
4262 c = (MonoClass*)rtm->data_items[* (guint16 *)(ip + 1)];
4263 g_assert (m_class_is_valuetype (c));
4264 /* if this assertion fails, we need to add a write barrier */
4265 g_assert (!MONO_TYPE_IS_REFERENCE (m_class_get_byval_arg (c)));
4266 stackval_from_data (m_class_get_byval_arg (c), (stackval*)sp [-2].data.p, sp [-1].data.p, FALSE);
4267 ip += 2;
4268 sp -= 2;
4269 MINT_IN_BREAK;
4271 MINT_IN_CASE(MINT_CPOBJ_VT) {
4272 c = (MonoClass*)rtm->data_items[* (guint16 *)(ip + 1)];
4273 g_assert (m_class_is_valuetype (c));
4274 /* if this assertion fails, we need to add a write barrier */
4275 g_assert (!MONO_TYPE_IS_REFERENCE (m_class_get_byval_arg (c)));
4276 stackval_from_data (m_class_get_byval_arg (c), &sp [-2], sp [-1].data.p, FALSE);
4277 ip += 2;
4278 sp -= 2;
4279 MINT_IN_BREAK;
4281 MINT_IN_CASE(MINT_LDOBJ) {
4282 void *p;
4283 c = (MonoClass*)rtm->data_items[* (guint16 *)(ip + 1)];
4284 ip += 2;
4285 p = sp [-1].data.p;
4286 stackval_from_data (m_class_get_byval_arg (c), &sp [-1], p, FALSE);
4287 MINT_IN_BREAK;
4289 MINT_IN_CASE(MINT_LDOBJ_VT) {
4290 void *p;
4291 c = (MonoClass*)rtm->data_items[* (guint16 *)(ip + 1)];
4292 ip += 2;
4293 p = sp [-1].data.p;
4294 if (!m_class_is_enumtype (c)) {
4295 int size = mono_class_value_size (c, NULL);
4296 sp [-1].data.p = vt_sp;
4297 vt_sp += ALIGN_TO (size, MINT_VT_ALIGNMENT);
4299 stackval_from_data (m_class_get_byval_arg (c), &sp [-1], p, FALSE);
4300 MINT_IN_BREAK;
4302 MINT_IN_CASE(MINT_LDSTR)
4303 sp->data.p = rtm->data_items [* (guint16 *)(ip + 1)];
4304 ++sp;
4305 ip += 2;
4306 MINT_IN_BREAK;
4307 MINT_IN_CASE(MINT_LDSTR_TOKEN) {
4308 MonoString *s = NULL;
4309 guint32 strtoken = (guint32)(gsize)rtm->data_items [* (guint16 *)(ip + 1)];
4311 MonoMethod *method = frame->imethod->method;
4312 if (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD) {
4313 s = (MonoString*)mono_method_get_wrapper_data (method, strtoken);
4314 } else if (method->wrapper_type != MONO_WRAPPER_NONE) {
4315 s = mono_string_new_wrapper_internal ((const char*)mono_method_get_wrapper_data (method, strtoken));
4316 } else {
4317 g_assert_not_reached ();
4319 sp->data.p = s;
4320 ++sp;
4321 ip += 2;
4322 MINT_IN_BREAK;
4324 MINT_IN_CASE(MINT_NEWOBJ_ARRAY) {
4325 MonoClass *newobj_class;
4326 InterpMethod *imethod;
4327 guint32 token = * (guint16 *)(ip + 1);
4328 guint16 param_count = * (guint16 *)(ip + 2);
4330 imethod = (InterpMethod*) rtm->data_items [token];
4331 newobj_class = imethod->method->klass;
4333 sp -= param_count;
4334 sp->data.p = ves_array_create (rtm->domain, newobj_class, param_count, sp, error);
4335 if (!mono_error_ok (error))
4336 THROW_EX (mono_error_convert_to_exception (error), ip);
4338 ++sp;
4339 ip += 3;
4340 MINT_IN_BREAK;
4342 MINT_IN_CASE(MINT_NEWOBJ_FAST)
4343 MINT_IN_CASE(MINT_NEWOBJ_VT_FAST)
4344 MINT_IN_CASE(MINT_NEWOBJ_VTST_FAST) {
4345 guint16 param_count;
4346 gboolean vt = *ip != MINT_NEWOBJ_FAST;
4347 stackval valuetype_this;
4349 frame->ip = ip;
4351 child_frame.imethod = (InterpMethod*) rtm->data_items [*(guint16*)(ip + 1)];
4352 param_count = *(guint16*)(ip + 2);
4354 if (param_count) {
4355 sp -= param_count;
4356 memmove (sp + 1, sp, param_count * sizeof (stackval));
4358 child_frame.stack_args = sp;
4360 if (vt) {
4361 gboolean vtst = *ip == MINT_NEWOBJ_VTST_FAST;
4362 if (vtst) {
4363 memset (vt_sp, 0, *(guint16*)(ip + 3));
4364 sp->data.p = vt_sp;
4365 valuetype_this.data.p = vt_sp;
4366 ip += 4;
4367 } else {
4368 memset (&valuetype_this, 0, sizeof (stackval));
4369 sp->data.p = &valuetype_this;
4370 ip += 3;
4372 } else {
4373 MonoVTable *vtable = (MonoVTable*) rtm->data_items [*(guint16*)(ip + 3)];
4374 if (G_UNLIKELY (!vtable->initialized)) {
4375 mono_runtime_class_init_full (vtable, error);
4376 if (!mono_error_ok (error))
4377 THROW_EX (mono_error_convert_to_exception (error), ip);
4379 o = mono_gc_alloc_obj (vtable, m_class_get_instance_size (vtable->klass));
4380 if (G_UNLIKELY (!o)) {
4381 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", m_class_get_instance_size (vtable->klass));
4382 THROW_EX (mono_error_convert_to_exception (error), ip);
4384 sp->data.p = o;
4385 ip += 4;
4388 interp_exec_method (&child_frame, context);
4390 CHECK_RESUME_STATE (context);
4392 if (vt)
4393 *sp = valuetype_this;
4394 else
4395 sp->data.p = o;
4396 ++sp;
4397 MINT_IN_BREAK;
4399 MINT_IN_CASE(MINT_NEWOBJ) {
4400 MonoClass *newobj_class;
4401 MonoMethodSignature *csig;
4402 stackval valuetype_this;
4403 guint32 token;
4404 stackval retval;
4406 frame->ip = ip;
4408 token = * (guint16 *)(ip + 1);
4409 ip += 2;
4411 child_frame.ip = NULL;
4412 child_frame.ex = NULL;
4414 child_frame.imethod = (InterpMethod*)rtm->data_items [token];
4415 csig = mono_method_signature_internal (child_frame.imethod->method);
4416 newobj_class = child_frame.imethod->method->klass;
4417 /*if (profiling_classes) {
4418 guint count = GPOINTER_TO_UINT (g_hash_table_lookup (profiling_classes, newobj_class));
4419 count++;
4420 g_hash_table_insert (profiling_classes, newobj_class, GUINT_TO_POINTER (count));
4423 g_assert (csig->hasthis);
4424 if (csig->param_count) {
4425 sp -= csig->param_count;
4426 memmove (sp + 1, sp, csig->param_count * sizeof (stackval));
4428 child_frame.stack_args = sp;
4431 * First arg is the object.
4433 if (m_class_is_valuetype (newobj_class)) {
4434 MonoType *t = m_class_get_byval_arg (newobj_class);
4435 memset (&valuetype_this, 0, sizeof (stackval));
4436 if (!m_class_is_enumtype (newobj_class) && (t->type == MONO_TYPE_VALUETYPE || (t->type == MONO_TYPE_GENERICINST && mono_type_generic_inst_is_valuetype (t)))) {
4437 sp->data.p = vt_sp;
4438 valuetype_this.data.p = vt_sp;
4439 } else {
4440 sp->data.p = &valuetype_this;
4442 } else {
4443 if (newobj_class != mono_defaults.string_class) {
4444 MonoVTable *vtable = mono_class_vtable_checked (rtm->domain, newobj_class, error);
4445 if (!mono_error_ok (error) || !mono_runtime_class_init_full (vtable, error))
4446 THROW_EX (mono_error_convert_to_exception (error), ip);
4447 o = mono_object_new_checked (rtm->domain, newobj_class, error);
4448 mono_error_cleanup (error); /* FIXME: don't swallow the error */
4449 EXCEPTION_CHECKPOINT;
4450 sp->data.p = o;
4451 #ifndef DISABLE_REMOTING
4452 if (mono_object_is_transparent_proxy (o)) {
4453 MonoMethod *remoting_invoke_method = mono_marshal_get_remoting_invoke_with_check (child_frame.imethod->method, error);
4454 mono_error_assert_ok (error);
4455 child_frame.imethod = mono_interp_get_imethod (rtm->domain, remoting_invoke_method, error);
4456 mono_error_assert_ok (error);
4458 #endif
4459 } else {
4460 sp->data.p = NULL;
4461 child_frame.retval = &retval;
4465 interp_exec_method (&child_frame, context);
4467 CHECK_RESUME_STATE (context);
4470 * a constructor returns void, but we need to return the object we created
4472 if (m_class_is_valuetype (newobj_class) && !m_class_is_enumtype (newobj_class)) {
4473 *sp = valuetype_this;
4474 } else if (newobj_class == mono_defaults.string_class) {
4475 *sp = retval;
4476 } else {
4477 sp->data.p = o;
4479 ++sp;
4480 MINT_IN_BREAK;
4482 MINT_IN_CASE(MINT_NEWOBJ_MAGIC) {
4483 frame->ip = ip;
4484 ip += 2;
4486 MINT_IN_BREAK;
4488 MINT_IN_CASE(MINT_INTRINS_BYREFERENCE_CTOR) {
4489 MonoMethodSignature *csig;
4490 guint32 token;
4492 frame->ip = ip;
4493 token = * (guint16 *)(ip + 1);
4494 ip += 2;
4496 InterpMethod *cmethod = (InterpMethod*)rtm->data_items [token];
4497 csig = mono_method_signature_internal (cmethod->method);
4499 g_assert (csig->hasthis);
4500 sp -= csig->param_count;
4502 gpointer arg0 = sp [0].data.p;
4504 gpointer *byreference_this = (gpointer*)vt_sp;
4505 *byreference_this = arg0;
4507 /* Followed by a VTRESULT opcode which will push the result on the stack */
4508 ++sp;
4509 MINT_IN_BREAK;
4510 break;
4512 MINT_IN_CASE(MINT_INTRINS_BYREFERENCE_GET_VALUE) {
4513 gpointer *byreference_this = (gpointer*)sp [-1].data.p;
4514 sp [-1].data.p = *byreference_this;
4515 ++ip;
4516 MINT_IN_BREAK;
4517 break;
4519 MINT_IN_CASE(MINT_CASTCLASS)
4520 c = (MonoClass*)rtm->data_items [*(guint16 *)(ip + 1)];
4521 if ((o = sp [-1].data.o)) {
4522 MonoObject *isinst_obj = mono_object_isinst_checked (o, c, error);
4523 mono_error_cleanup (error); /* FIXME: don't swallow the error */
4524 if (!isinst_obj)
4525 THROW_EX (mono_get_exception_invalid_cast (), ip);
4527 ip += 2;
4528 MINT_IN_BREAK;
4529 MINT_IN_CASE(MINT_ISINST)
4530 c = (MonoClass*)rtm->data_items [*(guint16 *)(ip + 1)];
4531 if ((o = sp [-1].data.o)) {
4532 MonoObject *isinst_obj = mono_object_isinst_checked (o, c, error);
4533 mono_error_cleanup (error); /* FIXME: don't swallow the error */
4534 if (!isinst_obj)
4535 sp [-1].data.p = NULL;
4537 ip += 2;
4538 MINT_IN_BREAK;
4539 MINT_IN_CASE(MINT_CONV_R_UN_I4)
4540 sp [-1].data.f = (double)(guint32)sp [-1].data.i;
4541 ++ip;
4542 MINT_IN_BREAK;
4543 MINT_IN_CASE(MINT_CONV_R_UN_I8)
4544 sp [-1].data.f = (double)(guint64)sp [-1].data.l;
4545 ++ip;
4546 MINT_IN_BREAK;
4547 MINT_IN_CASE(MINT_UNBOX)
4548 c = (MonoClass*)rtm->data_items[*(guint16 *)(ip + 1)];
4550 o = sp [-1].data.o;
4551 if (!o)
4552 THROW_EX (mono_get_exception_null_reference (), ip);
4554 MonoObject *isinst_obj;
4555 isinst_obj = mono_object_isinst_checked (o, c, error);
4556 mono_error_cleanup (error); /* FIXME: don't swallow the error */
4557 if (!(isinst_obj || ((m_class_get_rank (o->vtable->klass) == 0) && (m_class_get_element_class (o->vtable->klass) == m_class_get_element_class (c)))))
4558 THROW_EX (mono_get_exception_invalid_cast (), ip);
4560 sp [-1].data.p = mono_object_unbox_internal (o);
4561 ip += 2;
4562 MINT_IN_BREAK;
4563 MINT_IN_CASE(MINT_THROW)
4564 --sp;
4565 if (!sp->data.p)
4566 sp->data.p = mono_get_exception_null_reference ();
4568 THROW_EX ((MonoException *)sp->data.p, ip);
4569 MINT_IN_BREAK;
4570 MINT_IN_CASE(MINT_CHECKPOINT)
4571 /* Do synchronous checking of abort requests */
4572 EXCEPTION_CHECKPOINT;
4573 ++ip;
4574 MINT_IN_BREAK;
4575 MINT_IN_CASE(MINT_SAFEPOINT)
4576 /* Do synchronous checking of abort requests */
4577 EXCEPTION_CHECKPOINT;
4578 /* Poll safepoint */
4579 mono_threads_safepoint ();
4580 ++ip;
4581 MINT_IN_BREAK;
4582 MINT_IN_CASE(MINT_LDFLDA_UNSAFE)
4583 o = sp [-1].data.o;
4584 sp[-1].data.p = (char *)o + * (guint16 *)(ip + 1);
4585 ip += 2;
4586 MINT_IN_BREAK;
4587 MINT_IN_CASE(MINT_LDFLDA)
4588 o = sp [-1].data.o;
4589 if (!o)
4590 THROW_EX (mono_get_exception_null_reference (), ip);
4591 sp[-1].data.p = (char *)o + * (guint16 *)(ip + 1);
4592 ip += 2;
4593 MINT_IN_BREAK;
4594 MINT_IN_CASE(MINT_CKNULL)
4595 o = sp [-1].data.o;
4596 if (!o)
4597 THROW_EX (mono_get_exception_null_reference (), ip);
4598 ++ip;
4599 MINT_IN_BREAK;
4600 MINT_IN_CASE(MINT_CKNULL_N) {
4601 /* Same as CKNULL, but further down the stack */
4602 int n = *(guint16*)(ip + 1);
4603 o = sp [-n].data.o;
4604 if (!o)
4605 THROW_EX (mono_get_exception_null_reference (), ip);
4606 ip += 2;
4607 MINT_IN_BREAK;
4610 #define LDFLD(datamem, fieldtype) \
4611 o = sp [-1].data.o; \
4612 if (!o) \
4613 THROW_EX (mono_get_exception_null_reference (), ip); \
4614 sp[-1].data.datamem = * (fieldtype *)((char *)o + * (guint16 *)(ip + 1)) ; \
4615 ip += 2;
4617 MINT_IN_CASE(MINT_LDFLD_I1) LDFLD(i, gint8); MINT_IN_BREAK;
4618 MINT_IN_CASE(MINT_LDFLD_U1) LDFLD(i, guint8); MINT_IN_BREAK;
4619 MINT_IN_CASE(MINT_LDFLD_I2) LDFLD(i, gint16); MINT_IN_BREAK;
4620 MINT_IN_CASE(MINT_LDFLD_U2) LDFLD(i, guint16); MINT_IN_BREAK;
4621 MINT_IN_CASE(MINT_LDFLD_I4) LDFLD(i, gint32); MINT_IN_BREAK;
4622 MINT_IN_CASE(MINT_LDFLD_I8) LDFLD(l, gint64); MINT_IN_BREAK;
4623 MINT_IN_CASE(MINT_LDFLD_R4) LDFLD(f_r4, float); MINT_IN_BREAK;
4624 MINT_IN_CASE(MINT_LDFLD_R8) LDFLD(f, double); MINT_IN_BREAK;
4625 MINT_IN_CASE(MINT_LDFLD_O) LDFLD(p, gpointer); MINT_IN_BREAK;
4626 MINT_IN_CASE(MINT_LDFLD_P) LDFLD(p, gpointer); MINT_IN_BREAK;
4628 MINT_IN_CASE(MINT_LDFLD_VT) {
4629 o = sp [-1].data.o;
4630 if (!o)
4631 THROW_EX (mono_get_exception_null_reference (), ip);
4633 MonoClassField *field = (MonoClassField*)rtm->data_items[* (guint16 *)(ip + 2)];
4634 MonoClass *klass = mono_class_from_mono_type_internal (field->type);
4635 i32 = mono_class_value_size (klass, NULL);
4637 sp [-1].data.p = vt_sp;
4638 memcpy (sp [-1].data.p, (char *)o + * (guint16 *)(ip + 1), i32);
4639 vt_sp += ALIGN_TO (i32, MINT_VT_ALIGNMENT);
4640 ip += 3;
4641 MINT_IN_BREAK;
4644 MINT_IN_CASE(MINT_LDRMFLD) {
4645 MonoClassField *field;
4646 char *addr;
4648 o = sp [-1].data.o;
4649 if (!o)
4650 THROW_EX (mono_get_exception_null_reference (), ip);
4651 field = (MonoClassField*)rtm->data_items[* (guint16 *)(ip + 1)];
4652 ip += 2;
4653 #ifndef DISABLE_REMOTING
4654 if (mono_object_is_transparent_proxy (o)) {
4655 gpointer tmp;
4656 MonoClass *klass = ((MonoTransparentProxy*)o)->remote_class->proxy_class;
4658 addr = (char*)mono_load_remote_field_checked (o, klass, field, &tmp, error);
4659 mono_error_cleanup (error); /* FIXME: don't swallow the error */
4660 } else
4661 #endif
4662 addr = (char*)o + field->offset;
4664 stackval_from_data (field->type, &sp [-1], addr, FALSE);
4665 MINT_IN_BREAK;
4668 MINT_IN_CASE(MINT_LDRMFLD_VT) {
4669 MonoClassField *field;
4670 char *addr;
4672 o = sp [-1].data.o;
4673 if (!o)
4674 THROW_EX (mono_get_exception_null_reference (), ip);
4676 field = (MonoClassField*)rtm->data_items[* (guint16 *)(ip + 1)];
4677 MonoClass *klass = mono_class_from_mono_type_internal (field->type);
4678 i32 = mono_class_value_size (klass, NULL);
4680 ip += 2;
4681 #ifndef DISABLE_REMOTING
4682 if (mono_object_is_transparent_proxy (o)) {
4683 gpointer tmp;
4684 MonoClass *klass = ((MonoTransparentProxy*)o)->remote_class->proxy_class;
4685 addr = (char*)mono_load_remote_field_checked (o, klass, field, &tmp, error);
4686 mono_error_cleanup (error); /* FIXME: don't swallow the error */
4687 } else
4688 #endif
4689 addr = (char*)o + field->offset;
4691 sp [-1].data.p = vt_sp;
4692 memcpy(sp [-1].data.p, (char *)o + * (guint16 *)(ip + 1), i32);
4693 vt_sp += ALIGN_TO (i32, MINT_VT_ALIGNMENT);
4694 memcpy(sp [-1].data.p, addr, i32);
4695 MINT_IN_BREAK;
4698 #define STFLD(datamem, fieldtype) \
4699 o = sp [-2].data.o; \
4700 if (!o) \
4701 THROW_EX (mono_get_exception_null_reference (), ip); \
4702 sp -= 2; \
4703 * (fieldtype *)((char *)o + * (guint16 *)(ip + 1)) = sp[1].data.datamem; \
4704 ip += 2;
4706 MINT_IN_CASE(MINT_STFLD_I1) STFLD(i, gint8); MINT_IN_BREAK;
4707 MINT_IN_CASE(MINT_STFLD_U1) STFLD(i, guint8); MINT_IN_BREAK;
4708 MINT_IN_CASE(MINT_STFLD_I2) STFLD(i, gint16); MINT_IN_BREAK;
4709 MINT_IN_CASE(MINT_STFLD_U2) STFLD(i, guint16); MINT_IN_BREAK;
4710 MINT_IN_CASE(MINT_STFLD_I4) STFLD(i, gint32); MINT_IN_BREAK;
4711 MINT_IN_CASE(MINT_STFLD_I8) STFLD(l, gint64); MINT_IN_BREAK;
4712 MINT_IN_CASE(MINT_STFLD_R4) STFLD(f_r4, float); MINT_IN_BREAK;
4713 MINT_IN_CASE(MINT_STFLD_R8) STFLD(f, double); MINT_IN_BREAK;
4714 MINT_IN_CASE(MINT_STFLD_P) STFLD(p, gpointer); MINT_IN_BREAK;
4715 MINT_IN_CASE(MINT_STFLD_O)
4716 o = sp [-2].data.o;
4717 if (!o)
4718 THROW_EX (mono_get_exception_null_reference (), ip);
4719 sp -= 2;
4720 mono_gc_wbarrier_set_field_internal (o, (char *) o + * (guint16 *)(ip + 1), sp [1].data.o);
4721 ip += 2;
4722 MINT_IN_BREAK;
4724 MINT_IN_CASE(MINT_STFLD_VT) {
4725 o = sp [-2].data.o;
4726 if (!o)
4727 THROW_EX (mono_get_exception_null_reference (), ip);
4728 sp -= 2;
4730 MonoClassField *field = (MonoClassField*)rtm->data_items[* (guint16 *)(ip + 2)];
4731 MonoClass *klass = mono_class_from_mono_type_internal (field->type);
4732 i32 = mono_class_value_size (klass, NULL);
4734 guint16 offset = * (guint16 *)(ip + 1);
4735 mono_value_copy_internal ((char *) o + offset, sp [1].data.p, klass);
4737 vt_sp -= ALIGN_TO (i32, MINT_VT_ALIGNMENT);
4738 ip += 3;
4739 MINT_IN_BREAK;
4741 MINT_IN_CASE(MINT_STRMFLD) {
4742 MonoClassField *field;
4744 o = sp [-2].data.o;
4745 if (!o)
4746 THROW_EX (mono_get_exception_null_reference (), ip);
4748 field = (MonoClassField*)rtm->data_items[* (guint16 *)(ip + 1)];
4749 ip += 2;
4751 #ifndef DISABLE_REMOTING
4752 if (mono_object_is_transparent_proxy (o)) {
4753 MonoClass *klass = ((MonoTransparentProxy*)o)->remote_class->proxy_class;
4754 mono_store_remote_field_checked (o, klass, field, &sp [-1].data, error);
4755 mono_error_cleanup (error); /* FIXME: don't swallow the error */
4756 } else
4757 #endif
4758 stackval_to_data (field->type, &sp [-1], (char*)o + field->offset, FALSE);
4760 sp -= 2;
4761 MINT_IN_BREAK;
4763 MINT_IN_CASE(MINT_STRMFLD_VT) {
4764 MonoClassField *field;
4766 o = sp [-2].data.o;
4767 if (!o)
4768 THROW_EX (mono_get_exception_null_reference (), ip);
4769 field = (MonoClassField*)rtm->data_items[* (guint16 *)(ip + 1)];
4770 MonoClass *klass = mono_class_from_mono_type_internal (field->type);
4771 i32 = mono_class_value_size (klass, NULL);
4772 ip += 2;
4774 #ifndef DISABLE_REMOTING
4775 if (mono_object_is_transparent_proxy (o)) {
4776 MonoClass *klass = ((MonoTransparentProxy*)o)->remote_class->proxy_class;
4777 mono_store_remote_field_checked (o, klass, field, &sp [-1].data, error);
4778 mono_error_cleanup (error); /* FIXME: don't swallow the error */
4779 } else
4780 #endif
4781 mono_value_copy_internal ((char *) o + field->offset, sp [-1].data.p, klass);
4783 sp -= 2;
4784 vt_sp -= ALIGN_TO (i32, MINT_VT_ALIGNMENT);
4785 MINT_IN_BREAK;
4787 MINT_IN_CASE(MINT_LDSFLDA) {
4788 MonoClassField *field = (MonoClassField*)rtm->data_items[*(guint16 *)(ip + 1)];
4789 sp->data.p = mono_class_static_field_address (rtm->domain, field);
4790 EXCEPTION_CHECKPOINT;
4791 ip += 2;
4792 ++sp;
4793 MINT_IN_BREAK;
4796 /* We init class here to preserve cctor order */
4797 #define LDSFLD(datamem, fieldtype) { \
4798 MonoVTable *vtable = (MonoVTable*) rtm->data_items [*(guint16*)(ip + 1)]; \
4799 if (G_UNLIKELY (!vtable->initialized)) { \
4800 mono_runtime_class_init_full (vtable, error); \
4801 if (!mono_error_ok (error)) \
4802 THROW_EX (mono_error_convert_to_exception (error), ip); \
4804 sp[0].data.datamem = * (fieldtype *)(rtm->data_items [* (guint16 *)(ip + 2)]) ; \
4805 ip += 3; \
4806 sp++; \
4809 MINT_IN_CASE(MINT_LDSFLD_I1) LDSFLD(i, gint8); MINT_IN_BREAK;
4810 MINT_IN_CASE(MINT_LDSFLD_U1) LDSFLD(i, guint8); MINT_IN_BREAK;
4811 MINT_IN_CASE(MINT_LDSFLD_I2) LDSFLD(i, gint16); MINT_IN_BREAK;
4812 MINT_IN_CASE(MINT_LDSFLD_U2) LDSFLD(i, guint16); MINT_IN_BREAK;
4813 MINT_IN_CASE(MINT_LDSFLD_I4) LDSFLD(i, gint32); MINT_IN_BREAK;
4814 MINT_IN_CASE(MINT_LDSFLD_I8) LDSFLD(l, gint64); MINT_IN_BREAK;
4815 MINT_IN_CASE(MINT_LDSFLD_R4) LDSFLD(f_r4, float); MINT_IN_BREAK;
4816 MINT_IN_CASE(MINT_LDSFLD_R8) LDSFLD(f, double); MINT_IN_BREAK;
4817 MINT_IN_CASE(MINT_LDSFLD_O) LDSFLD(p, gpointer); MINT_IN_BREAK;
4818 MINT_IN_CASE(MINT_LDSFLD_P) LDSFLD(p, gpointer); MINT_IN_BREAK;
4820 MINT_IN_CASE(MINT_LDSFLD) {
4821 MonoClassField *field = (MonoClassField*)rtm->data_items [* (guint16 *)(ip + 1)];
4822 gpointer addr = mono_class_static_field_address (rtm->domain, field);
4823 EXCEPTION_CHECKPOINT;
4824 stackval_from_data (field->type, sp, addr, FALSE);
4825 ip += 2;
4826 ++sp;
4827 MINT_IN_BREAK;
4829 MINT_IN_CASE(MINT_LDSFLD_VT) {
4830 MonoClassField *field = (MonoClassField*)rtm->data_items [* (guint16 *)(ip + 1)];
4831 gpointer addr = mono_class_static_field_address (rtm->domain, field);
4832 EXCEPTION_CHECKPOINT;
4833 int size = READ32 (ip + 2);
4834 ip += 4;
4836 sp->data.p = vt_sp;
4837 vt_sp += ALIGN_TO (size, MINT_VT_ALIGNMENT);
4838 stackval_from_data (field->type, sp, addr, FALSE);
4839 ++sp;
4840 MINT_IN_BREAK;
4843 #define STSFLD(datamem, fieldtype) { \
4844 MonoVTable *vtable = (MonoVTable*) rtm->data_items [*(guint16*)(ip + 1)]; \
4845 if (G_UNLIKELY (!vtable->initialized)) { \
4846 mono_runtime_class_init_full (vtable, error); \
4847 if (!mono_error_ok (error)) \
4848 THROW_EX (mono_error_convert_to_exception (error), ip); \
4850 sp --; \
4851 * (fieldtype *)(rtm->data_items [* (guint16 *)(ip + 2)]) = sp[0].data.datamem; \
4852 ip += 3; \
4855 MINT_IN_CASE(MINT_STSFLD_I1) STSFLD(i, gint8); MINT_IN_BREAK;
4856 MINT_IN_CASE(MINT_STSFLD_U1) STSFLD(i, guint8); MINT_IN_BREAK;
4857 MINT_IN_CASE(MINT_STSFLD_I2) STSFLD(i, gint16); MINT_IN_BREAK;
4858 MINT_IN_CASE(MINT_STSFLD_U2) STSFLD(i, guint16); MINT_IN_BREAK;
4859 MINT_IN_CASE(MINT_STSFLD_I4) STSFLD(i, gint32); MINT_IN_BREAK;
4860 MINT_IN_CASE(MINT_STSFLD_I8) STSFLD(l, gint64); MINT_IN_BREAK;
4861 MINT_IN_CASE(MINT_STSFLD_R4) STSFLD(f_r4, float); MINT_IN_BREAK;
4862 MINT_IN_CASE(MINT_STSFLD_R8) STSFLD(f, double); MINT_IN_BREAK;
4863 MINT_IN_CASE(MINT_STSFLD_P) STSFLD(p, gpointer); MINT_IN_BREAK;
4864 MINT_IN_CASE(MINT_STSFLD_O) STSFLD(p, gpointer); MINT_IN_BREAK;
4866 MINT_IN_CASE(MINT_STSFLD) {
4867 MonoClassField *field = (MonoClassField*)rtm->data_items [* (guint16 *)(ip + 1)];
4868 gpointer addr = mono_class_static_field_address (rtm->domain, field);
4869 EXCEPTION_CHECKPOINT;
4870 ip += 2;
4871 --sp;
4872 stackval_to_data (field->type, sp, addr, FALSE);
4873 MINT_IN_BREAK;
4875 MINT_IN_CASE(MINT_STSFLD_VT) {
4876 MonoClassField *field = (MonoClassField*)rtm->data_items [* (guint16 *)(ip + 1)];
4877 gpointer addr = mono_class_static_field_address (rtm->domain, field);
4878 EXCEPTION_CHECKPOINT;
4879 MonoClass *klass = mono_class_from_mono_type_internal (field->type);
4880 i32 = mono_class_value_size (klass, NULL);
4881 ip += 2;
4883 --sp;
4884 stackval_to_data (field->type, sp, addr, FALSE);
4885 vt_sp -= ALIGN_TO (i32, MINT_VT_ALIGNMENT);
4886 MINT_IN_BREAK;
4888 MINT_IN_CASE(MINT_STOBJ_VT) {
4889 int size;
4890 c = (MonoClass*)rtm->data_items[* (guint16 *)(ip + 1)];
4891 ip += 2;
4892 size = mono_class_value_size (c, NULL);
4893 mono_value_copy_internal (sp [-2].data.p, sp [-1].data.p, c);
4894 vt_sp -= ALIGN_TO (size, MINT_VT_ALIGNMENT);
4895 sp -= 2;
4896 MINT_IN_BREAK;
4898 MINT_IN_CASE(MINT_STOBJ) {
4899 c = (MonoClass*)rtm->data_items[* (guint16 *)(ip + 1)];
4900 ip += 2;
4902 g_assert (!m_class_get_byval_arg (c)->byref);
4903 if (MONO_TYPE_IS_REFERENCE (m_class_get_byval_arg (c)))
4904 mono_gc_wbarrier_generic_store_internal (sp [-2].data.o, sp [-1].data.o);
4905 else
4906 stackval_to_data (m_class_get_byval_arg (c), &sp [-1], sp [-2].data.p, FALSE);
4907 sp -= 2;
4908 MINT_IN_BREAK;
4910 MINT_IN_CASE(MINT_CONV_OVF_I4_UN_R8)
4911 if (sp [-1].data.f < 0 || sp [-1].data.f > G_MAXINT32)
4912 THROW_EX (mono_get_exception_overflow (), ip);
4913 sp [-1].data.i = (gint32)sp [-1].data.f;
4914 ++ip;
4915 MINT_IN_BREAK;
4916 MINT_IN_CASE(MINT_CONV_OVF_U8_I4)
4917 if (sp [-1].data.i < 0)
4918 THROW_EX (mono_get_exception_overflow (), ip);
4919 sp [-1].data.l = sp [-1].data.i;
4920 ++ip;
4921 MINT_IN_BREAK;
4922 MINT_IN_CASE(MINT_CONV_OVF_U8_I8)
4923 if (sp [-1].data.l < 0)
4924 THROW_EX (mono_get_exception_overflow (), ip);
4925 ++ip;
4926 MINT_IN_BREAK;
4927 MINT_IN_CASE(MINT_CONV_OVF_I8_U8)
4928 if ((guint64) sp [-1].data.l > G_MAXINT64)
4929 THROW_EX (mono_get_exception_overflow (), ip);
4930 ++ip;
4931 MINT_IN_BREAK;
4932 MINT_IN_CASE(MINT_CONV_OVF_U8_R4)
4933 if (sp [-1].data.f_r4 < 0 || sp [-1].data.f_r4 > G_MAXUINT64 || isnan (sp [-1].data.f_r4))
4934 THROW_EX (mono_get_exception_overflow (), ip);
4935 sp [-1].data.l = (guint64)sp [-1].data.f_r4;
4936 ++ip;
4937 MINT_IN_BREAK;
4938 MINT_IN_CASE(MINT_CONV_OVF_U8_R8)
4939 if (sp [-1].data.f < 0 || sp [-1].data.f > G_MAXUINT64 || isnan (sp [-1].data.f))
4940 THROW_EX (mono_get_exception_overflow (), ip);
4941 sp [-1].data.l = (guint64)sp [-1].data.f;
4942 ++ip;
4943 MINT_IN_BREAK;
4944 MINT_IN_CASE(MINT_CONV_OVF_I8_UN_R8)
4945 if (sp [-1].data.f < 0 || sp [-1].data.f > G_MAXINT64)
4946 THROW_EX (mono_get_exception_overflow (), ip);
4947 sp [-1].data.l = (gint64)sp [-1].data.f;
4948 ++ip;
4949 MINT_IN_BREAK;
4950 MINT_IN_CASE(MINT_CONV_OVF_I8_R4)
4951 if (sp [-1].data.f_r4 < G_MININT64 || sp [-1].data.f_r4 > G_MAXINT64 || isnan (sp [-1].data.f_r4))
4952 THROW_EX (mono_get_exception_overflow (), ip);
4953 sp [-1].data.l = (gint64)sp [-1].data.f_r4;
4954 ++ip;
4955 MINT_IN_BREAK;
4956 MINT_IN_CASE(MINT_CONV_OVF_I8_R8)
4957 if (sp [-1].data.f < G_MININT64 || sp [-1].data.f > G_MAXINT64 || isnan (sp [-1].data.f))
4958 THROW_EX (mono_get_exception_overflow (), ip);
4959 sp [-1].data.l = (gint64)sp [-1].data.f;
4960 ++ip;
4961 MINT_IN_BREAK;
4962 MINT_IN_CASE(MINT_CONV_OVF_I4_UN_I8)
4963 if ((guint64)sp [-1].data.l > G_MAXINT32)
4964 THROW_EX (mono_get_exception_overflow (), ip);
4965 sp [-1].data.i = (gint32)sp [-1].data.l;
4966 ++ip;
4967 MINT_IN_BREAK;
4968 MINT_IN_CASE(MINT_BOX) {
4969 c = (MonoClass*)rtm->data_items [* (guint16 *)(ip + 1)];
4970 guint16 offset = * (guint16 *)(ip + 2);
4972 stackval_to_data (m_class_get_byval_arg (c), &sp [-1 - offset], (char *) &sp [-1 - offset], FALSE);
4973 sp [-1 - offset].data.p = mono_value_box_checked (rtm->domain, c, &sp [-1 - offset], error);
4974 mono_error_cleanup (error); /* FIXME: don't swallow the error */
4976 ip += 3;
4977 MINT_IN_BREAK;
4979 MINT_IN_CASE(MINT_BOX_VT) {
4980 c = (MonoClass*)rtm->data_items [* (guint16 *)(ip + 1)];
4981 guint16 offset = * (guint16 *)(ip + 2);
4982 gboolean pop_vt_sp = !(offset & BOX_NOT_CLEAR_VT_SP);
4983 offset &= ~BOX_NOT_CLEAR_VT_SP;
4985 int size = mono_class_value_size (c, NULL);
4986 sp [-1 - offset].data.p = mono_value_box_checked (rtm->domain, c, sp [-1 - offset].data.p, error);
4987 mono_error_cleanup (error); /* FIXME: don't swallow the error */
4988 size = ALIGN_TO (size, MINT_VT_ALIGNMENT);
4989 if (pop_vt_sp)
4990 vt_sp -= size;
4992 ip += 3;
4993 MINT_IN_BREAK;
4995 MINT_IN_CASE(MINT_NEWARR)
4996 sp [-1].data.p = (MonoObject*) mono_array_new_checked (rtm->domain, (MonoClass*)rtm->data_items[*(guint16 *)(ip + 1)], sp [-1].data.i, error);
4997 if (!mono_error_ok (error)) {
4998 THROW_EX (mono_error_convert_to_exception (error), ip);
5000 mono_error_cleanup (error); /* FIXME: don't swallow the error */
5001 ip += 2;
5002 /*if (profiling_classes) {
5003 guint count = GPOINTER_TO_UINT (g_hash_table_lookup (profiling_classes, o->vtable->klass));
5004 count++;
5005 g_hash_table_insert (profiling_classes, o->vtable->klass, GUINT_TO_POINTER (count));
5008 MINT_IN_BREAK;
5009 MINT_IN_CASE(MINT_LDLEN)
5010 o = sp [-1].data.o;
5011 if (!o)
5012 THROW_EX (mono_get_exception_null_reference (), ip);
5013 sp [-1].data.nati = mono_array_length_internal ((MonoArray *)o);
5014 ++ip;
5015 MINT_IN_BREAK;
5016 MINT_IN_CASE(MINT_LDLEN_SPAN) {
5017 o = sp [-1].data.o;
5018 gsize offset_length = (gsize) *(gint16 *) (ip + 1);
5019 if (!o)
5020 THROW_EX (mono_get_exception_null_reference (), ip);
5021 sp [-1].data.nati = *(gint32 *) ((guint8 *) o + offset_length);
5022 ip += 2;
5023 MINT_IN_BREAK;
5025 MINT_IN_CASE(MINT_GETCHR) {
5026 MonoString *s;
5027 s = (MonoString*)sp [-2].data.p;
5028 if (!s)
5029 THROW_EX (mono_get_exception_null_reference (), ip);
5030 i32 = sp [-1].data.i;
5031 if (i32 < 0 || i32 >= mono_string_length_internal (s))
5032 THROW_EX (mono_get_exception_index_out_of_range (), ip);
5033 --sp;
5034 sp [-1].data.i = mono_string_chars_internal (s)[i32];
5035 ++ip;
5036 MINT_IN_BREAK;
5038 MINT_IN_CASE(MINT_GETITEM_SPAN) {
5039 guint8 *span = (guint8 *) sp [-2].data.p;
5040 int index = sp [-1].data.i;
5041 gsize element_size = (gsize) *(gint16 *) (ip + 1);
5042 gsize offset_length = (gsize) *(gint16 *) (ip + 2);
5043 gsize offset_pointer = (gsize) *(gint16 *) (ip + 3);
5044 sp--;
5046 if (!span)
5047 THROW_EX (mono_get_exception_null_reference (), ip);
5049 gint32 length = *(gint32 *) (span + offset_length);
5050 if (index < 0 || index >= length)
5051 THROW_EX (mono_get_exception_index_out_of_range (), ip);
5053 gpointer pointer = *(gpointer *)(span + offset_pointer);
5054 sp [-1].data.p = (guint8 *) pointer + index * element_size;
5056 ip += 4;
5057 MINT_IN_BREAK;
5059 MINT_IN_CASE(MINT_STRLEN)
5060 ++ip;
5061 o = sp [-1].data.o;
5062 if (!o)
5063 THROW_EX (mono_get_exception_null_reference (), ip);
5064 sp [-1].data.i = mono_string_length_internal ((MonoString*) o);
5065 MINT_IN_BREAK;
5066 MINT_IN_CASE(MINT_ARRAY_RANK)
5067 o = sp [-1].data.o;
5068 if (!o)
5069 THROW_EX (mono_get_exception_null_reference (), ip);
5070 sp [-1].data.i = m_class_get_rank (mono_object_class (sp [-1].data.p));
5071 ip++;
5072 MINT_IN_BREAK;
5073 MINT_IN_CASE(MINT_LDELEMA)
5074 MINT_IN_CASE(MINT_LDELEMA_TC) {
5075 gboolean needs_typecheck = *ip == MINT_LDELEMA_TC;
5077 MonoClass *klass = (MonoClass*)rtm->data_items [*(guint16 *) (ip + 1)];
5078 guint16 numargs = *(guint16 *) (ip + 2);
5079 ip += 3;
5080 sp -= numargs;
5082 o = sp [0].data.o;
5083 if (!o)
5084 THROW_EX (mono_get_exception_null_reference (), ip);
5085 sp->data.p = ves_array_element_address (frame, klass, (MonoArray *) o, &sp [1], needs_typecheck);
5086 if (frame->ex)
5087 THROW_EX (frame->ex, ip);
5088 ++sp;
5090 MINT_IN_BREAK;
5092 MINT_IN_CASE(MINT_LDELEM_I1) /* fall through */
5093 MINT_IN_CASE(MINT_LDELEM_U1) /* fall through */
5094 MINT_IN_CASE(MINT_LDELEM_I2) /* fall through */
5095 MINT_IN_CASE(MINT_LDELEM_U2) /* fall through */
5096 MINT_IN_CASE(MINT_LDELEM_I4) /* fall through */
5097 MINT_IN_CASE(MINT_LDELEM_U4) /* fall through */
5098 MINT_IN_CASE(MINT_LDELEM_I8) /* fall through */
5099 MINT_IN_CASE(MINT_LDELEM_I) /* fall through */
5100 MINT_IN_CASE(MINT_LDELEM_R4) /* fall through */
5101 MINT_IN_CASE(MINT_LDELEM_R8) /* fall through */
5102 MINT_IN_CASE(MINT_LDELEM_REF) /* fall through */
5103 MINT_IN_CASE(MINT_LDELEM_VT) {
5104 MonoArray *o;
5105 mono_u aindex;
5107 sp -= 2;
5109 o = (MonoArray*)sp [0].data.p;
5110 if (!o)
5111 THROW_EX (mono_get_exception_null_reference (), ip);
5113 aindex = sp [1].data.i;
5114 if (aindex >= mono_array_length_internal (o))
5115 THROW_EX (mono_get_exception_index_out_of_range (), ip);
5118 * FIXME: throw mono_get_exception_array_type_mismatch () if needed
5120 switch (*ip) {
5121 case MINT_LDELEM_I1:
5122 sp [0].data.i = mono_array_get_fast (o, gint8, aindex);
5123 break;
5124 case MINT_LDELEM_U1:
5125 sp [0].data.i = mono_array_get_fast (o, guint8, aindex);
5126 break;
5127 case MINT_LDELEM_I2:
5128 sp [0].data.i = mono_array_get_fast (o, gint16, aindex);
5129 break;
5130 case MINT_LDELEM_U2:
5131 sp [0].data.i = mono_array_get_fast (o, guint16, aindex);
5132 break;
5133 case MINT_LDELEM_I:
5134 sp [0].data.nati = mono_array_get_fast (o, mono_i, aindex);
5135 break;
5136 case MINT_LDELEM_I4:
5137 sp [0].data.i = mono_array_get_fast (o, gint32, aindex);
5138 break;
5139 case MINT_LDELEM_U4:
5140 sp [0].data.i = mono_array_get_fast (o, guint32, aindex);
5141 break;
5142 case MINT_LDELEM_I8:
5143 sp [0].data.l = mono_array_get_fast (o, guint64, aindex);
5144 break;
5145 case MINT_LDELEM_R4:
5146 sp [0].data.f_r4 = mono_array_get_fast (o, float, aindex);
5147 break;
5148 case MINT_LDELEM_R8:
5149 sp [0].data.f = mono_array_get_fast (o, double, aindex);
5150 break;
5151 case MINT_LDELEM_REF:
5152 sp [0].data.p = mono_array_get_fast (o, gpointer, aindex);
5153 break;
5154 case MINT_LDELEM_VT: {
5155 MonoClass *klass_vt = (MonoClass*)rtm->data_items [*(guint16 *) (ip + 1)];
5156 i32 = READ32 (ip + 2);
5157 char *src_addr = mono_array_addr_with_size_fast ((MonoArray *) o, i32, aindex);
5158 sp [0].data.vt = vt_sp;
5159 stackval_from_data (m_class_get_byval_arg (klass_vt), sp, src_addr, FALSE);
5160 vt_sp += ALIGN_TO (i32, MINT_VT_ALIGNMENT);
5161 ip += 3;
5162 break;
5164 default:
5165 ves_abort();
5168 ++ip;
5169 ++sp;
5170 MINT_IN_BREAK;
5172 MINT_IN_CASE(MINT_STELEM_I) /* fall through */
5173 MINT_IN_CASE(MINT_STELEM_I1) /* fall through */
5174 MINT_IN_CASE(MINT_STELEM_U1) /* fall through */
5175 MINT_IN_CASE(MINT_STELEM_I2) /* fall through */
5176 MINT_IN_CASE(MINT_STELEM_U2) /* fall through */
5177 MINT_IN_CASE(MINT_STELEM_I4) /* fall through */
5178 MINT_IN_CASE(MINT_STELEM_I8) /* fall through */
5179 MINT_IN_CASE(MINT_STELEM_R4) /* fall through */
5180 MINT_IN_CASE(MINT_STELEM_R8) /* fall through */
5181 MINT_IN_CASE(MINT_STELEM_REF) /* fall through */
5182 MINT_IN_CASE(MINT_STELEM_VT) {
5183 mono_u aindex;
5185 sp -= 3;
5187 o = sp [0].data.o;
5188 if (!o)
5189 THROW_EX (mono_get_exception_null_reference (), ip);
5191 aindex = sp [1].data.i;
5192 if (aindex >= mono_array_length_internal ((MonoArray *)o))
5193 THROW_EX (mono_get_exception_index_out_of_range (), ip);
5195 switch (*ip) {
5196 case MINT_STELEM_I:
5197 mono_array_set_fast ((MonoArray *)o, mono_i, aindex, sp [2].data.nati);
5198 break;
5199 case MINT_STELEM_I1:
5200 mono_array_set_fast ((MonoArray *)o, gint8, aindex, sp [2].data.i);
5201 break;
5202 case MINT_STELEM_U1:
5203 mono_array_set_fast ((MonoArray *) o, guint8, aindex, sp [2].data.i);
5204 break;
5205 case MINT_STELEM_I2:
5206 mono_array_set_fast ((MonoArray *)o, gint16, aindex, sp [2].data.i);
5207 break;
5208 case MINT_STELEM_U2:
5209 mono_array_set_fast ((MonoArray *)o, guint16, aindex, sp [2].data.i);
5210 break;
5211 case MINT_STELEM_I4:
5212 mono_array_set_fast ((MonoArray *)o, gint32, aindex, sp [2].data.i);
5213 break;
5214 case MINT_STELEM_I8:
5215 mono_array_set_fast ((MonoArray *)o, gint64, aindex, sp [2].data.l);
5216 break;
5217 case MINT_STELEM_R4:
5218 mono_array_set_fast ((MonoArray *)o, float, aindex, sp [2].data.f_r4);
5219 break;
5220 case MINT_STELEM_R8:
5221 mono_array_set_fast ((MonoArray *)o, double, aindex, sp [2].data.f);
5222 break;
5223 case MINT_STELEM_REF: {
5224 MonoObject *isinst_obj = mono_object_isinst_checked (sp [2].data.o, m_class_get_element_class (mono_object_class (o)), error);
5225 mono_error_cleanup (error); /* FIXME: don't swallow the error */
5226 if (sp [2].data.p && !isinst_obj)
5227 THROW_EX (mono_get_exception_array_type_mismatch (), ip);
5228 mono_array_setref_fast ((MonoArray *) o, aindex, sp [2].data.p);
5229 break;
5231 case MINT_STELEM_VT: {
5232 MonoClass *klass_vt = (MonoClass*)rtm->data_items [*(guint16 *) (ip + 1)];
5233 i32 = READ32 (ip + 2);
5234 char *dst_addr = mono_array_addr_with_size_fast ((MonoArray *) o, i32, aindex);
5236 stackval_to_data (m_class_get_byval_arg (klass_vt), &sp [2], dst_addr, FALSE);
5237 vt_sp -= ALIGN_TO (i32, MINT_VT_ALIGNMENT);
5238 ip += 3;
5239 break;
5241 default:
5242 ves_abort();
5245 ++ip;
5246 MINT_IN_BREAK;
5248 MINT_IN_CASE(MINT_CONV_OVF_I4_U4)
5249 if (sp [-1].data.i < 0)
5250 THROW_EX (mono_get_exception_overflow (), ip);
5251 ++ip;
5252 MINT_IN_BREAK;
5253 MINT_IN_CASE(MINT_CONV_OVF_I4_I8)
5254 if (sp [-1].data.l < G_MININT32 || sp [-1].data.l > G_MAXINT32)
5255 THROW_EX (mono_get_exception_overflow (), ip);
5256 sp [-1].data.i = (gint32) sp [-1].data.l;
5257 ++ip;
5258 MINT_IN_BREAK;
5259 MINT_IN_CASE(MINT_CONV_OVF_I4_U8)
5260 if (sp [-1].data.l < 0 || sp [-1].data.l > G_MAXINT32)
5261 THROW_EX (mono_get_exception_overflow (), ip);
5262 sp [-1].data.i = (gint32) sp [-1].data.l;
5263 ++ip;
5264 MINT_IN_BREAK;
5265 MINT_IN_CASE(MINT_CONV_OVF_I4_R4)
5266 if (sp [-1].data.f_r4 < G_MININT32 || sp [-1].data.f_r4 > G_MAXINT32)
5267 THROW_EX (mono_get_exception_overflow (), ip);
5268 sp [-1].data.i = (gint32) sp [-1].data.f_r4;
5269 ++ip;
5270 MINT_IN_BREAK;
5271 MINT_IN_CASE(MINT_CONV_OVF_I4_R8)
5272 if (sp [-1].data.f < G_MININT32 || sp [-1].data.f > G_MAXINT32)
5273 THROW_EX (mono_get_exception_overflow (), ip);
5274 sp [-1].data.i = (gint32) sp [-1].data.f;
5275 ++ip;
5276 MINT_IN_BREAK;
5277 MINT_IN_CASE(MINT_CONV_OVF_U4_I4)
5278 if (sp [-1].data.i < 0)
5279 THROW_EX (mono_get_exception_overflow (), ip);
5280 ++ip;
5281 MINT_IN_BREAK;
5282 MINT_IN_CASE(MINT_CONV_OVF_U4_I8)
5283 if (sp [-1].data.l < 0 || sp [-1].data.l > G_MAXUINT32)
5284 THROW_EX (mono_get_exception_overflow (), ip);
5285 sp [-1].data.i = (guint32) sp [-1].data.l;
5286 ++ip;
5287 MINT_IN_BREAK;
5288 MINT_IN_CASE(MINT_CONV_OVF_U4_R4)
5289 if (sp [-1].data.f_r4 < 0 || sp [-1].data.f_r4 > G_MAXUINT32)
5290 THROW_EX (mono_get_exception_overflow (), ip);
5291 sp [-1].data.i = (guint32) sp [-1].data.f_r4;
5292 ++ip;
5293 MINT_IN_BREAK;
5294 MINT_IN_CASE(MINT_CONV_OVF_U4_R8)
5295 if (sp [-1].data.f < 0 || sp [-1].data.f > G_MAXUINT32)
5296 THROW_EX (mono_get_exception_overflow (), ip);
5297 sp [-1].data.i = (guint32) sp [-1].data.f;
5298 ++ip;
5299 MINT_IN_BREAK;
5300 MINT_IN_CASE(MINT_CONV_OVF_I2_I4)
5301 if (sp [-1].data.i < G_MININT16 || sp [-1].data.i > G_MAXINT16)
5302 THROW_EX (mono_get_exception_overflow (), ip);
5303 ++ip;
5304 MINT_IN_BREAK;
5305 MINT_IN_CASE(MINT_CONV_OVF_I2_U4)
5306 if (sp [-1].data.i < 0 || sp [-1].data.i > G_MAXINT16)
5307 THROW_EX (mono_get_exception_overflow (), ip);
5308 ++ip;
5309 MINT_IN_BREAK;
5310 MINT_IN_CASE(MINT_CONV_OVF_I2_I8)
5311 if (sp [-1].data.l < G_MININT16 || sp [-1].data.l > G_MAXINT16)
5312 THROW_EX (mono_get_exception_overflow (), ip);
5313 sp [-1].data.i = (gint16) sp [-1].data.l;
5314 ++ip;
5315 MINT_IN_BREAK;
5316 MINT_IN_CASE(MINT_CONV_OVF_I2_U8)
5317 if (sp [-1].data.l < 0 || sp [-1].data.l > G_MAXINT16)
5318 THROW_EX (mono_get_exception_overflow (), ip);
5319 sp [-1].data.i = (gint16) sp [-1].data.l;
5320 ++ip;
5321 MINT_IN_BREAK;
5322 MINT_IN_CASE(MINT_CONV_OVF_I2_R8)
5323 if (sp [-1].data.f < G_MININT16 || sp [-1].data.f > G_MAXINT16)
5324 THROW_EX (mono_get_exception_overflow (), ip);
5325 sp [-1].data.i = (gint16) sp [-1].data.f;
5326 ++ip;
5327 MINT_IN_BREAK;
5328 MINT_IN_CASE(MINT_CONV_OVF_I2_UN_R8)
5329 if (sp [-1].data.f < 0 || sp [-1].data.f > G_MAXINT16)
5330 THROW_EX (mono_get_exception_overflow (), ip);
5331 sp [-1].data.i = (gint16) sp [-1].data.f;
5332 ++ip;
5333 MINT_IN_BREAK;
5334 MINT_IN_CASE(MINT_CONV_OVF_U2_I4)
5335 if (sp [-1].data.i < 0 || sp [-1].data.i > G_MAXUINT16)
5336 THROW_EX (mono_get_exception_overflow (), ip);
5337 ++ip;
5338 MINT_IN_BREAK;
5339 MINT_IN_CASE(MINT_CONV_OVF_U2_I8)
5340 if (sp [-1].data.l < 0 || sp [-1].data.l > G_MAXUINT16)
5341 THROW_EX (mono_get_exception_overflow (), ip);
5342 sp [-1].data.i = (guint16) sp [-1].data.l;
5343 ++ip;
5344 MINT_IN_BREAK;
5345 MINT_IN_CASE(MINT_CONV_OVF_U2_R8)
5346 if (sp [-1].data.f < 0 || sp [-1].data.f > G_MAXUINT16)
5347 THROW_EX (mono_get_exception_overflow (), ip);
5348 sp [-1].data.i = (guint16) sp [-1].data.f;
5349 ++ip;
5350 MINT_IN_BREAK;
5351 MINT_IN_CASE(MINT_CONV_OVF_I1_I4)
5352 if (sp [-1].data.i < G_MININT8 || sp [-1].data.i > G_MAXINT8)
5353 THROW_EX (mono_get_exception_overflow (), ip);
5354 ++ip;
5355 MINT_IN_BREAK;
5356 MINT_IN_CASE(MINT_CONV_OVF_I1_U4)
5357 if (sp [-1].data.i < 0 || sp [-1].data.i > G_MAXINT8)
5358 THROW_EX (mono_get_exception_overflow (), ip);
5359 ++ip;
5360 MINT_IN_BREAK;
5361 MINT_IN_CASE(MINT_CONV_OVF_I1_I8)
5362 if (sp [-1].data.l < G_MININT8 || sp [-1].data.l > G_MAXINT8)
5363 THROW_EX (mono_get_exception_overflow (), ip);
5364 sp [-1].data.i = (gint8) sp [-1].data.l;
5365 ++ip;
5366 MINT_IN_BREAK;
5367 MINT_IN_CASE(MINT_CONV_OVF_I1_U8)
5368 if (sp [-1].data.l < 0 || sp [-1].data.l > G_MAXINT8)
5369 THROW_EX (mono_get_exception_overflow (), ip);
5370 sp [-1].data.i = (gint8) sp [-1].data.l;
5371 ++ip;
5372 MINT_IN_BREAK;
5373 MINT_IN_CASE(MINT_CONV_OVF_I1_R8)
5374 if (sp [-1].data.f < G_MININT8 || sp [-1].data.f > G_MAXINT8)
5375 THROW_EX (mono_get_exception_overflow (), ip);
5376 sp [-1].data.i = (gint8) sp [-1].data.f;
5377 ++ip;
5378 MINT_IN_BREAK;
5379 MINT_IN_CASE(MINT_CONV_OVF_I1_UN_R8)
5380 if (sp [-1].data.f < 0 || sp [-1].data.f > G_MAXINT8)
5381 THROW_EX (mono_get_exception_overflow (), ip);
5382 sp [-1].data.i = (gint8) sp [-1].data.f;
5383 ++ip;
5384 MINT_IN_BREAK;
5385 MINT_IN_CASE(MINT_CONV_OVF_U1_I4)
5386 if (sp [-1].data.i < 0 || sp [-1].data.i > G_MAXUINT8)
5387 THROW_EX (mono_get_exception_overflow (), ip);
5388 ++ip;
5389 MINT_IN_BREAK;
5390 MINT_IN_CASE(MINT_CONV_OVF_U1_I8)
5391 if (sp [-1].data.l < 0 || sp [-1].data.l > G_MAXUINT8)
5392 THROW_EX (mono_get_exception_overflow (), ip);
5393 sp [-1].data.i = (guint8) sp [-1].data.l;
5394 ++ip;
5395 MINT_IN_BREAK;
5396 MINT_IN_CASE(MINT_CONV_OVF_U1_R8)
5397 if (sp [-1].data.f < 0 || sp [-1].data.f > G_MAXUINT8)
5398 THROW_EX (mono_get_exception_overflow (), ip);
5399 sp [-1].data.i = (guint8) sp [-1].data.f;
5400 ++ip;
5401 MINT_IN_BREAK;
5402 #if 0
5403 MINT_IN_CASE(MINT_LDELEM)
5404 MINT_IN_CASE(MINT_STELEM)
5405 MINT_IN_CASE(MINT_UNBOX_ANY)
5406 #endif
5407 MINT_IN_CASE(MINT_CKFINITE)
5408 if (!mono_isfinite (sp [-1].data.f))
5409 THROW_EX (mono_get_exception_arithmetic (), ip);
5410 ++ip;
5411 MINT_IN_BREAK;
5412 MINT_IN_CASE(MINT_MKREFANY) {
5413 c = (MonoClass*)rtm->data_items [*(guint16 *)(ip + 1)];
5415 /* The value address is on the stack */
5416 gpointer addr = sp [-1].data.p;
5417 /* Push the typedref value on the stack */
5418 sp [-1].data.p = vt_sp;
5419 vt_sp += ALIGN_TO (sizeof (MonoTypedRef), MINT_VT_ALIGNMENT);
5421 MonoTypedRef *tref = (MonoTypedRef*)sp [-1].data.p;
5422 tref->klass = c;
5423 tref->type = m_class_get_byval_arg (c);
5424 tref->value = addr;
5426 ip += 2;
5427 MINT_IN_BREAK;
5429 MINT_IN_CASE(MINT_REFANYTYPE) {
5430 MonoTypedRef *tref = (MonoTypedRef*)sp [-1].data.p;
5431 MonoType *type = tref->type;
5433 vt_sp -= ALIGN_TO (sizeof (MonoTypedRef), MINT_VT_ALIGNMENT);
5434 sp [-1].data.p = vt_sp;
5435 vt_sp += 8;
5436 *(gpointer*)sp [-1].data.p = type;
5437 ip ++;
5438 MINT_IN_BREAK;
5440 MINT_IN_CASE(MINT_REFANYVAL) {
5441 MonoTypedRef *tref = (MonoTypedRef*)sp [-1].data.p;
5442 gpointer addr = tref->value;
5444 c = (MonoClass*)rtm->data_items [*(guint16 *)(ip + 1)];
5445 if (c != tref->klass)
5446 THROW_EX (mono_get_exception_invalid_cast (), ip);
5448 vt_sp -= ALIGN_TO (sizeof (MonoTypedRef), MINT_VT_ALIGNMENT);
5450 sp [-1].data.p = addr;
5451 ip += 2;
5452 MINT_IN_BREAK;
5454 MINT_IN_CASE(MINT_LDTOKEN)
5455 sp->data.p = vt_sp;
5456 vt_sp += 8;
5457 * (gpointer *)sp->data.p = rtm->data_items[*(guint16 *)(ip + 1)];
5458 ip += 2;
5459 ++sp;
5460 MINT_IN_BREAK;
5461 MINT_IN_CASE(MINT_ADD_OVF_I4)
5462 if (CHECK_ADD_OVERFLOW (sp [-2].data.i, sp [-1].data.i))
5463 THROW_EX (mono_get_exception_overflow (), ip);
5464 BINOP(i, +);
5465 MINT_IN_BREAK;
5466 MINT_IN_CASE(MINT_ADD_OVF_I8)
5467 if (CHECK_ADD_OVERFLOW64 (sp [-2].data.l, sp [-1].data.l))
5468 THROW_EX (mono_get_exception_overflow (), ip);
5469 BINOP(l, +);
5470 MINT_IN_BREAK;
5471 MINT_IN_CASE(MINT_ADD_OVF_UN_I4)
5472 if (CHECK_ADD_OVERFLOW_UN (sp [-2].data.i, sp [-1].data.i))
5473 THROW_EX (mono_get_exception_overflow (), ip);
5474 BINOP_CAST(i, +, guint32);
5475 MINT_IN_BREAK;
5476 MINT_IN_CASE(MINT_ADD_OVF_UN_I8)
5477 if (CHECK_ADD_OVERFLOW64_UN (sp [-2].data.l, sp [-1].data.l))
5478 THROW_EX (mono_get_exception_overflow (), ip);
5479 BINOP_CAST(l, +, guint64);
5480 MINT_IN_BREAK;
5481 MINT_IN_CASE(MINT_MUL_OVF_I4)
5482 if (CHECK_MUL_OVERFLOW (sp [-2].data.i, sp [-1].data.i))
5483 THROW_EX (mono_get_exception_overflow (), ip);
5484 BINOP(i, *);
5485 MINT_IN_BREAK;
5486 MINT_IN_CASE(MINT_MUL_OVF_I8)
5487 if (CHECK_MUL_OVERFLOW64 (sp [-2].data.l, sp [-1].data.l))
5488 THROW_EX (mono_get_exception_overflow (), ip);
5489 BINOP(l, *);
5490 MINT_IN_BREAK;
5491 MINT_IN_CASE(MINT_MUL_OVF_UN_I4)
5492 if (CHECK_MUL_OVERFLOW_UN (sp [-2].data.i, sp [-1].data.i))
5493 THROW_EX (mono_get_exception_overflow (), ip);
5494 BINOP_CAST(i, *, guint32);
5495 MINT_IN_BREAK;
5496 MINT_IN_CASE(MINT_MUL_OVF_UN_I8)
5497 if (CHECK_MUL_OVERFLOW64_UN (sp [-2].data.l, sp [-1].data.l))
5498 THROW_EX (mono_get_exception_overflow (), ip);
5499 BINOP_CAST(l, *, guint64);
5500 MINT_IN_BREAK;
5501 MINT_IN_CASE(MINT_SUB_OVF_I4)
5502 if (CHECK_SUB_OVERFLOW (sp [-2].data.i, sp [-1].data.i))
5503 THROW_EX (mono_get_exception_overflow (), ip);
5504 BINOP(i, -);
5505 MINT_IN_BREAK;
5506 MINT_IN_CASE(MINT_SUB_OVF_I8)
5507 if (CHECK_SUB_OVERFLOW64 (sp [-2].data.l, sp [-1].data.l))
5508 THROW_EX (mono_get_exception_overflow (), ip);
5509 BINOP(l, -);
5510 MINT_IN_BREAK;
5511 MINT_IN_CASE(MINT_SUB_OVF_UN_I4)
5512 if (CHECK_SUB_OVERFLOW_UN (sp [-2].data.i, sp [-1].data.i))
5513 THROW_EX (mono_get_exception_overflow (), ip);
5514 BINOP_CAST(i, -, guint32);
5515 MINT_IN_BREAK;
5516 MINT_IN_CASE(MINT_SUB_OVF_UN_I8)
5517 if (CHECK_SUB_OVERFLOW64_UN (sp [-2].data.l, sp [-1].data.l))
5518 THROW_EX (mono_get_exception_overflow (), ip);
5519 BINOP_CAST(l, -, guint64);
5520 MINT_IN_BREAK;
5521 MINT_IN_CASE(MINT_START_ABORT_PROT)
5522 mono_threads_begin_abort_protected_block ();
5523 ip ++;
5524 MINT_IN_BREAK;
5525 MINT_IN_CASE(MINT_ENDFINALLY) {
5526 ip ++;
5527 int clause_index = *ip;
5528 gboolean pending_abort = mono_threads_end_abort_protected_block ();
5530 if (clause_args && clause_index == clause_args->exit_clause)
5531 goto exit_frame;
5532 while (sp > frame->stack) {
5533 --sp;
5535 if (finally_ips) {
5536 ip = (const guint16*)finally_ips->data;
5537 finally_ips = g_slist_remove (finally_ips, ip);
5538 /* Throw abort after the last finally block to avoid confusing EH */
5539 if (pending_abort && !finally_ips)
5540 EXCEPTION_CHECKPOINT;
5541 goto main_loop;
5543 ves_abort();
5544 MINT_IN_BREAK;
5547 MINT_IN_CASE(MINT_LEAVE) /* Fall through */
5548 MINT_IN_CASE(MINT_LEAVE_S)
5549 while (sp > frame->stack) {
5550 --sp;
5552 frame->ip = ip;
5554 if (*ip == MINT_LEAVE_S) {
5555 ip += (short) *(ip + 1);
5556 } else {
5557 ip += (gint32) READ32 (ip + 1);
5559 endfinally_ip = ip;
5560 goto handle_finally;
5561 MINT_IN_BREAK;
5562 MINT_IN_CASE(MINT_LEAVE_CHECK)
5563 MINT_IN_CASE(MINT_LEAVE_S_CHECK)
5564 while (sp > frame->stack) {
5565 --sp;
5567 frame->ip = ip;
5569 if (frame->imethod->method->wrapper_type != MONO_WRAPPER_RUNTIME_INVOKE) {
5570 stackval tmp_sp;
5572 child_frame.parent = frame;
5573 child_frame.imethod = NULL;
5575 * We need for mono_thread_get_undeniable_exception to be able to unwind
5576 * to check the abort threshold. For this to work we use child_frame as a
5577 * dummy frame that is stored in the lmf and serves as the transition frame
5579 do_icall (&child_frame, NULL, MINT_ICALL_V_P, &tmp_sp, (gpointer)mono_thread_get_undeniable_exception);
5581 MonoException *abort_exc = (MonoException*)tmp_sp.data.p;
5582 if (abort_exc)
5583 THROW_EX (abort_exc, frame->ip);
5586 if (*ip == MINT_LEAVE_S_CHECK) {
5587 ip += (short) *(ip + 1);
5588 } else {
5589 ip += (gint32) READ32 (ip + 1);
5591 endfinally_ip = ip;
5592 goto handle_finally;
5593 MINT_IN_BREAK;
5594 MINT_IN_CASE(MINT_ICALL_V_V)
5595 MINT_IN_CASE(MINT_ICALL_V_P)
5596 MINT_IN_CASE(MINT_ICALL_P_V)
5597 MINT_IN_CASE(MINT_ICALL_P_P)
5598 MINT_IN_CASE(MINT_ICALL_PP_V)
5599 MINT_IN_CASE(MINT_ICALL_PP_P)
5600 MINT_IN_CASE(MINT_ICALL_PPP_V)
5601 MINT_IN_CASE(MINT_ICALL_PPP_P)
5602 MINT_IN_CASE(MINT_ICALL_PPPP_V)
5603 MINT_IN_CASE(MINT_ICALL_PPPP_P)
5604 MINT_IN_CASE(MINT_ICALL_PPPPP_V)
5605 MINT_IN_CASE(MINT_ICALL_PPPPP_P)
5606 MINT_IN_CASE(MINT_ICALL_PPPPPP_V)
5607 MINT_IN_CASE(MINT_ICALL_PPPPPP_P)
5608 frame->ip = ip;
5609 sp = do_icall (frame, NULL, *ip, sp, rtm->data_items [*(guint16 *)(ip + 1)]);
5610 EXCEPTION_CHECKPOINT;
5611 CHECK_RESUME_STATE (context);
5612 ip += 2;
5613 MINT_IN_BREAK;
5614 MINT_IN_CASE(MINT_MONO_LDPTR)
5615 sp->data.p = rtm->data_items [*(guint16 *)(ip + 1)];
5616 ip += 2;
5617 ++sp;
5618 MINT_IN_BREAK;
5619 MINT_IN_CASE(MINT_MONO_NEWOBJ)
5620 sp->data.p = mono_object_new_checked (rtm->domain, (MonoClass*)rtm->data_items [*(guint16 *)(ip + 1)], error);
5621 mono_error_cleanup (error); /* FIXME: don't swallow the error */
5622 ip += 2;
5623 sp++;
5624 MINT_IN_BREAK;
5625 MINT_IN_CASE(MINT_MONO_FREE)
5626 ++ip;
5627 --sp;
5628 g_error ("that doesn't seem right");
5629 g_free (sp->data.p);
5630 MINT_IN_BREAK;
5631 MINT_IN_CASE(MINT_MONO_RETOBJ)
5632 ++ip;
5633 sp--;
5634 stackval_from_data (mono_method_signature_internal (frame->imethod->method)->ret, frame->retval, sp->data.p,
5635 mono_method_signature_internal (frame->imethod->method)->pinvoke);
5636 if (sp > frame->stack)
5637 g_warning ("retobj: more values on stack: %d", sp-frame->stack);
5638 goto exit_frame;
5639 MINT_IN_CASE(MINT_MONO_TLS) {
5640 MonoTlsKey key = (MonoTlsKey)*(gint32 *)(ip + 1);
5641 sp->data.p = ((gpointer (*)(void)) mono_tls_get_tls_getter (key, FALSE)) ();
5642 sp++;
5643 ip += 3;
5644 MINT_IN_BREAK;
5646 MINT_IN_CASE(MINT_MONO_MEMORY_BARRIER) {
5647 ++ip;
5648 mono_memory_barrier ();
5649 MINT_IN_BREAK;
5651 MINT_IN_CASE(MINT_MONO_LDDOMAIN)
5652 sp->data.p = mono_domain_get ();
5653 ++sp;
5654 ++ip;
5655 MINT_IN_BREAK;
5656 MINT_IN_CASE(MINT_SDB_INTR_LOC)
5657 if (G_UNLIKELY (ss_enabled)) {
5658 typedef void (*T) (void);
5659 static T ss_tramp;
5661 if (!ss_tramp) {
5662 void *tramp = mini_get_single_step_trampoline ();
5663 mono_memory_barrier ();
5664 ss_tramp = (T)tramp;
5668 * Make this point to the MINT_SDB_SEQ_POINT instruction which follows this since
5669 * the address of that instruction is stored as the seq point address.
5671 frame->ip = ip + 1;
5674 * Use the same trampoline as the JIT. This ensures that
5675 * the debugger has the context for the last interpreter
5676 * native frame.
5678 do_debugger_tramp (ss_tramp, frame);
5680 CHECK_RESUME_STATE (context);
5682 ++ip;
5683 MINT_IN_BREAK;
5684 MINT_IN_CASE(MINT_SDB_SEQ_POINT)
5685 /* Just a placeholder for a breakpoint */
5686 ++ip;
5687 MINT_IN_BREAK;
5688 MINT_IN_CASE(MINT_SDB_BREAKPOINT) {
5689 typedef void (*T) (void);
5690 static T bp_tramp;
5691 if (!bp_tramp) {
5692 void *tramp = mini_get_breakpoint_trampoline ();
5693 mono_memory_barrier ();
5694 bp_tramp = (T)tramp;
5697 frame->ip = ip;
5699 /* Use the same trampoline as the JIT */
5700 do_debugger_tramp (bp_tramp, frame);
5702 CHECK_RESUME_STATE (context);
5704 ++ip;
5705 MINT_IN_BREAK;
5708 #define RELOP(datamem, op) \
5709 --sp; \
5710 sp [-1].data.i = sp [-1].data.datamem op sp [0].data.datamem; \
5711 ++ip;
5713 #define RELOP_FP(datamem, op, noorder) \
5714 --sp; \
5715 if (mono_isunordered (sp [-1].data.datamem, sp [0].data.datamem)) \
5716 sp [-1].data.i = noorder; \
5717 else \
5718 sp [-1].data.i = sp [-1].data.datamem op sp [0].data.datamem; \
5719 ++ip;
5721 MINT_IN_CASE(MINT_CEQ_I4)
5722 RELOP(i, ==);
5723 MINT_IN_BREAK;
5724 MINT_IN_CASE(MINT_CEQ0_I4)
5725 sp [-1].data.i = (sp [-1].data.i == 0);
5726 ++ip;
5727 MINT_IN_BREAK;
5728 MINT_IN_CASE(MINT_CEQ_I8)
5729 RELOP(l, ==);
5730 MINT_IN_BREAK;
5731 MINT_IN_CASE(MINT_CEQ_R4)
5732 RELOP_FP(f_r4, ==, 0);
5733 MINT_IN_BREAK;
5734 MINT_IN_CASE(MINT_CEQ_R8)
5735 RELOP_FP(f, ==, 0);
5736 MINT_IN_BREAK;
5737 MINT_IN_CASE(MINT_CNE_I4)
5738 RELOP(i, !=);
5739 MINT_IN_BREAK;
5740 MINT_IN_CASE(MINT_CNE_I8)
5741 RELOP(l, !=);
5742 MINT_IN_BREAK;
5743 MINT_IN_CASE(MINT_CNE_R4)
5744 RELOP_FP(f_r4, !=, 1);
5745 MINT_IN_BREAK;
5746 MINT_IN_CASE(MINT_CNE_R8)
5747 RELOP_FP(f, !=, 1);
5748 MINT_IN_BREAK;
5749 MINT_IN_CASE(MINT_CGT_I4)
5750 RELOP(i, >);
5751 MINT_IN_BREAK;
5752 MINT_IN_CASE(MINT_CGT_I8)
5753 RELOP(l, >);
5754 MINT_IN_BREAK;
5755 MINT_IN_CASE(MINT_CGT_R4)
5756 RELOP_FP(f_r4, >, 0);
5757 MINT_IN_BREAK;
5758 MINT_IN_CASE(MINT_CGT_R8)
5759 RELOP_FP(f, >, 0);
5760 MINT_IN_BREAK;
5761 MINT_IN_CASE(MINT_CGE_I4)
5762 RELOP(i, >=);
5763 MINT_IN_BREAK;
5764 MINT_IN_CASE(MINT_CGE_I8)
5765 RELOP(l, >=);
5766 MINT_IN_BREAK;
5767 MINT_IN_CASE(MINT_CGE_R4)
5768 RELOP_FP(f_r4, >=, 0);
5769 MINT_IN_BREAK;
5770 MINT_IN_CASE(MINT_CGE_R8)
5771 RELOP_FP(f, >=, 0);
5772 MINT_IN_BREAK;
5774 #define RELOP_CAST(datamem, op, type) \
5775 --sp; \
5776 sp [-1].data.i = (type)sp [-1].data.datamem op (type)sp [0].data.datamem; \
5777 ++ip;
5779 MINT_IN_CASE(MINT_CGE_UN_I4)
5780 RELOP_CAST(l, >=, guint32);
5781 MINT_IN_BREAK;
5782 MINT_IN_CASE(MINT_CGE_UN_I8)
5783 RELOP_CAST(l, >=, guint64);
5784 MINT_IN_BREAK;
5786 MINT_IN_CASE(MINT_CGT_UN_I4)
5787 RELOP_CAST(i, >, guint32);
5788 MINT_IN_BREAK;
5789 MINT_IN_CASE(MINT_CGT_UN_I8)
5790 RELOP_CAST(l, >, guint64);
5791 MINT_IN_BREAK;
5792 MINT_IN_CASE(MINT_CGT_UN_R4)
5793 RELOP_FP(f_r4, >, 1);
5794 MINT_IN_BREAK;
5795 MINT_IN_CASE(MINT_CGT_UN_R8)
5796 RELOP_FP(f, >, 1);
5797 MINT_IN_BREAK;
5798 MINT_IN_CASE(MINT_CLT_I4)
5799 RELOP(i, <);
5800 MINT_IN_BREAK;
5801 MINT_IN_CASE(MINT_CLT_I8)
5802 RELOP(l, <);
5803 MINT_IN_BREAK;
5804 MINT_IN_CASE(MINT_CLT_R4)
5805 RELOP_FP(f_r4, <, 0);
5806 MINT_IN_BREAK;
5807 MINT_IN_CASE(MINT_CLT_R8)
5808 RELOP_FP(f, <, 0);
5809 MINT_IN_BREAK;
5810 MINT_IN_CASE(MINT_CLT_UN_I4)
5811 RELOP_CAST(i, <, guint32);
5812 MINT_IN_BREAK;
5813 MINT_IN_CASE(MINT_CLT_UN_I8)
5814 RELOP_CAST(l, <, guint64);
5815 MINT_IN_BREAK;
5816 MINT_IN_CASE(MINT_CLT_UN_R4)
5817 RELOP_FP(f_r4, <, 1);
5818 MINT_IN_BREAK;
5819 MINT_IN_CASE(MINT_CLT_UN_R8)
5820 RELOP_FP(f, <, 1);
5821 MINT_IN_BREAK;
5822 MINT_IN_CASE(MINT_CLE_I4)
5823 RELOP(i, <=);
5824 MINT_IN_BREAK;
5825 MINT_IN_CASE(MINT_CLE_I8)
5826 RELOP(l, <=);
5827 MINT_IN_BREAK;
5828 MINT_IN_CASE(MINT_CLE_UN_I4)
5829 RELOP_CAST(l, <=, guint32);
5830 MINT_IN_BREAK;
5831 MINT_IN_CASE(MINT_CLE_UN_I8)
5832 RELOP_CAST(l, <=, guint64);
5833 MINT_IN_BREAK;
5834 MINT_IN_CASE(MINT_CLE_R4)
5835 RELOP_FP(f_r4, <=, 0);
5836 MINT_IN_BREAK;
5837 MINT_IN_CASE(MINT_CLE_R8)
5838 RELOP_FP(f, <=, 0);
5839 MINT_IN_BREAK;
5841 #undef RELOP
5842 #undef RELOP_FP
5843 #undef RELOP_CAST
5845 MINT_IN_CASE(MINT_LDFTN) {
5846 sp->data.p = rtm->data_items [* (guint16 *)(ip + 1)];
5847 ++sp;
5848 ip += 2;
5849 MINT_IN_BREAK;
5851 MINT_IN_CASE(MINT_LDVIRTFTN) {
5852 InterpMethod *m = (InterpMethod*)rtm->data_items [* (guint16 *)(ip + 1)];
5853 ip += 2;
5854 --sp;
5855 if (!sp->data.p)
5856 THROW_EX (mono_get_exception_null_reference (), ip - 2);
5858 sp->data.p = get_virtual_method (m, sp->data.o);
5859 ++sp;
5860 MINT_IN_BREAK;
5863 #define LDARG(datamem, argtype) \
5864 sp->data.datamem = * (argtype *)(frame->args + * (guint16 *)(ip + 1)); \
5865 ip += 2; \
5866 ++sp;
5868 MINT_IN_CASE(MINT_LDARG_I1) LDARG(i, gint8); MINT_IN_BREAK;
5869 MINT_IN_CASE(MINT_LDARG_U1) LDARG(i, guint8); MINT_IN_BREAK;
5870 MINT_IN_CASE(MINT_LDARG_I2) LDARG(i, gint16); MINT_IN_BREAK;
5871 MINT_IN_CASE(MINT_LDARG_U2) LDARG(i, guint16); MINT_IN_BREAK;
5872 MINT_IN_CASE(MINT_LDARG_I4) LDARG(i, gint32); MINT_IN_BREAK;
5873 MINT_IN_CASE(MINT_LDARG_I8) LDARG(l, gint64); MINT_IN_BREAK;
5874 MINT_IN_CASE(MINT_LDARG_R4) LDARG(f_r4, float); MINT_IN_BREAK;
5875 MINT_IN_CASE(MINT_LDARG_R8) LDARG(f, double); MINT_IN_BREAK;
5876 MINT_IN_CASE(MINT_LDARG_O) LDARG(p, gpointer); MINT_IN_BREAK;
5877 MINT_IN_CASE(MINT_LDARG_P) LDARG(p, gpointer); MINT_IN_BREAK;
5879 MINT_IN_CASE(MINT_LDARG_VT)
5880 sp->data.p = vt_sp;
5881 i32 = READ32(ip + 2);
5882 memcpy(sp->data.p, frame->args + * (guint16 *)(ip + 1), i32);
5883 vt_sp += ALIGN_TO (i32, MINT_VT_ALIGNMENT);
5884 ip += 4;
5885 ++sp;
5886 MINT_IN_BREAK;
5888 #define STARG(datamem, argtype) \
5889 --sp; \
5890 * (argtype *)(frame->args + * (guint16 *)(ip + 1)) = sp->data.datamem; \
5891 ip += 2; \
5893 MINT_IN_CASE(MINT_STARG_I1) STARG(i, gint8); MINT_IN_BREAK;
5894 MINT_IN_CASE(MINT_STARG_U1) STARG(i, guint8); MINT_IN_BREAK;
5895 MINT_IN_CASE(MINT_STARG_I2) STARG(i, gint16); MINT_IN_BREAK;
5896 MINT_IN_CASE(MINT_STARG_U2) STARG(i, guint16); MINT_IN_BREAK;
5897 MINT_IN_CASE(MINT_STARG_I4) STARG(i, gint32); MINT_IN_BREAK;
5898 MINT_IN_CASE(MINT_STARG_I8) STARG(l, gint64); MINT_IN_BREAK;
5899 MINT_IN_CASE(MINT_STARG_R4) STARG(f_r4, float); MINT_IN_BREAK;
5900 MINT_IN_CASE(MINT_STARG_R8) STARG(f, double); MINT_IN_BREAK;
5901 MINT_IN_CASE(MINT_STARG_O) STARG(p, gpointer); MINT_IN_BREAK;
5902 MINT_IN_CASE(MINT_STARG_P) STARG(p, gpointer); MINT_IN_BREAK;
5904 MINT_IN_CASE(MINT_STARG_VT)
5905 i32 = READ32(ip + 2);
5906 --sp;
5907 memcpy(frame->args + * (guint16 *)(ip + 1), sp->data.p, i32);
5908 vt_sp -= ALIGN_TO (i32, MINT_VT_ALIGNMENT);
5909 ip += 4;
5910 MINT_IN_BREAK;
5912 #define STINARG(datamem, argtype) \
5913 do { \
5914 int n = * (guint16 *)(ip + 1); \
5915 * (argtype *)(frame->args + rtm->arg_offsets [n]) = frame->stack_args [n].data.datamem; \
5916 ip += 2; \
5917 } while (0)
5919 MINT_IN_CASE(MINT_STINARG_I1) STINARG(i, gint8); MINT_IN_BREAK;
5920 MINT_IN_CASE(MINT_STINARG_U1) STINARG(i, guint8); MINT_IN_BREAK;
5921 MINT_IN_CASE(MINT_STINARG_I2) STINARG(i, gint16); MINT_IN_BREAK;
5922 MINT_IN_CASE(MINT_STINARG_U2) STINARG(i, guint16); MINT_IN_BREAK;
5923 MINT_IN_CASE(MINT_STINARG_I4) STINARG(i, gint32); MINT_IN_BREAK;
5924 MINT_IN_CASE(MINT_STINARG_I8) STINARG(l, gint64); MINT_IN_BREAK;
5925 MINT_IN_CASE(MINT_STINARG_R4) STINARG(f_r4, float); MINT_IN_BREAK;
5926 MINT_IN_CASE(MINT_STINARG_R8) STINARG(f, double); MINT_IN_BREAK;
5927 MINT_IN_CASE(MINT_STINARG_O) STINARG(p, gpointer); MINT_IN_BREAK;
5928 MINT_IN_CASE(MINT_STINARG_P) STINARG(p, gpointer); MINT_IN_BREAK;
5930 MINT_IN_CASE(MINT_STINARG_VT) {
5931 int n = * (guint16 *)(ip + 1);
5932 i32 = READ32(ip + 2);
5933 memcpy (frame->args + rtm->arg_offsets [n], frame->stack_args [n].data.p, i32);
5934 ip += 4;
5935 MINT_IN_BREAK;
5938 MINT_IN_CASE(MINT_PROF_ENTER) {
5939 ip += 1;
5941 if (MONO_PROFILER_ENABLED (method_enter)) {
5942 MonoProfilerCallContext *prof_ctx = NULL;
5944 if (frame->imethod->prof_flags & MONO_PROFILER_CALL_INSTRUMENTATION_ENTER_CONTEXT) {
5945 prof_ctx = g_new0 (MonoProfilerCallContext, 1);
5946 prof_ctx->interp_frame = frame;
5947 prof_ctx->method = frame->imethod->method;
5950 MONO_PROFILER_RAISE (method_enter, (frame->imethod->method, prof_ctx));
5952 g_free (prof_ctx);
5955 MINT_IN_BREAK;
5958 MINT_IN_CASE(MINT_LDARGA)
5959 sp->data.p = frame->args + * (guint16 *)(ip + 1);
5960 ip += 2;
5961 ++sp;
5962 MINT_IN_BREAK;
5964 #define LDLOC(datamem, argtype) \
5965 sp->data.datamem = * (argtype *)(locals + * (guint16 *)(ip + 1)); \
5966 ip += 2; \
5967 ++sp;
5969 MINT_IN_CASE(MINT_LDLOC_I1) LDLOC(i, gint8); MINT_IN_BREAK;
5970 MINT_IN_CASE(MINT_LDLOC_U1) LDLOC(i, guint8); MINT_IN_BREAK;
5971 MINT_IN_CASE(MINT_LDLOC_I2) LDLOC(i, gint16); MINT_IN_BREAK;
5972 MINT_IN_CASE(MINT_LDLOC_U2) LDLOC(i, guint16); MINT_IN_BREAK;
5973 MINT_IN_CASE(MINT_LDLOC_I4) LDLOC(i, gint32); MINT_IN_BREAK;
5974 MINT_IN_CASE(MINT_LDLOC_I8) LDLOC(l, gint64); MINT_IN_BREAK;
5975 MINT_IN_CASE(MINT_LDLOC_R4) LDLOC(f_r4, float); MINT_IN_BREAK;
5976 MINT_IN_CASE(MINT_LDLOC_R8) LDLOC(f, double); MINT_IN_BREAK;
5977 MINT_IN_CASE(MINT_LDLOC_O) LDLOC(p, gpointer); MINT_IN_BREAK;
5978 MINT_IN_CASE(MINT_LDLOC_P) LDLOC(p, gpointer); MINT_IN_BREAK;
5980 MINT_IN_CASE(MINT_LDLOC_VT)
5981 sp->data.p = vt_sp;
5982 i32 = READ32(ip + 2);
5983 memcpy(sp->data.p, locals + * (guint16 *)(ip + 1), i32);
5984 vt_sp += ALIGN_TO (i32, MINT_VT_ALIGNMENT);
5985 ip += 4;
5986 ++sp;
5987 MINT_IN_BREAK;
5989 MINT_IN_CASE(MINT_LDLOCA_S)
5990 sp->data.p = locals + * (guint16 *)(ip + 1);
5991 ip += 2;
5992 ++sp;
5993 MINT_IN_BREAK;
5995 #define STLOC(datamem, argtype) \
5996 --sp; \
5997 * (argtype *)(locals + * (guint16 *)(ip + 1)) = sp->data.datamem; \
5998 ip += 2;
6000 MINT_IN_CASE(MINT_STLOC_I1) STLOC(i, gint8); MINT_IN_BREAK;
6001 MINT_IN_CASE(MINT_STLOC_U1) STLOC(i, guint8); MINT_IN_BREAK;
6002 MINT_IN_CASE(MINT_STLOC_I2) STLOC(i, gint16); MINT_IN_BREAK;
6003 MINT_IN_CASE(MINT_STLOC_U2) STLOC(i, guint16); MINT_IN_BREAK;
6004 MINT_IN_CASE(MINT_STLOC_I4) STLOC(i, gint32); MINT_IN_BREAK;
6005 MINT_IN_CASE(MINT_STLOC_I8) STLOC(l, gint64); MINT_IN_BREAK;
6006 MINT_IN_CASE(MINT_STLOC_R4) STLOC(f_r4, float); MINT_IN_BREAK;
6007 MINT_IN_CASE(MINT_STLOC_R8) STLOC(f, double); MINT_IN_BREAK;
6008 MINT_IN_CASE(MINT_STLOC_O) STLOC(p, gpointer); MINT_IN_BREAK;
6009 MINT_IN_CASE(MINT_STLOC_P) STLOC(p, gpointer); MINT_IN_BREAK;
6011 #define STLOC_NP(datamem, argtype) \
6012 * (argtype *)(locals + * (guint16 *)(ip + 1)) = sp [-1].data.datamem; \
6013 ip += 2;
6015 MINT_IN_CASE(MINT_STLOC_NP_I4) STLOC_NP(i, gint32); MINT_IN_BREAK;
6016 MINT_IN_CASE(MINT_STLOC_NP_O) STLOC_NP(p, gpointer); MINT_IN_BREAK;
6018 MINT_IN_CASE(MINT_STLOC_VT)
6019 i32 = READ32(ip + 2);
6020 --sp;
6021 memcpy(locals + * (guint16 *)(ip + 1), sp->data.p, i32);
6022 vt_sp -= ALIGN_TO (i32, MINT_VT_ALIGNMENT);
6023 ip += 4;
6024 MINT_IN_BREAK;
6026 MINT_IN_CASE(MINT_LOCALLOC) {
6027 if (sp != frame->stack + 1) /*FIX?*/
6028 THROW_EX (mono_get_exception_execution_engine (NULL), ip);
6030 int len = sp [-1].data.i;
6031 sp [-1].data.p = alloca (len);
6033 if (frame->imethod->init_locals)
6034 memset (sp [-1].data.p, 0, len);
6035 ++ip;
6036 MINT_IN_BREAK;
6038 MINT_IN_CASE(MINT_ENDFILTER)
6039 /* top of stack is result of filter */
6040 frame->retval = &sp [-1];
6041 goto exit_frame;
6042 MINT_IN_CASE(MINT_INITOBJ)
6043 --sp;
6044 memset (sp->data.vt, 0, READ32(ip + 1));
6045 ip += 3;
6046 MINT_IN_BREAK;
6047 MINT_IN_CASE(MINT_CPBLK)
6048 sp -= 3;
6049 if (!sp [0].data.p || !sp [1].data.p)
6050 THROW_EX (mono_get_exception_null_reference(), ip - 1);
6051 ++ip;
6052 /* FIXME: value and size may be int64... */
6053 memcpy (sp [0].data.p, sp [1].data.p, sp [2].data.i);
6054 MINT_IN_BREAK;
6055 #if 0
6056 MINT_IN_CASE(MINT_CONSTRAINED_) {
6057 guint32 token;
6058 /* FIXME: implement */
6059 ++ip;
6060 token = READ32 (ip);
6061 ip += 2;
6062 MINT_IN_BREAK;
6064 #endif
6065 MINT_IN_CASE(MINT_INITBLK)
6066 sp -= 3;
6067 if (!sp [0].data.p)
6068 THROW_EX (mono_get_exception_null_reference(), ip - 1);
6069 ++ip;
6070 /* FIXME: value and size may be int64... */
6071 memset (sp [0].data.p, sp [1].data.i, sp [2].data.i);
6072 MINT_IN_BREAK;
6073 #if 0
6074 MINT_IN_CASE(MINT_NO_)
6075 /* FIXME: implement */
6076 ip += 2;
6077 MINT_IN_BREAK;
6078 #endif
6079 MINT_IN_CASE(MINT_RETHROW) {
6080 int exvar_offset = *(guint16*)(ip + 1);
6081 THROW_EX_GENERAL (*(MonoException**)(frame->locals + exvar_offset), ip, TRUE);
6082 MINT_IN_BREAK;
6084 MINT_IN_CASE(MINT_MONO_RETHROW) {
6086 * need to clarify what this should actually do:
6088 * Takes an exception from the stack and rethrows it.
6089 * This is useful for wrappers that don't want to have to
6090 * use CEE_THROW and lose the exception stacktrace.
6093 --sp;
6094 if (!sp->data.p)
6095 sp->data.p = mono_get_exception_null_reference ();
6097 THROW_EX_GENERAL ((MonoException *)sp->data.p, ip, TRUE);
6098 MINT_IN_BREAK;
6100 MINT_IN_CASE(MINT_LD_DELEGATE_METHOD_PTR) {
6101 MonoDelegate *del;
6103 --sp;
6104 del = (MonoDelegate*)sp->data.p;
6105 if (!del->interp_method) {
6106 /* Not created from interpreted code */
6107 ERROR_DECL (error);
6108 g_assert (del->method);
6109 del->interp_method = mono_interp_get_imethod (del->object.vtable->domain, del->method, error);
6110 mono_error_assert_ok (error);
6112 g_assert (del->interp_method);
6113 sp->data.p = del->interp_method;
6114 ++sp;
6115 ip += 1;
6116 MINT_IN_BREAK;
6118 MINT_IN_CASE(MINT_LD_DELEGATE_INVOKE_IMPL) {
6119 MonoDelegate *del;
6120 int n = *(guint16*)(ip + 1);
6121 del = (MonoDelegate*)sp [-n].data.p;
6122 if (!del->interp_invoke_impl) {
6124 * First time we are called. Set up the invoke wrapper. We might be able to do this
6125 * in ctor but we would need to handle AllocDelegateLike_internal separately
6127 ERROR_DECL (error);
6128 MonoMethod *invoke = mono_get_delegate_invoke_internal (del->object.vtable->klass);
6129 del->interp_invoke_impl = mono_interp_get_imethod (del->object.vtable->domain, mono_marshal_get_delegate_invoke (invoke, del), error);
6130 mono_error_assert_ok (error);
6132 sp ++;
6133 sp [-1].data.p = del->interp_invoke_impl;
6134 ip += 2;
6135 MINT_IN_BREAK;
6137 MINT_IN_DEFAULT
6138 g_print ("Unimplemented opcode: %04x %s at 0x%x\n", *ip, mono_interp_opname[*ip], ip-rtm->code);
6139 THROW_EX (mono_get_exception_execution_engine ("Unimplemented opcode"), ip);
6143 g_assert_not_reached ();
6144 handle_finally:
6146 int i;
6147 guint32 ip_offset;
6148 MonoExceptionClause *clause;
6149 GSList *old_list = finally_ips;
6150 MonoMethod *method = frame->imethod->method;
6152 #if DEBUG_INTERP
6153 if (tracing)
6154 g_print ("* Handle finally IL_%04x\n", endfinally_ip == NULL ? 0 : endfinally_ip - rtm->code);
6155 #endif
6156 if (rtm == NULL || (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
6157 || (method->iflags & (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL | METHOD_IMPL_ATTRIBUTE_RUNTIME))) {
6158 goto exit_frame;
6160 ip_offset = frame->ip - rtm->code;
6162 if (endfinally_ip != NULL)
6163 finally_ips = g_slist_prepend(finally_ips, (void *)endfinally_ip);
6165 for (i = rtm->num_clauses - 1; i >= 0; i--) {
6166 clause = &rtm->clauses [i];
6167 if (MONO_OFFSET_IN_CLAUSE (clause, ip_offset) && (endfinally_ip == NULL || !(MONO_OFFSET_IN_CLAUSE (clause, endfinally_ip - rtm->code)))) {
6168 if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY) {
6169 ip = rtm->code + clause->handler_offset;
6170 finally_ips = g_slist_prepend (finally_ips, (gpointer) ip);
6171 #if DEBUG_INTERP
6172 if (tracing)
6173 g_print ("* Found finally at IL_%04x with exception: %s\n", clause->handler_offset, frame->ex? "yes": "no");
6174 #endif
6179 endfinally_ip = NULL;
6181 if (old_list != finally_ips && finally_ips) {
6182 ip = (const guint16*)finally_ips->data;
6183 finally_ips = g_slist_remove (finally_ips, ip);
6184 sp = frame->stack; /* spec says stack should be empty at endfinally so it should be at the start too */
6185 vt_sp = (unsigned char *) sp + rtm->stack_size;
6186 goto main_loop;
6189 ves_abort();
6192 exit_frame:
6194 if (clause_args && clause_args->base_frame)
6195 memcpy (clause_args->base_frame->args, frame->args, rtm->alloca_size);
6197 if (!frame->ex && MONO_PROFILER_ENABLED (method_leave) &&
6198 frame->imethod->prof_flags & MONO_PROFILER_CALL_INSTRUMENTATION_LEAVE) {
6199 MonoProfilerCallContext *prof_ctx = NULL;
6201 if (frame->imethod->prof_flags & MONO_PROFILER_CALL_INSTRUMENTATION_LEAVE_CONTEXT) {
6202 prof_ctx = g_new0 (MonoProfilerCallContext, 1);
6203 prof_ctx->interp_frame = frame;
6204 prof_ctx->method = frame->imethod->method;
6206 MonoType *rtype = mono_method_signature_internal (frame->imethod->method)->ret;
6208 switch (rtype->type) {
6209 case MONO_TYPE_VOID:
6210 break;
6211 case MONO_TYPE_VALUETYPE:
6212 prof_ctx->return_value = frame->retval->data.p;
6213 break;
6214 default:
6215 prof_ctx->return_value = frame->retval;
6216 break;
6220 MONO_PROFILER_RAISE (method_leave, (frame->imethod->method, prof_ctx));
6222 g_free (prof_ctx);
6223 } else if (frame->ex && frame->imethod->prof_flags & MONO_PROFILER_CALL_INSTRUMENTATION_EXCEPTION_LEAVE)
6224 MONO_PROFILER_RAISE (method_exception_leave, (frame->imethod->method, &frame->ex->object));
6226 DEBUG_LEAVE ();
6229 static void
6230 interp_parse_options (const char *options)
6232 char **args, **ptr;
6234 if (!options)
6235 return;
6237 args = g_strsplit (options, ",", -1);
6238 for (ptr = args; ptr && *ptr; ptr ++) {
6239 char *arg = *ptr;
6241 if (strncmp (arg, "jit=", 4) == 0)
6242 mono_interp_jit_classes = g_slist_prepend (mono_interp_jit_classes, arg + 4);
6243 if (strncmp (arg, "interp-only=", 4) == 0)
6244 mono_interp_only_classes = g_slist_prepend (mono_interp_only_classes, arg + strlen ("interp-only="));
6245 if (strncmp (arg, "-inline", 7) == 0)
6246 mono_interp_opt &= ~INTERP_OPT_INLINE;
6250 typedef int (*TestMethod) (void);
6253 * interp_set_resume_state:
6255 * Set the state the interpeter will continue to execute from after execution returns to the interpreter.
6257 static void
6258 interp_set_resume_state (MonoJitTlsData *jit_tls, MonoException *ex, MonoJitExceptionInfo *ei, MonoInterpFrameHandle interp_frame, gpointer handler_ip)
6260 ThreadContext *context;
6262 g_assert (jit_tls);
6263 context = (ThreadContext*)jit_tls->interp_context;
6264 g_assert (context);
6266 context->has_resume_state = TRUE;
6267 context->handler_frame = (InterpFrame*)interp_frame;
6268 context->handler_ei = ei;
6269 /* This is on the stack, so it doesn't need a wbarrier */
6270 context->handler_frame->ex = ex;
6271 /* Ditto */
6272 if (ei)
6273 *(MonoException**)(context->handler_frame->locals + ei->exvar_offset) = ex;
6274 context->handler_ip = (guint16*) handler_ip;
6278 * interp_run_finally:
6280 * Run the finally clause identified by CLAUSE_INDEX in the intepreter frame given by
6281 * frame->interp_frame.
6282 * Return TRUE if the finally clause threw an exception.
6284 static gboolean
6285 interp_run_finally (StackFrameInfo *frame, int clause_index, gpointer handler_ip, gpointer handler_ip_end)
6287 InterpFrame *iframe = (InterpFrame*)frame->interp_frame;
6288 ThreadContext *context = get_context ();
6289 const unsigned short *old_ip = iframe->ip;
6290 FrameClauseArgs clause_args;
6292 memset (&clause_args, 0, sizeof (FrameClauseArgs));
6293 clause_args.start_with_ip = (guint16*) handler_ip;
6294 clause_args.end_at_ip = (guint16*) handler_ip_end;
6295 clause_args.exit_clause = clause_index;
6297 interp_exec_method_full (iframe, context, &clause_args);
6298 if (context->has_resume_state) {
6299 return TRUE;
6300 } else {
6301 iframe->ip = old_ip;
6302 return FALSE;
6307 * interp_run_filter:
6309 * Run the filter clause identified by CLAUSE_INDEX in the intepreter frame given by
6310 * frame->interp_frame.
6312 static gboolean
6313 interp_run_filter (StackFrameInfo *frame, MonoException *ex, int clause_index, gpointer handler_ip, gpointer handler_ip_end)
6315 InterpFrame *iframe = (InterpFrame*)frame->interp_frame;
6316 ThreadContext *context = get_context ();
6317 InterpFrame child_frame;
6318 stackval retval;
6319 FrameClauseArgs clause_args;
6322 * Have to run the clause in a new frame which is a copy of IFRAME, since
6323 * during debugging, there are two copies of the frame on the stack.
6325 memset (&child_frame, 0, sizeof (InterpFrame));
6326 child_frame.imethod = iframe->imethod;
6327 child_frame.retval = &retval;
6328 child_frame.parent = iframe;
6330 memset (&clause_args, 0, sizeof (FrameClauseArgs));
6331 clause_args.start_with_ip = (guint16*) handler_ip;
6332 clause_args.end_at_ip = (guint16*) handler_ip_end;
6333 clause_args.filter_exception = ex;
6334 clause_args.base_frame = iframe;
6336 interp_exec_method_full (&child_frame, context, &clause_args);
6337 /* ENDFILTER stores the result into child_frame->retval */
6338 return child_frame.retval->data.i ? TRUE : FALSE;
6341 typedef struct {
6342 InterpFrame *current;
6343 } StackIter;
6346 * interp_frame_iter_init:
6348 * Initialize an iterator for iterating through interpreted frames.
6350 static void
6351 interp_frame_iter_init (MonoInterpStackIter *iter, gpointer interp_exit_data)
6353 StackIter *stack_iter = (StackIter*)iter;
6355 stack_iter->current = (InterpFrame*)interp_exit_data;
6359 * interp_frame_iter_next:
6361 * Fill out FRAME with date for the next interpreter frame.
6363 static gboolean
6364 interp_frame_iter_next (MonoInterpStackIter *iter, StackFrameInfo *frame)
6366 StackIter *stack_iter = (StackIter*)iter;
6367 InterpFrame *iframe = stack_iter->current;
6369 memset (frame, 0, sizeof (StackFrameInfo));
6370 /* pinvoke frames doesn't have imethod set */
6371 while (iframe && !(iframe->imethod && iframe->imethod->code && iframe->imethod->jinfo))
6372 iframe = iframe->parent;
6373 if (!iframe)
6374 return FALSE;
6376 MonoMethod *method = iframe->imethod->method;
6377 frame->domain = iframe->imethod->domain;
6378 frame->interp_frame = iframe;
6379 frame->method = method;
6380 frame->actual_method = method;
6381 if (method && ((method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) || (method->iflags & (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL | METHOD_IMPL_ATTRIBUTE_RUNTIME)))) {
6382 frame->native_offset = -1;
6383 frame->type = FRAME_TYPE_MANAGED_TO_NATIVE;
6384 } else {
6385 frame->type = FRAME_TYPE_INTERP;
6386 /* This is the offset in the interpreter IR */
6387 frame->native_offset = (guint8*)iframe->ip - (guint8*)iframe->imethod->code;
6388 if (!method->wrapper_type || method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD)
6389 frame->managed = TRUE;
6391 frame->ji = iframe->imethod->jinfo;
6392 frame->frame_addr = iframe;
6394 stack_iter->current = iframe->parent;
6396 return TRUE;
6399 static MonoJitInfo*
6400 interp_find_jit_info (MonoDomain *domain, MonoMethod *method)
6402 InterpMethod* rtm;
6404 rtm = lookup_imethod (domain, method);
6405 if (rtm)
6406 return rtm->jinfo;
6407 else
6408 return NULL;
6411 static void
6412 interp_set_breakpoint (MonoJitInfo *jinfo, gpointer ip)
6414 guint16 *code = (guint16*)ip;
6415 g_assert (*code == MINT_SDB_SEQ_POINT);
6416 *code = MINT_SDB_BREAKPOINT;
6419 static void
6420 interp_clear_breakpoint (MonoJitInfo *jinfo, gpointer ip)
6422 guint16 *code = (guint16*)ip;
6423 g_assert (*code == MINT_SDB_BREAKPOINT);
6424 *code = MINT_SDB_SEQ_POINT;
6427 static MonoJitInfo*
6428 interp_frame_get_jit_info (MonoInterpFrameHandle frame)
6430 InterpFrame *iframe = (InterpFrame*)frame;
6432 g_assert (iframe->imethod);
6433 return iframe->imethod->jinfo;
6436 static gpointer
6437 interp_frame_get_ip (MonoInterpFrameHandle frame)
6439 InterpFrame *iframe = (InterpFrame*)frame;
6441 g_assert (iframe->imethod);
6442 return (gpointer)iframe->ip;
6445 static gpointer
6446 interp_frame_get_arg (MonoInterpFrameHandle frame, int pos)
6448 InterpFrame *iframe = (InterpFrame*)frame;
6450 g_assert (iframe->imethod);
6452 int arg_offset = iframe->imethod->arg_offsets [pos + (iframe->imethod->hasthis ? 1 : 0)];
6454 return iframe->args + arg_offset;
6457 static gpointer
6458 interp_frame_get_local (MonoInterpFrameHandle frame, int pos)
6460 InterpFrame *iframe = (InterpFrame*)frame;
6462 g_assert (iframe->imethod);
6464 return iframe->locals + iframe->imethod->local_offsets [pos];
6467 static gpointer
6468 interp_frame_get_this (MonoInterpFrameHandle frame)
6470 InterpFrame *iframe = (InterpFrame*)frame;
6472 g_assert (iframe->imethod);
6473 g_assert (iframe->imethod->hasthis);
6475 int arg_offset = iframe->imethod->arg_offsets [0];
6477 return iframe->args + arg_offset;
6480 static MonoInterpFrameHandle
6481 interp_frame_get_parent (MonoInterpFrameHandle frame)
6483 InterpFrame *iframe = (InterpFrame*)frame;
6485 return iframe->parent;
6488 static void
6489 interp_start_single_stepping (void)
6491 ss_enabled = TRUE;
6494 static void
6495 interp_stop_single_stepping (void)
6497 ss_enabled = FALSE;
6500 void
6501 mono_ee_interp_init (const char *opts)
6503 g_assert (mono_ee_api_version () == MONO_EE_API_VERSION);
6504 g_assert (!interp_init_done);
6505 interp_init_done = TRUE;
6507 mono_native_tls_alloc (&thread_context_id, NULL);
6508 set_context (NULL);
6510 interp_parse_options (opts);
6511 if (mini_get_debug_options ()->mdb_optimizations)
6512 mono_interp_opt &= ~INTERP_OPT_INLINE;
6513 mono_interp_transform_init ();
6515 MonoEECallbacks c;
6516 #ifdef MONO_ARCH_HAVE_INTERP_ENTRY_TRAMPOLINE
6517 c.entry_from_trampoline = interp_entry_from_trampoline;
6518 #endif
6519 c.to_native_trampoline = interp_to_native_trampoline;
6520 c.create_method_pointer = interp_create_method_pointer;
6521 c.create_method_pointer_llvmonly = interp_create_method_pointer_llvmonly;
6522 c.runtime_invoke = interp_runtime_invoke;
6523 c.init_delegate = interp_init_delegate;
6524 c.delegate_ctor = interp_delegate_ctor;
6525 c.get_remoting_invoke = interp_get_remoting_invoke;
6526 c.set_resume_state = interp_set_resume_state;
6527 c.run_finally = interp_run_finally;
6528 c.run_filter = interp_run_filter;
6529 c.frame_iter_init = interp_frame_iter_init;
6530 c.frame_iter_next = interp_frame_iter_next;
6531 c.find_jit_info = interp_find_jit_info;
6532 c.set_breakpoint = interp_set_breakpoint;
6533 c.clear_breakpoint = interp_clear_breakpoint;
6534 c.frame_get_jit_info = interp_frame_get_jit_info;
6535 c.frame_get_ip = interp_frame_get_ip;
6536 c.frame_get_arg = interp_frame_get_arg;
6537 c.frame_get_local = interp_frame_get_local;
6538 c.frame_get_this = interp_frame_get_this;
6539 c.frame_get_parent = interp_frame_get_parent;
6540 c.frame_arg_to_data = interp_frame_arg_to_data;
6541 c.data_to_frame_arg = interp_data_to_frame_arg;
6542 c.frame_arg_to_storage = interp_frame_arg_to_storage;
6543 c.frame_arg_set_storage = interp_frame_arg_set_storage;
6544 c.start_single_stepping = interp_start_single_stepping;
6545 c.stop_single_stepping = interp_stop_single_stepping;
6546 mini_install_interp_callbacks (&c);