[netcore] Clear system last error before P/Invoke calls with SetLastError=true (...
[mono-project.git] / mono / mini / interp / interp.c
blob198992c31b65fea4d285b933fd6d2f0c2f929350
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 INIT_FRAME(frame,parent_frame,method_args,method_retval,domain,mono_method,error) do { \
113 InterpMethod *_rmethod = mono_interp_get_imethod ((domain), (mono_method), (error)); \
114 init_frame ((frame), (parent_frame), _rmethod, (method_args), (method_retval)); \
115 } while (0)
117 #define interp_exec_method(frame, context, error) interp_exec_method_full ((frame), (context), NULL, error)
120 * List of classes whose methods will be executed by transitioning to JITted code.
121 * Used for testing.
123 GSList *mono_interp_jit_classes;
124 /* Optimizations enabled with interpreter */
125 int mono_interp_opt = INTERP_OPT_INLINE;
126 /* If TRUE, interpreted code will be interrupted at function entry/backward branches */
127 static gboolean ss_enabled;
129 static gboolean interp_init_done = FALSE;
131 static void interp_exec_method_full (InterpFrame *frame, ThreadContext *context, FrameClauseArgs *clause_args, MonoError *error);
132 static InterpMethod* lookup_method_pointer (gpointer addr);
134 typedef void (*ICallMethod) (InterpFrame *frame);
136 static MonoNativeTlsKey thread_context_id;
138 #define DEBUG_INTERP 0
139 #define COUNT_OPS 0
140 #if DEBUG_INTERP
141 int mono_interp_traceopt = 2;
142 /* If true, then we output the opcodes as we interpret them */
143 static int global_tracing = 2;
145 static int debug_indent_level = 0;
147 static int break_on_method = 0;
148 static int nested_trace = 0;
149 static GList *db_methods = NULL;
150 static char* dump_args (InterpFrame *inv);
152 static void
153 output_indent (void)
155 int h;
157 for (h = 0; h < debug_indent_level; h++)
158 g_print (" ");
161 static void
162 db_match_method (gpointer data, gpointer user_data)
164 MonoMethod *m = (MonoMethod*)user_data;
165 MonoMethodDesc *desc = data;
167 if (mono_method_desc_full_match (desc, m))
168 break_on_method = 1;
171 static void
172 debug_enter (InterpFrame *frame, int *tracing)
174 if (db_methods) {
175 g_list_foreach (db_methods, db_match_method, (gpointer)frame->imethod->method);
176 if (break_on_method)
177 *tracing = nested_trace ? (global_tracing = 2, 3) : 2;
178 break_on_method = 0;
180 if (*tracing) {
181 MonoMethod *method = frame->imethod->method;
182 char *mn, *args = dump_args (frame);
183 debug_indent_level++;
184 output_indent ();
185 mn = mono_method_full_name (method, FALSE);
186 g_print ("(%p) Entering %s (", mono_thread_internal_current (), mn);
187 g_free (mn);
188 g_print ("%s)\n", args);
189 g_free (args);
194 #define DEBUG_LEAVE() \
195 if (tracing) { \
196 char *mn, *args; \
197 args = dump_retval (frame); \
198 output_indent (); \
199 mn = mono_method_full_name (frame->imethod->method, FALSE); \
200 g_print ("(%p) Leaving %s", mono_thread_internal_current (), mn); \
201 g_free (mn); \
202 g_print (" => %s\n", args); \
203 g_free (args); \
204 debug_indent_level--; \
205 if (tracing == 3) global_tracing = 0; \
208 #else
210 int mono_interp_traceopt = 0;
211 static void debug_enter (InterpFrame *frame, int *tracing)
214 #define DEBUG_LEAVE()
216 #endif
218 static void
219 set_resume_state (ThreadContext *context, InterpFrame *frame)
221 frame->ex = NULL;
222 context->has_resume_state = 0;
223 context->handler_frame = NULL;
224 context->handler_ei = NULL;
227 /* Set the current execution state to the resume state in context */
228 #define SET_RESUME_STATE(context) do { \
229 ip = (const guint16*)(context)->handler_ip; \
230 /* spec says stack should be empty at endfinally so it should be at the start too */ \
231 sp = frame->stack; \
232 vt_sp = (unsigned char *) sp + imethod->stack_size; \
233 if (frame->ex) { \
234 sp->data.p = frame->ex; \
235 ++sp; \
237 /* We have thrown an exception from a finally block. Some of the leave targets were unwinded already */ \
238 while (finally_ips && \
239 finally_ips->data >= (context)->handler_ei->try_start && \
240 finally_ips->data < (context)->handler_ei->try_end) \
241 finally_ips = g_slist_remove (finally_ips, finally_ips->data); \
242 set_resume_state ((context), (frame)); \
243 goto main_loop; \
244 } while (0)
247 * If this bit is set, it means the call has thrown the exception, and we
248 * reached this point because the EH code in mono_handle_exception ()
249 * unwound all the JITted frames below us. mono_interp_set_resume_state ()
250 * has set the fields in context to indicate where we have to resume execution.
252 #define CHECK_RESUME_STATE(context) do { \
253 if ((context)->has_resume_state) { \
254 if (frame == (context)->handler_frame && (!clause_args || (context)->handler_ip < clause_args->end_at_ip)) \
255 SET_RESUME_STATE (context); \
256 else \
257 goto exit_frame; \
259 } while (0);
261 static void
262 set_context (ThreadContext *context)
264 mono_native_tls_set_value (thread_context_id, context);
266 if (!context)
267 return;
269 MonoJitTlsData *jit_tls = mono_tls_get_jit_tls ();
270 g_assertf (jit_tls, "ThreadContext needs initialized JIT TLS");
272 /* jit_tls assumes ownership of 'context' */
273 jit_tls->interp_context = context;
276 static ThreadContext *
277 get_context (void)
279 ThreadContext *context = (ThreadContext *) mono_native_tls_get_value (thread_context_id);
280 if (context == NULL) {
281 context = g_new0 (ThreadContext, 1);
282 set_context (context);
284 return context;
287 static MONO_NEVER_INLINE void
288 ves_real_abort (int line, MonoMethod *mh,
289 const unsigned short *ip, stackval *stack, stackval *sp)
291 ERROR_DECL (error);
292 MonoMethodHeader *header = mono_method_get_header_checked (mh, error);
293 mono_error_cleanup (error); /* FIXME: don't swallow the error */
294 g_printerr ("Execution aborted in method: %s::%s\n", m_class_get_name (mh->klass), mh->name);
295 g_printerr ("Line=%d IP=0x%04lx, Aborted execution\n", line, ip-(const unsigned short *) header->code);
296 g_printerr ("0x%04x %02x\n", ip-(const unsigned short *) header->code, *ip);
297 mono_metadata_free_mh (header);
300 #define ves_abort() \
301 do {\
302 ves_real_abort(__LINE__, frame->imethod->method, ip, frame->stack, sp); \
303 THROW_EX (mono_get_exception_execution_engine (NULL), ip); \
304 } while (0);
306 static InterpMethod*
307 lookup_imethod (MonoDomain *domain, MonoMethod *method)
309 InterpMethod *imethod;
310 MonoJitDomainInfo *info;
312 info = domain_jit_info (domain);
313 mono_domain_jit_code_hash_lock (domain);
314 imethod = (InterpMethod*)mono_internal_hash_table_lookup (&info->interp_code_hash, method);
315 mono_domain_jit_code_hash_unlock (domain);
316 return imethod;
319 static gpointer
320 interp_get_remoting_invoke (MonoMethod *method, gpointer addr, MonoError *error)
322 #ifndef DISABLE_REMOTING
323 InterpMethod *imethod;
325 if (addr) {
326 imethod = lookup_method_pointer (addr);
327 } else {
328 g_assert (method);
329 imethod = mono_interp_get_imethod (mono_domain_get (), method, error);
330 return_val_if_nok (error, NULL);
332 g_assert (imethod);
333 g_assert (mono_use_interpreter);
335 MonoMethod *remoting_invoke_method = mono_marshal_get_remoting_invoke (imethod->method, error);
336 return_val_if_nok (error, NULL);
337 return mono_interp_get_imethod (mono_domain_get (), remoting_invoke_method, error);
338 #else
339 g_assert_not_reached ();
340 return NULL;
341 #endif
344 InterpMethod*
345 mono_interp_get_imethod (MonoDomain *domain, MonoMethod *method, MonoError *error)
347 InterpMethod *imethod;
348 MonoJitDomainInfo *info;
349 MonoMethodSignature *sig;
350 int i;
352 error_init (error);
354 info = domain_jit_info (domain);
355 mono_domain_jit_code_hash_lock (domain);
356 imethod = (InterpMethod*)mono_internal_hash_table_lookup (&info->interp_code_hash, method);
357 mono_domain_jit_code_hash_unlock (domain);
358 if (imethod)
359 return imethod;
361 sig = mono_method_signature_internal (method);
363 imethod = (InterpMethod*)mono_domain_alloc0 (domain, sizeof (InterpMethod));
364 imethod->method = method;
365 imethod->domain = domain;
366 imethod->param_count = sig->param_count;
367 imethod->hasthis = sig->hasthis;
368 imethod->vararg = sig->call_convention == MONO_CALL_VARARG;
369 imethod->rtype = mini_get_underlying_type (sig->ret);
370 imethod->param_types = (MonoType**)mono_domain_alloc0 (domain, sizeof (MonoType*) * sig->param_count);
371 for (i = 0; i < sig->param_count; ++i)
372 imethod->param_types [i] = mini_get_underlying_type (sig->params [i]);
374 mono_domain_jit_code_hash_lock (domain);
375 if (!mono_internal_hash_table_lookup (&info->interp_code_hash, method))
376 mono_internal_hash_table_insert (&info->interp_code_hash, method, imethod);
377 mono_domain_jit_code_hash_unlock (domain);
379 imethod->prof_flags = mono_profiler_get_call_instrumentation_flags (imethod->method);
381 return imethod;
384 #if defined (MONO_CROSS_COMPILE) || defined (HOST_WASM)
385 #define INTERP_PUSH_LMF_WITH_CTX_BODY(ext, exit_label) \
386 (ext).kind = MONO_LMFEXT_INTERP_EXIT;
388 #elif defined(MONO_ARCH_HAS_NO_PROPER_MONOCTX)
389 /* some platforms, e.g. appleTV, don't provide us a precise MonoContext
390 * (registers are not accurate), thus resuming to the label does not work. */
391 #define INTERP_PUSH_LMF_WITH_CTX_BODY(ext, exit_label) \
392 (ext).kind = MONO_LMFEXT_INTERP_EXIT;
393 #elif defined (_MSC_VER)
394 #define INTERP_PUSH_LMF_WITH_CTX_BODY(ext, exit_label) \
395 (ext).kind = MONO_LMFEXT_INTERP_EXIT_WITH_CTX; \
396 (ext).interp_exit_label_set = FALSE; \
397 MONO_CONTEXT_GET_CURRENT ((ext).ctx); \
398 if ((ext).interp_exit_label_set == FALSE) \
399 mono_arch_do_ip_adjustment (&(ext).ctx); \
400 if ((ext).interp_exit_label_set == TRUE) \
401 goto exit_label; \
402 (ext).interp_exit_label_set = TRUE;
403 #elif defined(MONO_ARCH_HAS_MONO_CONTEXT)
404 #define INTERP_PUSH_LMF_WITH_CTX_BODY(ext, exit_label) \
405 (ext).kind = MONO_LMFEXT_INTERP_EXIT_WITH_CTX; \
406 MONO_CONTEXT_GET_CURRENT ((ext).ctx); \
407 MONO_CONTEXT_SET_IP (&(ext).ctx, (&&exit_label)); \
408 mono_arch_do_ip_adjustment (&(ext).ctx);
409 #else
410 #define INTERP_PUSH_LMF_WITH_CTX_BODY(ext, exit_label) g_error ("requires working mono-context");
411 #endif
413 /* INTERP_PUSH_LMF_WITH_CTX:
415 * same as interp_push_lmf, but retrieving and attaching MonoContext to it.
416 * This is needed to resume into the interp when the exception is thrown from
417 * native code (see ./mono/tests/install_eh_callback.exe).
419 * This must be a macro in order to retrieve the right register values for
420 * MonoContext.
422 #define INTERP_PUSH_LMF_WITH_CTX(frame, ext, exit_label) \
423 memset (&(ext), 0, sizeof (MonoLMFExt)); \
424 (ext).interp_exit_data = (frame); \
425 INTERP_PUSH_LMF_WITH_CTX_BODY ((ext), exit_label); \
426 mono_push_lmf (&(ext));
429 * interp_push_lmf:
431 * Push an LMF frame on the LMF stack
432 * to mark the transition to native code.
433 * This is needed for the native code to
434 * be able to do stack walks.
436 static void
437 interp_push_lmf (MonoLMFExt *ext, InterpFrame *frame)
439 memset (ext, 0, sizeof (MonoLMFExt));
440 ext->kind = MONO_LMFEXT_INTERP_EXIT;
441 ext->interp_exit_data = frame;
443 mono_push_lmf (ext);
446 static void
447 interp_pop_lmf (MonoLMFExt *ext)
449 mono_pop_lmf (&ext->lmf);
452 static MONO_NEVER_INLINE InterpMethod*
453 get_virtual_method (InterpMethod *imethod, MonoVTable *vtable)
455 MonoMethod *m = imethod->method;
456 MonoDomain *domain = imethod->domain;
457 InterpMethod *ret = NULL;
458 ERROR_DECL (error);
460 #ifndef DISABLE_REMOTING
461 if (mono_class_is_transparent_proxy (vtable->klass)) {
462 MonoMethod *remoting_invoke_method = mono_marshal_get_remoting_invoke_with_check (m, error);
463 mono_error_assert_ok (error);
464 ret = mono_interp_get_imethod (domain, remoting_invoke_method, error);
465 mono_error_assert_ok (error);
466 return ret;
468 #endif
470 if ((m->flags & METHOD_ATTRIBUTE_FINAL) || !(m->flags & METHOD_ATTRIBUTE_VIRTUAL)) {
471 if (m->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED) {
472 ret = mono_interp_get_imethod (domain, mono_marshal_get_synchronized_wrapper (m), error);
473 mono_error_cleanup (error); /* FIXME: don't swallow the error */
474 } else {
475 ret = imethod;
477 return ret;
480 mono_class_setup_vtable (vtable->klass);
482 int slot = mono_method_get_vtable_slot (m);
483 if (mono_class_is_interface (m->klass)) {
484 g_assert (vtable->klass != m->klass);
485 /* TODO: interface offset lookup is slow, go through IMT instead */
486 gboolean non_exact_match;
487 slot += mono_class_interface_offset_with_variance (vtable->klass, m->klass, &non_exact_match);
490 MonoMethod *virtual_method = m_class_get_vtable (vtable->klass) [slot];
491 if (m->is_inflated && mono_method_get_context (m)->method_inst) {
492 MonoGenericContext context = { NULL, NULL };
494 if (mono_class_is_ginst (virtual_method->klass))
495 context.class_inst = mono_class_get_generic_class (virtual_method->klass)->context.class_inst;
496 else if (mono_class_is_gtd (virtual_method->klass))
497 context.class_inst = mono_class_get_generic_container (virtual_method->klass)->context.class_inst;
498 context.method_inst = mono_method_get_context (m)->method_inst;
500 virtual_method = mono_class_inflate_generic_method_checked (virtual_method, &context, error);
501 mono_error_cleanup (error); /* FIXME: don't swallow the error */
504 if (virtual_method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) {
505 virtual_method = mono_marshal_get_native_wrapper (virtual_method, FALSE, FALSE);
508 if (virtual_method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED) {
509 virtual_method = mono_marshal_get_synchronized_wrapper (virtual_method);
512 InterpMethod *virtual_imethod = mono_interp_get_imethod (domain, virtual_method, error);
513 mono_error_cleanup (error); /* FIXME: don't swallow the error */
514 return virtual_imethod;
517 typedef struct {
518 InterpMethod *imethod;
519 InterpMethod *target_imethod;
520 } InterpVTableEntry;
522 /* domain lock must be held */
523 static GSList*
524 append_imethod (MonoDomain *domain, GSList *list, InterpMethod *imethod, InterpMethod *target_imethod)
526 GSList *ret;
527 InterpVTableEntry *entry;
529 entry = (InterpVTableEntry*) mono_mempool_alloc (domain->mp, sizeof (InterpVTableEntry));
530 entry->imethod = imethod;
531 entry->target_imethod = target_imethod;
532 ret = g_slist_append_mempool (domain->mp, list, entry);
534 return ret;
537 static InterpMethod*
538 get_target_imethod (GSList *list, InterpMethod *imethod)
540 while (list != NULL) {
541 InterpVTableEntry *entry = (InterpVTableEntry*) list->data;
542 if (entry->imethod == imethod)
543 return entry->target_imethod;
544 list = list->next;
546 return NULL;
549 static gpointer*
550 get_method_table (MonoVTable *vtable, int offset)
552 if (offset >= 0)
553 return vtable->interp_vtable;
554 else
555 return (gpointer*)vtable;
558 static gpointer*
559 alloc_method_table (MonoVTable *vtable, int offset)
561 gpointer *table;
563 if (offset >= 0) {
564 table = mono_domain_alloc0 (vtable->domain, m_class_get_vtable_size (vtable->klass) * sizeof (gpointer));
565 vtable->interp_vtable = table;
566 } else {
567 table = (gpointer*)vtable;
570 return table;
573 static InterpMethod*
574 get_virtual_method_fast (InterpMethod *imethod, MonoVTable *vtable, int offset)
576 gpointer *table;
578 #ifndef DISABLE_REMOTING
579 /* FIXME Remoting */
580 if (mono_class_is_transparent_proxy (vtable->klass))
581 return get_virtual_method (imethod, vtable);
582 #endif
584 table = get_method_table (vtable, offset);
586 if (!table) {
587 /* Lazily allocate method table */
588 mono_domain_lock (vtable->domain);
589 table = get_method_table (vtable, offset);
590 if (!table)
591 table = alloc_method_table (vtable, offset);
592 mono_domain_unlock (vtable->domain);
595 if (!table [offset]) {
596 InterpMethod *target_imethod = get_virtual_method (imethod, vtable);
597 /* Lazily initialize the method table slot */
598 mono_domain_lock (vtable->domain);
599 if (!table [offset]) {
600 if (imethod->method->is_inflated || offset < 0)
601 table [offset] = append_imethod (vtable->domain, NULL, imethod, target_imethod);
602 else
603 table [offset] = (gpointer) ((gsize)target_imethod | 0x1);
605 mono_domain_unlock (vtable->domain);
608 if ((gsize)table [offset] & 0x1) {
609 /* Non generic virtual call. Only one method in slot */
610 return (InterpMethod*) ((gsize)table [offset] & ~0x1);
611 } else {
612 /* Virtual generic or interface call. Multiple methods in slot */
613 InterpMethod *target_imethod = get_target_imethod ((GSList*)table [offset], imethod);
615 if (!target_imethod) {
616 target_imethod = get_virtual_method (imethod, vtable);
617 mono_domain_lock (vtable->domain);
618 if (!get_target_imethod ((GSList*)table [offset], imethod))
619 table [offset] = append_imethod (vtable->domain, (GSList*)table [offset], imethod, target_imethod);
620 mono_domain_unlock (vtable->domain);
622 return target_imethod;
626 static void inline
627 stackval_from_data (MonoType *type_, stackval *result, void *data, gboolean pinvoke)
629 MonoType *type = mini_native_type_replace_type (type_);
630 if (type->byref) {
631 switch (type->type) {
632 case MONO_TYPE_OBJECT:
633 case MONO_TYPE_CLASS:
634 case MONO_TYPE_STRING:
635 case MONO_TYPE_ARRAY:
636 case MONO_TYPE_SZARRAY:
637 break;
638 default:
639 break;
641 result->data.p = *(gpointer*)data;
642 return;
644 switch (type->type) {
645 case MONO_TYPE_VOID:
646 return;
647 case MONO_TYPE_I1:
648 result->data.i = *(gint8*)data;
649 return;
650 case MONO_TYPE_U1:
651 case MONO_TYPE_BOOLEAN:
652 result->data.i = *(guint8*)data;
653 return;
654 case MONO_TYPE_I2:
655 result->data.i = *(gint16*)data;
656 return;
657 case MONO_TYPE_U2:
658 case MONO_TYPE_CHAR:
659 result->data.i = *(guint16*)data;
660 return;
661 case MONO_TYPE_I4:
662 result->data.i = *(gint32*)data;
663 return;
664 case MONO_TYPE_U:
665 case MONO_TYPE_I:
666 result->data.nati = *(mono_i*)data;
667 return;
668 case MONO_TYPE_PTR:
669 result->data.p = *(gpointer*)data;
670 return;
671 case MONO_TYPE_U4:
672 result->data.i = *(guint32*)data;
673 return;
674 case MONO_TYPE_R4:
675 /* memmove handles unaligned case */
676 memmove (&result->data.f_r4, data, sizeof (float));
677 return;
678 case MONO_TYPE_I8:
679 case MONO_TYPE_U8:
680 memmove (&result->data.l, data, sizeof (gint64));
681 return;
682 case MONO_TYPE_R8:
683 memmove (&result->data.f, data, sizeof (double));
684 return;
685 case MONO_TYPE_STRING:
686 case MONO_TYPE_SZARRAY:
687 case MONO_TYPE_CLASS:
688 case MONO_TYPE_OBJECT:
689 case MONO_TYPE_ARRAY:
690 result->data.p = *(gpointer*)data;
691 return;
692 case MONO_TYPE_VALUETYPE:
693 if (m_class_is_enumtype (type->data.klass)) {
694 stackval_from_data (mono_class_enum_basetype_internal (type->data.klass), result, data, pinvoke);
695 return;
696 } else if (pinvoke) {
697 memcpy (result->data.vt, data, mono_class_native_size (type->data.klass, NULL));
698 } else {
699 mono_value_copy_internal (result->data.vt, data, type->data.klass);
701 return;
702 case MONO_TYPE_GENERICINST: {
703 if (mono_type_generic_inst_is_valuetype (type)) {
704 mono_value_copy_internal (result->data.vt, data, mono_class_from_mono_type_internal (type));
705 return;
707 stackval_from_data (m_class_get_byval_arg (type->data.generic_class->container_class), result, data, pinvoke);
708 return;
710 default:
711 g_error ("got type 0x%02x", type->type);
715 static void inline
716 stackval_to_data (MonoType *type_, stackval *val, void *data, gboolean pinvoke)
718 MonoType *type = mini_native_type_replace_type (type_);
719 if (type->byref) {
720 gpointer *p = (gpointer*)data;
721 *p = val->data.p;
722 return;
724 /* printf ("TODAT0 %p\n", data); */
725 switch (type->type) {
726 case MONO_TYPE_I1:
727 case MONO_TYPE_U1: {
728 guint8 *p = (guint8*)data;
729 *p = val->data.i;
730 return;
732 case MONO_TYPE_BOOLEAN: {
733 guint8 *p = (guint8*)data;
734 *p = (val->data.i != 0);
735 return;
737 case MONO_TYPE_I2:
738 case MONO_TYPE_U2:
739 case MONO_TYPE_CHAR: {
740 guint16 *p = (guint16*)data;
741 *p = val->data.i;
742 return;
744 case MONO_TYPE_I: {
745 mono_i *p = (mono_i*)data;
746 /* In theory the value used by stloc should match the local var type
747 but in practice it sometimes doesn't (a int32 gets dup'd and stloc'd into
748 a native int - both by csc and mcs). Not sure what to do about sign extension
749 as it is outside the spec... doing the obvious */
750 *p = (mono_i)val->data.nati;
751 return;
753 case MONO_TYPE_U: {
754 mono_u *p = (mono_u*)data;
755 /* see above. */
756 *p = (mono_u)val->data.nati;
757 return;
759 case MONO_TYPE_I4:
760 case MONO_TYPE_U4: {
761 gint32 *p = (gint32*)data;
762 *p = val->data.i;
763 return;
765 case MONO_TYPE_I8:
766 case MONO_TYPE_U8: {
767 memmove (data, &val->data.l, sizeof (gint64));
768 return;
770 case MONO_TYPE_R4: {
771 /* memmove handles unaligned case */
772 memmove (data, &val->data.f_r4, sizeof (float));
773 return;
775 case MONO_TYPE_R8: {
776 memmove (data, &val->data.f, sizeof (double));
777 return;
779 case MONO_TYPE_STRING:
780 case MONO_TYPE_SZARRAY:
781 case MONO_TYPE_CLASS:
782 case MONO_TYPE_OBJECT:
783 case MONO_TYPE_ARRAY: {
784 gpointer *p = (gpointer *) data;
785 mono_gc_wbarrier_generic_store_internal (p, val->data.o);
786 return;
788 case MONO_TYPE_PTR: {
789 gpointer *p = (gpointer *) data;
790 *p = val->data.p;
791 return;
793 case MONO_TYPE_VALUETYPE:
794 if (m_class_is_enumtype (type->data.klass)) {
795 stackval_to_data (mono_class_enum_basetype_internal (type->data.klass), val, data, pinvoke);
796 return;
797 } else if (pinvoke) {
798 memcpy (data, val->data.vt, mono_class_native_size (type->data.klass, NULL));
799 } else {
800 mono_value_copy_internal (data, val->data.vt, type->data.klass);
802 return;
803 case MONO_TYPE_GENERICINST: {
804 MonoClass *container_class = type->data.generic_class->container_class;
806 if (m_class_is_valuetype (container_class) && !m_class_is_enumtype (container_class)) {
807 mono_value_copy_internal (data, val->data.vt, mono_class_from_mono_type_internal (type));
808 return;
810 stackval_to_data (m_class_get_byval_arg (type->data.generic_class->container_class), val, data, pinvoke);
811 return;
813 default:
814 g_error ("got type %x", type->type);
819 * Same as stackval_to_data but return address of storage instead
820 * of copying the value.
822 static gpointer
823 stackval_to_data_addr (MonoType *type_, stackval *val)
825 MonoType *type = mini_native_type_replace_type (type_);
826 if (type->byref)
827 return &val->data.p;
829 switch (type->type) {
830 case MONO_TYPE_I1:
831 case MONO_TYPE_U1:
832 case MONO_TYPE_BOOLEAN:
833 case MONO_TYPE_I2:
834 case MONO_TYPE_U2:
835 case MONO_TYPE_CHAR:
836 case MONO_TYPE_I4:
837 case MONO_TYPE_U4:
838 return &val->data.i;
839 case MONO_TYPE_I:
840 case MONO_TYPE_U:
841 return &val->data.nati;
842 case MONO_TYPE_I8:
843 case MONO_TYPE_U8:
844 return &val->data.l;
845 case MONO_TYPE_R4:
846 return &val->data.f_r4;
847 case MONO_TYPE_R8:
848 return &val->data.f;
849 case MONO_TYPE_STRING:
850 case MONO_TYPE_SZARRAY:
851 case MONO_TYPE_CLASS:
852 case MONO_TYPE_OBJECT:
853 case MONO_TYPE_ARRAY:
854 case MONO_TYPE_PTR:
855 return &val->data.p;
856 case MONO_TYPE_VALUETYPE:
857 if (m_class_is_enumtype (type->data.klass))
858 return stackval_to_data_addr (mono_class_enum_basetype_internal (type->data.klass), val);
859 else
860 return val->data.vt;
861 case MONO_TYPE_TYPEDBYREF:
862 return val->data.vt;
863 case MONO_TYPE_GENERICINST: {
864 MonoClass *container_class = type->data.generic_class->container_class;
866 if (m_class_is_valuetype (container_class) && !m_class_is_enumtype (container_class))
867 return val->data.vt;
868 return stackval_to_data_addr (m_class_get_byval_arg (type->data.generic_class->container_class), val);
870 default:
871 g_error ("got type %x", type->type);
876 * interp_throw:
877 * Throw an exception from the interpreter.
879 static MONO_NEVER_INLINE void
880 interp_throw (ThreadContext *context, MonoException *ex, InterpFrame *frame, gconstpointer ip, gboolean rethrow)
882 ERROR_DECL (error);
883 MonoLMFExt ext;
885 interp_push_lmf (&ext, frame);
886 frame->ip = (const guint16*)ip;
887 frame->ex = ex;
889 if (mono_object_isinst_checked ((MonoObject *) ex, mono_defaults.exception_class, error)) {
890 MonoException *mono_ex = (MonoException *) ex;
891 if (!rethrow) {
892 mono_ex->stack_trace = NULL;
893 mono_ex->trace_ips = NULL;
896 mono_error_assert_ok (error);
898 MonoContext ctx;
899 memset (&ctx, 0, sizeof (MonoContext));
900 MONO_CONTEXT_SET_SP (&ctx, frame);
903 * Call the JIT EH code. The EH code will call back to us using:
904 * - mono_interp_set_resume_state ()/run_finally ()/run_filter ().
905 * Since ctx.ip is 0, this will start unwinding from the LMF frame
906 * pushed above, which points to our frames.
908 mono_handle_exception (&ctx, (MonoObject*)ex);
909 if (MONO_CONTEXT_GET_IP (&ctx) != 0) {
910 /* We need to unwind into non-interpreter code */
911 mono_restore_context (&ctx);
912 g_assert_not_reached ();
915 interp_pop_lmf (&ext);
917 g_assert (context->has_resume_state);
920 #define THROW_EX_GENERAL(exception,ex_ip, rethrow) \
921 do { \
922 interp_throw (context, (exception), (frame), (ex_ip), (rethrow)); \
923 CHECK_RESUME_STATE(context); \
924 } while (0)
926 #define THROW_EX(exception,ex_ip) THROW_EX_GENERAL ((exception), (ex_ip), FALSE)
928 #define EXCEPTION_CHECKPOINT \
929 do { \
930 if (*mono_thread_interruption_request_flag () && !mono_threads_is_critical_method (imethod->method)) { \
931 MonoException *exc = mono_thread_interruption_checkpoint (); \
932 if (exc) \
933 THROW_EX (exc, ip); \
935 } while (0)
938 static MonoObject*
939 ves_array_create (MonoDomain *domain, MonoClass *klass, int param_count, stackval *values, MonoError *error)
941 uintptr_t *lengths;
942 intptr_t *lower_bounds;
943 int i;
945 lengths = g_newa (uintptr_t, m_class_get_rank (klass) * 2);
946 for (i = 0; i < param_count; ++i) {
947 lengths [i] = values->data.i;
948 values ++;
950 if (m_class_get_rank (klass) == param_count) {
951 /* Only lengths provided. */
952 lower_bounds = NULL;
953 } else {
954 /* lower bounds are first. */
955 lower_bounds = (intptr_t *) lengths;
956 lengths += m_class_get_rank (klass);
958 return (MonoObject*) mono_array_new_full_checked (domain, klass, lengths, lower_bounds, error);
961 static gint32
962 ves_array_calculate_index (MonoArray *ao, stackval *sp, InterpFrame *frame, gboolean safe)
964 g_assert (!frame->ex);
965 MonoClass *ac = ((MonoObject *) ao)->vtable->klass;
967 guint32 pos = 0;
968 if (ao->bounds) {
969 for (gint32 i = 0; i < m_class_get_rank (ac); i++) {
970 guint32 idx = sp [i].data.i;
971 guint32 lower = ao->bounds [i].lower_bound;
972 guint32 len = ao->bounds [i].length;
973 if (safe && (idx < lower || (idx - lower) >= len)) {
974 frame->ex = mono_get_exception_index_out_of_range ();
975 return -1;
977 pos = (pos * len) + idx - lower;
979 } else {
980 pos = sp [0].data.i;
981 if (safe && pos >= ao->max_length) {
982 frame->ex = mono_get_exception_index_out_of_range ();
983 return -1;
986 return pos;
989 static MONO_NEVER_INLINE void
990 ves_array_set (InterpFrame *frame, stackval *sp, MonoMethodSignature *sig)
992 MonoObject *o = sp->data.o;
993 MonoArray *ao = (MonoArray *) o;
994 MonoClass *ac = o->vtable->klass;
996 g_assert (m_class_get_rank (ac) >= 1);
998 gint32 pos = ves_array_calculate_index (ao, sp + 1, frame, TRUE);
999 if (frame->ex)
1000 return;
1002 int val_index = 1 + m_class_get_rank (ac);
1003 if (sp [val_index].data.p && !m_class_is_valuetype (m_class_get_element_class (mono_object_class (o)))) {
1004 ERROR_DECL (error);
1005 MonoObject *isinst = mono_object_isinst_checked (sp [val_index].data.o, m_class_get_element_class (mono_object_class (o)), error);
1006 mono_error_cleanup (error);
1007 if (!isinst) {
1008 frame->ex = mono_get_exception_array_type_mismatch ();
1009 return;
1013 gint32 esize = mono_array_element_size (ac);
1014 gpointer ea = mono_array_addr_with_size_fast (ao, esize, pos);
1016 MonoType *mt = sig->params [m_class_get_rank (ac)];
1017 stackval_to_data (mt, &sp [val_index], ea, FALSE);
1020 static void
1021 ves_array_get (InterpFrame *frame, stackval *sp, stackval *retval, MonoMethodSignature *sig, gboolean safe)
1023 MonoObject *o = sp->data.o;
1024 MonoArray *ao = (MonoArray *) o;
1025 MonoClass *ac = o->vtable->klass;
1027 g_assert (m_class_get_rank (ac) >= 1);
1029 gint32 pos = ves_array_calculate_index (ao, sp + 1, frame, safe);
1030 if (frame->ex)
1031 return;
1033 gint32 esize = mono_array_element_size (ac);
1034 gpointer ea = mono_array_addr_with_size_fast (ao, esize, pos);
1036 MonoType *mt = sig->ret;
1037 stackval_from_data (mt, retval, ea, FALSE);
1040 static gpointer
1041 ves_array_element_address (InterpFrame *frame, MonoClass *required_type, MonoArray *ao, stackval *sp, gboolean needs_typecheck)
1043 MonoClass *ac = ((MonoObject *) ao)->vtable->klass;
1045 g_assert (m_class_get_rank (ac) >= 1);
1047 gint32 pos = ves_array_calculate_index (ao, sp, frame, TRUE);
1048 if (frame->ex)
1049 return NULL;
1051 if (needs_typecheck && !mono_class_is_assignable_from_internal (m_class_get_element_class (mono_object_class ((MonoObject *) ao)), required_type)) {
1052 frame->ex = mono_get_exception_array_type_mismatch ();
1053 return NULL;
1055 gint32 esize = mono_array_element_size (ac);
1056 return mono_array_addr_with_size_fast (ao, esize, pos);
1059 #ifdef MONO_ARCH_HAVE_INTERP_ENTRY_TRAMPOLINE
1060 static MonoFuncV mono_native_to_interp_trampoline = NULL;
1061 #endif
1063 #ifndef MONO_ARCH_HAVE_INTERP_PINVOKE_TRAMP
1064 static InterpMethodArguments* build_args_from_sig (MonoMethodSignature *sig, InterpFrame *frame)
1066 InterpMethodArguments *margs = g_malloc0 (sizeof (InterpMethodArguments));
1068 #ifdef TARGET_ARM
1069 g_assert (mono_arm_eabi_supported ());
1070 int i8_align = mono_arm_i8_align ();
1071 #endif
1073 #ifdef TARGET_WASM
1074 margs->sig = sig;
1075 #endif
1077 if (sig->hasthis)
1078 margs->ilen++;
1080 for (int i = 0; i < sig->param_count; i++) {
1081 guint32 ptype = sig->params [i]->byref ? MONO_TYPE_PTR : sig->params [i]->type;
1082 switch (ptype) {
1083 case MONO_TYPE_BOOLEAN:
1084 case MONO_TYPE_CHAR:
1085 case MONO_TYPE_I1:
1086 case MONO_TYPE_U1:
1087 case MONO_TYPE_I2:
1088 case MONO_TYPE_U2:
1089 case MONO_TYPE_I4:
1090 case MONO_TYPE_U4:
1091 case MONO_TYPE_I:
1092 case MONO_TYPE_U:
1093 case MONO_TYPE_PTR:
1094 case MONO_TYPE_SZARRAY:
1095 case MONO_TYPE_CLASS:
1096 case MONO_TYPE_OBJECT:
1097 case MONO_TYPE_STRING:
1098 case MONO_TYPE_VALUETYPE:
1099 case MONO_TYPE_GENERICINST:
1100 #if SIZEOF_VOID_P == 8
1101 case MONO_TYPE_I8:
1102 case MONO_TYPE_U8:
1103 #endif
1104 margs->ilen++;
1105 break;
1106 #if SIZEOF_VOID_P == 4
1107 case MONO_TYPE_I8:
1108 case MONO_TYPE_U8:
1109 #ifdef TARGET_ARM
1110 /* pairs begin at even registers */
1111 if (i8_align == 8 && margs->ilen & 1)
1112 margs->ilen++;
1113 #endif
1114 margs->ilen += 2;
1115 break;
1116 #endif
1117 case MONO_TYPE_R4:
1118 #if SIZEOF_VOID_P == 8
1119 case MONO_TYPE_R8:
1120 #endif
1121 margs->flen++;
1122 break;
1123 #if SIZEOF_VOID_P == 4
1124 case MONO_TYPE_R8:
1125 margs->flen += 2;
1126 break;
1127 #endif
1128 default:
1129 g_error ("build_args_from_sig: not implemented yet (1): 0x%x\n", ptype);
1133 if (margs->ilen > 0)
1134 margs->iargs = g_malloc0 (sizeof (gpointer) * margs->ilen);
1136 if (margs->flen > 0)
1137 margs->fargs = g_malloc0 (sizeof (double) * margs->flen);
1139 if (margs->ilen > INTERP_ICALL_TRAMP_IARGS)
1140 g_error ("build_args_from_sig: TODO, allocate gregs: %d\n", margs->ilen);
1142 if (margs->flen > INTERP_ICALL_TRAMP_FARGS)
1143 g_error ("build_args_from_sig: TODO, allocate fregs: %d\n", margs->flen);
1146 size_t int_i = 0;
1147 size_t int_f = 0;
1149 if (sig->hasthis) {
1150 margs->iargs [0] = frame->stack_args->data.p;
1151 int_i++;
1154 for (int i = 0; i < sig->param_count; i++) {
1155 guint32 ptype = sig->params [i]->byref ? MONO_TYPE_PTR : sig->params [i]->type;
1156 switch (ptype) {
1157 case MONO_TYPE_BOOLEAN:
1158 case MONO_TYPE_CHAR:
1159 case MONO_TYPE_I1:
1160 case MONO_TYPE_U1:
1161 case MONO_TYPE_I2:
1162 case MONO_TYPE_U2:
1163 case MONO_TYPE_I4:
1164 case MONO_TYPE_U4:
1165 case MONO_TYPE_I:
1166 case MONO_TYPE_U:
1167 case MONO_TYPE_PTR:
1168 case MONO_TYPE_SZARRAY:
1169 case MONO_TYPE_CLASS:
1170 case MONO_TYPE_OBJECT:
1171 case MONO_TYPE_STRING:
1172 case MONO_TYPE_VALUETYPE:
1173 case MONO_TYPE_GENERICINST:
1174 #if SIZEOF_VOID_P == 8
1175 case MONO_TYPE_I8:
1176 case MONO_TYPE_U8:
1177 #endif
1178 margs->iargs [int_i] = frame->stack_args [i].data.p;
1179 #if DEBUG_INTERP
1180 g_print ("build_args_from_sig: margs->iargs [%d]: %p (frame @ %d)\n", int_i, margs->iargs [int_i], i);
1181 #endif
1182 int_i++;
1183 break;
1184 #if SIZEOF_VOID_P == 4
1185 case MONO_TYPE_I8:
1186 case MONO_TYPE_U8: {
1187 stackval *sarg = &frame->stack_args [i];
1188 #ifdef TARGET_ARM
1189 /* pairs begin at even registers */
1190 if (i8_align == 8 && int_i & 1)
1191 int_i++;
1192 #endif
1193 margs->iargs [int_i] = (gpointer) sarg->data.pair.lo;
1194 int_i++;
1195 margs->iargs [int_i] = (gpointer) sarg->data.pair.hi;
1196 #if DEBUG_INTERP
1197 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);
1198 #endif
1199 int_i++;
1200 break;
1202 #endif
1203 case MONO_TYPE_R4:
1204 case MONO_TYPE_R8:
1205 if (ptype == MONO_TYPE_R4)
1206 * (float *) &(margs->fargs [int_f]) = frame->stack_args [i].data.f_r4;
1207 else
1208 margs->fargs [int_f] = frame->stack_args [i].data.f;
1209 #if DEBUG_INTERP
1210 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);
1211 #endif
1212 #if SIZEOF_VOID_P == 4
1213 int_f += 2;
1214 #else
1215 int_f++;
1216 #endif
1217 break;
1218 default:
1219 g_error ("build_args_from_sig: not implemented yet (2): 0x%x\n", ptype);
1223 switch (sig->ret->type) {
1224 case MONO_TYPE_BOOLEAN:
1225 case MONO_TYPE_CHAR:
1226 case MONO_TYPE_I1:
1227 case MONO_TYPE_U1:
1228 case MONO_TYPE_I2:
1229 case MONO_TYPE_U2:
1230 case MONO_TYPE_I4:
1231 case MONO_TYPE_U4:
1232 case MONO_TYPE_I:
1233 case MONO_TYPE_U:
1234 case MONO_TYPE_PTR:
1235 case MONO_TYPE_SZARRAY:
1236 case MONO_TYPE_CLASS:
1237 case MONO_TYPE_OBJECT:
1238 case MONO_TYPE_STRING:
1239 case MONO_TYPE_I8:
1240 case MONO_TYPE_U8:
1241 case MONO_TYPE_VALUETYPE:
1242 case MONO_TYPE_GENERICINST:
1243 margs->retval = &(frame->retval->data.p);
1244 margs->is_float_ret = 0;
1245 break;
1246 case MONO_TYPE_R4:
1247 case MONO_TYPE_R8:
1248 margs->retval = &(frame->retval->data.p);
1249 margs->is_float_ret = 1;
1250 break;
1251 case MONO_TYPE_VOID:
1252 margs->retval = NULL;
1253 break;
1254 default:
1255 g_error ("build_args_from_sig: ret type not implemented yet: 0x%x\n", sig->ret->type);
1258 return margs;
1260 #endif
1262 static void
1263 interp_frame_arg_to_data (MonoInterpFrameHandle frame, MonoMethodSignature *sig, int index, gpointer data)
1265 InterpFrame *iframe = (InterpFrame*)frame;
1267 if (index == -1)
1268 stackval_to_data (sig->ret, iframe->retval, data, sig->pinvoke);
1269 else
1270 stackval_to_data (sig->params [index], &iframe->stack_args [index], data, sig->pinvoke);
1273 static void
1274 interp_data_to_frame_arg (MonoInterpFrameHandle frame, MonoMethodSignature *sig, int index, gpointer data)
1276 InterpFrame *iframe = (InterpFrame*)frame;
1278 if (index == -1)
1279 stackval_from_data (sig->ret, iframe->retval, data, sig->pinvoke);
1280 else if (sig->hasthis && index == 0)
1281 iframe->stack_args [index].data.p = *(gpointer*)data;
1282 else
1283 stackval_from_data (sig->params [index - sig->hasthis], &iframe->stack_args [index], data, sig->pinvoke);
1286 static gpointer
1287 interp_frame_arg_to_storage (MonoInterpFrameHandle frame, MonoMethodSignature *sig, int index)
1289 InterpFrame *iframe = (InterpFrame*)frame;
1291 if (index == -1)
1292 return stackval_to_data_addr (sig->ret, iframe->retval);
1293 else
1294 return stackval_to_data_addr (sig->params [index], &iframe->stack_args [index]);
1297 static void
1298 interp_frame_arg_set_storage (MonoInterpFrameHandle frame, MonoMethodSignature *sig, int index, gpointer storage)
1300 InterpFrame *iframe = (InterpFrame*)frame;
1301 stackval *val = (index == -1) ? iframe->retval : &iframe->stack_args [index];
1302 MonoType *type = (index == -1) ? sig->ret : sig->params [index];
1304 switch (type->type) {
1305 case MONO_TYPE_GENERICINST:
1306 if (!MONO_TYPE_IS_REFERENCE (type))
1307 val->data.vt = storage;
1308 break;
1309 case MONO_TYPE_VALUETYPE:
1310 val->data.vt = storage;
1311 break;
1312 default:
1313 g_assert_not_reached ();
1317 static MonoPIFunc
1318 get_interp_to_native_trampoline (void)
1320 static MonoPIFunc trampoline = NULL;
1322 if (!trampoline) {
1323 if (mono_ee_features.use_aot_trampolines) {
1324 trampoline = (MonoPIFunc) mono_aot_get_trampoline ("interp_to_native_trampoline");
1325 } else {
1326 MonoTrampInfo *info;
1327 trampoline = (MonoPIFunc) mono_arch_get_interp_to_native_trampoline (&info);
1328 mono_tramp_info_register (info, NULL);
1330 mono_memory_barrier ();
1332 return trampoline;
1335 static void
1336 interp_to_native_trampoline (gpointer addr, gpointer ccontext)
1338 get_interp_to_native_trampoline () (addr, ccontext);
1341 /* MONO_NO_OPTIMIATION is needed due to usage of INTERP_PUSH_LMF_WITH_CTX. */
1342 #ifdef _MSC_VER
1343 #pragma optimize ("", off)
1344 #endif
1345 static MONO_NO_OPTIMIZATION MONO_NEVER_INLINE void
1346 ves_pinvoke_method (InterpFrame *frame, MonoMethodSignature *sig, MonoFuncV addr, gboolean string_ctor, ThreadContext *context, gboolean save_last_error)
1348 MonoLMFExt ext;
1349 gpointer args;
1351 frame->ex = NULL;
1353 g_assert (!frame->imethod);
1355 static MonoPIFunc entry_func = NULL;
1356 if (!entry_func) {
1357 #ifdef MONO_ARCH_HAS_NO_PROPER_MONOCTX
1358 ERROR_DECL (error);
1359 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);
1360 mono_error_assert_ok (error);
1361 #else
1362 entry_func = get_interp_to_native_trampoline ();
1363 #endif
1364 mono_memory_barrier ();
1367 #ifdef ENABLE_NETCORE
1368 if (save_last_error) {
1369 mono_marshal_clear_last_error ();
1371 #endif
1373 #ifdef MONO_ARCH_HAVE_INTERP_PINVOKE_TRAMP
1374 CallContext ccontext;
1375 mono_arch_set_native_call_context_args (&ccontext, frame, sig);
1376 args = &ccontext;
1377 #else
1378 InterpMethodArguments *margs = build_args_from_sig (sig, frame);
1379 args = margs;
1380 #endif
1382 INTERP_PUSH_LMF_WITH_CTX (frame, ext, exit_pinvoke);
1383 entry_func ((gpointer) addr, args);
1384 if (save_last_error)
1385 mono_marshal_set_last_error ();
1386 interp_pop_lmf (&ext);
1388 #ifdef MONO_ARCH_HAVE_INTERP_PINVOKE_TRAMP
1389 if (!frame->ex)
1390 mono_arch_get_native_call_context_ret (&ccontext, frame, sig);
1392 if (ccontext.stack != NULL)
1393 g_free (ccontext.stack);
1394 #else
1395 if (!frame->ex && !MONO_TYPE_ISSTRUCT (sig->ret))
1396 stackval_from_data (sig->ret, frame->retval, (char*)&frame->retval->data.p, sig->pinvoke);
1398 g_free (margs->iargs);
1399 g_free (margs->fargs);
1400 g_free (margs);
1401 #endif
1402 goto exit_pinvoke; // prevent unused label warning in some configurations
1403 exit_pinvoke:
1404 return;
1406 #ifdef _MSC_VER
1407 #pragma optimize ("", on)
1408 #endif
1411 * interp_init_delegate:
1413 * Initialize del->interp_method.
1415 static void
1416 interp_init_delegate (MonoDelegate *del, MonoError *error)
1418 MonoMethod *method;
1420 if (del->interp_method) {
1421 /* Delegate created by a call to ves_icall_mono_delegate_ctor_interp () */
1422 del->method = ((InterpMethod *)del->interp_method)->method;
1423 } else if (del->method) {
1424 /* Delegate created dynamically */
1425 del->interp_method = mono_interp_get_imethod (del->object.vtable->domain, del->method, error);
1426 } else {
1427 /* Created from JITted code */
1428 g_assert_not_reached ();
1431 method = ((InterpMethod*)del->interp_method)->method;
1432 if (del->target &&
1433 method &&
1434 method->flags & METHOD_ATTRIBUTE_VIRTUAL &&
1435 method->flags & METHOD_ATTRIBUTE_ABSTRACT &&
1436 mono_class_is_abstract (method->klass))
1437 del->interp_method = get_virtual_method ((InterpMethod*)del->interp_method, del->target->vtable);
1439 method = ((InterpMethod*)del->interp_method)->method;
1440 if (method && m_class_get_parent (method->klass) == mono_defaults.multicastdelegate_class) {
1441 const char *name = method->name;
1442 if (*name == 'I' && (strcmp (name, "Invoke") == 0)) {
1444 * When invoking the delegate interp_method is executed directly. If it's an
1445 * invoke make sure we replace it with the appropriate delegate invoke wrapper.
1447 * FIXME We should do this later, when we also know the delegate on which the
1448 * target method is called.
1450 del->interp_method = mono_interp_get_imethod (del->object.vtable->domain, mono_marshal_get_delegate_invoke (method, NULL), error);
1451 mono_error_assert_ok (error);
1455 if (!((InterpMethod *) del->interp_method)->transformed && method_is_dynamic (method)) {
1456 /* Return any errors from method compilation */
1457 mono_interp_transform_method ((InterpMethod *) del->interp_method, get_context (), error);
1458 return_if_nok (error);
1462 static void
1463 interp_delegate_ctor (MonoObjectHandle this_obj, MonoObjectHandle target, gpointer addr, MonoError *error)
1466 * addr is the result of an LDFTN opcode, i.e. an InterpMethod
1468 InterpMethod *imethod = (InterpMethod*)addr;
1470 if (!(imethod->method->flags & METHOD_ATTRIBUTE_STATIC)) {
1471 MonoMethod *invoke = mono_get_delegate_invoke_internal (mono_handle_class (this_obj));
1472 /* virtual invoke delegates must not have null check */
1473 if (mono_method_signature_internal (imethod->method)->param_count == mono_method_signature_internal (invoke)->param_count
1474 && MONO_HANDLE_IS_NULL (target)) {
1475 mono_error_set_argument (error, "this", "Delegate to an instance method cannot have null 'this'");
1476 return;
1480 g_assert (imethod->method);
1481 gpointer entry = mini_get_interp_callbacks ()->create_method_pointer (imethod->method, FALSE, error);
1482 return_if_nok (error);
1484 MONO_HANDLE_SETVAL (MONO_HANDLE_CAST (MonoDelegate, this_obj), interp_method, gpointer, imethod);
1486 mono_delegate_ctor (this_obj, target, entry, error);
1490 * From the spec:
1491 * runtime specifies that the implementation of the method is automatically
1492 * provided by the runtime and is primarily used for the methods of delegates.
1494 static MONO_NEVER_INLINE void
1495 ves_imethod (InterpFrame *frame, MonoMethod *method, MonoMethodSignature *sig, stackval *sp, stackval *retval)
1497 const char *name = method->name;
1498 mono_class_init_internal (method->klass);
1500 if (method->klass == mono_defaults.array_class) {
1501 if (!strcmp (name, "UnsafeMov")) {
1502 /* TODO: layout checks */
1503 stackval_from_data (sig->ret, retval, (char*) sp, FALSE);
1504 return;
1506 if (!strcmp (name, "UnsafeLoad")) {
1507 ves_array_get (frame, sp, retval, sig, FALSE);
1508 return;
1510 } else if (mini_class_is_system_array (method->klass)) {
1511 MonoObject *obj = (MonoObject*) sp->data.p;
1512 if (!obj) {
1513 frame->ex = mono_get_exception_null_reference ();
1514 return;
1516 if (*name == 'S' && (strcmp (name, "Set") == 0)) {
1517 ves_array_set (frame, sp, sig);
1518 return;
1520 if (*name == 'G' && (strcmp (name, "Get") == 0)) {
1521 ves_array_get (frame, sp, retval, sig, TRUE);
1522 return;
1526 g_error ("Don't know how to exec runtime method %s.%s::%s",
1527 m_class_get_name_space (method->klass), m_class_get_name (method->klass),
1528 method->name);
1531 #if DEBUG_INTERP
1532 static char*
1533 dump_stack (stackval *stack, stackval *sp)
1535 stackval *s = stack;
1536 GString *str = g_string_new ("");
1538 if (sp == stack)
1539 return g_string_free (str, FALSE);
1541 while (s < sp) {
1542 g_string_append_printf (str, "[%p (%lld)] ", s->data.l, s->data.l);
1543 ++s;
1545 return g_string_free (str, FALSE);
1548 static void
1549 dump_stackval (GString *str, stackval *s, MonoType *type)
1551 switch (type->type) {
1552 case MONO_TYPE_I1:
1553 case MONO_TYPE_U1:
1554 case MONO_TYPE_I2:
1555 case MONO_TYPE_U2:
1556 case MONO_TYPE_I4:
1557 case MONO_TYPE_U4:
1558 case MONO_TYPE_CHAR:
1559 case MONO_TYPE_BOOLEAN:
1560 g_string_append_printf (str, "[%d] ", s->data.i);
1561 break;
1562 case MONO_TYPE_STRING:
1563 case MONO_TYPE_SZARRAY:
1564 case MONO_TYPE_CLASS:
1565 case MONO_TYPE_OBJECT:
1566 case MONO_TYPE_ARRAY:
1567 case MONO_TYPE_PTR:
1568 case MONO_TYPE_I:
1569 case MONO_TYPE_U:
1570 g_string_append_printf (str, "[%p] ", s->data.p);
1571 break;
1572 case MONO_TYPE_VALUETYPE:
1573 if (m_class_is_enumtype (type->data.klass))
1574 g_string_append_printf (str, "[%d] ", s->data.i);
1575 else
1576 g_string_append_printf (str, "[vt:%p] ", s->data.p);
1577 break;
1578 case MONO_TYPE_R4:
1579 g_string_append_printf (str, "[%g] ", s->data.f_r4);
1580 break;
1581 case MONO_TYPE_R8:
1582 g_string_append_printf (str, "[%g] ", s->data.f);
1583 break;
1584 case MONO_TYPE_I8:
1585 case MONO_TYPE_U8:
1586 default: {
1587 GString *res = g_string_new ("");
1588 mono_type_get_desc (res, type, TRUE);
1589 g_string_append_printf (str, "[{%s} %lld/0x%0llx] ", res->str, s->data.l, s->data.l);
1590 g_string_free (res, TRUE);
1591 break;
1596 static char*
1597 dump_retval (InterpFrame *inv)
1599 GString *str = g_string_new ("");
1600 MonoType *ret = mono_method_signature_internal (inv->imethod->method)->ret;
1602 if (ret->type != MONO_TYPE_VOID)
1603 dump_stackval (str, inv->retval, ret);
1605 return g_string_free (str, FALSE);
1608 static char*
1609 dump_args (InterpFrame *inv)
1611 GString *str = g_string_new ("");
1612 int i;
1613 MonoMethodSignature *signature = mono_method_signature_internal (inv->imethod->method);
1615 if (signature->param_count == 0 && !signature->hasthis)
1616 return g_string_free (str, FALSE);
1618 if (signature->hasthis) {
1619 MonoMethod *method = inv->imethod->method;
1620 dump_stackval (str, inv->stack_args, m_class_get_byval_arg (method->klass));
1623 for (i = 0; i < signature->param_count; ++i)
1624 dump_stackval (str, inv->stack_args + (!!signature->hasthis) + i, signature->params [i]);
1626 return g_string_free (str, FALSE);
1628 #endif
1630 #define CHECK_ADD_OVERFLOW(a,b) \
1631 (gint32)(b) >= 0 ? (gint32)(G_MAXINT32) - (gint32)(b) < (gint32)(a) ? -1 : 0 \
1632 : (gint32)(G_MININT32) - (gint32)(b) > (gint32)(a) ? +1 : 0
1634 #define CHECK_SUB_OVERFLOW(a,b) \
1635 (gint32)(b) < 0 ? (gint32)(G_MAXINT32) + (gint32)(b) < (gint32)(a) ? -1 : 0 \
1636 : (gint32)(G_MININT32) + (gint32)(b) > (gint32)(a) ? +1 : 0
1638 #define CHECK_ADD_OVERFLOW_UN(a,b) \
1639 (guint32)(G_MAXUINT32) - (guint32)(b) < (guint32)(a) ? -1 : 0
1641 #define CHECK_SUB_OVERFLOW_UN(a,b) \
1642 (guint32)(a) < (guint32)(b) ? -1 : 0
1644 #define CHECK_ADD_OVERFLOW64(a,b) \
1645 (gint64)(b) >= 0 ? (gint64)(G_MAXINT64) - (gint64)(b) < (gint64)(a) ? -1 : 0 \
1646 : (gint64)(G_MININT64) - (gint64)(b) > (gint64)(a) ? +1 : 0
1648 #define CHECK_SUB_OVERFLOW64(a,b) \
1649 (gint64)(b) < 0 ? (gint64)(G_MAXINT64) + (gint64)(b) < (gint64)(a) ? -1 : 0 \
1650 : (gint64)(G_MININT64) + (gint64)(b) > (gint64)(a) ? +1 : 0
1652 #define CHECK_ADD_OVERFLOW64_UN(a,b) \
1653 (guint64)(G_MAXUINT64) - (guint64)(b) < (guint64)(a) ? -1 : 0
1655 #define CHECK_SUB_OVERFLOW64_UN(a,b) \
1656 (guint64)(a) < (guint64)(b) ? -1 : 0
1658 #if SIZEOF_VOID_P == 4
1659 #define CHECK_ADD_OVERFLOW_NAT(a,b) CHECK_ADD_OVERFLOW(a,b)
1660 #define CHECK_ADD_OVERFLOW_NAT_UN(a,b) CHECK_ADD_OVERFLOW_UN(a,b)
1661 #else
1662 #define CHECK_ADD_OVERFLOW_NAT(a,b) CHECK_ADD_OVERFLOW64(a,b)
1663 #define CHECK_ADD_OVERFLOW_NAT_UN(a,b) CHECK_ADD_OVERFLOW64_UN(a,b)
1664 #endif
1666 /* Resolves to TRUE if the operands would overflow */
1667 #define CHECK_MUL_OVERFLOW(a,b) \
1668 ((gint32)(a) == 0) || ((gint32)(b) == 0) ? 0 : \
1669 (((gint32)(a) > 0) && ((gint32)(b) == -1)) ? FALSE : \
1670 (((gint32)(a) < 0) && ((gint32)(b) == -1)) ? (a == G_MININT32) : \
1671 (((gint32)(a) > 0) && ((gint32)(b) > 0)) ? (gint32)(a) > ((G_MAXINT32) / (gint32)(b)) : \
1672 (((gint32)(a) > 0) && ((gint32)(b) < 0)) ? (gint32)(a) > ((G_MININT32) / (gint32)(b)) : \
1673 (((gint32)(a) < 0) && ((gint32)(b) > 0)) ? (gint32)(a) < ((G_MININT32) / (gint32)(b)) : \
1674 (gint32)(a) < ((G_MAXINT32) / (gint32)(b))
1676 #define CHECK_MUL_OVERFLOW_UN(a,b) \
1677 ((guint32)(a) == 0) || ((guint32)(b) == 0) ? 0 : \
1678 (guint32)(b) > ((G_MAXUINT32) / (guint32)(a))
1680 #define CHECK_MUL_OVERFLOW64(a,b) \
1681 ((gint64)(a) == 0) || ((gint64)(b) == 0) ? 0 : \
1682 (((gint64)(a) > 0) && ((gint64)(b) == -1)) ? FALSE : \
1683 (((gint64)(a) < 0) && ((gint64)(b) == -1)) ? (a == G_MININT64) : \
1684 (((gint64)(a) > 0) && ((gint64)(b) > 0)) ? (gint64)(a) > ((G_MAXINT64) / (gint64)(b)) : \
1685 (((gint64)(a) > 0) && ((gint64)(b) < 0)) ? (gint64)(a) > ((G_MININT64) / (gint64)(b)) : \
1686 (((gint64)(a) < 0) && ((gint64)(b) > 0)) ? (gint64)(a) < ((G_MININT64) / (gint64)(b)) : \
1687 (gint64)(a) < ((G_MAXINT64) / (gint64)(b))
1689 #define CHECK_MUL_OVERFLOW64_UN(a,b) \
1690 ((guint64)(a) == 0) || ((guint64)(b) == 0) ? 0 : \
1691 (guint64)(b) > ((G_MAXUINT64) / (guint64)(a))
1693 #if SIZEOF_VOID_P == 4
1694 #define CHECK_MUL_OVERFLOW_NAT(a,b) CHECK_MUL_OVERFLOW(a,b)
1695 #define CHECK_MUL_OVERFLOW_NAT_UN(a,b) CHECK_MUL_OVERFLOW_UN(a,b)
1696 #else
1697 #define CHECK_MUL_OVERFLOW_NAT(a,b) CHECK_MUL_OVERFLOW64(a,b)
1698 #define CHECK_MUL_OVERFLOW_NAT_UN(a,b) CHECK_MUL_OVERFLOW64_UN(a,b)
1699 #endif
1701 static MonoObject*
1702 interp_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError *error)
1704 InterpFrame frame;
1705 ThreadContext *context = get_context ();
1706 MonoMethodSignature *sig = mono_method_signature_internal (method);
1707 MonoClass *klass = mono_class_from_mono_type_internal (sig->ret);
1708 stackval result;
1709 MonoMethod *target_method = method;
1711 error_init (error);
1712 if (exc)
1713 *exc = NULL;
1715 frame.ex = NULL;
1717 MonoDomain *domain = mono_domain_get ();
1719 if (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
1720 target_method = mono_marshal_get_native_wrapper (target_method, FALSE, FALSE);
1721 MonoMethod *invoke_wrapper = mono_marshal_get_runtime_invoke_full (target_method, FALSE, TRUE);
1723 //* <code>MonoObject *runtime_invoke (MonoObject *this_obj, void **params, MonoObject **exc, void* method)</code>
1725 result.data.vt = alloca (mono_class_instance_size (klass));
1726 stackval args [4];
1728 if (sig->hasthis)
1729 args [0].data.p = obj;
1730 else
1731 args [0].data.p = NULL;
1732 args [1].data.p = params;
1733 args [2].data.p = exc;
1734 args [3].data.p = target_method;
1736 INIT_FRAME (&frame, NULL, args, &result, domain, invoke_wrapper, error);
1738 interp_exec_method (&frame, context, error);
1740 if (frame.ex) {
1741 if (exc) {
1742 *exc = (MonoObject*) frame.ex;
1743 return NULL;
1745 mono_error_set_exception_instance (error, frame.ex);
1746 return NULL;
1748 return (MonoObject*)result.data.p;
1751 typedef struct {
1752 InterpMethod *rmethod;
1753 gpointer this_arg;
1754 gpointer res;
1755 gpointer args [16];
1756 gpointer *many_args;
1757 } InterpEntryData;
1759 /* Main function for entering the interpreter from compiled code */
1760 static void
1761 interp_entry (InterpEntryData *data)
1763 InterpFrame frame;
1764 InterpMethod *rmethod;
1765 ThreadContext *context;
1766 stackval result;
1767 stackval *args;
1768 MonoMethod *method;
1769 MonoMethodSignature *sig;
1770 MonoType *type;
1771 gpointer orig_domain = NULL, attach_cookie;
1772 int i;
1774 if ((gsize)data->rmethod & 1) {
1775 /* Unbox */
1776 data->this_arg = mono_object_unbox_internal ((MonoObject*)data->this_arg);
1777 data->rmethod = (InterpMethod*)(gpointer)((gsize)data->rmethod & ~1);
1779 rmethod = data->rmethod;
1781 if (rmethod->needs_thread_attach)
1782 orig_domain = mono_threads_attach_coop (mono_domain_get (), &attach_cookie);
1784 context = get_context ();
1786 method = rmethod->method;
1787 sig = mono_method_signature_internal (method);
1789 // FIXME: Optimize this
1791 //printf ("%s\n", mono_method_full_name (method, 1));
1793 frame.ex = NULL;
1795 args = g_newa (stackval, sig->param_count + (sig->hasthis ? 1 : 0));
1796 if (sig->hasthis)
1797 args [0].data.p = data->this_arg;
1799 gpointer *params;
1800 if (data->many_args)
1801 params = data->many_args;
1802 else
1803 params = data->args;
1804 for (i = 0; i < sig->param_count; ++i) {
1805 int a_index = i + (sig->hasthis ? 1 : 0);
1806 if (sig->params [i]->byref) {
1807 args [a_index].data.p = params [i];
1808 continue;
1810 type = rmethod->param_types [i];
1811 switch (type->type) {
1812 case MONO_TYPE_VALUETYPE:
1813 args [a_index].data.p = params [i];
1814 break;
1815 case MONO_TYPE_GENERICINST:
1816 if (MONO_TYPE_IS_REFERENCE (type))
1817 args [a_index].data.p = *(gpointer*)params [i];
1818 else
1819 args [a_index].data.vt = params [i];
1820 break;
1821 default:
1822 stackval_from_data (type, &args [a_index], params [i], FALSE);
1823 break;
1827 memset (&result, 0, sizeof (result));
1828 init_frame (&frame, NULL, data->rmethod, args, &result);
1830 type = rmethod->rtype;
1831 switch (type->type) {
1832 case MONO_TYPE_GENERICINST:
1833 if (!MONO_TYPE_IS_REFERENCE (type))
1834 frame.retval->data.vt = data->res;
1835 break;
1836 case MONO_TYPE_VALUETYPE:
1837 frame.retval->data.vt = data->res;
1838 break;
1839 default:
1840 break;
1843 ERROR_DECL (error);
1844 interp_exec_method (&frame, context, error);
1846 if (rmethod->needs_thread_attach)
1847 mono_threads_detach_coop (orig_domain, &attach_cookie);
1849 if (mono_llvm_only) {
1850 if (frame.ex)
1851 mono_llvm_reraise_exception (frame.ex);
1852 } else {
1853 g_assert (frame.ex == NULL);
1856 type = rmethod->rtype;
1857 switch (type->type) {
1858 case MONO_TYPE_VOID:
1859 break;
1860 case MONO_TYPE_OBJECT:
1861 /* No need for a write barrier */
1862 *(MonoObject**)data->res = (MonoObject*)frame.retval->data.p;
1863 break;
1864 case MONO_TYPE_GENERICINST:
1865 if (MONO_TYPE_IS_REFERENCE (type)) {
1866 *(MonoObject**)data->res = (MonoObject*)frame.retval->data.p;
1867 } else {
1868 /* Already set before the call */
1870 break;
1871 case MONO_TYPE_VALUETYPE:
1872 /* Already set before the call */
1873 break;
1874 default:
1875 stackval_to_data (type, frame.retval, data->res, FALSE);
1876 break;
1880 static stackval *
1881 do_icall (InterpFrame *frame, MonoMethodSignature *sig, int op, stackval *sp, gpointer ptr, gboolean save_last_error)
1883 #ifdef ENABLE_NETCORE
1884 if (save_last_error)
1885 mono_marshal_clear_last_error ();
1886 #endif
1888 switch (op) {
1889 case MINT_ICALL_V_V: {
1890 typedef void (*T)(void);
1891 T func = (T)ptr;
1892 func ();
1893 break;
1895 case MINT_ICALL_V_P: {
1896 typedef gpointer (*T)(void);
1897 T func = (T)ptr;
1898 sp++;
1899 sp [-1].data.p = func ();
1900 break;
1902 case MINT_ICALL_P_V: {
1903 typedef void (*T)(gpointer);
1904 T func = (T)ptr;
1905 func (sp [-1].data.p);
1906 sp --;
1907 break;
1909 case MINT_ICALL_P_P: {
1910 typedef gpointer (*T)(gpointer);
1911 T func = (T)ptr;
1912 sp [-1].data.p = func (sp [-1].data.p);
1913 break;
1915 case MINT_ICALL_PP_V: {
1916 typedef void (*T)(gpointer,gpointer);
1917 T func = (T)ptr;
1918 sp -= 2;
1919 func (sp [0].data.p, sp [1].data.p);
1920 break;
1922 case MINT_ICALL_PP_P: {
1923 typedef gpointer (*T)(gpointer,gpointer);
1924 T func = (T)ptr;
1925 --sp;
1926 sp [-1].data.p = func (sp [-1].data.p, sp [0].data.p);
1927 break;
1929 case MINT_ICALL_PPP_V: {
1930 typedef void (*T)(gpointer,gpointer,gpointer);
1931 T func = (T)ptr;
1932 sp -= 3;
1933 func (sp [0].data.p, sp [1].data.p, sp [2].data.p);
1934 break;
1936 case MINT_ICALL_PPP_P: {
1937 typedef gpointer (*T)(gpointer,gpointer,gpointer);
1938 T func = (T)ptr;
1939 sp -= 2;
1940 sp [-1].data.p = func (sp [-1].data.p, sp [0].data.p, sp [1].data.p);
1941 break;
1943 case MINT_ICALL_PPPP_V: {
1944 typedef void (*T)(gpointer,gpointer,gpointer,gpointer);
1945 T func = (T)ptr;
1946 sp -= 4;
1947 func (sp [0].data.p, sp [1].data.p, sp [2].data.p, sp [3].data.p);
1948 break;
1950 case MINT_ICALL_PPPP_P: {
1951 typedef gpointer (*T)(gpointer,gpointer,gpointer,gpointer);
1952 T func = (T)ptr;
1953 sp -= 3;
1954 sp [-1].data.p = func (sp [-1].data.p, sp [0].data.p, sp [1].data.p, sp [2].data.p);
1955 break;
1957 case MINT_ICALL_PPPPP_V: {
1958 typedef void (*T)(gpointer,gpointer,gpointer,gpointer,gpointer);
1959 T func = (T)ptr;
1960 sp -= 5;
1961 func (sp [0].data.p, sp [1].data.p, sp [2].data.p, sp [3].data.p, sp [4].data.p);
1962 break;
1964 case MINT_ICALL_PPPPP_P: {
1965 typedef gpointer (*T)(gpointer,gpointer,gpointer,gpointer,gpointer);
1966 T func = (T)ptr;
1967 sp -= 4;
1968 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);
1969 break;
1971 case MINT_ICALL_PPPPPP_V: {
1972 typedef void (*T)(gpointer,gpointer,gpointer,gpointer,gpointer,gpointer);
1973 T func = (T)ptr;
1974 sp -= 6;
1975 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);
1976 break;
1978 case MINT_ICALL_PPPPPP_P: {
1979 typedef gpointer (*T)(gpointer,gpointer,gpointer,gpointer,gpointer,gpointer);
1980 T func = (T)ptr;
1981 sp -= 5;
1982 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);
1983 break;
1985 default:
1986 g_assert_not_reached ();
1989 if (save_last_error)
1990 mono_marshal_set_last_error ();
1992 /* convert the native representation to the stackval representation */
1993 if (sig)
1994 stackval_from_data (sig->ret, &sp [-1], (char*) &sp [-1].data.p, sig->pinvoke);
1996 return sp;
1999 /* MONO_NO_OPTIMIATION is needed due to usage of INTERP_PUSH_LMF_WITH_CTX. */
2000 #ifdef _MSC_VER
2001 #pragma optimize ("", off)
2002 #endif
2003 static MONO_NO_OPTIMIZATION MONO_NEVER_INLINE stackval *
2004 do_icall_wrapper (InterpFrame *frame, MonoMethodSignature *sig, int op, stackval *sp, gpointer ptr, gboolean save_last_error)
2006 MonoLMFExt ext;
2007 INTERP_PUSH_LMF_WITH_CTX (frame, ext, exit_icall);
2009 sp = do_icall (frame, sig, op, sp, ptr, save_last_error);
2011 interp_pop_lmf (&ext);
2013 goto exit_icall; // prevent unused label warning in some configurations
2014 exit_icall:
2015 return sp;
2017 #ifdef _MSC_VER
2018 #pragma optimize ("", on)
2019 #endif
2021 typedef struct {
2022 int pindex;
2023 gpointer jit_wrapper;
2024 gpointer *args;
2025 MonoFtnDesc *ftndesc;
2026 } JitCallCbData;
2028 static void
2029 jit_call_cb (gpointer arg)
2031 JitCallCbData *cb_data = (JitCallCbData*)arg;
2032 gpointer jit_wrapper = cb_data->jit_wrapper;
2033 int pindex = cb_data->pindex;
2034 gpointer *args = cb_data->args;
2035 MonoFtnDesc ftndesc = *cb_data->ftndesc;
2037 switch (pindex) {
2038 case 0: {
2039 typedef void (*T)(gpointer);
2040 T func = (T)jit_wrapper;
2042 func (&ftndesc);
2043 break;
2045 case 1: {
2046 typedef void (*T)(gpointer, gpointer);
2047 T func = (T)jit_wrapper;
2049 func (args [0], &ftndesc);
2050 break;
2052 case 2: {
2053 typedef void (*T)(gpointer, gpointer, gpointer);
2054 T func = (T)jit_wrapper;
2056 func (args [0], args [1], &ftndesc);
2057 break;
2059 case 3: {
2060 typedef void (*T)(gpointer, gpointer, gpointer, gpointer);
2061 T func = (T)jit_wrapper;
2063 func (args [0], args [1], args [2], &ftndesc);
2064 break;
2066 case 4: {
2067 typedef void (*T)(gpointer, gpointer, gpointer, gpointer, gpointer);
2068 T func = (T)jit_wrapper;
2070 func (args [0], args [1], args [2], args [3], &ftndesc);
2071 break;
2073 case 5: {
2074 typedef void (*T)(gpointer, gpointer, gpointer, gpointer, gpointer, gpointer);
2075 T func = (T)jit_wrapper;
2077 func (args [0], args [1], args [2], args [3], args [4], &ftndesc);
2078 break;
2080 case 6: {
2081 typedef void (*T)(gpointer, gpointer, gpointer, gpointer, gpointer, gpointer, gpointer);
2082 T func = (T)jit_wrapper;
2084 func (args [0], args [1], args [2], args [3], args [4], args [5], &ftndesc);
2085 break;
2087 case 7: {
2088 typedef void (*T)(gpointer, gpointer, gpointer, gpointer, gpointer, gpointer, gpointer, gpointer);
2089 T func = (T)jit_wrapper;
2091 func (args [0], args [1], args [2], args [3], args [4], args [5], args [6], &ftndesc);
2092 break;
2094 case 8: {
2095 typedef void (*T)(gpointer, gpointer, gpointer, gpointer, gpointer, gpointer, gpointer, gpointer, gpointer);
2096 T func = (T)jit_wrapper;
2098 func (args [0], args [1], args [2], args [3], args [4], args [5], args [6], args [7], &ftndesc);
2099 break;
2101 default:
2102 g_assert_not_reached ();
2103 break;
2107 static MONO_NEVER_INLINE stackval *
2108 do_jit_call (stackval *sp, unsigned char *vt_sp, ThreadContext *context, InterpFrame *frame, InterpMethod *rmethod, MonoError *error)
2110 MonoMethodSignature *sig;
2111 MonoFtnDesc ftndesc;
2112 guint8 res_buf [256];
2113 MonoType *type;
2114 MonoLMFExt ext;
2116 //printf ("jit_call: %s\n", mono_method_full_name (rmethod->method, 1));
2119 * Call JITted code through a gsharedvt_out wrapper. These wrappers receive every argument
2120 * by ref and return a return value using an explicit return value argument.
2122 if (!rmethod->jit_wrapper) {
2123 MonoMethod *method = rmethod->method;
2125 sig = mono_method_signature_internal (method);
2126 g_assert (sig);
2128 MonoMethod *wrapper = mini_get_gsharedvt_out_sig_wrapper (sig);
2129 //printf ("J: %s %s\n", mono_method_full_name (method, 1), mono_method_full_name (wrapper, 1));
2131 gpointer jit_wrapper = mono_jit_compile_method_jit_only (wrapper, error);
2132 mono_error_assert_ok (error);
2134 gpointer addr = mono_jit_compile_method_jit_only (method, error);
2135 return_val_if_nok (error, NULL);
2136 g_assert (addr);
2138 rmethod->jit_addr = addr;
2139 rmethod->jit_sig = sig;
2140 mono_memory_barrier ();
2141 rmethod->jit_wrapper = jit_wrapper;
2143 } else {
2144 sig = rmethod->jit_sig;
2147 sp -= sig->param_count;
2148 if (sig->hasthis)
2149 --sp;
2151 ftndesc.addr = rmethod->jit_addr;
2152 ftndesc.arg = NULL;
2154 // FIXME: Optimize this
2156 gpointer args [32];
2157 int pindex = 0;
2158 int stack_index = 0;
2159 if (rmethod->hasthis) {
2160 args [pindex ++] = sp [0].data.p;
2161 stack_index ++;
2163 type = rmethod->rtype;
2164 if (type->type != MONO_TYPE_VOID) {
2165 if (MONO_TYPE_ISSTRUCT (type))
2166 args [pindex ++] = vt_sp;
2167 else
2168 args [pindex ++] = res_buf;
2170 for (int i = 0; i < rmethod->param_count; ++i) {
2171 MonoType *t = rmethod->param_types [i];
2172 stackval *sval = &sp [stack_index + i];
2173 if (sig->params [i]->byref) {
2174 args [pindex ++] = sval->data.p;
2175 } else if (MONO_TYPE_ISSTRUCT (t)) {
2176 args [pindex ++] = sval->data.p;
2177 } else if (MONO_TYPE_IS_REFERENCE (t)) {
2178 args [pindex ++] = &sval->data.p;
2179 } else {
2180 switch (t->type) {
2181 case MONO_TYPE_I1:
2182 case MONO_TYPE_U1:
2183 case MONO_TYPE_I2:
2184 case MONO_TYPE_U2:
2185 case MONO_TYPE_I4:
2186 case MONO_TYPE_U4:
2187 case MONO_TYPE_VALUETYPE:
2188 args [pindex ++] = &sval->data.i;
2189 break;
2190 case MONO_TYPE_PTR:
2191 case MONO_TYPE_FNPTR:
2192 case MONO_TYPE_I:
2193 case MONO_TYPE_U:
2194 case MONO_TYPE_OBJECT:
2195 args [pindex ++] = &sval->data.p;
2196 break;
2197 case MONO_TYPE_I8:
2198 case MONO_TYPE_U8:
2199 args [pindex ++] = &sval->data.l;
2200 break;
2201 case MONO_TYPE_R4:
2202 args [pindex ++] = &sval->data.f_r4;
2203 break;
2204 case MONO_TYPE_R8:
2205 args [pindex ++] = &sval->data.f;
2206 break;
2207 default:
2208 printf ("%s\n", mono_type_full_name (t));
2209 g_assert_not_reached ();
2214 interp_push_lmf (&ext, frame);
2216 JitCallCbData cb_data;
2217 memset (&cb_data, 0, sizeof (cb_data));
2218 cb_data.jit_wrapper = rmethod->jit_wrapper;
2219 cb_data.pindex = pindex;
2220 cb_data.args = args;
2221 cb_data.ftndesc = &ftndesc;
2223 if (mono_aot_mode == MONO_AOT_MODE_LLVMONLY_INTERP) {
2224 /* Catch the exception thrown by the native code using a try-catch */
2225 gboolean thrown = FALSE;
2226 mono_llvm_cpp_catch_exception (jit_call_cb, &cb_data, &thrown);
2227 interp_pop_lmf (&ext);
2228 if (thrown) {
2229 MonoObject *obj = mono_llvm_load_exception ();
2230 g_assert (obj);
2231 mono_error_set_exception_instance (error, (MonoException*)obj);
2232 return sp;
2234 } else {
2235 jit_call_cb (&cb_data);
2236 interp_pop_lmf (&ext);
2239 MonoType *rtype = rmethod->rtype;
2240 switch (rtype->type) {
2241 case MONO_TYPE_VOID:
2242 case MONO_TYPE_OBJECT:
2243 case MONO_TYPE_STRING:
2244 case MONO_TYPE_CLASS:
2245 case MONO_TYPE_ARRAY:
2246 case MONO_TYPE_SZARRAY:
2247 case MONO_TYPE_I:
2248 case MONO_TYPE_U:
2249 case MONO_TYPE_PTR:
2250 sp->data.p = *(gpointer*)res_buf;
2251 break;
2252 case MONO_TYPE_I1:
2253 sp->data.i = *(gint8*)res_buf;
2254 break;
2255 case MONO_TYPE_U1:
2256 sp->data.i = *(guint8*)res_buf;
2257 break;
2258 case MONO_TYPE_I2:
2259 sp->data.i = *(gint16*)res_buf;
2260 break;
2261 case MONO_TYPE_U2:
2262 sp->data.i = *(guint16*)res_buf;
2263 break;
2264 case MONO_TYPE_I4:
2265 sp->data.i = *(gint32*)res_buf;
2266 break;
2267 case MONO_TYPE_U4:
2268 sp->data.i = *(guint32*)res_buf;
2269 break;
2270 case MONO_TYPE_I8:
2271 sp->data.l = *(gint64*)res_buf;
2272 break;
2273 case MONO_TYPE_U8:
2274 sp->data.l = *(guint64*)res_buf;
2275 break;
2276 case MONO_TYPE_R4:
2277 sp->data.f_r4 = *(float*)res_buf;
2278 break;
2279 case MONO_TYPE_R8:
2280 sp->data.f = *(double*)res_buf;
2281 break;
2282 case MONO_TYPE_TYPEDBYREF:
2283 case MONO_TYPE_VALUETYPE:
2284 /* The result was written to vt_sp */
2285 sp->data.p = vt_sp;
2286 break;
2287 case MONO_TYPE_GENERICINST:
2288 if (MONO_TYPE_IS_REFERENCE (rtype)) {
2289 sp->data.p = *(gpointer*)res_buf;
2290 } else {
2291 /* The result was written to vt_sp */
2292 sp->data.p = vt_sp;
2294 break;
2295 default:
2296 g_print ("%s\n", mono_type_full_name (rtype));
2297 g_assert_not_reached ();
2298 break;
2301 return sp;
2304 static MONO_NEVER_INLINE void
2305 do_debugger_tramp (void (*tramp) (void), InterpFrame *frame)
2307 MonoLMFExt ext;
2308 interp_push_lmf (&ext, frame);
2309 tramp ();
2310 interp_pop_lmf (&ext);
2313 static MONO_NEVER_INLINE void
2314 do_transform_method (InterpFrame *frame, ThreadContext *context)
2316 MonoLMFExt ext;
2317 /* Don't push lmf if we have no interp data */
2318 gboolean push_lmf = frame->parent != NULL;
2319 ERROR_DECL (error);
2321 /* Use the parent frame as the current frame is not complete yet */
2322 if (push_lmf)
2323 interp_push_lmf (&ext, frame->parent);
2325 mono_interp_transform_method (frame->imethod, context, error);
2326 frame->ex = mono_error_convert_to_exception (error);
2328 if (push_lmf)
2329 interp_pop_lmf (&ext);
2332 static MONO_NEVER_INLINE void
2333 copy_varargs_vtstack (MonoMethodSignature *csig, stackval *sp, unsigned char **vt_sp)
2335 char *vt = *(char**)vt_sp;
2336 stackval *first_arg = sp - csig->param_count;
2339 * We need to have the varargs linearly on the stack so the ArgIterator
2340 * can iterate over them. We pass the signature first and then copy them
2341 * one by one on the vtstack.
2343 *(gpointer*)vt = csig;
2344 vt += sizeof (gpointer);
2346 for (int i = csig->sentinelpos; i < csig->param_count; i++) {
2347 int align, arg_size;
2348 arg_size = mono_type_stack_size (csig->params [i], &align);
2349 vt = (char*)ALIGN_PTR_TO (vt, align);
2351 stackval_to_data (csig->params [i], &first_arg [i], vt, FALSE);
2352 vt += arg_size;
2355 vt = (char*)ALIGN_PTR_TO (vt, MINT_VT_ALIGNMENT);
2357 *(char**)vt_sp = vt;
2361 * These functions are the entry points into the interpreter from compiled code.
2362 * They are called by the interp_in wrappers. They have the following signature:
2363 * void (<optional this_arg>, <optional retval pointer>, <arg1>, ..., <argn>, <method ptr>)
2364 * They pack up their arguments into an InterpEntryData structure and call interp_entry ().
2365 * It would be possible for the wrappers to pack up the arguments etc, but that would make them bigger, and there are
2366 * more wrappers then these functions.
2367 * this/static * ret/void * 16 arguments -> 64 functions.
2370 #define MAX_INTERP_ENTRY_ARGS 8
2372 #define INTERP_ENTRY_BASE(_method, _this_arg, _res) \
2373 InterpEntryData data; \
2374 (data).rmethod = (_method); \
2375 (data).res = (_res); \
2376 (data).this_arg = (_this_arg); \
2377 (data).many_args = NULL;
2379 #define INTERP_ENTRY0(_this_arg, _res, _method) { \
2380 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2381 interp_entry (&data); \
2383 #define INTERP_ENTRY1(_this_arg, _res, _method) { \
2384 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2385 (data).args [0] = arg1; \
2386 interp_entry (&data); \
2388 #define INTERP_ENTRY2(_this_arg, _res, _method) { \
2389 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2390 (data).args [0] = arg1; \
2391 (data).args [1] = arg2; \
2392 interp_entry (&data); \
2394 #define INTERP_ENTRY3(_this_arg, _res, _method) { \
2395 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2396 (data).args [0] = arg1; \
2397 (data).args [1] = arg2; \
2398 (data).args [2] = arg3; \
2399 interp_entry (&data); \
2401 #define INTERP_ENTRY4(_this_arg, _res, _method) { \
2402 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2403 (data).args [0] = arg1; \
2404 (data).args [1] = arg2; \
2405 (data).args [2] = arg3; \
2406 (data).args [3] = arg4; \
2407 interp_entry (&data); \
2409 #define INTERP_ENTRY5(_this_arg, _res, _method) { \
2410 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2411 (data).args [0] = arg1; \
2412 (data).args [1] = arg2; \
2413 (data).args [2] = arg3; \
2414 (data).args [3] = arg4; \
2415 (data).args [4] = arg5; \
2416 interp_entry (&data); \
2418 #define INTERP_ENTRY6(_this_arg, _res, _method) { \
2419 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2420 (data).args [0] = arg1; \
2421 (data).args [1] = arg2; \
2422 (data).args [2] = arg3; \
2423 (data).args [3] = arg4; \
2424 (data).args [4] = arg5; \
2425 (data).args [5] = arg6; \
2426 interp_entry (&data); \
2428 #define INTERP_ENTRY7(_this_arg, _res, _method) { \
2429 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2430 (data).args [0] = arg1; \
2431 (data).args [1] = arg2; \
2432 (data).args [2] = arg3; \
2433 (data).args [3] = arg4; \
2434 (data).args [4] = arg5; \
2435 (data).args [5] = arg6; \
2436 (data).args [6] = arg7; \
2437 interp_entry (&data); \
2439 #define INTERP_ENTRY8(_this_arg, _res, _method) { \
2440 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2441 (data).args [0] = arg1; \
2442 (data).args [1] = arg2; \
2443 (data).args [2] = arg3; \
2444 (data).args [3] = arg4; \
2445 (data).args [4] = arg5; \
2446 (data).args [5] = arg6; \
2447 (data).args [6] = arg7; \
2448 (data).args [7] = arg8; \
2449 interp_entry (&data); \
2452 #define ARGLIST0 InterpMethod *rmethod
2453 #define ARGLIST1 gpointer arg1, InterpMethod *rmethod
2454 #define ARGLIST2 gpointer arg1, gpointer arg2, InterpMethod *rmethod
2455 #define ARGLIST3 gpointer arg1, gpointer arg2, gpointer arg3, InterpMethod *rmethod
2456 #define ARGLIST4 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, InterpMethod *rmethod
2457 #define ARGLIST5 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, gpointer arg5, InterpMethod *rmethod
2458 #define ARGLIST6 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, gpointer arg5, gpointer arg6, InterpMethod *rmethod
2459 #define ARGLIST7 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, gpointer arg5, gpointer arg6, gpointer arg7, InterpMethod *rmethod
2460 #define ARGLIST8 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, gpointer arg5, gpointer arg6, gpointer arg7, gpointer arg8, InterpMethod *rmethod
2462 static void interp_entry_static_0 (ARGLIST0) INTERP_ENTRY0 (NULL, NULL, rmethod)
2463 static void interp_entry_static_1 (ARGLIST1) INTERP_ENTRY1 (NULL, NULL, rmethod)
2464 static void interp_entry_static_2 (ARGLIST2) INTERP_ENTRY2 (NULL, NULL, rmethod)
2465 static void interp_entry_static_3 (ARGLIST3) INTERP_ENTRY3 (NULL, NULL, rmethod)
2466 static void interp_entry_static_4 (ARGLIST4) INTERP_ENTRY4 (NULL, NULL, rmethod)
2467 static void interp_entry_static_5 (ARGLIST5) INTERP_ENTRY5 (NULL, NULL, rmethod)
2468 static void interp_entry_static_6 (ARGLIST6) INTERP_ENTRY6 (NULL, NULL, rmethod)
2469 static void interp_entry_static_7 (ARGLIST7) INTERP_ENTRY7 (NULL, NULL, rmethod)
2470 static void interp_entry_static_8 (ARGLIST8) INTERP_ENTRY8 (NULL, NULL, rmethod)
2471 static void interp_entry_static_ret_0 (gpointer res, ARGLIST0) INTERP_ENTRY0 (NULL, res, rmethod)
2472 static void interp_entry_static_ret_1 (gpointer res, ARGLIST1) INTERP_ENTRY1 (NULL, res, rmethod)
2473 static void interp_entry_static_ret_2 (gpointer res, ARGLIST2) INTERP_ENTRY2 (NULL, res, rmethod)
2474 static void interp_entry_static_ret_3 (gpointer res, ARGLIST3) INTERP_ENTRY3 (NULL, res, rmethod)
2475 static void interp_entry_static_ret_4 (gpointer res, ARGLIST4) INTERP_ENTRY4 (NULL, res, rmethod)
2476 static void interp_entry_static_ret_5 (gpointer res, ARGLIST5) INTERP_ENTRY5 (NULL, res, rmethod)
2477 static void interp_entry_static_ret_6 (gpointer res, ARGLIST6) INTERP_ENTRY6 (NULL, res, rmethod)
2478 static void interp_entry_static_ret_7 (gpointer res, ARGLIST7) INTERP_ENTRY7 (NULL, res, rmethod)
2479 static void interp_entry_static_ret_8 (gpointer res, ARGLIST8) INTERP_ENTRY8 (NULL, res, rmethod)
2480 static void interp_entry_instance_0 (gpointer this_arg, ARGLIST0) INTERP_ENTRY0 (this_arg, NULL, rmethod)
2481 static void interp_entry_instance_1 (gpointer this_arg, ARGLIST1) INTERP_ENTRY1 (this_arg, NULL, rmethod)
2482 static void interp_entry_instance_2 (gpointer this_arg, ARGLIST2) INTERP_ENTRY2 (this_arg, NULL, rmethod)
2483 static void interp_entry_instance_3 (gpointer this_arg, ARGLIST3) INTERP_ENTRY3 (this_arg, NULL, rmethod)
2484 static void interp_entry_instance_4 (gpointer this_arg, ARGLIST4) INTERP_ENTRY4 (this_arg, NULL, rmethod)
2485 static void interp_entry_instance_5 (gpointer this_arg, ARGLIST5) INTERP_ENTRY5 (this_arg, NULL, rmethod)
2486 static void interp_entry_instance_6 (gpointer this_arg, ARGLIST6) INTERP_ENTRY6 (this_arg, NULL, rmethod)
2487 static void interp_entry_instance_7 (gpointer this_arg, ARGLIST7) INTERP_ENTRY7 (this_arg, NULL, rmethod)
2488 static void interp_entry_instance_8 (gpointer this_arg, ARGLIST8) INTERP_ENTRY8 (this_arg, NULL, rmethod)
2489 static void interp_entry_instance_ret_0 (gpointer this_arg, gpointer res, ARGLIST0) INTERP_ENTRY0 (this_arg, res, rmethod)
2490 static void interp_entry_instance_ret_1 (gpointer this_arg, gpointer res, ARGLIST1) INTERP_ENTRY1 (this_arg, res, rmethod)
2491 static void interp_entry_instance_ret_2 (gpointer this_arg, gpointer res, ARGLIST2) INTERP_ENTRY2 (this_arg, res, rmethod)
2492 static void interp_entry_instance_ret_3 (gpointer this_arg, gpointer res, ARGLIST3) INTERP_ENTRY3 (this_arg, res, rmethod)
2493 static void interp_entry_instance_ret_4 (gpointer this_arg, gpointer res, ARGLIST4) INTERP_ENTRY4 (this_arg, res, rmethod)
2494 static void interp_entry_instance_ret_5 (gpointer this_arg, gpointer res, ARGLIST5) INTERP_ENTRY5 (this_arg, res, rmethod)
2495 static void interp_entry_instance_ret_6 (gpointer this_arg, gpointer res, ARGLIST6) INTERP_ENTRY6 (this_arg, res, rmethod)
2496 static void interp_entry_instance_ret_7 (gpointer this_arg, gpointer res, ARGLIST7) INTERP_ENTRY7 (this_arg, res, rmethod)
2497 static void interp_entry_instance_ret_8 (gpointer this_arg, gpointer res, ARGLIST8) INTERP_ENTRY8 (this_arg, res, rmethod)
2499 #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
2501 static gpointer entry_funcs_static [MAX_INTERP_ENTRY_ARGS + 1] = { INTERP_ENTRY_FUNCLIST (static) };
2502 static gpointer entry_funcs_static_ret [MAX_INTERP_ENTRY_ARGS + 1] = { INTERP_ENTRY_FUNCLIST (static_ret) };
2503 static gpointer entry_funcs_instance [MAX_INTERP_ENTRY_ARGS + 1] = { INTERP_ENTRY_FUNCLIST (instance) };
2504 static gpointer entry_funcs_instance_ret [MAX_INTERP_ENTRY_ARGS + 1] = { INTERP_ENTRY_FUNCLIST (instance_ret) };
2506 /* General version for methods with more than MAX_INTERP_ENTRY_ARGS arguments */
2507 static void
2508 interp_entry_general (gpointer this_arg, gpointer res, gpointer *args, gpointer rmethod)
2510 INTERP_ENTRY_BASE ((InterpMethod*)rmethod, this_arg, res);
2511 data.many_args = args;
2512 interp_entry (&data);
2515 #ifdef MONO_ARCH_HAVE_INTERP_ENTRY_TRAMPOLINE
2517 // inline so we can alloc on stack
2518 #define alloc_storage_for_stackval(s, t, p) do { \
2519 if ((t)->type == MONO_TYPE_GENERICINST && !MONO_TYPE_IS_REFERENCE (t)) { \
2520 (s)->data.vt = alloca (mono_class_value_size (mono_class_from_mono_type_internal (t), NULL)); \
2521 } else if ((t)->type == MONO_TYPE_VALUETYPE) { \
2522 if (p) \
2523 (s)->data.vt = alloca (mono_class_native_size ((t)->data.klass, NULL)); \
2524 else \
2525 (s)->data.vt = alloca (mono_class_value_size ((t)->data.klass, NULL)); \
2527 } while (0)
2529 static void
2530 interp_entry_from_trampoline (gpointer ccontext_untyped, gpointer rmethod_untyped)
2532 InterpFrame frame;
2533 ThreadContext *context;
2534 stackval result;
2535 stackval *args;
2536 MonoMethod *method;
2537 MonoMethodSignature *sig;
2538 CallContext *ccontext = (CallContext*) ccontext_untyped;
2539 InterpMethod *rmethod = (InterpMethod*) rmethod_untyped;
2540 gpointer orig_domain = NULL, attach_cookie;
2541 int i;
2543 if (rmethod->needs_thread_attach)
2544 orig_domain = mono_threads_attach_coop (mono_domain_get (), &attach_cookie);
2546 context = get_context ();
2548 method = rmethod->method;
2549 sig = mono_method_signature_internal (method);
2551 frame.ex = NULL;
2553 args = (stackval*)alloca (sizeof (stackval) * (sig->param_count + (sig->hasthis ? 1 : 0)));
2555 init_frame (&frame, NULL, rmethod, args, &result);
2557 /* Allocate storage for value types */
2558 for (i = 0; i < sig->param_count; i++) {
2559 MonoType *type = sig->params [i];
2560 alloc_storage_for_stackval (&frame.stack_args [i + sig->hasthis], type, sig->pinvoke);
2563 if (sig->ret->type != MONO_TYPE_VOID)
2564 alloc_storage_for_stackval (frame.retval, sig->ret, sig->pinvoke);
2566 /* Copy the args saved in the trampoline to the frame stack */
2567 mono_arch_get_native_call_context_args (ccontext, &frame, sig);
2569 ERROR_DECL (error);
2570 interp_exec_method (&frame, context, error);
2572 if (rmethod->needs_thread_attach)
2573 mono_threads_detach_coop (orig_domain, &attach_cookie);
2575 // FIXME:
2576 g_assert (frame.ex == NULL);
2578 /* Write back the return value */
2579 mono_arch_set_native_call_context_ret (ccontext, &frame, sig);
2582 #else
2584 static void
2585 interp_entry_from_trampoline (gpointer ccontext_untyped, gpointer rmethod_untyped)
2587 g_assert_not_reached ();
2590 #endif /* MONO_ARCH_HAVE_INTERP_ENTRY_TRAMPOLINE */
2592 static InterpMethod*
2593 lookup_method_pointer (gpointer addr)
2595 MonoDomain *domain = mono_domain_get ();
2596 MonoJitDomainInfo *info = domain_jit_info (domain);
2597 InterpMethod *res = NULL;
2599 mono_domain_lock (domain);
2600 if (info->interp_method_pointer_hash)
2601 res = (InterpMethod*)g_hash_table_lookup (info->interp_method_pointer_hash, addr);
2602 mono_domain_unlock (domain);
2604 return res;
2607 #ifndef MONO_ARCH_HAVE_INTERP_NATIVE_TO_MANAGED
2608 static void
2609 interp_no_native_to_managed (void)
2611 g_error ("interpreter: native-to-managed transition not available on this platform");
2613 #endif
2615 static void
2616 no_llvmonly_interp_method_pointer (void)
2618 g_assert_not_reached ();
2622 * interp_create_method_pointer_llvmonly:
2624 * Return an ftndesc for entering the interpreter and executing METHOD.
2626 static MonoFtnDesc*
2627 interp_create_method_pointer_llvmonly (MonoMethod *method, gboolean unbox, MonoError *error)
2629 MonoDomain *domain = mono_domain_get ();
2630 gpointer addr, entry_func, entry_wrapper;
2631 MonoMethodSignature *sig;
2632 MonoMethod *wrapper;
2633 MonoJitDomainInfo *info;
2634 InterpMethod *imethod;
2636 imethod = mono_interp_get_imethod (domain, method, error);
2637 return_val_if_nok (error, NULL);
2639 if (unbox) {
2640 if (imethod->llvmonly_unbox_entry)
2641 return (MonoFtnDesc*)imethod->llvmonly_unbox_entry;
2642 } else {
2643 if (imethod->jit_entry)
2644 return (MonoFtnDesc*)imethod->jit_entry;
2647 sig = mono_method_signature_internal (method);
2650 * The entry functions need access to the method to call, so we have
2651 * to use a ftndesc. The caller uses a normal signature, while the
2652 * entry functions use a gsharedvt_in signature, so wrap the entry function in
2653 * a gsharedvt_in_sig wrapper.
2655 wrapper = mini_get_gsharedvt_in_sig_wrapper (sig);
2657 entry_wrapper = mono_jit_compile_method_jit_only (wrapper, error);
2658 mono_error_assertf_ok (error, "couldn't compile wrapper \"%s\" for \"%s\"",
2659 mono_method_get_name_full (wrapper, TRUE, TRUE, MONO_TYPE_NAME_FORMAT_IL),
2660 mono_method_get_name_full (method, TRUE, TRUE, MONO_TYPE_NAME_FORMAT_IL));
2662 if (sig->param_count > MAX_INTERP_ENTRY_ARGS) {
2663 g_assert_not_reached ();
2664 //entry_func = (gpointer)interp_entry_general;
2665 } else if (sig->hasthis) {
2666 if (sig->ret->type == MONO_TYPE_VOID)
2667 entry_func = entry_funcs_instance [sig->param_count];
2668 else
2669 entry_func = entry_funcs_instance_ret [sig->param_count];
2670 } else {
2671 if (sig->ret->type == MONO_TYPE_VOID)
2672 entry_func = entry_funcs_static [sig->param_count];
2673 else
2674 entry_func = entry_funcs_static_ret [sig->param_count];
2676 g_assert (entry_func);
2678 /* Encode unbox in the lower bit of imethod */
2679 gpointer entry_arg = imethod;
2680 if (unbox)
2681 entry_arg = (gpointer)(((gsize)entry_arg) | 1);
2682 MonoFtnDesc *entry_ftndesc = mini_llvmonly_create_ftndesc (mono_domain_get (), entry_func, entry_arg);
2684 addr = mini_llvmonly_create_ftndesc (mono_domain_get (), entry_wrapper, entry_ftndesc);
2686 info = domain_jit_info (domain);
2687 mono_domain_lock (domain);
2688 if (!info->interp_method_pointer_hash)
2689 info->interp_method_pointer_hash = g_hash_table_new (NULL, NULL);
2690 g_hash_table_insert (info->interp_method_pointer_hash, addr, imethod);
2691 mono_domain_unlock (domain);
2693 mono_memory_barrier ();
2694 if (unbox)
2695 imethod->llvmonly_unbox_entry = addr;
2696 else
2697 imethod->jit_entry = addr;
2699 return (MonoFtnDesc*)addr;
2703 * interp_create_method_pointer:
2705 * Return a function pointer which can be used to call METHOD using the
2706 * interpreter. Return NULL for methods which are not supported.
2708 static gpointer
2709 interp_create_method_pointer (MonoMethod *method, gboolean compile, MonoError *error)
2711 #ifndef MONO_ARCH_HAVE_INTERP_NATIVE_TO_MANAGED
2712 if (mono_llvm_only)
2713 return (gpointer)no_llvmonly_interp_method_pointer;
2714 return (gpointer)interp_no_native_to_managed;
2715 #else
2716 gpointer addr, entry_func, entry_wrapper = NULL;
2717 MonoDomain *domain = mono_domain_get ();
2718 MonoJitDomainInfo *info;
2719 InterpMethod *imethod = mono_interp_get_imethod (domain, method, error);
2721 if (mono_llvm_only)
2722 return (gpointer)no_llvmonly_interp_method_pointer;
2724 if (imethod->jit_entry)
2725 return imethod->jit_entry;
2727 if (compile && !imethod->transformed) {
2728 /* Return any errors from method compilation */
2729 mono_interp_transform_method (imethod, get_context (), error);
2730 return_val_if_nok (error, NULL);
2733 MonoMethodSignature *sig = mono_method_signature_internal (method);
2735 if (mono_llvm_only)
2736 /* The caller should call interp_create_method_pointer_llvmonly */
2737 g_assert_not_reached ();
2739 if (method->wrapper_type && method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE)
2740 return imethod;
2742 #ifndef MONO_ARCH_HAVE_FTNPTR_ARG_TRAMPOLINE
2744 * Interp in wrappers get the argument in the rgctx register. If
2745 * MONO_ARCH_HAVE_FTNPTR_ARG_TRAMPOLINE is defined it means that
2746 * on that arch the rgctx register is not scratch, so we use a
2747 * separate temp register. We should update the wrappers for this
2748 * if we really care about those architectures (arm).
2750 MonoMethod *wrapper = mini_get_interp_in_wrapper (sig);
2752 entry_wrapper = mono_jit_compile_method_jit_only (wrapper, error);
2753 #endif
2754 if (entry_wrapper) {
2755 if (sig->param_count > MAX_INTERP_ENTRY_ARGS) {
2756 entry_func = (gpointer)interp_entry_general;
2757 } else if (sig->hasthis) {
2758 if (sig->ret->type == MONO_TYPE_VOID)
2759 entry_func = entry_funcs_instance [sig->param_count];
2760 else
2761 entry_func = entry_funcs_instance_ret [sig->param_count];
2762 } else {
2763 if (sig->ret->type == MONO_TYPE_VOID)
2764 entry_func = entry_funcs_static [sig->param_count];
2765 else
2766 entry_func = entry_funcs_static_ret [sig->param_count];
2768 } else {
2769 #ifndef MONO_ARCH_HAVE_INTERP_ENTRY_TRAMPOLINE
2770 mono_error_assertf_ok (error, "couldn't compile wrapper \"%s\" for \"%s\"",
2771 mono_method_get_name_full (wrapper, TRUE, TRUE, MONO_TYPE_NAME_FORMAT_IL),
2772 mono_method_get_name_full (method, TRUE, TRUE, MONO_TYPE_NAME_FORMAT_IL));
2773 #else
2774 mono_error_cleanup (error);
2775 error_init_reuse (error);
2776 if (!mono_native_to_interp_trampoline) {
2777 if (mono_aot_only) {
2778 mono_native_to_interp_trampoline = (MonoFuncV)mono_aot_get_trampoline ("native_to_interp_trampoline");
2779 } else {
2780 MonoTrampInfo *info;
2781 mono_native_to_interp_trampoline = (MonoFuncV)mono_arch_get_native_to_interp_trampoline (&info);
2782 mono_tramp_info_register (info, NULL);
2785 entry_wrapper = (gpointer)mono_native_to_interp_trampoline;
2786 /* We need the lmf wrapper only when being called from mixed mode */
2787 if (sig->pinvoke)
2788 entry_func = (gpointer)interp_entry_from_trampoline;
2789 else {
2790 static gpointer cached_func = NULL;
2791 if (!cached_func) {
2792 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);
2793 mono_memory_barrier ();
2795 entry_func = cached_func;
2797 #endif
2800 g_assert (entry_func);
2801 /* This is the argument passed to the interp_in wrapper by the static rgctx trampoline */
2802 MonoFtnDesc *ftndesc = g_new0 (MonoFtnDesc, 1);
2803 ftndesc->addr = entry_func;
2804 ftndesc->arg = imethod;
2805 mono_error_assert_ok (error);
2808 * The wrapper is called by compiled code, which doesn't pass the extra argument, so we pass it in the
2809 * rgctx register using a trampoline.
2812 addr = mono_create_ftnptr_arg_trampoline (ftndesc, entry_wrapper);
2814 info = domain_jit_info (domain);
2815 mono_domain_lock (domain);
2816 if (!info->interp_method_pointer_hash)
2817 info->interp_method_pointer_hash = g_hash_table_new (NULL, NULL);
2818 g_hash_table_insert (info->interp_method_pointer_hash, addr, imethod);
2819 mono_domain_unlock (domain);
2821 mono_memory_barrier ();
2822 imethod->jit_entry = addr;
2824 return addr;
2825 #endif
2828 #if COUNT_OPS
2829 static int opcode_counts[512];
2831 #define COUNT_OP(op) opcode_counts[op]++
2832 #else
2833 #define COUNT_OP(op)
2834 #endif
2836 #if DEBUG_INTERP
2837 #define DUMP_INSTR() \
2838 if (tracing > 1) { \
2839 char *ins; \
2840 if (sp > frame->stack) { \
2841 ins = dump_stack (frame->stack, sp); \
2842 } else { \
2843 ins = g_strdup (""); \
2845 sp->data.l = 0; \
2846 output_indent (); \
2847 char *mn = mono_method_full_name (frame->imethod->method, FALSE); \
2848 char *disasm = mono_interp_dis_mintop(imethod->code, ip); \
2849 g_print ("(%p) %s -> %s\t%d:%s\n", mono_thread_internal_current (), mn, disasm, vt_sp - vtalloc, ins); \
2850 g_free (mn); \
2851 g_free (ins); \
2852 g_free (disasm); \
2854 #else
2855 #define DUMP_INSTR()
2856 #endif
2858 #if defined(__GNUC__) && !defined(TARGET_WASM)
2859 #define USE_COMPUTED_GOTO 1
2860 #endif
2861 #if USE_COMPUTED_GOTO
2862 #define MINT_IN_SWITCH(op) COUNT_OP(op); goto *in_labels[op];
2863 #define MINT_IN_CASE(x) LAB_ ## x:
2864 #if DEBUG_INTERP
2865 #define MINT_IN_BREAK if (tracing > 1) goto main_loop; else { COUNT_OP(*ip); goto *in_labels[*ip]; }
2866 #else
2867 #define MINT_IN_BREAK { COUNT_OP(*ip); goto *in_labels[*ip]; }
2868 #endif
2869 #define MINT_IN_DEFAULT mint_default: if (0) goto mint_default; /* make gcc shut up */
2870 #else
2871 #define MINT_IN_SWITCH(op) switch (op)
2872 #define MINT_IN_CASE(x) case x:
2873 #define MINT_IN_BREAK break
2874 #define MINT_IN_DEFAULT default:
2875 #endif
2877 #define INIT_VTABLE(vtable) do { \
2878 if (G_UNLIKELY (!(vtable)->initialized)) { \
2879 mono_runtime_class_init_full ((vtable), error); \
2880 if (!mono_error_ok (error)) \
2881 THROW_EX (mono_error_convert_to_exception (error), ip); \
2883 } while (0);
2886 * GC SAFETY:
2888 * The interpreter executes in gc unsafe (non-preempt) mode. On wasm, the C stack is
2889 * scannable but the wasm stack is not, so to make the code GC safe, the following rules
2890 * should be followed:
2891 * - every objref handled by the code needs to have a copy stored inside InterpFrame,
2892 * in stackval->data.o. For objrefs which are not yet on the IL stack, they can be stored
2893 * in frame->o. This will ensure the objects are pinned. The 'frame' local is assumed
2894 * to be allocated to the C stack and not to registers.
2895 * - minimalize the number of MonoObject* locals/arguments.
2898 #ifdef TARGET_WASM
2899 #define frame_objref(frame) (frame)->o
2900 #else
2901 #define frame_objref(frame) o
2902 #endif
2905 * If EXIT_AT_FINALLY is not -1, exit after exiting the finally clause with that index.
2906 * If BASE_FRAME is not NULL, copy arguments/locals from BASE_FRAME.
2907 * The ERROR argument is used to avoid declaring an error object for every interp frame, its not used
2908 * to return error information.
2910 static void
2911 interp_exec_method_full (InterpFrame *frame, ThreadContext *context, FrameClauseArgs *clause_args, MonoError *error)
2913 InterpFrame child_frame;
2914 GSList *finally_ips = NULL;
2915 const unsigned short *endfinally_ip = NULL;
2916 const unsigned short *ip = NULL;
2917 stackval *sp;
2918 InterpMethod *imethod = NULL;
2919 #if DEBUG_INTERP
2920 gint tracing = global_tracing;
2921 unsigned char *vtalloc;
2922 #else
2923 gint tracing = 0;
2924 #endif
2925 int i32;
2926 unsigned char *vt_sp;
2927 unsigned char *locals = NULL;
2928 // See the comment about GC safety above
2929 MonoObject *o = NULL;
2930 MonoClass *c;
2931 #if USE_COMPUTED_GOTO
2932 static void *in_labels[] = {
2933 #define OPDEF(a,b,c,d) \
2934 &&LAB_ ## a,
2935 #include "mintops.def"
2936 0 };
2937 #endif
2939 frame->ex = NULL;
2940 debug_enter (frame, &tracing);
2942 imethod = frame->imethod;
2943 if (!imethod->transformed) {
2944 #if DEBUG_INTERP
2945 char *mn = mono_method_full_name (imethod->method, TRUE);
2946 g_print ("(%p) Transforming %s\n", mono_thread_internal_current (), mn);
2947 g_free (mn);
2948 #endif
2950 frame->ip = NULL;
2951 do_transform_method (frame, context);
2952 if (frame->ex)
2953 THROW_EX (frame->ex, NULL);
2954 EXCEPTION_CHECKPOINT;
2957 if (!clause_args) {
2958 frame->args = g_newa (char, imethod->alloca_size);
2959 ip = imethod->code;
2960 } else {
2961 ip = clause_args->start_with_ip;
2962 if (clause_args->base_frame) {
2963 frame->args = g_newa (char, imethod->alloca_size);
2964 memcpy (frame->args, clause_args->base_frame->args, imethod->alloca_size);
2967 sp = frame->stack = (stackval *) (char *) frame->args;
2968 vt_sp = (unsigned char *) sp + imethod->stack_size;
2969 #if DEBUG_INTERP
2970 vtalloc = vt_sp;
2971 #endif
2972 locals = (unsigned char *) vt_sp + imethod->vt_stack_size;
2973 frame->locals = locals;
2974 child_frame.parent = frame;
2976 if (clause_args && clause_args->filter_exception) {
2977 sp->data.p = clause_args->filter_exception;
2978 sp++;
2981 //g_print ("(%p) Call %s\n", mono_thread_internal_current (), mono_method_get_full_name (frame->imethod->method));
2984 * using while (ip < end) may result in a 15% performance drop,
2985 * but it may be useful for debug
2987 while (1) {
2988 main_loop:
2989 /* g_assert (sp >= frame->stack); */
2990 /* g_assert(vt_sp - vtalloc <= imethod->vt_stack_size); */
2991 DUMP_INSTR();
2992 MINT_IN_SWITCH (*ip) {
2993 MINT_IN_CASE(MINT_INITLOCALS)
2994 memset (locals, 0, imethod->locals_size);
2995 ++ip;
2996 MINT_IN_BREAK;
2997 MINT_IN_CASE(MINT_NOP)
2998 ++ip;
2999 MINT_IN_BREAK;
3000 MINT_IN_CASE(MINT_NIY)
3001 g_error ("mint_niy: instruction not implemented yet. This shouldn't happen.");
3002 MINT_IN_BREAK;
3003 MINT_IN_CASE(MINT_BREAK)
3004 ++ip;
3005 do_debugger_tramp (mini_get_dbg_callbacks ()->user_break, frame);
3006 MINT_IN_BREAK;
3007 MINT_IN_CASE(MINT_BREAKPOINT)
3008 ++ip;
3009 mono_break ();
3010 MINT_IN_BREAK;
3011 MINT_IN_CASE(MINT_LDNULL)
3012 sp->data.p = NULL;
3013 ++ip;
3014 ++sp;
3015 MINT_IN_BREAK;
3016 MINT_IN_CASE(MINT_ARGLIST)
3017 g_assert (frame->varargs);
3018 sp->data.p = vt_sp;
3019 *(gpointer*)sp->data.p = frame->varargs;
3020 vt_sp += ALIGN_TO (sizeof (gpointer), MINT_VT_ALIGNMENT);
3021 ++ip;
3022 ++sp;
3023 MINT_IN_BREAK;
3024 MINT_IN_CASE(MINT_VTRESULT) {
3025 int ret_size = * (guint16 *)(ip + 1);
3026 unsigned char *ret_vt_sp = vt_sp;
3027 vt_sp -= READ32(ip + 2);
3028 if (ret_size > 0) {
3029 memmove (vt_sp, ret_vt_sp, ret_size);
3030 sp [-1].data.p = vt_sp;
3031 vt_sp += ALIGN_TO (ret_size, MINT_VT_ALIGNMENT);
3033 ip += 4;
3034 MINT_IN_BREAK;
3036 #define LDC(n) do { sp->data.i = (n); ++ip; ++sp; } while (0)
3037 MINT_IN_CASE(MINT_LDC_I4_M1)
3038 LDC(-1);
3039 MINT_IN_BREAK;
3040 MINT_IN_CASE(MINT_LDC_I4_0)
3041 LDC(0);
3042 MINT_IN_BREAK;
3043 MINT_IN_CASE(MINT_LDC_I4_1)
3044 LDC(1);
3045 MINT_IN_BREAK;
3046 MINT_IN_CASE(MINT_LDC_I4_2)
3047 LDC(2);
3048 MINT_IN_BREAK;
3049 MINT_IN_CASE(MINT_LDC_I4_3)
3050 LDC(3);
3051 MINT_IN_BREAK;
3052 MINT_IN_CASE(MINT_LDC_I4_4)
3053 LDC(4);
3054 MINT_IN_BREAK;
3055 MINT_IN_CASE(MINT_LDC_I4_5)
3056 LDC(5);
3057 MINT_IN_BREAK;
3058 MINT_IN_CASE(MINT_LDC_I4_6)
3059 LDC(6);
3060 MINT_IN_BREAK;
3061 MINT_IN_CASE(MINT_LDC_I4_7)
3062 LDC(7);
3063 MINT_IN_BREAK;
3064 MINT_IN_CASE(MINT_LDC_I4_8)
3065 LDC(8);
3066 MINT_IN_BREAK;
3067 MINT_IN_CASE(MINT_LDC_I4_S)
3068 sp->data.i = *(const short *)(ip + 1);
3069 ip += 2;
3070 ++sp;
3071 MINT_IN_BREAK;
3072 MINT_IN_CASE(MINT_LDC_I4)
3073 ++ip;
3074 sp->data.i = READ32 (ip);
3075 ip += 2;
3076 ++sp;
3077 MINT_IN_BREAK;
3078 MINT_IN_CASE(MINT_LDC_I8)
3079 ++ip;
3080 sp->data.l = READ64 (ip);
3081 ip += 4;
3082 ++sp;
3083 MINT_IN_BREAK;
3084 MINT_IN_CASE(MINT_LDC_I8_S)
3085 sp->data.l = *(const short *)(ip + 1);
3086 ip += 2;
3087 ++sp;
3088 MINT_IN_BREAK;
3089 MINT_IN_CASE(MINT_LDC_R4) {
3090 guint32 val;
3091 ++ip;
3092 val = READ32(ip);
3093 sp->data.f_r4 = * (float *)&val;
3094 ip += 2;
3095 ++sp;
3096 MINT_IN_BREAK;
3098 MINT_IN_CASE(MINT_LDC_R8)
3099 sp->data.l = READ64 (ip + 1); /* note union usage */
3100 ip += 5;
3101 ++sp;
3102 MINT_IN_BREAK;
3103 MINT_IN_CASE(MINT_DUP)
3104 sp [0] = sp[-1];
3105 ++sp;
3106 ++ip;
3107 MINT_IN_BREAK;
3108 MINT_IN_CASE(MINT_DUP_VT)
3109 i32 = READ32 (ip + 1);
3110 sp->data.p = vt_sp;
3111 memcpy(sp->data.p, sp [-1].data.p, i32);
3112 vt_sp += ALIGN_TO (i32, MINT_VT_ALIGNMENT);
3113 ++sp;
3114 ip += 3;
3115 MINT_IN_BREAK;
3116 MINT_IN_CASE(MINT_POP) {
3117 guint16 u16 = (* (guint16 *)(ip + 1)) + 1;
3118 if (u16 > 1)
3119 memmove (sp - u16, sp - 1, (u16 - 1) * sizeof (stackval));
3120 sp--;
3121 ip += 2;
3122 MINT_IN_BREAK;
3124 MINT_IN_CASE(MINT_JMP) {
3125 InterpMethod *new_method = (InterpMethod*)imethod->data_items [* (guint16 *)(ip + 1)];
3126 gboolean realloc_frame = new_method->alloca_size > imethod->alloca_size;
3128 if (imethod->prof_flags & MONO_PROFILER_CALL_INSTRUMENTATION_TAIL_CALL)
3129 MONO_PROFILER_RAISE (method_tail_call, (imethod->method, new_method->method));
3131 if (!new_method->transformed) {
3132 MONO_API_ERROR_INIT (error);
3134 frame->ip = ip;
3135 mono_interp_transform_method (new_method, context, error);
3136 frame->ex = mono_error_convert_to_exception (error);
3137 if (frame->ex)
3138 goto exit_frame;
3140 ip += 2;
3141 imethod = frame->imethod = new_method;
3143 * We allocate the stack frame from scratch and store the arguments in the
3144 * locals again since it's possible for the caller stack frame to be smaller
3145 * than the callee stack frame (at the interp level)
3147 if (realloc_frame) {
3148 frame->args = g_newa (char, imethod->alloca_size);
3149 memset (frame->args, 0, imethod->alloca_size);
3150 sp = frame->stack = (stackval *) frame->args;
3152 vt_sp = (unsigned char *) sp + imethod->stack_size;
3153 #if DEBUG_INTERP
3154 vtalloc = vt_sp;
3155 #endif
3156 locals = vt_sp + imethod->vt_stack_size;
3157 frame->locals = locals;
3158 ip = imethod->code;
3159 MINT_IN_BREAK;
3161 MINT_IN_CASE(MINT_CALLI) {
3162 MonoMethodSignature *csignature;
3163 stackval *endsp = sp;
3165 frame->ip = ip;
3167 csignature = (MonoMethodSignature*)imethod->data_items [* (guint16 *)(ip + 1)];
3168 ip += 2;
3169 --sp;
3170 --endsp;
3171 child_frame.imethod = (InterpMethod*)sp->data.p;
3173 sp->data.p = vt_sp;
3174 child_frame.retval = sp;
3175 /* decrement by the actual number of args */
3176 sp -= csignature->param_count;
3177 if (csignature->hasthis)
3178 --sp;
3179 child_frame.stack_args = sp;
3181 if (child_frame.imethod->method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) {
3182 child_frame.imethod = mono_interp_get_imethod (imethod->domain, mono_marshal_get_native_wrapper (child_frame.imethod->method, FALSE, FALSE), error);
3183 mono_error_cleanup (error); /* FIXME: don't swallow the error */
3186 if (csignature->hasthis) {
3187 MonoObject *this_arg = (MonoObject*)sp->data.p;
3189 if (m_class_is_valuetype (this_arg->vtable->klass)) {
3190 gpointer unboxed = mono_object_unbox_internal (this_arg);
3191 sp [0].data.p = unboxed;
3195 interp_exec_method (&child_frame, context, error);
3197 CHECK_RESUME_STATE (context);
3199 /* need to handle typedbyref ... */
3200 if (csignature->ret->type != MONO_TYPE_VOID) {
3201 *sp = *endsp;
3202 sp++;
3204 MINT_IN_BREAK;
3206 MINT_IN_CASE(MINT_CALLI_NAT_FAST) {
3207 gpointer target_ip = sp [-1].data.p;
3208 MonoMethodSignature *csignature = (MonoMethodSignature*)imethod->data_items [* (guint16 *)(ip + 1)];
3209 int opcode = *(guint16 *)(ip + 2);
3210 gboolean save_last_error = *(guint16 *)(ip + 3);
3212 sp--;
3213 frame->ip = ip;
3215 sp = do_icall_wrapper (frame, csignature, opcode, sp, target_ip, save_last_error);
3216 EXCEPTION_CHECKPOINT;
3217 CHECK_RESUME_STATE (context);
3218 ip += 4;
3219 MINT_IN_BREAK;
3221 MINT_IN_CASE(MINT_CALLI_NAT) {
3222 MonoMethodSignature *csignature;
3223 stackval *endsp = sp;
3224 unsigned char *code = NULL;
3225 gboolean save_last_error = FALSE;
3227 frame->ip = ip;
3229 csignature = (MonoMethodSignature*)imethod->data_items [* (guint16 *)(ip + 1)];
3230 save_last_error = *(guint16 *)(ip + 2);
3231 ip += 3;
3232 --sp;
3233 --endsp;
3234 code = (guchar*)sp->data.p;
3235 child_frame.imethod = NULL;
3237 sp->data.p = vt_sp;
3238 child_frame.retval = sp;
3239 /* decrement by the actual number of args */
3240 sp -= csignature->param_count;
3241 if (csignature->hasthis)
3242 --sp;
3243 child_frame.stack_args = sp;
3244 if (imethod->method->dynamic && csignature->pinvoke) {
3245 MonoMarshalSpec **mspecs;
3246 MonoMethodPInvoke piinfo;
3247 MonoMethod *m;
3249 /* Pinvoke call is missing the wrapper. See mono_get_native_calli_wrapper */
3250 mspecs = g_new0 (MonoMarshalSpec*, csignature->param_count + 1);
3251 memset (&piinfo, 0, sizeof (piinfo));
3253 m = mono_marshal_get_native_func_wrapper (m_class_get_image (imethod->method->klass), csignature, &piinfo, mspecs, code);
3255 for (int i = csignature->param_count; i >= 0; i--)
3256 if (mspecs [i])
3257 mono_metadata_free_marshal_spec (mspecs [i]);
3258 g_free (mspecs);
3260 child_frame.imethod = mono_interp_get_imethod (imethod->domain, m, error);
3261 mono_error_cleanup (error); /* FIXME: don't swallow the error */
3263 interp_exec_method (&child_frame, context, error);
3264 } else {
3265 ves_pinvoke_method (&child_frame, csignature, (MonoFuncV) code, FALSE, context, save_last_error);
3268 CHECK_RESUME_STATE (context);
3270 /* need to handle typedbyref ... */
3271 if (csignature->ret->type != MONO_TYPE_VOID) {
3272 *sp = *endsp;
3273 sp++;
3275 MINT_IN_BREAK;
3277 MINT_IN_CASE(MINT_CALLVIRT_FAST)
3278 MINT_IN_CASE(MINT_VCALLVIRT_FAST) {
3279 MonoObject *this_arg;
3280 MonoClass *this_class;
3281 gboolean is_void = *ip == MINT_VCALLVIRT_FAST;
3282 InterpMethod *target_imethod;
3283 stackval *endsp = sp;
3284 int slot;
3286 // FIXME Have it handle also remoting calls and use a single opcode for virtual calls
3288 frame->ip = ip;
3290 target_imethod = (InterpMethod*)imethod->data_items [* (guint16 *)(ip + 1)];
3291 slot = *(gint16*)(ip + 2);
3292 ip += 3;
3293 sp->data.p = vt_sp;
3294 child_frame.retval = sp;
3296 /* decrement by the actual number of args */
3297 sp -= target_imethod->param_count + target_imethod->hasthis;
3298 child_frame.stack_args = sp;
3300 this_arg = (MonoObject*)sp->data.p;
3301 this_class = this_arg->vtable->klass;
3303 child_frame.imethod = get_virtual_method_fast (target_imethod, this_arg->vtable, slot);
3304 if (m_class_is_valuetype (this_class) && m_class_is_valuetype (child_frame.imethod->method->klass)) {
3305 /* unbox */
3306 gpointer unboxed = mono_object_unbox_internal (this_arg);
3307 sp [0].data.p = unboxed;
3310 interp_exec_method (&child_frame, context, error);
3312 CHECK_RESUME_STATE (context);
3314 if (!is_void) {
3315 /* need to handle typedbyref ... */
3316 *sp = *endsp;
3317 sp++;
3319 MINT_IN_BREAK;
3321 MINT_IN_CASE(MINT_CALL_VARARG) {
3322 stackval *endsp = sp;
3323 int num_varargs = 0;
3324 MonoMethodSignature *csig;
3326 frame->ip = ip;
3328 child_frame.imethod = (InterpMethod*)imethod->data_items [* (guint16 *)(ip + 1)];
3329 /* The real signature for vararg calls */
3330 csig = (MonoMethodSignature*) imethod->data_items [* (guint16*) (ip + 2)];
3331 /* Push all vararg arguments from normal sp to vt_sp together with the signature */
3332 num_varargs = csig->param_count - csig->sentinelpos;
3333 child_frame.varargs = (char*) vt_sp;
3334 copy_varargs_vtstack (csig, sp, &vt_sp);
3336 ip += 3;
3337 sp->data.p = vt_sp;
3338 child_frame.retval = sp;
3340 /* decrement by the actual number of args */
3341 sp -= child_frame.imethod->param_count + child_frame.imethod->hasthis + num_varargs;
3342 child_frame.stack_args = sp;
3344 interp_exec_method (&child_frame, context, error);
3346 CHECK_RESUME_STATE (context);
3348 if (csig->ret->type != MONO_TYPE_VOID) {
3349 *sp = *endsp;
3350 sp++;
3352 MINT_IN_BREAK;
3354 MINT_IN_CASE(MINT_CALL)
3355 MINT_IN_CASE(MINT_VCALL)
3356 MINT_IN_CASE(MINT_CALLVIRT)
3357 MINT_IN_CASE(MINT_VCALLVIRT) {
3358 gboolean is_void = *ip == MINT_VCALL || *ip == MINT_VCALLVIRT;
3359 gboolean is_virtual = *ip == MINT_CALLVIRT || *ip == MINT_VCALLVIRT;
3360 stackval *endsp = sp;
3362 frame->ip = ip;
3364 child_frame.imethod = (InterpMethod*)imethod->data_items [* (guint16 *)(ip + 1)];
3365 ip += 2;
3366 sp->data.p = vt_sp;
3367 child_frame.retval = sp;
3369 /* decrement by the actual number of args */
3370 sp -= child_frame.imethod->param_count + child_frame.imethod->hasthis;
3371 child_frame.stack_args = sp;
3373 if (is_virtual) {
3374 MonoObject *this_arg = (MonoObject*)sp->data.p;
3375 MonoClass *this_class = this_arg->vtable->klass;
3377 child_frame.imethod = get_virtual_method (child_frame.imethod, this_arg->vtable);
3378 if (m_class_is_valuetype (this_class) && m_class_is_valuetype (child_frame.imethod->method->klass)) {
3379 /* unbox */
3380 gpointer unboxed = mono_object_unbox_internal (this_arg);
3381 sp [0].data.p = unboxed;
3385 interp_exec_method (&child_frame, context, error);
3387 CHECK_RESUME_STATE (context);
3389 if (!is_void) {
3390 /* need to handle typedbyref ... */
3391 *sp = *endsp;
3392 sp++;
3394 MINT_IN_BREAK;
3396 MINT_IN_CASE(MINT_JIT_CALL) {
3397 InterpMethod *rmethod = (InterpMethod*)imethod->data_items [* (guint16 *)(ip + 1)];
3398 MONO_API_ERROR_INIT (error);
3399 frame->ip = ip;
3400 sp = do_jit_call (sp, vt_sp, context, frame, rmethod, error);
3401 if (!is_ok (error)) {
3402 MonoException *ex = mono_error_convert_to_exception (error);
3403 THROW_EX (ex, ip);
3405 ip += 2;
3407 CHECK_RESUME_STATE (context);
3409 if (rmethod->rtype->type != MONO_TYPE_VOID)
3410 sp++;
3412 MINT_IN_BREAK;
3414 MINT_IN_CASE(MINT_CALLRUN) {
3415 MonoMethod *target_method = (MonoMethod*) imethod->data_items [* (guint16 *)(ip + 1)];
3416 MonoMethodSignature *sig = (MonoMethodSignature*) imethod->data_items [* (guint16 *)(ip + 2)];
3417 stackval *retval;
3419 sp->data.p = vt_sp;
3420 retval = sp;
3422 sp -= sig->param_count;
3423 if (sig->hasthis)
3424 sp--;
3426 ves_imethod (frame, target_method, sig, sp, retval);
3427 if (frame->ex)
3428 THROW_EX (frame->ex, ip);
3430 if (sig->ret->type != MONO_TYPE_VOID) {
3431 *sp = *retval;
3432 sp++;
3434 ip += 3;
3435 MINT_IN_BREAK;
3437 MINT_IN_CASE(MINT_RET)
3438 --sp;
3439 *frame->retval = *sp;
3440 if (sp > frame->stack)
3441 g_warning ("ret: more values on stack: %d", sp-frame->stack);
3442 goto exit_frame;
3443 MINT_IN_CASE(MINT_RET_VOID)
3444 if (sp > frame->stack)
3445 g_warning ("ret.void: more values on stack: %d %s", sp-frame->stack, mono_method_full_name (imethod->method, TRUE));
3446 goto exit_frame;
3447 MINT_IN_CASE(MINT_RET_VT)
3448 i32 = READ32(ip + 1);
3449 --sp;
3450 memcpy(frame->retval->data.p, sp->data.p, i32);
3451 if (sp > frame->stack)
3452 g_warning ("ret.vt: more values on stack: %d", sp-frame->stack);
3453 goto exit_frame;
3454 MINT_IN_CASE(MINT_BR_S)
3455 ip += (short) *(ip + 1);
3456 MINT_IN_BREAK;
3457 MINT_IN_CASE(MINT_BR)
3458 ip += (gint32) READ32(ip + 1);
3459 MINT_IN_BREAK;
3460 #define ZEROP_S(datamem, op) \
3461 --sp; \
3462 if (sp->data.datamem op 0) \
3463 ip += * (gint16 *)(ip + 1); \
3464 else \
3465 ip += 2;
3467 #define ZEROP(datamem, op) \
3468 --sp; \
3469 if (sp->data.datamem op 0) \
3470 ip += (gint32)READ32(ip + 1); \
3471 else \
3472 ip += 3;
3474 MINT_IN_CASE(MINT_BRFALSE_I4_S)
3475 ZEROP_S(i, ==);
3476 MINT_IN_BREAK;
3477 MINT_IN_CASE(MINT_BRFALSE_I8_S)
3478 ZEROP_S(l, ==);
3479 MINT_IN_BREAK;
3480 MINT_IN_CASE(MINT_BRFALSE_R4_S)
3481 ZEROP_S(f_r4, ==);
3482 MINT_IN_BREAK;
3483 MINT_IN_CASE(MINT_BRFALSE_R8_S)
3484 ZEROP_S(f, ==);
3485 MINT_IN_BREAK;
3486 MINT_IN_CASE(MINT_BRFALSE_I4)
3487 ZEROP(i, ==);
3488 MINT_IN_BREAK;
3489 MINT_IN_CASE(MINT_BRFALSE_I8)
3490 ZEROP(l, ==);
3491 MINT_IN_BREAK;
3492 MINT_IN_CASE(MINT_BRFALSE_R4)
3493 ZEROP_S(f_r4, ==);
3494 MINT_IN_BREAK;
3495 MINT_IN_CASE(MINT_BRFALSE_R8)
3496 ZEROP_S(f, ==);
3497 MINT_IN_BREAK;
3498 MINT_IN_CASE(MINT_BRTRUE_I4_S)
3499 ZEROP_S(i, !=);
3500 MINT_IN_BREAK;
3501 MINT_IN_CASE(MINT_BRTRUE_I8_S)
3502 ZEROP_S(l, !=);
3503 MINT_IN_BREAK;
3504 MINT_IN_CASE(MINT_BRTRUE_R4_S)
3505 ZEROP_S(f_r4, !=);
3506 MINT_IN_BREAK;
3507 MINT_IN_CASE(MINT_BRTRUE_R8_S)
3508 ZEROP_S(f, !=);
3509 MINT_IN_BREAK;
3510 MINT_IN_CASE(MINT_BRTRUE_I4)
3511 ZEROP(i, !=);
3512 MINT_IN_BREAK;
3513 MINT_IN_CASE(MINT_BRTRUE_I8)
3514 ZEROP(l, !=);
3515 MINT_IN_BREAK;
3516 MINT_IN_CASE(MINT_BRTRUE_R4)
3517 ZEROP(f_r4, !=);
3518 MINT_IN_BREAK;
3519 MINT_IN_CASE(MINT_BRTRUE_R8)
3520 ZEROP(f, !=);
3521 MINT_IN_BREAK;
3522 #define CONDBR_S(cond) \
3523 sp -= 2; \
3524 if (cond) \
3525 ip += * (gint16 *)(ip + 1); \
3526 else \
3527 ip += 2;
3528 #define BRELOP_S(datamem, op) \
3529 CONDBR_S(sp[0].data.datamem op sp[1].data.datamem)
3531 #define CONDBR(cond) \
3532 sp -= 2; \
3533 if (cond) \
3534 ip += (gint32)READ32(ip + 1); \
3535 else \
3536 ip += 3;
3538 #define BRELOP(datamem, op) \
3539 CONDBR(sp[0].data.datamem op sp[1].data.datamem)
3541 MINT_IN_CASE(MINT_BEQ_I4_S)
3542 BRELOP_S(i, ==)
3543 MINT_IN_BREAK;
3544 MINT_IN_CASE(MINT_BEQ_I8_S)
3545 BRELOP_S(l, ==)
3546 MINT_IN_BREAK;
3547 MINT_IN_CASE(MINT_BEQ_R4_S)
3548 CONDBR_S(!isunordered (sp [0].data.f_r4, sp [1].data.f_r4) && sp[0].data.f_r4 == sp[1].data.f_r4)
3549 MINT_IN_BREAK;
3550 MINT_IN_CASE(MINT_BEQ_R8_S)
3551 CONDBR_S(!mono_isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f == sp[1].data.f)
3552 MINT_IN_BREAK;
3553 MINT_IN_CASE(MINT_BEQ_I4)
3554 BRELOP(i, ==)
3555 MINT_IN_BREAK;
3556 MINT_IN_CASE(MINT_BEQ_I8)
3557 BRELOP(l, ==)
3558 MINT_IN_BREAK;
3559 MINT_IN_CASE(MINT_BEQ_R4)
3560 CONDBR(!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)
3563 CONDBR(!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_BGE_I4_S)
3566 BRELOP_S(i, >=)
3567 MINT_IN_BREAK;
3568 MINT_IN_CASE(MINT_BGE_I8_S)
3569 BRELOP_S(l, >=)
3570 MINT_IN_BREAK;
3571 MINT_IN_CASE(MINT_BGE_R4_S)
3572 CONDBR_S(!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_BGE_R8_S)
3575 CONDBR_S(!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)
3578 BRELOP(i, >=)
3579 MINT_IN_BREAK;
3580 MINT_IN_CASE(MINT_BGE_I8)
3581 BRELOP(l, >=)
3582 MINT_IN_BREAK;
3583 MINT_IN_CASE(MINT_BGE_R4)
3584 CONDBR(!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)
3587 CONDBR(!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_BGT_I4_S)
3590 BRELOP_S(i, >)
3591 MINT_IN_BREAK;
3592 MINT_IN_CASE(MINT_BGT_I8_S)
3593 BRELOP_S(l, >)
3594 MINT_IN_BREAK;
3595 MINT_IN_CASE(MINT_BGT_R4_S)
3596 CONDBR_S(!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_BGT_R8_S)
3599 CONDBR_S(!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)
3602 BRELOP(i, >)
3603 MINT_IN_BREAK;
3604 MINT_IN_CASE(MINT_BGT_I8)
3605 BRELOP(l, >)
3606 MINT_IN_BREAK;
3607 MINT_IN_CASE(MINT_BGT_R4)
3608 CONDBR(!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)
3611 CONDBR(!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_BLT_I4_S)
3614 BRELOP_S(i, <)
3615 MINT_IN_BREAK;
3616 MINT_IN_CASE(MINT_BLT_I8_S)
3617 BRELOP_S(l, <)
3618 MINT_IN_BREAK;
3619 MINT_IN_CASE(MINT_BLT_R4_S)
3620 CONDBR_S(!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_BLT_R8_S)
3623 CONDBR_S(!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)
3626 BRELOP(i, <)
3627 MINT_IN_BREAK;
3628 MINT_IN_CASE(MINT_BLT_I8)
3629 BRELOP(l, <)
3630 MINT_IN_BREAK;
3631 MINT_IN_CASE(MINT_BLT_R4)
3632 CONDBR(!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)
3635 CONDBR(!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_BLE_I4_S)
3638 BRELOP_S(i, <=)
3639 MINT_IN_BREAK;
3640 MINT_IN_CASE(MINT_BLE_I8_S)
3641 BRELOP_S(l, <=)
3642 MINT_IN_BREAK;
3643 MINT_IN_CASE(MINT_BLE_R4_S)
3644 CONDBR_S(!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_BLE_R8_S)
3647 CONDBR_S(!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)
3650 BRELOP(i, <=)
3651 MINT_IN_BREAK;
3652 MINT_IN_CASE(MINT_BLE_I8)
3653 BRELOP(l, <=)
3654 MINT_IN_BREAK;
3655 MINT_IN_CASE(MINT_BLE_R4)
3656 CONDBR(!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)
3659 CONDBR(!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_BNE_UN_I4_S)
3662 BRELOP_S(i, !=)
3663 MINT_IN_BREAK;
3664 MINT_IN_CASE(MINT_BNE_UN_I8_S)
3665 BRELOP_S(l, !=)
3666 MINT_IN_BREAK;
3667 MINT_IN_CASE(MINT_BNE_UN_R4_S)
3668 CONDBR_S(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_BNE_UN_R8_S)
3671 CONDBR_S(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)
3674 BRELOP(i, !=)
3675 MINT_IN_BREAK;
3676 MINT_IN_CASE(MINT_BNE_UN_I8)
3677 BRELOP(l, !=)
3678 MINT_IN_BREAK;
3679 MINT_IN_CASE(MINT_BNE_UN_R4)
3680 CONDBR(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)
3683 CONDBR(mono_isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f != sp[1].data.f)
3684 MINT_IN_BREAK;
3686 #define BRELOP_S_CAST(datamem, op, type) \
3687 sp -= 2; \
3688 if ((type) sp[0].data.datamem op (type) sp[1].data.datamem) \
3689 ip += * (gint16 *)(ip + 1); \
3690 else \
3691 ip += 2;
3693 #define BRELOP_CAST(datamem, op, type) \
3694 sp -= 2; \
3695 if ((type) sp[0].data.datamem op (type) sp[1].data.datamem) \
3696 ip += (gint32)READ32(ip + 1); \
3697 else \
3698 ip += 3;
3700 MINT_IN_CASE(MINT_BGE_UN_I4_S)
3701 BRELOP_S_CAST(i, >=, guint32);
3702 MINT_IN_BREAK;
3703 MINT_IN_CASE(MINT_BGE_UN_I8_S)
3704 BRELOP_S_CAST(l, >=, guint64);
3705 MINT_IN_BREAK;
3706 MINT_IN_CASE(MINT_BGE_UN_R4_S)
3707 CONDBR_S(isunordered (sp [0].data.f_r4, sp [1].data.f_r4) || sp[0].data.f_r4 >= sp[1].data.f_r4)
3708 MINT_IN_BREAK;
3709 MINT_IN_CASE(MINT_BGE_UN_R8_S)
3710 CONDBR_S(mono_isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f >= sp[1].data.f)
3711 MINT_IN_BREAK;
3712 MINT_IN_CASE(MINT_BGE_UN_I4)
3713 BRELOP_CAST(i, >=, guint32);
3714 MINT_IN_BREAK;
3715 MINT_IN_CASE(MINT_BGE_UN_I8)
3716 BRELOP_CAST(l, >=, guint64);
3717 MINT_IN_BREAK;
3718 MINT_IN_CASE(MINT_BGE_UN_R4)
3719 CONDBR(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)
3722 CONDBR(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_BGT_UN_I4_S)
3725 BRELOP_S_CAST(i, >, guint32);
3726 MINT_IN_BREAK;
3727 MINT_IN_CASE(MINT_BGT_UN_I8_S)
3728 BRELOP_S_CAST(l, >, guint64);
3729 MINT_IN_BREAK;
3730 MINT_IN_CASE(MINT_BGT_UN_R4_S)
3731 CONDBR_S(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_BGT_UN_R8_S)
3734 CONDBR_S(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)
3737 BRELOP_CAST(i, >, guint32);
3738 MINT_IN_BREAK;
3739 MINT_IN_CASE(MINT_BGT_UN_I8)
3740 BRELOP_CAST(l, >, guint64);
3741 MINT_IN_BREAK;
3742 MINT_IN_CASE(MINT_BGT_UN_R4)
3743 CONDBR(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)
3746 CONDBR(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_BLE_UN_I4_S)
3749 BRELOP_S_CAST(i, <=, guint32);
3750 MINT_IN_BREAK;
3751 MINT_IN_CASE(MINT_BLE_UN_I8_S)
3752 BRELOP_S_CAST(l, <=, guint64);
3753 MINT_IN_BREAK;
3754 MINT_IN_CASE(MINT_BLE_UN_R4_S)
3755 CONDBR_S(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_BLE_UN_R8_S)
3758 CONDBR_S(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)
3761 BRELOP_CAST(i, <=, guint32);
3762 MINT_IN_BREAK;
3763 MINT_IN_CASE(MINT_BLE_UN_I8)
3764 BRELOP_CAST(l, <=, guint64);
3765 MINT_IN_BREAK;
3766 MINT_IN_CASE(MINT_BLE_UN_R4)
3767 CONDBR(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)
3770 CONDBR(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_BLT_UN_I4_S)
3773 BRELOP_S_CAST(i, <, guint32);
3774 MINT_IN_BREAK;
3775 MINT_IN_CASE(MINT_BLT_UN_I8_S)
3776 BRELOP_S_CAST(l, <, guint64);
3777 MINT_IN_BREAK;
3778 MINT_IN_CASE(MINT_BLT_UN_R4_S)
3779 CONDBR_S(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_BLT_UN_R8_S)
3782 CONDBR_S(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)
3785 BRELOP_CAST(i, <, guint32);
3786 MINT_IN_BREAK;
3787 MINT_IN_CASE(MINT_BLT_UN_I8)
3788 BRELOP_CAST(l, <, guint64);
3789 MINT_IN_BREAK;
3790 MINT_IN_CASE(MINT_BLT_UN_R4)
3791 CONDBR(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)
3794 CONDBR(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_SWITCH) {
3797 guint32 n;
3798 const unsigned short *st;
3799 ++ip;
3800 n = READ32 (ip);
3801 ip += 2;
3802 st = ip + 2 * n;
3803 --sp;
3804 if ((guint32)sp->data.i < n) {
3805 gint offset;
3806 ip += 2 * (guint32)sp->data.i;
3807 offset = READ32 (ip);
3808 ip = ip + offset;
3809 } else {
3810 ip = st;
3812 MINT_IN_BREAK;
3814 MINT_IN_CASE(MINT_LDIND_I1_CHECK)
3815 if (!sp[-1].data.p)
3816 THROW_EX (mono_get_exception_null_reference (), ip);
3817 ++ip;
3818 sp[-1].data.i = *(gint8*)sp[-1].data.p;
3819 MINT_IN_BREAK;
3820 MINT_IN_CASE(MINT_LDIND_U1_CHECK)
3821 if (!sp[-1].data.p)
3822 THROW_EX (mono_get_exception_null_reference (), ip);
3823 ++ip;
3824 sp[-1].data.i = *(guint8*)sp[-1].data.p;
3825 MINT_IN_BREAK;
3826 MINT_IN_CASE(MINT_LDIND_I2_CHECK)
3827 if (!sp[-1].data.p)
3828 THROW_EX (mono_get_exception_null_reference (), ip);
3829 ++ip;
3830 sp[-1].data.i = *(gint16*)sp[-1].data.p;
3831 MINT_IN_BREAK;
3832 MINT_IN_CASE(MINT_LDIND_U2_CHECK)
3833 if (!sp[-1].data.p)
3834 THROW_EX (mono_get_exception_null_reference (), ip);
3835 ++ip;
3836 sp[-1].data.i = *(guint16*)sp[-1].data.p;
3837 MINT_IN_BREAK;
3838 MINT_IN_CASE(MINT_LDIND_I4_CHECK) /* Fall through */
3839 MINT_IN_CASE(MINT_LDIND_U4_CHECK)
3840 if (!sp[-1].data.p)
3841 THROW_EX (mono_get_exception_null_reference (), ip);
3842 ++ip;
3843 sp[-1].data.i = *(gint32*)sp[-1].data.p;
3844 MINT_IN_BREAK;
3845 MINT_IN_CASE(MINT_LDIND_I8_CHECK)
3846 if (!sp[-1].data.p)
3847 THROW_EX (mono_get_exception_null_reference (), ip);
3848 ++ip;
3849 #ifdef NO_UNALIGNED_ACCESS
3850 if ((gsize)sp [-1].data.p % SIZEOF_VOID_P)
3851 memcpy (&sp [-1].data.l, sp [-1].data.p, sizeof (gint64));
3852 else
3853 #endif
3854 sp[-1].data.l = *(gint64*)sp[-1].data.p;
3855 MINT_IN_BREAK;
3856 MINT_IN_CASE(MINT_LDIND_I) {
3857 guint16 offset = * (guint16 *)(ip + 1);
3858 sp[-1 - offset].data.p = *(gpointer*)sp[-1 - offset].data.p;
3859 ip += 2;
3860 MINT_IN_BREAK;
3862 MINT_IN_CASE(MINT_LDIND_I8) {
3863 guint16 offset = * (guint16 *)(ip + 1);
3864 #ifdef NO_UNALIGNED_ACCESS
3865 if ((gsize)sp [-1 - offset].data.p % SIZEOF_VOID_P)
3866 memcpy (&sp [-1 - offset].data.l, sp [-1 - offset].data.p, sizeof (gint64));
3867 else
3868 #endif
3869 sp[-1 - offset].data.l = *(gint64*)sp[-1 - offset].data.p;
3870 ip += 2;
3871 MINT_IN_BREAK;
3873 MINT_IN_CASE(MINT_LDIND_R4_CHECK)
3874 if (!sp[-1].data.p)
3875 THROW_EX (mono_get_exception_null_reference (), ip);
3876 ++ip;
3877 sp[-1].data.f_r4 = *(gfloat*)sp[-1].data.p;
3878 MINT_IN_BREAK;
3879 MINT_IN_CASE(MINT_LDIND_R8_CHECK)
3880 if (!sp[-1].data.p)
3881 THROW_EX (mono_get_exception_null_reference (), ip);
3882 ++ip;
3883 #ifdef NO_UNALIGNED_ACCESS
3884 if ((gsize)sp [-1].data.p % SIZEOF_VOID_P)
3885 memcpy (&sp [-1].data.f, sp [-1].data.p, sizeof (gdouble));
3886 else
3887 #endif
3888 sp[-1].data.f = *(gdouble*)sp[-1].data.p;
3889 MINT_IN_BREAK;
3890 MINT_IN_CASE(MINT_LDIND_REF)
3891 ++ip;
3892 sp[-1].data.p = *(gpointer*)sp[-1].data.p;
3893 MINT_IN_BREAK;
3894 MINT_IN_CASE(MINT_LDIND_REF_CHECK) {
3895 if (!sp [-1].data.p)
3896 THROW_EX (mono_get_exception_null_reference (), ip);
3897 ++ip;
3898 sp [-1].data.p = *(gpointer*)sp [-1].data.p;
3899 MINT_IN_BREAK;
3901 MINT_IN_CASE(MINT_STIND_REF)
3902 ++ip;
3903 sp -= 2;
3904 mono_gc_wbarrier_generic_store_internal (sp->data.p, sp [1].data.o);
3905 MINT_IN_BREAK;
3906 MINT_IN_CASE(MINT_STIND_I1)
3907 ++ip;
3908 sp -= 2;
3909 * (gint8 *) sp->data.p = (gint8)sp[1].data.i;
3910 MINT_IN_BREAK;
3911 MINT_IN_CASE(MINT_STIND_I2)
3912 ++ip;
3913 sp -= 2;
3914 * (gint16 *) sp->data.p = (gint16)sp[1].data.i;
3915 MINT_IN_BREAK;
3916 MINT_IN_CASE(MINT_STIND_I4)
3917 ++ip;
3918 sp -= 2;
3919 * (gint32 *) sp->data.p = sp[1].data.i;
3920 MINT_IN_BREAK;
3921 MINT_IN_CASE(MINT_STIND_I)
3922 ++ip;
3923 sp -= 2;
3924 * (mono_i *) sp->data.p = (mono_i)sp[1].data.p;
3925 MINT_IN_BREAK;
3926 MINT_IN_CASE(MINT_STIND_I8)
3927 ++ip;
3928 sp -= 2;
3929 #ifdef NO_UNALIGNED_ACCESS
3930 if ((gsize)sp->data.p % SIZEOF_VOID_P)
3931 memcpy (sp->data.p, &sp [1].data.l, sizeof (gint64));
3932 else
3933 #endif
3934 * (gint64 *) sp->data.p = sp[1].data.l;
3935 MINT_IN_BREAK;
3936 MINT_IN_CASE(MINT_STIND_R4)
3937 ++ip;
3938 sp -= 2;
3939 * (float *) sp->data.p = sp[1].data.f_r4;
3940 MINT_IN_BREAK;
3941 MINT_IN_CASE(MINT_STIND_R8)
3942 ++ip;
3943 sp -= 2;
3944 #ifdef NO_UNALIGNED_ACCESS
3945 if ((gsize)sp->data.p % SIZEOF_VOID_P)
3946 memcpy (sp->data.p, &sp [1].data.f, sizeof (double));
3947 else
3948 #endif
3949 * (double *) sp->data.p = sp[1].data.f;
3950 MINT_IN_BREAK;
3951 MINT_IN_CASE(MINT_MONO_ATOMIC_STORE_I4)
3952 ++ip;
3953 sp -= 2;
3954 mono_atomic_store_i32 ((gint32 *) sp->data.p, sp [1].data.i);
3955 MINT_IN_BREAK;
3956 #define BINOP(datamem, op) \
3957 --sp; \
3958 sp [-1].data.datamem = sp [-1].data.datamem op sp [0].data.datamem; \
3959 ++ip;
3960 MINT_IN_CASE(MINT_ADD_I4)
3961 BINOP(i, +);
3962 MINT_IN_BREAK;
3963 MINT_IN_CASE(MINT_ADD_I8)
3964 BINOP(l, +);
3965 MINT_IN_BREAK;
3966 MINT_IN_CASE(MINT_ADD_R4)
3967 BINOP(f_r4, +);
3968 MINT_IN_BREAK;
3969 MINT_IN_CASE(MINT_ADD_R8)
3970 BINOP(f, +);
3971 MINT_IN_BREAK;
3972 MINT_IN_CASE(MINT_ADD1_I4)
3973 ++sp [-1].data.i;
3974 ++ip;
3975 MINT_IN_BREAK;
3976 MINT_IN_CASE(MINT_ADD1_I8)
3977 ++sp [-1].data.l;
3978 ++ip;
3979 MINT_IN_BREAK;
3980 MINT_IN_CASE(MINT_SUB_I4)
3981 BINOP(i, -);
3982 MINT_IN_BREAK;
3983 MINT_IN_CASE(MINT_SUB_I8)
3984 BINOP(l, -);
3985 MINT_IN_BREAK;
3986 MINT_IN_CASE(MINT_SUB_R4)
3987 BINOP(f_r4, -);
3988 MINT_IN_BREAK;
3989 MINT_IN_CASE(MINT_SUB_R8)
3990 BINOP(f, -);
3991 MINT_IN_BREAK;
3992 MINT_IN_CASE(MINT_SUB1_I4)
3993 --sp [-1].data.i;
3994 ++ip;
3995 MINT_IN_BREAK;
3996 MINT_IN_CASE(MINT_SUB1_I8)
3997 --sp [-1].data.l;
3998 ++ip;
3999 MINT_IN_BREAK;
4000 MINT_IN_CASE(MINT_MUL_I4)
4001 BINOP(i, *);
4002 MINT_IN_BREAK;
4003 MINT_IN_CASE(MINT_MUL_I8)
4004 BINOP(l, *);
4005 MINT_IN_BREAK;
4006 MINT_IN_CASE(MINT_MUL_R4)
4007 BINOP(f_r4, *);
4008 MINT_IN_BREAK;
4009 MINT_IN_CASE(MINT_MUL_R8)
4010 BINOP(f, *);
4011 MINT_IN_BREAK;
4012 MINT_IN_CASE(MINT_DIV_I4)
4013 if (sp [-1].data.i == 0)
4014 THROW_EX (mono_get_exception_divide_by_zero (), ip);
4015 if (sp [-1].data.i == (-1) && sp [-2].data.i == G_MININT32)
4016 THROW_EX (mono_get_exception_overflow (), ip);
4017 BINOP(i, /);
4018 MINT_IN_BREAK;
4019 MINT_IN_CASE(MINT_DIV_I8)
4020 if (sp [-1].data.l == 0)
4021 THROW_EX (mono_get_exception_divide_by_zero (), ip);
4022 if (sp [-1].data.l == (-1) && sp [-2].data.l == G_MININT64)
4023 THROW_EX (mono_get_exception_overflow (), ip);
4024 BINOP(l, /);
4025 MINT_IN_BREAK;
4026 MINT_IN_CASE(MINT_DIV_R4)
4027 BINOP(f_r4, /);
4028 MINT_IN_BREAK;
4029 MINT_IN_CASE(MINT_DIV_R8)
4030 BINOP(f, /);
4031 MINT_IN_BREAK;
4033 #define BINOP_CAST(datamem, op, type) \
4034 --sp; \
4035 sp [-1].data.datamem = (type)sp [-1].data.datamem op (type)sp [0].data.datamem; \
4036 ++ip;
4037 MINT_IN_CASE(MINT_DIV_UN_I4)
4038 if (sp [-1].data.i == 0)
4039 THROW_EX (mono_get_exception_divide_by_zero (), ip);
4040 BINOP_CAST(i, /, guint32);
4041 MINT_IN_BREAK;
4042 MINT_IN_CASE(MINT_DIV_UN_I8)
4043 if (sp [-1].data.l == 0)
4044 THROW_EX (mono_get_exception_divide_by_zero (), ip);
4045 BINOP_CAST(l, /, guint64);
4046 MINT_IN_BREAK;
4047 MINT_IN_CASE(MINT_REM_I4)
4048 if (sp [-1].data.i == 0)
4049 THROW_EX (mono_get_exception_divide_by_zero (), ip);
4050 if (sp [-1].data.i == (-1) && sp [-2].data.i == G_MININT32)
4051 THROW_EX (mono_get_exception_overflow (), ip);
4052 BINOP(i, %);
4053 MINT_IN_BREAK;
4054 MINT_IN_CASE(MINT_REM_I8)
4055 if (sp [-1].data.l == 0)
4056 THROW_EX (mono_get_exception_divide_by_zero (), ip);
4057 if (sp [-1].data.l == (-1) && sp [-2].data.l == G_MININT64)
4058 THROW_EX (mono_get_exception_overflow (), ip);
4059 BINOP(l, %);
4060 MINT_IN_BREAK;
4061 MINT_IN_CASE(MINT_REM_R4)
4062 /* FIXME: what do we actually do here? */
4063 --sp;
4064 sp [-1].data.f_r4 = fmodf (sp [-1].data.f_r4, sp [0].data.f_r4);
4065 ++ip;
4066 MINT_IN_BREAK;
4067 MINT_IN_CASE(MINT_REM_R8)
4068 /* FIXME: what do we actually do here? */
4069 --sp;
4070 sp [-1].data.f = fmod (sp [-1].data.f, sp [0].data.f);
4071 ++ip;
4072 MINT_IN_BREAK;
4073 MINT_IN_CASE(MINT_REM_UN_I4)
4074 if (sp [-1].data.i == 0)
4075 THROW_EX (mono_get_exception_divide_by_zero (), ip);
4076 BINOP_CAST(i, %, guint32);
4077 MINT_IN_BREAK;
4078 MINT_IN_CASE(MINT_REM_UN_I8)
4079 if (sp [-1].data.l == 0)
4080 THROW_EX (mono_get_exception_divide_by_zero (), ip);
4081 BINOP_CAST(l, %, guint64);
4082 MINT_IN_BREAK;
4083 MINT_IN_CASE(MINT_AND_I4)
4084 BINOP(i, &);
4085 MINT_IN_BREAK;
4086 MINT_IN_CASE(MINT_AND_I8)
4087 BINOP(l, &);
4088 MINT_IN_BREAK;
4089 MINT_IN_CASE(MINT_OR_I4)
4090 BINOP(i, |);
4091 MINT_IN_BREAK;
4092 MINT_IN_CASE(MINT_OR_I8)
4093 BINOP(l, |);
4094 MINT_IN_BREAK;
4095 MINT_IN_CASE(MINT_XOR_I4)
4096 BINOP(i, ^);
4097 MINT_IN_BREAK;
4098 MINT_IN_CASE(MINT_XOR_I8)
4099 BINOP(l, ^);
4100 MINT_IN_BREAK;
4102 #define SHIFTOP(datamem, op) \
4103 --sp; \
4104 sp [-1].data.datamem = sp [-1].data.datamem op sp [0].data.i; \
4105 ++ip;
4107 MINT_IN_CASE(MINT_SHL_I4)
4108 SHIFTOP(i, <<);
4109 MINT_IN_BREAK;
4110 MINT_IN_CASE(MINT_SHL_I8)
4111 SHIFTOP(l, <<);
4112 MINT_IN_BREAK;
4113 MINT_IN_CASE(MINT_SHR_I4)
4114 SHIFTOP(i, >>);
4115 MINT_IN_BREAK;
4116 MINT_IN_CASE(MINT_SHR_I8)
4117 SHIFTOP(l, >>);
4118 MINT_IN_BREAK;
4119 MINT_IN_CASE(MINT_SHR_UN_I4)
4120 --sp;
4121 sp [-1].data.i = (guint32)sp [-1].data.i >> sp [0].data.i;
4122 ++ip;
4123 MINT_IN_BREAK;
4124 MINT_IN_CASE(MINT_SHR_UN_I8)
4125 --sp;
4126 sp [-1].data.l = (guint64)sp [-1].data.l >> sp [0].data.i;
4127 ++ip;
4128 MINT_IN_BREAK;
4129 MINT_IN_CASE(MINT_NEG_I4)
4130 sp [-1].data.i = - sp [-1].data.i;
4131 ++ip;
4132 MINT_IN_BREAK;
4133 MINT_IN_CASE(MINT_NEG_I8)
4134 sp [-1].data.l = - sp [-1].data.l;
4135 ++ip;
4136 MINT_IN_BREAK;
4137 MINT_IN_CASE(MINT_NEG_R4)
4138 sp [-1].data.f_r4 = - sp [-1].data.f_r4;
4139 ++ip;
4140 MINT_IN_BREAK;
4141 MINT_IN_CASE(MINT_NEG_R8)
4142 sp [-1].data.f = - sp [-1].data.f;
4143 ++ip;
4144 MINT_IN_BREAK;
4145 MINT_IN_CASE(MINT_NOT_I4)
4146 sp [-1].data.i = ~ sp [-1].data.i;
4147 ++ip;
4148 MINT_IN_BREAK;
4149 MINT_IN_CASE(MINT_NOT_I8)
4150 sp [-1].data.l = ~ sp [-1].data.l;
4151 ++ip;
4152 MINT_IN_BREAK;
4153 MINT_IN_CASE(MINT_CONV_I1_I4)
4154 sp [-1].data.i = (gint8)sp [-1].data.i;
4155 ++ip;
4156 MINT_IN_BREAK;
4157 MINT_IN_CASE(MINT_CONV_I1_I8)
4158 sp [-1].data.i = (gint8)sp [-1].data.l;
4159 ++ip;
4160 MINT_IN_BREAK;
4161 MINT_IN_CASE(MINT_CONV_I1_R4)
4162 sp [-1].data.i = (gint8) (gint32) sp [-1].data.f_r4;
4163 ++ip;
4164 MINT_IN_BREAK;
4165 MINT_IN_CASE(MINT_CONV_I1_R8)
4166 /* without gint32 cast, C compiler is allowed to use undefined
4167 * behaviour if data.f is bigger than >255. See conv.fpint section
4168 * in C standard:
4169 * > The conversion truncates; that is, the fractional part
4170 * > is discarded. The behavior is undefined if the truncated
4171 * > value cannot be represented in the destination type.
4172 * */
4173 sp [-1].data.i = (gint8) (gint32) sp [-1].data.f;
4174 ++ip;
4175 MINT_IN_BREAK;
4176 MINT_IN_CASE(MINT_CONV_U1_I4)
4177 sp [-1].data.i = (guint8)sp [-1].data.i;
4178 ++ip;
4179 MINT_IN_BREAK;
4180 MINT_IN_CASE(MINT_CONV_U1_I8)
4181 sp [-1].data.i = (guint8)sp [-1].data.l;
4182 ++ip;
4183 MINT_IN_BREAK;
4184 MINT_IN_CASE(MINT_CONV_U1_R4)
4185 sp [-1].data.i = (guint8) (guint32) sp [-1].data.f_r4;
4186 ++ip;
4187 MINT_IN_BREAK;
4188 MINT_IN_CASE(MINT_CONV_U1_R8)
4189 sp [-1].data.i = (guint8) (guint32) sp [-1].data.f;
4190 ++ip;
4191 MINT_IN_BREAK;
4192 MINT_IN_CASE(MINT_CONV_I2_I4)
4193 sp [-1].data.i = (gint16)sp [-1].data.i;
4194 ++ip;
4195 MINT_IN_BREAK;
4196 MINT_IN_CASE(MINT_CONV_I2_I8)
4197 sp [-1].data.i = (gint16)sp [-1].data.l;
4198 ++ip;
4199 MINT_IN_BREAK;
4200 MINT_IN_CASE(MINT_CONV_I2_R4)
4201 sp [-1].data.i = (gint16) (gint32) sp [-1].data.f_r4;
4202 ++ip;
4203 MINT_IN_BREAK;
4204 MINT_IN_CASE(MINT_CONV_I2_R8)
4205 sp [-1].data.i = (gint16) (gint32) sp [-1].data.f;
4206 ++ip;
4207 MINT_IN_BREAK;
4208 MINT_IN_CASE(MINT_CONV_U2_I4)
4209 sp [-1].data.i = (guint16)sp [-1].data.i;
4210 ++ip;
4211 MINT_IN_BREAK;
4212 MINT_IN_CASE(MINT_CONV_U2_I8)
4213 sp [-1].data.i = (guint16)sp [-1].data.l;
4214 ++ip;
4215 MINT_IN_BREAK;
4216 MINT_IN_CASE(MINT_CONV_U2_R4)
4217 sp [-1].data.i = (guint16) (guint32) sp [-1].data.f_r4;
4218 ++ip;
4219 MINT_IN_BREAK;
4220 MINT_IN_CASE(MINT_CONV_U2_R8)
4221 sp [-1].data.i = (guint16) (guint32) sp [-1].data.f;
4222 ++ip;
4223 MINT_IN_BREAK;
4224 MINT_IN_CASE(MINT_CONV_I4_R4)
4225 sp [-1].data.i = (gint32) sp [-1].data.f_r4;
4226 ++ip;
4227 MINT_IN_BREAK;
4228 MINT_IN_CASE(MINT_CONV_I4_R8)
4229 sp [-1].data.i = (gint32)sp [-1].data.f;
4230 ++ip;
4231 MINT_IN_BREAK;
4232 MINT_IN_CASE(MINT_CONV_U4_I8)
4233 MINT_IN_CASE(MINT_CONV_I4_I8)
4234 sp [-1].data.i = (gint32)sp [-1].data.l;
4235 ++ip;
4236 MINT_IN_BREAK;
4237 MINT_IN_CASE(MINT_CONV_I4_I8_SP)
4238 sp [-2].data.i = (gint32)sp [-2].data.l;
4239 ++ip;
4240 MINT_IN_BREAK;
4241 MINT_IN_CASE(MINT_CONV_U4_R4)
4242 /* needed on arm64 */
4243 if (isinf (sp [-1].data.f_r4))
4244 sp [-1].data.i = 0;
4245 /* needed by wasm */
4246 else if (isnan (sp [-1].data.f_r4))
4247 sp [-1].data.i = 0;
4248 else
4249 sp [-1].data.i = (guint32) sp [-1].data.f_r4;
4250 ++ip;
4251 MINT_IN_BREAK;
4252 MINT_IN_CASE(MINT_CONV_U4_R8)
4253 /* needed on arm64 */
4254 if (mono_isinf (sp [-1].data.f))
4255 sp [-1].data.i = 0;
4256 /* needed by wasm */
4257 else if (isnan (sp [-1].data.f))
4258 sp [-1].data.i = 0;
4259 else
4260 sp [-1].data.i = (guint32)sp [-1].data.f;
4261 ++ip;
4262 MINT_IN_BREAK;
4263 MINT_IN_CASE(MINT_CONV_I8_I4)
4264 sp [-1].data.l = sp [-1].data.i;
4265 ++ip;
4266 MINT_IN_BREAK;
4267 MINT_IN_CASE(MINT_CONV_I8_I4_SP)
4268 sp [-2].data.l = sp [-2].data.i;
4269 ++ip;
4270 MINT_IN_BREAK;
4271 MINT_IN_CASE(MINT_CONV_I8_U4)
4272 sp [-1].data.l = (guint32)sp [-1].data.i;
4273 ++ip;
4274 MINT_IN_BREAK;
4275 MINT_IN_CASE(MINT_CONV_I8_R4)
4276 sp [-1].data.l = (gint64) sp [-1].data.f_r4;
4277 ++ip;
4278 MINT_IN_BREAK;
4279 MINT_IN_CASE(MINT_CONV_I8_R8)
4280 sp [-1].data.l = (gint64)sp [-1].data.f;
4281 ++ip;
4282 MINT_IN_BREAK;
4283 MINT_IN_CASE(MINT_CONV_R4_I4)
4284 sp [-1].data.f_r4 = (float)sp [-1].data.i;
4285 ++ip;
4286 MINT_IN_BREAK;
4287 MINT_IN_CASE(MINT_CONV_R4_I8)
4288 sp [-1].data.f_r4 = (float)sp [-1].data.l;
4289 ++ip;
4290 MINT_IN_BREAK;
4291 MINT_IN_CASE(MINT_CONV_R4_R8)
4292 sp [-1].data.f_r4 = (float)sp [-1].data.f;
4293 ++ip;
4294 MINT_IN_BREAK;
4295 MINT_IN_CASE(MINT_CONV_R8_I4)
4296 sp [-1].data.f = (double)sp [-1].data.i;
4297 ++ip;
4298 MINT_IN_BREAK;
4299 MINT_IN_CASE(MINT_CONV_R8_I8)
4300 sp [-1].data.f = (double)sp [-1].data.l;
4301 ++ip;
4302 MINT_IN_BREAK;
4303 MINT_IN_CASE(MINT_CONV_R8_R4)
4304 sp [-1].data.f = (double) sp [-1].data.f_r4;
4305 ++ip;
4306 MINT_IN_BREAK;
4307 MINT_IN_CASE(MINT_CONV_R8_R4_SP)
4308 sp [-2].data.f = (double) sp [-2].data.f_r4;
4309 ++ip;
4310 MINT_IN_BREAK;
4311 MINT_IN_CASE(MINT_CONV_U8_I4)
4312 sp [-1].data.l = sp [-1].data.i & 0xffffffff;
4313 ++ip;
4314 MINT_IN_BREAK;
4315 MINT_IN_CASE(MINT_CONV_U8_R4)
4316 sp [-1].data.l = (guint64) sp [-1].data.f_r4;
4317 ++ip;
4318 MINT_IN_BREAK;
4319 MINT_IN_CASE(MINT_CONV_U8_R8)
4320 sp [-1].data.l = (guint64)sp [-1].data.f;
4321 ++ip;
4322 MINT_IN_BREAK;
4323 MINT_IN_CASE(MINT_CPOBJ) {
4324 c = (MonoClass*)imethod->data_items[* (guint16 *)(ip + 1)];
4325 g_assert (m_class_is_valuetype (c));
4326 /* if this assertion fails, we need to add a write barrier */
4327 g_assert (!MONO_TYPE_IS_REFERENCE (m_class_get_byval_arg (c)));
4328 stackval_from_data (m_class_get_byval_arg (c), (stackval*)sp [-2].data.p, sp [-1].data.p, FALSE);
4329 ip += 2;
4330 sp -= 2;
4331 MINT_IN_BREAK;
4333 MINT_IN_CASE(MINT_CPOBJ_VT) {
4334 c = (MonoClass*)imethod->data_items[* (guint16 *)(ip + 1)];
4335 mono_value_copy_internal (sp [-2].data.vt, sp [-1].data.vt, c);
4336 ip += 2;
4337 sp -= 2;
4338 MINT_IN_BREAK;
4340 MINT_IN_CASE(MINT_LDOBJ_VT) {
4341 int size = READ32(ip + 1);
4342 ip += 3;
4343 memcpy (vt_sp, sp [-1].data.p, size);
4344 sp [-1].data.p = vt_sp;
4345 vt_sp += ALIGN_TO (size, MINT_VT_ALIGNMENT);
4346 MINT_IN_BREAK;
4348 MINT_IN_CASE(MINT_LDSTR)
4349 sp->data.p = imethod->data_items [* (guint16 *)(ip + 1)];
4350 ++sp;
4351 ip += 2;
4352 MINT_IN_BREAK;
4353 MINT_IN_CASE(MINT_LDSTR_TOKEN) {
4354 MonoString *s = NULL;
4355 guint32 strtoken = (guint32)(gsize)imethod->data_items [* (guint16 *)(ip + 1)];
4357 MonoMethod *method = imethod->method;
4358 if (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD) {
4359 s = (MonoString*)mono_method_get_wrapper_data (method, strtoken);
4360 } else if (method->wrapper_type != MONO_WRAPPER_NONE) {
4361 s = mono_string_new_wrapper_internal ((const char*)mono_method_get_wrapper_data (method, strtoken));
4362 } else {
4363 g_assert_not_reached ();
4365 sp->data.p = s;
4366 ++sp;
4367 ip += 2;
4368 MINT_IN_BREAK;
4370 MINT_IN_CASE(MINT_NEWOBJ_ARRAY) {
4371 MonoClass *newobj_class;
4372 guint32 token = * (guint16 *)(ip + 1);
4373 guint16 param_count = * (guint16 *)(ip + 2);
4375 newobj_class = (MonoClass*) imethod->data_items [token];
4377 sp -= param_count;
4378 sp->data.o = ves_array_create (imethod->domain, newobj_class, param_count, sp, error);
4379 if (!mono_error_ok (error))
4380 THROW_EX (mono_error_convert_to_exception (error), ip);
4382 ++sp;
4383 ip += 3;
4384 MINT_IN_BREAK;
4386 MINT_IN_CASE(MINT_NEWOBJ_FAST)
4387 MINT_IN_CASE(MINT_NEWOBJ_VT_FAST)
4388 MINT_IN_CASE(MINT_NEWOBJ_VTST_FAST) {
4389 guint16 param_count;
4390 gboolean vt = *ip != MINT_NEWOBJ_FAST;
4391 stackval valuetype_this;
4393 frame->ip = ip;
4395 child_frame.imethod = (InterpMethod*) imethod->data_items [*(guint16*)(ip + 1)];
4396 param_count = *(guint16*)(ip + 2);
4398 if (param_count) {
4399 sp -= param_count;
4400 memmove (sp + 1, sp, param_count * sizeof (stackval));
4402 child_frame.stack_args = sp;
4404 if (vt) {
4405 gboolean vtst = *ip == MINT_NEWOBJ_VTST_FAST;
4406 if (vtst) {
4407 memset (vt_sp, 0, *(guint16*)(ip + 3));
4408 sp->data.p = vt_sp;
4409 valuetype_this.data.p = vt_sp;
4410 ip += 4;
4411 } else {
4412 memset (&valuetype_this, 0, sizeof (stackval));
4413 sp->data.p = &valuetype_this;
4414 ip += 3;
4416 } else {
4417 MonoVTable *vtable = (MonoVTable*) imethod->data_items [*(guint16*)(ip + 3)];
4418 if (G_UNLIKELY (!vtable->initialized)) {
4419 mono_runtime_class_init_full (vtable, error);
4420 if (!mono_error_ok (error))
4421 THROW_EX (mono_error_convert_to_exception (error), ip);
4423 frame_objref (frame) = mono_gc_alloc_obj (vtable, m_class_get_instance_size (vtable->klass));
4424 if (G_UNLIKELY (!frame_objref (frame))) {
4425 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", m_class_get_instance_size (vtable->klass));
4426 THROW_EX (mono_error_convert_to_exception (error), ip);
4428 sp->data.o = frame_objref (frame);
4429 ip += 4;
4432 interp_exec_method (&child_frame, context, error);
4434 CHECK_RESUME_STATE (context);
4436 if (vt)
4437 *sp = valuetype_this;
4438 else
4439 sp->data.p = frame_objref (frame);
4440 ++sp;
4441 MINT_IN_BREAK;
4443 MINT_IN_CASE(MINT_NEWOBJ) {
4444 MonoClass *newobj_class;
4445 MonoMethodSignature *csig;
4446 stackval valuetype_this;
4447 guint32 token;
4448 stackval retval;
4450 frame->ip = ip;
4452 token = * (guint16 *)(ip + 1);
4453 ip += 2;
4455 child_frame.ip = NULL;
4456 child_frame.ex = NULL;
4458 child_frame.imethod = (InterpMethod*)imethod->data_items [token];
4459 csig = mono_method_signature_internal (child_frame.imethod->method);
4460 newobj_class = child_frame.imethod->method->klass;
4461 /*if (profiling_classes) {
4462 guint count = GPOINTER_TO_UINT (g_hash_table_lookup (profiling_classes, newobj_class));
4463 count++;
4464 g_hash_table_insert (profiling_classes, newobj_class, GUINT_TO_POINTER (count));
4467 g_assert (csig->hasthis);
4468 if (csig->param_count) {
4469 sp -= csig->param_count;
4470 memmove (sp + 1, sp, csig->param_count * sizeof (stackval));
4472 child_frame.stack_args = sp;
4475 * First arg is the object.
4477 if (m_class_is_valuetype (newobj_class)) {
4478 MonoType *t = m_class_get_byval_arg (newobj_class);
4479 memset (&valuetype_this, 0, sizeof (stackval));
4480 if (!m_class_is_enumtype (newobj_class) && (t->type == MONO_TYPE_VALUETYPE || (t->type == MONO_TYPE_GENERICINST && mono_type_generic_inst_is_valuetype (t)))) {
4481 sp->data.p = vt_sp;
4482 valuetype_this.data.p = vt_sp;
4483 } else {
4484 sp->data.p = &valuetype_this;
4486 } else {
4487 if (newobj_class != mono_defaults.string_class) {
4488 MonoVTable *vtable = mono_class_vtable_checked (imethod->domain, newobj_class, error);
4489 if (!mono_error_ok (error) || !mono_runtime_class_init_full (vtable, error))
4490 THROW_EX (mono_error_convert_to_exception (error), ip);
4491 frame_objref (frame) = mono_object_new_checked (imethod->domain, newobj_class, error);
4492 mono_error_cleanup (error); /* FIXME: don't swallow the error */
4493 EXCEPTION_CHECKPOINT;
4494 sp->data.o = frame_objref (frame);
4495 #ifndef DISABLE_REMOTING
4496 if (mono_object_is_transparent_proxy (frame_objref (frame))) {
4497 MonoMethod *remoting_invoke_method = mono_marshal_get_remoting_invoke_with_check (child_frame.imethod->method, error);
4498 mono_error_assert_ok (error);
4499 child_frame.imethod = mono_interp_get_imethod (imethod->domain, remoting_invoke_method, error);
4500 mono_error_assert_ok (error);
4502 #endif
4503 } else {
4504 sp->data.p = NULL;
4505 child_frame.retval = &retval;
4509 interp_exec_method (&child_frame, context, error);
4511 CHECK_RESUME_STATE (context);
4514 * a constructor returns void, but we need to return the object we created
4516 if (m_class_is_valuetype (newobj_class) && !m_class_is_enumtype (newobj_class)) {
4517 *sp = valuetype_this;
4518 } else if (newobj_class == mono_defaults.string_class) {
4519 *sp = retval;
4520 } else {
4521 sp->data.o = frame_objref (frame);
4523 ++sp;
4524 MINT_IN_BREAK;
4526 MINT_IN_CASE(MINT_NEWOBJ_MAGIC) {
4527 frame->ip = ip;
4528 ip += 2;
4530 MINT_IN_BREAK;
4532 MINT_IN_CASE(MINT_INTRINS_BYREFERENCE_CTOR) {
4533 MonoMethodSignature *csig;
4534 guint32 token;
4536 frame->ip = ip;
4537 token = * (guint16 *)(ip + 1);
4538 ip += 2;
4540 InterpMethod *cmethod = (InterpMethod*)imethod->data_items [token];
4541 csig = mono_method_signature_internal (cmethod->method);
4543 g_assert (csig->hasthis);
4544 sp -= csig->param_count;
4546 gpointer arg0 = sp [0].data.p;
4548 gpointer *byreference_this = (gpointer*)vt_sp;
4549 *byreference_this = arg0;
4551 /* Followed by a VTRESULT opcode which will push the result on the stack */
4552 ++sp;
4553 MINT_IN_BREAK;
4555 MINT_IN_CASE(MINT_INTRINS_BYREFERENCE_GET_VALUE) {
4556 gpointer *byreference_this = (gpointer*)sp [-1].data.p;
4557 sp [-1].data.p = *byreference_this;
4558 ++ip;
4559 MINT_IN_BREAK;
4561 MINT_IN_CASE(MINT_INTRINS_UNSAFE_ADD_BYTE_OFFSET) {
4562 sp -= 2;
4563 sp [0].data.p = (guint8*)sp [0].data.p + sp [1].data.i;
4564 sp ++;
4565 ++ip;
4566 MINT_IN_BREAK;
4568 MINT_IN_CASE(MINT_INTRINS_UNSAFE_BYTE_OFFSET) {
4569 sp -= 2;
4570 sp [0].data.i = (guint8*)sp [1].data.p - (guint8*)sp [0].data.p;
4571 sp ++;
4572 ++ip;
4573 MINT_IN_BREAK;
4575 MINT_IN_CASE(MINT_INTRINS_RUNTIMEHELPERS_OBJECT_HAS_COMPONENT_SIZE) {
4576 sp -= 1;
4577 MonoObject *obj = sp [0].data.o;
4578 sp [0].data.i = (obj->vtable->flags & MONO_VT_FLAG_ARRAY_OR_STRING) != 0;
4579 sp ++;
4580 ++ip;
4581 MINT_IN_BREAK;
4583 MINT_IN_CASE(MINT_CASTCLASS_INTERFACE)
4584 MINT_IN_CASE(MINT_ISINST_INTERFACE) {
4585 gboolean isinst_instr = *ip == MINT_ISINST_INTERFACE;
4586 c = (MonoClass*)imethod->data_items [*(guint16 *)(ip + 1)];
4587 if ((o = sp [-1].data.o)) {
4588 gboolean isinst;
4589 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (o->vtable, m_class_get_interface_id (c))) {
4590 isinst = TRUE;
4591 } else if (m_class_is_array_special_interface (c) || mono_object_is_transparent_proxy (o)) {
4592 /* slow path */
4593 isinst = mono_object_isinst_checked (o, c, error) != NULL;
4594 mono_error_cleanup (error); /* FIXME: don't swallow the error */
4595 } else {
4596 isinst = FALSE;
4599 if (!isinst) {
4600 if (isinst_instr)
4601 sp [-1].data.p = NULL;
4602 else
4603 THROW_EX (mono_get_exception_invalid_cast (), ip);
4606 ip += 2;
4607 MINT_IN_BREAK;
4609 MINT_IN_CASE(MINT_CASTCLASS_COMMON)
4610 MINT_IN_CASE(MINT_ISINST_COMMON) {
4611 gboolean isinst_instr = *ip == MINT_ISINST_COMMON;
4612 c = (MonoClass*)imethod->data_items [*(guint16 *)(ip + 1)];
4613 if ((o = sp [-1].data.o)) {
4614 gboolean isinst = mono_class_has_parent_fast (o->vtable->klass, c);
4616 if (!isinst) {
4617 if (isinst_instr)
4618 sp [-1].data.p = NULL;
4619 else
4620 THROW_EX (mono_get_exception_invalid_cast (), ip);
4623 ip += 2;
4624 MINT_IN_BREAK;
4626 MINT_IN_CASE(MINT_CASTCLASS)
4627 MINT_IN_CASE(MINT_ISINST) {
4628 gboolean isinst_instr = *ip == MINT_ISINST;
4629 c = (MonoClass*)imethod->data_items [*(guint16 *)(ip + 1)];
4630 if ((o = sp [-1].data.o)) {
4631 MonoObject *isinst_obj = mono_object_isinst_checked (o, c, error);
4632 mono_error_cleanup (error); /* FIXME: don't swallow the error */
4633 if (!isinst_obj) {
4634 if (isinst_instr)
4635 sp [-1].data.p = NULL;
4636 else
4637 THROW_EX (mono_get_exception_invalid_cast (), ip);
4640 ip += 2;
4641 MINT_IN_BREAK;
4643 MINT_IN_CASE(MINT_CONV_R_UN_I4)
4644 sp [-1].data.f = (double)(guint32)sp [-1].data.i;
4645 ++ip;
4646 MINT_IN_BREAK;
4647 MINT_IN_CASE(MINT_CONV_R_UN_I8)
4648 sp [-1].data.f = (double)(guint64)sp [-1].data.l;
4649 ++ip;
4650 MINT_IN_BREAK;
4651 MINT_IN_CASE(MINT_UNBOX)
4652 c = (MonoClass*)imethod->data_items[*(guint16 *)(ip + 1)];
4654 o = sp [-1].data.o;
4655 if (!o)
4656 THROW_EX (mono_get_exception_null_reference (), ip);
4658 if (!(m_class_get_rank (o->vtable->klass) == 0 && m_class_get_element_class (o->vtable->klass) == m_class_get_element_class (c)))
4659 THROW_EX (mono_get_exception_invalid_cast (), ip);
4661 sp [-1].data.p = mono_object_unbox_internal (o);
4662 ip += 2;
4663 MINT_IN_BREAK;
4664 MINT_IN_CASE(MINT_THROW)
4665 --sp;
4666 if (!sp->data.p)
4667 sp->data.p = mono_get_exception_null_reference ();
4669 THROW_EX ((MonoException *)sp->data.p, ip);
4670 MINT_IN_BREAK;
4671 MINT_IN_CASE(MINT_CHECKPOINT)
4672 /* Do synchronous checking of abort requests */
4673 EXCEPTION_CHECKPOINT;
4674 ++ip;
4675 MINT_IN_BREAK;
4676 MINT_IN_CASE(MINT_SAFEPOINT)
4677 /* Do synchronous checking of abort requests */
4678 EXCEPTION_CHECKPOINT;
4679 /* Poll safepoint */
4680 mono_threads_safepoint ();
4681 ++ip;
4682 MINT_IN_BREAK;
4683 MINT_IN_CASE(MINT_LDFLDA_UNSAFE)
4684 o = sp [-1].data.o;
4685 sp[-1].data.p = (char *)o + * (guint16 *)(ip + 1);
4686 ip += 2;
4687 MINT_IN_BREAK;
4688 MINT_IN_CASE(MINT_LDFLDA)
4689 o = sp [-1].data.o;
4690 if (!o)
4691 THROW_EX (mono_get_exception_null_reference (), ip);
4692 sp[-1].data.p = (char *)o + * (guint16 *)(ip + 1);
4693 ip += 2;
4694 MINT_IN_BREAK;
4695 MINT_IN_CASE(MINT_CKNULL_N) {
4696 /* Same as CKNULL, but further down the stack */
4697 int n = *(guint16*)(ip + 1);
4698 o = sp [-n].data.o;
4699 if (!o)
4700 THROW_EX (mono_get_exception_null_reference (), ip);
4701 ip += 2;
4702 MINT_IN_BREAK;
4705 #define LDFLD_UNALIGNED(datamem, fieldtype, unaligned) \
4706 o = sp [-1].data.o; \
4707 if (!o) \
4708 THROW_EX (mono_get_exception_null_reference (), ip); \
4709 if (unaligned) \
4710 memcpy (&sp[-1].data.datamem, (char *)o + * (guint16 *)(ip + 1), sizeof (fieldtype)); \
4711 else \
4712 sp[-1].data.datamem = * (fieldtype *)((char *)o + * (guint16 *)(ip + 1)) ; \
4713 ip += 2;
4715 #define LDFLD(datamem, fieldtype) LDFLD_UNALIGNED(datamem, fieldtype, FALSE)
4717 MINT_IN_CASE(MINT_LDFLD_I1) LDFLD(i, gint8); MINT_IN_BREAK;
4718 MINT_IN_CASE(MINT_LDFLD_U1) LDFLD(i, guint8); MINT_IN_BREAK;
4719 MINT_IN_CASE(MINT_LDFLD_I2) LDFLD(i, gint16); MINT_IN_BREAK;
4720 MINT_IN_CASE(MINT_LDFLD_U2) LDFLD(i, guint16); MINT_IN_BREAK;
4721 MINT_IN_CASE(MINT_LDFLD_I4) LDFLD(i, gint32); MINT_IN_BREAK;
4722 MINT_IN_CASE(MINT_LDFLD_I8) LDFLD(l, gint64); MINT_IN_BREAK;
4723 MINT_IN_CASE(MINT_LDFLD_R4) LDFLD(f_r4, float); MINT_IN_BREAK;
4724 MINT_IN_CASE(MINT_LDFLD_R8) LDFLD(f, double); MINT_IN_BREAK;
4725 MINT_IN_CASE(MINT_LDFLD_O) LDFLD(p, gpointer); MINT_IN_BREAK;
4726 MINT_IN_CASE(MINT_LDFLD_P) LDFLD(p, gpointer); MINT_IN_BREAK;
4727 MINT_IN_CASE(MINT_LDFLD_I8_UNALIGNED) LDFLD_UNALIGNED(l, gint64, TRUE); MINT_IN_BREAK;
4728 MINT_IN_CASE(MINT_LDFLD_R8_UNALIGNED) LDFLD_UNALIGNED(f, double, TRUE); MINT_IN_BREAK;
4730 MINT_IN_CASE(MINT_LDFLD_VT) {
4731 o = sp [-1].data.o;
4732 if (!o)
4733 THROW_EX (mono_get_exception_null_reference (), ip);
4735 int size = READ32(ip + 2);
4736 sp [-1].data.p = vt_sp;
4737 memcpy (sp [-1].data.p, (char *)o + * (guint16 *)(ip + 1), size);
4738 vt_sp += ALIGN_TO (size, MINT_VT_ALIGNMENT);
4739 ip += 4;
4740 MINT_IN_BREAK;
4743 MINT_IN_CASE(MINT_LDRMFLD) {
4744 MonoClassField *field;
4745 char *addr;
4747 o = sp [-1].data.o;
4748 if (!o)
4749 THROW_EX (mono_get_exception_null_reference (), ip);
4750 field = (MonoClassField*)imethod->data_items[* (guint16 *)(ip + 1)];
4751 ip += 2;
4752 #ifndef DISABLE_REMOTING
4753 if (mono_object_is_transparent_proxy (o)) {
4754 gpointer tmp;
4755 MonoClass *klass = ((MonoTransparentProxy*)o)->remote_class->proxy_class;
4757 addr = (char*)mono_load_remote_field_checked (o, klass, field, &tmp, error);
4758 mono_error_cleanup (error); /* FIXME: don't swallow the error */
4759 } else
4760 #endif
4761 addr = (char*)o + field->offset;
4763 stackval_from_data (field->type, &sp [-1], addr, FALSE);
4764 MINT_IN_BREAK;
4767 MINT_IN_CASE(MINT_LDRMFLD_VT) {
4768 MonoClassField *field;
4769 char *addr;
4771 o = sp [-1].data.o;
4772 if (!o)
4773 THROW_EX (mono_get_exception_null_reference (), ip);
4775 field = (MonoClassField*)imethod->data_items[* (guint16 *)(ip + 1)];
4776 MonoClass *klass = mono_class_from_mono_type_internal (field->type);
4777 i32 = mono_class_value_size (klass, NULL);
4779 ip += 2;
4780 #ifndef DISABLE_REMOTING
4781 if (mono_object_is_transparent_proxy (o)) {
4782 gpointer tmp;
4783 MonoClass *klass = ((MonoTransparentProxy*)o)->remote_class->proxy_class;
4784 addr = (char*)mono_load_remote_field_checked (o, klass, field, &tmp, error);
4785 mono_error_cleanup (error); /* FIXME: don't swallow the error */
4786 } else
4787 #endif
4788 addr = (char*)o + field->offset;
4790 sp [-1].data.p = vt_sp;
4791 vt_sp += ALIGN_TO (i32, MINT_VT_ALIGNMENT);
4792 memcpy(sp [-1].data.p, addr, i32);
4793 MINT_IN_BREAK;
4796 #define STFLD_UNALIGNED(datamem, fieldtype, unaligned) \
4797 o = sp [-2].data.o; \
4798 if (!o) \
4799 THROW_EX (mono_get_exception_null_reference (), ip); \
4800 sp -= 2; \
4801 if (unaligned) \
4802 memcpy ((char *)o + * (guint16 *)(ip + 1), &sp[1].data.datamem, sizeof (fieldtype)); \
4803 else \
4804 * (fieldtype *)((char *)o + * (guint16 *)(ip + 1)) = sp[1].data.datamem; \
4805 ip += 2;
4807 #define STFLD(datamem, fieldtype) STFLD_UNALIGNED(datamem, fieldtype, FALSE)
4809 MINT_IN_CASE(MINT_STFLD_I1) STFLD(i, gint8); MINT_IN_BREAK;
4810 MINT_IN_CASE(MINT_STFLD_U1) STFLD(i, guint8); MINT_IN_BREAK;
4811 MINT_IN_CASE(MINT_STFLD_I2) STFLD(i, gint16); MINT_IN_BREAK;
4812 MINT_IN_CASE(MINT_STFLD_U2) STFLD(i, guint16); MINT_IN_BREAK;
4813 MINT_IN_CASE(MINT_STFLD_I4) STFLD(i, gint32); MINT_IN_BREAK;
4814 MINT_IN_CASE(MINT_STFLD_I8) STFLD(l, gint64); MINT_IN_BREAK;
4815 MINT_IN_CASE(MINT_STFLD_R4) STFLD(f_r4, float); MINT_IN_BREAK;
4816 MINT_IN_CASE(MINT_STFLD_R8) STFLD(f, double); MINT_IN_BREAK;
4817 MINT_IN_CASE(MINT_STFLD_P) STFLD(p, gpointer); MINT_IN_BREAK;
4818 MINT_IN_CASE(MINT_STFLD_O)
4819 o = sp [-2].data.o;
4820 if (!o)
4821 THROW_EX (mono_get_exception_null_reference (), ip);
4822 sp -= 2;
4823 mono_gc_wbarrier_set_field_internal (o, (char *) o + * (guint16 *)(ip + 1), sp [1].data.o);
4824 ip += 2;
4825 MINT_IN_BREAK;
4826 MINT_IN_CASE(MINT_STFLD_I8_UNALIGNED) STFLD_UNALIGNED(l, gint64, TRUE); MINT_IN_BREAK;
4827 MINT_IN_CASE(MINT_STFLD_R8_UNALIGNED) STFLD_UNALIGNED(f, double, TRUE); MINT_IN_BREAK;
4829 MINT_IN_CASE(MINT_STFLD_VT) {
4830 o = sp [-2].data.o;
4831 if (!o)
4832 THROW_EX (mono_get_exception_null_reference (), ip);
4833 sp -= 2;
4835 MonoClass *klass = (MonoClass*)imethod->data_items[* (guint16 *)(ip + 2)];
4836 i32 = mono_class_value_size (klass, NULL);
4838 guint16 offset = * (guint16 *)(ip + 1);
4839 mono_value_copy_internal ((char *) o + offset, sp [1].data.p, klass);
4841 vt_sp -= ALIGN_TO (i32, MINT_VT_ALIGNMENT);
4842 ip += 3;
4843 MINT_IN_BREAK;
4845 MINT_IN_CASE(MINT_STRMFLD) {
4846 MonoClassField *field;
4848 o = sp [-2].data.o;
4849 if (!o)
4850 THROW_EX (mono_get_exception_null_reference (), ip);
4852 field = (MonoClassField*)imethod->data_items[* (guint16 *)(ip + 1)];
4853 ip += 2;
4855 #ifndef DISABLE_REMOTING
4856 if (mono_object_is_transparent_proxy (o)) {
4857 MonoClass *klass = ((MonoTransparentProxy*)o)->remote_class->proxy_class;
4858 mono_store_remote_field_checked (o, klass, field, &sp [-1].data, error);
4859 mono_error_cleanup (error); /* FIXME: don't swallow the error */
4860 } else
4861 #endif
4862 stackval_to_data (field->type, &sp [-1], (char*)o + field->offset, FALSE);
4864 sp -= 2;
4865 MINT_IN_BREAK;
4867 MINT_IN_CASE(MINT_STRMFLD_VT) {
4868 MonoClassField *field;
4870 o = sp [-2].data.o;
4871 if (!o)
4872 THROW_EX (mono_get_exception_null_reference (), ip);
4873 field = (MonoClassField*)imethod->data_items[* (guint16 *)(ip + 1)];
4874 MonoClass *klass = mono_class_from_mono_type_internal (field->type);
4875 i32 = mono_class_value_size (klass, NULL);
4876 ip += 2;
4878 #ifndef DISABLE_REMOTING
4879 if (mono_object_is_transparent_proxy (o)) {
4880 MonoClass *klass = ((MonoTransparentProxy*)o)->remote_class->proxy_class;
4881 mono_store_remote_field_checked (o, klass, field, sp [-1].data.p, error);
4882 mono_error_cleanup (error); /* FIXME: don't swallow the error */
4883 } else
4884 #endif
4885 mono_value_copy_internal ((char *) o + field->offset, sp [-1].data.p, klass);
4887 sp -= 2;
4888 vt_sp -= ALIGN_TO (i32, MINT_VT_ALIGNMENT);
4889 MINT_IN_BREAK;
4891 MINT_IN_CASE(MINT_LDSFLDA) {
4892 MonoVTable *vtable = (MonoVTable*) imethod->data_items [*(guint16*)(ip + 1)];
4893 INIT_VTABLE (vtable);
4894 sp->data.p = imethod->data_items [*(guint16*)(ip + 2)];
4895 ip += 3;
4896 ++sp;
4897 MINT_IN_BREAK;
4900 MINT_IN_CASE(MINT_LDSSFLDA) {
4901 guint32 offset = READ32(ip + 1);
4902 sp->data.p = mono_get_special_static_data (offset);
4903 ip += 3;
4904 ++sp;
4905 MINT_IN_BREAK;
4908 /* We init class here to preserve cctor order */
4909 #define LDSFLD(datamem, fieldtype) { \
4910 MonoVTable *vtable = (MonoVTable*) imethod->data_items [*(guint16*)(ip + 1)]; \
4911 INIT_VTABLE (vtable); \
4912 sp[0].data.datamem = * (fieldtype *)(imethod->data_items [* (guint16 *)(ip + 2)]) ; \
4913 ip += 3; \
4914 sp++; \
4917 MINT_IN_CASE(MINT_LDSFLD_I1) LDSFLD(i, gint8); MINT_IN_BREAK;
4918 MINT_IN_CASE(MINT_LDSFLD_U1) LDSFLD(i, guint8); MINT_IN_BREAK;
4919 MINT_IN_CASE(MINT_LDSFLD_I2) LDSFLD(i, gint16); MINT_IN_BREAK;
4920 MINT_IN_CASE(MINT_LDSFLD_U2) LDSFLD(i, guint16); MINT_IN_BREAK;
4921 MINT_IN_CASE(MINT_LDSFLD_I4) LDSFLD(i, gint32); MINT_IN_BREAK;
4922 MINT_IN_CASE(MINT_LDSFLD_I8) LDSFLD(l, gint64); MINT_IN_BREAK;
4923 MINT_IN_CASE(MINT_LDSFLD_R4) LDSFLD(f_r4, float); MINT_IN_BREAK;
4924 MINT_IN_CASE(MINT_LDSFLD_R8) LDSFLD(f, double); MINT_IN_BREAK;
4925 MINT_IN_CASE(MINT_LDSFLD_O) LDSFLD(p, gpointer); MINT_IN_BREAK;
4926 MINT_IN_CASE(MINT_LDSFLD_P) LDSFLD(p, gpointer); MINT_IN_BREAK;
4928 MINT_IN_CASE(MINT_LDSFLD_VT) {
4929 MonoVTable *vtable = (MonoVTable*) imethod->data_items [*(guint16*)(ip + 1)];
4930 gpointer addr = imethod->data_items [*(guint16*)(ip + 2)];
4931 i32 = READ32(ip + 3);
4932 INIT_VTABLE (vtable);
4933 sp->data.p = vt_sp;
4935 memcpy (vt_sp, addr, i32);
4936 vt_sp += ALIGN_TO (i32, MINT_VT_ALIGNMENT);
4937 ip += 5;
4938 ++sp;
4939 MINT_IN_BREAK;
4942 #define LDTSFLD(datamem, fieldtype) { \
4943 guint32 offset = READ32(ip + 1); \
4944 MonoInternalThread *thread = mono_thread_internal_current (); \
4945 gpointer addr = ((char*)thread->static_data [offset & 0x3f]) + (offset >> 6); \
4946 sp[0].data.datamem = *(fieldtype*)addr; \
4947 ip += 3; \
4948 ++sp; \
4950 MINT_IN_CASE(MINT_LDTSFLD_I1) LDTSFLD(i, gint8); MINT_IN_BREAK;
4951 MINT_IN_CASE(MINT_LDTSFLD_U1) LDTSFLD(i, guint8); MINT_IN_BREAK;
4952 MINT_IN_CASE(MINT_LDTSFLD_I2) LDTSFLD(i, gint16); MINT_IN_BREAK;
4953 MINT_IN_CASE(MINT_LDTSFLD_U2) LDTSFLD(i, guint16); MINT_IN_BREAK;
4954 MINT_IN_CASE(MINT_LDTSFLD_I4) LDTSFLD(i, gint32); MINT_IN_BREAK;
4955 MINT_IN_CASE(MINT_LDTSFLD_I8) LDTSFLD(l, gint64); MINT_IN_BREAK;
4956 MINT_IN_CASE(MINT_LDTSFLD_R4) LDTSFLD(f_r4, float); MINT_IN_BREAK;
4957 MINT_IN_CASE(MINT_LDTSFLD_R8) LDTSFLD(f, double); MINT_IN_BREAK;
4958 MINT_IN_CASE(MINT_LDTSFLD_O) LDTSFLD(p, gpointer); MINT_IN_BREAK;
4959 MINT_IN_CASE(MINT_LDTSFLD_P) LDTSFLD(p, gpointer); MINT_IN_BREAK;
4961 MINT_IN_CASE(MINT_LDSSFLD) {
4962 MonoClassField *field = (MonoClassField*)imethod->data_items [* (guint16 *)(ip + 1)];
4963 guint32 offset = READ32(ip + 2);
4964 gpointer addr = mono_get_special_static_data (offset);
4965 stackval_from_data (field->type, sp, addr, FALSE);
4966 ip += 4;
4967 ++sp;
4968 MINT_IN_BREAK;
4970 MINT_IN_CASE(MINT_LDSSFLD_VT) {
4971 guint32 offset = READ32(ip + 1);
4972 gpointer addr = mono_get_special_static_data (offset);
4974 int size = READ32 (ip + 3);
4975 memcpy (vt_sp, addr, size);
4976 sp->data.p = vt_sp;
4977 vt_sp += ALIGN_TO (size, MINT_VT_ALIGNMENT);
4978 ip += 5;
4979 ++sp;
4980 MINT_IN_BREAK;
4982 #define STSFLD(datamem, fieldtype) { \
4983 MonoVTable *vtable = (MonoVTable*) imethod->data_items [*(guint16*)(ip + 1)]; \
4984 INIT_VTABLE (vtable); \
4985 sp --; \
4986 * (fieldtype *)(imethod->data_items [* (guint16 *)(ip + 2)]) = sp[0].data.datamem; \
4987 ip += 3; \
4990 MINT_IN_CASE(MINT_STSFLD_I1) STSFLD(i, gint8); MINT_IN_BREAK;
4991 MINT_IN_CASE(MINT_STSFLD_U1) STSFLD(i, guint8); MINT_IN_BREAK;
4992 MINT_IN_CASE(MINT_STSFLD_I2) STSFLD(i, gint16); MINT_IN_BREAK;
4993 MINT_IN_CASE(MINT_STSFLD_U2) STSFLD(i, guint16); MINT_IN_BREAK;
4994 MINT_IN_CASE(MINT_STSFLD_I4) STSFLD(i, gint32); MINT_IN_BREAK;
4995 MINT_IN_CASE(MINT_STSFLD_I8) STSFLD(l, gint64); MINT_IN_BREAK;
4996 MINT_IN_CASE(MINT_STSFLD_R4) STSFLD(f_r4, float); MINT_IN_BREAK;
4997 MINT_IN_CASE(MINT_STSFLD_R8) STSFLD(f, double); MINT_IN_BREAK;
4998 MINT_IN_CASE(MINT_STSFLD_P) STSFLD(p, gpointer); MINT_IN_BREAK;
4999 MINT_IN_CASE(MINT_STSFLD_O) STSFLD(p, gpointer); MINT_IN_BREAK;
5001 MINT_IN_CASE(MINT_STSFLD_VT) {
5002 MonoVTable *vtable = (MonoVTable*) imethod->data_items [*(guint16*)(ip + 1)];
5003 gpointer addr = imethod->data_items [*(guint16*)(ip + 2)];
5004 i32 = READ32(ip + 3);
5005 INIT_VTABLE (vtable);
5007 memcpy (addr, sp [-1].data.vt, i32);
5008 vt_sp -= ALIGN_TO (i32, MINT_VT_ALIGNMENT);
5009 ip += 4;
5010 --sp;
5011 MINT_IN_BREAK;
5014 #define STTSFLD(datamem, fieldtype) { \
5015 guint32 offset = READ32(ip + 1); \
5016 MonoInternalThread *thread = mono_thread_internal_current (); \
5017 gpointer addr = ((char*)thread->static_data [offset & 0x3f]) + (offset >> 6); \
5018 sp--; \
5019 *(fieldtype*)addr = sp[0].data.datamem; \
5020 ip += 3; \
5023 MINT_IN_CASE(MINT_STTSFLD_I1) STTSFLD(i, gint8); MINT_IN_BREAK;
5024 MINT_IN_CASE(MINT_STTSFLD_U1) STTSFLD(i, guint8); MINT_IN_BREAK;
5025 MINT_IN_CASE(MINT_STTSFLD_I2) STTSFLD(i, gint16); MINT_IN_BREAK;
5026 MINT_IN_CASE(MINT_STTSFLD_U2) STTSFLD(i, guint16); MINT_IN_BREAK;
5027 MINT_IN_CASE(MINT_STTSFLD_I4) STTSFLD(i, gint32); MINT_IN_BREAK;
5028 MINT_IN_CASE(MINT_STTSFLD_I8) STTSFLD(l, gint64); MINT_IN_BREAK;
5029 MINT_IN_CASE(MINT_STTSFLD_R4) STTSFLD(f_r4, float); MINT_IN_BREAK;
5030 MINT_IN_CASE(MINT_STTSFLD_R8) STTSFLD(f, double); MINT_IN_BREAK;
5031 MINT_IN_CASE(MINT_STTSFLD_P) STTSFLD(p, gpointer); MINT_IN_BREAK;
5032 MINT_IN_CASE(MINT_STTSFLD_O) STTSFLD(p, gpointer); MINT_IN_BREAK;
5034 MINT_IN_CASE(MINT_STSSFLD) {
5035 MonoClassField *field = (MonoClassField*)imethod->data_items [* (guint16 *)(ip + 1)];
5036 guint32 offset = READ32(ip + 2);
5037 gpointer addr = mono_get_special_static_data (offset);
5038 --sp;
5039 stackval_to_data (field->type, sp, addr, FALSE);
5040 ip += 4;
5041 MINT_IN_BREAK;
5043 MINT_IN_CASE(MINT_STSSFLD_VT) {
5044 guint32 offset = READ32(ip + 1);
5045 gpointer addr = mono_get_special_static_data (offset);
5046 --sp;
5047 int size = READ32 (ip + 3);
5048 memcpy (addr, sp->data.vt, size);
5049 vt_sp -= ALIGN_TO (size, MINT_VT_ALIGNMENT);
5050 ip += 5;
5051 MINT_IN_BREAK;
5054 MINT_IN_CASE(MINT_STOBJ_VT) {
5055 int size;
5056 c = (MonoClass*)imethod->data_items[* (guint16 *)(ip + 1)];
5057 ip += 2;
5058 size = mono_class_value_size (c, NULL);
5059 mono_value_copy_internal (sp [-2].data.p, sp [-1].data.p, c);
5060 vt_sp -= ALIGN_TO (size, MINT_VT_ALIGNMENT);
5061 sp -= 2;
5062 MINT_IN_BREAK;
5064 MINT_IN_CASE(MINT_CONV_OVF_I4_UN_R8)
5065 if (sp [-1].data.f < 0 || sp [-1].data.f > G_MAXINT32)
5066 THROW_EX (mono_get_exception_overflow (), ip);
5067 sp [-1].data.i = (gint32)sp [-1].data.f;
5068 ++ip;
5069 MINT_IN_BREAK;
5070 MINT_IN_CASE(MINT_CONV_OVF_U8_I4)
5071 if (sp [-1].data.i < 0)
5072 THROW_EX (mono_get_exception_overflow (), ip);
5073 sp [-1].data.l = sp [-1].data.i;
5074 ++ip;
5075 MINT_IN_BREAK;
5076 MINT_IN_CASE(MINT_CONV_OVF_U8_I8)
5077 if (sp [-1].data.l < 0)
5078 THROW_EX (mono_get_exception_overflow (), ip);
5079 ++ip;
5080 MINT_IN_BREAK;
5081 MINT_IN_CASE(MINT_CONV_OVF_I8_U8)
5082 if ((guint64) sp [-1].data.l > G_MAXINT64)
5083 THROW_EX (mono_get_exception_overflow (), ip);
5084 ++ip;
5085 MINT_IN_BREAK;
5086 MINT_IN_CASE(MINT_CONV_OVF_U8_R4)
5087 if (sp [-1].data.f_r4 < 0 || sp [-1].data.f_r4 > G_MAXUINT64 || isnan (sp [-1].data.f_r4))
5088 THROW_EX (mono_get_exception_overflow (), ip);
5089 sp [-1].data.l = (guint64)sp [-1].data.f_r4;
5090 ++ip;
5091 MINT_IN_BREAK;
5092 MINT_IN_CASE(MINT_CONV_OVF_U8_R8)
5093 if (sp [-1].data.f < 0 || sp [-1].data.f > G_MAXUINT64 || isnan (sp [-1].data.f))
5094 THROW_EX (mono_get_exception_overflow (), ip);
5095 sp [-1].data.l = (guint64)sp [-1].data.f;
5096 ++ip;
5097 MINT_IN_BREAK;
5098 MINT_IN_CASE(MINT_CONV_OVF_I8_UN_R8)
5099 if (sp [-1].data.f < 0 || sp [-1].data.f > G_MAXINT64)
5100 THROW_EX (mono_get_exception_overflow (), ip);
5101 sp [-1].data.l = (gint64)sp [-1].data.f;
5102 ++ip;
5103 MINT_IN_BREAK;
5104 MINT_IN_CASE(MINT_CONV_OVF_I8_UN_R4)
5105 if (sp [-1].data.f_r4 < 0 || sp [-1].data.f_r4 > G_MAXINT64)
5106 THROW_EX (mono_get_exception_overflow (), ip);
5107 sp [-1].data.l = (gint64)sp [-1].data.f_r4;
5108 ++ip;
5109 MINT_IN_BREAK;
5110 MINT_IN_CASE(MINT_CONV_OVF_I8_R4)
5111 if (sp [-1].data.f_r4 < G_MININT64 || sp [-1].data.f_r4 > G_MAXINT64 || isnan (sp [-1].data.f_r4))
5112 THROW_EX (mono_get_exception_overflow (), ip);
5113 sp [-1].data.l = (gint64)sp [-1].data.f_r4;
5114 ++ip;
5115 MINT_IN_BREAK;
5116 MINT_IN_CASE(MINT_CONV_OVF_I8_R8)
5117 if (sp [-1].data.f < G_MININT64 || sp [-1].data.f > G_MAXINT64 || isnan (sp [-1].data.f))
5118 THROW_EX (mono_get_exception_overflow (), ip);
5119 sp [-1].data.l = (gint64)sp [-1].data.f;
5120 ++ip;
5121 MINT_IN_BREAK;
5122 MINT_IN_CASE(MINT_CONV_OVF_I4_UN_I8)
5123 if ((guint64)sp [-1].data.l > G_MAXINT32)
5124 THROW_EX (mono_get_exception_overflow (), ip);
5125 sp [-1].data.i = (gint32)sp [-1].data.l;
5126 ++ip;
5127 MINT_IN_BREAK;
5128 MINT_IN_CASE(MINT_BOX) {
5129 MonoVTable *vtable = (MonoVTable*)imethod->data_items [* (guint16 *)(ip + 1)];
5130 guint16 offset = * (guint16 *)(ip + 2);
5132 frame_objref (frame) = mono_gc_alloc_obj (vtable, m_class_get_instance_size (vtable->klass));
5133 stackval_to_data (m_class_get_byval_arg (vtable->klass), &sp [-1 - offset], mono_object_get_data (frame_objref (frame)), FALSE);
5135 sp [-1 - offset].data.p = frame_objref (frame);
5137 ip += 3;
5138 MINT_IN_BREAK;
5140 MINT_IN_CASE(MINT_BOX_VT) {
5141 MonoVTable *vtable = (MonoVTable*)imethod->data_items [* (guint16 *)(ip + 1)];
5142 c = vtable->klass;
5143 guint16 offset = * (guint16 *)(ip + 2);
5144 gboolean pop_vt_sp = !(offset & BOX_NOT_CLEAR_VT_SP);
5145 offset &= ~BOX_NOT_CLEAR_VT_SP;
5147 int size = mono_class_value_size (c, NULL);
5148 frame_objref (frame) = mono_gc_alloc_obj (vtable, m_class_get_instance_size (vtable->klass));
5149 mono_value_copy_internal (mono_object_get_data (frame_objref (frame)), sp [-1 - offset].data.p, c);
5151 sp [-1 - offset].data.p = frame_objref (frame);
5152 size = ALIGN_TO (size, MINT_VT_ALIGNMENT);
5153 if (pop_vt_sp)
5154 vt_sp -= size;
5156 ip += 3;
5157 MINT_IN_BREAK;
5159 MINT_IN_CASE(MINT_BOX_NULLABLE) {
5160 c = (MonoClass*)imethod->data_items [* (guint16 *)(ip + 1)];
5161 guint16 offset = * (guint16 *)(ip + 2);
5162 gboolean pop_vt_sp = !(offset & BOX_NOT_CLEAR_VT_SP);
5163 offset &= ~BOX_NOT_CLEAR_VT_SP;
5165 int size = mono_class_value_size (c, NULL);
5167 sp [-1 - offset].data.o = mono_nullable_box (sp [-1 - offset].data.p, c, error);
5168 mono_error_cleanup (error); /* FIXME: don't swallow the error */
5170 size = ALIGN_TO (size, MINT_VT_ALIGNMENT);
5171 if (pop_vt_sp)
5172 vt_sp -= size;
5174 ip += 3;
5175 MINT_IN_BREAK;
5177 MINT_IN_CASE(MINT_NEWARR) {
5178 MonoVTable *vtable = (MonoVTable*)imethod->data_items[*(guint16 *)(ip + 1)];
5179 sp [-1].data.o = (MonoObject*) mono_array_new_specific_checked (vtable, sp [-1].data.i, error);
5180 if (!mono_error_ok (error)) {
5181 THROW_EX (mono_error_convert_to_exception (error), ip);
5183 mono_error_cleanup (error); /* FIXME: don't swallow the error */
5184 ip += 2;
5185 /*if (profiling_classes) {
5186 guint count = GPOINTER_TO_UINT (g_hash_table_lookup (profiling_classes, o->vtable->klass));
5187 count++;
5188 g_hash_table_insert (profiling_classes, o->vtable->klass, GUINT_TO_POINTER (count));
5191 MINT_IN_BREAK;
5193 MINT_IN_CASE(MINT_LDLEN)
5194 o = sp [-1].data.o;
5195 if (!o)
5196 THROW_EX (mono_get_exception_null_reference (), ip);
5197 sp [-1].data.nati = mono_array_length_internal ((MonoArray *)o);
5198 ++ip;
5199 MINT_IN_BREAK;
5200 MINT_IN_CASE(MINT_LDLEN_SPAN) {
5201 o = sp [-1].data.o;
5202 gsize offset_length = (gsize) *(gint16 *) (ip + 1);
5203 if (!o)
5204 THROW_EX (mono_get_exception_null_reference (), ip);
5205 sp [-1].data.nati = *(gint32 *) ((guint8 *) o + offset_length);
5206 ip += 2;
5207 MINT_IN_BREAK;
5209 MINT_IN_CASE(MINT_GETCHR) {
5210 MonoString *s;
5211 s = (MonoString*)sp [-2].data.p;
5212 if (!s)
5213 THROW_EX (mono_get_exception_null_reference (), ip);
5214 i32 = sp [-1].data.i;
5215 if (i32 < 0 || i32 >= mono_string_length_internal (s))
5216 THROW_EX (mono_get_exception_index_out_of_range (), ip);
5217 --sp;
5218 sp [-1].data.i = mono_string_chars_internal (s)[i32];
5219 ++ip;
5220 MINT_IN_BREAK;
5222 MINT_IN_CASE(MINT_GETITEM_SPAN) {
5223 guint8 *span = (guint8 *) sp [-2].data.p;
5224 int index = sp [-1].data.i;
5225 gsize element_size = (gsize) *(gint16 *) (ip + 1);
5226 gsize offset_length = (gsize) *(gint16 *) (ip + 2);
5227 gsize offset_pointer = (gsize) *(gint16 *) (ip + 3);
5228 sp--;
5230 if (!span)
5231 THROW_EX (mono_get_exception_null_reference (), ip);
5233 gint32 length = *(gint32 *) (span + offset_length);
5234 if (index < 0 || index >= length)
5235 THROW_EX (mono_get_exception_index_out_of_range (), ip);
5237 gpointer pointer = *(gpointer *)(span + offset_pointer);
5238 sp [-1].data.p = (guint8 *) pointer + index * element_size;
5240 ip += 4;
5241 MINT_IN_BREAK;
5243 MINT_IN_CASE(MINT_STRLEN)
5244 ++ip;
5245 o = sp [-1].data.o;
5246 if (!o)
5247 THROW_EX (mono_get_exception_null_reference (), ip);
5248 sp [-1].data.i = mono_string_length_internal ((MonoString*) o);
5249 MINT_IN_BREAK;
5250 MINT_IN_CASE(MINT_ARRAY_RANK)
5251 o = sp [-1].data.o;
5252 if (!o)
5253 THROW_EX (mono_get_exception_null_reference (), ip);
5254 sp [-1].data.i = m_class_get_rank (mono_object_class (sp [-1].data.p));
5255 ip++;
5256 MINT_IN_BREAK;
5257 MINT_IN_CASE(MINT_LDELEMA)
5258 MINT_IN_CASE(MINT_LDELEMA_TC) {
5259 gboolean needs_typecheck = *ip == MINT_LDELEMA_TC;
5261 MonoClass *klass = (MonoClass*)imethod->data_items [*(guint16 *) (ip + 1)];
5262 guint16 numargs = *(guint16 *) (ip + 2);
5263 ip += 3;
5264 sp -= numargs;
5266 o = sp [0].data.o;
5267 if (!o)
5268 THROW_EX (mono_get_exception_null_reference (), ip);
5269 sp->data.p = ves_array_element_address (frame, klass, (MonoArray *) o, &sp [1], needs_typecheck);
5270 if (frame->ex)
5271 THROW_EX (frame->ex, ip);
5272 ++sp;
5274 MINT_IN_BREAK;
5276 MINT_IN_CASE(MINT_LDELEM_I1) /* fall through */
5277 MINT_IN_CASE(MINT_LDELEM_U1) /* fall through */
5278 MINT_IN_CASE(MINT_LDELEM_I2) /* fall through */
5279 MINT_IN_CASE(MINT_LDELEM_U2) /* fall through */
5280 MINT_IN_CASE(MINT_LDELEM_I4) /* fall through */
5281 MINT_IN_CASE(MINT_LDELEM_U4) /* fall through */
5282 MINT_IN_CASE(MINT_LDELEM_I8) /* fall through */
5283 MINT_IN_CASE(MINT_LDELEM_I) /* fall through */
5284 MINT_IN_CASE(MINT_LDELEM_R4) /* fall through */
5285 MINT_IN_CASE(MINT_LDELEM_R8) /* fall through */
5286 MINT_IN_CASE(MINT_LDELEM_REF) /* fall through */
5287 MINT_IN_CASE(MINT_LDELEM_VT) {
5288 MonoArray *o;
5289 mono_u aindex;
5291 sp -= 2;
5293 o = (MonoArray*)sp [0].data.p;
5294 if (!o)
5295 THROW_EX (mono_get_exception_null_reference (), ip);
5297 aindex = sp [1].data.i;
5298 if (aindex >= mono_array_length_internal (o))
5299 THROW_EX (mono_get_exception_index_out_of_range (), ip);
5302 * FIXME: throw mono_get_exception_array_type_mismatch () if needed
5304 switch (*ip) {
5305 case MINT_LDELEM_I1:
5306 sp [0].data.i = mono_array_get_fast (o, gint8, aindex);
5307 break;
5308 case MINT_LDELEM_U1:
5309 sp [0].data.i = mono_array_get_fast (o, guint8, aindex);
5310 break;
5311 case MINT_LDELEM_I2:
5312 sp [0].data.i = mono_array_get_fast (o, gint16, aindex);
5313 break;
5314 case MINT_LDELEM_U2:
5315 sp [0].data.i = mono_array_get_fast (o, guint16, aindex);
5316 break;
5317 case MINT_LDELEM_I:
5318 sp [0].data.nati = mono_array_get_fast (o, mono_i, aindex);
5319 break;
5320 case MINT_LDELEM_I4:
5321 sp [0].data.i = mono_array_get_fast (o, gint32, aindex);
5322 break;
5323 case MINT_LDELEM_U4:
5324 sp [0].data.i = mono_array_get_fast (o, guint32, aindex);
5325 break;
5326 case MINT_LDELEM_I8:
5327 sp [0].data.l = mono_array_get_fast (o, guint64, aindex);
5328 break;
5329 case MINT_LDELEM_R4:
5330 sp [0].data.f_r4 = mono_array_get_fast (o, float, aindex);
5331 break;
5332 case MINT_LDELEM_R8:
5333 sp [0].data.f = mono_array_get_fast (o, double, aindex);
5334 break;
5335 case MINT_LDELEM_REF:
5336 sp [0].data.p = mono_array_get_fast (o, gpointer, aindex);
5337 break;
5338 case MINT_LDELEM_VT: {
5339 i32 = READ32 (ip + 1);
5340 char *src_addr = mono_array_addr_with_size_fast ((MonoArray *) o, i32, aindex);
5341 sp [0].data.vt = vt_sp;
5342 // Copying to vtstack. No wbarrier needed
5343 memcpy (sp [0].data.vt, src_addr, i32);
5344 vt_sp += ALIGN_TO (i32, MINT_VT_ALIGNMENT);
5345 ip += 2;
5346 break;
5348 default:
5349 ves_abort();
5352 ++ip;
5353 ++sp;
5354 MINT_IN_BREAK;
5356 MINT_IN_CASE(MINT_STELEM_I) /* fall through */
5357 MINT_IN_CASE(MINT_STELEM_I1) /* fall through */
5358 MINT_IN_CASE(MINT_STELEM_U1) /* fall through */
5359 MINT_IN_CASE(MINT_STELEM_I2) /* fall through */
5360 MINT_IN_CASE(MINT_STELEM_U2) /* fall through */
5361 MINT_IN_CASE(MINT_STELEM_I4) /* fall through */
5362 MINT_IN_CASE(MINT_STELEM_I8) /* fall through */
5363 MINT_IN_CASE(MINT_STELEM_R4) /* fall through */
5364 MINT_IN_CASE(MINT_STELEM_R8) /* fall through */
5365 MINT_IN_CASE(MINT_STELEM_REF) /* fall through */
5366 MINT_IN_CASE(MINT_STELEM_VT) {
5367 mono_u aindex;
5369 sp -= 3;
5371 o = sp [0].data.o;
5372 if (!o)
5373 THROW_EX (mono_get_exception_null_reference (), ip);
5375 aindex = sp [1].data.i;
5376 if (aindex >= mono_array_length_internal ((MonoArray *)o))
5377 THROW_EX (mono_get_exception_index_out_of_range (), ip);
5379 switch (*ip) {
5380 case MINT_STELEM_I:
5381 mono_array_set_fast ((MonoArray *)o, mono_i, aindex, sp [2].data.nati);
5382 break;
5383 case MINT_STELEM_I1:
5384 mono_array_set_fast ((MonoArray *)o, gint8, aindex, sp [2].data.i);
5385 break;
5386 case MINT_STELEM_U1:
5387 mono_array_set_fast ((MonoArray *) o, guint8, aindex, sp [2].data.i);
5388 break;
5389 case MINT_STELEM_I2:
5390 mono_array_set_fast ((MonoArray *)o, gint16, aindex, sp [2].data.i);
5391 break;
5392 case MINT_STELEM_U2:
5393 mono_array_set_fast ((MonoArray *)o, guint16, aindex, sp [2].data.i);
5394 break;
5395 case MINT_STELEM_I4:
5396 mono_array_set_fast ((MonoArray *)o, gint32, aindex, sp [2].data.i);
5397 break;
5398 case MINT_STELEM_I8:
5399 mono_array_set_fast ((MonoArray *)o, gint64, aindex, sp [2].data.l);
5400 break;
5401 case MINT_STELEM_R4:
5402 mono_array_set_fast ((MonoArray *)o, float, aindex, sp [2].data.f_r4);
5403 break;
5404 case MINT_STELEM_R8:
5405 mono_array_set_fast ((MonoArray *)o, double, aindex, sp [2].data.f);
5406 break;
5407 case MINT_STELEM_REF: {
5408 MonoObject *isinst_obj = mono_object_isinst_checked (sp [2].data.o, m_class_get_element_class (mono_object_class (o)), error);
5409 mono_error_cleanup (error); /* FIXME: don't swallow the error */
5410 if (sp [2].data.p && !isinst_obj)
5411 THROW_EX (mono_get_exception_array_type_mismatch (), ip);
5412 mono_array_setref_fast ((MonoArray *) o, aindex, sp [2].data.p);
5413 break;
5415 case MINT_STELEM_VT: {
5416 MonoClass *klass_vt = (MonoClass*)imethod->data_items [*(guint16 *) (ip + 1)];
5417 i32 = READ32 (ip + 2);
5418 char *dst_addr = mono_array_addr_with_size_fast ((MonoArray *) o, i32, aindex);
5420 mono_value_copy_internal (dst_addr, sp [2].data.vt, klass_vt);
5421 vt_sp -= ALIGN_TO (i32, MINT_VT_ALIGNMENT);
5422 ip += 3;
5423 break;
5425 default:
5426 ves_abort();
5429 ++ip;
5430 MINT_IN_BREAK;
5432 MINT_IN_CASE(MINT_CONV_OVF_I4_U4)
5433 if (sp [-1].data.i < 0)
5434 THROW_EX (mono_get_exception_overflow (), ip);
5435 ++ip;
5436 MINT_IN_BREAK;
5437 MINT_IN_CASE(MINT_CONV_OVF_I4_I8)
5438 if (sp [-1].data.l < G_MININT32 || sp [-1].data.l > G_MAXINT32)
5439 THROW_EX (mono_get_exception_overflow (), ip);
5440 sp [-1].data.i = (gint32) sp [-1].data.l;
5441 ++ip;
5442 MINT_IN_BREAK;
5443 MINT_IN_CASE(MINT_CONV_OVF_I4_U8)
5444 if (sp [-1].data.l < 0 || sp [-1].data.l > G_MAXINT32)
5445 THROW_EX (mono_get_exception_overflow (), ip);
5446 sp [-1].data.i = (gint32) sp [-1].data.l;
5447 ++ip;
5448 MINT_IN_BREAK;
5449 MINT_IN_CASE(MINT_CONV_OVF_I4_R4)
5450 if (sp [-1].data.f_r4 < G_MININT32 || sp [-1].data.f_r4 > G_MAXINT32)
5451 THROW_EX (mono_get_exception_overflow (), ip);
5452 sp [-1].data.i = (gint32) sp [-1].data.f_r4;
5453 ++ip;
5454 MINT_IN_BREAK;
5455 MINT_IN_CASE(MINT_CONV_OVF_I4_R8)
5456 if (sp [-1].data.f < G_MININT32 || sp [-1].data.f > G_MAXINT32)
5457 THROW_EX (mono_get_exception_overflow (), ip);
5458 sp [-1].data.i = (gint32) sp [-1].data.f;
5459 ++ip;
5460 MINT_IN_BREAK;
5461 MINT_IN_CASE(MINT_CONV_OVF_U4_I4)
5462 if (sp [-1].data.i < 0)
5463 THROW_EX (mono_get_exception_overflow (), ip);
5464 ++ip;
5465 MINT_IN_BREAK;
5466 MINT_IN_CASE(MINT_CONV_OVF_U4_I8)
5467 if (sp [-1].data.l < 0 || sp [-1].data.l > G_MAXUINT32)
5468 THROW_EX (mono_get_exception_overflow (), ip);
5469 sp [-1].data.i = (guint32) sp [-1].data.l;
5470 ++ip;
5471 MINT_IN_BREAK;
5472 MINT_IN_CASE(MINT_CONV_OVF_U4_R4)
5473 if (sp [-1].data.f_r4 < 0 || sp [-1].data.f_r4 > G_MAXUINT32)
5474 THROW_EX (mono_get_exception_overflow (), ip);
5475 sp [-1].data.i = (guint32) sp [-1].data.f_r4;
5476 ++ip;
5477 MINT_IN_BREAK;
5478 MINT_IN_CASE(MINT_CONV_OVF_U4_R8)
5479 if (sp [-1].data.f < 0 || sp [-1].data.f > G_MAXUINT32)
5480 THROW_EX (mono_get_exception_overflow (), ip);
5481 sp [-1].data.i = (guint32) sp [-1].data.f;
5482 ++ip;
5483 MINT_IN_BREAK;
5484 MINT_IN_CASE(MINT_CONV_OVF_I2_I4)
5485 if (sp [-1].data.i < G_MININT16 || sp [-1].data.i > G_MAXINT16)
5486 THROW_EX (mono_get_exception_overflow (), ip);
5487 ++ip;
5488 MINT_IN_BREAK;
5489 MINT_IN_CASE(MINT_CONV_OVF_I2_U4)
5490 if (sp [-1].data.i < 0 || sp [-1].data.i > G_MAXINT16)
5491 THROW_EX (mono_get_exception_overflow (), ip);
5492 ++ip;
5493 MINT_IN_BREAK;
5494 MINT_IN_CASE(MINT_CONV_OVF_I2_I8)
5495 if (sp [-1].data.l < G_MININT16 || sp [-1].data.l > G_MAXINT16)
5496 THROW_EX (mono_get_exception_overflow (), ip);
5497 sp [-1].data.i = (gint16) sp [-1].data.l;
5498 ++ip;
5499 MINT_IN_BREAK;
5500 MINT_IN_CASE(MINT_CONV_OVF_I2_U8)
5501 if (sp [-1].data.l < 0 || sp [-1].data.l > G_MAXINT16)
5502 THROW_EX (mono_get_exception_overflow (), ip);
5503 sp [-1].data.i = (gint16) sp [-1].data.l;
5504 ++ip;
5505 MINT_IN_BREAK;
5506 MINT_IN_CASE(MINT_CONV_OVF_I2_R8)
5507 if (sp [-1].data.f < G_MININT16 || sp [-1].data.f > G_MAXINT16)
5508 THROW_EX (mono_get_exception_overflow (), ip);
5509 sp [-1].data.i = (gint16) sp [-1].data.f;
5510 ++ip;
5511 MINT_IN_BREAK;
5512 MINT_IN_CASE(MINT_CONV_OVF_I2_UN_R8)
5513 if (sp [-1].data.f < 0 || sp [-1].data.f > G_MAXINT16)
5514 THROW_EX (mono_get_exception_overflow (), ip);
5515 sp [-1].data.i = (gint16) sp [-1].data.f;
5516 ++ip;
5517 MINT_IN_BREAK;
5518 MINT_IN_CASE(MINT_CONV_OVF_U2_I4)
5519 if (sp [-1].data.i < 0 || sp [-1].data.i > G_MAXUINT16)
5520 THROW_EX (mono_get_exception_overflow (), ip);
5521 ++ip;
5522 MINT_IN_BREAK;
5523 MINT_IN_CASE(MINT_CONV_OVF_U2_I8)
5524 if (sp [-1].data.l < 0 || sp [-1].data.l > G_MAXUINT16)
5525 THROW_EX (mono_get_exception_overflow (), ip);
5526 sp [-1].data.i = (guint16) sp [-1].data.l;
5527 ++ip;
5528 MINT_IN_BREAK;
5529 MINT_IN_CASE(MINT_CONV_OVF_U2_R8)
5530 if (sp [-1].data.f < 0 || sp [-1].data.f > G_MAXUINT16)
5531 THROW_EX (mono_get_exception_overflow (), ip);
5532 sp [-1].data.i = (guint16) sp [-1].data.f;
5533 ++ip;
5534 MINT_IN_BREAK;
5535 MINT_IN_CASE(MINT_CONV_OVF_I1_I4)
5536 if (sp [-1].data.i < G_MININT8 || sp [-1].data.i > G_MAXINT8)
5537 THROW_EX (mono_get_exception_overflow (), ip);
5538 ++ip;
5539 MINT_IN_BREAK;
5540 MINT_IN_CASE(MINT_CONV_OVF_I1_U4)
5541 if (sp [-1].data.i < 0 || sp [-1].data.i > G_MAXINT8)
5542 THROW_EX (mono_get_exception_overflow (), ip);
5543 ++ip;
5544 MINT_IN_BREAK;
5545 MINT_IN_CASE(MINT_CONV_OVF_I1_I8)
5546 if (sp [-1].data.l < G_MININT8 || sp [-1].data.l > G_MAXINT8)
5547 THROW_EX (mono_get_exception_overflow (), ip);
5548 sp [-1].data.i = (gint8) sp [-1].data.l;
5549 ++ip;
5550 MINT_IN_BREAK;
5551 MINT_IN_CASE(MINT_CONV_OVF_I1_U8)
5552 if (sp [-1].data.l < 0 || sp [-1].data.l > G_MAXINT8)
5553 THROW_EX (mono_get_exception_overflow (), ip);
5554 sp [-1].data.i = (gint8) sp [-1].data.l;
5555 ++ip;
5556 MINT_IN_BREAK;
5557 MINT_IN_CASE(MINT_CONV_OVF_I1_R8)
5558 if (sp [-1].data.f < G_MININT8 || sp [-1].data.f > G_MAXINT8)
5559 THROW_EX (mono_get_exception_overflow (), ip);
5560 sp [-1].data.i = (gint8) sp [-1].data.f;
5561 ++ip;
5562 MINT_IN_BREAK;
5563 MINT_IN_CASE(MINT_CONV_OVF_I1_UN_R8)
5564 if (sp [-1].data.f < 0 || sp [-1].data.f > G_MAXINT8)
5565 THROW_EX (mono_get_exception_overflow (), ip);
5566 sp [-1].data.i = (gint8) sp [-1].data.f;
5567 ++ip;
5568 MINT_IN_BREAK;
5569 MINT_IN_CASE(MINT_CONV_OVF_U1_I4)
5570 if (sp [-1].data.i < 0 || sp [-1].data.i > G_MAXUINT8)
5571 THROW_EX (mono_get_exception_overflow (), ip);
5572 ++ip;
5573 MINT_IN_BREAK;
5574 MINT_IN_CASE(MINT_CONV_OVF_U1_I8)
5575 if (sp [-1].data.l < 0 || sp [-1].data.l > G_MAXUINT8)
5576 THROW_EX (mono_get_exception_overflow (), ip);
5577 sp [-1].data.i = (guint8) sp [-1].data.l;
5578 ++ip;
5579 MINT_IN_BREAK;
5580 MINT_IN_CASE(MINT_CONV_OVF_U1_R8)
5581 if (sp [-1].data.f < 0 || sp [-1].data.f > G_MAXUINT8)
5582 THROW_EX (mono_get_exception_overflow (), ip);
5583 sp [-1].data.i = (guint8) sp [-1].data.f;
5584 ++ip;
5585 MINT_IN_BREAK;
5586 MINT_IN_CASE(MINT_CKFINITE)
5587 if (!mono_isfinite (sp [-1].data.f))
5588 THROW_EX (mono_get_exception_arithmetic (), ip);
5589 ++ip;
5590 MINT_IN_BREAK;
5591 MINT_IN_CASE(MINT_MKREFANY) {
5592 c = (MonoClass*)imethod->data_items [*(guint16 *)(ip + 1)];
5594 /* The value address is on the stack */
5595 gpointer addr = sp [-1].data.p;
5596 /* Push the typedref value on the stack */
5597 sp [-1].data.p = vt_sp;
5598 vt_sp += ALIGN_TO (sizeof (MonoTypedRef), MINT_VT_ALIGNMENT);
5600 MonoTypedRef *tref = (MonoTypedRef*)sp [-1].data.p;
5601 tref->klass = c;
5602 tref->type = m_class_get_byval_arg (c);
5603 tref->value = addr;
5605 ip += 2;
5606 MINT_IN_BREAK;
5608 MINT_IN_CASE(MINT_REFANYTYPE) {
5609 MonoTypedRef *tref = (MonoTypedRef*)sp [-1].data.p;
5610 MonoType *type = tref->type;
5612 vt_sp -= ALIGN_TO (sizeof (MonoTypedRef), MINT_VT_ALIGNMENT);
5613 sp [-1].data.p = vt_sp;
5614 vt_sp += 8;
5615 *(gpointer*)sp [-1].data.p = type;
5616 ip ++;
5617 MINT_IN_BREAK;
5619 MINT_IN_CASE(MINT_REFANYVAL) {
5620 MonoTypedRef *tref = (MonoTypedRef*)sp [-1].data.p;
5621 gpointer addr = tref->value;
5623 c = (MonoClass*)imethod->data_items [*(guint16 *)(ip + 1)];
5624 if (c != tref->klass)
5625 THROW_EX (mono_get_exception_invalid_cast (), ip);
5627 vt_sp -= ALIGN_TO (sizeof (MonoTypedRef), MINT_VT_ALIGNMENT);
5629 sp [-1].data.p = addr;
5630 ip += 2;
5631 MINT_IN_BREAK;
5633 MINT_IN_CASE(MINT_LDTOKEN)
5634 sp->data.p = vt_sp;
5635 vt_sp += 8;
5636 * (gpointer *)sp->data.p = imethod->data_items[*(guint16 *)(ip + 1)];
5637 ip += 2;
5638 ++sp;
5639 MINT_IN_BREAK;
5640 MINT_IN_CASE(MINT_ADD_OVF_I4)
5641 if (CHECK_ADD_OVERFLOW (sp [-2].data.i, sp [-1].data.i))
5642 THROW_EX (mono_get_exception_overflow (), ip);
5643 BINOP(i, +);
5644 MINT_IN_BREAK;
5645 MINT_IN_CASE(MINT_ADD_OVF_I8)
5646 if (CHECK_ADD_OVERFLOW64 (sp [-2].data.l, sp [-1].data.l))
5647 THROW_EX (mono_get_exception_overflow (), ip);
5648 BINOP(l, +);
5649 MINT_IN_BREAK;
5650 MINT_IN_CASE(MINT_ADD_OVF_UN_I4)
5651 if (CHECK_ADD_OVERFLOW_UN (sp [-2].data.i, sp [-1].data.i))
5652 THROW_EX (mono_get_exception_overflow (), ip);
5653 BINOP_CAST(i, +, guint32);
5654 MINT_IN_BREAK;
5655 MINT_IN_CASE(MINT_ADD_OVF_UN_I8)
5656 if (CHECK_ADD_OVERFLOW64_UN (sp [-2].data.l, sp [-1].data.l))
5657 THROW_EX (mono_get_exception_overflow (), ip);
5658 BINOP_CAST(l, +, guint64);
5659 MINT_IN_BREAK;
5660 MINT_IN_CASE(MINT_MUL_OVF_I4)
5661 if (CHECK_MUL_OVERFLOW (sp [-2].data.i, sp [-1].data.i))
5662 THROW_EX (mono_get_exception_overflow (), ip);
5663 BINOP(i, *);
5664 MINT_IN_BREAK;
5665 MINT_IN_CASE(MINT_MUL_OVF_I8)
5666 if (CHECK_MUL_OVERFLOW64 (sp [-2].data.l, sp [-1].data.l))
5667 THROW_EX (mono_get_exception_overflow (), ip);
5668 BINOP(l, *);
5669 MINT_IN_BREAK;
5670 MINT_IN_CASE(MINT_MUL_OVF_UN_I4)
5671 if (CHECK_MUL_OVERFLOW_UN (sp [-2].data.i, sp [-1].data.i))
5672 THROW_EX (mono_get_exception_overflow (), ip);
5673 BINOP_CAST(i, *, guint32);
5674 MINT_IN_BREAK;
5675 MINT_IN_CASE(MINT_MUL_OVF_UN_I8)
5676 if (CHECK_MUL_OVERFLOW64_UN (sp [-2].data.l, sp [-1].data.l))
5677 THROW_EX (mono_get_exception_overflow (), ip);
5678 BINOP_CAST(l, *, guint64);
5679 MINT_IN_BREAK;
5680 MINT_IN_CASE(MINT_SUB_OVF_I4)
5681 if (CHECK_SUB_OVERFLOW (sp [-2].data.i, sp [-1].data.i))
5682 THROW_EX (mono_get_exception_overflow (), ip);
5683 BINOP(i, -);
5684 MINT_IN_BREAK;
5685 MINT_IN_CASE(MINT_SUB_OVF_I8)
5686 if (CHECK_SUB_OVERFLOW64 (sp [-2].data.l, sp [-1].data.l))
5687 THROW_EX (mono_get_exception_overflow (), ip);
5688 BINOP(l, -);
5689 MINT_IN_BREAK;
5690 MINT_IN_CASE(MINT_SUB_OVF_UN_I4)
5691 if (CHECK_SUB_OVERFLOW_UN (sp [-2].data.i, sp [-1].data.i))
5692 THROW_EX (mono_get_exception_overflow (), ip);
5693 BINOP_CAST(i, -, guint32);
5694 MINT_IN_BREAK;
5695 MINT_IN_CASE(MINT_SUB_OVF_UN_I8)
5696 if (CHECK_SUB_OVERFLOW64_UN (sp [-2].data.l, sp [-1].data.l))
5697 THROW_EX (mono_get_exception_overflow (), ip);
5698 BINOP_CAST(l, -, guint64);
5699 MINT_IN_BREAK;
5700 MINT_IN_CASE(MINT_START_ABORT_PROT)
5701 mono_threads_begin_abort_protected_block ();
5702 ip ++;
5703 MINT_IN_BREAK;
5704 MINT_IN_CASE(MINT_ENDFINALLY) {
5705 ip ++;
5706 int clause_index = *ip;
5707 gboolean pending_abort = mono_threads_end_abort_protected_block ();
5709 if (clause_args && clause_index == clause_args->exit_clause)
5710 goto exit_frame;
5711 while (sp > frame->stack) {
5712 --sp;
5714 if (finally_ips) {
5715 ip = (const guint16*)finally_ips->data;
5716 finally_ips = g_slist_remove (finally_ips, ip);
5717 /* Throw abort after the last finally block to avoid confusing EH */
5718 if (pending_abort && !finally_ips)
5719 EXCEPTION_CHECKPOINT;
5720 goto main_loop;
5722 ves_abort();
5723 MINT_IN_BREAK;
5726 MINT_IN_CASE(MINT_LEAVE) /* Fall through */
5727 MINT_IN_CASE(MINT_LEAVE_S)
5728 while (sp > frame->stack) {
5729 --sp;
5731 frame->ip = ip;
5733 if (*ip == MINT_LEAVE_S) {
5734 ip += (short) *(ip + 1);
5735 } else {
5736 ip += (gint32) READ32 (ip + 1);
5738 endfinally_ip = ip;
5739 goto handle_finally;
5740 MINT_IN_BREAK;
5741 MINT_IN_CASE(MINT_LEAVE_CHECK)
5742 MINT_IN_CASE(MINT_LEAVE_S_CHECK)
5743 while (sp > frame->stack) {
5744 --sp;
5746 frame->ip = ip;
5748 if (imethod->method->wrapper_type != MONO_WRAPPER_RUNTIME_INVOKE) {
5749 stackval tmp_sp;
5751 child_frame.parent = frame;
5752 child_frame.imethod = NULL;
5754 * We need for mono_thread_get_undeniable_exception to be able to unwind
5755 * to check the abort threshold. For this to work we use child_frame as a
5756 * dummy frame that is stored in the lmf and serves as the transition frame
5758 do_icall_wrapper (&child_frame, NULL, MINT_ICALL_V_P, &tmp_sp, (gpointer)mono_thread_get_undeniable_exception, FALSE);
5760 MonoException *abort_exc = (MonoException*)tmp_sp.data.p;
5761 if (abort_exc)
5762 THROW_EX (abort_exc, frame->ip);
5765 if (*ip == MINT_LEAVE_S_CHECK) {
5766 ip += (short) *(ip + 1);
5767 } else {
5768 ip += (gint32) READ32 (ip + 1);
5770 endfinally_ip = ip;
5771 goto handle_finally;
5772 MINT_IN_BREAK;
5773 MINT_IN_CASE(MINT_ICALL_V_V)
5774 MINT_IN_CASE(MINT_ICALL_V_P)
5775 MINT_IN_CASE(MINT_ICALL_P_V)
5776 MINT_IN_CASE(MINT_ICALL_P_P)
5777 MINT_IN_CASE(MINT_ICALL_PP_V)
5778 MINT_IN_CASE(MINT_ICALL_PP_P)
5779 MINT_IN_CASE(MINT_ICALL_PPP_V)
5780 MINT_IN_CASE(MINT_ICALL_PPP_P)
5781 MINT_IN_CASE(MINT_ICALL_PPPP_V)
5782 MINT_IN_CASE(MINT_ICALL_PPPP_P)
5783 MINT_IN_CASE(MINT_ICALL_PPPPP_V)
5784 MINT_IN_CASE(MINT_ICALL_PPPPP_P)
5785 MINT_IN_CASE(MINT_ICALL_PPPPPP_V)
5786 MINT_IN_CASE(MINT_ICALL_PPPPPP_P)
5787 frame->ip = ip;
5788 sp = do_icall_wrapper (frame, NULL, *ip, sp, imethod->data_items [*(guint16 *)(ip + 1)], FALSE);
5789 EXCEPTION_CHECKPOINT;
5790 CHECK_RESUME_STATE (context);
5791 ip += 2;
5792 MINT_IN_BREAK;
5793 MINT_IN_CASE(MINT_MONO_LDPTR)
5794 sp->data.p = imethod->data_items [*(guint16 *)(ip + 1)];
5795 ip += 2;
5796 ++sp;
5797 MINT_IN_BREAK;
5798 MINT_IN_CASE(MINT_MONO_NEWOBJ)
5799 sp->data.p = mono_object_new_checked (imethod->domain, (MonoClass*)imethod->data_items [*(guint16 *)(ip + 1)], error);
5800 mono_error_cleanup (error); /* FIXME: don't swallow the error */
5801 ip += 2;
5802 sp++;
5803 MINT_IN_BREAK;
5804 MINT_IN_CASE(MINT_MONO_FREE)
5805 ++ip;
5806 --sp;
5807 g_error ("that doesn't seem right");
5808 g_free (sp->data.p);
5809 MINT_IN_BREAK;
5810 MINT_IN_CASE(MINT_MONO_RETOBJ)
5811 ++ip;
5812 sp--;
5813 stackval_from_data (mono_method_signature_internal (imethod->method)->ret, frame->retval, sp->data.p,
5814 mono_method_signature_internal (imethod->method)->pinvoke);
5815 if (sp > frame->stack)
5816 g_warning ("retobj: more values on stack: %d", sp-frame->stack);
5817 goto exit_frame;
5818 MINT_IN_CASE(MINT_MONO_SGEN_THREAD_INFO)
5819 sp->data.p = mono_tls_get_sgen_thread_info ();
5820 sp++;
5821 ++ip;
5822 MINT_IN_BREAK;
5823 MINT_IN_CASE(MINT_MONO_MEMORY_BARRIER) {
5824 ++ip;
5825 mono_memory_barrier ();
5826 MINT_IN_BREAK;
5828 MINT_IN_CASE(MINT_MONO_LDDOMAIN)
5829 sp->data.p = mono_domain_get ();
5830 ++sp;
5831 ++ip;
5832 MINT_IN_BREAK;
5833 MINT_IN_CASE(MINT_SDB_INTR_LOC)
5834 if (G_UNLIKELY (ss_enabled)) {
5835 typedef void (*T) (void);
5836 static T ss_tramp;
5838 if (!ss_tramp) {
5839 void *tramp = mini_get_single_step_trampoline ();
5840 mono_memory_barrier ();
5841 ss_tramp = (T)tramp;
5845 * Make this point to the MINT_SDB_SEQ_POINT instruction which follows this since
5846 * the address of that instruction is stored as the seq point address.
5848 frame->ip = ip + 1;
5851 * Use the same trampoline as the JIT. This ensures that
5852 * the debugger has the context for the last interpreter
5853 * native frame.
5855 do_debugger_tramp (ss_tramp, frame);
5857 CHECK_RESUME_STATE (context);
5859 ++ip;
5860 MINT_IN_BREAK;
5861 MINT_IN_CASE(MINT_SDB_SEQ_POINT)
5862 /* Just a placeholder for a breakpoint */
5863 ++ip;
5864 MINT_IN_BREAK;
5865 MINT_IN_CASE(MINT_SDB_BREAKPOINT) {
5866 typedef void (*T) (void);
5867 static T bp_tramp;
5868 if (!bp_tramp) {
5869 void *tramp = mini_get_breakpoint_trampoline ();
5870 mono_memory_barrier ();
5871 bp_tramp = (T)tramp;
5874 frame->ip = ip;
5876 /* Use the same trampoline as the JIT */
5877 do_debugger_tramp (bp_tramp, frame);
5879 CHECK_RESUME_STATE (context);
5881 ++ip;
5882 MINT_IN_BREAK;
5885 #define RELOP(datamem, op) \
5886 --sp; \
5887 sp [-1].data.i = sp [-1].data.datamem op sp [0].data.datamem; \
5888 ++ip;
5890 #define RELOP_FP(datamem, op, noorder) \
5891 --sp; \
5892 if (mono_isunordered (sp [-1].data.datamem, sp [0].data.datamem)) \
5893 sp [-1].data.i = noorder; \
5894 else \
5895 sp [-1].data.i = sp [-1].data.datamem op sp [0].data.datamem; \
5896 ++ip;
5898 MINT_IN_CASE(MINT_CEQ_I4)
5899 RELOP(i, ==);
5900 MINT_IN_BREAK;
5901 MINT_IN_CASE(MINT_CEQ0_I4)
5902 sp [-1].data.i = (sp [-1].data.i == 0);
5903 ++ip;
5904 MINT_IN_BREAK;
5905 MINT_IN_CASE(MINT_CEQ_I8)
5906 RELOP(l, ==);
5907 MINT_IN_BREAK;
5908 MINT_IN_CASE(MINT_CEQ_R4)
5909 RELOP_FP(f_r4, ==, 0);
5910 MINT_IN_BREAK;
5911 MINT_IN_CASE(MINT_CEQ_R8)
5912 RELOP_FP(f, ==, 0);
5913 MINT_IN_BREAK;
5914 MINT_IN_CASE(MINT_CNE_I4)
5915 RELOP(i, !=);
5916 MINT_IN_BREAK;
5917 MINT_IN_CASE(MINT_CNE_I8)
5918 RELOP(l, !=);
5919 MINT_IN_BREAK;
5920 MINT_IN_CASE(MINT_CNE_R4)
5921 RELOP_FP(f_r4, !=, 1);
5922 MINT_IN_BREAK;
5923 MINT_IN_CASE(MINT_CNE_R8)
5924 RELOP_FP(f, !=, 1);
5925 MINT_IN_BREAK;
5926 MINT_IN_CASE(MINT_CGT_I4)
5927 RELOP(i, >);
5928 MINT_IN_BREAK;
5929 MINT_IN_CASE(MINT_CGT_I8)
5930 RELOP(l, >);
5931 MINT_IN_BREAK;
5932 MINT_IN_CASE(MINT_CGT_R4)
5933 RELOP_FP(f_r4, >, 0);
5934 MINT_IN_BREAK;
5935 MINT_IN_CASE(MINT_CGT_R8)
5936 RELOP_FP(f, >, 0);
5937 MINT_IN_BREAK;
5938 MINT_IN_CASE(MINT_CGE_I4)
5939 RELOP(i, >=);
5940 MINT_IN_BREAK;
5941 MINT_IN_CASE(MINT_CGE_I8)
5942 RELOP(l, >=);
5943 MINT_IN_BREAK;
5944 MINT_IN_CASE(MINT_CGE_R4)
5945 RELOP_FP(f_r4, >=, 0);
5946 MINT_IN_BREAK;
5947 MINT_IN_CASE(MINT_CGE_R8)
5948 RELOP_FP(f, >=, 0);
5949 MINT_IN_BREAK;
5951 #define RELOP_CAST(datamem, op, type) \
5952 --sp; \
5953 sp [-1].data.i = (type)sp [-1].data.datamem op (type)sp [0].data.datamem; \
5954 ++ip;
5956 MINT_IN_CASE(MINT_CGE_UN_I4)
5957 RELOP_CAST(l, >=, guint32);
5958 MINT_IN_BREAK;
5959 MINT_IN_CASE(MINT_CGE_UN_I8)
5960 RELOP_CAST(l, >=, guint64);
5961 MINT_IN_BREAK;
5963 MINT_IN_CASE(MINT_CGT_UN_I4)
5964 RELOP_CAST(i, >, guint32);
5965 MINT_IN_BREAK;
5966 MINT_IN_CASE(MINT_CGT_UN_I8)
5967 RELOP_CAST(l, >, guint64);
5968 MINT_IN_BREAK;
5969 MINT_IN_CASE(MINT_CGT_UN_R4)
5970 RELOP_FP(f_r4, >, 1);
5971 MINT_IN_BREAK;
5972 MINT_IN_CASE(MINT_CGT_UN_R8)
5973 RELOP_FP(f, >, 1);
5974 MINT_IN_BREAK;
5975 MINT_IN_CASE(MINT_CLT_I4)
5976 RELOP(i, <);
5977 MINT_IN_BREAK;
5978 MINT_IN_CASE(MINT_CLT_I8)
5979 RELOP(l, <);
5980 MINT_IN_BREAK;
5981 MINT_IN_CASE(MINT_CLT_R4)
5982 RELOP_FP(f_r4, <, 0);
5983 MINT_IN_BREAK;
5984 MINT_IN_CASE(MINT_CLT_R8)
5985 RELOP_FP(f, <, 0);
5986 MINT_IN_BREAK;
5987 MINT_IN_CASE(MINT_CLT_UN_I4)
5988 RELOP_CAST(i, <, guint32);
5989 MINT_IN_BREAK;
5990 MINT_IN_CASE(MINT_CLT_UN_I8)
5991 RELOP_CAST(l, <, guint64);
5992 MINT_IN_BREAK;
5993 MINT_IN_CASE(MINT_CLT_UN_R4)
5994 RELOP_FP(f_r4, <, 1);
5995 MINT_IN_BREAK;
5996 MINT_IN_CASE(MINT_CLT_UN_R8)
5997 RELOP_FP(f, <, 1);
5998 MINT_IN_BREAK;
5999 MINT_IN_CASE(MINT_CLE_I4)
6000 RELOP(i, <=);
6001 MINT_IN_BREAK;
6002 MINT_IN_CASE(MINT_CLE_I8)
6003 RELOP(l, <=);
6004 MINT_IN_BREAK;
6005 MINT_IN_CASE(MINT_CLE_UN_I4)
6006 RELOP_CAST(l, <=, guint32);
6007 MINT_IN_BREAK;
6008 MINT_IN_CASE(MINT_CLE_UN_I8)
6009 RELOP_CAST(l, <=, guint64);
6010 MINT_IN_BREAK;
6011 MINT_IN_CASE(MINT_CLE_R4)
6012 RELOP_FP(f_r4, <=, 0);
6013 MINT_IN_BREAK;
6014 MINT_IN_CASE(MINT_CLE_R8)
6015 RELOP_FP(f, <=, 0);
6016 MINT_IN_BREAK;
6018 #undef RELOP
6019 #undef RELOP_FP
6020 #undef RELOP_CAST
6022 MINT_IN_CASE(MINT_LDFTN) {
6023 sp->data.p = imethod->data_items [* (guint16 *)(ip + 1)];
6024 ++sp;
6025 ip += 2;
6026 MINT_IN_BREAK;
6028 MINT_IN_CASE(MINT_LDVIRTFTN) {
6029 InterpMethod *m = (InterpMethod*)imethod->data_items [* (guint16 *)(ip + 1)];
6030 ip += 2;
6031 --sp;
6032 if (!sp->data.p)
6033 THROW_EX (mono_get_exception_null_reference (), ip - 2);
6035 sp->data.p = get_virtual_method (m, sp->data.o->vtable);
6036 ++sp;
6037 MINT_IN_BREAK;
6039 MINT_IN_CASE(MINT_LDFTN_DYNAMIC) {
6040 MONO_API_ERROR_INIT (error);
6041 InterpMethod *m = mono_interp_get_imethod (mono_domain_get (), (MonoMethod*) sp [-1].data.p, error);
6042 mono_error_assert_ok (error);
6043 sp [-1].data.p = m;
6044 ip++;
6045 MINT_IN_BREAK;
6048 #define LDARG(datamem, argtype) \
6049 sp->data.datamem = (argtype) frame->stack_args [*(guint16 *)(ip + 1)].data.datamem; \
6050 ip += 2; \
6051 ++sp;
6053 MINT_IN_CASE(MINT_LDARG_I1) LDARG(i, gint8); MINT_IN_BREAK;
6054 MINT_IN_CASE(MINT_LDARG_U1) LDARG(i, guint8); MINT_IN_BREAK;
6055 MINT_IN_CASE(MINT_LDARG_I2) LDARG(i, gint16); MINT_IN_BREAK;
6056 MINT_IN_CASE(MINT_LDARG_U2) LDARG(i, guint16); MINT_IN_BREAK;
6057 MINT_IN_CASE(MINT_LDARG_I4) LDARG(i, gint32); MINT_IN_BREAK;
6058 MINT_IN_CASE(MINT_LDARG_I8) LDARG(l, gint64); MINT_IN_BREAK;
6059 MINT_IN_CASE(MINT_LDARG_R4) LDARG(f_r4, float); MINT_IN_BREAK;
6060 MINT_IN_CASE(MINT_LDARG_R8) LDARG(f, double); MINT_IN_BREAK;
6061 MINT_IN_CASE(MINT_LDARG_O) LDARG(p, gpointer); MINT_IN_BREAK;
6062 MINT_IN_CASE(MINT_LDARG_P) LDARG(p, gpointer); MINT_IN_BREAK;
6064 MINT_IN_CASE(MINT_LDARG_VT)
6065 sp->data.p = vt_sp;
6066 i32 = READ32(ip + 2);
6067 memcpy(sp->data.p, frame->stack_args [* (guint16 *)(ip + 1)].data.p, i32);
6068 vt_sp += ALIGN_TO (i32, MINT_VT_ALIGNMENT);
6069 ip += 4;
6070 ++sp;
6071 MINT_IN_BREAK;
6073 #define STARG(datamem, argtype) \
6074 --sp; \
6075 frame->stack_args [*(guint16 *)(ip + 1)].data.datamem = (argtype) sp->data.datamem; \
6076 ip += 2; \
6078 MINT_IN_CASE(MINT_STARG_I1) STARG(i, gint8); MINT_IN_BREAK;
6079 MINT_IN_CASE(MINT_STARG_U1) STARG(i, guint8); MINT_IN_BREAK;
6080 MINT_IN_CASE(MINT_STARG_I2) STARG(i, gint16); MINT_IN_BREAK;
6081 MINT_IN_CASE(MINT_STARG_U2) STARG(i, guint16); MINT_IN_BREAK;
6082 MINT_IN_CASE(MINT_STARG_I4) STARG(i, gint32); MINT_IN_BREAK;
6083 MINT_IN_CASE(MINT_STARG_I8) STARG(l, gint64); MINT_IN_BREAK;
6084 MINT_IN_CASE(MINT_STARG_R4) STARG(f_r4, float); MINT_IN_BREAK;
6085 MINT_IN_CASE(MINT_STARG_R8) STARG(f, double); MINT_IN_BREAK;
6086 MINT_IN_CASE(MINT_STARG_O) STARG(p, gpointer); MINT_IN_BREAK;
6087 MINT_IN_CASE(MINT_STARG_P) STARG(p, gpointer); MINT_IN_BREAK;
6089 MINT_IN_CASE(MINT_STARG_VT)
6090 i32 = READ32(ip + 2);
6091 --sp;
6092 memcpy(frame->stack_args [* (guint16 *)(ip + 1)].data.p, sp->data.p, i32);
6093 vt_sp -= ALIGN_TO (i32, MINT_VT_ALIGNMENT);
6094 ip += 4;
6095 MINT_IN_BREAK;
6097 MINT_IN_CASE(MINT_PROF_ENTER) {
6098 ip += 1;
6100 if (MONO_PROFILER_ENABLED (method_enter)) {
6101 MonoProfilerCallContext *prof_ctx = NULL;
6103 if (imethod->prof_flags & MONO_PROFILER_CALL_INSTRUMENTATION_ENTER_CONTEXT) {
6104 prof_ctx = g_new0 (MonoProfilerCallContext, 1);
6105 prof_ctx->interp_frame = frame;
6106 prof_ctx->method = imethod->method;
6109 MONO_PROFILER_RAISE (method_enter, (imethod->method, prof_ctx));
6111 g_free (prof_ctx);
6114 MINT_IN_BREAK;
6117 MINT_IN_CASE(MINT_TRACE_ENTER) {
6118 ip += 1;
6120 MonoProfilerCallContext *prof_ctx = g_alloca (sizeof (MonoProfilerCallContext));
6121 prof_ctx->interp_frame = frame;
6122 prof_ctx->method = imethod->method;
6124 mono_trace_enter_method (imethod->method, prof_ctx);
6125 MINT_IN_BREAK;
6128 MINT_IN_CASE(MINT_TRACE_EXIT) {
6129 // Set retval
6130 i32 = READ32(ip + 1);
6131 --sp;
6132 if (i32 == -1)
6134 else if (i32)
6135 memcpy(frame->retval->data.p, sp->data.p, i32);
6136 else
6137 *frame->retval = *sp;
6139 MonoProfilerCallContext *prof_ctx = g_alloca (sizeof (MonoProfilerCallContext));
6140 prof_ctx->interp_frame = frame;
6141 prof_ctx->method = imethod->method;
6143 mono_trace_leave_method (imethod->method, prof_ctx);
6144 ip += 3;
6145 goto exit_frame;
6148 MINT_IN_CASE(MINT_LDARGA)
6149 sp->data.p = &frame->stack_args [* (guint16 *)(ip + 1)];
6150 ip += 2;
6151 ++sp;
6152 MINT_IN_BREAK;
6154 MINT_IN_CASE(MINT_LDARGA_VT)
6155 sp->data.p = frame->stack_args [* (guint16 *)(ip + 1)].data.p;
6156 ip += 2;
6157 ++sp;
6158 MINT_IN_BREAK;
6160 #define LDLOC(datamem, argtype) \
6161 sp->data.datamem = * (argtype *)(locals + * (guint16 *)(ip + 1)); \
6162 ip += 2; \
6163 ++sp;
6165 MINT_IN_CASE(MINT_LDLOC_I1) LDLOC(i, gint8); MINT_IN_BREAK;
6166 MINT_IN_CASE(MINT_LDLOC_U1) LDLOC(i, guint8); MINT_IN_BREAK;
6167 MINT_IN_CASE(MINT_LDLOC_I2) LDLOC(i, gint16); MINT_IN_BREAK;
6168 MINT_IN_CASE(MINT_LDLOC_U2) LDLOC(i, guint16); MINT_IN_BREAK;
6169 MINT_IN_CASE(MINT_LDLOC_I4) LDLOC(i, gint32); MINT_IN_BREAK;
6170 MINT_IN_CASE(MINT_LDLOC_I8) LDLOC(l, gint64); MINT_IN_BREAK;
6171 MINT_IN_CASE(MINT_LDLOC_R4) LDLOC(f_r4, float); MINT_IN_BREAK;
6172 MINT_IN_CASE(MINT_LDLOC_R8) LDLOC(f, double); MINT_IN_BREAK;
6173 MINT_IN_CASE(MINT_LDLOC_O) LDLOC(p, gpointer); MINT_IN_BREAK;
6174 MINT_IN_CASE(MINT_LDLOC_P) LDLOC(p, gpointer); MINT_IN_BREAK;
6176 MINT_IN_CASE(MINT_LDLOC_VT)
6177 sp->data.p = vt_sp;
6178 i32 = READ32(ip + 2);
6179 memcpy(sp->data.p, locals + * (guint16 *)(ip + 1), i32);
6180 vt_sp += ALIGN_TO (i32, MINT_VT_ALIGNMENT);
6181 ip += 4;
6182 ++sp;
6183 MINT_IN_BREAK;
6185 MINT_IN_CASE(MINT_LDLOCA_S)
6186 sp->data.p = locals + * (guint16 *)(ip + 1);
6187 ip += 2;
6188 ++sp;
6189 MINT_IN_BREAK;
6191 #define STLOC(datamem, argtype) \
6192 --sp; \
6193 * (argtype *)(locals + * (guint16 *)(ip + 1)) = sp->data.datamem; \
6194 ip += 2;
6196 MINT_IN_CASE(MINT_STLOC_I1) STLOC(i, gint8); MINT_IN_BREAK;
6197 MINT_IN_CASE(MINT_STLOC_U1) STLOC(i, guint8); MINT_IN_BREAK;
6198 MINT_IN_CASE(MINT_STLOC_I2) STLOC(i, gint16); MINT_IN_BREAK;
6199 MINT_IN_CASE(MINT_STLOC_U2) STLOC(i, guint16); MINT_IN_BREAK;
6200 MINT_IN_CASE(MINT_STLOC_I4) STLOC(i, gint32); MINT_IN_BREAK;
6201 MINT_IN_CASE(MINT_STLOC_I8) STLOC(l, gint64); MINT_IN_BREAK;
6202 MINT_IN_CASE(MINT_STLOC_R4) STLOC(f_r4, float); MINT_IN_BREAK;
6203 MINT_IN_CASE(MINT_STLOC_R8) STLOC(f, double); MINT_IN_BREAK;
6204 MINT_IN_CASE(MINT_STLOC_O) STLOC(p, gpointer); MINT_IN_BREAK;
6205 MINT_IN_CASE(MINT_STLOC_P) STLOC(p, gpointer); MINT_IN_BREAK;
6207 #define STLOC_NP(datamem, argtype) \
6208 * (argtype *)(locals + * (guint16 *)(ip + 1)) = sp [-1].data.datamem; \
6209 ip += 2;
6211 MINT_IN_CASE(MINT_STLOC_NP_I4) STLOC_NP(i, gint32); MINT_IN_BREAK;
6212 MINT_IN_CASE(MINT_STLOC_NP_O) STLOC_NP(p, gpointer); MINT_IN_BREAK;
6214 MINT_IN_CASE(MINT_STLOC_VT)
6215 i32 = READ32(ip + 2);
6216 --sp;
6217 memcpy(locals + * (guint16 *)(ip + 1), sp->data.p, i32);
6218 vt_sp -= ALIGN_TO (i32, MINT_VT_ALIGNMENT);
6219 ip += 4;
6220 MINT_IN_BREAK;
6222 MINT_IN_CASE(MINT_LOCALLOC) {
6223 if (sp != frame->stack + 1) /*FIX?*/
6224 THROW_EX (mono_get_exception_execution_engine (NULL), ip);
6226 int len = sp [-1].data.i;
6227 sp [-1].data.p = alloca (len);
6229 if (imethod->init_locals)
6230 memset (sp [-1].data.p, 0, len);
6231 ++ip;
6232 MINT_IN_BREAK;
6234 MINT_IN_CASE(MINT_ENDFILTER)
6235 /* top of stack is result of filter */
6236 frame->retval = &sp [-1];
6237 goto exit_frame;
6238 MINT_IN_CASE(MINT_INITOBJ)
6239 --sp;
6240 memset (sp->data.vt, 0, READ32(ip + 1));
6241 ip += 3;
6242 MINT_IN_BREAK;
6243 MINT_IN_CASE(MINT_CPBLK)
6244 sp -= 3;
6245 if (!sp [0].data.p || !sp [1].data.p)
6246 THROW_EX (mono_get_exception_null_reference(), ip - 1);
6247 ++ip;
6248 /* FIXME: value and size may be int64... */
6249 memcpy (sp [0].data.p, sp [1].data.p, sp [2].data.i);
6250 MINT_IN_BREAK;
6251 #if 0
6252 MINT_IN_CASE(MINT_CONSTRAINED_) {
6253 guint32 token;
6254 /* FIXME: implement */
6255 ++ip;
6256 token = READ32 (ip);
6257 ip += 2;
6258 MINT_IN_BREAK;
6260 #endif
6261 MINT_IN_CASE(MINT_INITBLK)
6262 sp -= 3;
6263 if (!sp [0].data.p)
6264 THROW_EX (mono_get_exception_null_reference(), ip - 1);
6265 ++ip;
6266 /* FIXME: value and size may be int64... */
6267 memset (sp [0].data.p, sp [1].data.i, sp [2].data.i);
6268 MINT_IN_BREAK;
6269 #if 0
6270 MINT_IN_CASE(MINT_NO_)
6271 /* FIXME: implement */
6272 ip += 2;
6273 MINT_IN_BREAK;
6274 #endif
6275 MINT_IN_CASE(MINT_RETHROW) {
6276 int exvar_offset = *(guint16*)(ip + 1);
6277 THROW_EX_GENERAL (*(MonoException**)(frame->locals + exvar_offset), ip, TRUE);
6278 MINT_IN_BREAK;
6280 MINT_IN_CASE(MINT_MONO_RETHROW) {
6282 * need to clarify what this should actually do:
6284 * Takes an exception from the stack and rethrows it.
6285 * This is useful for wrappers that don't want to have to
6286 * use CEE_THROW and lose the exception stacktrace.
6289 --sp;
6290 if (!sp->data.p)
6291 sp->data.p = mono_get_exception_null_reference ();
6293 THROW_EX_GENERAL ((MonoException *)sp->data.p, ip, TRUE);
6294 MINT_IN_BREAK;
6296 MINT_IN_CASE(MINT_LD_DELEGATE_METHOD_PTR) {
6297 MonoDelegate *del;
6299 --sp;
6300 del = (MonoDelegate*)sp->data.p;
6301 if (!del->interp_method) {
6302 /* Not created from interpreted code */
6303 MONO_API_ERROR_INIT (error);
6304 g_assert (del->method);
6305 del->interp_method = mono_interp_get_imethod (del->object.vtable->domain, del->method, error);
6306 mono_error_assert_ok (error);
6308 g_assert (del->interp_method);
6309 sp->data.p = del->interp_method;
6310 ++sp;
6311 ip += 1;
6312 MINT_IN_BREAK;
6314 MINT_IN_CASE(MINT_LD_DELEGATE_INVOKE_IMPL) {
6315 MonoDelegate *del;
6316 int n = *(guint16*)(ip + 1);
6317 del = (MonoDelegate*)sp [-n].data.p;
6318 if (!del->interp_invoke_impl) {
6320 * First time we are called. Set up the invoke wrapper. We might be able to do this
6321 * in ctor but we would need to handle AllocDelegateLike_internal separately
6323 MONO_API_ERROR_INIT (error);
6324 MonoMethod *invoke = mono_get_delegate_invoke_internal (del->object.vtable->klass);
6325 del->interp_invoke_impl = mono_interp_get_imethod (del->object.vtable->domain, mono_marshal_get_delegate_invoke (invoke, del), error);
6326 mono_error_assert_ok (error);
6328 sp ++;
6329 sp [-1].data.p = del->interp_invoke_impl;
6330 ip += 2;
6331 MINT_IN_BREAK;
6334 #define MATH_UNOP(mathfunc) \
6335 sp [-1].data.f = mathfunc (sp [-1].data.f); \
6336 ++ip;
6338 MINT_IN_CASE(MINT_ABS) MATH_UNOP(fabs); MINT_IN_BREAK;
6339 MINT_IN_CASE(MINT_ASIN) MATH_UNOP(asin); MINT_IN_BREAK;
6340 MINT_IN_CASE(MINT_ASINH) MATH_UNOP(asinh); MINT_IN_BREAK;
6341 MINT_IN_CASE(MINT_ACOS) MATH_UNOP(acos); MINT_IN_BREAK;
6342 MINT_IN_CASE(MINT_ACOSH) MATH_UNOP(acosh); MINT_IN_BREAK;
6343 MINT_IN_CASE(MINT_ATAN) MATH_UNOP(atan); MINT_IN_BREAK;
6344 MINT_IN_CASE(MINT_ATANH) MATH_UNOP(atanh); MINT_IN_BREAK;
6345 MINT_IN_CASE(MINT_COS) MATH_UNOP(cos); MINT_IN_BREAK;
6346 MINT_IN_CASE(MINT_CBRT) MATH_UNOP(cbrt); MINT_IN_BREAK;
6347 MINT_IN_CASE(MINT_COSH) MATH_UNOP(cosh); MINT_IN_BREAK;
6348 MINT_IN_CASE(MINT_SIN) MATH_UNOP(sin); MINT_IN_BREAK;
6349 MINT_IN_CASE(MINT_SQRT) MATH_UNOP(sqrt); MINT_IN_BREAK;
6350 MINT_IN_CASE(MINT_SINH) MATH_UNOP(sinh); MINT_IN_BREAK;
6351 MINT_IN_CASE(MINT_TAN) MATH_UNOP(tan); MINT_IN_BREAK;
6352 MINT_IN_CASE(MINT_TANH) MATH_UNOP(tanh); MINT_IN_BREAK;
6354 MINT_IN_CASE(MINT_INTRINS_ENUM_HASFLAG) {
6355 MonoClass *klass = (MonoClass*)imethod->data_items[* (guint16 *)(ip + 1)];
6356 guint64 a_val = 0, b_val = 0;
6358 stackval_to_data (m_class_get_byval_arg (klass), &sp [-2], &a_val, FALSE);
6359 stackval_to_data (m_class_get_byval_arg (klass), &sp [-1], &b_val, FALSE);
6360 sp--;
6361 sp [-1].data.i = (a_val & b_val) == b_val;
6362 ip += 2;
6363 MINT_IN_BREAK;
6365 MINT_IN_CASE(MINT_INTRINS_GET_HASHCODE) {
6366 sp [-1].data.i = mono_object_hash_internal (sp [-1].data.o);
6367 ip++;
6368 MINT_IN_BREAK;
6370 MINT_IN_CASE(MINT_INTRINS_GET_TYPE) {
6371 if (!sp[-1].data.o)
6372 THROW_EX (mono_get_exception_null_reference (), ip);
6373 sp [-1].data.o = (MonoObject*) sp [-1].data.o->vtable->type;
6374 ip++;
6375 MINT_IN_BREAK;
6378 MINT_IN_DEFAULT
6379 g_print ("Unimplemented opcode: %04x %s at 0x%x\n", *ip, mono_interp_opname[*ip], ip-imethod->code);
6380 THROW_EX (mono_get_exception_execution_engine ("Unimplemented opcode"), ip);
6384 g_assert_not_reached ();
6385 handle_finally:
6387 int i;
6388 guint32 ip_offset;
6389 MonoExceptionClause *clause;
6390 GSList *old_list = finally_ips;
6391 MonoMethod *method = imethod->method;
6393 #if DEBUG_INTERP
6394 if (tracing)
6395 g_print ("* Handle finally IL_%04x\n", endfinally_ip == NULL ? 0 : endfinally_ip - imethod->code);
6396 #endif
6397 if (imethod == NULL || (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
6398 || (method->iflags & (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL | METHOD_IMPL_ATTRIBUTE_RUNTIME))) {
6399 goto exit_frame;
6401 ip_offset = frame->ip - imethod->code;
6403 if (endfinally_ip != NULL)
6404 finally_ips = g_slist_prepend(finally_ips, (void *)endfinally_ip);
6406 for (i = imethod->num_clauses - 1; i >= 0; i--) {
6407 clause = &imethod->clauses [i];
6408 if (MONO_OFFSET_IN_CLAUSE (clause, ip_offset) && (endfinally_ip == NULL || !(MONO_OFFSET_IN_CLAUSE (clause, endfinally_ip - imethod->code)))) {
6409 if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY) {
6410 ip = imethod->code + clause->handler_offset;
6411 finally_ips = g_slist_prepend (finally_ips, (gpointer) ip);
6412 #if DEBUG_INTERP
6413 if (tracing)
6414 g_print ("* Found finally at IL_%04x with exception: %s\n", clause->handler_offset, frame->ex? "yes": "no");
6415 #endif
6420 endfinally_ip = NULL;
6422 if (old_list != finally_ips && finally_ips) {
6423 ip = (const guint16*)finally_ips->data;
6424 finally_ips = g_slist_remove (finally_ips, ip);
6425 sp = frame->stack; /* spec says stack should be empty at endfinally so it should be at the start too */
6426 vt_sp = (unsigned char *) sp + imethod->stack_size;
6427 goto main_loop;
6430 ves_abort();
6433 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;
6519 * interp_run_finally:
6521 * Run the finally clause identified by CLAUSE_INDEX in the intepreter frame given by
6522 * frame->interp_frame.
6523 * Return TRUE if the finally clause threw an exception.
6525 static gboolean
6526 interp_run_finally (StackFrameInfo *frame, int clause_index, gpointer handler_ip, gpointer handler_ip_end)
6528 InterpFrame *iframe = (InterpFrame*)frame->interp_frame;
6529 ThreadContext *context = get_context ();
6530 const unsigned short *old_ip = iframe->ip;
6531 FrameClauseArgs clause_args;
6533 memset (&clause_args, 0, sizeof (FrameClauseArgs));
6534 clause_args.start_with_ip = (guint16*) handler_ip;
6535 clause_args.end_at_ip = (guint16*) handler_ip_end;
6536 clause_args.exit_clause = clause_index;
6538 ERROR_DECL (error);
6539 interp_exec_method_full (iframe, context, &clause_args, error);
6540 if (context->has_resume_state) {
6541 return TRUE;
6542 } else {
6543 iframe->ip = old_ip;
6544 return FALSE;
6549 * interp_run_filter:
6551 * Run the filter clause identified by CLAUSE_INDEX in the intepreter frame given by
6552 * frame->interp_frame.
6554 static gboolean
6555 interp_run_filter (StackFrameInfo *frame, MonoException *ex, int clause_index, gpointer handler_ip, gpointer handler_ip_end)
6557 InterpFrame *iframe = (InterpFrame*)frame->interp_frame;
6558 ThreadContext *context = get_context ();
6559 InterpFrame child_frame;
6560 stackval retval;
6561 FrameClauseArgs clause_args;
6564 * Have to run the clause in a new frame which is a copy of IFRAME, since
6565 * during debugging, there are two copies of the frame on the stack.
6567 memset (&child_frame, 0, sizeof (InterpFrame));
6568 child_frame.imethod = iframe->imethod;
6569 child_frame.retval = &retval;
6570 child_frame.parent = iframe;
6571 child_frame.stack_args = iframe->stack_args;
6573 memset (&clause_args, 0, sizeof (FrameClauseArgs));
6574 clause_args.start_with_ip = (guint16*) handler_ip;
6575 clause_args.end_at_ip = (guint16*) handler_ip_end;
6576 clause_args.filter_exception = ex;
6577 clause_args.base_frame = iframe;
6579 ERROR_DECL (error);
6580 interp_exec_method_full (&child_frame, context, &clause_args, error);
6581 /* ENDFILTER stores the result into child_frame->retval */
6582 return child_frame.retval->data.i ? TRUE : FALSE;
6585 typedef struct {
6586 InterpFrame *current;
6587 } StackIter;
6590 * interp_frame_iter_init:
6592 * Initialize an iterator for iterating through interpreted frames.
6594 static void
6595 interp_frame_iter_init (MonoInterpStackIter *iter, gpointer interp_exit_data)
6597 StackIter *stack_iter = (StackIter*)iter;
6599 stack_iter->current = (InterpFrame*)interp_exit_data;
6603 * interp_frame_iter_next:
6605 * Fill out FRAME with date for the next interpreter frame.
6607 static gboolean
6608 interp_frame_iter_next (MonoInterpStackIter *iter, StackFrameInfo *frame)
6610 StackIter *stack_iter = (StackIter*)iter;
6611 InterpFrame *iframe = stack_iter->current;
6613 memset (frame, 0, sizeof (StackFrameInfo));
6614 /* pinvoke frames doesn't have imethod set */
6615 while (iframe && !(iframe->imethod && iframe->imethod->code && iframe->imethod->jinfo))
6616 iframe = iframe->parent;
6617 if (!iframe)
6618 return FALSE;
6620 MonoMethod *method = iframe->imethod->method;
6621 frame->domain = iframe->imethod->domain;
6622 frame->interp_frame = iframe;
6623 frame->method = method;
6624 frame->actual_method = method;
6625 if (method && ((method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) || (method->iflags & (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL | METHOD_IMPL_ATTRIBUTE_RUNTIME)))) {
6626 frame->native_offset = -1;
6627 frame->type = FRAME_TYPE_MANAGED_TO_NATIVE;
6628 } else {
6629 frame->type = FRAME_TYPE_INTERP;
6630 /* This is the offset in the interpreter IR */
6631 frame->native_offset = (guint8*)iframe->ip - (guint8*)iframe->imethod->code;
6632 if (!method->wrapper_type || method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD)
6633 frame->managed = TRUE;
6635 frame->ji = iframe->imethod->jinfo;
6636 frame->frame_addr = iframe;
6638 stack_iter->current = iframe->parent;
6640 return TRUE;
6643 static MonoJitInfo*
6644 interp_find_jit_info (MonoDomain *domain, MonoMethod *method)
6646 InterpMethod* imethod;
6648 imethod = lookup_imethod (domain, method);
6649 if (imethod)
6650 return imethod->jinfo;
6651 else
6652 return NULL;
6655 static void
6656 interp_set_breakpoint (MonoJitInfo *jinfo, gpointer ip)
6658 guint16 *code = (guint16*)ip;
6659 g_assert (*code == MINT_SDB_SEQ_POINT);
6660 *code = MINT_SDB_BREAKPOINT;
6663 static void
6664 interp_clear_breakpoint (MonoJitInfo *jinfo, gpointer ip)
6666 guint16 *code = (guint16*)ip;
6667 g_assert (*code == MINT_SDB_BREAKPOINT);
6668 *code = MINT_SDB_SEQ_POINT;
6671 static MonoJitInfo*
6672 interp_frame_get_jit_info (MonoInterpFrameHandle frame)
6674 InterpFrame *iframe = (InterpFrame*)frame;
6676 g_assert (iframe->imethod);
6677 return iframe->imethod->jinfo;
6680 static gpointer
6681 interp_frame_get_ip (MonoInterpFrameHandle frame)
6683 InterpFrame *iframe = (InterpFrame*)frame;
6685 g_assert (iframe->imethod);
6686 return (gpointer)iframe->ip;
6689 static gpointer
6690 interp_frame_get_arg (MonoInterpFrameHandle frame, int pos)
6692 InterpFrame *iframe = (InterpFrame*)frame;
6693 MonoMethodSignature *sig;
6695 g_assert (iframe->imethod);
6697 sig = mono_method_signature_internal (iframe->imethod->method);
6698 return stackval_to_data_addr (sig->params [pos], &iframe->stack_args [pos + !!iframe->imethod->hasthis]);
6701 static gpointer
6702 interp_frame_get_local (MonoInterpFrameHandle frame, int pos)
6704 InterpFrame *iframe = (InterpFrame*)frame;
6706 g_assert (iframe->imethod);
6708 return iframe->locals + iframe->imethod->local_offsets [pos];
6711 static gpointer
6712 interp_frame_get_this (MonoInterpFrameHandle frame)
6714 InterpFrame *iframe = (InterpFrame*)frame;
6716 g_assert (iframe->imethod);
6717 g_assert (iframe->imethod->hasthis);
6718 return &iframe->stack_args [0].data.p;
6721 static MonoInterpFrameHandle
6722 interp_frame_get_parent (MonoInterpFrameHandle frame)
6724 InterpFrame *iframe = (InterpFrame*)frame;
6726 return iframe->parent;
6729 static gpointer
6730 interp_frame_get_res (MonoInterpFrameHandle frame)
6732 InterpFrame *iframe = (InterpFrame*)frame;
6733 MonoMethodSignature *sig;
6735 g_assert (iframe->imethod);
6736 sig = mono_method_signature_internal (iframe->imethod->method);
6737 if (sig->ret->type == MONO_TYPE_VOID)
6738 return NULL;
6739 else
6740 return stackval_to_data_addr (sig->ret, iframe->retval);
6743 static void
6744 interp_start_single_stepping (void)
6746 ss_enabled = TRUE;
6749 static void
6750 interp_stop_single_stepping (void)
6752 ss_enabled = FALSE;
6755 static void
6756 register_interp_stats (void)
6758 mono_counters_init ();
6759 mono_counters_register ("Total transform time", MONO_COUNTER_INTERP | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_interp_stats.transform_time);
6760 mono_counters_register ("Methods inlined", MONO_COUNTER_INTERP | MONO_COUNTER_INT, &mono_interp_stats.inlined_methods);
6761 mono_counters_register ("Inline failures", MONO_COUNTER_INTERP | MONO_COUNTER_INT, &mono_interp_stats.inline_failures);
6764 #undef MONO_EE_CALLBACK
6765 #define MONO_EE_CALLBACK(ret, name, sig) interp_ ## name,
6767 static const MonoEECallbacks mono_interp_callbacks = {
6768 MONO_EE_CALLBACKS
6771 void
6772 mono_ee_interp_init (const char *opts)
6774 g_assert (mono_ee_api_version () == MONO_EE_API_VERSION);
6775 g_assert (!interp_init_done);
6776 interp_init_done = TRUE;
6778 mono_native_tls_alloc (&thread_context_id, NULL);
6779 set_context (NULL);
6781 interp_parse_options (opts);
6782 if (mini_get_debug_options ()->mdb_optimizations)
6783 mono_interp_opt &= ~INTERP_OPT_INLINE;
6784 mono_interp_transform_init ();
6786 mini_install_interp_callbacks (&mono_interp_callbacks);
6788 register_interp_stats ();