[interp] Fix DEBUG_INTERP build (#16057)
[mono-project.git] / mono / mini / interp / interp.c
blob284b80076eb8b5936a3d08d89ef171d6070c941c
1 /**
2 * \file
4 * interp.c: Interpreter for CIL byte codes
6 * Authors:
7 * Paolo Molaro (lupus@ximian.com)
8 * Miguel de Icaza (miguel@ximian.com)
9 * Dietmar Maurer (dietmar@ximian.com)
11 * (C) 2001, 2002 Ximian, Inc.
13 #ifndef __USE_ISOC99
14 #define __USE_ISOC99
15 #endif
16 #include "config.h"
18 #include <stdio.h>
19 #include <string.h>
20 #include <stdlib.h>
21 #include <glib.h>
22 #include <math.h>
23 #include <locale.h>
25 #include <mono/utils/gc_wrapper.h>
26 #include <mono/utils/mono-math.h>
27 #include <mono/utils/mono-counters.h>
29 #ifdef HAVE_ALLOCA_H
30 # include <alloca.h>
31 #else
32 # ifdef __CYGWIN__
33 # define alloca __builtin_alloca
34 # endif
35 #endif
37 /* trim excessive headers */
38 #include <mono/metadata/image.h>
39 #include <mono/metadata/assembly-internals.h>
40 #include <mono/metadata/cil-coff.h>
41 #include <mono/metadata/mono-endian.h>
42 #include <mono/metadata/tabledefs.h>
43 #include <mono/metadata/tokentype.h>
44 #include <mono/metadata/loader.h>
45 #include <mono/metadata/threads.h>
46 #include <mono/metadata/threadpool.h>
47 #include <mono/metadata/profiler-private.h>
48 #include <mono/metadata/appdomain.h>
49 #include <mono/metadata/reflection.h>
50 #include <mono/metadata/exception.h>
51 #include <mono/metadata/verify.h>
52 #include <mono/metadata/opcodes.h>
53 #include <mono/metadata/debug-helpers.h>
54 #include <mono/metadata/mono-config.h>
55 #include <mono/metadata/marshal.h>
56 #include <mono/metadata/environment.h>
57 #include <mono/metadata/mono-debug.h>
58 #include <mono/metadata/gc-internals.h>
59 #include <mono/utils/atomic.h>
61 #include "interp.h"
62 #include "interp-internals.h"
63 #include "mintops.h"
65 #include <mono/mini/mini.h>
66 #include <mono/mini/mini-runtime.h>
67 #include <mono/mini/aot-runtime.h>
68 #include <mono/mini/llvm-runtime.h>
69 #include <mono/mini/llvmonly-runtime.h>
70 #include <mono/mini/jit-icalls.h>
71 #include <mono/mini/debugger-agent.h>
72 #include <mono/mini/ee.h>
73 #include <mono/mini/trace.h>
75 #ifdef TARGET_ARM
76 #include <mono/mini/mini-arm.h>
77 #endif
78 #include <mono/metadata/icall-decl.h>
80 #ifdef _MSC_VER
81 #pragma warning(disable:4102) // label' : unreferenced label
82 #endif
84 /* Arguments that are passed when invoking only a finally/filter clause from the frame */
85 typedef struct {
86 /* Where we start the frame execution from */
87 guint16 *start_with_ip;
89 * End ip of the exit_clause. We need it so we know whether the resume
90 * state is for this frame (which is called from EH) or for the original
91 * frame further down the stack.
93 guint16 *end_at_ip;
94 /* When exiting this clause we also exit the frame */
95 int exit_clause;
96 /* Exception that we are filtering */
97 MonoException *filter_exception;
98 InterpFrame *base_frame;
99 } FrameClauseArgs;
101 static inline void
102 init_frame (InterpFrame *frame, InterpFrame *parent_frame, InterpMethod *rmethod, stackval *method_args, stackval *method_retval)
104 frame->parent = parent_frame;
105 frame->stack_args = method_args;
106 frame->retval = method_retval;
107 frame->imethod = rmethod;
108 frame->ex = NULL;
109 frame->ip = NULL;
112 #define interp_exec_method(frame, context, error) interp_exec_method_full ((frame), (context), NULL, error)
115 * List of classes whose methods will be executed by transitioning to JITted code.
116 * Used for testing.
118 GSList *mono_interp_jit_classes;
119 /* Optimizations enabled with interpreter */
120 int mono_interp_opt = INTERP_OPT_INLINE;
121 /* If TRUE, interpreted code will be interrupted at function entry/backward branches */
122 static gboolean ss_enabled;
124 static gboolean interp_init_done = FALSE;
126 static void interp_exec_method_full (InterpFrame *frame, ThreadContext *context, FrameClauseArgs *clause_args, MonoError *error);
127 static InterpMethod* lookup_method_pointer (gpointer addr);
129 typedef void (*ICallMethod) (InterpFrame *frame);
131 static MonoNativeTlsKey thread_context_id;
133 #define DEBUG_INTERP 0
134 #define COUNT_OPS 0
136 #if DEBUG_INTERP
137 int mono_interp_traceopt = 2;
138 /* If true, then we output the opcodes as we interpret them */
139 static int global_tracing = 2;
141 static int debug_indent_level = 0;
143 static int break_on_method = 0;
144 static int nested_trace = 0;
145 static GList *db_methods = NULL;
146 static char* dump_args (InterpFrame *inv);
148 static void
149 output_indent (void)
151 int h;
153 for (h = 0; h < debug_indent_level; h++)
154 g_print (" ");
157 static void
158 db_match_method (gpointer data, gpointer user_data)
160 MonoMethod *m = (MonoMethod*)user_data;
161 MonoMethodDesc *desc = data;
163 if (mono_method_desc_full_match (desc, m))
164 break_on_method = 1;
167 static void
168 debug_enter (InterpFrame *frame, int *tracing)
170 if (db_methods) {
171 g_list_foreach (db_methods, db_match_method, (gpointer)frame->imethod->method);
172 if (break_on_method)
173 *tracing = nested_trace ? (global_tracing = 2, 3) : 2;
174 break_on_method = 0;
176 if (*tracing) {
177 MonoMethod *method = frame->imethod->method;
178 char *mn, *args = dump_args (frame);
179 debug_indent_level++;
180 output_indent ();
181 mn = mono_method_full_name (method, FALSE);
182 g_print ("(%p) Entering %s (", mono_thread_internal_current (), mn);
183 g_free (mn);
184 g_print ("%s)\n", args);
185 g_free (args);
190 #define DEBUG_LEAVE() \
191 if (tracing) { \
192 char *mn, *args; \
193 args = dump_retval (frame); \
194 output_indent (); \
195 mn = mono_method_full_name (frame->imethod->method, FALSE); \
196 g_print ("(%p) Leaving %s", mono_thread_internal_current (), mn); \
197 g_free (mn); \
198 g_print (" => %s\n", args); \
199 g_free (args); \
200 debug_indent_level--; \
201 if (tracing == 3) global_tracing = 0; \
204 #else
206 int mono_interp_traceopt = 0;
207 static void debug_enter (InterpFrame *frame, int *tracing)
210 #define DEBUG_LEAVE()
212 #endif
214 #if defined(__GNUC__) && !defined(TARGET_WASM)
215 #define USE_COMPUTED_GOTO 1
216 #endif
217 #if USE_COMPUTED_GOTO
218 #define MINT_IN_SWITCH(op) COUNT_OP(op); goto *in_labels[op];
219 #define MINT_IN_CASE(x) LAB_ ## x:
220 #define MINT_IN_DISPATCH(op) goto *in_labels[op];
221 #if DEBUG_INTERP
222 #define MINT_IN_BREAK if (tracing > 1) { MINT_IN_DISPATCH(*ip); } else { COUNT_OP(*ip); goto *in_labels[*ip]; }
223 #else
224 #define MINT_IN_BREAK { COUNT_OP(*ip); goto *in_labels[*ip]; }
225 #endif
226 #define MINT_IN_DEFAULT mint_default: if (0) goto mint_default; /* make gcc shut up */
227 #else
228 #define MINT_IN_SWITCH(op) switch (op)
229 #define MINT_IN_CASE(x) case x:
230 #define MINT_IN_DISPATCH(op) goto main_loop;
231 #define MINT_IN_BREAK break
232 #define MINT_IN_DEFAULT default:
233 #endif
235 static void
236 set_resume_state (ThreadContext *context, InterpFrame *frame)
238 /* We have thrown an exception from a finally block. Some of the leave targets were unwinded already */
239 while (frame->finally_ips &&
240 frame->finally_ips->data >= context->handler_ei->try_start &&
241 frame->finally_ips->data < context->handler_ei->try_end)
242 frame->finally_ips = g_slist_remove (frame->finally_ips, frame->finally_ips->data);
243 frame->ex = NULL;
244 context->has_resume_state = 0;
245 context->handler_frame = NULL;
246 context->handler_ei = NULL;
249 /* Set the current execution state to the resume state in context */
250 #define SET_RESUME_STATE(context) do { \
251 ip = (const guint16*)(context)->handler_ip; \
252 /* spec says stack should be empty at endfinally so it should be at the start too */ \
253 sp = frame->stack; \
254 vt_sp = (unsigned char *) sp + imethod->stack_size; \
255 if (frame->ex) { \
256 sp->data.p = frame->ex; \
257 ++sp; \
259 set_resume_state ((context), (frame)); \
260 MINT_IN_DISPATCH(*ip); \
261 } while (0)
264 * If this bit is set, it means the call has thrown the exception, and we
265 * reached this point because the EH code in mono_handle_exception ()
266 * unwound all the JITted frames below us. mono_interp_set_resume_state ()
267 * has set the fields in context to indicate where we have to resume execution.
269 #define CHECK_RESUME_STATE(context) do { \
270 if ((context)->has_resume_state) { \
271 if (frame == (context)->handler_frame && (!clause_args || (context)->handler_ip < clause_args->end_at_ip)) \
272 SET_RESUME_STATE (context); \
273 else \
274 goto exit_frame; \
276 } while (0);
278 static void
279 set_context (ThreadContext *context)
281 mono_native_tls_set_value (thread_context_id, context);
283 if (!context)
284 return;
286 MonoJitTlsData *jit_tls = mono_tls_get_jit_tls ();
287 g_assertf (jit_tls, "ThreadContext needs initialized JIT TLS");
289 /* jit_tls assumes ownership of 'context' */
290 jit_tls->interp_context = context;
293 static ThreadContext *
294 get_context (void)
296 ThreadContext *context = (ThreadContext *) mono_native_tls_get_value (thread_context_id);
297 if (context == NULL) {
298 context = g_new0 (ThreadContext, 1);
299 set_context (context);
301 return context;
304 static MONO_NEVER_INLINE void
305 ves_real_abort (int line, MonoMethod *mh,
306 const unsigned short *ip, stackval *stack, stackval *sp)
308 ERROR_DECL (error);
309 MonoMethodHeader *header = mono_method_get_header_checked (mh, error);
310 mono_error_cleanup (error); /* FIXME: don't swallow the error */
311 g_printerr ("Execution aborted in method: %s::%s\n", m_class_get_name (mh->klass), mh->name);
312 g_printerr ("Line=%d IP=0x%04lx, Aborted execution\n", line, ip-(const unsigned short *) header->code);
313 g_printerr ("0x%04x %02x\n", ip-(const unsigned short *) header->code, *ip);
314 mono_metadata_free_mh (header);
317 #define ves_abort() \
318 do {\
319 ves_real_abort(__LINE__, frame->imethod->method, ip, frame->stack, sp); \
320 THROW_EX (mono_get_exception_execution_engine (NULL), ip); \
321 } while (0);
323 static InterpMethod*
324 lookup_imethod (MonoDomain *domain, MonoMethod *method)
326 InterpMethod *imethod;
327 MonoJitDomainInfo *info;
329 info = domain_jit_info (domain);
330 mono_domain_jit_code_hash_lock (domain);
331 imethod = (InterpMethod*)mono_internal_hash_table_lookup (&info->interp_code_hash, method);
332 mono_domain_jit_code_hash_unlock (domain);
333 return imethod;
336 static gpointer
337 interp_get_remoting_invoke (MonoMethod *method, gpointer addr, MonoError *error)
339 #ifndef DISABLE_REMOTING
340 InterpMethod *imethod;
342 if (addr) {
343 imethod = lookup_method_pointer (addr);
344 } else {
345 g_assert (method);
346 imethod = mono_interp_get_imethod (mono_domain_get (), method, error);
347 return_val_if_nok (error, NULL);
349 g_assert (imethod);
350 g_assert (mono_use_interpreter);
352 MonoMethod *remoting_invoke_method = mono_marshal_get_remoting_invoke (imethod->method, error);
353 return_val_if_nok (error, NULL);
354 return mono_interp_get_imethod (mono_domain_get (), remoting_invoke_method, error);
355 #else
356 g_assert_not_reached ();
357 return NULL;
358 #endif
361 InterpMethod*
362 mono_interp_get_imethod (MonoDomain *domain, MonoMethod *method, MonoError *error)
364 InterpMethod *imethod;
365 MonoJitDomainInfo *info;
366 MonoMethodSignature *sig;
367 int i;
369 error_init (error);
371 info = domain_jit_info (domain);
372 mono_domain_jit_code_hash_lock (domain);
373 imethod = (InterpMethod*)mono_internal_hash_table_lookup (&info->interp_code_hash, method);
374 mono_domain_jit_code_hash_unlock (domain);
375 if (imethod)
376 return imethod;
378 sig = mono_method_signature_internal (method);
380 imethod = (InterpMethod*)mono_domain_alloc0 (domain, sizeof (InterpMethod));
381 imethod->method = method;
382 imethod->domain = domain;
383 imethod->param_count = sig->param_count;
384 imethod->hasthis = sig->hasthis;
385 imethod->vararg = sig->call_convention == MONO_CALL_VARARG;
386 imethod->rtype = mini_get_underlying_type (sig->ret);
387 imethod->param_types = (MonoType**)mono_domain_alloc0 (domain, sizeof (MonoType*) * sig->param_count);
388 for (i = 0; i < sig->param_count; ++i)
389 imethod->param_types [i] = mini_get_underlying_type (sig->params [i]);
391 mono_domain_jit_code_hash_lock (domain);
392 if (!mono_internal_hash_table_lookup (&info->interp_code_hash, method))
393 mono_internal_hash_table_insert (&info->interp_code_hash, method, imethod);
394 mono_domain_jit_code_hash_unlock (domain);
396 imethod->prof_flags = mono_profiler_get_call_instrumentation_flags (imethod->method);
398 return imethod;
401 #if defined (MONO_CROSS_COMPILE) || defined (HOST_WASM)
402 #define INTERP_PUSH_LMF_WITH_CTX_BODY(ext, exit_label) \
403 (ext).kind = MONO_LMFEXT_INTERP_EXIT;
405 #elif defined(MONO_ARCH_HAS_NO_PROPER_MONOCTX)
406 /* some platforms, e.g. appleTV, don't provide us a precise MonoContext
407 * (registers are not accurate), thus resuming to the label does not work. */
408 #define INTERP_PUSH_LMF_WITH_CTX_BODY(ext, exit_label) \
409 (ext).kind = MONO_LMFEXT_INTERP_EXIT;
410 #elif defined (_MSC_VER)
411 #define INTERP_PUSH_LMF_WITH_CTX_BODY(ext, exit_label) \
412 (ext).kind = MONO_LMFEXT_INTERP_EXIT_WITH_CTX; \
413 (ext).interp_exit_label_set = FALSE; \
414 MONO_CONTEXT_GET_CURRENT ((ext).ctx); \
415 if ((ext).interp_exit_label_set == FALSE) \
416 mono_arch_do_ip_adjustment (&(ext).ctx); \
417 if ((ext).interp_exit_label_set == TRUE) \
418 goto exit_label; \
419 (ext).interp_exit_label_set = TRUE;
420 #elif defined(MONO_ARCH_HAS_MONO_CONTEXT)
421 #define INTERP_PUSH_LMF_WITH_CTX_BODY(ext, exit_label) \
422 (ext).kind = MONO_LMFEXT_INTERP_EXIT_WITH_CTX; \
423 MONO_CONTEXT_GET_CURRENT ((ext).ctx); \
424 MONO_CONTEXT_SET_IP (&(ext).ctx, (&&exit_label)); \
425 mono_arch_do_ip_adjustment (&(ext).ctx);
426 #else
427 #define INTERP_PUSH_LMF_WITH_CTX_BODY(ext, exit_label) g_error ("requires working mono-context");
428 #endif
430 /* INTERP_PUSH_LMF_WITH_CTX:
432 * same as interp_push_lmf, but retrieving and attaching MonoContext to it.
433 * This is needed to resume into the interp when the exception is thrown from
434 * native code (see ./mono/tests/install_eh_callback.exe).
436 * This must be a macro in order to retrieve the right register values for
437 * MonoContext.
439 #define INTERP_PUSH_LMF_WITH_CTX(frame, ext, exit_label) \
440 memset (&(ext), 0, sizeof (MonoLMFExt)); \
441 (ext).interp_exit_data = (frame); \
442 INTERP_PUSH_LMF_WITH_CTX_BODY ((ext), exit_label); \
443 mono_push_lmf (&(ext));
446 * interp_push_lmf:
448 * Push an LMF frame on the LMF stack
449 * to mark the transition to native code.
450 * This is needed for the native code to
451 * be able to do stack walks.
453 static void
454 interp_push_lmf (MonoLMFExt *ext, InterpFrame *frame)
456 memset (ext, 0, sizeof (MonoLMFExt));
457 ext->kind = MONO_LMFEXT_INTERP_EXIT;
458 ext->interp_exit_data = frame;
460 mono_push_lmf (ext);
463 static void
464 interp_pop_lmf (MonoLMFExt *ext)
466 mono_pop_lmf (&ext->lmf);
469 static MONO_NEVER_INLINE InterpMethod*
470 get_virtual_method (InterpMethod *imethod, MonoVTable *vtable)
472 MonoMethod *m = imethod->method;
473 MonoDomain *domain = imethod->domain;
474 InterpMethod *ret = NULL;
475 ERROR_DECL (error);
477 #ifndef DISABLE_REMOTING
478 if (mono_class_is_transparent_proxy (vtable->klass)) {
479 MonoMethod *remoting_invoke_method = mono_marshal_get_remoting_invoke_with_check (m, error);
480 mono_error_assert_ok (error);
481 ret = mono_interp_get_imethod (domain, remoting_invoke_method, error);
482 mono_error_assert_ok (error);
483 return ret;
485 #endif
487 if ((m->flags & METHOD_ATTRIBUTE_FINAL) || !(m->flags & METHOD_ATTRIBUTE_VIRTUAL)) {
488 if (m->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED) {
489 ret = mono_interp_get_imethod (domain, mono_marshal_get_synchronized_wrapper (m), error);
490 mono_error_cleanup (error); /* FIXME: don't swallow the error */
491 } else {
492 ret = imethod;
494 return ret;
497 mono_class_setup_vtable (vtable->klass);
499 int slot = mono_method_get_vtable_slot (m);
500 if (mono_class_is_interface (m->klass)) {
501 g_assert (vtable->klass != m->klass);
502 /* TODO: interface offset lookup is slow, go through IMT instead */
503 gboolean non_exact_match;
504 slot += mono_class_interface_offset_with_variance (vtable->klass, m->klass, &non_exact_match);
507 MonoMethod *virtual_method = m_class_get_vtable (vtable->klass) [slot];
508 if (m->is_inflated && mono_method_get_context (m)->method_inst) {
509 MonoGenericContext context = { NULL, NULL };
511 if (mono_class_is_ginst (virtual_method->klass))
512 context.class_inst = mono_class_get_generic_class (virtual_method->klass)->context.class_inst;
513 else if (mono_class_is_gtd (virtual_method->klass))
514 context.class_inst = mono_class_get_generic_container (virtual_method->klass)->context.class_inst;
515 context.method_inst = mono_method_get_context (m)->method_inst;
517 virtual_method = mono_class_inflate_generic_method_checked (virtual_method, &context, error);
518 mono_error_cleanup (error); /* FIXME: don't swallow the error */
521 if (virtual_method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) {
522 virtual_method = mono_marshal_get_native_wrapper (virtual_method, FALSE, FALSE);
525 if (virtual_method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED) {
526 virtual_method = mono_marshal_get_synchronized_wrapper (virtual_method);
529 InterpMethod *virtual_imethod = mono_interp_get_imethod (domain, virtual_method, error);
530 mono_error_cleanup (error); /* FIXME: don't swallow the error */
531 return virtual_imethod;
534 typedef struct {
535 InterpMethod *imethod;
536 InterpMethod *target_imethod;
537 } InterpVTableEntry;
539 /* domain lock must be held */
540 static GSList*
541 append_imethod (MonoDomain *domain, GSList *list, InterpMethod *imethod, InterpMethod *target_imethod)
543 GSList *ret;
544 InterpVTableEntry *entry;
546 entry = (InterpVTableEntry*) mono_mempool_alloc (domain->mp, sizeof (InterpVTableEntry));
547 entry->imethod = imethod;
548 entry->target_imethod = target_imethod;
549 ret = g_slist_append_mempool (domain->mp, list, entry);
551 return ret;
554 static InterpMethod*
555 get_target_imethod (GSList *list, InterpMethod *imethod)
557 while (list != NULL) {
558 InterpVTableEntry *entry = (InterpVTableEntry*) list->data;
559 if (entry->imethod == imethod)
560 return entry->target_imethod;
561 list = list->next;
563 return NULL;
566 static gpointer*
567 get_method_table (MonoVTable *vtable, int offset)
569 if (offset >= 0)
570 return vtable->interp_vtable;
571 else
572 return (gpointer*)vtable;
575 static gpointer*
576 alloc_method_table (MonoVTable *vtable, int offset)
578 gpointer *table;
580 if (offset >= 0) {
581 table = mono_domain_alloc0 (vtable->domain, m_class_get_vtable_size (vtable->klass) * sizeof (gpointer));
582 vtable->interp_vtable = table;
583 } else {
584 table = (gpointer*)vtable;
587 return table;
590 static InterpMethod*
591 get_virtual_method_fast (InterpMethod *imethod, MonoVTable *vtable, int offset)
593 gpointer *table;
595 #ifndef DISABLE_REMOTING
596 /* FIXME Remoting */
597 if (mono_class_is_transparent_proxy (vtable->klass))
598 return get_virtual_method (imethod, vtable);
599 #endif
601 table = get_method_table (vtable, offset);
603 if (!table) {
604 /* Lazily allocate method table */
605 mono_domain_lock (vtable->domain);
606 table = get_method_table (vtable, offset);
607 if (!table)
608 table = alloc_method_table (vtable, offset);
609 mono_domain_unlock (vtable->domain);
612 if (!table [offset]) {
613 InterpMethod *target_imethod = get_virtual_method (imethod, vtable);
614 /* Lazily initialize the method table slot */
615 mono_domain_lock (vtable->domain);
616 if (!table [offset]) {
617 if (imethod->method->is_inflated || offset < 0)
618 table [offset] = append_imethod (vtable->domain, NULL, imethod, target_imethod);
619 else
620 table [offset] = (gpointer) ((gsize)target_imethod | 0x1);
622 mono_domain_unlock (vtable->domain);
625 if ((gsize)table [offset] & 0x1) {
626 /* Non generic virtual call. Only one method in slot */
627 return (InterpMethod*) ((gsize)table [offset] & ~0x1);
628 } else {
629 /* Virtual generic or interface call. Multiple methods in slot */
630 InterpMethod *target_imethod = get_target_imethod ((GSList*)table [offset], imethod);
632 if (!target_imethod) {
633 target_imethod = get_virtual_method (imethod, vtable);
634 mono_domain_lock (vtable->domain);
635 if (!get_target_imethod ((GSList*)table [offset], imethod))
636 table [offset] = append_imethod (vtable->domain, (GSList*)table [offset], imethod, target_imethod);
637 mono_domain_unlock (vtable->domain);
639 return target_imethod;
643 static void inline
644 stackval_from_data (MonoType *type_, stackval *result, void *data, gboolean pinvoke)
646 MonoType *type = mini_native_type_replace_type (type_);
647 if (type->byref) {
648 switch (type->type) {
649 case MONO_TYPE_OBJECT:
650 case MONO_TYPE_CLASS:
651 case MONO_TYPE_STRING:
652 case MONO_TYPE_ARRAY:
653 case MONO_TYPE_SZARRAY:
654 break;
655 default:
656 break;
658 result->data.p = *(gpointer*)data;
659 return;
661 switch (type->type) {
662 case MONO_TYPE_VOID:
663 return;
664 case MONO_TYPE_I1:
665 result->data.i = *(gint8*)data;
666 return;
667 case MONO_TYPE_U1:
668 case MONO_TYPE_BOOLEAN:
669 result->data.i = *(guint8*)data;
670 return;
671 case MONO_TYPE_I2:
672 result->data.i = *(gint16*)data;
673 return;
674 case MONO_TYPE_U2:
675 case MONO_TYPE_CHAR:
676 result->data.i = *(guint16*)data;
677 return;
678 case MONO_TYPE_I4:
679 result->data.i = *(gint32*)data;
680 return;
681 case MONO_TYPE_U:
682 case MONO_TYPE_I:
683 result->data.nati = *(mono_i*)data;
684 return;
685 case MONO_TYPE_PTR:
686 result->data.p = *(gpointer*)data;
687 return;
688 case MONO_TYPE_U4:
689 result->data.i = *(guint32*)data;
690 return;
691 case MONO_TYPE_R4:
692 /* memmove handles unaligned case */
693 memmove (&result->data.f_r4, data, sizeof (float));
694 return;
695 case MONO_TYPE_I8:
696 case MONO_TYPE_U8:
697 memmove (&result->data.l, data, sizeof (gint64));
698 return;
699 case MONO_TYPE_R8:
700 memmove (&result->data.f, data, sizeof (double));
701 return;
702 case MONO_TYPE_STRING:
703 case MONO_TYPE_SZARRAY:
704 case MONO_TYPE_CLASS:
705 case MONO_TYPE_OBJECT:
706 case MONO_TYPE_ARRAY:
707 result->data.p = *(gpointer*)data;
708 return;
709 case MONO_TYPE_VALUETYPE:
710 if (m_class_is_enumtype (type->data.klass)) {
711 stackval_from_data (mono_class_enum_basetype_internal (type->data.klass), result, data, pinvoke);
712 return;
713 } else if (pinvoke) {
714 memcpy (result->data.vt, data, mono_class_native_size (type->data.klass, NULL));
715 } else {
716 mono_value_copy_internal (result->data.vt, data, type->data.klass);
718 return;
719 case MONO_TYPE_GENERICINST: {
720 if (mono_type_generic_inst_is_valuetype (type)) {
721 mono_value_copy_internal (result->data.vt, data, mono_class_from_mono_type_internal (type));
722 return;
724 stackval_from_data (m_class_get_byval_arg (type->data.generic_class->container_class), result, data, pinvoke);
725 return;
727 default:
728 g_error ("got type 0x%02x", type->type);
732 static void inline
733 stackval_to_data (MonoType *type_, stackval *val, void *data, gboolean pinvoke)
735 MonoType *type = mini_native_type_replace_type (type_);
736 if (type->byref) {
737 gpointer *p = (gpointer*)data;
738 *p = val->data.p;
739 return;
741 /* printf ("TODAT0 %p\n", data); */
742 switch (type->type) {
743 case MONO_TYPE_I1:
744 case MONO_TYPE_U1: {
745 guint8 *p = (guint8*)data;
746 *p = val->data.i;
747 return;
749 case MONO_TYPE_BOOLEAN: {
750 guint8 *p = (guint8*)data;
751 *p = (val->data.i != 0);
752 return;
754 case MONO_TYPE_I2:
755 case MONO_TYPE_U2:
756 case MONO_TYPE_CHAR: {
757 guint16 *p = (guint16*)data;
758 *p = val->data.i;
759 return;
761 case MONO_TYPE_I: {
762 mono_i *p = (mono_i*)data;
763 /* In theory the value used by stloc should match the local var type
764 but in practice it sometimes doesn't (a int32 gets dup'd and stloc'd into
765 a native int - both by csc and mcs). Not sure what to do about sign extension
766 as it is outside the spec... doing the obvious */
767 *p = (mono_i)val->data.nati;
768 return;
770 case MONO_TYPE_U: {
771 mono_u *p = (mono_u*)data;
772 /* see above. */
773 *p = (mono_u)val->data.nati;
774 return;
776 case MONO_TYPE_I4:
777 case MONO_TYPE_U4: {
778 gint32 *p = (gint32*)data;
779 *p = val->data.i;
780 return;
782 case MONO_TYPE_I8:
783 case MONO_TYPE_U8: {
784 memmove (data, &val->data.l, sizeof (gint64));
785 return;
787 case MONO_TYPE_R4: {
788 /* memmove handles unaligned case */
789 memmove (data, &val->data.f_r4, sizeof (float));
790 return;
792 case MONO_TYPE_R8: {
793 memmove (data, &val->data.f, sizeof (double));
794 return;
796 case MONO_TYPE_STRING:
797 case MONO_TYPE_SZARRAY:
798 case MONO_TYPE_CLASS:
799 case MONO_TYPE_OBJECT:
800 case MONO_TYPE_ARRAY: {
801 gpointer *p = (gpointer *) data;
802 mono_gc_wbarrier_generic_store_internal (p, val->data.o);
803 return;
805 case MONO_TYPE_PTR: {
806 gpointer *p = (gpointer *) data;
807 *p = val->data.p;
808 return;
810 case MONO_TYPE_VALUETYPE:
811 if (m_class_is_enumtype (type->data.klass)) {
812 stackval_to_data (mono_class_enum_basetype_internal (type->data.klass), val, data, pinvoke);
813 return;
814 } else if (pinvoke) {
815 memcpy (data, val->data.vt, mono_class_native_size (type->data.klass, NULL));
816 } else {
817 mono_value_copy_internal (data, val->data.vt, type->data.klass);
819 return;
820 case MONO_TYPE_GENERICINST: {
821 MonoClass *container_class = type->data.generic_class->container_class;
823 if (m_class_is_valuetype (container_class) && !m_class_is_enumtype (container_class)) {
824 mono_value_copy_internal (data, val->data.vt, mono_class_from_mono_type_internal (type));
825 return;
827 stackval_to_data (m_class_get_byval_arg (type->data.generic_class->container_class), val, data, pinvoke);
828 return;
830 default:
831 g_error ("got type %x", type->type);
836 * Same as stackval_to_data but return address of storage instead
837 * of copying the value.
839 static gpointer
840 stackval_to_data_addr (MonoType *type_, stackval *val)
842 MonoType *type = mini_native_type_replace_type (type_);
843 if (type->byref)
844 return &val->data.p;
846 switch (type->type) {
847 case MONO_TYPE_I1:
848 case MONO_TYPE_U1:
849 case MONO_TYPE_BOOLEAN:
850 case MONO_TYPE_I2:
851 case MONO_TYPE_U2:
852 case MONO_TYPE_CHAR:
853 case MONO_TYPE_I4:
854 case MONO_TYPE_U4:
855 return &val->data.i;
856 case MONO_TYPE_I:
857 case MONO_TYPE_U:
858 return &val->data.nati;
859 case MONO_TYPE_I8:
860 case MONO_TYPE_U8:
861 return &val->data.l;
862 case MONO_TYPE_R4:
863 return &val->data.f_r4;
864 case MONO_TYPE_R8:
865 return &val->data.f;
866 case MONO_TYPE_STRING:
867 case MONO_TYPE_SZARRAY:
868 case MONO_TYPE_CLASS:
869 case MONO_TYPE_OBJECT:
870 case MONO_TYPE_ARRAY:
871 case MONO_TYPE_PTR:
872 return &val->data.p;
873 case MONO_TYPE_VALUETYPE:
874 if (m_class_is_enumtype (type->data.klass))
875 return stackval_to_data_addr (mono_class_enum_basetype_internal (type->data.klass), val);
876 else
877 return val->data.vt;
878 case MONO_TYPE_TYPEDBYREF:
879 return val->data.vt;
880 case MONO_TYPE_GENERICINST: {
881 MonoClass *container_class = type->data.generic_class->container_class;
883 if (m_class_is_valuetype (container_class) && !m_class_is_enumtype (container_class))
884 return val->data.vt;
885 return stackval_to_data_addr (m_class_get_byval_arg (type->data.generic_class->container_class), val);
887 default:
888 g_error ("got type %x", type->type);
893 * interp_throw:
894 * Throw an exception from the interpreter.
896 static MONO_NEVER_INLINE void
897 interp_throw (ThreadContext *context, MonoException *ex, InterpFrame *frame, gconstpointer ip, gboolean rethrow)
899 ERROR_DECL (error);
900 MonoLMFExt ext;
902 interp_push_lmf (&ext, frame);
903 frame->ip = (const guint16*)ip;
904 frame->ex = ex;
906 if (mono_object_isinst_checked ((MonoObject *) ex, mono_defaults.exception_class, error)) {
907 MonoException *mono_ex = (MonoException *) ex;
908 if (!rethrow) {
909 mono_ex->stack_trace = NULL;
910 mono_ex->trace_ips = NULL;
913 mono_error_assert_ok (error);
915 MonoContext ctx;
916 memset (&ctx, 0, sizeof (MonoContext));
917 MONO_CONTEXT_SET_SP (&ctx, frame);
920 * Call the JIT EH code. The EH code will call back to us using:
921 * - mono_interp_set_resume_state ()/run_finally ()/run_filter ().
922 * Since ctx.ip is 0, this will start unwinding from the LMF frame
923 * pushed above, which points to our frames.
925 mono_handle_exception (&ctx, (MonoObject*)ex);
926 if (MONO_CONTEXT_GET_IP (&ctx) != 0) {
927 /* We need to unwind into non-interpreter code */
928 mono_restore_context (&ctx);
929 g_assert_not_reached ();
932 interp_pop_lmf (&ext);
934 g_assert (context->has_resume_state);
937 #define THROW_EX_GENERAL(exception,ex_ip, rethrow) \
938 do { \
939 interp_throw (context, (exception), (frame), (ex_ip), (rethrow)); \
940 CHECK_RESUME_STATE(context); \
941 } while (0)
943 #define THROW_EX(exception,ex_ip) THROW_EX_GENERAL ((exception), (ex_ip), FALSE)
945 #define THROW_EX_OVF(ip) THROW_EX (mono_get_exception_overflow (), ip)
947 #define THROW_EX_DIV_ZERO(ip) THROW_EX (mono_get_exception_divide_by_zero (), ip)
949 #define NULL_CHECK(o) do { \
950 if (G_UNLIKELY (!(o))) \
951 THROW_EX (mono_get_exception_null_reference (), ip); \
952 } while (0)
954 #define EXCEPTION_CHECKPOINT \
955 do { \
956 if (*mono_thread_interruption_request_flag () && !mono_threads_is_critical_method (imethod->method)) { \
957 MonoException *exc = mono_thread_interruption_checkpoint (); \
958 if (exc) \
959 THROW_EX (exc, ip); \
961 } while (0)
964 static MonoObject*
965 ves_array_create (MonoDomain *domain, MonoClass *klass, int param_count, stackval *values, MonoError *error)
967 uintptr_t *lengths;
968 intptr_t *lower_bounds;
969 int i;
971 lengths = g_newa (uintptr_t, m_class_get_rank (klass) * 2);
972 for (i = 0; i < param_count; ++i) {
973 lengths [i] = values->data.i;
974 values ++;
976 if (m_class_get_rank (klass) == param_count) {
977 /* Only lengths provided. */
978 lower_bounds = NULL;
979 } else {
980 /* lower bounds are first. */
981 lower_bounds = (intptr_t *) lengths;
982 lengths += m_class_get_rank (klass);
984 return (MonoObject*) mono_array_new_full_checked (domain, klass, lengths, lower_bounds, error);
987 static gint32
988 ves_array_calculate_index (MonoArray *ao, stackval *sp, InterpFrame *frame, gboolean safe)
990 g_assert (!frame->ex);
991 MonoClass *ac = ((MonoObject *) ao)->vtable->klass;
993 guint32 pos = 0;
994 if (ao->bounds) {
995 for (gint32 i = 0; i < m_class_get_rank (ac); i++) {
996 guint32 idx = sp [i].data.i;
997 guint32 lower = ao->bounds [i].lower_bound;
998 guint32 len = ao->bounds [i].length;
999 if (safe && (idx < lower || (idx - lower) >= len)) {
1000 frame->ex = mono_get_exception_index_out_of_range ();
1001 return -1;
1003 pos = (pos * len) + idx - lower;
1005 } else {
1006 pos = sp [0].data.i;
1007 if (safe && pos >= ao->max_length) {
1008 frame->ex = mono_get_exception_index_out_of_range ();
1009 return -1;
1012 return pos;
1015 static MONO_NEVER_INLINE void
1016 ves_array_set (InterpFrame *frame, stackval *sp, MonoMethodSignature *sig)
1018 MonoObject *o = sp->data.o;
1019 MonoArray *ao = (MonoArray *) o;
1020 MonoClass *ac = o->vtable->klass;
1022 g_assert (m_class_get_rank (ac) >= 1);
1024 gint32 pos = ves_array_calculate_index (ao, sp + 1, frame, TRUE);
1025 if (frame->ex)
1026 return;
1028 int val_index = 1 + m_class_get_rank (ac);
1029 if (sp [val_index].data.p && !m_class_is_valuetype (m_class_get_element_class (mono_object_class (o)))) {
1030 ERROR_DECL (error);
1031 MonoObject *isinst = mono_object_isinst_checked (sp [val_index].data.o, m_class_get_element_class (mono_object_class (o)), error);
1032 mono_error_cleanup (error);
1033 if (!isinst) {
1034 frame->ex = mono_get_exception_array_type_mismatch ();
1035 return;
1039 gint32 esize = mono_array_element_size (ac);
1040 gpointer ea = mono_array_addr_with_size_fast (ao, esize, pos);
1042 MonoType *mt = sig->params [m_class_get_rank (ac)];
1043 stackval_to_data (mt, &sp [val_index], ea, FALSE);
1046 static void
1047 ves_array_get (InterpFrame *frame, stackval *sp, stackval *retval, MonoMethodSignature *sig, gboolean safe)
1049 MonoObject *o = sp->data.o;
1050 MonoArray *ao = (MonoArray *) o;
1051 MonoClass *ac = o->vtable->klass;
1053 g_assert (m_class_get_rank (ac) >= 1);
1055 gint32 pos = ves_array_calculate_index (ao, sp + 1, frame, safe);
1056 if (frame->ex)
1057 return;
1059 gint32 esize = mono_array_element_size (ac);
1060 gpointer ea = mono_array_addr_with_size_fast (ao, esize, pos);
1062 MonoType *mt = sig->ret;
1063 stackval_from_data (mt, retval, ea, FALSE);
1066 static gpointer
1067 ves_array_element_address (InterpFrame *frame, MonoClass *required_type, MonoArray *ao, stackval *sp, gboolean needs_typecheck)
1069 MonoClass *ac = ((MonoObject *) ao)->vtable->klass;
1071 g_assert (m_class_get_rank (ac) >= 1);
1073 gint32 pos = ves_array_calculate_index (ao, sp, frame, TRUE);
1074 if (frame->ex)
1075 return NULL;
1077 if (needs_typecheck && !mono_class_is_assignable_from_internal (m_class_get_element_class (mono_object_class ((MonoObject *) ao)), required_type)) {
1078 frame->ex = mono_get_exception_array_type_mismatch ();
1079 return NULL;
1081 gint32 esize = mono_array_element_size (ac);
1082 return mono_array_addr_with_size_fast (ao, esize, pos);
1085 #ifdef MONO_ARCH_HAVE_INTERP_ENTRY_TRAMPOLINE
1086 static MonoFuncV mono_native_to_interp_trampoline = NULL;
1087 #endif
1089 #ifndef MONO_ARCH_HAVE_INTERP_PINVOKE_TRAMP
1090 static InterpMethodArguments* build_args_from_sig (MonoMethodSignature *sig, InterpFrame *frame)
1092 InterpMethodArguments *margs = g_malloc0 (sizeof (InterpMethodArguments));
1094 #ifdef TARGET_ARM
1095 g_assert (mono_arm_eabi_supported ());
1096 int i8_align = mono_arm_i8_align ();
1097 #endif
1099 #ifdef TARGET_WASM
1100 margs->sig = sig;
1101 #endif
1103 if (sig->hasthis)
1104 margs->ilen++;
1106 for (int i = 0; i < sig->param_count; i++) {
1107 guint32 ptype = sig->params [i]->byref ? MONO_TYPE_PTR : sig->params [i]->type;
1108 switch (ptype) {
1109 case MONO_TYPE_BOOLEAN:
1110 case MONO_TYPE_CHAR:
1111 case MONO_TYPE_I1:
1112 case MONO_TYPE_U1:
1113 case MONO_TYPE_I2:
1114 case MONO_TYPE_U2:
1115 case MONO_TYPE_I4:
1116 case MONO_TYPE_U4:
1117 case MONO_TYPE_I:
1118 case MONO_TYPE_U:
1119 case MONO_TYPE_PTR:
1120 case MONO_TYPE_SZARRAY:
1121 case MONO_TYPE_CLASS:
1122 case MONO_TYPE_OBJECT:
1123 case MONO_TYPE_STRING:
1124 case MONO_TYPE_VALUETYPE:
1125 case MONO_TYPE_GENERICINST:
1126 #if SIZEOF_VOID_P == 8
1127 case MONO_TYPE_I8:
1128 case MONO_TYPE_U8:
1129 #endif
1130 margs->ilen++;
1131 break;
1132 #if SIZEOF_VOID_P == 4
1133 case MONO_TYPE_I8:
1134 case MONO_TYPE_U8:
1135 #ifdef TARGET_ARM
1136 /* pairs begin at even registers */
1137 if (i8_align == 8 && margs->ilen & 1)
1138 margs->ilen++;
1139 #endif
1140 margs->ilen += 2;
1141 break;
1142 #endif
1143 case MONO_TYPE_R4:
1144 #if SIZEOF_VOID_P == 8
1145 case MONO_TYPE_R8:
1146 #endif
1147 margs->flen++;
1148 break;
1149 #if SIZEOF_VOID_P == 4
1150 case MONO_TYPE_R8:
1151 margs->flen += 2;
1152 break;
1153 #endif
1154 default:
1155 g_error ("build_args_from_sig: not implemented yet (1): 0x%x\n", ptype);
1159 if (margs->ilen > 0)
1160 margs->iargs = g_malloc0 (sizeof (gpointer) * margs->ilen);
1162 if (margs->flen > 0)
1163 margs->fargs = g_malloc0 (sizeof (double) * margs->flen);
1165 if (margs->ilen > INTERP_ICALL_TRAMP_IARGS)
1166 g_error ("build_args_from_sig: TODO, allocate gregs: %d\n", margs->ilen);
1168 if (margs->flen > INTERP_ICALL_TRAMP_FARGS)
1169 g_error ("build_args_from_sig: TODO, allocate fregs: %d\n", margs->flen);
1172 size_t int_i = 0;
1173 size_t int_f = 0;
1175 if (sig->hasthis) {
1176 margs->iargs [0] = frame->stack_args->data.p;
1177 int_i++;
1180 for (int i = 0; i < sig->param_count; i++) {
1181 guint32 ptype = sig->params [i]->byref ? MONO_TYPE_PTR : sig->params [i]->type;
1182 switch (ptype) {
1183 case MONO_TYPE_BOOLEAN:
1184 case MONO_TYPE_CHAR:
1185 case MONO_TYPE_I1:
1186 case MONO_TYPE_U1:
1187 case MONO_TYPE_I2:
1188 case MONO_TYPE_U2:
1189 case MONO_TYPE_I4:
1190 case MONO_TYPE_U4:
1191 case MONO_TYPE_I:
1192 case MONO_TYPE_U:
1193 case MONO_TYPE_PTR:
1194 case MONO_TYPE_SZARRAY:
1195 case MONO_TYPE_CLASS:
1196 case MONO_TYPE_OBJECT:
1197 case MONO_TYPE_STRING:
1198 case MONO_TYPE_VALUETYPE:
1199 case MONO_TYPE_GENERICINST:
1200 #if SIZEOF_VOID_P == 8
1201 case MONO_TYPE_I8:
1202 case MONO_TYPE_U8:
1203 #endif
1204 margs->iargs [int_i] = frame->stack_args [i].data.p;
1205 #if DEBUG_INTERP
1206 g_print ("build_args_from_sig: margs->iargs [%d]: %p (frame @ %d)\n", int_i, margs->iargs [int_i], i);
1207 #endif
1208 int_i++;
1209 break;
1210 #if SIZEOF_VOID_P == 4
1211 case MONO_TYPE_I8:
1212 case MONO_TYPE_U8: {
1213 stackval *sarg = &frame->stack_args [i];
1214 #ifdef TARGET_ARM
1215 /* pairs begin at even registers */
1216 if (i8_align == 8 && int_i & 1)
1217 int_i++;
1218 #endif
1219 margs->iargs [int_i] = (gpointer) sarg->data.pair.lo;
1220 int_i++;
1221 margs->iargs [int_i] = (gpointer) sarg->data.pair.hi;
1222 #if DEBUG_INTERP
1223 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);
1224 #endif
1225 int_i++;
1226 break;
1228 #endif
1229 case MONO_TYPE_R4:
1230 case MONO_TYPE_R8:
1231 if (ptype == MONO_TYPE_R4)
1232 * (float *) &(margs->fargs [int_f]) = frame->stack_args [i].data.f_r4;
1233 else
1234 margs->fargs [int_f] = frame->stack_args [i].data.f;
1235 #if DEBUG_INTERP
1236 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);
1237 #endif
1238 #if SIZEOF_VOID_P == 4
1239 int_f += 2;
1240 #else
1241 int_f++;
1242 #endif
1243 break;
1244 default:
1245 g_error ("build_args_from_sig: not implemented yet (2): 0x%x\n", ptype);
1249 switch (sig->ret->type) {
1250 case MONO_TYPE_BOOLEAN:
1251 case MONO_TYPE_CHAR:
1252 case MONO_TYPE_I1:
1253 case MONO_TYPE_U1:
1254 case MONO_TYPE_I2:
1255 case MONO_TYPE_U2:
1256 case MONO_TYPE_I4:
1257 case MONO_TYPE_U4:
1258 case MONO_TYPE_I:
1259 case MONO_TYPE_U:
1260 case MONO_TYPE_PTR:
1261 case MONO_TYPE_SZARRAY:
1262 case MONO_TYPE_CLASS:
1263 case MONO_TYPE_OBJECT:
1264 case MONO_TYPE_STRING:
1265 case MONO_TYPE_I8:
1266 case MONO_TYPE_U8:
1267 case MONO_TYPE_VALUETYPE:
1268 case MONO_TYPE_GENERICINST:
1269 margs->retval = &(frame->retval->data.p);
1270 margs->is_float_ret = 0;
1271 break;
1272 case MONO_TYPE_R4:
1273 case MONO_TYPE_R8:
1274 margs->retval = &(frame->retval->data.p);
1275 margs->is_float_ret = 1;
1276 break;
1277 case MONO_TYPE_VOID:
1278 margs->retval = NULL;
1279 break;
1280 default:
1281 g_error ("build_args_from_sig: ret type not implemented yet: 0x%x\n", sig->ret->type);
1284 return margs;
1286 #endif
1288 static void
1289 interp_frame_arg_to_data (MonoInterpFrameHandle frame, MonoMethodSignature *sig, int index, gpointer data)
1291 InterpFrame *iframe = (InterpFrame*)frame;
1293 if (index == -1)
1294 stackval_to_data (sig->ret, iframe->retval, data, sig->pinvoke);
1295 else
1296 stackval_to_data (sig->params [index], &iframe->stack_args [index], data, sig->pinvoke);
1299 static void
1300 interp_data_to_frame_arg (MonoInterpFrameHandle frame, MonoMethodSignature *sig, int index, gpointer data)
1302 InterpFrame *iframe = (InterpFrame*)frame;
1304 if (index == -1)
1305 stackval_from_data (sig->ret, iframe->retval, data, sig->pinvoke);
1306 else if (sig->hasthis && index == 0)
1307 iframe->stack_args [index].data.p = *(gpointer*)data;
1308 else
1309 stackval_from_data (sig->params [index - sig->hasthis], &iframe->stack_args [index], data, sig->pinvoke);
1312 static gpointer
1313 interp_frame_arg_to_storage (MonoInterpFrameHandle frame, MonoMethodSignature *sig, int index)
1315 InterpFrame *iframe = (InterpFrame*)frame;
1317 if (index == -1)
1318 return stackval_to_data_addr (sig->ret, iframe->retval);
1319 else
1320 return stackval_to_data_addr (sig->params [index], &iframe->stack_args [index]);
1323 static void
1324 interp_frame_arg_set_storage (MonoInterpFrameHandle frame, MonoMethodSignature *sig, int index, gpointer storage)
1326 InterpFrame *iframe = (InterpFrame*)frame;
1327 stackval *val = (index == -1) ? iframe->retval : &iframe->stack_args [index];
1328 MonoType *type = (index == -1) ? sig->ret : sig->params [index];
1330 switch (type->type) {
1331 case MONO_TYPE_GENERICINST:
1332 if (!MONO_TYPE_IS_REFERENCE (type))
1333 val->data.vt = storage;
1334 break;
1335 case MONO_TYPE_VALUETYPE:
1336 val->data.vt = storage;
1337 break;
1338 default:
1339 g_assert_not_reached ();
1343 static MonoPIFunc
1344 get_interp_to_native_trampoline (void)
1346 static MonoPIFunc trampoline = NULL;
1348 if (!trampoline) {
1349 if (mono_ee_features.use_aot_trampolines) {
1350 trampoline = (MonoPIFunc) mono_aot_get_trampoline ("interp_to_native_trampoline");
1351 } else {
1352 MonoTrampInfo *info;
1353 trampoline = (MonoPIFunc) mono_arch_get_interp_to_native_trampoline (&info);
1354 mono_tramp_info_register (info, NULL);
1356 mono_memory_barrier ();
1358 return trampoline;
1361 static void
1362 interp_to_native_trampoline (gpointer addr, gpointer ccontext)
1364 get_interp_to_native_trampoline () (addr, ccontext);
1367 /* MONO_NO_OPTIMIATION is needed due to usage of INTERP_PUSH_LMF_WITH_CTX. */
1368 #ifdef _MSC_VER
1369 #pragma optimize ("", off)
1370 #endif
1371 static MONO_NO_OPTIMIZATION MONO_NEVER_INLINE void
1372 ves_pinvoke_method (InterpFrame *frame, MonoMethodSignature *sig, MonoFuncV addr, gboolean string_ctor, ThreadContext *context, gboolean save_last_error)
1374 MonoLMFExt ext;
1375 gpointer args;
1377 frame->ex = NULL;
1379 g_assert (!frame->imethod);
1381 static MonoPIFunc entry_func = NULL;
1382 if (!entry_func) {
1383 #ifdef MONO_ARCH_HAS_NO_PROPER_MONOCTX
1384 ERROR_DECL (error);
1385 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);
1386 mono_error_assert_ok (error);
1387 #else
1388 entry_func = get_interp_to_native_trampoline ();
1389 #endif
1390 mono_memory_barrier ();
1393 #ifdef ENABLE_NETCORE
1394 if (save_last_error) {
1395 mono_marshal_clear_last_error ();
1397 #endif
1399 #ifdef MONO_ARCH_HAVE_INTERP_PINVOKE_TRAMP
1400 CallContext ccontext;
1401 mono_arch_set_native_call_context_args (&ccontext, frame, sig);
1402 args = &ccontext;
1403 #else
1404 InterpMethodArguments *margs = build_args_from_sig (sig, frame);
1405 args = margs;
1406 #endif
1408 INTERP_PUSH_LMF_WITH_CTX (frame, ext, exit_pinvoke);
1409 entry_func ((gpointer) addr, args);
1410 if (save_last_error)
1411 mono_marshal_set_last_error ();
1412 interp_pop_lmf (&ext);
1414 #ifdef MONO_ARCH_HAVE_INTERP_PINVOKE_TRAMP
1415 if (!frame->ex)
1416 mono_arch_get_native_call_context_ret (&ccontext, frame, sig);
1418 if (ccontext.stack != NULL)
1419 g_free (ccontext.stack);
1420 #else
1421 if (!frame->ex && !MONO_TYPE_ISSTRUCT (sig->ret))
1422 stackval_from_data (sig->ret, frame->retval, (char*)&frame->retval->data.p, sig->pinvoke);
1424 g_free (margs->iargs);
1425 g_free (margs->fargs);
1426 g_free (margs);
1427 #endif
1428 goto exit_pinvoke; // prevent unused label warning in some configurations
1429 exit_pinvoke:
1430 return;
1432 #ifdef _MSC_VER
1433 #pragma optimize ("", on)
1434 #endif
1437 * interp_init_delegate:
1439 * Initialize del->interp_method.
1441 static void
1442 interp_init_delegate (MonoDelegate *del, MonoError *error)
1444 MonoMethod *method;
1446 if (del->interp_method) {
1447 /* Delegate created by a call to ves_icall_mono_delegate_ctor_interp () */
1448 del->method = ((InterpMethod *)del->interp_method)->method;
1449 } else if (del->method) {
1450 /* Delegate created dynamically */
1451 del->interp_method = mono_interp_get_imethod (del->object.vtable->domain, del->method, error);
1452 } else {
1453 /* Created from JITted code */
1454 g_assert_not_reached ();
1457 method = ((InterpMethod*)del->interp_method)->method;
1458 if (del->target &&
1459 method &&
1460 method->flags & METHOD_ATTRIBUTE_VIRTUAL &&
1461 method->flags & METHOD_ATTRIBUTE_ABSTRACT &&
1462 mono_class_is_abstract (method->klass))
1463 del->interp_method = get_virtual_method ((InterpMethod*)del->interp_method, del->target->vtable);
1465 method = ((InterpMethod*)del->interp_method)->method;
1466 if (method && m_class_get_parent (method->klass) == mono_defaults.multicastdelegate_class) {
1467 const char *name = method->name;
1468 if (*name == 'I' && (strcmp (name, "Invoke") == 0)) {
1470 * When invoking the delegate interp_method is executed directly. If it's an
1471 * invoke make sure we replace it with the appropriate delegate invoke wrapper.
1473 * FIXME We should do this later, when we also know the delegate on which the
1474 * target method is called.
1476 del->interp_method = mono_interp_get_imethod (del->object.vtable->domain, mono_marshal_get_delegate_invoke (method, NULL), error);
1477 mono_error_assert_ok (error);
1481 if (!((InterpMethod *) del->interp_method)->transformed && method_is_dynamic (method)) {
1482 /* Return any errors from method compilation */
1483 mono_interp_transform_method ((InterpMethod *) del->interp_method, get_context (), error);
1484 return_if_nok (error);
1488 static void
1489 interp_delegate_ctor (MonoObjectHandle this_obj, MonoObjectHandle target, gpointer addr, MonoError *error)
1492 * addr is the result of an LDFTN opcode, i.e. an InterpMethod
1494 InterpMethod *imethod = (InterpMethod*)addr;
1496 if (!(imethod->method->flags & METHOD_ATTRIBUTE_STATIC)) {
1497 MonoMethod *invoke = mono_get_delegate_invoke_internal (mono_handle_class (this_obj));
1498 /* virtual invoke delegates must not have null check */
1499 if (mono_method_signature_internal (imethod->method)->param_count == mono_method_signature_internal (invoke)->param_count
1500 && MONO_HANDLE_IS_NULL (target)) {
1501 mono_error_set_argument (error, "this", "Delegate to an instance method cannot have null 'this'");
1502 return;
1506 g_assert (imethod->method);
1507 gpointer entry = mini_get_interp_callbacks ()->create_method_pointer (imethod->method, FALSE, error);
1508 return_if_nok (error);
1510 MONO_HANDLE_SETVAL (MONO_HANDLE_CAST (MonoDelegate, this_obj), interp_method, gpointer, imethod);
1512 mono_delegate_ctor (this_obj, target, entry, error);
1516 * From the spec:
1517 * runtime specifies that the implementation of the method is automatically
1518 * provided by the runtime and is primarily used for the methods of delegates.
1520 static MONO_NEVER_INLINE void
1521 ves_imethod (InterpFrame *frame, MonoMethod *method, MonoMethodSignature *sig, stackval *sp, stackval *retval)
1523 const char *name = method->name;
1524 mono_class_init_internal (method->klass);
1526 if (method->klass == mono_defaults.array_class) {
1527 if (!strcmp (name, "UnsafeMov")) {
1528 /* TODO: layout checks */
1529 stackval_from_data (sig->ret, retval, (char*) sp, FALSE);
1530 return;
1532 if (!strcmp (name, "UnsafeLoad")) {
1533 ves_array_get (frame, sp, retval, sig, FALSE);
1534 return;
1536 } else if (mini_class_is_system_array (method->klass)) {
1537 MonoObject *obj = (MonoObject*) sp->data.p;
1538 if (!obj) {
1539 frame->ex = mono_get_exception_null_reference ();
1540 return;
1542 if (*name == 'S' && (strcmp (name, "Set") == 0)) {
1543 ves_array_set (frame, sp, sig);
1544 return;
1546 if (*name == 'G' && (strcmp (name, "Get") == 0)) {
1547 ves_array_get (frame, sp, retval, sig, TRUE);
1548 return;
1552 g_error ("Don't know how to exec runtime method %s.%s::%s",
1553 m_class_get_name_space (method->klass), m_class_get_name (method->klass),
1554 method->name);
1557 #if DEBUG_INTERP
1558 static char*
1559 dump_stack (stackval *stack, stackval *sp)
1561 stackval *s = stack;
1562 GString *str = g_string_new ("");
1564 if (sp == stack)
1565 return g_string_free (str, FALSE);
1567 while (s < sp) {
1568 g_string_append_printf (str, "[%p (%lld)] ", s->data.l, s->data.l);
1569 ++s;
1571 return g_string_free (str, FALSE);
1574 static void
1575 dump_stackval (GString *str, stackval *s, MonoType *type)
1577 switch (type->type) {
1578 case MONO_TYPE_I1:
1579 case MONO_TYPE_U1:
1580 case MONO_TYPE_I2:
1581 case MONO_TYPE_U2:
1582 case MONO_TYPE_I4:
1583 case MONO_TYPE_U4:
1584 case MONO_TYPE_CHAR:
1585 case MONO_TYPE_BOOLEAN:
1586 g_string_append_printf (str, "[%d] ", s->data.i);
1587 break;
1588 case MONO_TYPE_STRING:
1589 case MONO_TYPE_SZARRAY:
1590 case MONO_TYPE_CLASS:
1591 case MONO_TYPE_OBJECT:
1592 case MONO_TYPE_ARRAY:
1593 case MONO_TYPE_PTR:
1594 case MONO_TYPE_I:
1595 case MONO_TYPE_U:
1596 g_string_append_printf (str, "[%p] ", s->data.p);
1597 break;
1598 case MONO_TYPE_VALUETYPE:
1599 if (m_class_is_enumtype (type->data.klass))
1600 g_string_append_printf (str, "[%d] ", s->data.i);
1601 else
1602 g_string_append_printf (str, "[vt:%p] ", s->data.p);
1603 break;
1604 case MONO_TYPE_R4:
1605 g_string_append_printf (str, "[%g] ", s->data.f_r4);
1606 break;
1607 case MONO_TYPE_R8:
1608 g_string_append_printf (str, "[%g] ", s->data.f);
1609 break;
1610 case MONO_TYPE_I8:
1611 case MONO_TYPE_U8:
1612 default: {
1613 GString *res = g_string_new ("");
1614 mono_type_get_desc (res, type, TRUE);
1615 g_string_append_printf (str, "[{%s} %lld/0x%0llx] ", res->str, s->data.l, s->data.l);
1616 g_string_free (res, TRUE);
1617 break;
1622 static char*
1623 dump_retval (InterpFrame *inv)
1625 GString *str = g_string_new ("");
1626 MonoType *ret = mono_method_signature_internal (inv->imethod->method)->ret;
1628 if (ret->type != MONO_TYPE_VOID)
1629 dump_stackval (str, inv->retval, ret);
1631 return g_string_free (str, FALSE);
1634 static char*
1635 dump_args (InterpFrame *inv)
1637 GString *str = g_string_new ("");
1638 int i;
1639 MonoMethodSignature *signature = mono_method_signature_internal (inv->imethod->method);
1641 if (signature->param_count == 0 && !signature->hasthis)
1642 return g_string_free (str, FALSE);
1644 if (signature->hasthis) {
1645 MonoMethod *method = inv->imethod->method;
1646 dump_stackval (str, inv->stack_args, m_class_get_byval_arg (method->klass));
1649 for (i = 0; i < signature->param_count; ++i)
1650 dump_stackval (str, inv->stack_args + (!!signature->hasthis) + i, signature->params [i]);
1652 return g_string_free (str, FALSE);
1654 #endif
1656 #define CHECK_ADD_OVERFLOW(a,b) \
1657 (gint32)(b) >= 0 ? (gint32)(G_MAXINT32) - (gint32)(b) < (gint32)(a) ? -1 : 0 \
1658 : (gint32)(G_MININT32) - (gint32)(b) > (gint32)(a) ? +1 : 0
1660 #define CHECK_SUB_OVERFLOW(a,b) \
1661 (gint32)(b) < 0 ? (gint32)(G_MAXINT32) + (gint32)(b) < (gint32)(a) ? -1 : 0 \
1662 : (gint32)(G_MININT32) + (gint32)(b) > (gint32)(a) ? +1 : 0
1664 #define CHECK_ADD_OVERFLOW_UN(a,b) \
1665 (guint32)(G_MAXUINT32) - (guint32)(b) < (guint32)(a) ? -1 : 0
1667 #define CHECK_SUB_OVERFLOW_UN(a,b) \
1668 (guint32)(a) < (guint32)(b) ? -1 : 0
1670 #define CHECK_ADD_OVERFLOW64(a,b) \
1671 (gint64)(b) >= 0 ? (gint64)(G_MAXINT64) - (gint64)(b) < (gint64)(a) ? -1 : 0 \
1672 : (gint64)(G_MININT64) - (gint64)(b) > (gint64)(a) ? +1 : 0
1674 #define CHECK_SUB_OVERFLOW64(a,b) \
1675 (gint64)(b) < 0 ? (gint64)(G_MAXINT64) + (gint64)(b) < (gint64)(a) ? -1 : 0 \
1676 : (gint64)(G_MININT64) + (gint64)(b) > (gint64)(a) ? +1 : 0
1678 #define CHECK_ADD_OVERFLOW64_UN(a,b) \
1679 (guint64)(G_MAXUINT64) - (guint64)(b) < (guint64)(a) ? -1 : 0
1681 #define CHECK_SUB_OVERFLOW64_UN(a,b) \
1682 (guint64)(a) < (guint64)(b) ? -1 : 0
1684 #if SIZEOF_VOID_P == 4
1685 #define CHECK_ADD_OVERFLOW_NAT(a,b) CHECK_ADD_OVERFLOW(a,b)
1686 #define CHECK_ADD_OVERFLOW_NAT_UN(a,b) CHECK_ADD_OVERFLOW_UN(a,b)
1687 #else
1688 #define CHECK_ADD_OVERFLOW_NAT(a,b) CHECK_ADD_OVERFLOW64(a,b)
1689 #define CHECK_ADD_OVERFLOW_NAT_UN(a,b) CHECK_ADD_OVERFLOW64_UN(a,b)
1690 #endif
1692 /* Resolves to TRUE if the operands would overflow */
1693 #define CHECK_MUL_OVERFLOW(a,b) \
1694 ((gint32)(a) == 0) || ((gint32)(b) == 0) ? 0 : \
1695 (((gint32)(a) > 0) && ((gint32)(b) == -1)) ? FALSE : \
1696 (((gint32)(a) < 0) && ((gint32)(b) == -1)) ? (a == G_MININT32) : \
1697 (((gint32)(a) > 0) && ((gint32)(b) > 0)) ? (gint32)(a) > ((G_MAXINT32) / (gint32)(b)) : \
1698 (((gint32)(a) > 0) && ((gint32)(b) < 0)) ? (gint32)(a) > ((G_MININT32) / (gint32)(b)) : \
1699 (((gint32)(a) < 0) && ((gint32)(b) > 0)) ? (gint32)(a) < ((G_MININT32) / (gint32)(b)) : \
1700 (gint32)(a) < ((G_MAXINT32) / (gint32)(b))
1702 #define CHECK_MUL_OVERFLOW_UN(a,b) \
1703 ((guint32)(a) == 0) || ((guint32)(b) == 0) ? 0 : \
1704 (guint32)(b) > ((G_MAXUINT32) / (guint32)(a))
1706 #define CHECK_MUL_OVERFLOW64(a,b) \
1707 ((gint64)(a) == 0) || ((gint64)(b) == 0) ? 0 : \
1708 (((gint64)(a) > 0) && ((gint64)(b) == -1)) ? FALSE : \
1709 (((gint64)(a) < 0) && ((gint64)(b) == -1)) ? (a == G_MININT64) : \
1710 (((gint64)(a) > 0) && ((gint64)(b) > 0)) ? (gint64)(a) > ((G_MAXINT64) / (gint64)(b)) : \
1711 (((gint64)(a) > 0) && ((gint64)(b) < 0)) ? (gint64)(a) > ((G_MININT64) / (gint64)(b)) : \
1712 (((gint64)(a) < 0) && ((gint64)(b) > 0)) ? (gint64)(a) < ((G_MININT64) / (gint64)(b)) : \
1713 (gint64)(a) < ((G_MAXINT64) / (gint64)(b))
1715 #define CHECK_MUL_OVERFLOW64_UN(a,b) \
1716 ((guint64)(a) == 0) || ((guint64)(b) == 0) ? 0 : \
1717 (guint64)(b) > ((G_MAXUINT64) / (guint64)(a))
1719 #if SIZEOF_VOID_P == 4
1720 #define CHECK_MUL_OVERFLOW_NAT(a,b) CHECK_MUL_OVERFLOW(a,b)
1721 #define CHECK_MUL_OVERFLOW_NAT_UN(a,b) CHECK_MUL_OVERFLOW_UN(a,b)
1722 #else
1723 #define CHECK_MUL_OVERFLOW_NAT(a,b) CHECK_MUL_OVERFLOW64(a,b)
1724 #define CHECK_MUL_OVERFLOW_NAT_UN(a,b) CHECK_MUL_OVERFLOW64_UN(a,b)
1725 #endif
1727 static MonoObject*
1728 interp_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError *error)
1730 InterpFrame frame;
1731 ThreadContext *context = get_context ();
1732 MonoMethodSignature *sig = mono_method_signature_internal (method);
1733 MonoClass *klass = mono_class_from_mono_type_internal (sig->ret);
1734 stackval result;
1735 MonoMethod *target_method = method;
1737 error_init (error);
1738 if (exc)
1739 *exc = NULL;
1741 frame.ex = NULL;
1743 MonoDomain *domain = mono_domain_get ();
1745 if (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
1746 target_method = mono_marshal_get_native_wrapper (target_method, FALSE, FALSE);
1747 MonoMethod *invoke_wrapper = mono_marshal_get_runtime_invoke_full (target_method, FALSE, TRUE);
1749 //* <code>MonoObject *runtime_invoke (MonoObject *this_obj, void **params, MonoObject **exc, void* method)</code>
1751 result.data.vt = alloca (mono_class_instance_size (klass));
1752 stackval args [4];
1754 if (sig->hasthis)
1755 args [0].data.p = obj;
1756 else
1757 args [0].data.p = NULL;
1758 args [1].data.p = params;
1759 args [2].data.p = exc;
1760 args [3].data.p = target_method;
1762 InterpMethod *imethod = mono_interp_get_imethod (domain, invoke_wrapper, error);
1763 mono_error_assert_ok (error);
1764 init_frame (&frame, NULL, imethod, args, &result);
1766 interp_exec_method (&frame, context, error);
1768 if (frame.ex) {
1769 if (exc) {
1770 *exc = (MonoObject*) frame.ex;
1771 return NULL;
1773 mono_error_set_exception_instance (error, frame.ex);
1774 return NULL;
1776 return (MonoObject*)result.data.p;
1779 typedef struct {
1780 InterpMethod *rmethod;
1781 gpointer this_arg;
1782 gpointer res;
1783 gpointer args [16];
1784 gpointer *many_args;
1785 } InterpEntryData;
1787 /* Main function for entering the interpreter from compiled code */
1788 static void
1789 interp_entry (InterpEntryData *data)
1791 InterpFrame frame;
1792 InterpMethod *rmethod;
1793 ThreadContext *context;
1794 stackval result;
1795 stackval *args;
1796 MonoMethod *method;
1797 MonoMethodSignature *sig;
1798 MonoType *type;
1799 gpointer orig_domain = NULL, attach_cookie;
1800 int i;
1802 if ((gsize)data->rmethod & 1) {
1803 /* Unbox */
1804 data->this_arg = mono_object_unbox_internal ((MonoObject*)data->this_arg);
1805 data->rmethod = (InterpMethod*)(gpointer)((gsize)data->rmethod & ~1);
1807 rmethod = data->rmethod;
1809 if (rmethod->needs_thread_attach)
1810 orig_domain = mono_threads_attach_coop (mono_domain_get (), &attach_cookie);
1812 context = get_context ();
1814 method = rmethod->method;
1815 sig = mono_method_signature_internal (method);
1817 // FIXME: Optimize this
1819 //printf ("%s\n", mono_method_full_name (method, 1));
1821 frame.ex = NULL;
1823 args = g_newa (stackval, sig->param_count + (sig->hasthis ? 1 : 0));
1824 if (sig->hasthis)
1825 args [0].data.p = data->this_arg;
1827 gpointer *params;
1828 if (data->many_args)
1829 params = data->many_args;
1830 else
1831 params = data->args;
1832 for (i = 0; i < sig->param_count; ++i) {
1833 int a_index = i + (sig->hasthis ? 1 : 0);
1834 if (sig->params [i]->byref) {
1835 args [a_index].data.p = params [i];
1836 continue;
1838 type = rmethod->param_types [i];
1839 switch (type->type) {
1840 case MONO_TYPE_VALUETYPE:
1841 args [a_index].data.p = params [i];
1842 break;
1843 case MONO_TYPE_GENERICINST:
1844 if (MONO_TYPE_IS_REFERENCE (type))
1845 args [a_index].data.p = *(gpointer*)params [i];
1846 else
1847 args [a_index].data.vt = params [i];
1848 break;
1849 default:
1850 stackval_from_data (type, &args [a_index], params [i], FALSE);
1851 break;
1855 memset (&result, 0, sizeof (result));
1856 init_frame (&frame, NULL, data->rmethod, args, &result);
1858 type = rmethod->rtype;
1859 switch (type->type) {
1860 case MONO_TYPE_GENERICINST:
1861 if (!MONO_TYPE_IS_REFERENCE (type))
1862 frame.retval->data.vt = data->res;
1863 break;
1864 case MONO_TYPE_VALUETYPE:
1865 frame.retval->data.vt = data->res;
1866 break;
1867 default:
1868 break;
1871 ERROR_DECL (error);
1872 interp_exec_method (&frame, context, error);
1874 if (rmethod->needs_thread_attach)
1875 mono_threads_detach_coop (orig_domain, &attach_cookie);
1877 if (mono_llvm_only) {
1878 if (frame.ex)
1879 mono_llvm_reraise_exception (frame.ex);
1880 } else {
1881 g_assert (frame.ex == NULL);
1884 type = rmethod->rtype;
1885 switch (type->type) {
1886 case MONO_TYPE_VOID:
1887 break;
1888 case MONO_TYPE_OBJECT:
1889 /* No need for a write barrier */
1890 *(MonoObject**)data->res = (MonoObject*)frame.retval->data.p;
1891 break;
1892 case MONO_TYPE_GENERICINST:
1893 if (MONO_TYPE_IS_REFERENCE (type)) {
1894 *(MonoObject**)data->res = (MonoObject*)frame.retval->data.p;
1895 } else {
1896 /* Already set before the call */
1898 break;
1899 case MONO_TYPE_VALUETYPE:
1900 /* Already set before the call */
1901 break;
1902 default:
1903 stackval_to_data (type, frame.retval, data->res, FALSE);
1904 break;
1908 static stackval *
1909 do_icall (InterpFrame *frame, MonoMethodSignature *sig, int op, stackval *sp, gpointer ptr, gboolean save_last_error)
1911 #ifdef ENABLE_NETCORE
1912 if (save_last_error)
1913 mono_marshal_clear_last_error ();
1914 #endif
1916 switch (op) {
1917 case MINT_ICALL_V_V: {
1918 typedef void (*T)(void);
1919 T func = (T)ptr;
1920 func ();
1921 break;
1923 case MINT_ICALL_V_P: {
1924 typedef gpointer (*T)(void);
1925 T func = (T)ptr;
1926 sp++;
1927 sp [-1].data.p = func ();
1928 break;
1930 case MINT_ICALL_P_V: {
1931 typedef void (*T)(gpointer);
1932 T func = (T)ptr;
1933 func (sp [-1].data.p);
1934 sp --;
1935 break;
1937 case MINT_ICALL_P_P: {
1938 typedef gpointer (*T)(gpointer);
1939 T func = (T)ptr;
1940 sp [-1].data.p = func (sp [-1].data.p);
1941 break;
1943 case MINT_ICALL_PP_V: {
1944 typedef void (*T)(gpointer,gpointer);
1945 T func = (T)ptr;
1946 sp -= 2;
1947 func (sp [0].data.p, sp [1].data.p);
1948 break;
1950 case MINT_ICALL_PP_P: {
1951 typedef gpointer (*T)(gpointer,gpointer);
1952 T func = (T)ptr;
1953 --sp;
1954 sp [-1].data.p = func (sp [-1].data.p, sp [0].data.p);
1955 break;
1957 case MINT_ICALL_PPP_V: {
1958 typedef void (*T)(gpointer,gpointer,gpointer);
1959 T func = (T)ptr;
1960 sp -= 3;
1961 func (sp [0].data.p, sp [1].data.p, sp [2].data.p);
1962 break;
1964 case MINT_ICALL_PPP_P: {
1965 typedef gpointer (*T)(gpointer,gpointer,gpointer);
1966 T func = (T)ptr;
1967 sp -= 2;
1968 sp [-1].data.p = func (sp [-1].data.p, sp [0].data.p, sp [1].data.p);
1969 break;
1971 case MINT_ICALL_PPPP_V: {
1972 typedef void (*T)(gpointer,gpointer,gpointer,gpointer);
1973 T func = (T)ptr;
1974 sp -= 4;
1975 func (sp [0].data.p, sp [1].data.p, sp [2].data.p, sp [3].data.p);
1976 break;
1978 case MINT_ICALL_PPPP_P: {
1979 typedef gpointer (*T)(gpointer,gpointer,gpointer,gpointer);
1980 T func = (T)ptr;
1981 sp -= 3;
1982 sp [-1].data.p = func (sp [-1].data.p, sp [0].data.p, sp [1].data.p, sp [2].data.p);
1983 break;
1985 case MINT_ICALL_PPPPP_V: {
1986 typedef void (*T)(gpointer,gpointer,gpointer,gpointer,gpointer);
1987 T func = (T)ptr;
1988 sp -= 5;
1989 func (sp [0].data.p, sp [1].data.p, sp [2].data.p, sp [3].data.p, sp [4].data.p);
1990 break;
1992 case MINT_ICALL_PPPPP_P: {
1993 typedef gpointer (*T)(gpointer,gpointer,gpointer,gpointer,gpointer);
1994 T func = (T)ptr;
1995 sp -= 4;
1996 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);
1997 break;
1999 case MINT_ICALL_PPPPPP_V: {
2000 typedef void (*T)(gpointer,gpointer,gpointer,gpointer,gpointer,gpointer);
2001 T func = (T)ptr;
2002 sp -= 6;
2003 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);
2004 break;
2006 case MINT_ICALL_PPPPPP_P: {
2007 typedef gpointer (*T)(gpointer,gpointer,gpointer,gpointer,gpointer,gpointer);
2008 T func = (T)ptr;
2009 sp -= 5;
2010 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);
2011 break;
2013 default:
2014 g_assert_not_reached ();
2017 if (save_last_error)
2018 mono_marshal_set_last_error ();
2020 /* convert the native representation to the stackval representation */
2021 if (sig)
2022 stackval_from_data (sig->ret, &sp [-1], (char*) &sp [-1].data.p, sig->pinvoke);
2024 return sp;
2027 /* MONO_NO_OPTIMIATION is needed due to usage of INTERP_PUSH_LMF_WITH_CTX. */
2028 #ifdef _MSC_VER
2029 #pragma optimize ("", off)
2030 #endif
2031 static MONO_NO_OPTIMIZATION MONO_NEVER_INLINE stackval *
2032 do_icall_wrapper (InterpFrame *frame, MonoMethodSignature *sig, int op, stackval *sp, gpointer ptr, gboolean save_last_error)
2034 MonoLMFExt ext;
2035 INTERP_PUSH_LMF_WITH_CTX (frame, ext, exit_icall);
2037 sp = do_icall (frame, sig, op, sp, ptr, save_last_error);
2039 interp_pop_lmf (&ext);
2041 goto exit_icall; // prevent unused label warning in some configurations
2042 exit_icall:
2043 return sp;
2045 #ifdef _MSC_VER
2046 #pragma optimize ("", on)
2047 #endif
2049 typedef struct {
2050 int pindex;
2051 gpointer jit_wrapper;
2052 gpointer *args;
2053 MonoFtnDesc *ftndesc;
2054 } JitCallCbData;
2056 static void
2057 jit_call_cb (gpointer arg)
2059 JitCallCbData *cb_data = (JitCallCbData*)arg;
2060 gpointer jit_wrapper = cb_data->jit_wrapper;
2061 int pindex = cb_data->pindex;
2062 gpointer *args = cb_data->args;
2063 MonoFtnDesc ftndesc = *cb_data->ftndesc;
2065 switch (pindex) {
2066 case 0: {
2067 typedef void (*T)(gpointer);
2068 T func = (T)jit_wrapper;
2070 func (&ftndesc);
2071 break;
2073 case 1: {
2074 typedef void (*T)(gpointer, gpointer);
2075 T func = (T)jit_wrapper;
2077 func (args [0], &ftndesc);
2078 break;
2080 case 2: {
2081 typedef void (*T)(gpointer, gpointer, gpointer);
2082 T func = (T)jit_wrapper;
2084 func (args [0], args [1], &ftndesc);
2085 break;
2087 case 3: {
2088 typedef void (*T)(gpointer, gpointer, gpointer, gpointer);
2089 T func = (T)jit_wrapper;
2091 func (args [0], args [1], args [2], &ftndesc);
2092 break;
2094 case 4: {
2095 typedef void (*T)(gpointer, gpointer, gpointer, gpointer, gpointer);
2096 T func = (T)jit_wrapper;
2098 func (args [0], args [1], args [2], args [3], &ftndesc);
2099 break;
2101 case 5: {
2102 typedef void (*T)(gpointer, gpointer, gpointer, gpointer, gpointer, gpointer);
2103 T func = (T)jit_wrapper;
2105 func (args [0], args [1], args [2], args [3], args [4], &ftndesc);
2106 break;
2108 case 6: {
2109 typedef void (*T)(gpointer, gpointer, gpointer, gpointer, gpointer, gpointer, gpointer);
2110 T func = (T)jit_wrapper;
2112 func (args [0], args [1], args [2], args [3], args [4], args [5], &ftndesc);
2113 break;
2115 case 7: {
2116 typedef void (*T)(gpointer, gpointer, gpointer, gpointer, gpointer, gpointer, gpointer, gpointer);
2117 T func = (T)jit_wrapper;
2119 func (args [0], args [1], args [2], args [3], args [4], args [5], args [6], &ftndesc);
2120 break;
2122 case 8: {
2123 typedef void (*T)(gpointer, gpointer, gpointer, gpointer, gpointer, gpointer, gpointer, gpointer, gpointer);
2124 T func = (T)jit_wrapper;
2126 func (args [0], args [1], args [2], args [3], args [4], args [5], args [6], args [7], &ftndesc);
2127 break;
2129 default:
2130 g_assert_not_reached ();
2131 break;
2135 static MONO_NEVER_INLINE stackval *
2136 do_jit_call (stackval *sp, unsigned char *vt_sp, ThreadContext *context, InterpFrame *frame, InterpMethod *rmethod, MonoError *error)
2138 MonoMethodSignature *sig;
2139 MonoFtnDesc ftndesc;
2140 guint8 res_buf [256];
2141 MonoType *type;
2142 MonoLMFExt ext;
2144 //printf ("jit_call: %s\n", mono_method_full_name (rmethod->method, 1));
2147 * Call JITted code through a gsharedvt_out wrapper. These wrappers receive every argument
2148 * by ref and return a return value using an explicit return value argument.
2150 if (!rmethod->jit_wrapper) {
2151 MonoMethod *method = rmethod->method;
2153 sig = mono_method_signature_internal (method);
2154 g_assert (sig);
2156 MonoMethod *wrapper = mini_get_gsharedvt_out_sig_wrapper (sig);
2157 //printf ("J: %s %s\n", mono_method_full_name (method, 1), mono_method_full_name (wrapper, 1));
2159 gpointer jit_wrapper = mono_jit_compile_method_jit_only (wrapper, error);
2160 mono_error_assert_ok (error);
2162 gpointer addr = mono_jit_compile_method_jit_only (method, error);
2163 return_val_if_nok (error, NULL);
2164 g_assert (addr);
2166 rmethod->jit_addr = addr;
2167 rmethod->jit_sig = sig;
2168 mono_memory_barrier ();
2169 rmethod->jit_wrapper = jit_wrapper;
2171 } else {
2172 sig = rmethod->jit_sig;
2175 sp -= sig->param_count;
2176 if (sig->hasthis)
2177 --sp;
2179 ftndesc.addr = rmethod->jit_addr;
2180 ftndesc.arg = NULL;
2182 // FIXME: Optimize this
2184 gpointer args [32];
2185 int pindex = 0;
2186 int stack_index = 0;
2187 if (rmethod->hasthis) {
2188 args [pindex ++] = sp [0].data.p;
2189 stack_index ++;
2191 type = rmethod->rtype;
2192 if (type->type != MONO_TYPE_VOID) {
2193 if (MONO_TYPE_ISSTRUCT (type))
2194 args [pindex ++] = vt_sp;
2195 else
2196 args [pindex ++] = res_buf;
2198 for (int i = 0; i < rmethod->param_count; ++i) {
2199 MonoType *t = rmethod->param_types [i];
2200 stackval *sval = &sp [stack_index + i];
2201 if (sig->params [i]->byref) {
2202 args [pindex ++] = sval->data.p;
2203 } else if (MONO_TYPE_ISSTRUCT (t)) {
2204 args [pindex ++] = sval->data.p;
2205 } else if (MONO_TYPE_IS_REFERENCE (t)) {
2206 args [pindex ++] = &sval->data.p;
2207 } else {
2208 switch (t->type) {
2209 case MONO_TYPE_I1:
2210 case MONO_TYPE_U1:
2211 case MONO_TYPE_I2:
2212 case MONO_TYPE_U2:
2213 case MONO_TYPE_I4:
2214 case MONO_TYPE_U4:
2215 case MONO_TYPE_VALUETYPE:
2216 args [pindex ++] = &sval->data.i;
2217 break;
2218 case MONO_TYPE_PTR:
2219 case MONO_TYPE_FNPTR:
2220 case MONO_TYPE_I:
2221 case MONO_TYPE_U:
2222 case MONO_TYPE_OBJECT:
2223 args [pindex ++] = &sval->data.p;
2224 break;
2225 case MONO_TYPE_I8:
2226 case MONO_TYPE_U8:
2227 args [pindex ++] = &sval->data.l;
2228 break;
2229 case MONO_TYPE_R4:
2230 args [pindex ++] = &sval->data.f_r4;
2231 break;
2232 case MONO_TYPE_R8:
2233 args [pindex ++] = &sval->data.f;
2234 break;
2235 default:
2236 printf ("%s\n", mono_type_full_name (t));
2237 g_assert_not_reached ();
2242 interp_push_lmf (&ext, frame);
2244 JitCallCbData cb_data;
2245 memset (&cb_data, 0, sizeof (cb_data));
2246 cb_data.jit_wrapper = rmethod->jit_wrapper;
2247 cb_data.pindex = pindex;
2248 cb_data.args = args;
2249 cb_data.ftndesc = &ftndesc;
2251 if (mono_aot_mode == MONO_AOT_MODE_LLVMONLY_INTERP) {
2252 /* Catch the exception thrown by the native code using a try-catch */
2253 gboolean thrown = FALSE;
2254 mono_llvm_cpp_catch_exception (jit_call_cb, &cb_data, &thrown);
2255 interp_pop_lmf (&ext);
2256 if (thrown) {
2257 MonoObject *obj = mono_llvm_load_exception ();
2258 g_assert (obj);
2259 mono_error_set_exception_instance (error, (MonoException*)obj);
2260 return sp;
2262 } else {
2263 jit_call_cb (&cb_data);
2264 interp_pop_lmf (&ext);
2267 MonoType *rtype = rmethod->rtype;
2268 switch (rtype->type) {
2269 case MONO_TYPE_VOID:
2270 case MONO_TYPE_OBJECT:
2271 case MONO_TYPE_STRING:
2272 case MONO_TYPE_CLASS:
2273 case MONO_TYPE_ARRAY:
2274 case MONO_TYPE_SZARRAY:
2275 case MONO_TYPE_I:
2276 case MONO_TYPE_U:
2277 case MONO_TYPE_PTR:
2278 sp->data.p = *(gpointer*)res_buf;
2279 break;
2280 case MONO_TYPE_I1:
2281 sp->data.i = *(gint8*)res_buf;
2282 break;
2283 case MONO_TYPE_U1:
2284 sp->data.i = *(guint8*)res_buf;
2285 break;
2286 case MONO_TYPE_I2:
2287 sp->data.i = *(gint16*)res_buf;
2288 break;
2289 case MONO_TYPE_U2:
2290 sp->data.i = *(guint16*)res_buf;
2291 break;
2292 case MONO_TYPE_I4:
2293 sp->data.i = *(gint32*)res_buf;
2294 break;
2295 case MONO_TYPE_U4:
2296 sp->data.i = *(guint32*)res_buf;
2297 break;
2298 case MONO_TYPE_I8:
2299 sp->data.l = *(gint64*)res_buf;
2300 break;
2301 case MONO_TYPE_U8:
2302 sp->data.l = *(guint64*)res_buf;
2303 break;
2304 case MONO_TYPE_R4:
2305 sp->data.f_r4 = *(float*)res_buf;
2306 break;
2307 case MONO_TYPE_R8:
2308 sp->data.f = *(double*)res_buf;
2309 break;
2310 case MONO_TYPE_TYPEDBYREF:
2311 case MONO_TYPE_VALUETYPE:
2312 /* The result was written to vt_sp */
2313 sp->data.p = vt_sp;
2314 break;
2315 case MONO_TYPE_GENERICINST:
2316 if (MONO_TYPE_IS_REFERENCE (rtype)) {
2317 sp->data.p = *(gpointer*)res_buf;
2318 } else {
2319 /* The result was written to vt_sp */
2320 sp->data.p = vt_sp;
2322 break;
2323 default:
2324 g_print ("%s\n", mono_type_full_name (rtype));
2325 g_assert_not_reached ();
2326 break;
2329 return sp;
2332 static MONO_NEVER_INLINE void
2333 do_debugger_tramp (void (*tramp) (void), InterpFrame *frame)
2335 MonoLMFExt ext;
2336 interp_push_lmf (&ext, frame);
2337 tramp ();
2338 interp_pop_lmf (&ext);
2341 static MONO_NEVER_INLINE void
2342 do_transform_method (InterpFrame *frame, ThreadContext *context)
2344 MonoLMFExt ext;
2345 /* Don't push lmf if we have no interp data */
2346 gboolean push_lmf = frame->parent != NULL;
2347 ERROR_DECL (error);
2349 /* Use the parent frame as the current frame is not complete yet */
2350 if (push_lmf)
2351 interp_push_lmf (&ext, frame->parent);
2353 mono_interp_transform_method (frame->imethod, context, error);
2354 frame->ex = mono_error_convert_to_exception (error);
2356 if (push_lmf)
2357 interp_pop_lmf (&ext);
2360 static MONO_NEVER_INLINE void
2361 copy_varargs_vtstack (MonoMethodSignature *csig, stackval *sp, unsigned char **vt_sp)
2363 char *vt = *(char**)vt_sp;
2364 stackval *first_arg = sp - csig->param_count;
2367 * We need to have the varargs linearly on the stack so the ArgIterator
2368 * can iterate over them. We pass the signature first and then copy them
2369 * one by one on the vtstack.
2371 *(gpointer*)vt = csig;
2372 vt += sizeof (gpointer);
2374 for (int i = csig->sentinelpos; i < csig->param_count; i++) {
2375 int align, arg_size;
2376 arg_size = mono_type_stack_size (csig->params [i], &align);
2377 vt = (char*)ALIGN_PTR_TO (vt, align);
2379 stackval_to_data (csig->params [i], &first_arg [i], vt, FALSE);
2380 vt += arg_size;
2383 vt = (char*)ALIGN_PTR_TO (vt, MINT_VT_ALIGNMENT);
2385 *(char**)vt_sp = vt;
2389 * These functions are the entry points into the interpreter from compiled code.
2390 * They are called by the interp_in wrappers. They have the following signature:
2391 * void (<optional this_arg>, <optional retval pointer>, <arg1>, ..., <argn>, <method ptr>)
2392 * They pack up their arguments into an InterpEntryData structure and call interp_entry ().
2393 * It would be possible for the wrappers to pack up the arguments etc, but that would make them bigger, and there are
2394 * more wrappers then these functions.
2395 * this/static * ret/void * 16 arguments -> 64 functions.
2398 #define MAX_INTERP_ENTRY_ARGS 8
2400 #define INTERP_ENTRY_BASE(_method, _this_arg, _res) \
2401 InterpEntryData data; \
2402 (data).rmethod = (_method); \
2403 (data).res = (_res); \
2404 (data).this_arg = (_this_arg); \
2405 (data).many_args = NULL;
2407 #define INTERP_ENTRY0(_this_arg, _res, _method) { \
2408 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2409 interp_entry (&data); \
2411 #define INTERP_ENTRY1(_this_arg, _res, _method) { \
2412 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2413 (data).args [0] = arg1; \
2414 interp_entry (&data); \
2416 #define INTERP_ENTRY2(_this_arg, _res, _method) { \
2417 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2418 (data).args [0] = arg1; \
2419 (data).args [1] = arg2; \
2420 interp_entry (&data); \
2422 #define INTERP_ENTRY3(_this_arg, _res, _method) { \
2423 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2424 (data).args [0] = arg1; \
2425 (data).args [1] = arg2; \
2426 (data).args [2] = arg3; \
2427 interp_entry (&data); \
2429 #define INTERP_ENTRY4(_this_arg, _res, _method) { \
2430 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2431 (data).args [0] = arg1; \
2432 (data).args [1] = arg2; \
2433 (data).args [2] = arg3; \
2434 (data).args [3] = arg4; \
2435 interp_entry (&data); \
2437 #define INTERP_ENTRY5(_this_arg, _res, _method) { \
2438 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2439 (data).args [0] = arg1; \
2440 (data).args [1] = arg2; \
2441 (data).args [2] = arg3; \
2442 (data).args [3] = arg4; \
2443 (data).args [4] = arg5; \
2444 interp_entry (&data); \
2446 #define INTERP_ENTRY6(_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 (data).args [3] = arg4; \
2452 (data).args [4] = arg5; \
2453 (data).args [5] = arg6; \
2454 interp_entry (&data); \
2456 #define INTERP_ENTRY7(_this_arg, _res, _method) { \
2457 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2458 (data).args [0] = arg1; \
2459 (data).args [1] = arg2; \
2460 (data).args [2] = arg3; \
2461 (data).args [3] = arg4; \
2462 (data).args [4] = arg5; \
2463 (data).args [5] = arg6; \
2464 (data).args [6] = arg7; \
2465 interp_entry (&data); \
2467 #define INTERP_ENTRY8(_this_arg, _res, _method) { \
2468 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2469 (data).args [0] = arg1; \
2470 (data).args [1] = arg2; \
2471 (data).args [2] = arg3; \
2472 (data).args [3] = arg4; \
2473 (data).args [4] = arg5; \
2474 (data).args [5] = arg6; \
2475 (data).args [6] = arg7; \
2476 (data).args [7] = arg8; \
2477 interp_entry (&data); \
2480 #define ARGLIST0 InterpMethod *rmethod
2481 #define ARGLIST1 gpointer arg1, InterpMethod *rmethod
2482 #define ARGLIST2 gpointer arg1, gpointer arg2, InterpMethod *rmethod
2483 #define ARGLIST3 gpointer arg1, gpointer arg2, gpointer arg3, InterpMethod *rmethod
2484 #define ARGLIST4 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, InterpMethod *rmethod
2485 #define ARGLIST5 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, gpointer arg5, InterpMethod *rmethod
2486 #define ARGLIST6 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, gpointer arg5, gpointer arg6, InterpMethod *rmethod
2487 #define ARGLIST7 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, gpointer arg5, gpointer arg6, gpointer arg7, InterpMethod *rmethod
2488 #define ARGLIST8 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, gpointer arg5, gpointer arg6, gpointer arg7, gpointer arg8, InterpMethod *rmethod
2490 static void interp_entry_static_0 (ARGLIST0) INTERP_ENTRY0 (NULL, NULL, rmethod)
2491 static void interp_entry_static_1 (ARGLIST1) INTERP_ENTRY1 (NULL, NULL, rmethod)
2492 static void interp_entry_static_2 (ARGLIST2) INTERP_ENTRY2 (NULL, NULL, rmethod)
2493 static void interp_entry_static_3 (ARGLIST3) INTERP_ENTRY3 (NULL, NULL, rmethod)
2494 static void interp_entry_static_4 (ARGLIST4) INTERP_ENTRY4 (NULL, NULL, rmethod)
2495 static void interp_entry_static_5 (ARGLIST5) INTERP_ENTRY5 (NULL, NULL, rmethod)
2496 static void interp_entry_static_6 (ARGLIST6) INTERP_ENTRY6 (NULL, NULL, rmethod)
2497 static void interp_entry_static_7 (ARGLIST7) INTERP_ENTRY7 (NULL, NULL, rmethod)
2498 static void interp_entry_static_8 (ARGLIST8) INTERP_ENTRY8 (NULL, NULL, rmethod)
2499 static void interp_entry_static_ret_0 (gpointer res, ARGLIST0) INTERP_ENTRY0 (NULL, res, rmethod)
2500 static void interp_entry_static_ret_1 (gpointer res, ARGLIST1) INTERP_ENTRY1 (NULL, res, rmethod)
2501 static void interp_entry_static_ret_2 (gpointer res, ARGLIST2) INTERP_ENTRY2 (NULL, res, rmethod)
2502 static void interp_entry_static_ret_3 (gpointer res, ARGLIST3) INTERP_ENTRY3 (NULL, res, rmethod)
2503 static void interp_entry_static_ret_4 (gpointer res, ARGLIST4) INTERP_ENTRY4 (NULL, res, rmethod)
2504 static void interp_entry_static_ret_5 (gpointer res, ARGLIST5) INTERP_ENTRY5 (NULL, res, rmethod)
2505 static void interp_entry_static_ret_6 (gpointer res, ARGLIST6) INTERP_ENTRY6 (NULL, res, rmethod)
2506 static void interp_entry_static_ret_7 (gpointer res, ARGLIST7) INTERP_ENTRY7 (NULL, res, rmethod)
2507 static void interp_entry_static_ret_8 (gpointer res, ARGLIST8) INTERP_ENTRY8 (NULL, res, rmethod)
2508 static void interp_entry_instance_0 (gpointer this_arg, ARGLIST0) INTERP_ENTRY0 (this_arg, NULL, rmethod)
2509 static void interp_entry_instance_1 (gpointer this_arg, ARGLIST1) INTERP_ENTRY1 (this_arg, NULL, rmethod)
2510 static void interp_entry_instance_2 (gpointer this_arg, ARGLIST2) INTERP_ENTRY2 (this_arg, NULL, rmethod)
2511 static void interp_entry_instance_3 (gpointer this_arg, ARGLIST3) INTERP_ENTRY3 (this_arg, NULL, rmethod)
2512 static void interp_entry_instance_4 (gpointer this_arg, ARGLIST4) INTERP_ENTRY4 (this_arg, NULL, rmethod)
2513 static void interp_entry_instance_5 (gpointer this_arg, ARGLIST5) INTERP_ENTRY5 (this_arg, NULL, rmethod)
2514 static void interp_entry_instance_6 (gpointer this_arg, ARGLIST6) INTERP_ENTRY6 (this_arg, NULL, rmethod)
2515 static void interp_entry_instance_7 (gpointer this_arg, ARGLIST7) INTERP_ENTRY7 (this_arg, NULL, rmethod)
2516 static void interp_entry_instance_8 (gpointer this_arg, ARGLIST8) INTERP_ENTRY8 (this_arg, NULL, rmethod)
2517 static void interp_entry_instance_ret_0 (gpointer this_arg, gpointer res, ARGLIST0) INTERP_ENTRY0 (this_arg, res, rmethod)
2518 static void interp_entry_instance_ret_1 (gpointer this_arg, gpointer res, ARGLIST1) INTERP_ENTRY1 (this_arg, res, rmethod)
2519 static void interp_entry_instance_ret_2 (gpointer this_arg, gpointer res, ARGLIST2) INTERP_ENTRY2 (this_arg, res, rmethod)
2520 static void interp_entry_instance_ret_3 (gpointer this_arg, gpointer res, ARGLIST3) INTERP_ENTRY3 (this_arg, res, rmethod)
2521 static void interp_entry_instance_ret_4 (gpointer this_arg, gpointer res, ARGLIST4) INTERP_ENTRY4 (this_arg, res, rmethod)
2522 static void interp_entry_instance_ret_5 (gpointer this_arg, gpointer res, ARGLIST5) INTERP_ENTRY5 (this_arg, res, rmethod)
2523 static void interp_entry_instance_ret_6 (gpointer this_arg, gpointer res, ARGLIST6) INTERP_ENTRY6 (this_arg, res, rmethod)
2524 static void interp_entry_instance_ret_7 (gpointer this_arg, gpointer res, ARGLIST7) INTERP_ENTRY7 (this_arg, res, rmethod)
2525 static void interp_entry_instance_ret_8 (gpointer this_arg, gpointer res, ARGLIST8) INTERP_ENTRY8 (this_arg, res, rmethod)
2527 #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
2529 static gpointer entry_funcs_static [MAX_INTERP_ENTRY_ARGS + 1] = { INTERP_ENTRY_FUNCLIST (static) };
2530 static gpointer entry_funcs_static_ret [MAX_INTERP_ENTRY_ARGS + 1] = { INTERP_ENTRY_FUNCLIST (static_ret) };
2531 static gpointer entry_funcs_instance [MAX_INTERP_ENTRY_ARGS + 1] = { INTERP_ENTRY_FUNCLIST (instance) };
2532 static gpointer entry_funcs_instance_ret [MAX_INTERP_ENTRY_ARGS + 1] = { INTERP_ENTRY_FUNCLIST (instance_ret) };
2534 /* General version for methods with more than MAX_INTERP_ENTRY_ARGS arguments */
2535 static void
2536 interp_entry_general (gpointer this_arg, gpointer res, gpointer *args, gpointer rmethod)
2538 INTERP_ENTRY_BASE ((InterpMethod*)rmethod, this_arg, res);
2539 data.many_args = args;
2540 interp_entry (&data);
2543 #ifdef MONO_ARCH_HAVE_INTERP_ENTRY_TRAMPOLINE
2545 // inline so we can alloc on stack
2546 #define alloc_storage_for_stackval(s, t, p) do { \
2547 if ((t)->type == MONO_TYPE_GENERICINST && !MONO_TYPE_IS_REFERENCE (t)) { \
2548 (s)->data.vt = alloca (mono_class_value_size (mono_class_from_mono_type_internal (t), NULL)); \
2549 } else if ((t)->type == MONO_TYPE_VALUETYPE) { \
2550 if (p) \
2551 (s)->data.vt = alloca (mono_class_native_size ((t)->data.klass, NULL)); \
2552 else \
2553 (s)->data.vt = alloca (mono_class_value_size ((t)->data.klass, NULL)); \
2555 } while (0)
2557 static void
2558 interp_entry_from_trampoline (gpointer ccontext_untyped, gpointer rmethod_untyped)
2560 InterpFrame frame;
2561 ThreadContext *context;
2562 stackval result;
2563 stackval *args;
2564 MonoMethod *method;
2565 MonoMethodSignature *sig;
2566 CallContext *ccontext = (CallContext*) ccontext_untyped;
2567 InterpMethod *rmethod = (InterpMethod*) rmethod_untyped;
2568 gpointer orig_domain = NULL, attach_cookie;
2569 int i;
2571 if (rmethod->needs_thread_attach)
2572 orig_domain = mono_threads_attach_coop (mono_domain_get (), &attach_cookie);
2574 context = get_context ();
2576 method = rmethod->method;
2577 sig = mono_method_signature_internal (method);
2579 frame.ex = NULL;
2581 args = (stackval*)alloca (sizeof (stackval) * (sig->param_count + (sig->hasthis ? 1 : 0)));
2583 init_frame (&frame, NULL, rmethod, args, &result);
2585 /* Allocate storage for value types */
2586 for (i = 0; i < sig->param_count; i++) {
2587 MonoType *type = sig->params [i];
2588 alloc_storage_for_stackval (&frame.stack_args [i + sig->hasthis], type, sig->pinvoke);
2591 if (sig->ret->type != MONO_TYPE_VOID)
2592 alloc_storage_for_stackval (frame.retval, sig->ret, sig->pinvoke);
2594 /* Copy the args saved in the trampoline to the frame stack */
2595 mono_arch_get_native_call_context_args (ccontext, &frame, sig);
2597 ERROR_DECL (error);
2598 interp_exec_method (&frame, context, error);
2600 if (rmethod->needs_thread_attach)
2601 mono_threads_detach_coop (orig_domain, &attach_cookie);
2603 // FIXME:
2604 g_assert (frame.ex == NULL);
2606 /* Write back the return value */
2607 mono_arch_set_native_call_context_ret (ccontext, &frame, sig);
2610 #else
2612 static void
2613 interp_entry_from_trampoline (gpointer ccontext_untyped, gpointer rmethod_untyped)
2615 g_assert_not_reached ();
2618 #endif /* MONO_ARCH_HAVE_INTERP_ENTRY_TRAMPOLINE */
2620 static InterpMethod*
2621 lookup_method_pointer (gpointer addr)
2623 MonoDomain *domain = mono_domain_get ();
2624 MonoJitDomainInfo *info = domain_jit_info (domain);
2625 InterpMethod *res = NULL;
2627 mono_domain_lock (domain);
2628 if (info->interp_method_pointer_hash)
2629 res = (InterpMethod*)g_hash_table_lookup (info->interp_method_pointer_hash, addr);
2630 mono_domain_unlock (domain);
2632 return res;
2635 #ifndef MONO_ARCH_HAVE_INTERP_NATIVE_TO_MANAGED
2636 static void
2637 interp_no_native_to_managed (void)
2639 g_error ("interpreter: native-to-managed transition not available on this platform");
2641 #endif
2643 static void
2644 no_llvmonly_interp_method_pointer (void)
2646 g_assert_not_reached ();
2650 * interp_create_method_pointer_llvmonly:
2652 * Return an ftndesc for entering the interpreter and executing METHOD.
2654 static MonoFtnDesc*
2655 interp_create_method_pointer_llvmonly (MonoMethod *method, gboolean unbox, MonoError *error)
2657 MonoDomain *domain = mono_domain_get ();
2658 gpointer addr, entry_func, entry_wrapper;
2659 MonoMethodSignature *sig;
2660 MonoMethod *wrapper;
2661 MonoJitDomainInfo *info;
2662 InterpMethod *imethod;
2664 imethod = mono_interp_get_imethod (domain, method, error);
2665 return_val_if_nok (error, NULL);
2667 if (unbox) {
2668 if (imethod->llvmonly_unbox_entry)
2669 return (MonoFtnDesc*)imethod->llvmonly_unbox_entry;
2670 } else {
2671 if (imethod->jit_entry)
2672 return (MonoFtnDesc*)imethod->jit_entry;
2675 sig = mono_method_signature_internal (method);
2678 * The entry functions need access to the method to call, so we have
2679 * to use a ftndesc. The caller uses a normal signature, while the
2680 * entry functions use a gsharedvt_in signature, so wrap the entry function in
2681 * a gsharedvt_in_sig wrapper.
2683 wrapper = mini_get_gsharedvt_in_sig_wrapper (sig);
2685 entry_wrapper = mono_jit_compile_method_jit_only (wrapper, error);
2686 mono_error_assertf_ok (error, "couldn't compile wrapper \"%s\" for \"%s\"",
2687 mono_method_get_name_full (wrapper, TRUE, TRUE, MONO_TYPE_NAME_FORMAT_IL),
2688 mono_method_get_name_full (method, TRUE, TRUE, MONO_TYPE_NAME_FORMAT_IL));
2690 if (sig->param_count > MAX_INTERP_ENTRY_ARGS) {
2691 g_assert_not_reached ();
2692 //entry_func = (gpointer)interp_entry_general;
2693 } else if (sig->hasthis) {
2694 if (sig->ret->type == MONO_TYPE_VOID)
2695 entry_func = entry_funcs_instance [sig->param_count];
2696 else
2697 entry_func = entry_funcs_instance_ret [sig->param_count];
2698 } else {
2699 if (sig->ret->type == MONO_TYPE_VOID)
2700 entry_func = entry_funcs_static [sig->param_count];
2701 else
2702 entry_func = entry_funcs_static_ret [sig->param_count];
2704 g_assert (entry_func);
2706 /* Encode unbox in the lower bit of imethod */
2707 gpointer entry_arg = imethod;
2708 if (unbox)
2709 entry_arg = (gpointer)(((gsize)entry_arg) | 1);
2710 MonoFtnDesc *entry_ftndesc = mini_llvmonly_create_ftndesc (mono_domain_get (), entry_func, entry_arg);
2712 addr = mini_llvmonly_create_ftndesc (mono_domain_get (), entry_wrapper, entry_ftndesc);
2714 info = domain_jit_info (domain);
2715 mono_domain_lock (domain);
2716 if (!info->interp_method_pointer_hash)
2717 info->interp_method_pointer_hash = g_hash_table_new (NULL, NULL);
2718 g_hash_table_insert (info->interp_method_pointer_hash, addr, imethod);
2719 mono_domain_unlock (domain);
2721 mono_memory_barrier ();
2722 if (unbox)
2723 imethod->llvmonly_unbox_entry = addr;
2724 else
2725 imethod->jit_entry = addr;
2727 return (MonoFtnDesc*)addr;
2731 * interp_create_method_pointer:
2733 * Return a function pointer which can be used to call METHOD using the
2734 * interpreter. Return NULL for methods which are not supported.
2736 static gpointer
2737 interp_create_method_pointer (MonoMethod *method, gboolean compile, MonoError *error)
2739 #ifndef MONO_ARCH_HAVE_INTERP_NATIVE_TO_MANAGED
2740 if (mono_llvm_only)
2741 return (gpointer)no_llvmonly_interp_method_pointer;
2742 return (gpointer)interp_no_native_to_managed;
2743 #else
2744 gpointer addr, entry_func, entry_wrapper = NULL;
2745 MonoDomain *domain = mono_domain_get ();
2746 MonoJitDomainInfo *info;
2747 InterpMethod *imethod = mono_interp_get_imethod (domain, method, error);
2749 if (mono_llvm_only)
2750 return (gpointer)no_llvmonly_interp_method_pointer;
2752 if (imethod->jit_entry)
2753 return imethod->jit_entry;
2755 if (compile && !imethod->transformed) {
2756 /* Return any errors from method compilation */
2757 mono_interp_transform_method (imethod, get_context (), error);
2758 return_val_if_nok (error, NULL);
2761 MonoMethodSignature *sig = mono_method_signature_internal (method);
2763 if (mono_llvm_only)
2764 /* The caller should call interp_create_method_pointer_llvmonly */
2765 g_assert_not_reached ();
2767 if (method->wrapper_type && method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE)
2768 return imethod;
2770 #ifndef MONO_ARCH_HAVE_FTNPTR_ARG_TRAMPOLINE
2772 * Interp in wrappers get the argument in the rgctx register. If
2773 * MONO_ARCH_HAVE_FTNPTR_ARG_TRAMPOLINE is defined it means that
2774 * on that arch the rgctx register is not scratch, so we use a
2775 * separate temp register. We should update the wrappers for this
2776 * if we really care about those architectures (arm).
2778 MonoMethod *wrapper = mini_get_interp_in_wrapper (sig);
2780 entry_wrapper = mono_jit_compile_method_jit_only (wrapper, error);
2781 #endif
2782 if (entry_wrapper) {
2783 if (sig->param_count > MAX_INTERP_ENTRY_ARGS) {
2784 entry_func = (gpointer)interp_entry_general;
2785 } else if (sig->hasthis) {
2786 if (sig->ret->type == MONO_TYPE_VOID)
2787 entry_func = entry_funcs_instance [sig->param_count];
2788 else
2789 entry_func = entry_funcs_instance_ret [sig->param_count];
2790 } else {
2791 if (sig->ret->type == MONO_TYPE_VOID)
2792 entry_func = entry_funcs_static [sig->param_count];
2793 else
2794 entry_func = entry_funcs_static_ret [sig->param_count];
2796 } else {
2797 #ifndef MONO_ARCH_HAVE_INTERP_ENTRY_TRAMPOLINE
2798 mono_error_assertf_ok (error, "couldn't compile wrapper \"%s\" for \"%s\"",
2799 mono_method_get_name_full (wrapper, TRUE, TRUE, MONO_TYPE_NAME_FORMAT_IL),
2800 mono_method_get_name_full (method, TRUE, TRUE, MONO_TYPE_NAME_FORMAT_IL));
2801 #else
2802 mono_error_cleanup (error);
2803 error_init_reuse (error);
2804 if (!mono_native_to_interp_trampoline) {
2805 if (mono_aot_only) {
2806 mono_native_to_interp_trampoline = (MonoFuncV)mono_aot_get_trampoline ("native_to_interp_trampoline");
2807 } else {
2808 MonoTrampInfo *info;
2809 mono_native_to_interp_trampoline = (MonoFuncV)mono_arch_get_native_to_interp_trampoline (&info);
2810 mono_tramp_info_register (info, NULL);
2813 entry_wrapper = (gpointer)mono_native_to_interp_trampoline;
2814 /* We need the lmf wrapper only when being called from mixed mode */
2815 if (sig->pinvoke)
2816 entry_func = (gpointer)interp_entry_from_trampoline;
2817 else {
2818 static gpointer cached_func = NULL;
2819 if (!cached_func) {
2820 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);
2821 mono_memory_barrier ();
2823 entry_func = cached_func;
2825 #endif
2828 g_assert (entry_func);
2829 /* This is the argument passed to the interp_in wrapper by the static rgctx trampoline */
2830 MonoFtnDesc *ftndesc = g_new0 (MonoFtnDesc, 1);
2831 ftndesc->addr = entry_func;
2832 ftndesc->arg = imethod;
2833 mono_error_assert_ok (error);
2836 * The wrapper is called by compiled code, which doesn't pass the extra argument, so we pass it in the
2837 * rgctx register using a trampoline.
2840 addr = mono_create_ftnptr_arg_trampoline (ftndesc, entry_wrapper);
2842 info = domain_jit_info (domain);
2843 mono_domain_lock (domain);
2844 if (!info->interp_method_pointer_hash)
2845 info->interp_method_pointer_hash = g_hash_table_new (NULL, NULL);
2846 g_hash_table_insert (info->interp_method_pointer_hash, addr, imethod);
2847 mono_domain_unlock (domain);
2849 mono_memory_barrier ();
2850 imethod->jit_entry = addr;
2852 return addr;
2853 #endif
2856 #if COUNT_OPS
2857 static int opcode_counts[512];
2859 #define COUNT_OP(op) opcode_counts[op]++
2860 #else
2861 #define COUNT_OP(op)
2862 #endif
2864 #if DEBUG_INTERP
2865 #define DUMP_INSTR() \
2866 if (tracing > 1) { \
2867 char *ins; \
2868 if (sp > frame->stack) { \
2869 ins = dump_stack (frame->stack, sp); \
2870 } else { \
2871 ins = g_strdup (""); \
2873 sp->data.l = 0; \
2874 output_indent (); \
2875 char *mn = mono_method_full_name (frame->imethod->method, FALSE); \
2876 char *disasm = mono_interp_dis_mintop(imethod->code, ip); \
2877 g_print ("(%p) %s -> %s\t%d:%s\n", mono_thread_internal_current (), mn, disasm, vt_sp - vtalloc, ins); \
2878 g_free (mn); \
2879 g_free (ins); \
2880 g_free (disasm); \
2882 #else
2883 #define DUMP_INSTR()
2884 #endif
2886 #define INIT_VTABLE(vtable) do { \
2887 if (G_UNLIKELY (!(vtable)->initialized)) { \
2888 mono_runtime_class_init_full ((vtable), error); \
2889 if (!mono_error_ok (error)) \
2890 THROW_EX (mono_error_convert_to_exception (error), ip); \
2892 } while (0);
2895 * GC SAFETY:
2897 * The interpreter executes in gc unsafe (non-preempt) mode. On wasm, the C stack is
2898 * scannable but the wasm stack is not, so to make the code GC safe, the following rules
2899 * should be followed:
2900 * - every objref handled by the code needs to have a copy stored inside InterpFrame,
2901 * in stackval->data.o. For objrefs which are not yet on the IL stack, they can be stored
2902 * in frame->o. This will ensure the objects are pinned. The 'frame' local is assumed
2903 * to be allocated to the C stack and not to registers.
2904 * - minimalize the number of MonoObject* locals/arguments.
2907 #ifdef TARGET_WASM
2908 #define frame_objref(frame) (frame)->o
2909 #else
2910 #define frame_objref(frame) o
2911 #endif
2914 * If EXIT_AT_FINALLY is not -1, exit after exiting the finally clause with that index.
2915 * If BASE_FRAME is not NULL, copy arguments/locals from BASE_FRAME.
2916 * The ERROR argument is used to avoid declaring an error object for every interp frame, its not used
2917 * to return error information.
2919 static void
2920 interp_exec_method_full (InterpFrame *frame, ThreadContext *context, FrameClauseArgs *clause_args, MonoError *error)
2922 InterpFrame child_frame;
2923 const unsigned short *ip = NULL;
2924 stackval *sp;
2925 InterpMethod *imethod = NULL;
2926 #if DEBUG_INTERP
2927 gint tracing = global_tracing;
2928 unsigned char *vtalloc;
2929 #endif
2930 int i32;
2931 unsigned char *vt_sp;
2932 unsigned char *locals = NULL;
2933 // See the comment about GC safety above
2934 MonoObject *o = NULL;
2935 MonoClass *c;
2936 #if USE_COMPUTED_GOTO
2937 static void *in_labels[] = {
2938 #define OPDEF(a,b,c,d) \
2939 &&LAB_ ## a,
2940 #include "mintops.def"
2941 0 };
2942 #endif
2944 MonoMethodPInvoke* piinfo = NULL;
2946 frame->ex = NULL;
2947 frame->finally_ips = NULL;
2948 frame->endfinally_ip = NULL;
2950 #if DEBUG_INTERP
2951 debug_enter (frame, &tracing);
2952 #endif
2954 imethod = frame->imethod;
2955 if (!imethod->transformed) {
2956 #if DEBUG_INTERP
2957 char *mn = mono_method_full_name (imethod->method, TRUE);
2958 g_print ("(%p) Transforming %s\n", mono_thread_internal_current (), mn);
2959 g_free (mn);
2960 #endif
2962 frame->ip = NULL;
2963 do_transform_method (frame, context);
2964 if (frame->ex)
2965 THROW_EX (frame->ex, NULL);
2966 EXCEPTION_CHECKPOINT;
2969 if (!clause_args) {
2970 frame->args = g_newa (char, imethod->alloca_size);
2971 ip = imethod->code;
2972 } else {
2973 ip = clause_args->start_with_ip;
2974 if (clause_args->base_frame) {
2975 frame->args = g_newa (char, imethod->alloca_size);
2976 memcpy (frame->args, clause_args->base_frame->args, imethod->alloca_size);
2979 sp = frame->stack = (stackval *) (char *) frame->args;
2980 vt_sp = (unsigned char *) sp + imethod->stack_size;
2981 #if DEBUG_INTERP
2982 vtalloc = vt_sp;
2983 #endif
2984 locals = (unsigned char *) vt_sp + imethod->vt_stack_size;
2985 frame->locals = locals;
2986 child_frame.parent = frame;
2988 if (clause_args && clause_args->filter_exception) {
2989 sp->data.p = clause_args->filter_exception;
2990 sp++;
2993 //g_print ("(%p) Call %s\n", mono_thread_internal_current (), mono_method_get_full_name (frame->imethod->method));
2996 * using while (ip < end) may result in a 15% performance drop,
2997 * but it may be useful for debug
2999 while (1) {
3000 #ifndef USE_COMPUTED_GOTO
3001 main_loop:
3002 #endif
3003 /* g_assert (sp >= frame->stack); */
3004 /* g_assert(vt_sp - vtalloc <= imethod->vt_stack_size); */
3005 DUMP_INSTR();
3006 MINT_IN_SWITCH (*ip) {
3007 MINT_IN_CASE(MINT_INITLOCALS)
3008 memset (locals, 0, imethod->locals_size);
3009 ++ip;
3010 MINT_IN_BREAK;
3011 MINT_IN_CASE(MINT_NOP)
3012 ++ip;
3013 MINT_IN_BREAK;
3014 MINT_IN_CASE(MINT_NIY)
3015 g_error ("mint_niy: instruction not implemented yet. This shouldn't happen.");
3016 MINT_IN_BREAK;
3017 MINT_IN_CASE(MINT_BREAK)
3018 ++ip;
3019 do_debugger_tramp (mini_get_dbg_callbacks ()->user_break, frame);
3020 MINT_IN_BREAK;
3021 MINT_IN_CASE(MINT_BREAKPOINT)
3022 ++ip;
3023 mono_break ();
3024 MINT_IN_BREAK;
3025 MINT_IN_CASE(MINT_LDNULL)
3026 sp->data.p = NULL;
3027 ++ip;
3028 ++sp;
3029 MINT_IN_BREAK;
3030 MINT_IN_CASE(MINT_ARGLIST)
3031 g_assert (frame->varargs);
3032 sp->data.p = vt_sp;
3033 *(gpointer*)sp->data.p = frame->varargs;
3034 vt_sp += ALIGN_TO (sizeof (gpointer), MINT_VT_ALIGNMENT);
3035 ++ip;
3036 ++sp;
3037 MINT_IN_BREAK;
3038 MINT_IN_CASE(MINT_VTRESULT) {
3039 int ret_size = * (guint16 *)(ip + 1);
3040 unsigned char *ret_vt_sp = vt_sp;
3041 vt_sp -= READ32(ip + 2);
3042 if (ret_size > 0) {
3043 memmove (vt_sp, ret_vt_sp, ret_size);
3044 sp [-1].data.p = vt_sp;
3045 vt_sp += ALIGN_TO (ret_size, MINT_VT_ALIGNMENT);
3047 ip += 4;
3048 MINT_IN_BREAK;
3050 #define LDC(n) do { sp->data.i = (n); ++ip; ++sp; } while (0)
3051 MINT_IN_CASE(MINT_LDC_I4_M1)
3052 LDC(-1);
3053 MINT_IN_BREAK;
3054 MINT_IN_CASE(MINT_LDC_I4_0)
3055 LDC(0);
3056 MINT_IN_BREAK;
3057 MINT_IN_CASE(MINT_LDC_I4_1)
3058 LDC(1);
3059 MINT_IN_BREAK;
3060 MINT_IN_CASE(MINT_LDC_I4_2)
3061 LDC(2);
3062 MINT_IN_BREAK;
3063 MINT_IN_CASE(MINT_LDC_I4_3)
3064 LDC(3);
3065 MINT_IN_BREAK;
3066 MINT_IN_CASE(MINT_LDC_I4_4)
3067 LDC(4);
3068 MINT_IN_BREAK;
3069 MINT_IN_CASE(MINT_LDC_I4_5)
3070 LDC(5);
3071 MINT_IN_BREAK;
3072 MINT_IN_CASE(MINT_LDC_I4_6)
3073 LDC(6);
3074 MINT_IN_BREAK;
3075 MINT_IN_CASE(MINT_LDC_I4_7)
3076 LDC(7);
3077 MINT_IN_BREAK;
3078 MINT_IN_CASE(MINT_LDC_I4_8)
3079 LDC(8);
3080 MINT_IN_BREAK;
3081 MINT_IN_CASE(MINT_LDC_I4_S)
3082 sp->data.i = *(const short *)(ip + 1);
3083 ip += 2;
3084 ++sp;
3085 MINT_IN_BREAK;
3086 MINT_IN_CASE(MINT_LDC_I4)
3087 ++ip;
3088 sp->data.i = READ32 (ip);
3089 ip += 2;
3090 ++sp;
3091 MINT_IN_BREAK;
3092 MINT_IN_CASE(MINT_LDC_I8)
3093 ++ip;
3094 sp->data.l = READ64 (ip);
3095 ip += 4;
3096 ++sp;
3097 MINT_IN_BREAK;
3098 MINT_IN_CASE(MINT_LDC_I8_S)
3099 sp->data.l = *(const short *)(ip + 1);
3100 ip += 2;
3101 ++sp;
3102 MINT_IN_BREAK;
3103 MINT_IN_CASE(MINT_LDC_R4) {
3104 guint32 val;
3105 ++ip;
3106 val = READ32(ip);
3107 sp->data.f_r4 = * (float *)&val;
3108 ip += 2;
3109 ++sp;
3110 MINT_IN_BREAK;
3112 MINT_IN_CASE(MINT_LDC_R8)
3113 sp->data.l = READ64 (ip + 1); /* note union usage */
3114 ip += 5;
3115 ++sp;
3116 MINT_IN_BREAK;
3117 MINT_IN_CASE(MINT_DUP)
3118 sp [0] = sp[-1];
3119 ++sp;
3120 ++ip;
3121 MINT_IN_BREAK;
3122 MINT_IN_CASE(MINT_DUP_VT)
3123 i32 = READ32 (ip + 1);
3124 sp->data.p = vt_sp;
3125 memcpy(sp->data.p, sp [-1].data.p, i32);
3126 vt_sp += ALIGN_TO (i32, MINT_VT_ALIGNMENT);
3127 ++sp;
3128 ip += 3;
3129 MINT_IN_BREAK;
3130 MINT_IN_CASE(MINT_POP) {
3131 guint16 u16 = (* (guint16 *)(ip + 1)) + 1;
3132 if (u16 > 1)
3133 memmove (sp - u16, sp - 1, (u16 - 1) * sizeof (stackval));
3134 sp--;
3135 ip += 2;
3136 MINT_IN_BREAK;
3138 MINT_IN_CASE(MINT_JMP) {
3139 InterpMethod *new_method = (InterpMethod*)imethod->data_items [* (guint16 *)(ip + 1)];
3140 gboolean realloc_frame = new_method->alloca_size > imethod->alloca_size;
3142 if (imethod->prof_flags & MONO_PROFILER_CALL_INSTRUMENTATION_TAIL_CALL)
3143 MONO_PROFILER_RAISE (method_tail_call, (imethod->method, new_method->method));
3145 if (!new_method->transformed) {
3146 MONO_API_ERROR_INIT (error);
3148 frame->ip = ip;
3149 mono_interp_transform_method (new_method, context, error);
3150 frame->ex = mono_error_convert_to_exception (error);
3151 if (frame->ex)
3152 goto exit_frame;
3154 ip += 2;
3155 imethod = frame->imethod = new_method;
3157 * We allocate the stack frame from scratch and store the arguments in the
3158 * locals again since it's possible for the caller stack frame to be smaller
3159 * than the callee stack frame (at the interp level)
3161 if (realloc_frame) {
3162 frame->args = g_newa (char, imethod->alloca_size);
3163 memset (frame->args, 0, imethod->alloca_size);
3164 sp = frame->stack = (stackval *) frame->args;
3166 vt_sp = (unsigned char *) sp + imethod->stack_size;
3167 #if DEBUG_INTERP
3168 vtalloc = vt_sp;
3169 #endif
3170 locals = vt_sp + imethod->vt_stack_size;
3171 frame->locals = locals;
3172 ip = imethod->code;
3173 MINT_IN_BREAK;
3175 MINT_IN_CASE(MINT_CALLI) {
3176 MonoMethodSignature *csignature;
3177 stackval *endsp = sp;
3179 frame->ip = ip;
3181 csignature = (MonoMethodSignature*)imethod->data_items [* (guint16 *)(ip + 1)];
3182 ip += 2;
3183 --sp;
3184 --endsp;
3185 child_frame.imethod = (InterpMethod*)sp->data.p;
3187 sp->data.p = vt_sp;
3188 child_frame.retval = sp;
3189 /* decrement by the actual number of args */
3190 sp -= csignature->param_count;
3191 if (csignature->hasthis)
3192 --sp;
3193 child_frame.stack_args = sp;
3195 if (child_frame.imethod->method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) {
3196 child_frame.imethod = mono_interp_get_imethod (imethod->domain, mono_marshal_get_native_wrapper (child_frame.imethod->method, FALSE, FALSE), error);
3197 mono_error_cleanup (error); /* FIXME: don't swallow the error */
3200 if (csignature->hasthis) {
3201 MonoObject *this_arg = (MonoObject*)sp->data.p;
3203 if (m_class_is_valuetype (this_arg->vtable->klass)) {
3204 gpointer unboxed = mono_object_unbox_internal (this_arg);
3205 sp [0].data.p = unboxed;
3209 interp_exec_method (&child_frame, context, error);
3211 CHECK_RESUME_STATE (context);
3213 /* need to handle typedbyref ... */
3214 if (csignature->ret->type != MONO_TYPE_VOID) {
3215 *sp = *endsp;
3216 sp++;
3218 MINT_IN_BREAK;
3220 MINT_IN_CASE(MINT_CALLI_NAT_FAST) {
3221 gpointer target_ip = sp [-1].data.p;
3222 MonoMethodSignature *csignature = (MonoMethodSignature*)imethod->data_items [* (guint16 *)(ip + 1)];
3223 int opcode = *(guint16 *)(ip + 2);
3224 gboolean save_last_error = *(guint16 *)(ip + 3);
3226 sp--;
3227 frame->ip = ip;
3229 sp = do_icall_wrapper (frame, csignature, opcode, sp, target_ip, save_last_error);
3230 EXCEPTION_CHECKPOINT;
3231 CHECK_RESUME_STATE (context);
3232 ip += 4;
3233 MINT_IN_BREAK;
3235 MINT_IN_CASE(MINT_CALLI_NAT) {
3236 MonoMethodSignature *csignature;
3237 stackval *endsp = sp;
3238 unsigned char *code = NULL;
3239 gboolean save_last_error = FALSE;
3241 frame->ip = ip;
3243 csignature = (MonoMethodSignature*)imethod->data_items [* (guint16 *)(ip + 1)];
3244 save_last_error = *(guint16 *)(ip + 2);
3245 ip += 3;
3246 --sp;
3247 --endsp;
3248 code = (guchar*)sp->data.p;
3249 child_frame.imethod = NULL;
3251 sp->data.p = vt_sp;
3252 child_frame.retval = sp;
3253 /* decrement by the actual number of args */
3254 sp -= csignature->param_count;
3255 if (csignature->hasthis)
3256 --sp;
3257 child_frame.stack_args = sp;
3258 if (imethod->method->dynamic && csignature->pinvoke) {
3259 MonoMarshalSpec **mspecs;
3260 MonoMethod *m;
3262 /* Pinvoke call is missing the wrapper. See mono_get_native_calli_wrapper */
3263 mspecs = g_new0 (MonoMarshalSpec*, csignature->param_count + 1);
3265 piinfo = piinfo ? piinfo : g_newa (MonoMethodPInvoke, 1);
3266 memset (piinfo, 0, sizeof (*piinfo));
3268 m = mono_marshal_get_native_func_wrapper (m_class_get_image (imethod->method->klass), csignature, piinfo, mspecs, code);
3270 for (int i = csignature->param_count; i >= 0; i--)
3271 if (mspecs [i])
3272 mono_metadata_free_marshal_spec (mspecs [i]);
3273 g_free (mspecs);
3275 child_frame.imethod = mono_interp_get_imethod (imethod->domain, m, error);
3276 mono_error_cleanup (error); /* FIXME: don't swallow the error */
3278 interp_exec_method (&child_frame, context, error);
3279 } else {
3280 ves_pinvoke_method (&child_frame, csignature, (MonoFuncV) code, FALSE, context, save_last_error);
3283 CHECK_RESUME_STATE (context);
3285 /* need to handle typedbyref ... */
3286 if (csignature->ret->type != MONO_TYPE_VOID) {
3287 *sp = *endsp;
3288 sp++;
3290 MINT_IN_BREAK;
3292 MINT_IN_CASE(MINT_CALLVIRT_FAST)
3293 MINT_IN_CASE(MINT_VCALLVIRT_FAST) {
3294 MonoObject *this_arg;
3295 MonoClass *this_class;
3296 gboolean is_void = *ip == MINT_VCALLVIRT_FAST;
3297 InterpMethod *target_imethod;
3298 stackval *endsp = sp;
3299 int slot;
3301 // FIXME Have it handle also remoting calls and use a single opcode for virtual calls
3303 frame->ip = ip;
3305 target_imethod = (InterpMethod*)imethod->data_items [* (guint16 *)(ip + 1)];
3306 slot = *(gint16*)(ip + 2);
3307 ip += 3;
3308 sp->data.p = vt_sp;
3309 child_frame.retval = sp;
3311 /* decrement by the actual number of args */
3312 sp -= target_imethod->param_count + target_imethod->hasthis;
3313 child_frame.stack_args = sp;
3315 this_arg = (MonoObject*)sp->data.p;
3316 this_class = this_arg->vtable->klass;
3318 child_frame.imethod = get_virtual_method_fast (target_imethod, this_arg->vtable, slot);
3319 if (m_class_is_valuetype (this_class) && m_class_is_valuetype (child_frame.imethod->method->klass)) {
3320 /* unbox */
3321 gpointer unboxed = mono_object_unbox_internal (this_arg);
3322 sp [0].data.p = unboxed;
3325 interp_exec_method (&child_frame, context, error);
3327 CHECK_RESUME_STATE (context);
3329 if (!is_void) {
3330 /* need to handle typedbyref ... */
3331 *sp = *endsp;
3332 sp++;
3334 MINT_IN_BREAK;
3336 MINT_IN_CASE(MINT_CALL_VARARG) {
3337 stackval *endsp = sp;
3338 int num_varargs = 0;
3339 MonoMethodSignature *csig;
3341 frame->ip = ip;
3343 child_frame.imethod = (InterpMethod*)imethod->data_items [* (guint16 *)(ip + 1)];
3344 /* The real signature for vararg calls */
3345 csig = (MonoMethodSignature*) imethod->data_items [* (guint16*) (ip + 2)];
3346 /* Push all vararg arguments from normal sp to vt_sp together with the signature */
3347 num_varargs = csig->param_count - csig->sentinelpos;
3348 child_frame.varargs = (char*) vt_sp;
3349 copy_varargs_vtstack (csig, sp, &vt_sp);
3351 ip += 3;
3352 sp->data.p = vt_sp;
3353 child_frame.retval = sp;
3355 /* decrement by the actual number of args */
3356 sp -= child_frame.imethod->param_count + child_frame.imethod->hasthis + num_varargs;
3357 child_frame.stack_args = sp;
3359 interp_exec_method (&child_frame, context, error);
3361 CHECK_RESUME_STATE (context);
3363 if (csig->ret->type != MONO_TYPE_VOID) {
3364 *sp = *endsp;
3365 sp++;
3367 MINT_IN_BREAK;
3369 MINT_IN_CASE(MINT_CALL)
3370 MINT_IN_CASE(MINT_VCALL)
3371 MINT_IN_CASE(MINT_CALLVIRT)
3372 MINT_IN_CASE(MINT_VCALLVIRT) {
3373 gboolean is_void = *ip == MINT_VCALL || *ip == MINT_VCALLVIRT;
3374 gboolean is_virtual = *ip == MINT_CALLVIRT || *ip == MINT_VCALLVIRT;
3375 stackval *endsp = sp;
3377 frame->ip = ip;
3379 child_frame.imethod = (InterpMethod*)imethod->data_items [* (guint16 *)(ip + 1)];
3380 ip += 2;
3381 sp->data.p = vt_sp;
3382 child_frame.retval = sp;
3384 /* decrement by the actual number of args */
3385 sp -= child_frame.imethod->param_count + child_frame.imethod->hasthis;
3386 child_frame.stack_args = sp;
3388 if (is_virtual) {
3389 MonoObject *this_arg = (MonoObject*)sp->data.p;
3390 MonoClass *this_class = this_arg->vtable->klass;
3392 child_frame.imethod = get_virtual_method (child_frame.imethod, this_arg->vtable);
3393 if (m_class_is_valuetype (this_class) && m_class_is_valuetype (child_frame.imethod->method->klass)) {
3394 /* unbox */
3395 gpointer unboxed = mono_object_unbox_internal (this_arg);
3396 sp [0].data.p = unboxed;
3400 interp_exec_method (&child_frame, context, error);
3402 CHECK_RESUME_STATE (context);
3404 if (!is_void) {
3405 /* need to handle typedbyref ... */
3406 *sp = *endsp;
3407 sp++;
3409 MINT_IN_BREAK;
3411 MINT_IN_CASE(MINT_JIT_CALL) {
3412 InterpMethod *rmethod = (InterpMethod*)imethod->data_items [* (guint16 *)(ip + 1)];
3413 MONO_API_ERROR_INIT (error);
3414 frame->ip = ip;
3415 sp = do_jit_call (sp, vt_sp, context, frame, rmethod, error);
3416 if (!is_ok (error)) {
3417 MonoException *ex = mono_error_convert_to_exception (error);
3418 THROW_EX (ex, ip);
3420 ip += 2;
3422 CHECK_RESUME_STATE (context);
3424 if (rmethod->rtype->type != MONO_TYPE_VOID)
3425 sp++;
3427 MINT_IN_BREAK;
3429 MINT_IN_CASE(MINT_CALLRUN) {
3430 MonoMethod *target_method = (MonoMethod*) imethod->data_items [* (guint16 *)(ip + 1)];
3431 MonoMethodSignature *sig = (MonoMethodSignature*) imethod->data_items [* (guint16 *)(ip + 2)];
3432 stackval *retval;
3434 sp->data.p = vt_sp;
3435 retval = sp;
3437 sp -= sig->param_count;
3438 if (sig->hasthis)
3439 sp--;
3441 ves_imethod (frame, target_method, sig, sp, retval);
3442 if (frame->ex)
3443 THROW_EX (frame->ex, ip);
3445 if (sig->ret->type != MONO_TYPE_VOID) {
3446 *sp = *retval;
3447 sp++;
3449 ip += 3;
3450 MINT_IN_BREAK;
3452 MINT_IN_CASE(MINT_RET)
3453 --sp;
3454 *frame->retval = *sp;
3455 if (sp > frame->stack)
3456 g_warning ("ret: more values on stack: %d", sp-frame->stack);
3457 goto exit_frame;
3458 MINT_IN_CASE(MINT_RET_VOID)
3459 if (sp > frame->stack)
3460 g_warning ("ret.void: more values on stack: %d %s", sp-frame->stack, mono_method_full_name (imethod->method, TRUE));
3461 goto exit_frame;
3462 MINT_IN_CASE(MINT_RET_VT)
3463 i32 = READ32(ip + 1);
3464 --sp;
3465 memcpy(frame->retval->data.p, sp->data.p, i32);
3466 if (sp > frame->stack)
3467 g_warning ("ret.vt: more values on stack: %d", sp-frame->stack);
3468 goto exit_frame;
3469 MINT_IN_CASE(MINT_BR_S)
3470 ip += (short) *(ip + 1);
3471 MINT_IN_BREAK;
3472 MINT_IN_CASE(MINT_BR)
3473 ip += (gint32) READ32(ip + 1);
3474 MINT_IN_BREAK;
3475 #define ZEROP_S(datamem, op) \
3476 --sp; \
3477 if (sp->data.datamem op 0) \
3478 ip += * (gint16 *)(ip + 1); \
3479 else \
3480 ip += 2;
3482 #define ZEROP(datamem, op) \
3483 --sp; \
3484 if (sp->data.datamem op 0) \
3485 ip += (gint32)READ32(ip + 1); \
3486 else \
3487 ip += 3;
3489 MINT_IN_CASE(MINT_BRFALSE_I4_S)
3490 ZEROP_S(i, ==);
3491 MINT_IN_BREAK;
3492 MINT_IN_CASE(MINT_BRFALSE_I8_S)
3493 ZEROP_S(l, ==);
3494 MINT_IN_BREAK;
3495 MINT_IN_CASE(MINT_BRFALSE_R4_S)
3496 ZEROP_S(f_r4, ==);
3497 MINT_IN_BREAK;
3498 MINT_IN_CASE(MINT_BRFALSE_R8_S)
3499 ZEROP_S(f, ==);
3500 MINT_IN_BREAK;
3501 MINT_IN_CASE(MINT_BRFALSE_I4)
3502 ZEROP(i, ==);
3503 MINT_IN_BREAK;
3504 MINT_IN_CASE(MINT_BRFALSE_I8)
3505 ZEROP(l, ==);
3506 MINT_IN_BREAK;
3507 MINT_IN_CASE(MINT_BRFALSE_R4)
3508 ZEROP_S(f_r4, ==);
3509 MINT_IN_BREAK;
3510 MINT_IN_CASE(MINT_BRFALSE_R8)
3511 ZEROP_S(f, ==);
3512 MINT_IN_BREAK;
3513 MINT_IN_CASE(MINT_BRTRUE_I4_S)
3514 ZEROP_S(i, !=);
3515 MINT_IN_BREAK;
3516 MINT_IN_CASE(MINT_BRTRUE_I8_S)
3517 ZEROP_S(l, !=);
3518 MINT_IN_BREAK;
3519 MINT_IN_CASE(MINT_BRTRUE_R4_S)
3520 ZEROP_S(f_r4, !=);
3521 MINT_IN_BREAK;
3522 MINT_IN_CASE(MINT_BRTRUE_R8_S)
3523 ZEROP_S(f, !=);
3524 MINT_IN_BREAK;
3525 MINT_IN_CASE(MINT_BRTRUE_I4)
3526 ZEROP(i, !=);
3527 MINT_IN_BREAK;
3528 MINT_IN_CASE(MINT_BRTRUE_I8)
3529 ZEROP(l, !=);
3530 MINT_IN_BREAK;
3531 MINT_IN_CASE(MINT_BRTRUE_R4)
3532 ZEROP(f_r4, !=);
3533 MINT_IN_BREAK;
3534 MINT_IN_CASE(MINT_BRTRUE_R8)
3535 ZEROP(f, !=);
3536 MINT_IN_BREAK;
3537 #define CONDBR_S(cond) \
3538 sp -= 2; \
3539 if (cond) \
3540 ip += * (gint16 *)(ip + 1); \
3541 else \
3542 ip += 2;
3543 #define BRELOP_S(datamem, op) \
3544 CONDBR_S(sp[0].data.datamem op sp[1].data.datamem)
3546 #define CONDBR(cond) \
3547 sp -= 2; \
3548 if (cond) \
3549 ip += (gint32)READ32(ip + 1); \
3550 else \
3551 ip += 3;
3553 #define BRELOP(datamem, op) \
3554 CONDBR(sp[0].data.datamem op sp[1].data.datamem)
3556 MINT_IN_CASE(MINT_BEQ_I4_S)
3557 BRELOP_S(i, ==)
3558 MINT_IN_BREAK;
3559 MINT_IN_CASE(MINT_BEQ_I8_S)
3560 BRELOP_S(l, ==)
3561 MINT_IN_BREAK;
3562 MINT_IN_CASE(MINT_BEQ_R4_S)
3563 CONDBR_S(!isunordered (sp [0].data.f_r4, sp [1].data.f_r4) && sp[0].data.f_r4 == sp[1].data.f_r4)
3564 MINT_IN_BREAK;
3565 MINT_IN_CASE(MINT_BEQ_R8_S)
3566 CONDBR_S(!mono_isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f == sp[1].data.f)
3567 MINT_IN_BREAK;
3568 MINT_IN_CASE(MINT_BEQ_I4)
3569 BRELOP(i, ==)
3570 MINT_IN_BREAK;
3571 MINT_IN_CASE(MINT_BEQ_I8)
3572 BRELOP(l, ==)
3573 MINT_IN_BREAK;
3574 MINT_IN_CASE(MINT_BEQ_R4)
3575 CONDBR(!isunordered (sp [0].data.f_r4, sp [1].data.f_r4) && sp[0].data.f_r4 == sp[1].data.f_r4)
3576 MINT_IN_BREAK;
3577 MINT_IN_CASE(MINT_BEQ_R8)
3578 CONDBR(!mono_isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f == sp[1].data.f)
3579 MINT_IN_BREAK;
3580 MINT_IN_CASE(MINT_BGE_I4_S)
3581 BRELOP_S(i, >=)
3582 MINT_IN_BREAK;
3583 MINT_IN_CASE(MINT_BGE_I8_S)
3584 BRELOP_S(l, >=)
3585 MINT_IN_BREAK;
3586 MINT_IN_CASE(MINT_BGE_R4_S)
3587 CONDBR_S(!isunordered (sp [0].data.f_r4, sp [1].data.f_r4) && sp[0].data.f_r4 >= sp[1].data.f_r4)
3588 MINT_IN_BREAK;
3589 MINT_IN_CASE(MINT_BGE_R8_S)
3590 CONDBR_S(!mono_isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f >= sp[1].data.f)
3591 MINT_IN_BREAK;
3592 MINT_IN_CASE(MINT_BGE_I4)
3593 BRELOP(i, >=)
3594 MINT_IN_BREAK;
3595 MINT_IN_CASE(MINT_BGE_I8)
3596 BRELOP(l, >=)
3597 MINT_IN_BREAK;
3598 MINT_IN_CASE(MINT_BGE_R4)
3599 CONDBR(!isunordered (sp [0].data.f_r4, sp [1].data.f_r4) && sp[0].data.f_r4 >= sp[1].data.f_r4)
3600 MINT_IN_BREAK;
3601 MINT_IN_CASE(MINT_BGE_R8)
3602 CONDBR(!mono_isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f >= sp[1].data.f)
3603 MINT_IN_BREAK;
3604 MINT_IN_CASE(MINT_BGT_I4_S)
3605 BRELOP_S(i, >)
3606 MINT_IN_BREAK;
3607 MINT_IN_CASE(MINT_BGT_I8_S)
3608 BRELOP_S(l, >)
3609 MINT_IN_BREAK;
3610 MINT_IN_CASE(MINT_BGT_R4_S)
3611 CONDBR_S(!isunordered (sp [0].data.f_r4, sp [1].data.f_r4) && sp[0].data.f_r4 > sp[1].data.f_r4)
3612 MINT_IN_BREAK;
3613 MINT_IN_CASE(MINT_BGT_R8_S)
3614 CONDBR_S(!mono_isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f > sp[1].data.f)
3615 MINT_IN_BREAK;
3616 MINT_IN_CASE(MINT_BGT_I4)
3617 BRELOP(i, >)
3618 MINT_IN_BREAK;
3619 MINT_IN_CASE(MINT_BGT_I8)
3620 BRELOP(l, >)
3621 MINT_IN_BREAK;
3622 MINT_IN_CASE(MINT_BGT_R4)
3623 CONDBR(!isunordered (sp [0].data.f_r4, sp [1].data.f_r4) && sp[0].data.f_r4 > sp[1].data.f_r4)
3624 MINT_IN_BREAK;
3625 MINT_IN_CASE(MINT_BGT_R8)
3626 CONDBR(!mono_isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f > sp[1].data.f)
3627 MINT_IN_BREAK;
3628 MINT_IN_CASE(MINT_BLT_I4_S)
3629 BRELOP_S(i, <)
3630 MINT_IN_BREAK;
3631 MINT_IN_CASE(MINT_BLT_I8_S)
3632 BRELOP_S(l, <)
3633 MINT_IN_BREAK;
3634 MINT_IN_CASE(MINT_BLT_R4_S)
3635 CONDBR_S(!isunordered (sp [0].data.f_r4, sp [1].data.f_r4) && sp[0].data.f_r4 < sp[1].data.f_r4)
3636 MINT_IN_BREAK;
3637 MINT_IN_CASE(MINT_BLT_R8_S)
3638 CONDBR_S(!mono_isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f < sp[1].data.f)
3639 MINT_IN_BREAK;
3640 MINT_IN_CASE(MINT_BLT_I4)
3641 BRELOP(i, <)
3642 MINT_IN_BREAK;
3643 MINT_IN_CASE(MINT_BLT_I8)
3644 BRELOP(l, <)
3645 MINT_IN_BREAK;
3646 MINT_IN_CASE(MINT_BLT_R4)
3647 CONDBR(!isunordered (sp [0].data.f_r4, sp [1].data.f_r4) && sp[0].data.f_r4 < sp[1].data.f_r4)
3648 MINT_IN_BREAK;
3649 MINT_IN_CASE(MINT_BLT_R8)
3650 CONDBR(!mono_isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f < sp[1].data.f)
3651 MINT_IN_BREAK;
3652 MINT_IN_CASE(MINT_BLE_I4_S)
3653 BRELOP_S(i, <=)
3654 MINT_IN_BREAK;
3655 MINT_IN_CASE(MINT_BLE_I8_S)
3656 BRELOP_S(l, <=)
3657 MINT_IN_BREAK;
3658 MINT_IN_CASE(MINT_BLE_R4_S)
3659 CONDBR_S(!isunordered (sp [0].data.f_r4, sp [1].data.f_r4) && sp[0].data.f_r4 <= sp[1].data.f_r4)
3660 MINT_IN_BREAK;
3661 MINT_IN_CASE(MINT_BLE_R8_S)
3662 CONDBR_S(!mono_isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f <= sp[1].data.f)
3663 MINT_IN_BREAK;
3664 MINT_IN_CASE(MINT_BLE_I4)
3665 BRELOP(i, <=)
3666 MINT_IN_BREAK;
3667 MINT_IN_CASE(MINT_BLE_I8)
3668 BRELOP(l, <=)
3669 MINT_IN_BREAK;
3670 MINT_IN_CASE(MINT_BLE_R4)
3671 CONDBR(!isunordered (sp [0].data.f_r4, sp [1].data.f_r4) && sp[0].data.f_r4 <= sp[1].data.f_r4)
3672 MINT_IN_BREAK;
3673 MINT_IN_CASE(MINT_BLE_R8)
3674 CONDBR(!mono_isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f <= sp[1].data.f)
3675 MINT_IN_BREAK;
3676 MINT_IN_CASE(MINT_BNE_UN_I4_S)
3677 BRELOP_S(i, !=)
3678 MINT_IN_BREAK;
3679 MINT_IN_CASE(MINT_BNE_UN_I8_S)
3680 BRELOP_S(l, !=)
3681 MINT_IN_BREAK;
3682 MINT_IN_CASE(MINT_BNE_UN_R4_S)
3683 CONDBR_S(isunordered (sp [0].data.f_r4, sp [1].data.f_r4) || sp[0].data.f_r4 != sp[1].data.f_r4)
3684 MINT_IN_BREAK;
3685 MINT_IN_CASE(MINT_BNE_UN_R8_S)
3686 CONDBR_S(mono_isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f != sp[1].data.f)
3687 MINT_IN_BREAK;
3688 MINT_IN_CASE(MINT_BNE_UN_I4)
3689 BRELOP(i, !=)
3690 MINT_IN_BREAK;
3691 MINT_IN_CASE(MINT_BNE_UN_I8)
3692 BRELOP(l, !=)
3693 MINT_IN_BREAK;
3694 MINT_IN_CASE(MINT_BNE_UN_R4)
3695 CONDBR(isunordered (sp [0].data.f_r4, sp [1].data.f_r4) || sp[0].data.f_r4 != sp[1].data.f_r4)
3696 MINT_IN_BREAK;
3697 MINT_IN_CASE(MINT_BNE_UN_R8)
3698 CONDBR(mono_isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f != sp[1].data.f)
3699 MINT_IN_BREAK;
3701 #define BRELOP_S_CAST(datamem, op, type) \
3702 sp -= 2; \
3703 if ((type) sp[0].data.datamem op (type) sp[1].data.datamem) \
3704 ip += * (gint16 *)(ip + 1); \
3705 else \
3706 ip += 2;
3708 #define BRELOP_CAST(datamem, op, type) \
3709 sp -= 2; \
3710 if ((type) sp[0].data.datamem op (type) sp[1].data.datamem) \
3711 ip += (gint32)READ32(ip + 1); \
3712 else \
3713 ip += 3;
3715 MINT_IN_CASE(MINT_BGE_UN_I4_S)
3716 BRELOP_S_CAST(i, >=, guint32);
3717 MINT_IN_BREAK;
3718 MINT_IN_CASE(MINT_BGE_UN_I8_S)
3719 BRELOP_S_CAST(l, >=, guint64);
3720 MINT_IN_BREAK;
3721 MINT_IN_CASE(MINT_BGE_UN_R4_S)
3722 CONDBR_S(isunordered (sp [0].data.f_r4, sp [1].data.f_r4) || sp[0].data.f_r4 >= sp[1].data.f_r4)
3723 MINT_IN_BREAK;
3724 MINT_IN_CASE(MINT_BGE_UN_R8_S)
3725 CONDBR_S(mono_isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f >= sp[1].data.f)
3726 MINT_IN_BREAK;
3727 MINT_IN_CASE(MINT_BGE_UN_I4)
3728 BRELOP_CAST(i, >=, guint32);
3729 MINT_IN_BREAK;
3730 MINT_IN_CASE(MINT_BGE_UN_I8)
3731 BRELOP_CAST(l, >=, guint64);
3732 MINT_IN_BREAK;
3733 MINT_IN_CASE(MINT_BGE_UN_R4)
3734 CONDBR(isunordered (sp [0].data.f_r4, sp [1].data.f_r4) || sp[0].data.f_r4 >= sp[1].data.f_r4)
3735 MINT_IN_BREAK;
3736 MINT_IN_CASE(MINT_BGE_UN_R8)
3737 CONDBR(mono_isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f >= sp[1].data.f)
3738 MINT_IN_BREAK;
3739 MINT_IN_CASE(MINT_BGT_UN_I4_S)
3740 BRELOP_S_CAST(i, >, guint32);
3741 MINT_IN_BREAK;
3742 MINT_IN_CASE(MINT_BGT_UN_I8_S)
3743 BRELOP_S_CAST(l, >, guint64);
3744 MINT_IN_BREAK;
3745 MINT_IN_CASE(MINT_BGT_UN_R4_S)
3746 CONDBR_S(isunordered (sp [0].data.f_r4, sp [1].data.f_r4) || sp[0].data.f_r4 > sp[1].data.f_r4)
3747 MINT_IN_BREAK;
3748 MINT_IN_CASE(MINT_BGT_UN_R8_S)
3749 CONDBR_S(mono_isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f > sp[1].data.f)
3750 MINT_IN_BREAK;
3751 MINT_IN_CASE(MINT_BGT_UN_I4)
3752 BRELOP_CAST(i, >, guint32);
3753 MINT_IN_BREAK;
3754 MINT_IN_CASE(MINT_BGT_UN_I8)
3755 BRELOP_CAST(l, >, guint64);
3756 MINT_IN_BREAK;
3757 MINT_IN_CASE(MINT_BGT_UN_R4)
3758 CONDBR(isunordered (sp [0].data.f_r4, sp [1].data.f_r4) || sp[0].data.f_r4 > sp[1].data.f_r4)
3759 MINT_IN_BREAK;
3760 MINT_IN_CASE(MINT_BGT_UN_R8)
3761 CONDBR(mono_isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f > sp[1].data.f)
3762 MINT_IN_BREAK;
3763 MINT_IN_CASE(MINT_BLE_UN_I4_S)
3764 BRELOP_S_CAST(i, <=, guint32);
3765 MINT_IN_BREAK;
3766 MINT_IN_CASE(MINT_BLE_UN_I8_S)
3767 BRELOP_S_CAST(l, <=, guint64);
3768 MINT_IN_BREAK;
3769 MINT_IN_CASE(MINT_BLE_UN_R4_S)
3770 CONDBR_S(isunordered (sp [0].data.f_r4, sp [1].data.f_r4) || sp[0].data.f_r4 <= sp[1].data.f_r4)
3771 MINT_IN_BREAK;
3772 MINT_IN_CASE(MINT_BLE_UN_R8_S)
3773 CONDBR_S(mono_isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f <= sp[1].data.f)
3774 MINT_IN_BREAK;
3775 MINT_IN_CASE(MINT_BLE_UN_I4)
3776 BRELOP_CAST(i, <=, guint32);
3777 MINT_IN_BREAK;
3778 MINT_IN_CASE(MINT_BLE_UN_I8)
3779 BRELOP_CAST(l, <=, guint64);
3780 MINT_IN_BREAK;
3781 MINT_IN_CASE(MINT_BLE_UN_R4)
3782 CONDBR(isunordered (sp [0].data.f_r4, sp [1].data.f_r4) || sp[0].data.f_r4 <= sp[1].data.f_r4)
3783 MINT_IN_BREAK;
3784 MINT_IN_CASE(MINT_BLE_UN_R8)
3785 CONDBR(mono_isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f <= sp[1].data.f)
3786 MINT_IN_BREAK;
3787 MINT_IN_CASE(MINT_BLT_UN_I4_S)
3788 BRELOP_S_CAST(i, <, guint32);
3789 MINT_IN_BREAK;
3790 MINT_IN_CASE(MINT_BLT_UN_I8_S)
3791 BRELOP_S_CAST(l, <, guint64);
3792 MINT_IN_BREAK;
3793 MINT_IN_CASE(MINT_BLT_UN_R4_S)
3794 CONDBR_S(isunordered (sp [0].data.f_r4, sp [1].data.f_r4) || sp[0].data.f_r4 < sp[1].data.f_r4)
3795 MINT_IN_BREAK;
3796 MINT_IN_CASE(MINT_BLT_UN_R8_S)
3797 CONDBR_S(mono_isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f < sp[1].data.f)
3798 MINT_IN_BREAK;
3799 MINT_IN_CASE(MINT_BLT_UN_I4)
3800 BRELOP_CAST(i, <, guint32);
3801 MINT_IN_BREAK;
3802 MINT_IN_CASE(MINT_BLT_UN_I8)
3803 BRELOP_CAST(l, <, guint64);
3804 MINT_IN_BREAK;
3805 MINT_IN_CASE(MINT_BLT_UN_R4)
3806 CONDBR(isunordered (sp [0].data.f_r4, sp [1].data.f_r4) || sp[0].data.f_r4 < sp[1].data.f_r4)
3807 MINT_IN_BREAK;
3808 MINT_IN_CASE(MINT_BLT_UN_R8)
3809 CONDBR(mono_isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f < sp[1].data.f)
3810 MINT_IN_BREAK;
3811 MINT_IN_CASE(MINT_SWITCH) {
3812 guint32 n;
3813 const unsigned short *st;
3814 ++ip;
3815 n = READ32 (ip);
3816 ip += 2;
3817 st = ip + 2 * n;
3818 --sp;
3819 if ((guint32)sp->data.i < n) {
3820 gint offset;
3821 ip += 2 * (guint32)sp->data.i;
3822 offset = READ32 (ip);
3823 ip = ip + offset;
3824 } else {
3825 ip = st;
3827 MINT_IN_BREAK;
3829 MINT_IN_CASE(MINT_LDIND_I1_CHECK)
3830 NULL_CHECK (sp [-1].data.p);
3831 ++ip;
3832 sp[-1].data.i = *(gint8*)sp[-1].data.p;
3833 MINT_IN_BREAK;
3834 MINT_IN_CASE(MINT_LDIND_U1_CHECK)
3835 NULL_CHECK (sp [-1].data.p);
3836 ++ip;
3837 sp[-1].data.i = *(guint8*)sp[-1].data.p;
3838 MINT_IN_BREAK;
3839 MINT_IN_CASE(MINT_LDIND_I2_CHECK)
3840 NULL_CHECK (sp [-1].data.p);
3841 ++ip;
3842 sp[-1].data.i = *(gint16*)sp[-1].data.p;
3843 MINT_IN_BREAK;
3844 MINT_IN_CASE(MINT_LDIND_U2_CHECK)
3845 NULL_CHECK (sp [-1].data.p);
3846 ++ip;
3847 sp[-1].data.i = *(guint16*)sp[-1].data.p;
3848 MINT_IN_BREAK;
3849 MINT_IN_CASE(MINT_LDIND_I4_CHECK) /* Fall through */
3850 MINT_IN_CASE(MINT_LDIND_U4_CHECK)
3851 NULL_CHECK (sp [-1].data.p);
3852 ++ip;
3853 sp[-1].data.i = *(gint32*)sp[-1].data.p;
3854 MINT_IN_BREAK;
3855 MINT_IN_CASE(MINT_LDIND_I8_CHECK)
3856 NULL_CHECK (sp [-1].data.p);
3857 ++ip;
3858 #ifdef NO_UNALIGNED_ACCESS
3859 if ((gsize)sp [-1].data.p % SIZEOF_VOID_P)
3860 memcpy (&sp [-1].data.l, sp [-1].data.p, sizeof (gint64));
3861 else
3862 #endif
3863 sp[-1].data.l = *(gint64*)sp[-1].data.p;
3864 MINT_IN_BREAK;
3865 MINT_IN_CASE(MINT_LDIND_I) {
3866 guint16 offset = * (guint16 *)(ip + 1);
3867 sp[-1 - offset].data.p = *(gpointer*)sp[-1 - offset].data.p;
3868 ip += 2;
3869 MINT_IN_BREAK;
3871 MINT_IN_CASE(MINT_LDIND_I8) {
3872 guint16 offset = * (guint16 *)(ip + 1);
3873 #ifdef NO_UNALIGNED_ACCESS
3874 if ((gsize)sp [-1 - offset].data.p % SIZEOF_VOID_P)
3875 memcpy (&sp [-1 - offset].data.l, sp [-1 - offset].data.p, sizeof (gint64));
3876 else
3877 #endif
3878 sp[-1 - offset].data.l = *(gint64*)sp[-1 - offset].data.p;
3879 ip += 2;
3880 MINT_IN_BREAK;
3882 MINT_IN_CASE(MINT_LDIND_R4_CHECK)
3883 NULL_CHECK (sp [-1].data.p);
3884 ++ip;
3885 sp[-1].data.f_r4 = *(gfloat*)sp[-1].data.p;
3886 MINT_IN_BREAK;
3887 MINT_IN_CASE(MINT_LDIND_R8_CHECK)
3888 NULL_CHECK (sp [-1].data.p);
3889 ++ip;
3890 #ifdef NO_UNALIGNED_ACCESS
3891 if ((gsize)sp [-1].data.p % SIZEOF_VOID_P)
3892 memcpy (&sp [-1].data.f, sp [-1].data.p, sizeof (gdouble));
3893 else
3894 #endif
3895 sp[-1].data.f = *(gdouble*)sp[-1].data.p;
3896 MINT_IN_BREAK;
3897 MINT_IN_CASE(MINT_LDIND_REF)
3898 ++ip;
3899 sp[-1].data.p = *(gpointer*)sp[-1].data.p;
3900 MINT_IN_BREAK;
3901 MINT_IN_CASE(MINT_LDIND_REF_CHECK) {
3902 NULL_CHECK (sp [-1].data.p);
3903 ++ip;
3904 sp [-1].data.p = *(gpointer*)sp [-1].data.p;
3905 MINT_IN_BREAK;
3907 MINT_IN_CASE(MINT_STIND_REF)
3908 ++ip;
3909 sp -= 2;
3910 mono_gc_wbarrier_generic_store_internal (sp->data.p, sp [1].data.o);
3911 MINT_IN_BREAK;
3912 MINT_IN_CASE(MINT_STIND_I1)
3913 ++ip;
3914 sp -= 2;
3915 * (gint8 *) sp->data.p = (gint8)sp[1].data.i;
3916 MINT_IN_BREAK;
3917 MINT_IN_CASE(MINT_STIND_I2)
3918 ++ip;
3919 sp -= 2;
3920 * (gint16 *) sp->data.p = (gint16)sp[1].data.i;
3921 MINT_IN_BREAK;
3922 MINT_IN_CASE(MINT_STIND_I4)
3923 ++ip;
3924 sp -= 2;
3925 * (gint32 *) sp->data.p = sp[1].data.i;
3926 MINT_IN_BREAK;
3927 MINT_IN_CASE(MINT_STIND_I)
3928 ++ip;
3929 sp -= 2;
3930 * (mono_i *) sp->data.p = (mono_i)sp[1].data.p;
3931 MINT_IN_BREAK;
3932 MINT_IN_CASE(MINT_STIND_I8)
3933 ++ip;
3934 sp -= 2;
3935 #ifdef NO_UNALIGNED_ACCESS
3936 if ((gsize)sp->data.p % SIZEOF_VOID_P)
3937 memcpy (sp->data.p, &sp [1].data.l, sizeof (gint64));
3938 else
3939 #endif
3940 * (gint64 *) sp->data.p = sp[1].data.l;
3941 MINT_IN_BREAK;
3942 MINT_IN_CASE(MINT_STIND_R4)
3943 ++ip;
3944 sp -= 2;
3945 * (float *) sp->data.p = sp[1].data.f_r4;
3946 MINT_IN_BREAK;
3947 MINT_IN_CASE(MINT_STIND_R8)
3948 ++ip;
3949 sp -= 2;
3950 #ifdef NO_UNALIGNED_ACCESS
3951 if ((gsize)sp->data.p % SIZEOF_VOID_P)
3952 memcpy (sp->data.p, &sp [1].data.f, sizeof (double));
3953 else
3954 #endif
3955 * (double *) sp->data.p = sp[1].data.f;
3956 MINT_IN_BREAK;
3957 MINT_IN_CASE(MINT_MONO_ATOMIC_STORE_I4)
3958 ++ip;
3959 sp -= 2;
3960 mono_atomic_store_i32 ((gint32 *) sp->data.p, sp [1].data.i);
3961 MINT_IN_BREAK;
3962 #define BINOP(datamem, op) \
3963 --sp; \
3964 sp [-1].data.datamem = sp [-1].data.datamem op sp [0].data.datamem; \
3965 ++ip;
3966 MINT_IN_CASE(MINT_ADD_I4)
3967 BINOP(i, +);
3968 MINT_IN_BREAK;
3969 MINT_IN_CASE(MINT_ADD_I8)
3970 BINOP(l, +);
3971 MINT_IN_BREAK;
3972 MINT_IN_CASE(MINT_ADD_R4)
3973 BINOP(f_r4, +);
3974 MINT_IN_BREAK;
3975 MINT_IN_CASE(MINT_ADD_R8)
3976 BINOP(f, +);
3977 MINT_IN_BREAK;
3978 MINT_IN_CASE(MINT_ADD1_I4)
3979 ++sp [-1].data.i;
3980 ++ip;
3981 MINT_IN_BREAK;
3982 MINT_IN_CASE(MINT_ADD1_I8)
3983 ++sp [-1].data.l;
3984 ++ip;
3985 MINT_IN_BREAK;
3986 MINT_IN_CASE(MINT_SUB_I4)
3987 BINOP(i, -);
3988 MINT_IN_BREAK;
3989 MINT_IN_CASE(MINT_SUB_I8)
3990 BINOP(l, -);
3991 MINT_IN_BREAK;
3992 MINT_IN_CASE(MINT_SUB_R4)
3993 BINOP(f_r4, -);
3994 MINT_IN_BREAK;
3995 MINT_IN_CASE(MINT_SUB_R8)
3996 BINOP(f, -);
3997 MINT_IN_BREAK;
3998 MINT_IN_CASE(MINT_SUB1_I4)
3999 --sp [-1].data.i;
4000 ++ip;
4001 MINT_IN_BREAK;
4002 MINT_IN_CASE(MINT_SUB1_I8)
4003 --sp [-1].data.l;
4004 ++ip;
4005 MINT_IN_BREAK;
4006 MINT_IN_CASE(MINT_MUL_I4)
4007 BINOP(i, *);
4008 MINT_IN_BREAK;
4009 MINT_IN_CASE(MINT_MUL_I8)
4010 BINOP(l, *);
4011 MINT_IN_BREAK;
4012 MINT_IN_CASE(MINT_MUL_R4)
4013 BINOP(f_r4, *);
4014 MINT_IN_BREAK;
4015 MINT_IN_CASE(MINT_MUL_R8)
4016 BINOP(f, *);
4017 MINT_IN_BREAK;
4018 MINT_IN_CASE(MINT_DIV_I4)
4019 if (sp [-1].data.i == 0)
4020 THROW_EX_DIV_ZERO (ip);
4021 if (sp [-1].data.i == (-1) && sp [-2].data.i == G_MININT32)
4022 THROW_EX_OVF (ip);
4023 BINOP(i, /);
4024 MINT_IN_BREAK;
4025 MINT_IN_CASE(MINT_DIV_I8)
4026 if (sp [-1].data.l == 0)
4027 THROW_EX_DIV_ZERO (ip);
4028 if (sp [-1].data.l == (-1) && sp [-2].data.l == G_MININT64)
4029 THROW_EX_OVF (ip);
4030 BINOP(l, /);
4031 MINT_IN_BREAK;
4032 MINT_IN_CASE(MINT_DIV_R4)
4033 BINOP(f_r4, /);
4034 MINT_IN_BREAK;
4035 MINT_IN_CASE(MINT_DIV_R8)
4036 BINOP(f, /);
4037 MINT_IN_BREAK;
4039 #define BINOP_CAST(datamem, op, type) \
4040 --sp; \
4041 sp [-1].data.datamem = (type)sp [-1].data.datamem op (type)sp [0].data.datamem; \
4042 ++ip;
4043 MINT_IN_CASE(MINT_DIV_UN_I4)
4044 if (sp [-1].data.i == 0)
4045 THROW_EX_DIV_ZERO (ip);
4046 BINOP_CAST(i, /, guint32);
4047 MINT_IN_BREAK;
4048 MINT_IN_CASE(MINT_DIV_UN_I8)
4049 if (sp [-1].data.l == 0)
4050 THROW_EX_DIV_ZERO (ip);
4051 BINOP_CAST(l, /, guint64);
4052 MINT_IN_BREAK;
4053 MINT_IN_CASE(MINT_REM_I4)
4054 if (sp [-1].data.i == 0)
4055 THROW_EX_DIV_ZERO (ip);
4056 if (sp [-1].data.i == (-1) && sp [-2].data.i == G_MININT32)
4057 THROW_EX_OVF (ip);
4058 BINOP(i, %);
4059 MINT_IN_BREAK;
4060 MINT_IN_CASE(MINT_REM_I8)
4061 if (sp [-1].data.l == 0)
4062 THROW_EX_DIV_ZERO (ip);
4063 if (sp [-1].data.l == (-1) && sp [-2].data.l == G_MININT64)
4064 THROW_EX_OVF (ip);
4065 BINOP(l, %);
4066 MINT_IN_BREAK;
4067 MINT_IN_CASE(MINT_REM_R4)
4068 /* FIXME: what do we actually do here? */
4069 --sp;
4070 sp [-1].data.f_r4 = fmodf (sp [-1].data.f_r4, sp [0].data.f_r4);
4071 ++ip;
4072 MINT_IN_BREAK;
4073 MINT_IN_CASE(MINT_REM_R8)
4074 /* FIXME: what do we actually do here? */
4075 --sp;
4076 sp [-1].data.f = fmod (sp [-1].data.f, sp [0].data.f);
4077 ++ip;
4078 MINT_IN_BREAK;
4079 MINT_IN_CASE(MINT_REM_UN_I4)
4080 if (sp [-1].data.i == 0)
4081 THROW_EX_DIV_ZERO (ip);
4082 BINOP_CAST(i, %, guint32);
4083 MINT_IN_BREAK;
4084 MINT_IN_CASE(MINT_REM_UN_I8)
4085 if (sp [-1].data.l == 0)
4086 THROW_EX_DIV_ZERO (ip);
4087 BINOP_CAST(l, %, guint64);
4088 MINT_IN_BREAK;
4089 MINT_IN_CASE(MINT_AND_I4)
4090 BINOP(i, &);
4091 MINT_IN_BREAK;
4092 MINT_IN_CASE(MINT_AND_I8)
4093 BINOP(l, &);
4094 MINT_IN_BREAK;
4095 MINT_IN_CASE(MINT_OR_I4)
4096 BINOP(i, |);
4097 MINT_IN_BREAK;
4098 MINT_IN_CASE(MINT_OR_I8)
4099 BINOP(l, |);
4100 MINT_IN_BREAK;
4101 MINT_IN_CASE(MINT_XOR_I4)
4102 BINOP(i, ^);
4103 MINT_IN_BREAK;
4104 MINT_IN_CASE(MINT_XOR_I8)
4105 BINOP(l, ^);
4106 MINT_IN_BREAK;
4108 #define SHIFTOP(datamem, op) \
4109 --sp; \
4110 sp [-1].data.datamem = sp [-1].data.datamem op sp [0].data.i; \
4111 ++ip;
4113 MINT_IN_CASE(MINT_SHL_I4)
4114 SHIFTOP(i, <<);
4115 MINT_IN_BREAK;
4116 MINT_IN_CASE(MINT_SHL_I8)
4117 SHIFTOP(l, <<);
4118 MINT_IN_BREAK;
4119 MINT_IN_CASE(MINT_SHR_I4)
4120 SHIFTOP(i, >>);
4121 MINT_IN_BREAK;
4122 MINT_IN_CASE(MINT_SHR_I8)
4123 SHIFTOP(l, >>);
4124 MINT_IN_BREAK;
4125 MINT_IN_CASE(MINT_SHR_UN_I4)
4126 --sp;
4127 sp [-1].data.i = (guint32)sp [-1].data.i >> sp [0].data.i;
4128 ++ip;
4129 MINT_IN_BREAK;
4130 MINT_IN_CASE(MINT_SHR_UN_I8)
4131 --sp;
4132 sp [-1].data.l = (guint64)sp [-1].data.l >> sp [0].data.i;
4133 ++ip;
4134 MINT_IN_BREAK;
4135 MINT_IN_CASE(MINT_NEG_I4)
4136 sp [-1].data.i = - sp [-1].data.i;
4137 ++ip;
4138 MINT_IN_BREAK;
4139 MINT_IN_CASE(MINT_NEG_I8)
4140 sp [-1].data.l = - sp [-1].data.l;
4141 ++ip;
4142 MINT_IN_BREAK;
4143 MINT_IN_CASE(MINT_NEG_R4)
4144 sp [-1].data.f_r4 = - sp [-1].data.f_r4;
4145 ++ip;
4146 MINT_IN_BREAK;
4147 MINT_IN_CASE(MINT_NEG_R8)
4148 sp [-1].data.f = - sp [-1].data.f;
4149 ++ip;
4150 MINT_IN_BREAK;
4151 MINT_IN_CASE(MINT_NOT_I4)
4152 sp [-1].data.i = ~ sp [-1].data.i;
4153 ++ip;
4154 MINT_IN_BREAK;
4155 MINT_IN_CASE(MINT_NOT_I8)
4156 sp [-1].data.l = ~ sp [-1].data.l;
4157 ++ip;
4158 MINT_IN_BREAK;
4159 MINT_IN_CASE(MINT_CONV_I1_I4)
4160 sp [-1].data.i = (gint8)sp [-1].data.i;
4161 ++ip;
4162 MINT_IN_BREAK;
4163 MINT_IN_CASE(MINT_CONV_I1_I8)
4164 sp [-1].data.i = (gint8)sp [-1].data.l;
4165 ++ip;
4166 MINT_IN_BREAK;
4167 MINT_IN_CASE(MINT_CONV_I1_R4)
4168 sp [-1].data.i = (gint8) (gint32) sp [-1].data.f_r4;
4169 ++ip;
4170 MINT_IN_BREAK;
4171 MINT_IN_CASE(MINT_CONV_I1_R8)
4172 /* without gint32 cast, C compiler is allowed to use undefined
4173 * behaviour if data.f is bigger than >255. See conv.fpint section
4174 * in C standard:
4175 * > The conversion truncates; that is, the fractional part
4176 * > is discarded. The behavior is undefined if the truncated
4177 * > value cannot be represented in the destination type.
4178 * */
4179 sp [-1].data.i = (gint8) (gint32) sp [-1].data.f;
4180 ++ip;
4181 MINT_IN_BREAK;
4182 MINT_IN_CASE(MINT_CONV_U1_I4)
4183 sp [-1].data.i = (guint8)sp [-1].data.i;
4184 ++ip;
4185 MINT_IN_BREAK;
4186 MINT_IN_CASE(MINT_CONV_U1_I8)
4187 sp [-1].data.i = (guint8)sp [-1].data.l;
4188 ++ip;
4189 MINT_IN_BREAK;
4190 MINT_IN_CASE(MINT_CONV_U1_R4)
4191 sp [-1].data.i = (guint8) (guint32) sp [-1].data.f_r4;
4192 ++ip;
4193 MINT_IN_BREAK;
4194 MINT_IN_CASE(MINT_CONV_U1_R8)
4195 sp [-1].data.i = (guint8) (guint32) sp [-1].data.f;
4196 ++ip;
4197 MINT_IN_BREAK;
4198 MINT_IN_CASE(MINT_CONV_I2_I4)
4199 sp [-1].data.i = (gint16)sp [-1].data.i;
4200 ++ip;
4201 MINT_IN_BREAK;
4202 MINT_IN_CASE(MINT_CONV_I2_I8)
4203 sp [-1].data.i = (gint16)sp [-1].data.l;
4204 ++ip;
4205 MINT_IN_BREAK;
4206 MINT_IN_CASE(MINT_CONV_I2_R4)
4207 sp [-1].data.i = (gint16) (gint32) sp [-1].data.f_r4;
4208 ++ip;
4209 MINT_IN_BREAK;
4210 MINT_IN_CASE(MINT_CONV_I2_R8)
4211 sp [-1].data.i = (gint16) (gint32) sp [-1].data.f;
4212 ++ip;
4213 MINT_IN_BREAK;
4214 MINT_IN_CASE(MINT_CONV_U2_I4)
4215 sp [-1].data.i = (guint16)sp [-1].data.i;
4216 ++ip;
4217 MINT_IN_BREAK;
4218 MINT_IN_CASE(MINT_CONV_U2_I8)
4219 sp [-1].data.i = (guint16)sp [-1].data.l;
4220 ++ip;
4221 MINT_IN_BREAK;
4222 MINT_IN_CASE(MINT_CONV_U2_R4)
4223 sp [-1].data.i = (guint16) (guint32) sp [-1].data.f_r4;
4224 ++ip;
4225 MINT_IN_BREAK;
4226 MINT_IN_CASE(MINT_CONV_U2_R8)
4227 sp [-1].data.i = (guint16) (guint32) sp [-1].data.f;
4228 ++ip;
4229 MINT_IN_BREAK;
4230 MINT_IN_CASE(MINT_CONV_I4_R4)
4231 sp [-1].data.i = (gint32) sp [-1].data.f_r4;
4232 ++ip;
4233 MINT_IN_BREAK;
4234 MINT_IN_CASE(MINT_CONV_I4_R8)
4235 sp [-1].data.i = (gint32)sp [-1].data.f;
4236 ++ip;
4237 MINT_IN_BREAK;
4238 MINT_IN_CASE(MINT_CONV_U4_I8)
4239 MINT_IN_CASE(MINT_CONV_I4_I8)
4240 sp [-1].data.i = (gint32)sp [-1].data.l;
4241 ++ip;
4242 MINT_IN_BREAK;
4243 MINT_IN_CASE(MINT_CONV_I4_I8_SP)
4244 sp [-2].data.i = (gint32)sp [-2].data.l;
4245 ++ip;
4246 MINT_IN_BREAK;
4247 MINT_IN_CASE(MINT_CONV_U4_R4)
4248 #ifdef MONO_ARCH_EMULATE_FCONV_TO_U4
4249 sp [-1].data.i = mono_rconv_u4 (sp [-1].data.f_r4);
4250 #else
4251 sp [-1].data.i = (guint32) sp [-1].data.f_r4;
4252 #endif
4253 ++ip;
4254 MINT_IN_BREAK;
4255 MINT_IN_CASE(MINT_CONV_U4_R8)
4256 #ifdef MONO_ARCH_EMULATE_FCONV_TO_U4
4257 sp [-1].data.i = mono_fconv_u4_2 (sp [-1].data.f);
4258 #else
4259 sp [-1].data.i = (guint32) sp [-1].data.f;
4260 #endif
4261 ++ip;
4262 MINT_IN_BREAK;
4263 MINT_IN_CASE(MINT_CONV_I8_I4)
4264 sp [-1].data.l = sp [-1].data.i;
4265 ++ip;
4266 MINT_IN_BREAK;
4267 MINT_IN_CASE(MINT_CONV_I8_I4_SP)
4268 sp [-2].data.l = sp [-2].data.i;
4269 ++ip;
4270 MINT_IN_BREAK;
4271 MINT_IN_CASE(MINT_CONV_I8_U4)
4272 sp [-1].data.l = (guint32)sp [-1].data.i;
4273 ++ip;
4274 MINT_IN_BREAK;
4275 MINT_IN_CASE(MINT_CONV_I8_R4)
4276 sp [-1].data.l = (gint64) sp [-1].data.f_r4;
4277 ++ip;
4278 MINT_IN_BREAK;
4279 MINT_IN_CASE(MINT_CONV_I8_R8)
4280 sp [-1].data.l = (gint64)sp [-1].data.f;
4281 ++ip;
4282 MINT_IN_BREAK;
4283 MINT_IN_CASE(MINT_CONV_R4_I4)
4284 sp [-1].data.f_r4 = (float)sp [-1].data.i;
4285 ++ip;
4286 MINT_IN_BREAK;
4287 MINT_IN_CASE(MINT_CONV_R4_I8)
4288 sp [-1].data.f_r4 = (float)sp [-1].data.l;
4289 ++ip;
4290 MINT_IN_BREAK;
4291 MINT_IN_CASE(MINT_CONV_R4_R8)
4292 sp [-1].data.f_r4 = (float)sp [-1].data.f;
4293 ++ip;
4294 MINT_IN_BREAK;
4295 MINT_IN_CASE(MINT_CONV_R8_I4)
4296 sp [-1].data.f = (double)sp [-1].data.i;
4297 ++ip;
4298 MINT_IN_BREAK;
4299 MINT_IN_CASE(MINT_CONV_R8_I8)
4300 sp [-1].data.f = (double)sp [-1].data.l;
4301 ++ip;
4302 MINT_IN_BREAK;
4303 MINT_IN_CASE(MINT_CONV_R8_R4)
4304 sp [-1].data.f = (double) sp [-1].data.f_r4;
4305 ++ip;
4306 MINT_IN_BREAK;
4307 MINT_IN_CASE(MINT_CONV_R8_R4_SP)
4308 sp [-2].data.f = (double) sp [-2].data.f_r4;
4309 ++ip;
4310 MINT_IN_BREAK;
4311 MINT_IN_CASE(MINT_CONV_U8_I4)
4312 sp [-1].data.l = sp [-1].data.i & 0xffffffff;
4313 ++ip;
4314 MINT_IN_BREAK;
4315 MINT_IN_CASE(MINT_CONV_U8_R4)
4316 #ifdef MONO_ARCH_EMULATE_FCONV_TO_U8
4317 sp [-1].data.l = mono_rconv_u8 (sp [-1].data.f_r4);
4318 #else
4319 sp [-1].data.l = (guint64) sp [-1].data.f_r4;
4320 #endif
4321 ++ip;
4322 MINT_IN_BREAK;
4323 MINT_IN_CASE(MINT_CONV_U8_R8)
4324 #ifdef MONO_ARCH_EMULATE_FCONV_TO_U8
4325 sp [-1].data.l = mono_fconv_u8_2 (sp [-1].data.f);
4326 #else
4327 sp [-1].data.l = (guint64)sp [-1].data.f;
4328 #endif
4329 ++ip;
4330 MINT_IN_BREAK;
4331 MINT_IN_CASE(MINT_CPOBJ) {
4332 c = (MonoClass*)imethod->data_items[* (guint16 *)(ip + 1)];
4333 g_assert (m_class_is_valuetype (c));
4334 /* if this assertion fails, we need to add a write barrier */
4335 g_assert (!MONO_TYPE_IS_REFERENCE (m_class_get_byval_arg (c)));
4336 stackval_from_data (m_class_get_byval_arg (c), (stackval*)sp [-2].data.p, sp [-1].data.p, FALSE);
4337 ip += 2;
4338 sp -= 2;
4339 MINT_IN_BREAK;
4341 MINT_IN_CASE(MINT_CPOBJ_VT) {
4342 c = (MonoClass*)imethod->data_items[* (guint16 *)(ip + 1)];
4343 mono_value_copy_internal (sp [-2].data.vt, sp [-1].data.vt, c);
4344 ip += 2;
4345 sp -= 2;
4346 MINT_IN_BREAK;
4348 MINT_IN_CASE(MINT_LDOBJ_VT) {
4349 int size = READ32(ip + 1);
4350 ip += 3;
4351 memcpy (vt_sp, sp [-1].data.p, size);
4352 sp [-1].data.p = vt_sp;
4353 vt_sp += ALIGN_TO (size, MINT_VT_ALIGNMENT);
4354 MINT_IN_BREAK;
4356 MINT_IN_CASE(MINT_LDSTR)
4357 sp->data.p = imethod->data_items [* (guint16 *)(ip + 1)];
4358 ++sp;
4359 ip += 2;
4360 MINT_IN_BREAK;
4361 MINT_IN_CASE(MINT_LDSTR_TOKEN) {
4362 MonoString *s = NULL;
4363 guint32 strtoken = (guint32)(gsize)imethod->data_items [* (guint16 *)(ip + 1)];
4365 MonoMethod *method = imethod->method;
4366 if (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD) {
4367 s = (MonoString*)mono_method_get_wrapper_data (method, strtoken);
4368 } else if (method->wrapper_type != MONO_WRAPPER_NONE) {
4369 s = mono_string_new_wrapper_internal ((const char*)mono_method_get_wrapper_data (method, strtoken));
4370 } else {
4371 g_assert_not_reached ();
4373 sp->data.p = s;
4374 ++sp;
4375 ip += 2;
4376 MINT_IN_BREAK;
4378 MINT_IN_CASE(MINT_NEWOBJ_ARRAY) {
4379 MonoClass *newobj_class;
4380 guint32 token = * (guint16 *)(ip + 1);
4381 guint16 param_count = * (guint16 *)(ip + 2);
4383 newobj_class = (MonoClass*) imethod->data_items [token];
4385 sp -= param_count;
4386 sp->data.o = ves_array_create (imethod->domain, newobj_class, param_count, sp, error);
4387 if (!mono_error_ok (error))
4388 THROW_EX (mono_error_convert_to_exception (error), ip);
4390 ++sp;
4391 ip += 3;
4392 MINT_IN_BREAK;
4394 MINT_IN_CASE(MINT_NEWOBJ_FAST) {
4395 guint16 param_count;
4396 guint16 imethod_index = *(guint16*) (ip + 1);
4398 const gboolean is_inlined = imethod_index == 0xffff;
4400 param_count = *(guint16*)(ip + 2);
4402 if (param_count) {
4403 sp -= param_count;
4404 memmove (sp + 1 + is_inlined, sp, param_count * sizeof (stackval));
4407 MonoVTable *vtable = (MonoVTable*) imethod->data_items [*(guint16*)(ip + 3)];
4408 INIT_VTABLE (vtable);
4410 frame_objref (frame) = mono_gc_alloc_obj (vtable, m_class_get_instance_size (vtable->klass));
4411 if (G_UNLIKELY (!frame_objref (frame))) {
4412 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", m_class_get_instance_size (vtable->klass));
4413 THROW_EX (mono_error_convert_to_exception (error), ip);
4416 sp [0].data.o = frame_objref (frame);
4417 if (is_inlined) {
4418 sp [1].data.o = frame_objref (frame);
4419 sp += param_count + 2;
4420 } else {
4421 InterpMethod *ctor_method = (InterpMethod*) imethod->data_items [imethod_index];
4422 frame->ip = ip;
4424 child_frame.imethod = ctor_method;
4425 child_frame.stack_args = sp;
4427 interp_exec_method (&child_frame, context, error);
4428 CHECK_RESUME_STATE (context);
4429 sp [0].data.o = frame_objref (frame);
4430 sp++;
4432 ip += 4;
4434 MINT_IN_BREAK;
4436 MINT_IN_CASE(MINT_NEWOBJ_VT_FAST)
4437 MINT_IN_CASE(MINT_NEWOBJ_VTST_FAST) {
4438 guint16 param_count;
4439 stackval valuetype_this;
4441 frame->ip = ip;
4443 child_frame.imethod = (InterpMethod*) imethod->data_items [*(guint16*)(ip + 1)];
4444 param_count = *(guint16*)(ip + 2);
4446 if (param_count) {
4447 sp -= param_count;
4448 memmove (sp + 1, sp, param_count * sizeof (stackval));
4450 child_frame.stack_args = sp;
4452 gboolean vtst = *ip == MINT_NEWOBJ_VTST_FAST;
4453 if (vtst) {
4454 memset (vt_sp, 0, *(guint16*)(ip + 3));
4455 sp->data.p = vt_sp;
4456 valuetype_this.data.p = vt_sp;
4457 ip += 4;
4458 } else {
4459 memset (&valuetype_this, 0, sizeof (stackval));
4460 sp->data.p = &valuetype_this;
4461 ip += 3;
4464 interp_exec_method (&child_frame, context, error);
4466 CHECK_RESUME_STATE (context);
4468 *sp = valuetype_this;
4469 ++sp;
4470 MINT_IN_BREAK;
4472 MINT_IN_CASE(MINT_NEWOBJ) {
4473 MonoClass *newobj_class;
4474 MonoMethodSignature *csig;
4475 stackval valuetype_this;
4476 guint32 token;
4477 stackval retval;
4479 frame->ip = ip;
4481 token = * (guint16 *)(ip + 1);
4482 ip += 2;
4484 child_frame.ip = NULL;
4485 child_frame.ex = NULL;
4487 child_frame.imethod = (InterpMethod*)imethod->data_items [token];
4488 csig = mono_method_signature_internal (child_frame.imethod->method);
4489 newobj_class = child_frame.imethod->method->klass;
4490 /*if (profiling_classes) {
4491 guint count = GPOINTER_TO_UINT (g_hash_table_lookup (profiling_classes, newobj_class));
4492 count++;
4493 g_hash_table_insert (profiling_classes, newobj_class, GUINT_TO_POINTER (count));
4496 g_assert (csig->hasthis);
4497 if (csig->param_count) {
4498 sp -= csig->param_count;
4499 memmove (sp + 1, sp, csig->param_count * sizeof (stackval));
4501 child_frame.stack_args = sp;
4504 * First arg is the object.
4506 if (m_class_is_valuetype (newobj_class)) {
4507 MonoType *t = m_class_get_byval_arg (newobj_class);
4508 memset (&valuetype_this, 0, sizeof (stackval));
4509 if (!m_class_is_enumtype (newobj_class) && (t->type == MONO_TYPE_VALUETYPE || (t->type == MONO_TYPE_GENERICINST && mono_type_generic_inst_is_valuetype (t)))) {
4510 sp->data.p = vt_sp;
4511 valuetype_this.data.p = vt_sp;
4512 } else {
4513 sp->data.p = &valuetype_this;
4515 } else {
4516 if (newobj_class != mono_defaults.string_class) {
4517 MonoVTable *vtable = mono_class_vtable_checked (imethod->domain, newobj_class, error);
4518 if (!mono_error_ok (error) || !mono_runtime_class_init_full (vtable, error))
4519 THROW_EX (mono_error_convert_to_exception (error), ip);
4520 frame_objref (frame) = mono_object_new_checked (imethod->domain, newobj_class, error);
4521 mono_error_cleanup (error); /* FIXME: don't swallow the error */
4522 EXCEPTION_CHECKPOINT;
4523 sp->data.o = frame_objref (frame);
4524 #ifndef DISABLE_REMOTING
4525 if (mono_object_is_transparent_proxy (frame_objref (frame))) {
4526 MonoMethod *remoting_invoke_method = mono_marshal_get_remoting_invoke_with_check (child_frame.imethod->method, error);
4527 mono_error_assert_ok (error);
4528 child_frame.imethod = mono_interp_get_imethod (imethod->domain, remoting_invoke_method, error);
4529 mono_error_assert_ok (error);
4531 #endif
4532 } else {
4533 sp->data.p = NULL;
4534 child_frame.retval = &retval;
4538 interp_exec_method (&child_frame, context, error);
4540 CHECK_RESUME_STATE (context);
4543 * a constructor returns void, but we need to return the object we created
4545 if (m_class_is_valuetype (newobj_class) && !m_class_is_enumtype (newobj_class)) {
4546 *sp = valuetype_this;
4547 } else if (newobj_class == mono_defaults.string_class) {
4548 *sp = retval;
4549 } else {
4550 sp->data.o = frame_objref (frame);
4552 ++sp;
4553 MINT_IN_BREAK;
4555 MINT_IN_CASE(MINT_NEWOBJ_MAGIC) {
4556 frame->ip = ip;
4557 ip += 2;
4559 MINT_IN_BREAK;
4561 MINT_IN_CASE(MINT_INTRINS_BYREFERENCE_CTOR) {
4562 MonoMethodSignature *csig;
4563 guint32 token;
4565 frame->ip = ip;
4566 token = * (guint16 *)(ip + 1);
4567 ip += 2;
4569 InterpMethod *cmethod = (InterpMethod*)imethod->data_items [token];
4570 csig = mono_method_signature_internal (cmethod->method);
4572 g_assert (csig->hasthis);
4573 sp -= csig->param_count;
4575 gpointer arg0 = sp [0].data.p;
4577 gpointer *byreference_this = (gpointer*)vt_sp;
4578 *byreference_this = arg0;
4580 /* Followed by a VTRESULT opcode which will push the result on the stack */
4581 ++sp;
4582 MINT_IN_BREAK;
4584 MINT_IN_CASE(MINT_INTRINS_BYREFERENCE_GET_VALUE) {
4585 gpointer *byreference_this = (gpointer*)sp [-1].data.p;
4586 sp [-1].data.p = *byreference_this;
4587 ++ip;
4588 MINT_IN_BREAK;
4590 MINT_IN_CASE(MINT_INTRINS_UNSAFE_ADD_BYTE_OFFSET) {
4591 sp -= 2;
4592 sp [0].data.p = (guint8*)sp [0].data.p + sp [1].data.nati;
4593 sp ++;
4594 ++ip;
4595 MINT_IN_BREAK;
4597 MINT_IN_CASE(MINT_INTRINS_UNSAFE_BYTE_OFFSET) {
4598 sp -= 2;
4599 sp [0].data.nati = (guint8*)sp [1].data.p - (guint8*)sp [0].data.p;
4600 sp ++;
4601 ++ip;
4602 MINT_IN_BREAK;
4604 MINT_IN_CASE(MINT_INTRINS_RUNTIMEHELPERS_OBJECT_HAS_COMPONENT_SIZE) {
4605 sp -= 1;
4606 MonoObject *obj = sp [0].data.o;
4607 sp [0].data.i = (obj->vtable->flags & MONO_VT_FLAG_ARRAY_OR_STRING) != 0;
4608 sp ++;
4609 ++ip;
4610 MINT_IN_BREAK;
4612 MINT_IN_CASE(MINT_CASTCLASS_INTERFACE)
4613 MINT_IN_CASE(MINT_ISINST_INTERFACE) {
4614 gboolean isinst_instr = *ip == MINT_ISINST_INTERFACE;
4615 c = (MonoClass*)imethod->data_items [*(guint16 *)(ip + 1)];
4616 if ((o = sp [-1].data.o)) {
4617 gboolean isinst;
4618 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (o->vtable, m_class_get_interface_id (c))) {
4619 isinst = TRUE;
4620 } else if (m_class_is_array_special_interface (c) || mono_object_is_transparent_proxy (o)) {
4621 /* slow path */
4622 isinst = mono_object_isinst_checked (o, c, error) != NULL;
4623 mono_error_cleanup (error); /* FIXME: don't swallow the error */
4624 } else {
4625 isinst = FALSE;
4628 if (!isinst) {
4629 if (isinst_instr)
4630 sp [-1].data.p = NULL;
4631 else
4632 THROW_EX (mono_get_exception_invalid_cast (), ip);
4635 ip += 2;
4636 MINT_IN_BREAK;
4638 MINT_IN_CASE(MINT_CASTCLASS_COMMON)
4639 MINT_IN_CASE(MINT_ISINST_COMMON) {
4640 gboolean isinst_instr = *ip == MINT_ISINST_COMMON;
4641 c = (MonoClass*)imethod->data_items [*(guint16 *)(ip + 1)];
4642 if ((o = sp [-1].data.o)) {
4643 gboolean isinst = mono_class_has_parent_fast (o->vtable->klass, c);
4645 if (!isinst) {
4646 if (isinst_instr)
4647 sp [-1].data.p = NULL;
4648 else
4649 THROW_EX (mono_get_exception_invalid_cast (), ip);
4652 ip += 2;
4653 MINT_IN_BREAK;
4655 MINT_IN_CASE(MINT_CASTCLASS)
4656 MINT_IN_CASE(MINT_ISINST) {
4657 gboolean isinst_instr = *ip == MINT_ISINST;
4658 c = (MonoClass*)imethod->data_items [*(guint16 *)(ip + 1)];
4659 if ((o = sp [-1].data.o)) {
4660 MonoObject *isinst_obj = mono_object_isinst_checked (o, c, error);
4661 mono_error_cleanup (error); /* FIXME: don't swallow the error */
4662 if (!isinst_obj) {
4663 if (isinst_instr)
4664 sp [-1].data.p = NULL;
4665 else
4666 THROW_EX (mono_get_exception_invalid_cast (), ip);
4669 ip += 2;
4670 MINT_IN_BREAK;
4672 MINT_IN_CASE(MINT_CONV_R_UN_I4)
4673 sp [-1].data.f = (double)(guint32)sp [-1].data.i;
4674 ++ip;
4675 MINT_IN_BREAK;
4676 MINT_IN_CASE(MINT_CONV_R_UN_I8)
4677 sp [-1].data.f = (double)(guint64)sp [-1].data.l;
4678 ++ip;
4679 MINT_IN_BREAK;
4680 MINT_IN_CASE(MINT_UNBOX)
4681 c = (MonoClass*)imethod->data_items[*(guint16 *)(ip + 1)];
4683 o = sp [-1].data.o;
4684 NULL_CHECK (o);
4686 if (!(m_class_get_rank (o->vtable->klass) == 0 && m_class_get_element_class (o->vtable->klass) == m_class_get_element_class (c)))
4687 THROW_EX (mono_get_exception_invalid_cast (), ip);
4689 sp [-1].data.p = mono_object_unbox_internal (o);
4690 ip += 2;
4691 MINT_IN_BREAK;
4692 MINT_IN_CASE(MINT_THROW)
4693 --sp;
4694 if (!sp->data.p)
4695 sp->data.p = mono_get_exception_null_reference ();
4697 THROW_EX ((MonoException *)sp->data.p, ip);
4698 MINT_IN_BREAK;
4699 MINT_IN_CASE(MINT_CHECKPOINT)
4700 /* Do synchronous checking of abort requests */
4701 EXCEPTION_CHECKPOINT;
4702 ++ip;
4703 MINT_IN_BREAK;
4704 MINT_IN_CASE(MINT_SAFEPOINT)
4705 /* Do synchronous checking of abort requests */
4706 EXCEPTION_CHECKPOINT;
4707 /* Poll safepoint */
4708 mono_threads_safepoint ();
4709 ++ip;
4710 MINT_IN_BREAK;
4711 MINT_IN_CASE(MINT_LDFLDA_UNSAFE)
4712 o = sp [-1].data.o;
4713 sp[-1].data.p = (char *)o + * (guint16 *)(ip + 1);
4714 ip += 2;
4715 MINT_IN_BREAK;
4716 MINT_IN_CASE(MINT_LDFLDA)
4717 o = sp [-1].data.o;
4718 NULL_CHECK (o);
4719 sp[-1].data.p = (char *)o + * (guint16 *)(ip + 1);
4720 ip += 2;
4721 MINT_IN_BREAK;
4722 MINT_IN_CASE(MINT_CKNULL_N) {
4723 /* Same as CKNULL, but further down the stack */
4724 int n = *(guint16*)(ip + 1);
4725 o = sp [-n].data.o;
4726 NULL_CHECK (o);
4727 ip += 2;
4728 MINT_IN_BREAK;
4731 #define LDFLD_UNALIGNED(datamem, fieldtype, unaligned) \
4732 o = sp [-1].data.o; \
4733 NULL_CHECK (o); \
4734 if (unaligned) \
4735 memcpy (&sp[-1].data.datamem, (char *)o + * (guint16 *)(ip + 1), sizeof (fieldtype)); \
4736 else \
4737 sp[-1].data.datamem = * (fieldtype *)((char *)o + * (guint16 *)(ip + 1)) ; \
4738 ip += 2;
4740 #define LDFLD(datamem, fieldtype) LDFLD_UNALIGNED(datamem, fieldtype, FALSE)
4742 MINT_IN_CASE(MINT_LDFLD_I1) LDFLD(i, gint8); MINT_IN_BREAK;
4743 MINT_IN_CASE(MINT_LDFLD_U1) LDFLD(i, guint8); MINT_IN_BREAK;
4744 MINT_IN_CASE(MINT_LDFLD_I2) LDFLD(i, gint16); MINT_IN_BREAK;
4745 MINT_IN_CASE(MINT_LDFLD_U2) LDFLD(i, guint16); MINT_IN_BREAK;
4746 MINT_IN_CASE(MINT_LDFLD_I4) LDFLD(i, gint32); MINT_IN_BREAK;
4747 MINT_IN_CASE(MINT_LDFLD_I8) LDFLD(l, gint64); MINT_IN_BREAK;
4748 MINT_IN_CASE(MINT_LDFLD_R4) LDFLD(f_r4, float); MINT_IN_BREAK;
4749 MINT_IN_CASE(MINT_LDFLD_R8) LDFLD(f, double); MINT_IN_BREAK;
4750 MINT_IN_CASE(MINT_LDFLD_O) LDFLD(p, gpointer); MINT_IN_BREAK;
4751 MINT_IN_CASE(MINT_LDFLD_P) LDFLD(p, gpointer); MINT_IN_BREAK;
4752 MINT_IN_CASE(MINT_LDFLD_I8_UNALIGNED) LDFLD_UNALIGNED(l, gint64, TRUE); MINT_IN_BREAK;
4753 MINT_IN_CASE(MINT_LDFLD_R8_UNALIGNED) LDFLD_UNALIGNED(f, double, TRUE); MINT_IN_BREAK;
4755 MINT_IN_CASE(MINT_LDFLD_VT) {
4756 o = sp [-1].data.o;
4757 NULL_CHECK (o);
4759 int size = READ32(ip + 2);
4760 sp [-1].data.p = vt_sp;
4761 memcpy (sp [-1].data.p, (char *)o + * (guint16 *)(ip + 1), size);
4762 vt_sp += ALIGN_TO (size, MINT_VT_ALIGNMENT);
4763 ip += 4;
4764 MINT_IN_BREAK;
4767 MINT_IN_CASE(MINT_LDRMFLD) {
4768 MonoClassField *field;
4769 char *addr;
4771 o = sp [-1].data.o;
4772 NULL_CHECK (o);
4773 field = (MonoClassField*)imethod->data_items[* (guint16 *)(ip + 1)];
4774 ip += 2;
4775 #ifndef DISABLE_REMOTING
4776 if (mono_object_is_transparent_proxy (o)) {
4777 gpointer tmp;
4778 MonoClass *klass = ((MonoTransparentProxy*)o)->remote_class->proxy_class;
4780 addr = (char*)mono_load_remote_field_checked (o, klass, field, &tmp, error);
4781 mono_error_cleanup (error); /* FIXME: don't swallow the error */
4782 } else
4783 #endif
4784 addr = (char*)o + field->offset;
4786 stackval_from_data (field->type, &sp [-1], addr, FALSE);
4787 MINT_IN_BREAK;
4790 MINT_IN_CASE(MINT_LDRMFLD_VT) {
4791 MonoClassField *field;
4792 char *addr;
4794 o = sp [-1].data.o;
4795 NULL_CHECK (o);
4797 field = (MonoClassField*)imethod->data_items[* (guint16 *)(ip + 1)];
4798 MonoClass *klass = mono_class_from_mono_type_internal (field->type);
4799 i32 = mono_class_value_size (klass, NULL);
4801 ip += 2;
4802 #ifndef DISABLE_REMOTING
4803 if (mono_object_is_transparent_proxy (o)) {
4804 gpointer tmp;
4805 MonoClass *klass = ((MonoTransparentProxy*)o)->remote_class->proxy_class;
4806 addr = (char*)mono_load_remote_field_checked (o, klass, field, &tmp, error);
4807 mono_error_cleanup (error); /* FIXME: don't swallow the error */
4808 } else
4809 #endif
4810 addr = (char*)o + field->offset;
4812 sp [-1].data.p = vt_sp;
4813 vt_sp += ALIGN_TO (i32, MINT_VT_ALIGNMENT);
4814 memcpy(sp [-1].data.p, addr, i32);
4815 MINT_IN_BREAK;
4818 #define STFLD_UNALIGNED(datamem, fieldtype, unaligned) \
4819 o = sp [-2].data.o; \
4820 NULL_CHECK (o); \
4821 sp -= 2; \
4822 if (unaligned) \
4823 memcpy ((char *)o + * (guint16 *)(ip + 1), &sp[1].data.datamem, sizeof (fieldtype)); \
4824 else \
4825 * (fieldtype *)((char *)o + * (guint16 *)(ip + 1)) = sp[1].data.datamem; \
4826 ip += 2;
4828 #define STFLD(datamem, fieldtype) STFLD_UNALIGNED(datamem, fieldtype, FALSE)
4830 MINT_IN_CASE(MINT_STFLD_I1) STFLD(i, gint8); MINT_IN_BREAK;
4831 MINT_IN_CASE(MINT_STFLD_U1) STFLD(i, guint8); MINT_IN_BREAK;
4832 MINT_IN_CASE(MINT_STFLD_I2) STFLD(i, gint16); MINT_IN_BREAK;
4833 MINT_IN_CASE(MINT_STFLD_U2) STFLD(i, guint16); MINT_IN_BREAK;
4834 MINT_IN_CASE(MINT_STFLD_I4) STFLD(i, gint32); MINT_IN_BREAK;
4835 MINT_IN_CASE(MINT_STFLD_I8) STFLD(l, gint64); MINT_IN_BREAK;
4836 MINT_IN_CASE(MINT_STFLD_R4) STFLD(f_r4, float); MINT_IN_BREAK;
4837 MINT_IN_CASE(MINT_STFLD_R8) STFLD(f, double); MINT_IN_BREAK;
4838 MINT_IN_CASE(MINT_STFLD_P) STFLD(p, gpointer); MINT_IN_BREAK;
4839 MINT_IN_CASE(MINT_STFLD_O)
4840 o = sp [-2].data.o;
4841 NULL_CHECK (o);
4842 sp -= 2;
4843 mono_gc_wbarrier_set_field_internal (o, (char *) o + * (guint16 *)(ip + 1), sp [1].data.o);
4844 ip += 2;
4845 MINT_IN_BREAK;
4846 MINT_IN_CASE(MINT_STFLD_I8_UNALIGNED) STFLD_UNALIGNED(l, gint64, TRUE); MINT_IN_BREAK;
4847 MINT_IN_CASE(MINT_STFLD_R8_UNALIGNED) STFLD_UNALIGNED(f, double, TRUE); MINT_IN_BREAK;
4849 MINT_IN_CASE(MINT_STFLD_VT) {
4850 o = sp [-2].data.o;
4851 NULL_CHECK (o);
4852 sp -= 2;
4854 MonoClass *klass = (MonoClass*)imethod->data_items[* (guint16 *)(ip + 2)];
4855 i32 = mono_class_value_size (klass, NULL);
4857 guint16 offset = * (guint16 *)(ip + 1);
4858 mono_value_copy_internal ((char *) o + offset, sp [1].data.p, klass);
4860 vt_sp -= ALIGN_TO (i32, MINT_VT_ALIGNMENT);
4861 ip += 3;
4862 MINT_IN_BREAK;
4864 MINT_IN_CASE(MINT_STRMFLD) {
4865 MonoClassField *field;
4867 o = sp [-2].data.o;
4868 NULL_CHECK (o);
4870 field = (MonoClassField*)imethod->data_items[* (guint16 *)(ip + 1)];
4871 ip += 2;
4873 #ifndef DISABLE_REMOTING
4874 if (mono_object_is_transparent_proxy (o)) {
4875 MonoClass *klass = ((MonoTransparentProxy*)o)->remote_class->proxy_class;
4876 mono_store_remote_field_checked (o, klass, field, &sp [-1].data, error);
4877 mono_error_cleanup (error); /* FIXME: don't swallow the error */
4878 } else
4879 #endif
4880 stackval_to_data (field->type, &sp [-1], (char*)o + field->offset, FALSE);
4882 sp -= 2;
4883 MINT_IN_BREAK;
4885 MINT_IN_CASE(MINT_STRMFLD_VT) {
4886 MonoClassField *field;
4888 o = sp [-2].data.o;
4889 NULL_CHECK (o);
4890 field = (MonoClassField*)imethod->data_items[* (guint16 *)(ip + 1)];
4891 MonoClass *klass = mono_class_from_mono_type_internal (field->type);
4892 i32 = mono_class_value_size (klass, NULL);
4893 ip += 2;
4895 #ifndef DISABLE_REMOTING
4896 if (mono_object_is_transparent_proxy (o)) {
4897 MonoClass *klass = ((MonoTransparentProxy*)o)->remote_class->proxy_class;
4898 mono_store_remote_field_checked (o, klass, field, sp [-1].data.p, error);
4899 mono_error_cleanup (error); /* FIXME: don't swallow the error */
4900 } else
4901 #endif
4902 mono_value_copy_internal ((char *) o + field->offset, sp [-1].data.p, klass);
4904 sp -= 2;
4905 vt_sp -= ALIGN_TO (i32, MINT_VT_ALIGNMENT);
4906 MINT_IN_BREAK;
4908 MINT_IN_CASE(MINT_LDSFLDA) {
4909 MonoVTable *vtable = (MonoVTable*) imethod->data_items [*(guint16*)(ip + 1)];
4910 INIT_VTABLE (vtable);
4911 sp->data.p = imethod->data_items [*(guint16*)(ip + 2)];
4912 ip += 3;
4913 ++sp;
4914 MINT_IN_BREAK;
4917 MINT_IN_CASE(MINT_LDSSFLDA) {
4918 guint32 offset = READ32(ip + 1);
4919 sp->data.p = mono_get_special_static_data (offset);
4920 ip += 3;
4921 ++sp;
4922 MINT_IN_BREAK;
4925 /* We init class here to preserve cctor order */
4926 #define LDSFLD(datamem, fieldtype) { \
4927 MonoVTable *vtable = (MonoVTable*) imethod->data_items [*(guint16*)(ip + 1)]; \
4928 INIT_VTABLE (vtable); \
4929 sp[0].data.datamem = * (fieldtype *)(imethod->data_items [* (guint16 *)(ip + 2)]) ; \
4930 ip += 3; \
4931 sp++; \
4934 MINT_IN_CASE(MINT_LDSFLD_I1) LDSFLD(i, gint8); MINT_IN_BREAK;
4935 MINT_IN_CASE(MINT_LDSFLD_U1) LDSFLD(i, guint8); MINT_IN_BREAK;
4936 MINT_IN_CASE(MINT_LDSFLD_I2) LDSFLD(i, gint16); MINT_IN_BREAK;
4937 MINT_IN_CASE(MINT_LDSFLD_U2) LDSFLD(i, guint16); MINT_IN_BREAK;
4938 MINT_IN_CASE(MINT_LDSFLD_I4) LDSFLD(i, gint32); MINT_IN_BREAK;
4939 MINT_IN_CASE(MINT_LDSFLD_I8) LDSFLD(l, gint64); MINT_IN_BREAK;
4940 MINT_IN_CASE(MINT_LDSFLD_R4) LDSFLD(f_r4, float); MINT_IN_BREAK;
4941 MINT_IN_CASE(MINT_LDSFLD_R8) LDSFLD(f, double); MINT_IN_BREAK;
4942 MINT_IN_CASE(MINT_LDSFLD_O) LDSFLD(p, gpointer); MINT_IN_BREAK;
4943 MINT_IN_CASE(MINT_LDSFLD_P) LDSFLD(p, gpointer); MINT_IN_BREAK;
4945 MINT_IN_CASE(MINT_LDSFLD_VT) {
4946 MonoVTable *vtable = (MonoVTable*) imethod->data_items [*(guint16*)(ip + 1)];
4947 gpointer addr = imethod->data_items [*(guint16*)(ip + 2)];
4948 i32 = READ32(ip + 3);
4949 INIT_VTABLE (vtable);
4950 sp->data.p = vt_sp;
4952 memcpy (vt_sp, addr, i32);
4953 vt_sp += ALIGN_TO (i32, MINT_VT_ALIGNMENT);
4954 ip += 5;
4955 ++sp;
4956 MINT_IN_BREAK;
4959 #define LDTSFLD(datamem, fieldtype) { \
4960 guint32 offset = READ32(ip + 1); \
4961 MonoInternalThread *thread = mono_thread_internal_current (); \
4962 gpointer addr = ((char*)thread->static_data [offset & 0x3f]) + (offset >> 6); \
4963 sp[0].data.datamem = *(fieldtype*)addr; \
4964 ip += 3; \
4965 ++sp; \
4967 MINT_IN_CASE(MINT_LDTSFLD_I1) LDTSFLD(i, gint8); MINT_IN_BREAK;
4968 MINT_IN_CASE(MINT_LDTSFLD_U1) LDTSFLD(i, guint8); MINT_IN_BREAK;
4969 MINT_IN_CASE(MINT_LDTSFLD_I2) LDTSFLD(i, gint16); MINT_IN_BREAK;
4970 MINT_IN_CASE(MINT_LDTSFLD_U2) LDTSFLD(i, guint16); MINT_IN_BREAK;
4971 MINT_IN_CASE(MINT_LDTSFLD_I4) LDTSFLD(i, gint32); MINT_IN_BREAK;
4972 MINT_IN_CASE(MINT_LDTSFLD_I8) LDTSFLD(l, gint64); MINT_IN_BREAK;
4973 MINT_IN_CASE(MINT_LDTSFLD_R4) LDTSFLD(f_r4, float); MINT_IN_BREAK;
4974 MINT_IN_CASE(MINT_LDTSFLD_R8) LDTSFLD(f, double); MINT_IN_BREAK;
4975 MINT_IN_CASE(MINT_LDTSFLD_O) LDTSFLD(p, gpointer); MINT_IN_BREAK;
4976 MINT_IN_CASE(MINT_LDTSFLD_P) LDTSFLD(p, gpointer); MINT_IN_BREAK;
4978 MINT_IN_CASE(MINT_LDSSFLD) {
4979 MonoClassField *field = (MonoClassField*)imethod->data_items [* (guint16 *)(ip + 1)];
4980 guint32 offset = READ32(ip + 2);
4981 gpointer addr = mono_get_special_static_data (offset);
4982 stackval_from_data (field->type, sp, addr, FALSE);
4983 ip += 4;
4984 ++sp;
4985 MINT_IN_BREAK;
4987 MINT_IN_CASE(MINT_LDSSFLD_VT) {
4988 guint32 offset = READ32(ip + 1);
4989 gpointer addr = mono_get_special_static_data (offset);
4991 int size = READ32 (ip + 3);
4992 memcpy (vt_sp, addr, size);
4993 sp->data.p = vt_sp;
4994 vt_sp += ALIGN_TO (size, MINT_VT_ALIGNMENT);
4995 ip += 5;
4996 ++sp;
4997 MINT_IN_BREAK;
4999 #define STSFLD(datamem, fieldtype) { \
5000 MonoVTable *vtable = (MonoVTable*) imethod->data_items [*(guint16*)(ip + 1)]; \
5001 INIT_VTABLE (vtable); \
5002 sp --; \
5003 * (fieldtype *)(imethod->data_items [* (guint16 *)(ip + 2)]) = sp[0].data.datamem; \
5004 ip += 3; \
5007 MINT_IN_CASE(MINT_STSFLD_I1) STSFLD(i, gint8); MINT_IN_BREAK;
5008 MINT_IN_CASE(MINT_STSFLD_U1) STSFLD(i, guint8); MINT_IN_BREAK;
5009 MINT_IN_CASE(MINT_STSFLD_I2) STSFLD(i, gint16); MINT_IN_BREAK;
5010 MINT_IN_CASE(MINT_STSFLD_U2) STSFLD(i, guint16); MINT_IN_BREAK;
5011 MINT_IN_CASE(MINT_STSFLD_I4) STSFLD(i, gint32); MINT_IN_BREAK;
5012 MINT_IN_CASE(MINT_STSFLD_I8) STSFLD(l, gint64); MINT_IN_BREAK;
5013 MINT_IN_CASE(MINT_STSFLD_R4) STSFLD(f_r4, float); MINT_IN_BREAK;
5014 MINT_IN_CASE(MINT_STSFLD_R8) STSFLD(f, double); MINT_IN_BREAK;
5015 MINT_IN_CASE(MINT_STSFLD_P) STSFLD(p, gpointer); MINT_IN_BREAK;
5016 MINT_IN_CASE(MINT_STSFLD_O) STSFLD(p, gpointer); MINT_IN_BREAK;
5018 MINT_IN_CASE(MINT_STSFLD_VT) {
5019 MonoVTable *vtable = (MonoVTable*) imethod->data_items [*(guint16*)(ip + 1)];
5020 gpointer addr = imethod->data_items [*(guint16*)(ip + 2)];
5021 i32 = READ32(ip + 3);
5022 INIT_VTABLE (vtable);
5024 memcpy (addr, sp [-1].data.vt, i32);
5025 vt_sp -= ALIGN_TO (i32, MINT_VT_ALIGNMENT);
5026 ip += 4;
5027 --sp;
5028 MINT_IN_BREAK;
5031 #define STTSFLD(datamem, fieldtype) { \
5032 guint32 offset = READ32(ip + 1); \
5033 MonoInternalThread *thread = mono_thread_internal_current (); \
5034 gpointer addr = ((char*)thread->static_data [offset & 0x3f]) + (offset >> 6); \
5035 sp--; \
5036 *(fieldtype*)addr = sp[0].data.datamem; \
5037 ip += 3; \
5040 MINT_IN_CASE(MINT_STTSFLD_I1) STTSFLD(i, gint8); MINT_IN_BREAK;
5041 MINT_IN_CASE(MINT_STTSFLD_U1) STTSFLD(i, guint8); MINT_IN_BREAK;
5042 MINT_IN_CASE(MINT_STTSFLD_I2) STTSFLD(i, gint16); MINT_IN_BREAK;
5043 MINT_IN_CASE(MINT_STTSFLD_U2) STTSFLD(i, guint16); MINT_IN_BREAK;
5044 MINT_IN_CASE(MINT_STTSFLD_I4) STTSFLD(i, gint32); MINT_IN_BREAK;
5045 MINT_IN_CASE(MINT_STTSFLD_I8) STTSFLD(l, gint64); MINT_IN_BREAK;
5046 MINT_IN_CASE(MINT_STTSFLD_R4) STTSFLD(f_r4, float); MINT_IN_BREAK;
5047 MINT_IN_CASE(MINT_STTSFLD_R8) STTSFLD(f, double); MINT_IN_BREAK;
5048 MINT_IN_CASE(MINT_STTSFLD_P) STTSFLD(p, gpointer); MINT_IN_BREAK;
5049 MINT_IN_CASE(MINT_STTSFLD_O) STTSFLD(p, gpointer); MINT_IN_BREAK;
5051 MINT_IN_CASE(MINT_STSSFLD) {
5052 MonoClassField *field = (MonoClassField*)imethod->data_items [* (guint16 *)(ip + 1)];
5053 guint32 offset = READ32(ip + 2);
5054 gpointer addr = mono_get_special_static_data (offset);
5055 --sp;
5056 stackval_to_data (field->type, sp, addr, FALSE);
5057 ip += 4;
5058 MINT_IN_BREAK;
5060 MINT_IN_CASE(MINT_STSSFLD_VT) {
5061 guint32 offset = READ32(ip + 1);
5062 gpointer addr = mono_get_special_static_data (offset);
5063 --sp;
5064 int size = READ32 (ip + 3);
5065 memcpy (addr, sp->data.vt, size);
5066 vt_sp -= ALIGN_TO (size, MINT_VT_ALIGNMENT);
5067 ip += 5;
5068 MINT_IN_BREAK;
5071 MINT_IN_CASE(MINT_STOBJ_VT) {
5072 int size;
5073 c = (MonoClass*)imethod->data_items[* (guint16 *)(ip + 1)];
5074 ip += 2;
5075 size = mono_class_value_size (c, NULL);
5076 mono_value_copy_internal (sp [-2].data.p, sp [-1].data.p, c);
5077 vt_sp -= ALIGN_TO (size, MINT_VT_ALIGNMENT);
5078 sp -= 2;
5079 MINT_IN_BREAK;
5081 MINT_IN_CASE(MINT_CONV_OVF_I4_UN_R8)
5082 if (sp [-1].data.f < 0 || sp [-1].data.f > G_MAXINT32)
5083 THROW_EX_OVF (ip);
5084 sp [-1].data.i = (gint32)sp [-1].data.f;
5085 ++ip;
5086 MINT_IN_BREAK;
5087 MINT_IN_CASE(MINT_CONV_OVF_U8_I4)
5088 if (sp [-1].data.i < 0)
5089 THROW_EX_OVF (ip);
5090 sp [-1].data.l = sp [-1].data.i;
5091 ++ip;
5092 MINT_IN_BREAK;
5093 MINT_IN_CASE(MINT_CONV_OVF_U8_I8)
5094 if (sp [-1].data.l < 0)
5095 THROW_EX_OVF (ip);
5096 ++ip;
5097 MINT_IN_BREAK;
5098 MINT_IN_CASE(MINT_CONV_OVF_I8_U8)
5099 if ((guint64) sp [-1].data.l > G_MAXINT64)
5100 THROW_EX_OVF (ip);
5101 ++ip;
5102 MINT_IN_BREAK;
5103 MINT_IN_CASE(MINT_CONV_OVF_U8_R4)
5104 if (sp [-1].data.f_r4 < 0 || sp [-1].data.f_r4 > G_MAXUINT64 || isnan (sp [-1].data.f_r4))
5105 THROW_EX_OVF (ip);
5106 sp [-1].data.l = (guint64)sp [-1].data.f_r4;
5107 ++ip;
5108 MINT_IN_BREAK;
5109 MINT_IN_CASE(MINT_CONV_OVF_U8_R8)
5110 if (sp [-1].data.f < 0 || sp [-1].data.f > G_MAXUINT64 || isnan (sp [-1].data.f))
5111 THROW_EX_OVF (ip);
5112 sp [-1].data.l = (guint64)sp [-1].data.f;
5113 ++ip;
5114 MINT_IN_BREAK;
5115 MINT_IN_CASE(MINT_CONV_OVF_I8_UN_R8)
5116 if (sp [-1].data.f < 0 || sp [-1].data.f > G_MAXINT64)
5117 THROW_EX_OVF (ip);
5118 sp [-1].data.l = (gint64)sp [-1].data.f;
5119 ++ip;
5120 MINT_IN_BREAK;
5121 MINT_IN_CASE(MINT_CONV_OVF_I8_UN_R4)
5122 if (sp [-1].data.f_r4 < 0 || sp [-1].data.f_r4 > G_MAXINT64)
5123 THROW_EX_OVF (ip);
5124 sp [-1].data.l = (gint64)sp [-1].data.f_r4;
5125 ++ip;
5126 MINT_IN_BREAK;
5127 MINT_IN_CASE(MINT_CONV_OVF_I8_R4)
5128 if (sp [-1].data.f_r4 < G_MININT64 || sp [-1].data.f_r4 > G_MAXINT64 || isnan (sp [-1].data.f_r4))
5129 THROW_EX_OVF (ip);
5130 sp [-1].data.l = (gint64)sp [-1].data.f_r4;
5131 ++ip;
5132 MINT_IN_BREAK;
5133 MINT_IN_CASE(MINT_CONV_OVF_I8_R8)
5134 if (sp [-1].data.f < G_MININT64 || sp [-1].data.f > G_MAXINT64 || isnan (sp [-1].data.f))
5135 THROW_EX_OVF (ip);
5136 sp [-1].data.l = (gint64)sp [-1].data.f;
5137 ++ip;
5138 MINT_IN_BREAK;
5139 MINT_IN_CASE(MINT_CONV_OVF_I4_UN_I8)
5140 if ((guint64)sp [-1].data.l > G_MAXINT32)
5141 THROW_EX_OVF (ip);
5142 sp [-1].data.i = (gint32)sp [-1].data.l;
5143 ++ip;
5144 MINT_IN_BREAK;
5145 MINT_IN_CASE(MINT_BOX) {
5146 MonoVTable *vtable = (MonoVTable*)imethod->data_items [* (guint16 *)(ip + 1)];
5147 guint16 offset = * (guint16 *)(ip + 2);
5149 frame_objref (frame) = mono_gc_alloc_obj (vtable, m_class_get_instance_size (vtable->klass));
5150 stackval_to_data (m_class_get_byval_arg (vtable->klass), &sp [-1 - offset], mono_object_get_data (frame_objref (frame)), FALSE);
5152 sp [-1 - offset].data.p = frame_objref (frame);
5154 ip += 3;
5155 MINT_IN_BREAK;
5157 MINT_IN_CASE(MINT_BOX_VT) {
5158 MonoVTable *vtable = (MonoVTable*)imethod->data_items [* (guint16 *)(ip + 1)];
5159 c = vtable->klass;
5160 guint16 offset = * (guint16 *)(ip + 2);
5161 gboolean pop_vt_sp = !(offset & BOX_NOT_CLEAR_VT_SP);
5162 offset &= ~BOX_NOT_CLEAR_VT_SP;
5164 int size = mono_class_value_size (c, NULL);
5165 frame_objref (frame) = mono_gc_alloc_obj (vtable, m_class_get_instance_size (vtable->klass));
5166 mono_value_copy_internal (mono_object_get_data (frame_objref (frame)), sp [-1 - offset].data.p, c);
5168 sp [-1 - offset].data.p = frame_objref (frame);
5169 size = ALIGN_TO (size, MINT_VT_ALIGNMENT);
5170 if (pop_vt_sp)
5171 vt_sp -= size;
5173 ip += 3;
5174 MINT_IN_BREAK;
5176 MINT_IN_CASE(MINT_BOX_NULLABLE) {
5177 c = (MonoClass*)imethod->data_items [* (guint16 *)(ip + 1)];
5178 guint16 offset = * (guint16 *)(ip + 2);
5179 gboolean pop_vt_sp = !(offset & BOX_NOT_CLEAR_VT_SP);
5180 offset &= ~BOX_NOT_CLEAR_VT_SP;
5182 int size = mono_class_value_size (c, NULL);
5184 sp [-1 - offset].data.o = mono_nullable_box (sp [-1 - offset].data.p, c, error);
5185 mono_error_cleanup (error); /* FIXME: don't swallow the error */
5187 size = ALIGN_TO (size, MINT_VT_ALIGNMENT);
5188 if (pop_vt_sp)
5189 vt_sp -= size;
5191 ip += 3;
5192 MINT_IN_BREAK;
5194 MINT_IN_CASE(MINT_NEWARR) {
5195 MonoVTable *vtable = (MonoVTable*)imethod->data_items[*(guint16 *)(ip + 1)];
5196 sp [-1].data.o = (MonoObject*) mono_array_new_specific_checked (vtable, sp [-1].data.i, error);
5197 if (!mono_error_ok (error)) {
5198 THROW_EX (mono_error_convert_to_exception (error), ip);
5200 mono_error_cleanup (error); /* FIXME: don't swallow the error */
5201 ip += 2;
5202 /*if (profiling_classes) {
5203 guint count = GPOINTER_TO_UINT (g_hash_table_lookup (profiling_classes, o->vtable->klass));
5204 count++;
5205 g_hash_table_insert (profiling_classes, o->vtable->klass, GUINT_TO_POINTER (count));
5208 MINT_IN_BREAK;
5210 MINT_IN_CASE(MINT_LDLEN)
5211 o = sp [-1].data.o;
5212 NULL_CHECK (o);
5213 sp [-1].data.nati = mono_array_length_internal ((MonoArray *)o);
5214 ++ip;
5215 MINT_IN_BREAK;
5216 MINT_IN_CASE(MINT_LDLEN_SPAN) {
5217 o = sp [-1].data.o;
5218 NULL_CHECK (o);
5219 gsize offset_length = (gsize) *(gint16 *) (ip + 1);
5220 sp [-1].data.nati = *(gint32 *) ((guint8 *) o + offset_length);
5221 ip += 2;
5222 MINT_IN_BREAK;
5224 MINT_IN_CASE(MINT_GETCHR) {
5225 MonoString *s;
5226 s = (MonoString*)sp [-2].data.p;
5227 NULL_CHECK (s);
5228 i32 = sp [-1].data.i;
5229 if (i32 < 0 || i32 >= mono_string_length_internal (s))
5230 THROW_EX (mono_get_exception_index_out_of_range (), ip);
5231 --sp;
5232 sp [-1].data.i = mono_string_chars_internal (s)[i32];
5233 ++ip;
5234 MINT_IN_BREAK;
5236 MINT_IN_CASE(MINT_GETITEM_SPAN) {
5237 guint8 *span = (guint8 *) sp [-2].data.p;
5238 int index = sp [-1].data.i;
5239 gsize element_size = (gsize) *(gint16 *) (ip + 1);
5240 gsize offset_length = (gsize) *(gint16 *) (ip + 2);
5241 gsize offset_pointer = (gsize) *(gint16 *) (ip + 3);
5242 sp--;
5244 NULL_CHECK (span);
5246 gint32 length = *(gint32 *) (span + offset_length);
5247 if (index < 0 || index >= length)
5248 THROW_EX (mono_get_exception_index_out_of_range (), ip);
5250 gpointer pointer = *(gpointer *)(span + offset_pointer);
5251 sp [-1].data.p = (guint8 *) pointer + index * element_size;
5253 ip += 4;
5254 MINT_IN_BREAK;
5256 MINT_IN_CASE(MINT_STRLEN)
5257 ++ip;
5258 o = sp [-1].data.o;
5259 NULL_CHECK (o);
5260 sp [-1].data.i = mono_string_length_internal ((MonoString*) o);
5261 MINT_IN_BREAK;
5262 MINT_IN_CASE(MINT_ARRAY_RANK)
5263 o = sp [-1].data.o;
5264 NULL_CHECK (o);
5265 sp [-1].data.i = m_class_get_rank (mono_object_class (sp [-1].data.p));
5266 ip++;
5267 MINT_IN_BREAK;
5268 MINT_IN_CASE(MINT_LDELEMA_FAST) {
5269 /* No bounds, one direction */
5270 gint32 size = READ32 (ip + 1);
5271 gint32 index = sp [-1].data.i;
5273 MonoArray *ao = (MonoArray*)sp [-2].data.o;
5274 NULL_CHECK (ao);
5275 if (index >= ao->max_length)
5276 THROW_EX (mono_get_exception_index_out_of_range (), ip);
5277 sp [-2].data.p = mono_array_addr_with_size_fast (ao, size, index);
5278 ip += 3;
5279 sp --;
5281 MINT_IN_BREAK;
5283 MINT_IN_CASE(MINT_LDELEMA)
5284 MINT_IN_CASE(MINT_LDELEMA_TC) {
5285 gboolean needs_typecheck = *ip == MINT_LDELEMA_TC;
5287 MonoClass *klass = (MonoClass*)imethod->data_items [*(guint16 *) (ip + 1)];
5288 guint16 numargs = *(guint16 *) (ip + 2);
5289 ip += 3;
5290 sp -= numargs;
5292 o = sp [0].data.o;
5293 NULL_CHECK (o);
5294 sp->data.p = ves_array_element_address (frame, klass, (MonoArray *) o, &sp [1], needs_typecheck);
5295 if (frame->ex)
5296 THROW_EX (frame->ex, ip);
5297 ++sp;
5299 MINT_IN_BREAK;
5301 MINT_IN_CASE(MINT_LDELEM_I1) /* fall through */
5302 MINT_IN_CASE(MINT_LDELEM_U1) /* fall through */
5303 MINT_IN_CASE(MINT_LDELEM_I2) /* fall through */
5304 MINT_IN_CASE(MINT_LDELEM_U2) /* fall through */
5305 MINT_IN_CASE(MINT_LDELEM_I4) /* fall through */
5306 MINT_IN_CASE(MINT_LDELEM_U4) /* fall through */
5307 MINT_IN_CASE(MINT_LDELEM_I8) /* fall through */
5308 MINT_IN_CASE(MINT_LDELEM_I) /* fall through */
5309 MINT_IN_CASE(MINT_LDELEM_R4) /* fall through */
5310 MINT_IN_CASE(MINT_LDELEM_R8) /* fall through */
5311 MINT_IN_CASE(MINT_LDELEM_REF) /* fall through */
5312 MINT_IN_CASE(MINT_LDELEM_VT) {
5313 MonoArray *o;
5314 mono_u aindex;
5316 sp -= 2;
5318 o = (MonoArray*)sp [0].data.p;
5319 NULL_CHECK (o);
5321 aindex = sp [1].data.i;
5322 if (aindex >= mono_array_length_internal (o))
5323 THROW_EX (mono_get_exception_index_out_of_range (), ip);
5326 * FIXME: throw mono_get_exception_array_type_mismatch () if needed
5328 switch (*ip) {
5329 case MINT_LDELEM_I1:
5330 sp [0].data.i = mono_array_get_fast (o, gint8, aindex);
5331 break;
5332 case MINT_LDELEM_U1:
5333 sp [0].data.i = mono_array_get_fast (o, guint8, aindex);
5334 break;
5335 case MINT_LDELEM_I2:
5336 sp [0].data.i = mono_array_get_fast (o, gint16, aindex);
5337 break;
5338 case MINT_LDELEM_U2:
5339 sp [0].data.i = mono_array_get_fast (o, guint16, aindex);
5340 break;
5341 case MINT_LDELEM_I:
5342 sp [0].data.nati = mono_array_get_fast (o, mono_i, aindex);
5343 break;
5344 case MINT_LDELEM_I4:
5345 sp [0].data.i = mono_array_get_fast (o, gint32, aindex);
5346 break;
5347 case MINT_LDELEM_U4:
5348 sp [0].data.i = mono_array_get_fast (o, guint32, aindex);
5349 break;
5350 case MINT_LDELEM_I8:
5351 sp [0].data.l = mono_array_get_fast (o, guint64, aindex);
5352 break;
5353 case MINT_LDELEM_R4:
5354 sp [0].data.f_r4 = mono_array_get_fast (o, float, aindex);
5355 break;
5356 case MINT_LDELEM_R8:
5357 sp [0].data.f = mono_array_get_fast (o, double, aindex);
5358 break;
5359 case MINT_LDELEM_REF:
5360 sp [0].data.p = mono_array_get_fast (o, gpointer, aindex);
5361 break;
5362 case MINT_LDELEM_VT: {
5363 i32 = READ32 (ip + 1);
5364 char *src_addr = mono_array_addr_with_size_fast ((MonoArray *) o, i32, aindex);
5365 sp [0].data.vt = vt_sp;
5366 // Copying to vtstack. No wbarrier needed
5367 memcpy (sp [0].data.vt, src_addr, i32);
5368 vt_sp += ALIGN_TO (i32, MINT_VT_ALIGNMENT);
5369 ip += 2;
5370 break;
5372 default:
5373 ves_abort();
5376 ++ip;
5377 ++sp;
5378 MINT_IN_BREAK;
5380 MINT_IN_CASE(MINT_STELEM_I) /* fall through */
5381 MINT_IN_CASE(MINT_STELEM_I1) /* fall through */
5382 MINT_IN_CASE(MINT_STELEM_U1) /* fall through */
5383 MINT_IN_CASE(MINT_STELEM_I2) /* fall through */
5384 MINT_IN_CASE(MINT_STELEM_U2) /* fall through */
5385 MINT_IN_CASE(MINT_STELEM_I4) /* fall through */
5386 MINT_IN_CASE(MINT_STELEM_I8) /* fall through */
5387 MINT_IN_CASE(MINT_STELEM_R4) /* fall through */
5388 MINT_IN_CASE(MINT_STELEM_R8) /* fall through */
5389 MINT_IN_CASE(MINT_STELEM_REF) /* fall through */
5390 MINT_IN_CASE(MINT_STELEM_VT) {
5391 mono_u aindex;
5393 sp -= 3;
5395 o = sp [0].data.o;
5396 NULL_CHECK (o);
5398 aindex = sp [1].data.i;
5399 if (aindex >= mono_array_length_internal ((MonoArray *)o))
5400 THROW_EX (mono_get_exception_index_out_of_range (), ip);
5402 switch (*ip) {
5403 case MINT_STELEM_I:
5404 mono_array_set_fast ((MonoArray *)o, mono_i, aindex, sp [2].data.nati);
5405 break;
5406 case MINT_STELEM_I1:
5407 mono_array_set_fast ((MonoArray *)o, gint8, aindex, sp [2].data.i);
5408 break;
5409 case MINT_STELEM_U1:
5410 mono_array_set_fast ((MonoArray *) o, guint8, aindex, sp [2].data.i);
5411 break;
5412 case MINT_STELEM_I2:
5413 mono_array_set_fast ((MonoArray *)o, gint16, aindex, sp [2].data.i);
5414 break;
5415 case MINT_STELEM_U2:
5416 mono_array_set_fast ((MonoArray *)o, guint16, aindex, sp [2].data.i);
5417 break;
5418 case MINT_STELEM_I4:
5419 mono_array_set_fast ((MonoArray *)o, gint32, aindex, sp [2].data.i);
5420 break;
5421 case MINT_STELEM_I8:
5422 mono_array_set_fast ((MonoArray *)o, gint64, aindex, sp [2].data.l);
5423 break;
5424 case MINT_STELEM_R4:
5425 mono_array_set_fast ((MonoArray *)o, float, aindex, sp [2].data.f_r4);
5426 break;
5427 case MINT_STELEM_R8:
5428 mono_array_set_fast ((MonoArray *)o, double, aindex, sp [2].data.f);
5429 break;
5430 case MINT_STELEM_REF: {
5431 MonoObject *isinst_obj = mono_object_isinst_checked (sp [2].data.o, m_class_get_element_class (mono_object_class (o)), error);
5432 mono_error_cleanup (error); /* FIXME: don't swallow the error */
5433 if (sp [2].data.p && !isinst_obj)
5434 THROW_EX (mono_get_exception_array_type_mismatch (), ip);
5435 mono_array_setref_fast ((MonoArray *) o, aindex, sp [2].data.p);
5436 break;
5438 case MINT_STELEM_VT: {
5439 MonoClass *klass_vt = (MonoClass*)imethod->data_items [*(guint16 *) (ip + 1)];
5440 i32 = READ32 (ip + 2);
5441 char *dst_addr = mono_array_addr_with_size_fast ((MonoArray *) o, i32, aindex);
5443 mono_value_copy_internal (dst_addr, sp [2].data.vt, klass_vt);
5444 vt_sp -= ALIGN_TO (i32, MINT_VT_ALIGNMENT);
5445 ip += 3;
5446 break;
5448 default:
5449 ves_abort();
5452 ++ip;
5453 MINT_IN_BREAK;
5455 MINT_IN_CASE(MINT_CONV_OVF_I4_U4)
5456 if (sp [-1].data.i < 0)
5457 THROW_EX_OVF (ip);
5458 ++ip;
5459 MINT_IN_BREAK;
5460 MINT_IN_CASE(MINT_CONV_OVF_I4_I8)
5461 if (sp [-1].data.l < G_MININT32 || sp [-1].data.l > G_MAXINT32)
5462 THROW_EX_OVF (ip);
5463 sp [-1].data.i = (gint32) sp [-1].data.l;
5464 ++ip;
5465 MINT_IN_BREAK;
5466 MINT_IN_CASE(MINT_CONV_OVF_I4_U8)
5467 if (sp [-1].data.l < 0 || sp [-1].data.l > G_MAXINT32)
5468 THROW_EX_OVF (ip);
5469 sp [-1].data.i = (gint32) sp [-1].data.l;
5470 ++ip;
5471 MINT_IN_BREAK;
5472 MINT_IN_CASE(MINT_CONV_OVF_I4_R4)
5473 if (sp [-1].data.f_r4 < G_MININT32 || sp [-1].data.f_r4 > G_MAXINT32)
5474 THROW_EX_OVF (ip);
5475 sp [-1].data.i = (gint32) sp [-1].data.f_r4;
5476 ++ip;
5477 MINT_IN_BREAK;
5478 MINT_IN_CASE(MINT_CONV_OVF_I4_R8)
5479 if (sp [-1].data.f < G_MININT32 || sp [-1].data.f > G_MAXINT32)
5480 THROW_EX_OVF (ip);
5481 sp [-1].data.i = (gint32) sp [-1].data.f;
5482 ++ip;
5483 MINT_IN_BREAK;
5484 MINT_IN_CASE(MINT_CONV_OVF_U4_I4)
5485 if (sp [-1].data.i < 0)
5486 THROW_EX_OVF (ip);
5487 ++ip;
5488 MINT_IN_BREAK;
5489 MINT_IN_CASE(MINT_CONV_OVF_U4_I8)
5490 if (sp [-1].data.l < 0 || sp [-1].data.l > G_MAXUINT32)
5491 THROW_EX_OVF (ip);
5492 sp [-1].data.i = (guint32) sp [-1].data.l;
5493 ++ip;
5494 MINT_IN_BREAK;
5495 MINT_IN_CASE(MINT_CONV_OVF_U4_R4)
5496 if (sp [-1].data.f_r4 < 0 || sp [-1].data.f_r4 > G_MAXUINT32)
5497 THROW_EX_OVF (ip);
5498 sp [-1].data.i = (guint32) sp [-1].data.f_r4;
5499 ++ip;
5500 MINT_IN_BREAK;
5501 MINT_IN_CASE(MINT_CONV_OVF_U4_R8)
5502 if (sp [-1].data.f < 0 || sp [-1].data.f > G_MAXUINT32)
5503 THROW_EX_OVF (ip);
5504 sp [-1].data.i = (guint32) sp [-1].data.f;
5505 ++ip;
5506 MINT_IN_BREAK;
5507 MINT_IN_CASE(MINT_CONV_OVF_I2_I4)
5508 if (sp [-1].data.i < G_MININT16 || sp [-1].data.i > G_MAXINT16)
5509 THROW_EX_OVF (ip);
5510 ++ip;
5511 MINT_IN_BREAK;
5512 MINT_IN_CASE(MINT_CONV_OVF_I2_U4)
5513 if (sp [-1].data.i < 0 || sp [-1].data.i > G_MAXINT16)
5514 THROW_EX_OVF (ip);
5515 ++ip;
5516 MINT_IN_BREAK;
5517 MINT_IN_CASE(MINT_CONV_OVF_I2_I8)
5518 if (sp [-1].data.l < G_MININT16 || sp [-1].data.l > G_MAXINT16)
5519 THROW_EX_OVF (ip);
5520 sp [-1].data.i = (gint16) sp [-1].data.l;
5521 ++ip;
5522 MINT_IN_BREAK;
5523 MINT_IN_CASE(MINT_CONV_OVF_I2_U8)
5524 if (sp [-1].data.l < 0 || sp [-1].data.l > G_MAXINT16)
5525 THROW_EX_OVF (ip);
5526 sp [-1].data.i = (gint16) sp [-1].data.l;
5527 ++ip;
5528 MINT_IN_BREAK;
5529 MINT_IN_CASE(MINT_CONV_OVF_I2_R8)
5530 if (sp [-1].data.f < G_MININT16 || sp [-1].data.f > G_MAXINT16)
5531 THROW_EX_OVF (ip);
5532 sp [-1].data.i = (gint16) sp [-1].data.f;
5533 ++ip;
5534 MINT_IN_BREAK;
5535 MINT_IN_CASE(MINT_CONV_OVF_I2_UN_R8)
5536 if (sp [-1].data.f < 0 || sp [-1].data.f > G_MAXINT16)
5537 THROW_EX_OVF (ip);
5538 sp [-1].data.i = (gint16) sp [-1].data.f;
5539 ++ip;
5540 MINT_IN_BREAK;
5541 MINT_IN_CASE(MINT_CONV_OVF_U2_I4)
5542 if (sp [-1].data.i < 0 || sp [-1].data.i > G_MAXUINT16)
5543 THROW_EX_OVF (ip);
5544 ++ip;
5545 MINT_IN_BREAK;
5546 MINT_IN_CASE(MINT_CONV_OVF_U2_I8)
5547 if (sp [-1].data.l < 0 || sp [-1].data.l > G_MAXUINT16)
5548 THROW_EX_OVF (ip);
5549 sp [-1].data.i = (guint16) sp [-1].data.l;
5550 ++ip;
5551 MINT_IN_BREAK;
5552 MINT_IN_CASE(MINT_CONV_OVF_U2_R8)
5553 if (sp [-1].data.f < 0 || sp [-1].data.f > G_MAXUINT16)
5554 THROW_EX_OVF (ip);
5555 sp [-1].data.i = (guint16) sp [-1].data.f;
5556 ++ip;
5557 MINT_IN_BREAK;
5558 MINT_IN_CASE(MINT_CONV_OVF_I1_I4)
5559 if (sp [-1].data.i < G_MININT8 || sp [-1].data.i > G_MAXINT8)
5560 THROW_EX_OVF (ip);
5561 ++ip;
5562 MINT_IN_BREAK;
5563 MINT_IN_CASE(MINT_CONV_OVF_I1_U4)
5564 if (sp [-1].data.i < 0 || sp [-1].data.i > G_MAXINT8)
5565 THROW_EX_OVF (ip);
5566 ++ip;
5567 MINT_IN_BREAK;
5568 MINT_IN_CASE(MINT_CONV_OVF_I1_I8)
5569 if (sp [-1].data.l < G_MININT8 || sp [-1].data.l > G_MAXINT8)
5570 THROW_EX_OVF (ip);
5571 sp [-1].data.i = (gint8) sp [-1].data.l;
5572 ++ip;
5573 MINT_IN_BREAK;
5574 MINT_IN_CASE(MINT_CONV_OVF_I1_U8)
5575 if (sp [-1].data.l < 0 || sp [-1].data.l > G_MAXINT8)
5576 THROW_EX_OVF (ip);
5577 sp [-1].data.i = (gint8) sp [-1].data.l;
5578 ++ip;
5579 MINT_IN_BREAK;
5580 MINT_IN_CASE(MINT_CONV_OVF_I1_R8)
5581 if (sp [-1].data.f < G_MININT8 || sp [-1].data.f > G_MAXINT8)
5582 THROW_EX_OVF (ip);
5583 sp [-1].data.i = (gint8) sp [-1].data.f;
5584 ++ip;
5585 MINT_IN_BREAK;
5586 MINT_IN_CASE(MINT_CONV_OVF_I1_UN_R8)
5587 if (sp [-1].data.f < 0 || sp [-1].data.f > G_MAXINT8)
5588 THROW_EX_OVF (ip);
5589 sp [-1].data.i = (gint8) sp [-1].data.f;
5590 ++ip;
5591 MINT_IN_BREAK;
5592 MINT_IN_CASE(MINT_CONV_OVF_U1_I4)
5593 if (sp [-1].data.i < 0 || sp [-1].data.i > G_MAXUINT8)
5594 THROW_EX_OVF (ip);
5595 ++ip;
5596 MINT_IN_BREAK;
5597 MINT_IN_CASE(MINT_CONV_OVF_U1_I8)
5598 if (sp [-1].data.l < 0 || sp [-1].data.l > G_MAXUINT8)
5599 THROW_EX_OVF (ip);
5600 sp [-1].data.i = (guint8) sp [-1].data.l;
5601 ++ip;
5602 MINT_IN_BREAK;
5603 MINT_IN_CASE(MINT_CONV_OVF_U1_R8)
5604 if (sp [-1].data.f < 0 || sp [-1].data.f > G_MAXUINT8)
5605 THROW_EX_OVF (ip);
5606 sp [-1].data.i = (guint8) sp [-1].data.f;
5607 ++ip;
5608 MINT_IN_BREAK;
5609 MINT_IN_CASE(MINT_CKFINITE)
5610 if (!mono_isfinite (sp [-1].data.f))
5611 THROW_EX (mono_get_exception_arithmetic (), ip);
5612 ++ip;
5613 MINT_IN_BREAK;
5614 MINT_IN_CASE(MINT_MKREFANY) {
5615 c = (MonoClass*)imethod->data_items [*(guint16 *)(ip + 1)];
5617 /* The value address is on the stack */
5618 gpointer addr = sp [-1].data.p;
5619 /* Push the typedref value on the stack */
5620 sp [-1].data.p = vt_sp;
5621 vt_sp += ALIGN_TO (sizeof (MonoTypedRef), MINT_VT_ALIGNMENT);
5623 MonoTypedRef *tref = (MonoTypedRef*)sp [-1].data.p;
5624 tref->klass = c;
5625 tref->type = m_class_get_byval_arg (c);
5626 tref->value = addr;
5628 ip += 2;
5629 MINT_IN_BREAK;
5631 MINT_IN_CASE(MINT_REFANYTYPE) {
5632 MonoTypedRef *tref = (MonoTypedRef*)sp [-1].data.p;
5633 MonoType *type = tref->type;
5635 vt_sp -= ALIGN_TO (sizeof (MonoTypedRef), MINT_VT_ALIGNMENT);
5636 sp [-1].data.p = vt_sp;
5637 vt_sp += 8;
5638 *(gpointer*)sp [-1].data.p = type;
5639 ip ++;
5640 MINT_IN_BREAK;
5642 MINT_IN_CASE(MINT_REFANYVAL) {
5643 MonoTypedRef *tref = (MonoTypedRef*)sp [-1].data.p;
5644 gpointer addr = tref->value;
5646 c = (MonoClass*)imethod->data_items [*(guint16 *)(ip + 1)];
5647 if (c != tref->klass)
5648 THROW_EX (mono_get_exception_invalid_cast (), ip);
5650 vt_sp -= ALIGN_TO (sizeof (MonoTypedRef), MINT_VT_ALIGNMENT);
5652 sp [-1].data.p = addr;
5653 ip += 2;
5654 MINT_IN_BREAK;
5656 MINT_IN_CASE(MINT_LDTOKEN)
5657 sp->data.p = vt_sp;
5658 vt_sp += 8;
5659 * (gpointer *)sp->data.p = imethod->data_items[*(guint16 *)(ip + 1)];
5660 ip += 2;
5661 ++sp;
5662 MINT_IN_BREAK;
5663 MINT_IN_CASE(MINT_ADD_OVF_I4)
5664 if (CHECK_ADD_OVERFLOW (sp [-2].data.i, sp [-1].data.i))
5665 THROW_EX_OVF (ip);
5666 BINOP(i, +);
5667 MINT_IN_BREAK;
5668 MINT_IN_CASE(MINT_ADD_OVF_I8)
5669 if (CHECK_ADD_OVERFLOW64 (sp [-2].data.l, sp [-1].data.l))
5670 THROW_EX_OVF (ip);
5671 BINOP(l, +);
5672 MINT_IN_BREAK;
5673 MINT_IN_CASE(MINT_ADD_OVF_UN_I4)
5674 if (CHECK_ADD_OVERFLOW_UN (sp [-2].data.i, sp [-1].data.i))
5675 THROW_EX_OVF (ip);
5676 BINOP_CAST(i, +, guint32);
5677 MINT_IN_BREAK;
5678 MINT_IN_CASE(MINT_ADD_OVF_UN_I8)
5679 if (CHECK_ADD_OVERFLOW64_UN (sp [-2].data.l, sp [-1].data.l))
5680 THROW_EX_OVF (ip);
5681 BINOP_CAST(l, +, guint64);
5682 MINT_IN_BREAK;
5683 MINT_IN_CASE(MINT_MUL_OVF_I4)
5684 if (CHECK_MUL_OVERFLOW (sp [-2].data.i, sp [-1].data.i))
5685 THROW_EX_OVF (ip);
5686 BINOP(i, *);
5687 MINT_IN_BREAK;
5688 MINT_IN_CASE(MINT_MUL_OVF_I8)
5689 if (CHECK_MUL_OVERFLOW64 (sp [-2].data.l, sp [-1].data.l))
5690 THROW_EX_OVF (ip);
5691 BINOP(l, *);
5692 MINT_IN_BREAK;
5693 MINT_IN_CASE(MINT_MUL_OVF_UN_I4)
5694 if (CHECK_MUL_OVERFLOW_UN (sp [-2].data.i, sp [-1].data.i))
5695 THROW_EX_OVF (ip);
5696 BINOP_CAST(i, *, guint32);
5697 MINT_IN_BREAK;
5698 MINT_IN_CASE(MINT_MUL_OVF_UN_I8)
5699 if (CHECK_MUL_OVERFLOW64_UN (sp [-2].data.l, sp [-1].data.l))
5700 THROW_EX_OVF (ip);
5701 BINOP_CAST(l, *, guint64);
5702 MINT_IN_BREAK;
5703 MINT_IN_CASE(MINT_SUB_OVF_I4)
5704 if (CHECK_SUB_OVERFLOW (sp [-2].data.i, sp [-1].data.i))
5705 THROW_EX_OVF (ip);
5706 BINOP(i, -);
5707 MINT_IN_BREAK;
5708 MINT_IN_CASE(MINT_SUB_OVF_I8)
5709 if (CHECK_SUB_OVERFLOW64 (sp [-2].data.l, sp [-1].data.l))
5710 THROW_EX_OVF (ip);
5711 BINOP(l, -);
5712 MINT_IN_BREAK;
5713 MINT_IN_CASE(MINT_SUB_OVF_UN_I4)
5714 if (CHECK_SUB_OVERFLOW_UN (sp [-2].data.i, sp [-1].data.i))
5715 THROW_EX_OVF (ip);
5716 BINOP_CAST(i, -, guint32);
5717 MINT_IN_BREAK;
5718 MINT_IN_CASE(MINT_SUB_OVF_UN_I8)
5719 if (CHECK_SUB_OVERFLOW64_UN (sp [-2].data.l, sp [-1].data.l))
5720 THROW_EX_OVF (ip);
5721 BINOP_CAST(l, -, guint64);
5722 MINT_IN_BREAK;
5723 MINT_IN_CASE(MINT_START_ABORT_PROT)
5724 mono_threads_begin_abort_protected_block ();
5725 ip ++;
5726 MINT_IN_BREAK;
5727 MINT_IN_CASE(MINT_ENDFINALLY) {
5728 ip ++;
5729 int clause_index = *ip;
5730 gboolean pending_abort = mono_threads_end_abort_protected_block ();
5732 if (clause_args && clause_index == clause_args->exit_clause)
5733 goto exit_frame;
5734 while (sp > frame->stack) {
5735 --sp;
5737 if (frame->finally_ips) {
5738 ip = (const guint16*)frame->finally_ips->data;
5739 frame->finally_ips = g_slist_remove (frame->finally_ips, ip);
5740 /* Throw abort after the last finally block to avoid confusing EH */
5741 if (pending_abort && !frame->finally_ips)
5742 EXCEPTION_CHECKPOINT;
5743 MINT_IN_DISPATCH(*ip);
5745 ves_abort();
5746 MINT_IN_BREAK;
5749 MINT_IN_CASE(MINT_LEAVE)
5750 MINT_IN_CASE(MINT_LEAVE_S)
5751 MINT_IN_CASE(MINT_LEAVE_CHECK)
5752 MINT_IN_CASE(MINT_LEAVE_S_CHECK) {
5753 while (sp > frame->stack) {
5754 --sp;
5756 frame->ip = ip;
5758 if (*ip == MINT_LEAVE_S_CHECK || *ip == MINT_LEAVE_CHECK) {
5759 if (imethod->method->wrapper_type != MONO_WRAPPER_RUNTIME_INVOKE) {
5760 stackval tmp_sp;
5762 child_frame.parent = frame;
5763 child_frame.imethod = NULL;
5765 * We need for mono_thread_get_undeniable_exception to be able to unwind
5766 * to check the abort threshold. For this to work we use child_frame as a
5767 * dummy frame that is stored in the lmf and serves as the transition frame
5769 do_icall_wrapper (&child_frame, NULL, MINT_ICALL_V_P, &tmp_sp, (gpointer)mono_thread_get_undeniable_exception, FALSE);
5771 MonoException *abort_exc = (MonoException*)tmp_sp.data.p;
5772 if (abort_exc)
5773 THROW_EX (abort_exc, frame->ip);
5777 if (*ip == MINT_LEAVE_S || *ip == MINT_LEAVE_S_CHECK) {
5778 ip += (short) *(ip + 1);
5779 } else {
5780 ip += (gint32) READ32 (ip + 1);
5782 frame->endfinally_ip = ip;
5784 guint32 ip_offset;
5785 MonoExceptionClause *clause;
5786 GSList *old_list = frame->finally_ips;
5787 MonoMethod *method = imethod->method;
5789 #if DEBUG_INTERP
5790 if (tracing)
5791 g_print ("* Handle finally IL_%04x\n", frame->endfinally_ip == NULL ? 0 : frame->endfinally_ip - imethod->code);
5792 #endif
5793 if (imethod == NULL || (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
5794 || (method->iflags & (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL | METHOD_IMPL_ATTRIBUTE_RUNTIME))) {
5795 goto exit_frame;
5797 ip_offset = frame->ip - imethod->code;
5799 if (frame->endfinally_ip != NULL)
5800 frame->finally_ips = g_slist_prepend(frame->finally_ips, (void *)frame->endfinally_ip);
5802 for (int i = imethod->num_clauses - 1; i >= 0; i--) {
5803 clause = &imethod->clauses [i];
5804 if (MONO_OFFSET_IN_CLAUSE (clause, ip_offset) && (frame->endfinally_ip == NULL || !(MONO_OFFSET_IN_CLAUSE (clause, frame->endfinally_ip - imethod->code)))) {
5805 if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY) {
5806 ip = imethod->code + clause->handler_offset;
5807 frame->finally_ips = g_slist_prepend (frame->finally_ips, (gpointer) ip);
5808 #if DEBUG_INTERP
5809 if (tracing)
5810 g_print ("* Found finally at IL_%04x with exception: %s\n", clause->handler_offset, frame->ex? "yes": "no");
5811 #endif
5816 frame->endfinally_ip = NULL;
5818 if (old_list != frame->finally_ips && frame->finally_ips) {
5819 ip = (const guint16*)frame->finally_ips->data;
5820 frame->finally_ips = g_slist_remove (frame->finally_ips, ip);
5821 sp = frame->stack; /* spec says stack should be empty at endfinally so it should be at the start too */
5822 vt_sp = (unsigned char *) sp + imethod->stack_size;
5823 MINT_IN_DISPATCH (*ip);
5826 ves_abort();
5827 MINT_IN_BREAK;
5829 MINT_IN_CASE(MINT_ICALL_V_V)
5830 MINT_IN_CASE(MINT_ICALL_V_P)
5831 MINT_IN_CASE(MINT_ICALL_P_V)
5832 MINT_IN_CASE(MINT_ICALL_P_P)
5833 MINT_IN_CASE(MINT_ICALL_PP_V)
5834 MINT_IN_CASE(MINT_ICALL_PP_P)
5835 MINT_IN_CASE(MINT_ICALL_PPP_V)
5836 MINT_IN_CASE(MINT_ICALL_PPP_P)
5837 MINT_IN_CASE(MINT_ICALL_PPPP_V)
5838 MINT_IN_CASE(MINT_ICALL_PPPP_P)
5839 MINT_IN_CASE(MINT_ICALL_PPPPP_V)
5840 MINT_IN_CASE(MINT_ICALL_PPPPP_P)
5841 MINT_IN_CASE(MINT_ICALL_PPPPPP_V)
5842 MINT_IN_CASE(MINT_ICALL_PPPPPP_P)
5843 frame->ip = ip;
5844 sp = do_icall_wrapper (frame, NULL, *ip, sp, imethod->data_items [*(guint16 *)(ip + 1)], FALSE);
5845 EXCEPTION_CHECKPOINT;
5846 CHECK_RESUME_STATE (context);
5847 ip += 2;
5848 MINT_IN_BREAK;
5849 MINT_IN_CASE(MINT_MONO_LDPTR)
5850 sp->data.p = imethod->data_items [*(guint16 *)(ip + 1)];
5851 ip += 2;
5852 ++sp;
5853 MINT_IN_BREAK;
5854 MINT_IN_CASE(MINT_MONO_NEWOBJ)
5855 sp->data.p = mono_object_new_checked (imethod->domain, (MonoClass*)imethod->data_items [*(guint16 *)(ip + 1)], error);
5856 mono_error_cleanup (error); /* FIXME: don't swallow the error */
5857 ip += 2;
5858 sp++;
5859 MINT_IN_BREAK;
5860 MINT_IN_CASE(MINT_MONO_FREE)
5861 ++ip;
5862 --sp;
5863 g_error ("that doesn't seem right");
5864 g_free (sp->data.p);
5865 MINT_IN_BREAK;
5866 MINT_IN_CASE(MINT_MONO_RETOBJ)
5867 ++ip;
5868 sp--;
5869 stackval_from_data (mono_method_signature_internal (imethod->method)->ret, frame->retval, sp->data.p,
5870 mono_method_signature_internal (imethod->method)->pinvoke);
5871 if (sp > frame->stack)
5872 g_warning ("retobj: more values on stack: %d", sp-frame->stack);
5873 goto exit_frame;
5874 MINT_IN_CASE(MINT_MONO_SGEN_THREAD_INFO)
5875 sp->data.p = mono_tls_get_sgen_thread_info ();
5876 sp++;
5877 ++ip;
5878 MINT_IN_BREAK;
5879 MINT_IN_CASE(MINT_MONO_MEMORY_BARRIER) {
5880 ++ip;
5881 mono_memory_barrier ();
5882 MINT_IN_BREAK;
5884 MINT_IN_CASE(MINT_MONO_LDDOMAIN)
5885 sp->data.p = mono_domain_get ();
5886 ++sp;
5887 ++ip;
5888 MINT_IN_BREAK;
5889 MINT_IN_CASE(MINT_SDB_INTR_LOC)
5890 if (G_UNLIKELY (ss_enabled)) {
5891 typedef void (*T) (void);
5892 static T ss_tramp;
5894 if (!ss_tramp) {
5895 void *tramp = mini_get_single_step_trampoline ();
5896 mono_memory_barrier ();
5897 ss_tramp = (T)tramp;
5901 * Make this point to the MINT_SDB_SEQ_POINT instruction which follows this since
5902 * the address of that instruction is stored as the seq point address.
5904 frame->ip = ip + 1;
5907 * Use the same trampoline as the JIT. This ensures that
5908 * the debugger has the context for the last interpreter
5909 * native frame.
5911 do_debugger_tramp (ss_tramp, frame);
5913 CHECK_RESUME_STATE (context);
5915 ++ip;
5916 MINT_IN_BREAK;
5917 MINT_IN_CASE(MINT_SDB_SEQ_POINT)
5918 /* Just a placeholder for a breakpoint */
5919 ++ip;
5920 MINT_IN_BREAK;
5921 MINT_IN_CASE(MINT_SDB_BREAKPOINT) {
5922 typedef void (*T) (void);
5923 static T bp_tramp;
5924 if (!bp_tramp) {
5925 void *tramp = mini_get_breakpoint_trampoline ();
5926 mono_memory_barrier ();
5927 bp_tramp = (T)tramp;
5930 frame->ip = ip;
5932 /* Use the same trampoline as the JIT */
5933 do_debugger_tramp (bp_tramp, frame);
5935 CHECK_RESUME_STATE (context);
5937 ++ip;
5938 MINT_IN_BREAK;
5941 #define RELOP(datamem, op) \
5942 --sp; \
5943 sp [-1].data.i = sp [-1].data.datamem op sp [0].data.datamem; \
5944 ++ip;
5946 #define RELOP_FP(datamem, op, noorder) \
5947 --sp; \
5948 if (mono_isunordered (sp [-1].data.datamem, sp [0].data.datamem)) \
5949 sp [-1].data.i = noorder; \
5950 else \
5951 sp [-1].data.i = sp [-1].data.datamem op sp [0].data.datamem; \
5952 ++ip;
5954 MINT_IN_CASE(MINT_CEQ_I4)
5955 RELOP(i, ==);
5956 MINT_IN_BREAK;
5957 MINT_IN_CASE(MINT_CEQ0_I4)
5958 sp [-1].data.i = (sp [-1].data.i == 0);
5959 ++ip;
5960 MINT_IN_BREAK;
5961 MINT_IN_CASE(MINT_CEQ_I8)
5962 RELOP(l, ==);
5963 MINT_IN_BREAK;
5964 MINT_IN_CASE(MINT_CEQ_R4)
5965 RELOP_FP(f_r4, ==, 0);
5966 MINT_IN_BREAK;
5967 MINT_IN_CASE(MINT_CEQ_R8)
5968 RELOP_FP(f, ==, 0);
5969 MINT_IN_BREAK;
5970 MINT_IN_CASE(MINT_CNE_I4)
5971 RELOP(i, !=);
5972 MINT_IN_BREAK;
5973 MINT_IN_CASE(MINT_CNE_I8)
5974 RELOP(l, !=);
5975 MINT_IN_BREAK;
5976 MINT_IN_CASE(MINT_CNE_R4)
5977 RELOP_FP(f_r4, !=, 1);
5978 MINT_IN_BREAK;
5979 MINT_IN_CASE(MINT_CNE_R8)
5980 RELOP_FP(f, !=, 1);
5981 MINT_IN_BREAK;
5982 MINT_IN_CASE(MINT_CGT_I4)
5983 RELOP(i, >);
5984 MINT_IN_BREAK;
5985 MINT_IN_CASE(MINT_CGT_I8)
5986 RELOP(l, >);
5987 MINT_IN_BREAK;
5988 MINT_IN_CASE(MINT_CGT_R4)
5989 RELOP_FP(f_r4, >, 0);
5990 MINT_IN_BREAK;
5991 MINT_IN_CASE(MINT_CGT_R8)
5992 RELOP_FP(f, >, 0);
5993 MINT_IN_BREAK;
5994 MINT_IN_CASE(MINT_CGE_I4)
5995 RELOP(i, >=);
5996 MINT_IN_BREAK;
5997 MINT_IN_CASE(MINT_CGE_I8)
5998 RELOP(l, >=);
5999 MINT_IN_BREAK;
6000 MINT_IN_CASE(MINT_CGE_R4)
6001 RELOP_FP(f_r4, >=, 0);
6002 MINT_IN_BREAK;
6003 MINT_IN_CASE(MINT_CGE_R8)
6004 RELOP_FP(f, >=, 0);
6005 MINT_IN_BREAK;
6007 #define RELOP_CAST(datamem, op, type) \
6008 --sp; \
6009 sp [-1].data.i = (type)sp [-1].data.datamem op (type)sp [0].data.datamem; \
6010 ++ip;
6012 MINT_IN_CASE(MINT_CGE_UN_I4)
6013 RELOP_CAST(l, >=, guint32);
6014 MINT_IN_BREAK;
6015 MINT_IN_CASE(MINT_CGE_UN_I8)
6016 RELOP_CAST(l, >=, guint64);
6017 MINT_IN_BREAK;
6019 MINT_IN_CASE(MINT_CGT_UN_I4)
6020 RELOP_CAST(i, >, guint32);
6021 MINT_IN_BREAK;
6022 MINT_IN_CASE(MINT_CGT_UN_I8)
6023 RELOP_CAST(l, >, guint64);
6024 MINT_IN_BREAK;
6025 MINT_IN_CASE(MINT_CGT_UN_R4)
6026 RELOP_FP(f_r4, >, 1);
6027 MINT_IN_BREAK;
6028 MINT_IN_CASE(MINT_CGT_UN_R8)
6029 RELOP_FP(f, >, 1);
6030 MINT_IN_BREAK;
6031 MINT_IN_CASE(MINT_CLT_I4)
6032 RELOP(i, <);
6033 MINT_IN_BREAK;
6034 MINT_IN_CASE(MINT_CLT_I8)
6035 RELOP(l, <);
6036 MINT_IN_BREAK;
6037 MINT_IN_CASE(MINT_CLT_R4)
6038 RELOP_FP(f_r4, <, 0);
6039 MINT_IN_BREAK;
6040 MINT_IN_CASE(MINT_CLT_R8)
6041 RELOP_FP(f, <, 0);
6042 MINT_IN_BREAK;
6043 MINT_IN_CASE(MINT_CLT_UN_I4)
6044 RELOP_CAST(i, <, guint32);
6045 MINT_IN_BREAK;
6046 MINT_IN_CASE(MINT_CLT_UN_I8)
6047 RELOP_CAST(l, <, guint64);
6048 MINT_IN_BREAK;
6049 MINT_IN_CASE(MINT_CLT_UN_R4)
6050 RELOP_FP(f_r4, <, 1);
6051 MINT_IN_BREAK;
6052 MINT_IN_CASE(MINT_CLT_UN_R8)
6053 RELOP_FP(f, <, 1);
6054 MINT_IN_BREAK;
6055 MINT_IN_CASE(MINT_CLE_I4)
6056 RELOP(i, <=);
6057 MINT_IN_BREAK;
6058 MINT_IN_CASE(MINT_CLE_I8)
6059 RELOP(l, <=);
6060 MINT_IN_BREAK;
6061 MINT_IN_CASE(MINT_CLE_UN_I4)
6062 RELOP_CAST(l, <=, guint32);
6063 MINT_IN_BREAK;
6064 MINT_IN_CASE(MINT_CLE_UN_I8)
6065 RELOP_CAST(l, <=, guint64);
6066 MINT_IN_BREAK;
6067 MINT_IN_CASE(MINT_CLE_R4)
6068 RELOP_FP(f_r4, <=, 0);
6069 MINT_IN_BREAK;
6070 MINT_IN_CASE(MINT_CLE_R8)
6071 RELOP_FP(f, <=, 0);
6072 MINT_IN_BREAK;
6074 #undef RELOP
6075 #undef RELOP_FP
6076 #undef RELOP_CAST
6078 MINT_IN_CASE(MINT_LDFTN) {
6079 sp->data.p = imethod->data_items [* (guint16 *)(ip + 1)];
6080 ++sp;
6081 ip += 2;
6082 MINT_IN_BREAK;
6084 MINT_IN_CASE(MINT_LDVIRTFTN) {
6085 InterpMethod *m = (InterpMethod*)imethod->data_items [* (guint16 *)(ip + 1)];
6086 --sp;
6087 NULL_CHECK (sp->data.p);
6089 sp->data.p = get_virtual_method (m, sp->data.o->vtable);
6090 ip += 2;
6091 ++sp;
6092 MINT_IN_BREAK;
6094 MINT_IN_CASE(MINT_LDFTN_DYNAMIC) {
6095 MONO_API_ERROR_INIT (error);
6096 InterpMethod *m = mono_interp_get_imethod (mono_domain_get (), (MonoMethod*) sp [-1].data.p, error);
6097 mono_error_assert_ok (error);
6098 sp [-1].data.p = m;
6099 ip++;
6100 MINT_IN_BREAK;
6103 #define LDARG(datamem, argtype) \
6104 sp->data.datamem = (argtype) frame->stack_args [*(guint16 *)(ip + 1)].data.datamem; \
6105 ip += 2; \
6106 ++sp;
6108 MINT_IN_CASE(MINT_LDARG_I1) LDARG(i, gint8); MINT_IN_BREAK;
6109 MINT_IN_CASE(MINT_LDARG_U1) LDARG(i, guint8); MINT_IN_BREAK;
6110 MINT_IN_CASE(MINT_LDARG_I2) LDARG(i, gint16); MINT_IN_BREAK;
6111 MINT_IN_CASE(MINT_LDARG_U2) LDARG(i, guint16); MINT_IN_BREAK;
6112 MINT_IN_CASE(MINT_LDARG_I4) LDARG(i, gint32); MINT_IN_BREAK;
6113 MINT_IN_CASE(MINT_LDARG_I8) LDARG(l, gint64); MINT_IN_BREAK;
6114 MINT_IN_CASE(MINT_LDARG_R4) LDARG(f_r4, float); MINT_IN_BREAK;
6115 MINT_IN_CASE(MINT_LDARG_R8) LDARG(f, double); MINT_IN_BREAK;
6116 MINT_IN_CASE(MINT_LDARG_O) LDARG(p, gpointer); MINT_IN_BREAK;
6117 MINT_IN_CASE(MINT_LDARG_P) LDARG(p, gpointer); MINT_IN_BREAK;
6119 MINT_IN_CASE(MINT_LDARG_VT)
6120 sp->data.p = vt_sp;
6121 i32 = READ32(ip + 2);
6122 memcpy(sp->data.p, frame->stack_args [* (guint16 *)(ip + 1)].data.p, i32);
6123 vt_sp += ALIGN_TO (i32, MINT_VT_ALIGNMENT);
6124 ip += 4;
6125 ++sp;
6126 MINT_IN_BREAK;
6128 #define STARG(datamem, argtype) \
6129 --sp; \
6130 frame->stack_args [*(guint16 *)(ip + 1)].data.datamem = (argtype) sp->data.datamem; \
6131 ip += 2; \
6133 MINT_IN_CASE(MINT_STARG_I1) STARG(i, gint8); MINT_IN_BREAK;
6134 MINT_IN_CASE(MINT_STARG_U1) STARG(i, guint8); MINT_IN_BREAK;
6135 MINT_IN_CASE(MINT_STARG_I2) STARG(i, gint16); MINT_IN_BREAK;
6136 MINT_IN_CASE(MINT_STARG_U2) STARG(i, guint16); MINT_IN_BREAK;
6137 MINT_IN_CASE(MINT_STARG_I4) STARG(i, gint32); MINT_IN_BREAK;
6138 MINT_IN_CASE(MINT_STARG_I8) STARG(l, gint64); MINT_IN_BREAK;
6139 MINT_IN_CASE(MINT_STARG_R4) STARG(f_r4, float); MINT_IN_BREAK;
6140 MINT_IN_CASE(MINT_STARG_R8) STARG(f, double); MINT_IN_BREAK;
6141 MINT_IN_CASE(MINT_STARG_O) STARG(p, gpointer); MINT_IN_BREAK;
6142 MINT_IN_CASE(MINT_STARG_P) STARG(p, gpointer); MINT_IN_BREAK;
6144 MINT_IN_CASE(MINT_STARG_VT)
6145 i32 = READ32(ip + 2);
6146 --sp;
6147 memcpy(frame->stack_args [* (guint16 *)(ip + 1)].data.p, sp->data.p, i32);
6148 vt_sp -= ALIGN_TO (i32, MINT_VT_ALIGNMENT);
6149 ip += 4;
6150 MINT_IN_BREAK;
6152 MINT_IN_CASE(MINT_PROF_ENTER) {
6153 ip += 1;
6155 if (MONO_PROFILER_ENABLED (method_enter)) {
6156 MonoProfilerCallContext *prof_ctx = NULL;
6158 if (imethod->prof_flags & MONO_PROFILER_CALL_INSTRUMENTATION_ENTER_CONTEXT) {
6159 prof_ctx = g_new0 (MonoProfilerCallContext, 1);
6160 prof_ctx->interp_frame = frame;
6161 prof_ctx->method = imethod->method;
6164 MONO_PROFILER_RAISE (method_enter, (imethod->method, prof_ctx));
6166 g_free (prof_ctx);
6169 MINT_IN_BREAK;
6172 MINT_IN_CASE(MINT_TRACE_ENTER) {
6173 ip += 1;
6175 MonoProfilerCallContext *prof_ctx = g_alloca (sizeof (MonoProfilerCallContext));
6176 prof_ctx->interp_frame = frame;
6177 prof_ctx->method = imethod->method;
6179 mono_trace_enter_method (imethod->method, prof_ctx);
6180 MINT_IN_BREAK;
6183 MINT_IN_CASE(MINT_TRACE_EXIT) {
6184 // Set retval
6185 i32 = READ32(ip + 1);
6186 --sp;
6187 if (i32 == -1)
6189 else if (i32)
6190 memcpy(frame->retval->data.p, sp->data.p, i32);
6191 else
6192 *frame->retval = *sp;
6194 MonoProfilerCallContext *prof_ctx = g_alloca (sizeof (MonoProfilerCallContext));
6195 prof_ctx->interp_frame = frame;
6196 prof_ctx->method = imethod->method;
6198 mono_trace_leave_method (imethod->method, prof_ctx);
6199 ip += 3;
6200 goto exit_frame;
6203 MINT_IN_CASE(MINT_LDARGA)
6204 sp->data.p = &frame->stack_args [* (guint16 *)(ip + 1)];
6205 ip += 2;
6206 ++sp;
6207 MINT_IN_BREAK;
6209 MINT_IN_CASE(MINT_LDARGA_VT)
6210 sp->data.p = frame->stack_args [* (guint16 *)(ip + 1)].data.p;
6211 ip += 2;
6212 ++sp;
6213 MINT_IN_BREAK;
6215 #define LDLOC(datamem, argtype) \
6216 sp->data.datamem = * (argtype *)(locals + * (guint16 *)(ip + 1)); \
6217 ip += 2; \
6218 ++sp;
6220 MINT_IN_CASE(MINT_LDLOC_I1) LDLOC(i, gint8); MINT_IN_BREAK;
6221 MINT_IN_CASE(MINT_LDLOC_U1) LDLOC(i, guint8); MINT_IN_BREAK;
6222 MINT_IN_CASE(MINT_LDLOC_I2) LDLOC(i, gint16); MINT_IN_BREAK;
6223 MINT_IN_CASE(MINT_LDLOC_U2) LDLOC(i, guint16); MINT_IN_BREAK;
6224 MINT_IN_CASE(MINT_LDLOC_I4) LDLOC(i, gint32); MINT_IN_BREAK;
6225 MINT_IN_CASE(MINT_LDLOC_I8) LDLOC(l, gint64); MINT_IN_BREAK;
6226 MINT_IN_CASE(MINT_LDLOC_R4) LDLOC(f_r4, float); MINT_IN_BREAK;
6227 MINT_IN_CASE(MINT_LDLOC_R8) LDLOC(f, double); MINT_IN_BREAK;
6228 MINT_IN_CASE(MINT_LDLOC_O) LDLOC(p, gpointer); MINT_IN_BREAK;
6229 MINT_IN_CASE(MINT_LDLOC_P) LDLOC(p, gpointer); MINT_IN_BREAK;
6231 MINT_IN_CASE(MINT_LDLOC_VT)
6232 sp->data.p = vt_sp;
6233 i32 = READ32(ip + 2);
6234 memcpy(sp->data.p, locals + * (guint16 *)(ip + 1), i32);
6235 vt_sp += ALIGN_TO (i32, MINT_VT_ALIGNMENT);
6236 ip += 4;
6237 ++sp;
6238 MINT_IN_BREAK;
6240 MINT_IN_CASE(MINT_LDLOCA_S)
6241 sp->data.p = locals + * (guint16 *)(ip + 1);
6242 ip += 2;
6243 ++sp;
6244 MINT_IN_BREAK;
6246 #define STLOC(datamem, argtype) \
6247 --sp; \
6248 * (argtype *)(locals + * (guint16 *)(ip + 1)) = sp->data.datamem; \
6249 ip += 2;
6251 MINT_IN_CASE(MINT_STLOC_I1) STLOC(i, gint8); MINT_IN_BREAK;
6252 MINT_IN_CASE(MINT_STLOC_U1) STLOC(i, guint8); MINT_IN_BREAK;
6253 MINT_IN_CASE(MINT_STLOC_I2) STLOC(i, gint16); MINT_IN_BREAK;
6254 MINT_IN_CASE(MINT_STLOC_U2) STLOC(i, guint16); MINT_IN_BREAK;
6255 MINT_IN_CASE(MINT_STLOC_I4) STLOC(i, gint32); MINT_IN_BREAK;
6256 MINT_IN_CASE(MINT_STLOC_I8) STLOC(l, gint64); MINT_IN_BREAK;
6257 MINT_IN_CASE(MINT_STLOC_R4) STLOC(f_r4, float); MINT_IN_BREAK;
6258 MINT_IN_CASE(MINT_STLOC_R8) STLOC(f, double); MINT_IN_BREAK;
6259 MINT_IN_CASE(MINT_STLOC_O) STLOC(p, gpointer); MINT_IN_BREAK;
6260 MINT_IN_CASE(MINT_STLOC_P) STLOC(p, gpointer); MINT_IN_BREAK;
6262 #define STLOC_NP(datamem, argtype) \
6263 * (argtype *)(locals + * (guint16 *)(ip + 1)) = sp [-1].data.datamem; \
6264 ip += 2;
6266 MINT_IN_CASE(MINT_STLOC_NP_I4) STLOC_NP(i, gint32); MINT_IN_BREAK;
6267 MINT_IN_CASE(MINT_STLOC_NP_O) STLOC_NP(p, gpointer); MINT_IN_BREAK;
6269 MINT_IN_CASE(MINT_STLOC_VT)
6270 i32 = READ32(ip + 2);
6271 --sp;
6272 memcpy(locals + * (guint16 *)(ip + 1), sp->data.p, i32);
6273 vt_sp -= ALIGN_TO (i32, MINT_VT_ALIGNMENT);
6274 ip += 4;
6275 MINT_IN_BREAK;
6277 MINT_IN_CASE(MINT_LOCALLOC) {
6278 if (sp != frame->stack + 1) /*FIX?*/
6279 THROW_EX (mono_get_exception_execution_engine (NULL), ip);
6281 int len = sp [-1].data.i;
6282 sp [-1].data.p = alloca (len);
6284 if (imethod->init_locals)
6285 memset (sp [-1].data.p, 0, len);
6286 ++ip;
6287 MINT_IN_BREAK;
6289 MINT_IN_CASE(MINT_ENDFILTER)
6290 /* top of stack is result of filter */
6291 frame->retval = &sp [-1];
6292 goto exit_frame;
6293 MINT_IN_CASE(MINT_INITOBJ)
6294 --sp;
6295 memset (sp->data.vt, 0, READ32(ip + 1));
6296 ip += 3;
6297 MINT_IN_BREAK;
6298 MINT_IN_CASE(MINT_CPBLK)
6299 sp -= 3;
6300 if (!sp [0].data.p || !sp [1].data.p)
6301 THROW_EX (mono_get_exception_null_reference(), ip - 1);
6302 ++ip;
6303 /* FIXME: value and size may be int64... */
6304 memcpy (sp [0].data.p, sp [1].data.p, sp [2].data.i);
6305 MINT_IN_BREAK;
6306 #if 0
6307 MINT_IN_CASE(MINT_CONSTRAINED_) {
6308 guint32 token;
6309 /* FIXME: implement */
6310 ++ip;
6311 token = READ32 (ip);
6312 ip += 2;
6313 MINT_IN_BREAK;
6315 #endif
6316 MINT_IN_CASE(MINT_INITBLK)
6317 sp -= 3;
6318 NULL_CHECK (sp [0].data.p);
6319 ++ip;
6320 /* FIXME: value and size may be int64... */
6321 memset (sp [0].data.p, sp [1].data.i, sp [2].data.i);
6322 MINT_IN_BREAK;
6323 #if 0
6324 MINT_IN_CASE(MINT_NO_)
6325 /* FIXME: implement */
6326 ip += 2;
6327 MINT_IN_BREAK;
6328 #endif
6329 MINT_IN_CASE(MINT_RETHROW) {
6330 int exvar_offset = *(guint16*)(ip + 1);
6331 THROW_EX_GENERAL (*(MonoException**)(frame->locals + exvar_offset), ip, TRUE);
6332 MINT_IN_BREAK;
6334 MINT_IN_CASE(MINT_MONO_RETHROW) {
6336 * need to clarify what this should actually do:
6338 * Takes an exception from the stack and rethrows it.
6339 * This is useful for wrappers that don't want to have to
6340 * use CEE_THROW and lose the exception stacktrace.
6343 --sp;
6344 if (!sp->data.p)
6345 sp->data.p = mono_get_exception_null_reference ();
6347 THROW_EX_GENERAL ((MonoException *)sp->data.p, ip, TRUE);
6348 MINT_IN_BREAK;
6350 MINT_IN_CASE(MINT_LD_DELEGATE_METHOD_PTR) {
6351 MonoDelegate *del;
6353 --sp;
6354 del = (MonoDelegate*)sp->data.p;
6355 if (!del->interp_method) {
6356 /* Not created from interpreted code */
6357 MONO_API_ERROR_INIT (error);
6358 g_assert (del->method);
6359 del->interp_method = mono_interp_get_imethod (del->object.vtable->domain, del->method, error);
6360 mono_error_assert_ok (error);
6362 g_assert (del->interp_method);
6363 sp->data.p = del->interp_method;
6364 ++sp;
6365 ip += 1;
6366 MINT_IN_BREAK;
6368 MINT_IN_CASE(MINT_LD_DELEGATE_INVOKE_IMPL) {
6369 MonoDelegate *del;
6370 int n = *(guint16*)(ip + 1);
6371 del = (MonoDelegate*)sp [-n].data.p;
6372 if (!del->interp_invoke_impl) {
6374 * First time we are called. Set up the invoke wrapper. We might be able to do this
6375 * in ctor but we would need to handle AllocDelegateLike_internal separately
6377 MONO_API_ERROR_INIT (error);
6378 MonoMethod *invoke = mono_get_delegate_invoke_internal (del->object.vtable->klass);
6379 del->interp_invoke_impl = mono_interp_get_imethod (del->object.vtable->domain, mono_marshal_get_delegate_invoke (invoke, del), error);
6380 mono_error_assert_ok (error);
6382 sp ++;
6383 sp [-1].data.p = del->interp_invoke_impl;
6384 ip += 2;
6385 MINT_IN_BREAK;
6388 #define MATH_UNOP(mathfunc) \
6389 sp [-1].data.f = mathfunc (sp [-1].data.f); \
6390 ++ip;
6392 MINT_IN_CASE(MINT_ABS) MATH_UNOP(fabs); MINT_IN_BREAK;
6393 MINT_IN_CASE(MINT_ASIN) MATH_UNOP(asin); MINT_IN_BREAK;
6394 MINT_IN_CASE(MINT_ASINH) MATH_UNOP(asinh); MINT_IN_BREAK;
6395 MINT_IN_CASE(MINT_ACOS) MATH_UNOP(acos); MINT_IN_BREAK;
6396 MINT_IN_CASE(MINT_ACOSH) MATH_UNOP(acosh); MINT_IN_BREAK;
6397 MINT_IN_CASE(MINT_ATAN) MATH_UNOP(atan); MINT_IN_BREAK;
6398 MINT_IN_CASE(MINT_ATANH) MATH_UNOP(atanh); MINT_IN_BREAK;
6399 MINT_IN_CASE(MINT_COS) MATH_UNOP(cos); MINT_IN_BREAK;
6400 MINT_IN_CASE(MINT_CBRT) MATH_UNOP(cbrt); MINT_IN_BREAK;
6401 MINT_IN_CASE(MINT_COSH) MATH_UNOP(cosh); MINT_IN_BREAK;
6402 MINT_IN_CASE(MINT_SIN) MATH_UNOP(sin); MINT_IN_BREAK;
6403 MINT_IN_CASE(MINT_SQRT) MATH_UNOP(sqrt); MINT_IN_BREAK;
6404 MINT_IN_CASE(MINT_SINH) MATH_UNOP(sinh); MINT_IN_BREAK;
6405 MINT_IN_CASE(MINT_TAN) MATH_UNOP(tan); MINT_IN_BREAK;
6406 MINT_IN_CASE(MINT_TANH) MATH_UNOP(tanh); MINT_IN_BREAK;
6408 MINT_IN_CASE(MINT_INTRINS_ENUM_HASFLAG) {
6409 MonoClass *klass = (MonoClass*)imethod->data_items[* (guint16 *)(ip + 1)];
6410 guint64 a_val = 0, b_val = 0;
6412 stackval_to_data (m_class_get_byval_arg (klass), &sp [-2], &a_val, FALSE);
6413 stackval_to_data (m_class_get_byval_arg (klass), &sp [-1], &b_val, FALSE);
6414 sp--;
6415 sp [-1].data.i = (a_val & b_val) == b_val;
6416 ip += 2;
6417 MINT_IN_BREAK;
6419 MINT_IN_CASE(MINT_INTRINS_GET_HASHCODE) {
6420 sp [-1].data.i = mono_object_hash_internal (sp [-1].data.o);
6421 ip++;
6422 MINT_IN_BREAK;
6424 MINT_IN_CASE(MINT_INTRINS_GET_TYPE) {
6425 NULL_CHECK (sp [-1].data.p);
6426 sp [-1].data.o = (MonoObject*) sp [-1].data.o->vtable->type;
6427 ip++;
6428 MINT_IN_BREAK;
6431 MINT_IN_DEFAULT
6432 g_error ("Unimplemented opcode: %04x %s at 0x%x\n", *ip, mono_interp_opname[*ip], ip-imethod->code);
6436 g_assert_not_reached ();
6438 exit_frame:
6439 error_init_reuse (error);
6441 if (clause_args && clause_args->base_frame)
6442 memcpy (clause_args->base_frame->args, frame->args, imethod->alloca_size);
6444 if (!frame->ex && MONO_PROFILER_ENABLED (method_leave) &&
6445 imethod->prof_flags & MONO_PROFILER_CALL_INSTRUMENTATION_LEAVE) {
6446 MonoProfilerCallContext *prof_ctx = NULL;
6448 if (imethod->prof_flags & MONO_PROFILER_CALL_INSTRUMENTATION_LEAVE_CONTEXT) {
6449 prof_ctx = g_new0 (MonoProfilerCallContext, 1);
6450 prof_ctx->interp_frame = frame;
6451 prof_ctx->method = imethod->method;
6453 MonoType *rtype = mono_method_signature_internal (imethod->method)->ret;
6455 switch (rtype->type) {
6456 case MONO_TYPE_VOID:
6457 break;
6458 case MONO_TYPE_VALUETYPE:
6459 prof_ctx->return_value = frame->retval->data.p;
6460 break;
6461 default:
6462 prof_ctx->return_value = frame->retval;
6463 break;
6467 MONO_PROFILER_RAISE (method_leave, (imethod->method, prof_ctx));
6469 g_free (prof_ctx);
6470 } else if (frame->ex && imethod->prof_flags & MONO_PROFILER_CALL_INSTRUMENTATION_EXCEPTION_LEAVE)
6471 MONO_PROFILER_RAISE (method_exception_leave, (imethod->method, &frame->ex->object));
6473 DEBUG_LEAVE ();
6476 static void
6477 interp_parse_options (const char *options)
6479 char **args, **ptr;
6481 if (!options)
6482 return;
6484 args = g_strsplit (options, ",", -1);
6485 for (ptr = args; ptr && *ptr; ptr ++) {
6486 char *arg = *ptr;
6488 if (strncmp (arg, "jit=", 4) == 0)
6489 mono_interp_jit_classes = g_slist_prepend (mono_interp_jit_classes, arg + 4);
6490 if (strncmp (arg, "interp-only=", 4) == 0)
6491 mono_interp_only_classes = g_slist_prepend (mono_interp_only_classes, arg + strlen ("interp-only="));
6492 if (strncmp (arg, "-inline", 7) == 0)
6493 mono_interp_opt &= ~INTERP_OPT_INLINE;
6498 * interp_set_resume_state:
6500 * Set the state the interpeter will continue to execute from after execution returns to the interpreter.
6502 static void
6503 interp_set_resume_state (MonoJitTlsData *jit_tls, MonoException *ex, MonoJitExceptionInfo *ei, MonoInterpFrameHandle interp_frame, gpointer handler_ip)
6505 ThreadContext *context;
6507 g_assert (jit_tls);
6508 context = (ThreadContext*)jit_tls->interp_context;
6509 g_assert (context);
6511 context->has_resume_state = TRUE;
6512 context->handler_frame = (InterpFrame*)interp_frame;
6513 context->handler_ei = ei;
6514 /* This is on the stack, so it doesn't need a wbarrier */
6515 context->handler_frame->ex = ex;
6516 /* Ditto */
6517 if (ei)
6518 *(MonoException**)(context->handler_frame->locals + ei->exvar_offset) = ex;
6519 context->handler_ip = (guint16*) handler_ip;
6523 * interp_run_finally:
6525 * Run the finally clause identified by CLAUSE_INDEX in the intepreter frame given by
6526 * frame->interp_frame.
6527 * Return TRUE if the finally clause threw an exception.
6529 static gboolean
6530 interp_run_finally (StackFrameInfo *frame, int clause_index, gpointer handler_ip, gpointer handler_ip_end)
6532 InterpFrame *iframe = (InterpFrame*)frame->interp_frame;
6533 ThreadContext *context = get_context ();
6534 const unsigned short *old_ip = iframe->ip;
6535 FrameClauseArgs clause_args;
6537 memset (&clause_args, 0, sizeof (FrameClauseArgs));
6538 clause_args.start_with_ip = (guint16*) handler_ip;
6539 clause_args.end_at_ip = (guint16*) handler_ip_end;
6540 clause_args.exit_clause = clause_index;
6542 ERROR_DECL (error);
6543 interp_exec_method_full (iframe, context, &clause_args, error);
6544 if (context->has_resume_state) {
6545 return TRUE;
6546 } else {
6547 iframe->ip = old_ip;
6548 return FALSE;
6553 * interp_run_filter:
6555 * Run the filter clause identified by CLAUSE_INDEX in the intepreter frame given by
6556 * frame->interp_frame.
6558 static gboolean
6559 interp_run_filter (StackFrameInfo *frame, MonoException *ex, int clause_index, gpointer handler_ip, gpointer handler_ip_end)
6561 InterpFrame *iframe = (InterpFrame*)frame->interp_frame;
6562 ThreadContext *context = get_context ();
6563 InterpFrame child_frame;
6564 stackval retval;
6565 FrameClauseArgs clause_args;
6568 * Have to run the clause in a new frame which is a copy of IFRAME, since
6569 * during debugging, there are two copies of the frame on the stack.
6571 memset (&child_frame, 0, sizeof (InterpFrame));
6572 child_frame.imethod = iframe->imethod;
6573 child_frame.retval = &retval;
6574 child_frame.parent = iframe;
6575 child_frame.stack_args = iframe->stack_args;
6577 memset (&clause_args, 0, sizeof (FrameClauseArgs));
6578 clause_args.start_with_ip = (guint16*) handler_ip;
6579 clause_args.end_at_ip = (guint16*) handler_ip_end;
6580 clause_args.filter_exception = ex;
6581 clause_args.base_frame = iframe;
6583 ERROR_DECL (error);
6584 interp_exec_method_full (&child_frame, context, &clause_args, error);
6585 /* ENDFILTER stores the result into child_frame->retval */
6586 return child_frame.retval->data.i ? TRUE : FALSE;
6589 typedef struct {
6590 InterpFrame *current;
6591 } StackIter;
6594 * interp_frame_iter_init:
6596 * Initialize an iterator for iterating through interpreted frames.
6598 static void
6599 interp_frame_iter_init (MonoInterpStackIter *iter, gpointer interp_exit_data)
6601 StackIter *stack_iter = (StackIter*)iter;
6603 stack_iter->current = (InterpFrame*)interp_exit_data;
6607 * interp_frame_iter_next:
6609 * Fill out FRAME with date for the next interpreter frame.
6611 static gboolean
6612 interp_frame_iter_next (MonoInterpStackIter *iter, StackFrameInfo *frame)
6614 StackIter *stack_iter = (StackIter*)iter;
6615 InterpFrame *iframe = stack_iter->current;
6617 memset (frame, 0, sizeof (StackFrameInfo));
6618 /* pinvoke frames doesn't have imethod set */
6619 while (iframe && !(iframe->imethod && iframe->imethod->code && iframe->imethod->jinfo))
6620 iframe = iframe->parent;
6621 if (!iframe)
6622 return FALSE;
6624 MonoMethod *method = iframe->imethod->method;
6625 frame->domain = iframe->imethod->domain;
6626 frame->interp_frame = iframe;
6627 frame->method = method;
6628 frame->actual_method = method;
6629 if (method && ((method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) || (method->iflags & (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL | METHOD_IMPL_ATTRIBUTE_RUNTIME)))) {
6630 frame->native_offset = -1;
6631 frame->type = FRAME_TYPE_MANAGED_TO_NATIVE;
6632 } else {
6633 frame->type = FRAME_TYPE_INTERP;
6634 /* This is the offset in the interpreter IR */
6635 frame->native_offset = (guint8*)iframe->ip - (guint8*)iframe->imethod->code;
6636 if (!method->wrapper_type || method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD)
6637 frame->managed = TRUE;
6639 frame->ji = iframe->imethod->jinfo;
6640 frame->frame_addr = iframe;
6642 stack_iter->current = iframe->parent;
6644 return TRUE;
6647 static MonoJitInfo*
6648 interp_find_jit_info (MonoDomain *domain, MonoMethod *method)
6650 InterpMethod* imethod;
6652 imethod = lookup_imethod (domain, method);
6653 if (imethod)
6654 return imethod->jinfo;
6655 else
6656 return NULL;
6659 static void
6660 interp_set_breakpoint (MonoJitInfo *jinfo, gpointer ip)
6662 guint16 *code = (guint16*)ip;
6663 g_assert (*code == MINT_SDB_SEQ_POINT);
6664 *code = MINT_SDB_BREAKPOINT;
6667 static void
6668 interp_clear_breakpoint (MonoJitInfo *jinfo, gpointer ip)
6670 guint16 *code = (guint16*)ip;
6671 g_assert (*code == MINT_SDB_BREAKPOINT);
6672 *code = MINT_SDB_SEQ_POINT;
6675 static MonoJitInfo*
6676 interp_frame_get_jit_info (MonoInterpFrameHandle frame)
6678 InterpFrame *iframe = (InterpFrame*)frame;
6680 g_assert (iframe->imethod);
6681 return iframe->imethod->jinfo;
6684 static gpointer
6685 interp_frame_get_ip (MonoInterpFrameHandle frame)
6687 InterpFrame *iframe = (InterpFrame*)frame;
6689 g_assert (iframe->imethod);
6690 return (gpointer)iframe->ip;
6693 static gpointer
6694 interp_frame_get_arg (MonoInterpFrameHandle frame, int pos)
6696 InterpFrame *iframe = (InterpFrame*)frame;
6697 MonoMethodSignature *sig;
6699 g_assert (iframe->imethod);
6701 sig = mono_method_signature_internal (iframe->imethod->method);
6702 return stackval_to_data_addr (sig->params [pos], &iframe->stack_args [pos + !!iframe->imethod->hasthis]);
6705 static gpointer
6706 interp_frame_get_local (MonoInterpFrameHandle frame, int pos)
6708 InterpFrame *iframe = (InterpFrame*)frame;
6710 g_assert (iframe->imethod);
6712 return iframe->locals + iframe->imethod->local_offsets [pos];
6715 static gpointer
6716 interp_frame_get_this (MonoInterpFrameHandle frame)
6718 InterpFrame *iframe = (InterpFrame*)frame;
6720 g_assert (iframe->imethod);
6721 g_assert (iframe->imethod->hasthis);
6722 return &iframe->stack_args [0].data.p;
6725 static MonoInterpFrameHandle
6726 interp_frame_get_parent (MonoInterpFrameHandle frame)
6728 InterpFrame *iframe = (InterpFrame*)frame;
6730 return iframe->parent;
6733 static gpointer
6734 interp_frame_get_res (MonoInterpFrameHandle frame)
6736 InterpFrame *iframe = (InterpFrame*)frame;
6737 MonoMethodSignature *sig;
6739 g_assert (iframe->imethod);
6740 sig = mono_method_signature_internal (iframe->imethod->method);
6741 if (sig->ret->type == MONO_TYPE_VOID)
6742 return NULL;
6743 else
6744 return stackval_to_data_addr (sig->ret, iframe->retval);
6747 static void
6748 interp_start_single_stepping (void)
6750 ss_enabled = TRUE;
6753 static void
6754 interp_stop_single_stepping (void)
6756 ss_enabled = FALSE;
6759 static void
6760 register_interp_stats (void)
6762 mono_counters_init ();
6763 mono_counters_register ("Total transform time", MONO_COUNTER_INTERP | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_interp_stats.transform_time);
6764 mono_counters_register ("Methods inlined", MONO_COUNTER_INTERP | MONO_COUNTER_INT, &mono_interp_stats.inlined_methods);
6765 mono_counters_register ("Inline failures", MONO_COUNTER_INTERP | MONO_COUNTER_INT, &mono_interp_stats.inline_failures);
6768 #undef MONO_EE_CALLBACK
6769 #define MONO_EE_CALLBACK(ret, name, sig) interp_ ## name,
6771 static const MonoEECallbacks mono_interp_callbacks = {
6772 MONO_EE_CALLBACKS
6775 void
6776 mono_ee_interp_init (const char *opts)
6778 g_assert (mono_ee_api_version () == MONO_EE_API_VERSION);
6779 g_assert (!interp_init_done);
6780 interp_init_done = TRUE;
6782 mono_native_tls_alloc (&thread_context_id, NULL);
6783 set_context (NULL);
6785 interp_parse_options (opts);
6786 if (mini_get_debug_options ()->mdb_optimizations)
6787 mono_interp_opt &= ~INTERP_OPT_INLINE;
6788 mono_interp_transform_init ();
6790 mini_install_interp_callbacks (&mono_interp_callbacks);
6792 register_interp_stats ();