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