[netcore] add some intrinsics for interpreter (#14547)
[mono-project.git] / mono / mini / interp / interp.c
blobade2f4817c4141ebc8d89b278be199c0b7f92cc0
1 /**
2 * \file
3 * PLEASE NOTE: This is a research prototype.
6 * interp.c: Interpreter for CIL byte codes
8 * Authors:
9 * Paolo Molaro (lupus@ximian.com)
10 * Miguel de Icaza (miguel@ximian.com)
11 * Dietmar Maurer (dietmar@ximian.com)
13 * (C) 2001, 2002 Ximian, Inc.
15 #ifndef __USE_ISOC99
16 #define __USE_ISOC99
17 #endif
18 #include "config.h"
20 #include <stdio.h>
21 #include <string.h>
22 #include <stdlib.h>
23 #include <glib.h>
24 #include <math.h>
25 #include <locale.h>
27 #include <mono/utils/gc_wrapper.h>
28 #include <mono/utils/mono-math.h>
29 #include <mono/utils/mono-counters.h>
31 #ifdef HAVE_ALLOCA_H
32 # include <alloca.h>
33 #else
34 # ifdef __CYGWIN__
35 # define alloca __builtin_alloca
36 # endif
37 #endif
39 /* trim excessive headers */
40 #include <mono/metadata/image.h>
41 #include <mono/metadata/assembly-internals.h>
42 #include <mono/metadata/cil-coff.h>
43 #include <mono/metadata/mono-endian.h>
44 #include <mono/metadata/tabledefs.h>
45 #include <mono/metadata/tokentype.h>
46 #include <mono/metadata/loader.h>
47 #include <mono/metadata/threads.h>
48 #include <mono/metadata/threadpool.h>
49 #include <mono/metadata/profiler-private.h>
50 #include <mono/metadata/appdomain.h>
51 #include <mono/metadata/reflection.h>
52 #include <mono/metadata/exception.h>
53 #include <mono/metadata/verify.h>
54 #include <mono/metadata/opcodes.h>
55 #include <mono/metadata/debug-helpers.h>
56 #include <mono/metadata/mono-config.h>
57 #include <mono/metadata/marshal.h>
58 #include <mono/metadata/environment.h>
59 #include <mono/metadata/mono-debug.h>
60 #include <mono/metadata/gc-internals.h>
61 #include <mono/utils/atomic.h>
63 #include "interp.h"
64 #include "interp-internals.h"
65 #include "mintops.h"
67 #include <mono/mini/mini.h>
68 #include <mono/mini/mini-runtime.h>
69 #include <mono/mini/aot-runtime.h>
70 #include <mono/mini/llvm-runtime.h>
71 #include <mono/mini/llvmonly-runtime.h>
72 #include <mono/mini/jit-icalls.h>
73 #include <mono/mini/debugger-agent.h>
74 #include <mono/mini/ee.h>
75 #include <mono/mini/trace.h>
77 #ifdef TARGET_ARM
78 #include <mono/mini/mini-arm.h>
79 #endif
80 #include <mono/metadata/icall-decl.h>
82 #ifdef _MSC_VER
83 #pragma warning(disable:4102) // label' : unreferenced label
84 #endif
86 /* Arguments that are passed when invoking only a finally/filter clause from the frame */
87 typedef struct {
88 /* Where we start the frame execution from */
89 guint16 *start_with_ip;
91 * End ip of the exit_clause. We need it so we know whether the resume
92 * state is for this frame (which is called from EH) or for the original
93 * frame further down the stack.
95 guint16 *end_at_ip;
96 /* When exiting this clause we also exit the frame */
97 int exit_clause;
98 /* Exception that we are filtering */
99 MonoException *filter_exception;
100 InterpFrame *base_frame;
101 } FrameClauseArgs;
103 static inline void
104 init_frame (InterpFrame *frame, InterpFrame *parent_frame, InterpMethod *rmethod, stackval *method_args, stackval *method_retval)
106 frame->parent = parent_frame;
107 frame->stack_args = method_args;
108 frame->retval = method_retval;
109 frame->imethod = rmethod;
110 frame->ex = NULL;
111 frame->ip = NULL;
112 frame->invoke_trap = 0;
115 #define INIT_FRAME(frame,parent_frame,method_args,method_retval,domain,mono_method,error) do { \
116 InterpMethod *_rmethod = mono_interp_get_imethod ((domain), (mono_method), (error)); \
117 init_frame ((frame), (parent_frame), _rmethod, (method_args), (method_retval)); \
118 } while (0)
120 #define interp_exec_method(frame, context) interp_exec_method_full ((frame), (context), NULL)
123 * List of classes whose methods will be executed by transitioning to JITted code.
124 * Used for testing.
126 GSList *mono_interp_jit_classes;
127 /* Optimizations enabled with interpreter */
128 int mono_interp_opt = INTERP_OPT_INLINE;
129 /* If TRUE, interpreted code will be interrupted at function entry/backward branches */
130 static gboolean ss_enabled;
132 static gboolean interp_init_done = FALSE;
134 static void interp_exec_method_full (InterpFrame *frame, ThreadContext *context, FrameClauseArgs *clause_args);
135 static InterpMethod* lookup_method_pointer (gpointer addr);
137 typedef void (*ICallMethod) (InterpFrame *frame);
139 static MonoNativeTlsKey thread_context_id;
141 #define DEBUG_INTERP 0
142 #define COUNT_OPS 0
143 #if DEBUG_INTERP
144 int mono_interp_traceopt = 2;
145 /* If true, then we output the opcodes as we interpret them */
146 static int global_tracing = 2;
148 static int debug_indent_level = 0;
150 static int break_on_method = 0;
151 static int nested_trace = 0;
152 static GList *db_methods = NULL;
153 static char* dump_args (InterpFrame *inv);
155 static void
156 output_indent (void)
158 int h;
160 for (h = 0; h < debug_indent_level; h++)
161 g_print (" ");
164 static void
165 db_match_method (gpointer data, gpointer user_data)
167 MonoMethod *m = (MonoMethod*)user_data;
168 MonoMethodDesc *desc = data;
170 if (mono_method_desc_full_match (desc, m))
171 break_on_method = 1;
174 static void
175 debug_enter (InterpFrame *frame, int *tracing)
177 if (db_methods) {
178 g_list_foreach (db_methods, db_match_method, (gpointer)frame->imethod->method);
179 if (break_on_method)
180 *tracing = nested_trace ? (global_tracing = 2, 3) : 2;
181 break_on_method = 0;
183 if (*tracing) {
184 MonoMethod *method = frame->imethod->method;
185 char *mn, *args = dump_args (frame);
186 debug_indent_level++;
187 output_indent ();
188 mn = mono_method_full_name (method, FALSE);
189 g_print ("(%p) Entering %s (", mono_thread_internal_current (), mn);
190 g_free (mn);
191 g_print ("%s)\n", args);
192 g_free (args);
197 #define DEBUG_LEAVE() \
198 if (tracing) { \
199 char *mn, *args; \
200 args = dump_retval (frame); \
201 output_indent (); \
202 mn = mono_method_full_name (frame->imethod->method, FALSE); \
203 g_print ("(%p) Leaving %s", mono_thread_internal_current (), mn); \
204 g_free (mn); \
205 g_print (" => %s\n", args); \
206 g_free (args); \
207 debug_indent_level--; \
208 if (tracing == 3) global_tracing = 0; \
211 #else
213 int mono_interp_traceopt = 0;
214 static void debug_enter (InterpFrame *frame, int *tracing)
217 #define DEBUG_LEAVE()
219 #endif
221 static void
222 set_resume_state (ThreadContext *context, InterpFrame *frame)
224 frame->ex = NULL;
225 context->has_resume_state = 0;
226 context->handler_frame = NULL;
227 context->handler_ei = NULL;
230 /* Set the current execution state to the resume state in context */
231 #define SET_RESUME_STATE(context) do { \
232 ip = (const guint16*)(context)->handler_ip; \
233 /* spec says stack should be empty at endfinally so it should be at the start too */ \
234 sp = frame->stack; \
235 vt_sp = (unsigned char *) sp + imethod->stack_size; \
236 if (frame->ex) { \
237 sp->data.p = frame->ex; \
238 ++sp; \
240 /* We have thrown an exception from a finally block. Some of the leave targets were unwinded already */ \
241 while (finally_ips && \
242 finally_ips->data >= (context)->handler_ei->try_start && \
243 finally_ips->data < (context)->handler_ei->try_end) \
244 finally_ips = g_slist_remove (finally_ips, finally_ips->data); \
245 set_resume_state ((context), (frame)); \
246 goto main_loop; \
247 } while (0)
250 * If this bit is set, it means the call has thrown the exception, and we
251 * reached this point because the EH code in mono_handle_exception ()
252 * unwound all the JITted frames below us. mono_interp_set_resume_state ()
253 * has set the fields in context to indicate where we have to resume execution.
255 #define CHECK_RESUME_STATE(context) do { \
256 if ((context)->has_resume_state) { \
257 if (frame == (context)->handler_frame && (!clause_args || (context)->handler_ip < clause_args->end_at_ip)) \
258 SET_RESUME_STATE (context); \
259 else \
260 goto exit_frame; \
262 } while (0);
264 static void
265 set_context (ThreadContext *context)
267 mono_native_tls_set_value (thread_context_id, context);
269 if (!context)
270 return;
272 MonoJitTlsData *jit_tls = mono_tls_get_jit_tls ();
273 g_assertf (jit_tls, "ThreadContext needs initialized JIT TLS");
275 /* jit_tls assumes ownership of 'context' */
276 jit_tls->interp_context = context;
279 static ThreadContext *
280 get_context (void)
282 ThreadContext *context = (ThreadContext *) mono_native_tls_get_value (thread_context_id);
283 if (context == NULL) {
284 context = g_new0 (ThreadContext, 1);
285 set_context (context);
287 return context;
290 static void
291 ves_real_abort (int line, MonoMethod *mh,
292 const unsigned short *ip, stackval *stack, stackval *sp)
294 ERROR_DECL (error);
295 MonoMethodHeader *header = mono_method_get_header_checked (mh, error);
296 mono_error_cleanup (error); /* FIXME: don't swallow the error */
297 g_printerr ("Execution aborted in method: %s::%s\n", m_class_get_name (mh->klass), mh->name);
298 g_printerr ("Line=%d IP=0x%04lx, Aborted execution\n", line, ip-(const unsigned short *) header->code);
299 g_printerr ("0x%04x %02x\n", ip-(const unsigned short *) header->code, *ip);
300 mono_metadata_free_mh (header);
303 #define ves_abort() \
304 do {\
305 ves_real_abort(__LINE__, frame->imethod->method, ip, frame->stack, sp); \
306 THROW_EX (mono_get_exception_execution_engine (NULL), ip); \
307 } while (0);
309 static InterpMethod*
310 lookup_imethod (MonoDomain *domain, MonoMethod *method)
312 InterpMethod *imethod;
313 MonoJitDomainInfo *info;
315 info = domain_jit_info (domain);
316 mono_domain_jit_code_hash_lock (domain);
317 imethod = (InterpMethod*)mono_internal_hash_table_lookup (&info->interp_code_hash, method);
318 mono_domain_jit_code_hash_unlock (domain);
319 return imethod;
322 static gpointer
323 interp_get_remoting_invoke (MonoMethod *method, gpointer addr, MonoError *error)
325 #ifndef DISABLE_REMOTING
326 InterpMethod *imethod;
328 if (addr) {
329 imethod = lookup_method_pointer (addr);
330 } else {
331 g_assert (method);
332 imethod = mono_interp_get_imethod (mono_domain_get (), method, error);
333 return_val_if_nok (error, NULL);
335 g_assert (imethod);
336 g_assert (mono_use_interpreter);
338 MonoMethod *remoting_invoke_method = mono_marshal_get_remoting_invoke (imethod->method, error);
339 return_val_if_nok (error, NULL);
340 return mono_interp_get_imethod (mono_domain_get (), remoting_invoke_method, error);
341 #else
342 g_assert_not_reached ();
343 return NULL;
344 #endif
347 InterpMethod*
348 mono_interp_get_imethod (MonoDomain *domain, MonoMethod *method, MonoError *error)
350 InterpMethod *imethod;
351 MonoJitDomainInfo *info;
352 MonoMethodSignature *sig;
353 int i;
355 error_init (error);
357 info = domain_jit_info (domain);
358 mono_domain_jit_code_hash_lock (domain);
359 imethod = (InterpMethod*)mono_internal_hash_table_lookup (&info->interp_code_hash, method);
360 mono_domain_jit_code_hash_unlock (domain);
361 if (imethod)
362 return imethod;
364 sig = mono_method_signature_internal (method);
366 imethod = (InterpMethod*)mono_domain_alloc0 (domain, sizeof (InterpMethod));
367 imethod->method = method;
368 imethod->domain = domain;
369 imethod->param_count = sig->param_count;
370 imethod->hasthis = sig->hasthis;
371 imethod->vararg = sig->call_convention == MONO_CALL_VARARG;
372 imethod->rtype = mini_get_underlying_type (sig->ret);
373 imethod->param_types = (MonoType**)mono_domain_alloc0 (domain, sizeof (MonoType*) * sig->param_count);
374 for (i = 0; i < sig->param_count; ++i)
375 imethod->param_types [i] = mini_get_underlying_type (sig->params [i]);
377 mono_domain_jit_code_hash_lock (domain);
378 if (!mono_internal_hash_table_lookup (&info->interp_code_hash, method))
379 mono_internal_hash_table_insert (&info->interp_code_hash, method, imethod);
380 mono_domain_jit_code_hash_unlock (domain);
382 imethod->prof_flags = mono_profiler_get_call_instrumentation_flags (imethod->method);
384 return imethod;
387 #if defined (MONO_CROSS_COMPILE) || defined (HOST_WASM) || defined (_MSC_VER)
388 #define INTERP_PUSH_LMF_WITH_CTX_BODY(ext, exit_addr) \
389 (ext).kind = MONO_LMFEXT_INTERP_EXIT;
391 #elif defined(MONO_ARCH_HAS_NO_PROPER_MONOCTX)
392 /* some platforms, e.g. appleTV, don't provide us a precise MonoContext
393 * (registers are not accurate), thus resuming to the label does not work. */
394 #define INTERP_PUSH_LMF_WITH_CTX_BODY(ext, exit_addr) \
395 (ext).kind = MONO_LMFEXT_INTERP_EXIT;
397 #elif defined(MONO_ARCH_HAS_MONO_CONTEXT)
398 #define INTERP_PUSH_LMF_WITH_CTX_BODY(ext, exit_addr) \
399 (ext).kind = MONO_LMFEXT_INTERP_EXIT_WITH_CTX; \
400 MONO_CONTEXT_GET_CURRENT ((ext).ctx); \
401 MONO_CONTEXT_SET_IP (&(ext).ctx, (exit_addr)); \
402 mono_arch_do_ip_adjustment (&(ext).ctx);
403 #else
404 #define INTERP_PUSH_LMF_WITH_CTX_BODY(ext, exit_addr) g_error ("requires working mono-context");
405 #endif
407 /* INTERP_PUSH_LMF_WITH_CTX:
409 * same as interp_push_lmf, but retrieving and attaching MonoContext to it.
410 * This is needed to resume into the interp when the exception is thrown from
411 * native code (see ./mono/tests/install_eh_callback.exe).
413 * This must be a macro in order to retrieve the right register values for
414 * MonoContext.
416 #define INTERP_PUSH_LMF_WITH_CTX(frame, ext, exit_addr) \
417 memset (&(ext), 0, sizeof (MonoLMFExt)); \
418 (ext).interp_exit_data = (frame); \
419 INTERP_PUSH_LMF_WITH_CTX_BODY ((ext), (exit_addr)); \
420 mono_push_lmf (&(ext));
423 * interp_push_lmf:
425 * Push an LMF frame on the LMF stack
426 * to mark the transition to native code.
427 * This is needed for the native code to
428 * be able to do stack walks.
430 static void
431 interp_push_lmf (MonoLMFExt *ext, InterpFrame *frame)
433 memset (ext, 0, sizeof (MonoLMFExt));
434 ext->kind = MONO_LMFEXT_INTERP_EXIT;
435 ext->interp_exit_data = frame;
437 mono_push_lmf (ext);
440 static void
441 interp_pop_lmf (MonoLMFExt *ext)
443 mono_pop_lmf (&ext->lmf);
446 static InterpMethod*
447 get_virtual_method (InterpMethod *imethod, MonoObject *obj)
449 MonoMethod *m = imethod->method;
450 MonoDomain *domain = imethod->domain;
451 InterpMethod *ret = NULL;
452 ERROR_DECL (error);
454 #ifndef DISABLE_REMOTING
455 if (mono_object_is_transparent_proxy (obj)) {
456 MonoMethod *remoting_invoke_method = mono_marshal_get_remoting_invoke_with_check (m, error);
457 mono_error_assert_ok (error);
458 ret = mono_interp_get_imethod (domain, remoting_invoke_method, error);
459 mono_error_assert_ok (error);
460 return ret;
462 #endif
464 if ((m->flags & METHOD_ATTRIBUTE_FINAL) || !(m->flags & METHOD_ATTRIBUTE_VIRTUAL)) {
465 if (m->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED) {
466 ret = mono_interp_get_imethod (domain, mono_marshal_get_synchronized_wrapper (m), error);
467 mono_error_cleanup (error); /* FIXME: don't swallow the error */
468 } else {
469 ret = imethod;
471 return ret;
474 mono_class_setup_vtable (obj->vtable->klass);
476 int slot = mono_method_get_vtable_slot (m);
477 if (mono_class_is_interface (m->klass)) {
478 g_assert (obj->vtable->klass != m->klass);
479 /* TODO: interface offset lookup is slow, go through IMT instead */
480 gboolean non_exact_match;
481 slot += mono_class_interface_offset_with_variance (obj->vtable->klass, m->klass, &non_exact_match);
484 MonoMethod *virtual_method = m_class_get_vtable (mono_object_class (obj)) [slot];
485 if (m->is_inflated && mono_method_get_context (m)->method_inst) {
486 MonoGenericContext context = { NULL, NULL };
488 if (mono_class_is_ginst (virtual_method->klass))
489 context.class_inst = mono_class_get_generic_class (virtual_method->klass)->context.class_inst;
490 else if (mono_class_is_gtd (virtual_method->klass))
491 context.class_inst = mono_class_get_generic_container (virtual_method->klass)->context.class_inst;
492 context.method_inst = mono_method_get_context (m)->method_inst;
494 virtual_method = mono_class_inflate_generic_method_checked (virtual_method, &context, error);
495 mono_error_cleanup (error); /* FIXME: don't swallow the error */
498 if (virtual_method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) {
499 virtual_method = mono_marshal_get_native_wrapper (virtual_method, FALSE, FALSE);
502 if (virtual_method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED) {
503 virtual_method = mono_marshal_get_synchronized_wrapper (virtual_method);
506 InterpMethod *virtual_imethod = mono_interp_get_imethod (domain, virtual_method, error);
507 mono_error_cleanup (error); /* FIXME: don't swallow the error */
508 return virtual_imethod;
511 typedef struct {
512 InterpMethod *imethod;
513 InterpMethod *target_imethod;
514 } InterpVTableEntry;
516 /* domain lock must be held */
517 static GSList*
518 append_imethod (MonoDomain *domain, GSList *list, InterpMethod *imethod, InterpMethod *target_imethod)
520 GSList *ret;
521 InterpVTableEntry *entry;
523 entry = (InterpVTableEntry*) mono_mempool_alloc (domain->mp, sizeof (InterpVTableEntry));
524 entry->imethod = imethod;
525 entry->target_imethod = target_imethod;
526 ret = g_slist_append_mempool (domain->mp, list, entry);
528 return ret;
531 static InterpMethod*
532 get_target_imethod (GSList *list, InterpMethod *imethod)
534 while (list != NULL) {
535 InterpVTableEntry *entry = (InterpVTableEntry*) list->data;
536 if (entry->imethod == imethod)
537 return entry->target_imethod;
538 list = list->next;
540 return NULL;
543 static gpointer*
544 get_method_table (MonoObject *obj, int offset)
546 if (offset >= 0) {
547 return obj->vtable->interp_vtable;
548 } else {
549 return (gpointer*)obj->vtable;
553 static gpointer*
554 alloc_method_table (MonoObject *obj, int offset)
556 gpointer *table;
558 if (offset >= 0) {
559 table = mono_domain_alloc0 (obj->vtable->domain, m_class_get_vtable_size (obj->vtable->klass) * sizeof (gpointer));
560 obj->vtable->interp_vtable = table;
561 } else {
562 table = (gpointer*)obj->vtable;
565 return table;
568 static InterpMethod*
569 get_virtual_method_fast (MonoObject *obj, InterpMethod *imethod, int offset)
571 gpointer *table;
573 #ifndef DISABLE_REMOTING
574 /* FIXME Remoting */
575 if (mono_object_is_transparent_proxy (obj))
576 return get_virtual_method (imethod, obj);
577 #endif
579 table = get_method_table (obj, offset);
581 if (!table) {
582 /* Lazily allocate method table */
583 mono_domain_lock (obj->vtable->domain);
584 table = get_method_table (obj, offset);
585 if (!table)
586 table = alloc_method_table (obj, offset);
587 mono_domain_unlock (obj->vtable->domain);
590 if (!table [offset]) {
591 InterpMethod *target_imethod = get_virtual_method (imethod, obj);
592 /* Lazily initialize the method table slot */
593 mono_domain_lock (obj->vtable->domain);
594 if (!table [offset]) {
595 if (imethod->method->is_inflated || offset < 0)
596 table [offset] = append_imethod (obj->vtable->domain, NULL, imethod, target_imethod);
597 else
598 table [offset] = (gpointer) ((gsize)target_imethod | 0x1);
600 mono_domain_unlock (obj->vtable->domain);
603 if ((gsize)table [offset] & 0x1) {
604 /* Non generic virtual call. Only one method in slot */
605 return (InterpMethod*) ((gsize)table [offset] & ~0x1);
606 } else {
607 /* Virtual generic or interface call. Multiple methods in slot */
608 InterpMethod *target_imethod = get_target_imethod ((GSList*)table [offset], imethod);
610 if (!target_imethod) {
611 target_imethod = get_virtual_method (imethod, obj);
612 mono_domain_lock (obj->vtable->domain);
613 if (!get_target_imethod ((GSList*)table [offset], imethod))
614 table [offset] = append_imethod (obj->vtable->domain, (GSList*)table [offset], imethod, target_imethod);
615 mono_domain_unlock (obj->vtable->domain);
617 return target_imethod;
621 static void inline
622 stackval_from_data (MonoType *type_, stackval *result, void *data, gboolean pinvoke)
624 MonoType *type = mini_native_type_replace_type (type_);
625 if (type->byref) {
626 switch (type->type) {
627 case MONO_TYPE_OBJECT:
628 case MONO_TYPE_CLASS:
629 case MONO_TYPE_STRING:
630 case MONO_TYPE_ARRAY:
631 case MONO_TYPE_SZARRAY:
632 break;
633 default:
634 break;
636 result->data.p = *(gpointer*)data;
637 return;
639 switch (type->type) {
640 case MONO_TYPE_VOID:
641 return;
642 case MONO_TYPE_I1:
643 result->data.i = *(gint8*)data;
644 return;
645 case MONO_TYPE_U1:
646 case MONO_TYPE_BOOLEAN:
647 result->data.i = *(guint8*)data;
648 return;
649 case MONO_TYPE_I2:
650 result->data.i = *(gint16*)data;
651 return;
652 case MONO_TYPE_U2:
653 case MONO_TYPE_CHAR:
654 result->data.i = *(guint16*)data;
655 return;
656 case MONO_TYPE_I4:
657 result->data.i = *(gint32*)data;
658 return;
659 case MONO_TYPE_U:
660 case MONO_TYPE_I:
661 result->data.nati = *(mono_i*)data;
662 return;
663 case MONO_TYPE_PTR:
664 result->data.p = *(gpointer*)data;
665 return;
666 case MONO_TYPE_U4:
667 result->data.i = *(guint32*)data;
668 return;
669 case MONO_TYPE_R4:
670 /* memmove handles unaligned case */
671 memmove (&result->data.f_r4, data, sizeof (float));
672 return;
673 case MONO_TYPE_I8:
674 case MONO_TYPE_U8:
675 memmove (&result->data.l, data, sizeof (gint64));
676 return;
677 case MONO_TYPE_R8:
678 memmove (&result->data.f, data, sizeof (double));
679 return;
680 case MONO_TYPE_STRING:
681 case MONO_TYPE_SZARRAY:
682 case MONO_TYPE_CLASS:
683 case MONO_TYPE_OBJECT:
684 case MONO_TYPE_ARRAY:
685 result->data.p = *(gpointer*)data;
686 return;
687 case MONO_TYPE_VALUETYPE:
688 if (m_class_is_enumtype (type->data.klass)) {
689 stackval_from_data (mono_class_enum_basetype_internal (type->data.klass), result, data, pinvoke);
690 return;
691 } else if (pinvoke) {
692 memcpy (result->data.vt, data, mono_class_native_size (type->data.klass, NULL));
693 } else {
694 mono_value_copy_internal (result->data.vt, data, type->data.klass);
696 return;
697 case MONO_TYPE_GENERICINST: {
698 if (mono_type_generic_inst_is_valuetype (type)) {
699 mono_value_copy_internal (result->data.vt, data, mono_class_from_mono_type_internal (type));
700 return;
702 stackval_from_data (m_class_get_byval_arg (type->data.generic_class->container_class), result, data, pinvoke);
703 return;
705 default:
706 g_error ("got type 0x%02x", type->type);
710 static void inline
711 stackval_to_data (MonoType *type_, stackval *val, void *data, gboolean pinvoke)
713 MonoType *type = mini_native_type_replace_type (type_);
714 if (type->byref) {
715 gpointer *p = (gpointer*)data;
716 *p = val->data.p;
717 return;
719 /* printf ("TODAT0 %p\n", data); */
720 switch (type->type) {
721 case MONO_TYPE_I1:
722 case MONO_TYPE_U1: {
723 guint8 *p = (guint8*)data;
724 *p = val->data.i;
725 return;
727 case MONO_TYPE_BOOLEAN: {
728 guint8 *p = (guint8*)data;
729 *p = (val->data.i != 0);
730 return;
732 case MONO_TYPE_I2:
733 case MONO_TYPE_U2:
734 case MONO_TYPE_CHAR: {
735 guint16 *p = (guint16*)data;
736 *p = val->data.i;
737 return;
739 case MONO_TYPE_I: {
740 mono_i *p = (mono_i*)data;
741 /* In theory the value used by stloc should match the local var type
742 but in practice it sometimes doesn't (a int32 gets dup'd and stloc'd into
743 a native int - both by csc and mcs). Not sure what to do about sign extension
744 as it is outside the spec... doing the obvious */
745 *p = (mono_i)val->data.nati;
746 return;
748 case MONO_TYPE_U: {
749 mono_u *p = (mono_u*)data;
750 /* see above. */
751 *p = (mono_u)val->data.nati;
752 return;
754 case MONO_TYPE_I4:
755 case MONO_TYPE_U4: {
756 gint32 *p = (gint32*)data;
757 *p = val->data.i;
758 return;
760 case MONO_TYPE_I8:
761 case MONO_TYPE_U8: {
762 memmove (data, &val->data.l, sizeof (gint64));
763 return;
765 case MONO_TYPE_R4: {
766 /* memmove handles unaligned case */
767 memmove (data, &val->data.f_r4, sizeof (float));
768 return;
770 case MONO_TYPE_R8: {
771 memmove (data, &val->data.f, sizeof (double));
772 return;
774 case MONO_TYPE_STRING:
775 case MONO_TYPE_SZARRAY:
776 case MONO_TYPE_CLASS:
777 case MONO_TYPE_OBJECT:
778 case MONO_TYPE_ARRAY: {
779 gpointer *p = (gpointer *) data;
780 mono_gc_wbarrier_generic_store_internal (p, val->data.o);
781 return;
783 case MONO_TYPE_PTR: {
784 gpointer *p = (gpointer *) data;
785 *p = val->data.p;
786 return;
788 case MONO_TYPE_VALUETYPE:
789 if (m_class_is_enumtype (type->data.klass)) {
790 stackval_to_data (mono_class_enum_basetype_internal (type->data.klass), val, data, pinvoke);
791 return;
792 } else if (pinvoke) {
793 memcpy (data, val->data.vt, mono_class_native_size (type->data.klass, NULL));
794 } else {
795 mono_value_copy_internal (data, val->data.vt, type->data.klass);
797 return;
798 case MONO_TYPE_GENERICINST: {
799 MonoClass *container_class = type->data.generic_class->container_class;
801 if (m_class_is_valuetype (container_class) && !m_class_is_enumtype (container_class)) {
802 mono_value_copy_internal (data, val->data.vt, mono_class_from_mono_type_internal (type));
803 return;
805 stackval_to_data (m_class_get_byval_arg (type->data.generic_class->container_class), val, data, pinvoke);
806 return;
808 default:
809 g_error ("got type %x", type->type);
814 * Same as stackval_to_data but return address of storage instead
815 * of copying the value.
817 static gpointer
818 stackval_to_data_addr (MonoType *type_, stackval *val)
820 MonoType *type = mini_native_type_replace_type (type_);
821 if (type->byref)
822 return &val->data.p;
824 switch (type->type) {
825 case MONO_TYPE_I1:
826 case MONO_TYPE_U1:
827 case MONO_TYPE_BOOLEAN:
828 case MONO_TYPE_I2:
829 case MONO_TYPE_U2:
830 case MONO_TYPE_CHAR:
831 case MONO_TYPE_I4:
832 case MONO_TYPE_U4:
833 return &val->data.i;
834 case MONO_TYPE_I:
835 case MONO_TYPE_U:
836 return &val->data.nati;
837 case MONO_TYPE_I8:
838 case MONO_TYPE_U8:
839 return &val->data.l;
840 case MONO_TYPE_R4:
841 return &val->data.f_r4;
842 case MONO_TYPE_R8:
843 return &val->data.f;
844 case MONO_TYPE_STRING:
845 case MONO_TYPE_SZARRAY:
846 case MONO_TYPE_CLASS:
847 case MONO_TYPE_OBJECT:
848 case MONO_TYPE_ARRAY:
849 case MONO_TYPE_PTR:
850 return &val->data.p;
851 case MONO_TYPE_VALUETYPE:
852 if (m_class_is_enumtype (type->data.klass))
853 return stackval_to_data_addr (mono_class_enum_basetype_internal (type->data.klass), val);
854 else
855 return val->data.vt;
856 case MONO_TYPE_TYPEDBYREF:
857 return val->data.vt;
858 case MONO_TYPE_GENERICINST: {
859 MonoClass *container_class = type->data.generic_class->container_class;
861 if (m_class_is_valuetype (container_class) && !m_class_is_enumtype (container_class))
862 return val->data.vt;
863 return stackval_to_data_addr (m_class_get_byval_arg (type->data.generic_class->container_class), val);
865 default:
866 g_error ("got type %x", type->type);
871 * interp_throw:
872 * Throw an exception from the interpreter.
874 static MONO_NEVER_INLINE void
875 interp_throw (ThreadContext *context, MonoException *ex, InterpFrame *frame, gconstpointer ip, gboolean rethrow)
877 ERROR_DECL (error);
878 MonoLMFExt ext;
880 interp_push_lmf (&ext, frame);
881 frame->ip = (const guint16*)ip;
882 frame->ex = ex;
884 if (mono_object_isinst_checked ((MonoObject *) ex, mono_defaults.exception_class, error)) {
885 MonoException *mono_ex = (MonoException *) ex;
886 if (!rethrow) {
887 mono_ex->stack_trace = NULL;
888 mono_ex->trace_ips = NULL;
891 mono_error_assert_ok (error);
893 MonoContext ctx;
894 memset (&ctx, 0, sizeof (MonoContext));
895 MONO_CONTEXT_SET_SP (&ctx, frame);
898 * Call the JIT EH code. The EH code will call back to us using:
899 * - mono_interp_set_resume_state ()/run_finally ()/run_filter ().
900 * Since ctx.ip is 0, this will start unwinding from the LMF frame
901 * pushed above, which points to our frames.
903 mono_handle_exception (&ctx, (MonoObject*)ex);
904 if (MONO_CONTEXT_GET_IP (&ctx) != 0) {
905 /* We need to unwind into non-interpreter code */
906 mono_restore_context (&ctx);
907 g_assert_not_reached ();
910 interp_pop_lmf (&ext);
912 g_assert (context->has_resume_state);
915 #define THROW_EX_GENERAL(exception,ex_ip, rethrow) \
916 do { \
917 interp_throw (context, (exception), (frame), (ex_ip), (rethrow)); \
918 CHECK_RESUME_STATE(context); \
919 } while (0)
921 #define THROW_EX(exception,ex_ip) THROW_EX_GENERAL ((exception), (ex_ip), FALSE)
923 #define EXCEPTION_CHECKPOINT \
924 do { \
925 if (*mono_thread_interruption_request_flag () && !mono_threads_is_critical_method (imethod->method)) { \
926 MonoException *exc = mono_thread_interruption_checkpoint (); \
927 if (exc) \
928 THROW_EX (exc, ip); \
930 } while (0)
933 static MonoObject*
934 ves_array_create (MonoDomain *domain, MonoClass *klass, int param_count, stackval *values, MonoError *error)
936 uintptr_t *lengths;
937 intptr_t *lower_bounds;
938 MonoObject *obj;
939 int i;
941 lengths = g_newa (uintptr_t, m_class_get_rank (klass) * 2);
942 for (i = 0; i < param_count; ++i) {
943 lengths [i] = values->data.i;
944 values ++;
946 if (m_class_get_rank (klass) == param_count) {
947 /* Only lengths provided. */
948 lower_bounds = NULL;
949 } else {
950 /* lower bounds are first. */
951 lower_bounds = (intptr_t *) lengths;
952 lengths += m_class_get_rank (klass);
954 obj = (MonoObject*) mono_array_new_full_checked (domain, klass, lengths, lower_bounds, error);
955 return obj;
958 static gint32
959 ves_array_calculate_index (MonoArray *ao, stackval *sp, InterpFrame *frame, gboolean safe)
961 g_assert (!frame->ex);
962 MonoClass *ac = ((MonoObject *) ao)->vtable->klass;
964 guint32 pos = 0;
965 if (ao->bounds) {
966 for (gint32 i = 0; i < m_class_get_rank (ac); i++) {
967 guint32 idx = sp [i].data.i;
968 guint32 lower = ao->bounds [i].lower_bound;
969 guint32 len = ao->bounds [i].length;
970 if (safe && (idx < lower || (idx - lower) >= len)) {
971 frame->ex = mono_get_exception_index_out_of_range ();
972 return -1;
974 pos = (pos * len) + idx - lower;
976 } else {
977 pos = sp [0].data.i;
978 if (safe && pos >= ao->max_length) {
979 frame->ex = mono_get_exception_index_out_of_range ();
980 return -1;
983 return pos;
986 static void
987 ves_array_set (InterpFrame *frame, stackval *sp, MonoMethodSignature *sig)
989 MonoObject *o = sp->data.o;
990 MonoArray *ao = (MonoArray *) o;
991 MonoClass *ac = o->vtable->klass;
993 g_assert (m_class_get_rank (ac) >= 1);
995 gint32 pos = ves_array_calculate_index (ao, sp + 1, frame, TRUE);
996 if (frame->ex)
997 return;
999 int val_index = 1 + m_class_get_rank (ac);
1000 if (sp [val_index].data.p && !m_class_is_valuetype (m_class_get_element_class (mono_object_class (o)))) {
1001 ERROR_DECL (error);
1002 MonoObject *isinst = mono_object_isinst_checked (sp [val_index].data.o, m_class_get_element_class (mono_object_class (o)), error);
1003 mono_error_cleanup (error);
1004 if (!isinst) {
1005 frame->ex = mono_get_exception_array_type_mismatch ();
1006 return;
1010 gint32 esize = mono_array_element_size (ac);
1011 gpointer ea = mono_array_addr_with_size_fast (ao, esize, pos);
1013 MonoType *mt = sig->params [m_class_get_rank (ac)];
1014 stackval_to_data (mt, &sp [val_index], ea, FALSE);
1017 static void
1018 ves_array_get (InterpFrame *frame, stackval *sp, stackval *retval, MonoMethodSignature *sig, gboolean safe)
1020 MonoObject *o = sp->data.o;
1021 MonoArray *ao = (MonoArray *) o;
1022 MonoClass *ac = o->vtable->klass;
1024 g_assert (m_class_get_rank (ac) >= 1);
1026 gint32 pos = ves_array_calculate_index (ao, sp + 1, frame, safe);
1027 if (frame->ex)
1028 return;
1030 gint32 esize = mono_array_element_size (ac);
1031 gpointer ea = mono_array_addr_with_size_fast (ao, esize, pos);
1033 MonoType *mt = sig->ret;
1034 stackval_from_data (mt, retval, ea, FALSE);
1037 static gpointer
1038 ves_array_element_address (InterpFrame *frame, MonoClass *required_type, MonoArray *ao, stackval *sp, gboolean needs_typecheck)
1040 MonoClass *ac = ((MonoObject *) ao)->vtable->klass;
1042 g_assert (m_class_get_rank (ac) >= 1);
1044 gint32 pos = ves_array_calculate_index (ao, sp, frame, TRUE);
1045 if (frame->ex)
1046 return NULL;
1048 if (needs_typecheck && !mono_class_is_assignable_from_internal (m_class_get_element_class (mono_object_class ((MonoObject *) ao)), required_type)) {
1049 frame->ex = mono_get_exception_array_type_mismatch ();
1050 return NULL;
1052 gint32 esize = mono_array_element_size (ac);
1053 return mono_array_addr_with_size_fast (ao, esize, pos);
1056 #ifdef MONO_ARCH_HAVE_INTERP_ENTRY_TRAMPOLINE
1057 static MonoFuncV mono_native_to_interp_trampoline = NULL;
1058 #endif
1060 #ifndef MONO_ARCH_HAVE_INTERP_PINVOKE_TRAMP
1061 static InterpMethodArguments* build_args_from_sig (MonoMethodSignature *sig, InterpFrame *frame)
1063 InterpMethodArguments *margs = g_malloc0 (sizeof (InterpMethodArguments));
1065 #ifdef TARGET_ARM
1066 g_assert (mono_arm_eabi_supported ());
1067 int i8_align = mono_arm_i8_align ();
1068 #endif
1070 #ifdef TARGET_WASM
1071 margs->sig = sig;
1072 #endif
1074 if (sig->hasthis)
1075 margs->ilen++;
1077 for (int i = 0; i < sig->param_count; i++) {
1078 guint32 ptype = sig->params [i]->byref ? MONO_TYPE_PTR : sig->params [i]->type;
1079 switch (ptype) {
1080 case MONO_TYPE_BOOLEAN:
1081 case MONO_TYPE_CHAR:
1082 case MONO_TYPE_I1:
1083 case MONO_TYPE_U1:
1084 case MONO_TYPE_I2:
1085 case MONO_TYPE_U2:
1086 case MONO_TYPE_I4:
1087 case MONO_TYPE_U4:
1088 case MONO_TYPE_I:
1089 case MONO_TYPE_U:
1090 case MONO_TYPE_PTR:
1091 case MONO_TYPE_SZARRAY:
1092 case MONO_TYPE_CLASS:
1093 case MONO_TYPE_OBJECT:
1094 case MONO_TYPE_STRING:
1095 case MONO_TYPE_VALUETYPE:
1096 case MONO_TYPE_GENERICINST:
1097 #if SIZEOF_VOID_P == 8
1098 case MONO_TYPE_I8:
1099 case MONO_TYPE_U8:
1100 #endif
1101 margs->ilen++;
1102 break;
1103 #if SIZEOF_VOID_P == 4
1104 case MONO_TYPE_I8:
1105 case MONO_TYPE_U8:
1106 #ifdef TARGET_ARM
1107 /* pairs begin at even registers */
1108 if (i8_align == 8 && margs->ilen & 1)
1109 margs->ilen++;
1110 #endif
1111 margs->ilen += 2;
1112 break;
1113 #endif
1114 case MONO_TYPE_R4:
1115 #if SIZEOF_VOID_P == 8
1116 case MONO_TYPE_R8:
1117 #endif
1118 margs->flen++;
1119 break;
1120 #if SIZEOF_VOID_P == 4
1121 case MONO_TYPE_R8:
1122 margs->flen += 2;
1123 break;
1124 #endif
1125 default:
1126 g_error ("build_args_from_sig: not implemented yet (1): 0x%x\n", ptype);
1130 if (margs->ilen > 0)
1131 margs->iargs = g_malloc0 (sizeof (gpointer) * margs->ilen);
1133 if (margs->flen > 0)
1134 margs->fargs = g_malloc0 (sizeof (double) * margs->flen);
1136 if (margs->ilen > INTERP_ICALL_TRAMP_IARGS)
1137 g_error ("build_args_from_sig: TODO, allocate gregs: %d\n", margs->ilen);
1139 if (margs->flen > INTERP_ICALL_TRAMP_FARGS)
1140 g_error ("build_args_from_sig: TODO, allocate fregs: %d\n", margs->flen);
1143 size_t int_i = 0;
1144 size_t int_f = 0;
1146 if (sig->hasthis) {
1147 margs->iargs [0] = frame->stack_args->data.p;
1148 int_i++;
1151 for (int i = 0; i < sig->param_count; i++) {
1152 guint32 ptype = sig->params [i]->byref ? MONO_TYPE_PTR : sig->params [i]->type;
1153 switch (ptype) {
1154 case MONO_TYPE_BOOLEAN:
1155 case MONO_TYPE_CHAR:
1156 case MONO_TYPE_I1:
1157 case MONO_TYPE_U1:
1158 case MONO_TYPE_I2:
1159 case MONO_TYPE_U2:
1160 case MONO_TYPE_I4:
1161 case MONO_TYPE_U4:
1162 case MONO_TYPE_I:
1163 case MONO_TYPE_U:
1164 case MONO_TYPE_PTR:
1165 case MONO_TYPE_SZARRAY:
1166 case MONO_TYPE_CLASS:
1167 case MONO_TYPE_OBJECT:
1168 case MONO_TYPE_STRING:
1169 case MONO_TYPE_VALUETYPE:
1170 case MONO_TYPE_GENERICINST:
1171 #if SIZEOF_VOID_P == 8
1172 case MONO_TYPE_I8:
1173 case MONO_TYPE_U8:
1174 #endif
1175 margs->iargs [int_i] = frame->stack_args [i].data.p;
1176 #if DEBUG_INTERP
1177 g_print ("build_args_from_sig: margs->iargs [%d]: %p (frame @ %d)\n", int_i, margs->iargs [int_i], i);
1178 #endif
1179 int_i++;
1180 break;
1181 #if SIZEOF_VOID_P == 4
1182 case MONO_TYPE_I8:
1183 case MONO_TYPE_U8: {
1184 stackval *sarg = &frame->stack_args [i];
1185 #ifdef TARGET_ARM
1186 /* pairs begin at even registers */
1187 if (i8_align == 8 && int_i & 1)
1188 int_i++;
1189 #endif
1190 margs->iargs [int_i] = (gpointer) sarg->data.pair.lo;
1191 int_i++;
1192 margs->iargs [int_i] = (gpointer) sarg->data.pair.hi;
1193 #if DEBUG_INTERP
1194 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);
1195 #endif
1196 int_i++;
1197 break;
1199 #endif
1200 case MONO_TYPE_R4:
1201 case MONO_TYPE_R8:
1202 if (ptype == MONO_TYPE_R4)
1203 * (float *) &(margs->fargs [int_f]) = frame->stack_args [i].data.f_r4;
1204 else
1205 margs->fargs [int_f] = frame->stack_args [i].data.f;
1206 #if DEBUG_INTERP
1207 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);
1208 #endif
1209 #if SIZEOF_VOID_P == 4
1210 int_f += 2;
1211 #else
1212 int_f++;
1213 #endif
1214 break;
1215 default:
1216 g_error ("build_args_from_sig: not implemented yet (2): 0x%x\n", ptype);
1220 switch (sig->ret->type) {
1221 case MONO_TYPE_BOOLEAN:
1222 case MONO_TYPE_CHAR:
1223 case MONO_TYPE_I1:
1224 case MONO_TYPE_U1:
1225 case MONO_TYPE_I2:
1226 case MONO_TYPE_U2:
1227 case MONO_TYPE_I4:
1228 case MONO_TYPE_U4:
1229 case MONO_TYPE_I:
1230 case MONO_TYPE_U:
1231 case MONO_TYPE_PTR:
1232 case MONO_TYPE_SZARRAY:
1233 case MONO_TYPE_CLASS:
1234 case MONO_TYPE_OBJECT:
1235 case MONO_TYPE_STRING:
1236 case MONO_TYPE_I8:
1237 case MONO_TYPE_U8:
1238 case MONO_TYPE_VALUETYPE:
1239 case MONO_TYPE_GENERICINST:
1240 margs->retval = &(frame->retval->data.p);
1241 margs->is_float_ret = 0;
1242 break;
1243 case MONO_TYPE_R4:
1244 case MONO_TYPE_R8:
1245 margs->retval = &(frame->retval->data.p);
1246 margs->is_float_ret = 1;
1247 break;
1248 case MONO_TYPE_VOID:
1249 margs->retval = NULL;
1250 break;
1251 default:
1252 g_error ("build_args_from_sig: ret type not implemented yet: 0x%x\n", sig->ret->type);
1255 return margs;
1257 #endif
1259 static void
1260 interp_frame_arg_to_data (MonoInterpFrameHandle frame, MonoMethodSignature *sig, int index, gpointer data)
1262 InterpFrame *iframe = (InterpFrame*)frame;
1264 if (index == -1)
1265 stackval_to_data (sig->ret, iframe->retval, data, sig->pinvoke);
1266 else
1267 stackval_to_data (sig->params [index], &iframe->stack_args [index], data, sig->pinvoke);
1270 static void
1271 interp_data_to_frame_arg (MonoInterpFrameHandle frame, MonoMethodSignature *sig, int index, gpointer data)
1273 InterpFrame *iframe = (InterpFrame*)frame;
1275 if (index == -1)
1276 stackval_from_data (sig->ret, iframe->retval, data, sig->pinvoke);
1277 else if (sig->hasthis && index == 0)
1278 iframe->stack_args [index].data.p = *(gpointer*)data;
1279 else
1280 stackval_from_data (sig->params [index - sig->hasthis], &iframe->stack_args [index], data, sig->pinvoke);
1283 static gpointer
1284 interp_frame_arg_to_storage (MonoInterpFrameHandle frame, MonoMethodSignature *sig, int index)
1286 InterpFrame *iframe = (InterpFrame*)frame;
1288 if (index == -1)
1289 return stackval_to_data_addr (sig->ret, iframe->retval);
1290 else
1291 return stackval_to_data_addr (sig->params [index], &iframe->stack_args [index]);
1294 static void
1295 interp_frame_arg_set_storage (MonoInterpFrameHandle frame, MonoMethodSignature *sig, int index, gpointer storage)
1297 InterpFrame *iframe = (InterpFrame*)frame;
1298 stackval *val = (index == -1) ? iframe->retval : &iframe->stack_args [index];
1299 MonoType *type = (index == -1) ? sig->ret : sig->params [index];
1301 switch (type->type) {
1302 case MONO_TYPE_GENERICINST:
1303 if (!MONO_TYPE_IS_REFERENCE (type))
1304 val->data.vt = storage;
1305 break;
1306 case MONO_TYPE_VALUETYPE:
1307 val->data.vt = storage;
1308 break;
1309 default:
1310 g_assert_not_reached ();
1314 static MonoPIFunc
1315 get_interp_to_native_trampoline (void)
1317 static MonoPIFunc trampoline = NULL;
1319 if (!trampoline) {
1320 if (mono_ee_features.use_aot_trampolines) {
1321 trampoline = (MonoPIFunc) mono_aot_get_trampoline ("interp_to_native_trampoline");
1322 } else {
1323 MonoTrampInfo *info;
1324 trampoline = (MonoPIFunc) mono_arch_get_interp_to_native_trampoline (&info);
1325 // TODO:
1326 // mono_tramp_info_register (info, NULL);
1328 mono_memory_barrier ();
1330 return trampoline;
1333 static void
1334 interp_to_native_trampoline (gpointer addr, gpointer ccontext)
1336 get_interp_to_native_trampoline () (addr, ccontext);
1339 /* MONO_NO_OPTIMIATION is needed due to usage of INTERP_PUSH_LMF_WITH_CTX. */
1340 static MONO_NO_OPTIMIZATION MONO_NEVER_INLINE void
1341 ves_pinvoke_method (InterpFrame *frame, MonoMethodSignature *sig, MonoFuncV addr, gboolean string_ctor, ThreadContext *context)
1343 MonoLMFExt ext;
1344 gpointer args;
1346 frame->ex = NULL;
1348 g_assert (!frame->imethod);
1350 static MonoPIFunc entry_func = NULL;
1351 if (!entry_func) {
1352 #ifdef MONO_ARCH_HAS_NO_PROPER_MONOCTX
1353 ERROR_DECL (error);
1354 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);
1355 mono_error_assert_ok (error);
1356 #else
1357 entry_func = get_interp_to_native_trampoline ();
1358 #endif
1359 mono_memory_barrier ();
1362 #ifdef MONO_ARCH_HAVE_INTERP_PINVOKE_TRAMP
1363 CallContext ccontext;
1364 mono_arch_set_native_call_context_args (&ccontext, frame, sig);
1365 args = &ccontext;
1366 #else
1367 InterpMethodArguments *margs = build_args_from_sig (sig, frame);
1368 args = margs;
1369 #endif
1371 INTERP_PUSH_LMF_WITH_CTX (frame, ext, &&exit_pinvoke);
1372 entry_func ((gpointer) addr, args);
1373 interp_pop_lmf (&ext);
1375 #ifdef MONO_ARCH_HAVE_INTERP_PINVOKE_TRAMP
1376 if (!frame->ex)
1377 mono_arch_get_native_call_context_ret (&ccontext, frame, sig);
1378 #else
1379 if (!frame->ex && !MONO_TYPE_ISSTRUCT (sig->ret))
1380 stackval_from_data (sig->ret, frame->retval, (char*)&frame->retval->data.p, sig->pinvoke);
1382 g_free (margs->iargs);
1383 g_free (margs->fargs);
1384 g_free (margs);
1385 #endif
1386 goto exit_pinvoke; // prevent unused label warning in some configurations
1387 exit_pinvoke:
1388 return;
1392 * interp_init_delegate:
1394 * Initialize del->interp_method.
1396 static void
1397 interp_init_delegate (MonoDelegate *del, MonoError *error)
1399 MonoMethod *method;
1401 if (del->interp_method) {
1402 /* Delegate created by a call to ves_icall_mono_delegate_ctor_interp () */
1403 del->method = ((InterpMethod *)del->interp_method)->method;
1404 } else if (del->method) {
1405 /* Delegate created dynamically */
1406 del->interp_method = mono_interp_get_imethod (del->object.vtable->domain, del->method, error);
1407 } else {
1408 /* Created from JITted code */
1409 g_assert_not_reached ();
1412 method = ((InterpMethod*)del->interp_method)->method;
1413 if (del->target &&
1414 method &&
1415 method->flags & METHOD_ATTRIBUTE_VIRTUAL &&
1416 method->flags & METHOD_ATTRIBUTE_ABSTRACT &&
1417 mono_class_is_abstract (method->klass))
1418 del->interp_method = get_virtual_method ((InterpMethod*)del->interp_method, del->target);
1420 method = ((InterpMethod*)del->interp_method)->method;
1421 if (method && m_class_get_parent (method->klass) == mono_defaults.multicastdelegate_class) {
1422 const char *name = method->name;
1423 if (*name == 'I' && (strcmp (name, "Invoke") == 0)) {
1425 * When invoking the delegate interp_method is executed directly. If it's an
1426 * invoke make sure we replace it with the appropriate delegate invoke wrapper.
1428 * FIXME We should do this later, when we also know the delegate on which the
1429 * target method is called.
1431 del->interp_method = mono_interp_get_imethod (del->object.vtable->domain, mono_marshal_get_delegate_invoke (method, NULL), error);
1432 mono_error_assert_ok (error);
1436 if (!((InterpMethod *) del->interp_method)->transformed && method_is_dynamic (method)) {
1437 /* Return any errors from method compilation */
1438 mono_interp_transform_method ((InterpMethod *) del->interp_method, get_context (), error);
1439 return_if_nok (error);
1443 static void
1444 interp_delegate_ctor (MonoObjectHandle this_obj, MonoObjectHandle target, gpointer addr, MonoError *error)
1447 * addr is the result of an LDFTN opcode, i.e. an InterpMethod
1449 InterpMethod *imethod = (InterpMethod*)addr;
1451 if (!(imethod->method->flags & METHOD_ATTRIBUTE_STATIC)) {
1452 MonoMethod *invoke = mono_get_delegate_invoke_internal (mono_handle_class (this_obj));
1453 /* virtual invoke delegates must not have null check */
1454 if (mono_method_signature_internal (imethod->method)->param_count == mono_method_signature_internal (invoke)->param_count
1455 && MONO_HANDLE_IS_NULL (target)) {
1456 mono_error_set_argument (error, "this", "Delegate to an instance method cannot have null 'this'");
1457 return;
1461 g_assert (imethod->method);
1462 gpointer entry = mini_get_interp_callbacks ()->create_method_pointer (imethod->method, FALSE, error);
1463 return_if_nok (error);
1465 MONO_HANDLE_SETVAL (MONO_HANDLE_CAST (MonoDelegate, this_obj), interp_method, gpointer, imethod);
1467 mono_delegate_ctor (this_obj, target, entry, error);
1471 * From the spec:
1472 * runtime specifies that the implementation of the method is automatically
1473 * provided by the runtime and is primarily used for the methods of delegates.
1475 static MONO_NEVER_INLINE void
1476 ves_imethod (InterpFrame *frame, MonoMethod *method, MonoMethodSignature *sig, stackval *sp, stackval *retval)
1478 const char *name = method->name;
1479 mono_class_init_internal (method->klass);
1481 if (method->klass == mono_defaults.array_class) {
1482 if (!strcmp (name, "UnsafeMov")) {
1483 /* TODO: layout checks */
1484 stackval_from_data (sig->ret, retval, (char*) sp, FALSE);
1485 return;
1487 if (!strcmp (name, "UnsafeLoad")) {
1488 ves_array_get (frame, sp, retval, sig, FALSE);
1489 return;
1491 } else if (mini_class_is_system_array (method->klass)) {
1492 MonoObject *obj = (MonoObject*) sp->data.p;
1493 if (!obj) {
1494 frame->ex = mono_get_exception_null_reference ();
1495 return;
1497 if (*name == 'S' && (strcmp (name, "Set") == 0)) {
1498 ves_array_set (frame, sp, sig);
1499 return;
1501 if (*name == 'G' && (strcmp (name, "Get") == 0)) {
1502 ves_array_get (frame, sp, retval, sig, TRUE);
1503 return;
1507 g_error ("Don't know how to exec runtime method %s.%s::%s",
1508 m_class_get_name_space (method->klass), m_class_get_name (method->klass),
1509 method->name);
1512 #if DEBUG_INTERP
1513 static char*
1514 dump_stack (stackval *stack, stackval *sp)
1516 stackval *s = stack;
1517 GString *str = g_string_new ("");
1519 if (sp == stack)
1520 return g_string_free (str, FALSE);
1522 while (s < sp) {
1523 g_string_append_printf (str, "[%p (%lld)] ", s->data.l, s->data.l);
1524 ++s;
1526 return g_string_free (str, FALSE);
1529 static void
1530 dump_stackval (GString *str, stackval *s, MonoType *type)
1532 switch (type->type) {
1533 case MONO_TYPE_I1:
1534 case MONO_TYPE_U1:
1535 case MONO_TYPE_I2:
1536 case MONO_TYPE_U2:
1537 case MONO_TYPE_I4:
1538 case MONO_TYPE_U4:
1539 case MONO_TYPE_CHAR:
1540 case MONO_TYPE_BOOLEAN:
1541 g_string_append_printf (str, "[%d] ", s->data.i);
1542 break;
1543 case MONO_TYPE_STRING:
1544 case MONO_TYPE_SZARRAY:
1545 case MONO_TYPE_CLASS:
1546 case MONO_TYPE_OBJECT:
1547 case MONO_TYPE_ARRAY:
1548 case MONO_TYPE_PTR:
1549 case MONO_TYPE_I:
1550 case MONO_TYPE_U:
1551 g_string_append_printf (str, "[%p] ", s->data.p);
1552 break;
1553 case MONO_TYPE_VALUETYPE:
1554 if (m_class_is_enumtype (type->data.klass))
1555 g_string_append_printf (str, "[%d] ", s->data.i);
1556 else
1557 g_string_append_printf (str, "[vt:%p] ", s->data.p);
1558 break;
1559 case MONO_TYPE_R4:
1560 g_string_append_printf (str, "[%g] ", s->data.f_r4);
1561 break;
1562 case MONO_TYPE_R8:
1563 g_string_append_printf (str, "[%g] ", s->data.f);
1564 break;
1565 case MONO_TYPE_I8:
1566 case MONO_TYPE_U8:
1567 default: {
1568 GString *res = g_string_new ("");
1569 mono_type_get_desc (res, type, TRUE);
1570 g_string_append_printf (str, "[{%s} %lld/0x%0llx] ", res->str, s->data.l, s->data.l);
1571 g_string_free (res, TRUE);
1572 break;
1577 static char*
1578 dump_retval (InterpFrame *inv)
1580 GString *str = g_string_new ("");
1581 MonoType *ret = mono_method_signature_internal (inv->imethod->method)->ret;
1583 if (ret->type != MONO_TYPE_VOID)
1584 dump_stackval (str, inv->retval, ret);
1586 return g_string_free (str, FALSE);
1589 static char*
1590 dump_args (InterpFrame *inv)
1592 GString *str = g_string_new ("");
1593 int i;
1594 MonoMethodSignature *signature = mono_method_signature_internal (inv->imethod->method);
1596 if (signature->param_count == 0 && !signature->hasthis)
1597 return g_string_free (str, FALSE);
1599 if (signature->hasthis) {
1600 MonoMethod *method = inv->imethod->method;
1601 dump_stackval (str, inv->stack_args, m_class_get_byval_arg (method->klass));
1604 for (i = 0; i < signature->param_count; ++i)
1605 dump_stackval (str, inv->stack_args + (!!signature->hasthis) + i, signature->params [i]);
1607 return g_string_free (str, FALSE);
1609 #endif
1611 #define CHECK_ADD_OVERFLOW(a,b) \
1612 (gint32)(b) >= 0 ? (gint32)(G_MAXINT32) - (gint32)(b) < (gint32)(a) ? -1 : 0 \
1613 : (gint32)(G_MININT32) - (gint32)(b) > (gint32)(a) ? +1 : 0
1615 #define CHECK_SUB_OVERFLOW(a,b) \
1616 (gint32)(b) < 0 ? (gint32)(G_MAXINT32) + (gint32)(b) < (gint32)(a) ? -1 : 0 \
1617 : (gint32)(G_MININT32) + (gint32)(b) > (gint32)(a) ? +1 : 0
1619 #define CHECK_ADD_OVERFLOW_UN(a,b) \
1620 (guint32)(G_MAXUINT32) - (guint32)(b) < (guint32)(a) ? -1 : 0
1622 #define CHECK_SUB_OVERFLOW_UN(a,b) \
1623 (guint32)(a) < (guint32)(b) ? -1 : 0
1625 #define CHECK_ADD_OVERFLOW64(a,b) \
1626 (gint64)(b) >= 0 ? (gint64)(G_MAXINT64) - (gint64)(b) < (gint64)(a) ? -1 : 0 \
1627 : (gint64)(G_MININT64) - (gint64)(b) > (gint64)(a) ? +1 : 0
1629 #define CHECK_SUB_OVERFLOW64(a,b) \
1630 (gint64)(b) < 0 ? (gint64)(G_MAXINT64) + (gint64)(b) < (gint64)(a) ? -1 : 0 \
1631 : (gint64)(G_MININT64) + (gint64)(b) > (gint64)(a) ? +1 : 0
1633 #define CHECK_ADD_OVERFLOW64_UN(a,b) \
1634 (guint64)(G_MAXUINT64) - (guint64)(b) < (guint64)(a) ? -1 : 0
1636 #define CHECK_SUB_OVERFLOW64_UN(a,b) \
1637 (guint64)(a) < (guint64)(b) ? -1 : 0
1639 #if SIZEOF_VOID_P == 4
1640 #define CHECK_ADD_OVERFLOW_NAT(a,b) CHECK_ADD_OVERFLOW(a,b)
1641 #define CHECK_ADD_OVERFLOW_NAT_UN(a,b) CHECK_ADD_OVERFLOW_UN(a,b)
1642 #else
1643 #define CHECK_ADD_OVERFLOW_NAT(a,b) CHECK_ADD_OVERFLOW64(a,b)
1644 #define CHECK_ADD_OVERFLOW_NAT_UN(a,b) CHECK_ADD_OVERFLOW64_UN(a,b)
1645 #endif
1647 /* Resolves to TRUE if the operands would overflow */
1648 #define CHECK_MUL_OVERFLOW(a,b) \
1649 ((gint32)(a) == 0) || ((gint32)(b) == 0) ? 0 : \
1650 (((gint32)(a) > 0) && ((gint32)(b) == -1)) ? FALSE : \
1651 (((gint32)(a) < 0) && ((gint32)(b) == -1)) ? (a == G_MININT32) : \
1652 (((gint32)(a) > 0) && ((gint32)(b) > 0)) ? (gint32)(a) > ((G_MAXINT32) / (gint32)(b)) : \
1653 (((gint32)(a) > 0) && ((gint32)(b) < 0)) ? (gint32)(a) > ((G_MININT32) / (gint32)(b)) : \
1654 (((gint32)(a) < 0) && ((gint32)(b) > 0)) ? (gint32)(a) < ((G_MININT32) / (gint32)(b)) : \
1655 (gint32)(a) < ((G_MAXINT32) / (gint32)(b))
1657 #define CHECK_MUL_OVERFLOW_UN(a,b) \
1658 ((guint32)(a) == 0) || ((guint32)(b) == 0) ? 0 : \
1659 (guint32)(b) > ((G_MAXUINT32) / (guint32)(a))
1661 #define CHECK_MUL_OVERFLOW64(a,b) \
1662 ((gint64)(a) == 0) || ((gint64)(b) == 0) ? 0 : \
1663 (((gint64)(a) > 0) && ((gint64)(b) == -1)) ? FALSE : \
1664 (((gint64)(a) < 0) && ((gint64)(b) == -1)) ? (a == G_MININT64) : \
1665 (((gint64)(a) > 0) && ((gint64)(b) > 0)) ? (gint64)(a) > ((G_MAXINT64) / (gint64)(b)) : \
1666 (((gint64)(a) > 0) && ((gint64)(b) < 0)) ? (gint64)(a) > ((G_MININT64) / (gint64)(b)) : \
1667 (((gint64)(a) < 0) && ((gint64)(b) > 0)) ? (gint64)(a) < ((G_MININT64) / (gint64)(b)) : \
1668 (gint64)(a) < ((G_MAXINT64) / (gint64)(b))
1670 #define CHECK_MUL_OVERFLOW64_UN(a,b) \
1671 ((guint64)(a) == 0) || ((guint64)(b) == 0) ? 0 : \
1672 (guint64)(b) > ((G_MAXUINT64) / (guint64)(a))
1674 #if SIZEOF_VOID_P == 4
1675 #define CHECK_MUL_OVERFLOW_NAT(a,b) CHECK_MUL_OVERFLOW(a,b)
1676 #define CHECK_MUL_OVERFLOW_NAT_UN(a,b) CHECK_MUL_OVERFLOW_UN(a,b)
1677 #else
1678 #define CHECK_MUL_OVERFLOW_NAT(a,b) CHECK_MUL_OVERFLOW64(a,b)
1679 #define CHECK_MUL_OVERFLOW_NAT_UN(a,b) CHECK_MUL_OVERFLOW64_UN(a,b)
1680 #endif
1682 static MonoObject*
1683 interp_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError *error)
1685 InterpFrame frame;
1686 ThreadContext *context = get_context ();
1687 MonoMethodSignature *sig = mono_method_signature_internal (method);
1688 MonoClass *klass = mono_class_from_mono_type_internal (sig->ret);
1689 stackval result;
1690 MonoMethod *target_method = method;
1692 error_init (error);
1693 if (exc)
1694 *exc = NULL;
1696 frame.ex = NULL;
1698 MonoDomain *domain = mono_domain_get ();
1700 if (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
1701 target_method = mono_marshal_get_native_wrapper (target_method, FALSE, FALSE);
1702 MonoMethod *invoke_wrapper = mono_marshal_get_runtime_invoke_full (target_method, FALSE, TRUE);
1704 //* <code>MonoObject *runtime_invoke (MonoObject *this_obj, void **params, MonoObject **exc, void* method)</code>
1706 result.data.vt = alloca (mono_class_instance_size (klass));
1707 stackval args [4];
1709 if (sig->hasthis)
1710 args [0].data.p = obj;
1711 else
1712 args [0].data.p = NULL;
1713 args [1].data.p = params;
1714 args [2].data.p = exc;
1715 args [3].data.p = target_method;
1717 INIT_FRAME (&frame, NULL, args, &result, domain, invoke_wrapper, error);
1719 if (exc)
1720 frame.invoke_trap = 1;
1722 interp_exec_method (&frame, context);
1724 if (frame.ex) {
1725 if (exc) {
1726 *exc = (MonoObject*) frame.ex;
1727 return NULL;
1729 mono_error_set_exception_instance (error, frame.ex);
1730 return NULL;
1732 return (MonoObject*)result.data.p;
1735 typedef struct {
1736 InterpMethod *rmethod;
1737 gpointer this_arg;
1738 gpointer res;
1739 gpointer args [16];
1740 gpointer *many_args;
1741 } InterpEntryData;
1743 /* Main function for entering the interpreter from compiled code */
1744 static void
1745 interp_entry (InterpEntryData *data)
1747 InterpFrame frame;
1748 InterpMethod *rmethod;
1749 ThreadContext *context;
1750 stackval result;
1751 stackval *args;
1752 MonoMethod *method;
1753 MonoMethodSignature *sig;
1754 MonoType *type;
1755 gpointer orig_domain, attach_cookie;
1756 int i;
1758 if ((gsize)data->rmethod & 1) {
1759 /* Unbox */
1760 data->this_arg = mono_object_unbox_internal ((MonoObject*)data->this_arg);
1761 data->rmethod = (InterpMethod*)(gpointer)((gsize)data->rmethod & ~1);
1763 rmethod = data->rmethod;
1765 if (rmethod->needs_thread_attach)
1766 orig_domain = mono_threads_attach_coop (mono_domain_get (), &attach_cookie);
1768 context = get_context ();
1770 method = rmethod->method;
1771 sig = mono_method_signature_internal (method);
1773 // FIXME: Optimize this
1775 //printf ("%s\n", mono_method_full_name (method, 1));
1777 frame.ex = NULL;
1779 args = g_newa (stackval, sig->param_count + (sig->hasthis ? 1 : 0));
1780 if (sig->hasthis)
1781 args [0].data.p = data->this_arg;
1783 gpointer *params;
1784 if (data->many_args)
1785 params = data->many_args;
1786 else
1787 params = data->args;
1788 for (i = 0; i < sig->param_count; ++i) {
1789 int a_index = i + (sig->hasthis ? 1 : 0);
1790 if (sig->params [i]->byref) {
1791 args [a_index].data.p = params [i];
1792 continue;
1794 type = rmethod->param_types [i];
1795 switch (type->type) {
1796 case MONO_TYPE_VALUETYPE:
1797 args [a_index].data.p = params [i];
1798 break;
1799 case MONO_TYPE_GENERICINST:
1800 if (MONO_TYPE_IS_REFERENCE (type))
1801 args [a_index].data.p = *(gpointer*)params [i];
1802 else
1803 args [a_index].data.vt = params [i];
1804 break;
1805 default:
1806 stackval_from_data (type, &args [a_index], params [i], FALSE);
1807 break;
1811 memset (&result, 0, sizeof (result));
1812 init_frame (&frame, NULL, data->rmethod, args, &result);
1814 type = rmethod->rtype;
1815 switch (type->type) {
1816 case MONO_TYPE_GENERICINST:
1817 if (!MONO_TYPE_IS_REFERENCE (type))
1818 frame.retval->data.vt = data->res;
1819 break;
1820 case MONO_TYPE_VALUETYPE:
1821 frame.retval->data.vt = data->res;
1822 break;
1823 default:
1824 break;
1827 interp_exec_method (&frame, context);
1829 if (rmethod->needs_thread_attach)
1830 mono_threads_detach_coop (orig_domain, &attach_cookie);
1832 if (mono_llvm_only) {
1833 if (frame.ex)
1834 mono_llvm_reraise_exception (frame.ex);
1835 } else {
1836 g_assert (frame.ex == NULL);
1839 type = rmethod->rtype;
1840 switch (type->type) {
1841 case MONO_TYPE_VOID:
1842 break;
1843 case MONO_TYPE_OBJECT:
1844 /* No need for a write barrier */
1845 *(MonoObject**)data->res = (MonoObject*)frame.retval->data.p;
1846 break;
1847 case MONO_TYPE_GENERICINST:
1848 if (MONO_TYPE_IS_REFERENCE (type)) {
1849 *(MonoObject**)data->res = (MonoObject*)frame.retval->data.p;
1850 } else {
1851 /* Already set before the call */
1853 break;
1854 case MONO_TYPE_VALUETYPE:
1855 /* Already set before the call */
1856 break;
1857 default:
1858 stackval_to_data (type, frame.retval, data->res, FALSE);
1859 break;
1863 static stackval *
1864 do_icall (InterpFrame *frame, MonoMethodSignature *sig, int op, stackval *sp, gpointer ptr)
1866 switch (op) {
1867 case MINT_ICALL_V_V: {
1868 typedef void (*T)(void);
1869 T func = (T)ptr;
1870 func ();
1871 break;
1873 case MINT_ICALL_V_P: {
1874 typedef gpointer (*T)(void);
1875 T func = (T)ptr;
1876 sp++;
1877 sp [-1].data.p = func ();
1878 break;
1880 case MINT_ICALL_P_V: {
1881 typedef void (*T)(gpointer);
1882 T func = (T)ptr;
1883 func (sp [-1].data.p);
1884 sp --;
1885 break;
1887 case MINT_ICALL_P_P: {
1888 typedef gpointer (*T)(gpointer);
1889 T func = (T)ptr;
1890 sp [-1].data.p = func (sp [-1].data.p);
1891 break;
1893 case MINT_ICALL_PP_V: {
1894 typedef void (*T)(gpointer,gpointer);
1895 T func = (T)ptr;
1896 sp -= 2;
1897 func (sp [0].data.p, sp [1].data.p);
1898 break;
1900 case MINT_ICALL_PP_P: {
1901 typedef gpointer (*T)(gpointer,gpointer);
1902 T func = (T)ptr;
1903 --sp;
1904 sp [-1].data.p = func (sp [-1].data.p, sp [0].data.p);
1905 break;
1907 case MINT_ICALL_PPP_V: {
1908 typedef void (*T)(gpointer,gpointer,gpointer);
1909 T func = (T)ptr;
1910 sp -= 3;
1911 func (sp [0].data.p, sp [1].data.p, sp [2].data.p);
1912 break;
1914 case MINT_ICALL_PPP_P: {
1915 typedef gpointer (*T)(gpointer,gpointer,gpointer);
1916 T func = (T)ptr;
1917 sp -= 2;
1918 sp [-1].data.p = func (sp [-1].data.p, sp [0].data.p, sp [1].data.p);
1919 break;
1921 case MINT_ICALL_PPPP_V: {
1922 typedef void (*T)(gpointer,gpointer,gpointer,gpointer);
1923 T func = (T)ptr;
1924 sp -= 4;
1925 func (sp [0].data.p, sp [1].data.p, sp [2].data.p, sp [3].data.p);
1926 break;
1928 case MINT_ICALL_PPPP_P: {
1929 typedef gpointer (*T)(gpointer,gpointer,gpointer,gpointer);
1930 T func = (T)ptr;
1931 sp -= 3;
1932 sp [-1].data.p = func (sp [-1].data.p, sp [0].data.p, sp [1].data.p, sp [2].data.p);
1933 break;
1935 case MINT_ICALL_PPPPP_V: {
1936 typedef void (*T)(gpointer,gpointer,gpointer,gpointer,gpointer);
1937 T func = (T)ptr;
1938 sp -= 5;
1939 func (sp [0].data.p, sp [1].data.p, sp [2].data.p, sp [3].data.p, sp [4].data.p);
1940 break;
1942 case MINT_ICALL_PPPPP_P: {
1943 typedef gpointer (*T)(gpointer,gpointer,gpointer,gpointer,gpointer);
1944 T func = (T)ptr;
1945 sp -= 4;
1946 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);
1947 break;
1949 case MINT_ICALL_PPPPPP_V: {
1950 typedef void (*T)(gpointer,gpointer,gpointer,gpointer,gpointer,gpointer);
1951 T func = (T)ptr;
1952 sp -= 6;
1953 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);
1954 break;
1956 case MINT_ICALL_PPPPPP_P: {
1957 typedef gpointer (*T)(gpointer,gpointer,gpointer,gpointer,gpointer,gpointer);
1958 T func = (T)ptr;
1959 sp -= 5;
1960 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);
1961 break;
1963 default:
1964 g_assert_not_reached ();
1967 /* convert the native representation to the stackval representation */
1968 if (sig)
1969 stackval_from_data (sig->ret, &sp [-1], (char*) &sp [-1].data.p, sig->pinvoke);
1971 return sp;
1974 /* MONO_NO_OPTIMIATION is needed due to usage of INTERP_PUSH_LMF_WITH_CTX. */
1975 static MONO_NO_OPTIMIZATION MONO_NEVER_INLINE stackval *
1976 do_icall_wrapper (InterpFrame *frame, MonoMethodSignature *sig, int op, stackval *sp, gpointer ptr)
1978 MonoLMFExt ext;
1979 INTERP_PUSH_LMF_WITH_CTX (frame, ext, &&exit_icall);
1981 sp = do_icall (frame, sig, op, sp, ptr);
1983 interp_pop_lmf (&ext);
1985 goto exit_icall; // prevent unused label warning in some configurations
1986 exit_icall:
1987 return sp;
1990 typedef struct {
1991 int pindex;
1992 gpointer jit_wrapper;
1993 gpointer *args;
1994 MonoFtnDesc *ftndesc;
1995 } JitCallCbData;
1997 static void
1998 jit_call_cb (gpointer arg)
2000 JitCallCbData *cb_data = (JitCallCbData*)arg;
2001 gpointer jit_wrapper = cb_data->jit_wrapper;
2002 int pindex = cb_data->pindex;
2003 gpointer *args = cb_data->args;
2004 MonoFtnDesc ftndesc = *cb_data->ftndesc;
2006 switch (pindex) {
2007 case 0: {
2008 typedef void (*T)(gpointer);
2009 T func = (T)jit_wrapper;
2011 func (&ftndesc);
2012 break;
2014 case 1: {
2015 typedef void (*T)(gpointer, gpointer);
2016 T func = (T)jit_wrapper;
2018 func (args [0], &ftndesc);
2019 break;
2021 case 2: {
2022 typedef void (*T)(gpointer, gpointer, gpointer);
2023 T func = (T)jit_wrapper;
2025 func (args [0], args [1], &ftndesc);
2026 break;
2028 case 3: {
2029 typedef void (*T)(gpointer, gpointer, gpointer, gpointer);
2030 T func = (T)jit_wrapper;
2032 func (args [0], args [1], args [2], &ftndesc);
2033 break;
2035 case 4: {
2036 typedef void (*T)(gpointer, gpointer, gpointer, gpointer, gpointer);
2037 T func = (T)jit_wrapper;
2039 func (args [0], args [1], args [2], args [3], &ftndesc);
2040 break;
2042 case 5: {
2043 typedef void (*T)(gpointer, gpointer, gpointer, gpointer, gpointer, gpointer);
2044 T func = (T)jit_wrapper;
2046 func (args [0], args [1], args [2], args [3], args [4], &ftndesc);
2047 break;
2049 case 6: {
2050 typedef void (*T)(gpointer, gpointer, gpointer, gpointer, gpointer, gpointer, gpointer);
2051 T func = (T)jit_wrapper;
2053 func (args [0], args [1], args [2], args [3], args [4], args [5], &ftndesc);
2054 break;
2056 case 7: {
2057 typedef void (*T)(gpointer, gpointer, gpointer, gpointer, gpointer, gpointer, gpointer, gpointer);
2058 T func = (T)jit_wrapper;
2060 func (args [0], args [1], args [2], args [3], args [4], args [5], args [6], &ftndesc);
2061 break;
2063 case 8: {
2064 typedef void (*T)(gpointer, gpointer, gpointer, gpointer, gpointer, gpointer, gpointer, gpointer, gpointer);
2065 T func = (T)jit_wrapper;
2067 func (args [0], args [1], args [2], args [3], args [4], args [5], args [6], args [7], &ftndesc);
2068 break;
2070 default:
2071 g_assert_not_reached ();
2072 break;
2076 static MONO_NEVER_INLINE stackval *
2077 do_jit_call (stackval *sp, unsigned char *vt_sp, ThreadContext *context, InterpFrame *frame, InterpMethod *rmethod, MonoError *error)
2079 MonoMethodSignature *sig;
2080 MonoFtnDesc ftndesc;
2081 guint8 res_buf [256];
2082 MonoType *type;
2083 MonoLMFExt ext;
2085 //printf ("jit_call: %s\n", mono_method_full_name (rmethod->method, 1));
2088 * Call JITted code through a gsharedvt_out wrapper. These wrappers receive every argument
2089 * by ref and return a return value using an explicit return value argument.
2091 if (!rmethod->jit_wrapper) {
2092 MonoMethod *method = rmethod->method;
2094 sig = mono_method_signature_internal (method);
2095 g_assert (sig);
2097 MonoMethod *wrapper = mini_get_gsharedvt_out_sig_wrapper (sig);
2098 //printf ("J: %s %s\n", mono_method_full_name (method, 1), mono_method_full_name (wrapper, 1));
2100 gpointer jit_wrapper = mono_jit_compile_method_jit_only (wrapper, error);
2101 mono_error_assert_ok (error);
2103 gpointer addr = mono_jit_compile_method_jit_only (method, error);
2104 return_val_if_nok (error, NULL);
2105 g_assert (addr);
2107 rmethod->jit_addr = addr;
2108 rmethod->jit_sig = sig;
2109 mono_memory_barrier ();
2110 rmethod->jit_wrapper = jit_wrapper;
2112 } else {
2113 sig = rmethod->jit_sig;
2116 sp -= sig->param_count;
2117 if (sig->hasthis)
2118 --sp;
2120 ftndesc.addr = rmethod->jit_addr;
2121 ftndesc.arg = NULL;
2123 // FIXME: Optimize this
2125 gpointer args [32];
2126 int pindex = 0;
2127 int stack_index = 0;
2128 if (rmethod->hasthis) {
2129 args [pindex ++] = sp [0].data.p;
2130 stack_index ++;
2132 type = rmethod->rtype;
2133 if (type->type != MONO_TYPE_VOID) {
2134 if (MONO_TYPE_ISSTRUCT (type))
2135 args [pindex ++] = vt_sp;
2136 else
2137 args [pindex ++] = res_buf;
2139 for (int i = 0; i < rmethod->param_count; ++i) {
2140 MonoType *t = rmethod->param_types [i];
2141 stackval *sval = &sp [stack_index + i];
2142 if (sig->params [i]->byref) {
2143 args [pindex ++] = sval->data.p;
2144 } else if (MONO_TYPE_ISSTRUCT (t)) {
2145 args [pindex ++] = sval->data.p;
2146 } else if (MONO_TYPE_IS_REFERENCE (t)) {
2147 args [pindex ++] = &sval->data.p;
2148 } else {
2149 switch (t->type) {
2150 case MONO_TYPE_I1:
2151 case MONO_TYPE_U1:
2152 case MONO_TYPE_I2:
2153 case MONO_TYPE_U2:
2154 case MONO_TYPE_I4:
2155 case MONO_TYPE_U4:
2156 case MONO_TYPE_VALUETYPE:
2157 args [pindex ++] = &sval->data.i;
2158 break;
2159 case MONO_TYPE_PTR:
2160 case MONO_TYPE_FNPTR:
2161 case MONO_TYPE_I:
2162 case MONO_TYPE_U:
2163 case MONO_TYPE_OBJECT:
2164 args [pindex ++] = &sval->data.p;
2165 break;
2166 case MONO_TYPE_I8:
2167 case MONO_TYPE_U8:
2168 args [pindex ++] = &sval->data.l;
2169 break;
2170 case MONO_TYPE_R4:
2171 args [pindex ++] = &sval->data.f_r4;
2172 break;
2173 case MONO_TYPE_R8:
2174 args [pindex ++] = &sval->data.f;
2175 break;
2176 default:
2177 printf ("%s\n", mono_type_full_name (t));
2178 g_assert_not_reached ();
2183 interp_push_lmf (&ext, frame);
2185 JitCallCbData cb_data;
2186 memset (&cb_data, 0, sizeof (cb_data));
2187 cb_data.jit_wrapper = rmethod->jit_wrapper;
2188 cb_data.pindex = pindex;
2189 cb_data.args = args;
2190 cb_data.ftndesc = &ftndesc;
2192 if (mono_aot_mode == MONO_AOT_MODE_LLVMONLY_INTERP) {
2193 /* Catch the exception thrown by the native code using a try-catch */
2194 gboolean thrown = FALSE;
2195 mono_llvm_cpp_catch_exception (jit_call_cb, &cb_data, &thrown);
2196 interp_pop_lmf (&ext);
2197 if (thrown) {
2198 MonoObject *obj = mono_llvm_load_exception ();
2199 g_assert (obj);
2200 mono_error_set_exception_instance (error, (MonoException*)obj);
2201 return sp;
2203 } else {
2204 jit_call_cb (&cb_data);
2205 interp_pop_lmf (&ext);
2208 MonoType *rtype = rmethod->rtype;
2209 switch (rtype->type) {
2210 case MONO_TYPE_VOID:
2211 case MONO_TYPE_OBJECT:
2212 case MONO_TYPE_STRING:
2213 case MONO_TYPE_CLASS:
2214 case MONO_TYPE_ARRAY:
2215 case MONO_TYPE_SZARRAY:
2216 case MONO_TYPE_I:
2217 case MONO_TYPE_U:
2218 case MONO_TYPE_PTR:
2219 sp->data.p = *(gpointer*)res_buf;
2220 break;
2221 case MONO_TYPE_I1:
2222 sp->data.i = *(gint8*)res_buf;
2223 break;
2224 case MONO_TYPE_U1:
2225 sp->data.i = *(guint8*)res_buf;
2226 break;
2227 case MONO_TYPE_I2:
2228 sp->data.i = *(gint16*)res_buf;
2229 break;
2230 case MONO_TYPE_U2:
2231 sp->data.i = *(guint16*)res_buf;
2232 break;
2233 case MONO_TYPE_I4:
2234 sp->data.i = *(gint32*)res_buf;
2235 break;
2236 case MONO_TYPE_U4:
2237 sp->data.i = *(guint32*)res_buf;
2238 break;
2239 case MONO_TYPE_I8:
2240 sp->data.l = *(gint64*)res_buf;
2241 break;
2242 case MONO_TYPE_U8:
2243 sp->data.l = *(guint64*)res_buf;
2244 break;
2245 case MONO_TYPE_R4:
2246 sp->data.f_r4 = *(float*)res_buf;
2247 break;
2248 case MONO_TYPE_R8:
2249 sp->data.f = *(double*)res_buf;
2250 break;
2251 case MONO_TYPE_TYPEDBYREF:
2252 case MONO_TYPE_VALUETYPE:
2253 /* The result was written to vt_sp */
2254 sp->data.p = vt_sp;
2255 break;
2256 case MONO_TYPE_GENERICINST:
2257 if (MONO_TYPE_IS_REFERENCE (rtype)) {
2258 sp->data.p = *(gpointer*)res_buf;
2259 } else {
2260 /* The result was written to vt_sp */
2261 sp->data.p = vt_sp;
2263 break;
2264 default:
2265 g_print ("%s\n", mono_type_full_name (rtype));
2266 g_assert_not_reached ();
2267 break;
2270 return sp;
2273 static MONO_NEVER_INLINE void
2274 do_debugger_tramp (void (*tramp) (void), InterpFrame *frame)
2276 MonoLMFExt ext;
2277 interp_push_lmf (&ext, frame);
2278 tramp ();
2279 interp_pop_lmf (&ext);
2282 static MONO_NEVER_INLINE void
2283 do_transform_method (InterpFrame *frame, ThreadContext *context)
2285 MonoLMFExt ext;
2286 /* Don't push lmf if we have no interp data */
2287 gboolean push_lmf = frame->parent != NULL;
2288 ERROR_DECL (error);
2290 /* Use the parent frame as the current frame is not complete yet */
2291 if (push_lmf)
2292 interp_push_lmf (&ext, frame->parent);
2294 mono_interp_transform_method (frame->imethod, context, error);
2295 frame->ex = mono_error_convert_to_exception (error);
2297 if (push_lmf)
2298 interp_pop_lmf (&ext);
2301 static void
2302 copy_varargs_vtstack (MonoMethodSignature *csig, stackval *sp, unsigned char **vt_sp)
2304 char *vt = *(char**)vt_sp;
2305 stackval *first_arg = sp - csig->param_count;
2308 * We need to have the varargs linearly on the stack so the ArgIterator
2309 * can iterate over them. We pass the signature first and then copy them
2310 * one by one on the vtstack.
2312 *(gpointer*)vt = csig;
2313 vt += sizeof (gpointer);
2315 for (int i = csig->sentinelpos; i < csig->param_count; i++) {
2316 int align, arg_size;
2317 arg_size = mono_type_stack_size (csig->params [i], &align);
2318 vt = (char*)ALIGN_PTR_TO (vt, align);
2320 stackval_to_data (csig->params [i], &first_arg [i], vt, FALSE);
2321 vt += arg_size;
2324 vt = (char*)ALIGN_PTR_TO (vt, MINT_VT_ALIGNMENT);
2326 *(char**)vt_sp = vt;
2330 * These functions are the entry points into the interpreter from compiled code.
2331 * They are called by the interp_in wrappers. They have the following signature:
2332 * void (<optional this_arg>, <optional retval pointer>, <arg1>, ..., <argn>, <method ptr>)
2333 * They pack up their arguments into an InterpEntryData structure and call interp_entry ().
2334 * It would be possible for the wrappers to pack up the arguments etc, but that would make them bigger, and there are
2335 * more wrappers then these functions.
2336 * this/static * ret/void * 16 arguments -> 64 functions.
2339 #define MAX_INTERP_ENTRY_ARGS 8
2341 #define INTERP_ENTRY_BASE(_method, _this_arg, _res) \
2342 InterpEntryData data; \
2343 (data).rmethod = (_method); \
2344 (data).res = (_res); \
2345 (data).this_arg = (_this_arg); \
2346 (data).many_args = NULL;
2348 #define INTERP_ENTRY0(_this_arg, _res, _method) { \
2349 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2350 interp_entry (&data); \
2352 #define INTERP_ENTRY1(_this_arg, _res, _method) { \
2353 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2354 (data).args [0] = arg1; \
2355 interp_entry (&data); \
2357 #define INTERP_ENTRY2(_this_arg, _res, _method) { \
2358 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2359 (data).args [0] = arg1; \
2360 (data).args [1] = arg2; \
2361 interp_entry (&data); \
2363 #define INTERP_ENTRY3(_this_arg, _res, _method) { \
2364 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2365 (data).args [0] = arg1; \
2366 (data).args [1] = arg2; \
2367 (data).args [2] = arg3; \
2368 interp_entry (&data); \
2370 #define INTERP_ENTRY4(_this_arg, _res, _method) { \
2371 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2372 (data).args [0] = arg1; \
2373 (data).args [1] = arg2; \
2374 (data).args [2] = arg3; \
2375 (data).args [3] = arg4; \
2376 interp_entry (&data); \
2378 #define INTERP_ENTRY5(_this_arg, _res, _method) { \
2379 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2380 (data).args [0] = arg1; \
2381 (data).args [1] = arg2; \
2382 (data).args [2] = arg3; \
2383 (data).args [3] = arg4; \
2384 (data).args [4] = arg5; \
2385 interp_entry (&data); \
2387 #define INTERP_ENTRY6(_this_arg, _res, _method) { \
2388 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2389 (data).args [0] = arg1; \
2390 (data).args [1] = arg2; \
2391 (data).args [2] = arg3; \
2392 (data).args [3] = arg4; \
2393 (data).args [4] = arg5; \
2394 (data).args [5] = arg6; \
2395 interp_entry (&data); \
2397 #define INTERP_ENTRY7(_this_arg, _res, _method) { \
2398 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2399 (data).args [0] = arg1; \
2400 (data).args [1] = arg2; \
2401 (data).args [2] = arg3; \
2402 (data).args [3] = arg4; \
2403 (data).args [4] = arg5; \
2404 (data).args [5] = arg6; \
2405 (data).args [6] = arg7; \
2406 interp_entry (&data); \
2408 #define INTERP_ENTRY8(_this_arg, _res, _method) { \
2409 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2410 (data).args [0] = arg1; \
2411 (data).args [1] = arg2; \
2412 (data).args [2] = arg3; \
2413 (data).args [3] = arg4; \
2414 (data).args [4] = arg5; \
2415 (data).args [5] = arg6; \
2416 (data).args [6] = arg7; \
2417 (data).args [7] = arg8; \
2418 interp_entry (&data); \
2421 #define ARGLIST0 InterpMethod *rmethod
2422 #define ARGLIST1 gpointer arg1, InterpMethod *rmethod
2423 #define ARGLIST2 gpointer arg1, gpointer arg2, InterpMethod *rmethod
2424 #define ARGLIST3 gpointer arg1, gpointer arg2, gpointer arg3, InterpMethod *rmethod
2425 #define ARGLIST4 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, InterpMethod *rmethod
2426 #define ARGLIST5 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, gpointer arg5, InterpMethod *rmethod
2427 #define ARGLIST6 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, gpointer arg5, gpointer arg6, InterpMethod *rmethod
2428 #define ARGLIST7 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, gpointer arg5, gpointer arg6, gpointer arg7, InterpMethod *rmethod
2429 #define ARGLIST8 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, gpointer arg5, gpointer arg6, gpointer arg7, gpointer arg8, InterpMethod *rmethod
2431 static void interp_entry_static_0 (ARGLIST0) INTERP_ENTRY0 (NULL, NULL, rmethod)
2432 static void interp_entry_static_1 (ARGLIST1) INTERP_ENTRY1 (NULL, NULL, rmethod)
2433 static void interp_entry_static_2 (ARGLIST2) INTERP_ENTRY2 (NULL, NULL, rmethod)
2434 static void interp_entry_static_3 (ARGLIST3) INTERP_ENTRY3 (NULL, NULL, rmethod)
2435 static void interp_entry_static_4 (ARGLIST4) INTERP_ENTRY4 (NULL, NULL, rmethod)
2436 static void interp_entry_static_5 (ARGLIST5) INTERP_ENTRY5 (NULL, NULL, rmethod)
2437 static void interp_entry_static_6 (ARGLIST6) INTERP_ENTRY6 (NULL, NULL, rmethod)
2438 static void interp_entry_static_7 (ARGLIST7) INTERP_ENTRY7 (NULL, NULL, rmethod)
2439 static void interp_entry_static_8 (ARGLIST8) INTERP_ENTRY8 (NULL, NULL, rmethod)
2440 static void interp_entry_static_ret_0 (gpointer res, ARGLIST0) INTERP_ENTRY0 (NULL, res, rmethod)
2441 static void interp_entry_static_ret_1 (gpointer res, ARGLIST1) INTERP_ENTRY1 (NULL, res, rmethod)
2442 static void interp_entry_static_ret_2 (gpointer res, ARGLIST2) INTERP_ENTRY2 (NULL, res, rmethod)
2443 static void interp_entry_static_ret_3 (gpointer res, ARGLIST3) INTERP_ENTRY3 (NULL, res, rmethod)
2444 static void interp_entry_static_ret_4 (gpointer res, ARGLIST4) INTERP_ENTRY4 (NULL, res, rmethod)
2445 static void interp_entry_static_ret_5 (gpointer res, ARGLIST5) INTERP_ENTRY5 (NULL, res, rmethod)
2446 static void interp_entry_static_ret_6 (gpointer res, ARGLIST6) INTERP_ENTRY6 (NULL, res, rmethod)
2447 static void interp_entry_static_ret_7 (gpointer res, ARGLIST7) INTERP_ENTRY7 (NULL, res, rmethod)
2448 static void interp_entry_static_ret_8 (gpointer res, ARGLIST8) INTERP_ENTRY8 (NULL, res, rmethod)
2449 static void interp_entry_instance_0 (gpointer this_arg, ARGLIST0) INTERP_ENTRY0 (this_arg, NULL, rmethod)
2450 static void interp_entry_instance_1 (gpointer this_arg, ARGLIST1) INTERP_ENTRY1 (this_arg, NULL, rmethod)
2451 static void interp_entry_instance_2 (gpointer this_arg, ARGLIST2) INTERP_ENTRY2 (this_arg, NULL, rmethod)
2452 static void interp_entry_instance_3 (gpointer this_arg, ARGLIST3) INTERP_ENTRY3 (this_arg, NULL, rmethod)
2453 static void interp_entry_instance_4 (gpointer this_arg, ARGLIST4) INTERP_ENTRY4 (this_arg, NULL, rmethod)
2454 static void interp_entry_instance_5 (gpointer this_arg, ARGLIST5) INTERP_ENTRY5 (this_arg, NULL, rmethod)
2455 static void interp_entry_instance_6 (gpointer this_arg, ARGLIST6) INTERP_ENTRY6 (this_arg, NULL, rmethod)
2456 static void interp_entry_instance_7 (gpointer this_arg, ARGLIST7) INTERP_ENTRY7 (this_arg, NULL, rmethod)
2457 static void interp_entry_instance_8 (gpointer this_arg, ARGLIST8) INTERP_ENTRY8 (this_arg, NULL, rmethod)
2458 static void interp_entry_instance_ret_0 (gpointer this_arg, gpointer res, ARGLIST0) INTERP_ENTRY0 (this_arg, res, rmethod)
2459 static void interp_entry_instance_ret_1 (gpointer this_arg, gpointer res, ARGLIST1) INTERP_ENTRY1 (this_arg, res, rmethod)
2460 static void interp_entry_instance_ret_2 (gpointer this_arg, gpointer res, ARGLIST2) INTERP_ENTRY2 (this_arg, res, rmethod)
2461 static void interp_entry_instance_ret_3 (gpointer this_arg, gpointer res, ARGLIST3) INTERP_ENTRY3 (this_arg, res, rmethod)
2462 static void interp_entry_instance_ret_4 (gpointer this_arg, gpointer res, ARGLIST4) INTERP_ENTRY4 (this_arg, res, rmethod)
2463 static void interp_entry_instance_ret_5 (gpointer this_arg, gpointer res, ARGLIST5) INTERP_ENTRY5 (this_arg, res, rmethod)
2464 static void interp_entry_instance_ret_6 (gpointer this_arg, gpointer res, ARGLIST6) INTERP_ENTRY6 (this_arg, res, rmethod)
2465 static void interp_entry_instance_ret_7 (gpointer this_arg, gpointer res, ARGLIST7) INTERP_ENTRY7 (this_arg, res, rmethod)
2466 static void interp_entry_instance_ret_8 (gpointer this_arg, gpointer res, ARGLIST8) INTERP_ENTRY8 (this_arg, res, rmethod)
2468 #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
2470 static gpointer entry_funcs_static [MAX_INTERP_ENTRY_ARGS + 1] = { INTERP_ENTRY_FUNCLIST (static) };
2471 static gpointer entry_funcs_static_ret [MAX_INTERP_ENTRY_ARGS + 1] = { INTERP_ENTRY_FUNCLIST (static_ret) };
2472 static gpointer entry_funcs_instance [MAX_INTERP_ENTRY_ARGS + 1] = { INTERP_ENTRY_FUNCLIST (instance) };
2473 static gpointer entry_funcs_instance_ret [MAX_INTERP_ENTRY_ARGS + 1] = { INTERP_ENTRY_FUNCLIST (instance_ret) };
2475 /* General version for methods with more than MAX_INTERP_ENTRY_ARGS arguments */
2476 static void
2477 interp_entry_general (gpointer this_arg, gpointer res, gpointer *args, gpointer rmethod)
2479 INTERP_ENTRY_BASE ((InterpMethod*)rmethod, this_arg, res);
2480 data.many_args = args;
2481 interp_entry (&data);
2484 #ifdef MONO_ARCH_HAVE_INTERP_ENTRY_TRAMPOLINE
2486 // inline so we can alloc on stack
2487 #define alloc_storage_for_stackval(s, t, p) do { \
2488 if ((t)->type == MONO_TYPE_GENERICINST && !MONO_TYPE_IS_REFERENCE (t)) { \
2489 (s)->data.vt = alloca (mono_class_value_size (mono_class_from_mono_type_internal (t), NULL)); \
2490 } else if ((t)->type == MONO_TYPE_VALUETYPE) { \
2491 if (p) \
2492 (s)->data.vt = alloca (mono_class_native_size ((t)->data.klass, NULL)); \
2493 else \
2494 (s)->data.vt = alloca (mono_class_value_size ((t)->data.klass, NULL)); \
2496 } while (0)
2498 static void
2499 interp_entry_from_trampoline (gpointer ccontext_untyped, gpointer rmethod_untyped)
2501 InterpFrame frame;
2502 ThreadContext *context;
2503 stackval result;
2504 stackval *args;
2505 MonoMethod *method;
2506 MonoMethodSignature *sig;
2507 CallContext *ccontext = (CallContext*) ccontext_untyped;
2508 InterpMethod *rmethod = (InterpMethod*) rmethod_untyped;
2509 gpointer orig_domain = NULL, attach_cookie;
2510 int i;
2512 if (rmethod->needs_thread_attach)
2513 orig_domain = mono_threads_attach_coop (mono_domain_get (), &attach_cookie);
2515 context = get_context ();
2517 method = rmethod->method;
2518 sig = mono_method_signature_internal (method);
2520 frame.ex = NULL;
2522 args = (stackval*)alloca (sizeof (stackval) * (sig->param_count + (sig->hasthis ? 1 : 0)));
2524 init_frame (&frame, NULL, rmethod, args, &result);
2526 /* Allocate storage for value types */
2527 for (i = 0; i < sig->param_count; i++) {
2528 MonoType *type = sig->params [i];
2529 alloc_storage_for_stackval (&frame.stack_args [i + sig->hasthis], type, sig->pinvoke);
2532 if (sig->ret->type != MONO_TYPE_VOID)
2533 alloc_storage_for_stackval (frame.retval, sig->ret, sig->pinvoke);
2535 /* Copy the args saved in the trampoline to the frame stack */
2536 mono_arch_get_native_call_context_args (ccontext, &frame, sig);
2538 interp_exec_method (&frame, context);
2540 if (rmethod->needs_thread_attach)
2541 mono_threads_detach_coop (orig_domain, &attach_cookie);
2543 // FIXME:
2544 g_assert (frame.ex == NULL);
2546 /* Write back the return value */
2547 mono_arch_set_native_call_context_ret (ccontext, &frame, sig);
2549 #endif /* MONO_ARCH_HAVE_INTERP_ENTRY_TRAMPOLINE */
2551 static InterpMethod*
2552 lookup_method_pointer (gpointer addr)
2554 MonoDomain *domain = mono_domain_get ();
2555 MonoJitDomainInfo *info = domain_jit_info (domain);
2556 InterpMethod *res = NULL;
2558 mono_domain_lock (domain);
2559 if (info->interp_method_pointer_hash)
2560 res = (InterpMethod*)g_hash_table_lookup (info->interp_method_pointer_hash, addr);
2561 mono_domain_unlock (domain);
2563 return res;
2566 #ifndef MONO_ARCH_HAVE_INTERP_NATIVE_TO_MANAGED
2567 static void
2568 interp_no_native_to_managed (void)
2570 g_error ("interpreter: native-to-managed transition not available on this platform");
2572 #endif
2574 static void
2575 no_llvmonly_interp_method_pointer (void)
2577 g_assert_not_reached ();
2581 * interp_create_method_pointer_llvmonly:
2583 * Return an ftndesc for entering the interpreter and executing METHOD.
2585 static MonoFtnDesc*
2586 interp_create_method_pointer_llvmonly (MonoMethod *method, gboolean unbox, MonoError *error)
2588 MonoDomain *domain = mono_domain_get ();
2589 gpointer addr, entry_func, entry_wrapper;
2590 MonoMethodSignature *sig;
2591 MonoMethod *wrapper;
2592 MonoJitDomainInfo *info;
2593 InterpMethod *imethod;
2595 imethod = mono_interp_get_imethod (domain, method, error);
2596 return_val_if_nok (error, NULL);
2598 if (unbox) {
2599 if (imethod->llvmonly_unbox_entry)
2600 return (MonoFtnDesc*)imethod->llvmonly_unbox_entry;
2601 } else {
2602 if (imethod->jit_entry)
2603 return (MonoFtnDesc*)imethod->jit_entry;
2606 sig = mono_method_signature_internal (method);
2609 * The entry functions need access to the method to call, so we have
2610 * to use a ftndesc. The caller uses a normal signature, while the
2611 * entry functions use a gsharedvt_in signature, so wrap the entry function in
2612 * a gsharedvt_in_sig wrapper.
2614 wrapper = mini_get_gsharedvt_in_sig_wrapper (sig);
2616 entry_wrapper = mono_jit_compile_method_jit_only (wrapper, error);
2617 mono_error_assertf_ok (error, "couldn't compile wrapper \"%s\" for \"%s\"",
2618 mono_method_get_name_full (wrapper, TRUE, TRUE, MONO_TYPE_NAME_FORMAT_IL),
2619 mono_method_get_name_full (method, TRUE, TRUE, MONO_TYPE_NAME_FORMAT_IL));
2621 if (sig->param_count > MAX_INTERP_ENTRY_ARGS) {
2622 g_assert_not_reached ();
2623 //entry_func = (gpointer)interp_entry_general;
2624 } else if (sig->hasthis) {
2625 if (sig->ret->type == MONO_TYPE_VOID)
2626 entry_func = entry_funcs_instance [sig->param_count];
2627 else
2628 entry_func = entry_funcs_instance_ret [sig->param_count];
2629 } else {
2630 if (sig->ret->type == MONO_TYPE_VOID)
2631 entry_func = entry_funcs_static [sig->param_count];
2632 else
2633 entry_func = entry_funcs_static_ret [sig->param_count];
2635 g_assert (entry_func);
2637 /* Encode unbox in the lower bit of imethod */
2638 gpointer entry_arg = imethod;
2639 if (unbox)
2640 entry_arg = (gpointer)(((gsize)entry_arg) | 1);
2641 MonoFtnDesc *entry_ftndesc = mini_llvmonly_create_ftndesc (mono_domain_get (), entry_func, entry_arg);
2643 addr = mini_llvmonly_create_ftndesc (mono_domain_get (), entry_wrapper, entry_ftndesc);
2645 info = domain_jit_info (domain);
2646 mono_domain_lock (domain);
2647 if (!info->interp_method_pointer_hash)
2648 info->interp_method_pointer_hash = g_hash_table_new (NULL, NULL);
2649 g_hash_table_insert (info->interp_method_pointer_hash, addr, imethod);
2650 mono_domain_unlock (domain);
2652 mono_memory_barrier ();
2653 if (unbox)
2654 imethod->llvmonly_unbox_entry = addr;
2655 else
2656 imethod->jit_entry = addr;
2658 return (MonoFtnDesc*)addr;
2662 * interp_create_method_pointer:
2664 * Return a function pointer which can be used to call METHOD using the
2665 * interpreter. Return NULL for methods which are not supported.
2667 static gpointer
2668 interp_create_method_pointer (MonoMethod *method, gboolean compile, MonoError *error)
2670 #ifndef MONO_ARCH_HAVE_INTERP_NATIVE_TO_MANAGED
2671 if (mono_llvm_only)
2672 return (gpointer)no_llvmonly_interp_method_pointer;
2673 return (gpointer)interp_no_native_to_managed;
2674 #else
2675 gpointer addr, entry_func, entry_wrapper;
2676 MonoDomain *domain = mono_domain_get ();
2677 MonoJitDomainInfo *info;
2678 InterpMethod *imethod = mono_interp_get_imethod (domain, method, error);
2680 if (mono_llvm_only)
2681 return (gpointer)no_llvmonly_interp_method_pointer;
2683 if (imethod->jit_entry)
2684 return imethod->jit_entry;
2686 if (compile && !imethod->transformed) {
2687 /* Return any errors from method compilation */
2688 mono_interp_transform_method (imethod, get_context (), error);
2689 return_val_if_nok (error, NULL);
2692 MonoMethodSignature *sig = mono_method_signature_internal (method);
2694 if (mono_llvm_only)
2695 /* The caller should call interp_create_method_pointer_llvmonly */
2696 g_assert_not_reached ();
2698 if (method->wrapper_type && method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE)
2699 return imethod;
2701 #ifndef MONO_ARCH_HAVE_INTERP_ENTRY_TRAMPOLINE
2702 MonoMethod *wrapper = mini_get_interp_in_wrapper (sig);
2704 entry_wrapper = mono_jit_compile_method_jit_only (wrapper, error);
2705 mono_error_assertf_ok (error, "couldn't compile wrapper \"%s\" for \"%s\"",
2706 mono_method_get_name_full (wrapper, TRUE, TRUE, MONO_TYPE_NAME_FORMAT_IL),
2707 mono_method_get_name_full (method, TRUE, TRUE, MONO_TYPE_NAME_FORMAT_IL));
2709 if (sig->param_count > MAX_INTERP_ENTRY_ARGS) {
2710 entry_func = (gpointer)interp_entry_general;
2711 } else if (sig->hasthis) {
2712 if (sig->ret->type == MONO_TYPE_VOID)
2713 entry_func = entry_funcs_instance [sig->param_count];
2714 else
2715 entry_func = entry_funcs_instance_ret [sig->param_count];
2716 } else {
2717 if (sig->ret->type == MONO_TYPE_VOID)
2718 entry_func = entry_funcs_static [sig->param_count];
2719 else
2720 entry_func = entry_funcs_static_ret [sig->param_count];
2722 g_assert (entry_func);
2723 #else
2724 if (!mono_native_to_interp_trampoline) {
2725 if (mono_aot_only) {
2726 mono_native_to_interp_trampoline = (MonoFuncV)mono_aot_get_trampoline ("native_to_interp_trampoline");
2727 } else {
2728 MonoTrampInfo *info;
2729 mono_native_to_interp_trampoline = (MonoFuncV)mono_arch_get_native_to_interp_trampoline (&info);
2730 mono_tramp_info_register (info, NULL);
2733 entry_wrapper = (gpointer)mono_native_to_interp_trampoline;
2734 /* We need the lmf wrapper only when being called from mixed mode */
2735 if (sig->pinvoke)
2736 entry_func = (gpointer)interp_entry_from_trampoline;
2737 else {
2738 static gpointer cached_func = NULL;
2739 if (!cached_func) {
2740 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);
2741 mono_memory_barrier ();
2743 entry_func = cached_func;
2745 #endif
2746 /* This is the argument passed to the interp_in wrapper by the static rgctx trampoline */
2747 MonoFtnDesc *ftndesc = g_new0 (MonoFtnDesc, 1);
2748 ftndesc->addr = entry_func;
2749 ftndesc->arg = imethod;
2750 mono_error_assert_ok (error);
2753 * The wrapper is called by compiled code, which doesn't pass the extra argument, so we pass it in the
2754 * rgctx register using a trampoline.
2757 addr = mono_create_ftnptr_arg_trampoline (ftndesc, entry_wrapper);
2759 info = domain_jit_info (domain);
2760 mono_domain_lock (domain);
2761 if (!info->interp_method_pointer_hash)
2762 info->interp_method_pointer_hash = g_hash_table_new (NULL, NULL);
2763 g_hash_table_insert (info->interp_method_pointer_hash, addr, imethod);
2764 mono_domain_unlock (domain);
2766 mono_memory_barrier ();
2767 imethod->jit_entry = addr;
2769 return addr;
2770 #endif
2773 #if COUNT_OPS
2774 static int opcode_counts[512];
2776 #define COUNT_OP(op) opcode_counts[op]++
2777 #else
2778 #define COUNT_OP(op)
2779 #endif
2781 #if DEBUG_INTERP
2782 #define DUMP_INSTR() \
2783 if (tracing > 1) { \
2784 char *ins; \
2785 if (sp > frame->stack) { \
2786 ins = dump_stack (frame->stack, sp); \
2787 } else { \
2788 ins = g_strdup (""); \
2790 sp->data.l = 0; \
2791 output_indent (); \
2792 char *mn = mono_method_full_name (frame->imethod->method, FALSE); \
2793 char *disasm = mono_interp_dis_mintop(imethod->code, ip); \
2794 g_print ("(%p) %s -> %s\t%d:%s\n", mono_thread_internal_current (), mn, disasm, vt_sp - vtalloc, ins); \
2795 g_free (mn); \
2796 g_free (ins); \
2797 g_free (disasm); \
2799 #else
2800 #define DUMP_INSTR()
2801 #endif
2803 #ifdef __GNUC__
2804 #define USE_COMPUTED_GOTO 1
2805 #endif
2806 #if USE_COMPUTED_GOTO
2807 #define MINT_IN_SWITCH(op) COUNT_OP(op); goto *in_labels[op];
2808 #define MINT_IN_CASE(x) LAB_ ## x:
2809 #if DEBUG_INTERP
2810 #define MINT_IN_BREAK if (tracing > 1) goto main_loop; else { COUNT_OP(*ip); goto *in_labels[*ip]; }
2811 #else
2812 #define MINT_IN_BREAK { COUNT_OP(*ip); goto *in_labels[*ip]; }
2813 #endif
2814 #define MINT_IN_DEFAULT mint_default: if (0) goto mint_default; /* make gcc shut up */
2815 #else
2816 #define MINT_IN_SWITCH(op) switch (op)
2817 #define MINT_IN_CASE(x) case x:
2818 #define MINT_IN_BREAK break
2819 #define MINT_IN_DEFAULT default:
2820 #endif
2822 #define INIT_VTABLE(vtable) do { \
2823 if (G_UNLIKELY (!(vtable)->initialized)) { \
2824 mono_runtime_class_init_full ((vtable), error); \
2825 if (!mono_error_ok (error)) \
2826 THROW_EX (mono_error_convert_to_exception (error), ip); \
2828 } while (0);
2831 * If EXIT_AT_FINALLY is not -1, exit after exiting the finally clause with that index.
2832 * If BASE_FRAME is not NULL, copy arguments/locals from BASE_FRAME.
2834 static void
2835 interp_exec_method_full (InterpFrame *frame, ThreadContext *context, FrameClauseArgs *clause_args)
2837 InterpFrame child_frame;
2838 GSList *finally_ips = NULL;
2839 const unsigned short *endfinally_ip = NULL;
2840 const unsigned short *ip = NULL;
2841 stackval *sp;
2842 InterpMethod *imethod = NULL;
2843 #if DEBUG_INTERP
2844 gint tracing = global_tracing;
2845 unsigned char *vtalloc;
2846 #else
2847 gint tracing = 0;
2848 #endif
2849 int i32;
2850 unsigned char *vt_sp;
2851 unsigned char *locals = NULL;
2852 ERROR_DECL (error);
2853 MonoObject *o = NULL;
2854 MonoClass *c;
2855 #if USE_COMPUTED_GOTO
2856 static void *in_labels[] = {
2857 #define OPDEF(a,b,c,d) \
2858 &&LAB_ ## a,
2859 #include "mintops.def"
2860 0 };
2861 #endif
2863 frame->ex = NULL;
2864 debug_enter (frame, &tracing);
2866 imethod = frame->imethod;
2867 if (!imethod->transformed) {
2868 #if DEBUG_INTERP
2869 char *mn = mono_method_full_name (imethod->method, TRUE);
2870 g_print ("(%p) Transforming %s\n", mono_thread_internal_current (), mn);
2871 g_free (mn);
2872 #endif
2874 frame->ip = NULL;
2875 do_transform_method (frame, context);
2876 if (frame->ex)
2877 THROW_EX (frame->ex, NULL);
2878 EXCEPTION_CHECKPOINT;
2881 if (!clause_args) {
2882 frame->args = g_newa (char, imethod->alloca_size);
2883 ip = imethod->code;
2884 } else {
2885 ip = clause_args->start_with_ip;
2886 if (clause_args->base_frame) {
2887 frame->args = g_newa (char, imethod->alloca_size);
2888 memcpy (frame->args, clause_args->base_frame->args, imethod->alloca_size);
2891 sp = frame->stack = (stackval *) (char *) frame->args;
2892 vt_sp = (unsigned char *) sp + imethod->stack_size;
2893 #if DEBUG_INTERP
2894 vtalloc = vt_sp;
2895 #endif
2896 locals = (unsigned char *) vt_sp + imethod->vt_stack_size;
2897 frame->locals = locals;
2898 child_frame.parent = frame;
2900 if (clause_args && clause_args->filter_exception) {
2901 sp->data.p = clause_args->filter_exception;
2902 sp++;
2905 //g_print ("(%p) Call %s\n", mono_thread_internal_current (), mono_method_get_full_name (frame->imethod->method));
2908 * using while (ip < end) may result in a 15% performance drop,
2909 * but it may be useful for debug
2911 while (1) {
2912 main_loop:
2913 /* g_assert (sp >= frame->stack); */
2914 /* g_assert(vt_sp - vtalloc <= imethod->vt_stack_size); */
2915 DUMP_INSTR();
2916 MINT_IN_SWITCH (*ip) {
2917 MINT_IN_CASE(MINT_INITLOCALS)
2918 memset (locals, 0, imethod->locals_size);
2919 ++ip;
2920 MINT_IN_BREAK;
2921 MINT_IN_CASE(MINT_NOP)
2922 ++ip;
2923 MINT_IN_BREAK;
2924 MINT_IN_CASE(MINT_NIY)
2925 g_error ("mint_niy: instruction not implemented yet. This shouldn't happen.");
2926 MINT_IN_BREAK;
2927 MINT_IN_CASE(MINT_BREAK)
2928 ++ip;
2929 do_debugger_tramp (mini_get_dbg_callbacks ()->user_break, frame);
2930 MINT_IN_BREAK;
2931 MINT_IN_CASE(MINT_BREAKPOINT)
2932 ++ip;
2933 mono_break ();
2934 MINT_IN_BREAK;
2935 MINT_IN_CASE(MINT_LDNULL)
2936 sp->data.p = NULL;
2937 ++ip;
2938 ++sp;
2939 MINT_IN_BREAK;
2940 MINT_IN_CASE(MINT_ARGLIST)
2941 g_assert (frame->varargs);
2942 sp->data.p = vt_sp;
2943 *(gpointer*)sp->data.p = frame->varargs;
2944 vt_sp += ALIGN_TO (sizeof (gpointer), MINT_VT_ALIGNMENT);
2945 ++ip;
2946 ++sp;
2947 MINT_IN_BREAK;
2948 MINT_IN_CASE(MINT_VTRESULT) {
2949 int ret_size = * (guint16 *)(ip + 1);
2950 unsigned char *ret_vt_sp = vt_sp;
2951 vt_sp -= READ32(ip + 2);
2952 if (ret_size > 0) {
2953 memmove (vt_sp, ret_vt_sp, ret_size);
2954 sp [-1].data.p = vt_sp;
2955 vt_sp += ALIGN_TO (ret_size, MINT_VT_ALIGNMENT);
2957 ip += 4;
2958 MINT_IN_BREAK;
2960 #define LDC(n) do { sp->data.i = (n); ++ip; ++sp; } while (0)
2961 MINT_IN_CASE(MINT_LDC_I4_M1)
2962 LDC(-1);
2963 MINT_IN_BREAK;
2964 MINT_IN_CASE(MINT_LDC_I4_0)
2965 LDC(0);
2966 MINT_IN_BREAK;
2967 MINT_IN_CASE(MINT_LDC_I4_1)
2968 LDC(1);
2969 MINT_IN_BREAK;
2970 MINT_IN_CASE(MINT_LDC_I4_2)
2971 LDC(2);
2972 MINT_IN_BREAK;
2973 MINT_IN_CASE(MINT_LDC_I4_3)
2974 LDC(3);
2975 MINT_IN_BREAK;
2976 MINT_IN_CASE(MINT_LDC_I4_4)
2977 LDC(4);
2978 MINT_IN_BREAK;
2979 MINT_IN_CASE(MINT_LDC_I4_5)
2980 LDC(5);
2981 MINT_IN_BREAK;
2982 MINT_IN_CASE(MINT_LDC_I4_6)
2983 LDC(6);
2984 MINT_IN_BREAK;
2985 MINT_IN_CASE(MINT_LDC_I4_7)
2986 LDC(7);
2987 MINT_IN_BREAK;
2988 MINT_IN_CASE(MINT_LDC_I4_8)
2989 LDC(8);
2990 MINT_IN_BREAK;
2991 MINT_IN_CASE(MINT_LDC_I4_S)
2992 sp->data.i = *(const short *)(ip + 1);
2993 ip += 2;
2994 ++sp;
2995 MINT_IN_BREAK;
2996 MINT_IN_CASE(MINT_LDC_I4)
2997 ++ip;
2998 sp->data.i = READ32 (ip);
2999 ip += 2;
3000 ++sp;
3001 MINT_IN_BREAK;
3002 MINT_IN_CASE(MINT_LDC_I8)
3003 ++ip;
3004 sp->data.l = READ64 (ip);
3005 ip += 4;
3006 ++sp;
3007 MINT_IN_BREAK;
3008 MINT_IN_CASE(MINT_LDC_I8_S)
3009 sp->data.l = *(const short *)(ip + 1);
3010 ip += 2;
3011 ++sp;
3012 MINT_IN_BREAK;
3013 MINT_IN_CASE(MINT_LDC_R4) {
3014 guint32 val;
3015 ++ip;
3016 val = READ32(ip);
3017 sp->data.f_r4 = * (float *)&val;
3018 ip += 2;
3019 ++sp;
3020 MINT_IN_BREAK;
3022 MINT_IN_CASE(MINT_LDC_R8)
3023 sp->data.l = READ64 (ip + 1); /* note union usage */
3024 ip += 5;
3025 ++sp;
3026 MINT_IN_BREAK;
3027 MINT_IN_CASE(MINT_DUP)
3028 sp [0] = sp[-1];
3029 ++sp;
3030 ++ip;
3031 MINT_IN_BREAK;
3032 MINT_IN_CASE(MINT_DUP_VT)
3033 i32 = READ32 (ip + 1);
3034 sp->data.p = vt_sp;
3035 memcpy(sp->data.p, sp [-1].data.p, i32);
3036 vt_sp += ALIGN_TO (i32, MINT_VT_ALIGNMENT);
3037 ++sp;
3038 ip += 3;
3039 MINT_IN_BREAK;
3040 MINT_IN_CASE(MINT_POP) {
3041 guint16 u16 = (* (guint16 *)(ip + 1)) + 1;
3042 if (u16 > 1)
3043 memmove (sp - u16, sp - 1, (u16 - 1) * sizeof (stackval));
3044 sp--;
3045 ip += 2;
3046 MINT_IN_BREAK;
3048 MINT_IN_CASE(MINT_JMP) {
3049 InterpMethod *new_method = (InterpMethod*)imethod->data_items [* (guint16 *)(ip + 1)];
3050 gboolean realloc_frame = new_method->alloca_size > imethod->alloca_size;
3052 if (imethod->prof_flags & MONO_PROFILER_CALL_INSTRUMENTATION_TAIL_CALL)
3053 MONO_PROFILER_RAISE (method_tail_call, (imethod->method, new_method->method));
3055 if (!new_method->transformed) {
3056 ERROR_DECL (error);
3058 frame->ip = ip;
3059 mono_interp_transform_method (new_method, context, error);
3060 frame->ex = mono_error_convert_to_exception (error);
3061 if (frame->ex)
3062 goto exit_frame;
3064 ip += 2;
3065 imethod = frame->imethod = new_method;
3067 * We allocate the stack frame from scratch and store the arguments in the
3068 * locals again since it's possible for the caller stack frame to be smaller
3069 * than the callee stack frame (at the interp level)
3071 if (realloc_frame) {
3072 frame->args = g_newa (char, imethod->alloca_size);
3073 memset (frame->args, 0, imethod->alloca_size);
3074 sp = frame->stack = (stackval *) frame->args;
3076 vt_sp = (unsigned char *) sp + imethod->stack_size;
3077 #if DEBUG_INTERP
3078 vtalloc = vt_sp;
3079 #endif
3080 locals = vt_sp + imethod->vt_stack_size;
3081 frame->locals = locals;
3082 ip = imethod->code;
3083 MINT_IN_BREAK;
3085 MINT_IN_CASE(MINT_CALLI) {
3086 MonoMethodSignature *csignature;
3087 stackval *endsp = sp;
3089 frame->ip = ip;
3091 csignature = (MonoMethodSignature*)imethod->data_items [* (guint16 *)(ip + 1)];
3092 ip += 2;
3093 --sp;
3094 --endsp;
3095 child_frame.imethod = (InterpMethod*)sp->data.p;
3097 sp->data.p = vt_sp;
3098 child_frame.retval = sp;
3099 /* decrement by the actual number of args */
3100 sp -= csignature->param_count;
3101 if (csignature->hasthis)
3102 --sp;
3103 child_frame.stack_args = sp;
3105 if (child_frame.imethod->method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) {
3106 child_frame.imethod = mono_interp_get_imethod (imethod->domain, mono_marshal_get_native_wrapper (child_frame.imethod->method, FALSE, FALSE), error);
3107 mono_error_cleanup (error); /* FIXME: don't swallow the error */
3110 if (csignature->hasthis) {
3111 MonoObject *this_arg = (MonoObject*)sp->data.p;
3113 if (m_class_is_valuetype (this_arg->vtable->klass)) {
3114 gpointer unboxed = mono_object_unbox_internal (this_arg);
3115 sp [0].data.p = unboxed;
3119 interp_exec_method (&child_frame, context);
3121 CHECK_RESUME_STATE (context);
3123 /* need to handle typedbyref ... */
3124 if (csignature->ret->type != MONO_TYPE_VOID) {
3125 *sp = *endsp;
3126 sp++;
3128 MINT_IN_BREAK;
3130 MINT_IN_CASE(MINT_CALLI_NAT_FAST) {
3131 gpointer target_ip = sp [-1].data.p;
3132 MonoMethodSignature *csignature = (MonoMethodSignature*)imethod->data_items [* (guint16 *)(ip + 1)];
3133 int opcode = *(guint16 *)(ip + 2);
3135 sp--;
3136 frame->ip = ip;
3138 sp = do_icall_wrapper (frame, csignature, opcode, sp, target_ip);
3139 EXCEPTION_CHECKPOINT;
3140 CHECK_RESUME_STATE (context);
3141 ip += 3;
3142 MINT_IN_BREAK;
3144 MINT_IN_CASE(MINT_CALLI_NAT) {
3145 MonoMethodSignature *csignature;
3146 stackval *endsp = sp;
3147 unsigned char *code = NULL;
3149 frame->ip = ip;
3151 csignature = (MonoMethodSignature*)imethod->data_items [* (guint16 *)(ip + 1)];
3152 ip += 2;
3153 --sp;
3154 --endsp;
3155 code = (guchar*)sp->data.p;
3156 child_frame.imethod = NULL;
3158 sp->data.p = vt_sp;
3159 child_frame.retval = sp;
3160 /* decrement by the actual number of args */
3161 sp -= csignature->param_count;
3162 if (csignature->hasthis)
3163 --sp;
3164 child_frame.stack_args = sp;
3165 if (imethod->method->dynamic && csignature->pinvoke) {
3166 MonoMarshalSpec **mspecs;
3167 MonoMethodPInvoke piinfo;
3168 MonoMethod *m;
3170 /* Pinvoke call is missing the wrapper. See mono_get_native_calli_wrapper */
3171 mspecs = g_new0 (MonoMarshalSpec*, csignature->param_count + 1);
3172 memset (&piinfo, 0, sizeof (piinfo));
3174 m = mono_marshal_get_native_func_wrapper (m_class_get_image (imethod->method->klass), csignature, &piinfo, mspecs, code);
3176 for (int i = csignature->param_count; i >= 0; i--)
3177 if (mspecs [i])
3178 mono_metadata_free_marshal_spec (mspecs [i]);
3179 g_free (mspecs);
3181 child_frame.imethod = mono_interp_get_imethod (imethod->domain, m, error);
3182 mono_error_cleanup (error); /* FIXME: don't swallow the error */
3184 interp_exec_method (&child_frame, context);
3185 } else {
3186 ves_pinvoke_method (&child_frame, csignature, (MonoFuncV) code, FALSE, context);
3189 CHECK_RESUME_STATE (context);
3191 /* need to handle typedbyref ... */
3192 if (csignature->ret->type != MONO_TYPE_VOID) {
3193 *sp = *endsp;
3194 sp++;
3196 MINT_IN_BREAK;
3198 MINT_IN_CASE(MINT_CALLVIRT_FAST)
3199 MINT_IN_CASE(MINT_VCALLVIRT_FAST) {
3200 MonoObject *this_arg;
3201 MonoClass *this_class;
3202 gboolean is_void = *ip == MINT_VCALLVIRT_FAST;
3203 InterpMethod *target_imethod;
3204 stackval *endsp = sp;
3205 int slot;
3207 // FIXME Have it handle also remoting calls and use a single opcode for virtual calls
3209 frame->ip = ip;
3211 target_imethod = (InterpMethod*)imethod->data_items [* (guint16 *)(ip + 1)];
3212 slot = *(gint16*)(ip + 2);
3213 ip += 3;
3214 sp->data.p = vt_sp;
3215 child_frame.retval = sp;
3217 /* decrement by the actual number of args */
3218 sp -= target_imethod->param_count + target_imethod->hasthis;
3219 child_frame.stack_args = sp;
3221 this_arg = (MonoObject*)sp->data.p;
3222 this_class = this_arg->vtable->klass;
3224 child_frame.imethod = get_virtual_method_fast (this_arg, target_imethod, slot);
3225 if (m_class_is_valuetype (this_class) && m_class_is_valuetype (child_frame.imethod->method->klass)) {
3226 /* unbox */
3227 gpointer unboxed = mono_object_unbox_internal (this_arg);
3228 sp [0].data.p = unboxed;
3231 interp_exec_method (&child_frame, context);
3233 CHECK_RESUME_STATE (context);
3235 if (!is_void) {
3236 /* need to handle typedbyref ... */
3237 *sp = *endsp;
3238 sp++;
3240 MINT_IN_BREAK;
3242 MINT_IN_CASE(MINT_CALL_VARARG) {
3243 stackval *endsp = sp;
3244 int num_varargs = 0;
3245 MonoMethodSignature *csig;
3247 frame->ip = ip;
3249 child_frame.imethod = (InterpMethod*)imethod->data_items [* (guint16 *)(ip + 1)];
3250 /* The real signature for vararg calls */
3251 csig = (MonoMethodSignature*) imethod->data_items [* (guint16*) (ip + 2)];
3252 /* Push all vararg arguments from normal sp to vt_sp together with the signature */
3253 num_varargs = csig->param_count - csig->sentinelpos;
3254 child_frame.varargs = (char*) vt_sp;
3255 copy_varargs_vtstack (csig, sp, &vt_sp);
3257 ip += 3;
3258 sp->data.p = vt_sp;
3259 child_frame.retval = sp;
3261 /* decrement by the actual number of args */
3262 sp -= child_frame.imethod->param_count + child_frame.imethod->hasthis + num_varargs;
3263 child_frame.stack_args = sp;
3265 interp_exec_method (&child_frame, context);
3267 CHECK_RESUME_STATE (context);
3269 if (csig->ret->type != MONO_TYPE_VOID) {
3270 *sp = *endsp;
3271 sp++;
3273 MINT_IN_BREAK;
3275 MINT_IN_CASE(MINT_CALL)
3276 MINT_IN_CASE(MINT_VCALL)
3277 MINT_IN_CASE(MINT_CALLVIRT)
3278 MINT_IN_CASE(MINT_VCALLVIRT) {
3279 gboolean is_void = *ip == MINT_VCALL || *ip == MINT_VCALLVIRT;
3280 gboolean is_virtual = *ip == MINT_CALLVIRT || *ip == MINT_VCALLVIRT;
3281 stackval *endsp = sp;
3283 frame->ip = ip;
3285 child_frame.imethod = (InterpMethod*)imethod->data_items [* (guint16 *)(ip + 1)];
3286 ip += 2;
3287 sp->data.p = vt_sp;
3288 child_frame.retval = sp;
3290 /* decrement by the actual number of args */
3291 sp -= child_frame.imethod->param_count + child_frame.imethod->hasthis;
3292 child_frame.stack_args = sp;
3294 if (is_virtual) {
3295 MonoObject *this_arg = (MonoObject*)sp->data.p;
3296 MonoClass *this_class = this_arg->vtable->klass;
3298 child_frame.imethod = get_virtual_method (child_frame.imethod, this_arg);
3299 if (m_class_is_valuetype (this_class) && m_class_is_valuetype (child_frame.imethod->method->klass)) {
3300 /* unbox */
3301 gpointer unboxed = mono_object_unbox_internal (this_arg);
3302 sp [0].data.p = unboxed;
3306 interp_exec_method (&child_frame, context);
3308 CHECK_RESUME_STATE (context);
3310 if (!is_void) {
3311 /* need to handle typedbyref ... */
3312 *sp = *endsp;
3313 sp++;
3315 MINT_IN_BREAK;
3317 MINT_IN_CASE(MINT_JIT_CALL) {
3318 InterpMethod *rmethod = (InterpMethod*)imethod->data_items [* (guint16 *)(ip + 1)];
3319 ERROR_DECL (error);
3320 frame->ip = ip;
3321 sp = do_jit_call (sp, vt_sp, context, frame, rmethod, error);
3322 if (!is_ok (error)) {
3323 MonoException *ex = mono_error_convert_to_exception (error);
3324 THROW_EX (ex, ip);
3326 ip += 2;
3328 CHECK_RESUME_STATE (context);
3330 if (rmethod->rtype->type != MONO_TYPE_VOID)
3331 sp++;
3333 MINT_IN_BREAK;
3335 MINT_IN_CASE(MINT_CALLRUN) {
3336 MonoMethod *target_method = (MonoMethod*) imethod->data_items [* (guint16 *)(ip + 1)];
3337 MonoMethodSignature *sig = (MonoMethodSignature*) imethod->data_items [* (guint16 *)(ip + 2)];
3338 stackval *retval;
3340 sp->data.p = vt_sp;
3341 retval = sp;
3343 sp -= sig->param_count;
3344 if (sig->hasthis)
3345 sp--;
3347 ves_imethod (frame, target_method, sig, sp, retval);
3348 if (frame->ex)
3349 THROW_EX (frame->ex, ip);
3351 if (sig->ret->type != MONO_TYPE_VOID) {
3352 *sp = *retval;
3353 sp++;
3355 ip += 3;
3356 MINT_IN_BREAK;
3358 MINT_IN_CASE(MINT_RET)
3359 --sp;
3360 *frame->retval = *sp;
3361 if (sp > frame->stack)
3362 g_warning ("ret: more values on stack: %d", sp-frame->stack);
3363 goto exit_frame;
3364 MINT_IN_CASE(MINT_RET_VOID)
3365 if (sp > frame->stack)
3366 g_warning ("ret.void: more values on stack: %d %s", sp-frame->stack, mono_method_full_name (imethod->method, TRUE));
3367 goto exit_frame;
3368 MINT_IN_CASE(MINT_RET_VT)
3369 i32 = READ32(ip + 1);
3370 --sp;
3371 memcpy(frame->retval->data.p, sp->data.p, i32);
3372 if (sp > frame->stack)
3373 g_warning ("ret.vt: more values on stack: %d", sp-frame->stack);
3374 goto exit_frame;
3375 MINT_IN_CASE(MINT_BR_S)
3376 ip += (short) *(ip + 1);
3377 MINT_IN_BREAK;
3378 MINT_IN_CASE(MINT_BR)
3379 ip += (gint32) READ32(ip + 1);
3380 MINT_IN_BREAK;
3381 #define ZEROP_S(datamem, op) \
3382 --sp; \
3383 if (sp->data.datamem op 0) \
3384 ip += * (gint16 *)(ip + 1); \
3385 else \
3386 ip += 2;
3388 #define ZEROP(datamem, op) \
3389 --sp; \
3390 if (sp->data.datamem op 0) \
3391 ip += (gint32)READ32(ip + 1); \
3392 else \
3393 ip += 3;
3395 MINT_IN_CASE(MINT_BRFALSE_I4_S)
3396 ZEROP_S(i, ==);
3397 MINT_IN_BREAK;
3398 MINT_IN_CASE(MINT_BRFALSE_I8_S)
3399 ZEROP_S(l, ==);
3400 MINT_IN_BREAK;
3401 MINT_IN_CASE(MINT_BRFALSE_R4_S)
3402 ZEROP_S(f_r4, ==);
3403 MINT_IN_BREAK;
3404 MINT_IN_CASE(MINT_BRFALSE_R8_S)
3405 ZEROP_S(f, ==);
3406 MINT_IN_BREAK;
3407 MINT_IN_CASE(MINT_BRFALSE_I4)
3408 ZEROP(i, ==);
3409 MINT_IN_BREAK;
3410 MINT_IN_CASE(MINT_BRFALSE_I8)
3411 ZEROP(l, ==);
3412 MINT_IN_BREAK;
3413 MINT_IN_CASE(MINT_BRFALSE_R4)
3414 ZEROP_S(f_r4, ==);
3415 MINT_IN_BREAK;
3416 MINT_IN_CASE(MINT_BRFALSE_R8)
3417 ZEROP_S(f, ==);
3418 MINT_IN_BREAK;
3419 MINT_IN_CASE(MINT_BRTRUE_I4_S)
3420 ZEROP_S(i, !=);
3421 MINT_IN_BREAK;
3422 MINT_IN_CASE(MINT_BRTRUE_I8_S)
3423 ZEROP_S(l, !=);
3424 MINT_IN_BREAK;
3425 MINT_IN_CASE(MINT_BRTRUE_R4_S)
3426 ZEROP_S(f_r4, !=);
3427 MINT_IN_BREAK;
3428 MINT_IN_CASE(MINT_BRTRUE_R8_S)
3429 ZEROP_S(f, !=);
3430 MINT_IN_BREAK;
3431 MINT_IN_CASE(MINT_BRTRUE_I4)
3432 ZEROP(i, !=);
3433 MINT_IN_BREAK;
3434 MINT_IN_CASE(MINT_BRTRUE_I8)
3435 ZEROP(l, !=);
3436 MINT_IN_BREAK;
3437 MINT_IN_CASE(MINT_BRTRUE_R4)
3438 ZEROP(f_r4, !=);
3439 MINT_IN_BREAK;
3440 MINT_IN_CASE(MINT_BRTRUE_R8)
3441 ZEROP(f, !=);
3442 MINT_IN_BREAK;
3443 #define CONDBR_S(cond) \
3444 sp -= 2; \
3445 if (cond) \
3446 ip += * (gint16 *)(ip + 1); \
3447 else \
3448 ip += 2;
3449 #define BRELOP_S(datamem, op) \
3450 CONDBR_S(sp[0].data.datamem op sp[1].data.datamem)
3452 #define CONDBR(cond) \
3453 sp -= 2; \
3454 if (cond) \
3455 ip += (gint32)READ32(ip + 1); \
3456 else \
3457 ip += 3;
3459 #define BRELOP(datamem, op) \
3460 CONDBR(sp[0].data.datamem op sp[1].data.datamem)
3462 MINT_IN_CASE(MINT_BEQ_I4_S)
3463 BRELOP_S(i, ==)
3464 MINT_IN_BREAK;
3465 MINT_IN_CASE(MINT_BEQ_I8_S)
3466 BRELOP_S(l, ==)
3467 MINT_IN_BREAK;
3468 MINT_IN_CASE(MINT_BEQ_R4_S)
3469 CONDBR_S(!isunordered (sp [0].data.f_r4, sp [1].data.f_r4) && sp[0].data.f_r4 == sp[1].data.f_r4)
3470 MINT_IN_BREAK;
3471 MINT_IN_CASE(MINT_BEQ_R8_S)
3472 CONDBR_S(!mono_isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f == sp[1].data.f)
3473 MINT_IN_BREAK;
3474 MINT_IN_CASE(MINT_BEQ_I4)
3475 BRELOP(i, ==)
3476 MINT_IN_BREAK;
3477 MINT_IN_CASE(MINT_BEQ_I8)
3478 BRELOP(l, ==)
3479 MINT_IN_BREAK;
3480 MINT_IN_CASE(MINT_BEQ_R4)
3481 CONDBR(!isunordered (sp [0].data.f_r4, sp [1].data.f_r4) && sp[0].data.f_r4 == sp[1].data.f_r4)
3482 MINT_IN_BREAK;
3483 MINT_IN_CASE(MINT_BEQ_R8)
3484 CONDBR(!mono_isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f == sp[1].data.f)
3485 MINT_IN_BREAK;
3486 MINT_IN_CASE(MINT_BGE_I4_S)
3487 BRELOP_S(i, >=)
3488 MINT_IN_BREAK;
3489 MINT_IN_CASE(MINT_BGE_I8_S)
3490 BRELOP_S(l, >=)
3491 MINT_IN_BREAK;
3492 MINT_IN_CASE(MINT_BGE_R4_S)
3493 CONDBR_S(!isunordered (sp [0].data.f_r4, sp [1].data.f_r4) && sp[0].data.f_r4 >= sp[1].data.f_r4)
3494 MINT_IN_BREAK;
3495 MINT_IN_CASE(MINT_BGE_R8_S)
3496 CONDBR_S(!mono_isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f >= sp[1].data.f)
3497 MINT_IN_BREAK;
3498 MINT_IN_CASE(MINT_BGE_I4)
3499 BRELOP(i, >=)
3500 MINT_IN_BREAK;
3501 MINT_IN_CASE(MINT_BGE_I8)
3502 BRELOP(l, >=)
3503 MINT_IN_BREAK;
3504 MINT_IN_CASE(MINT_BGE_R4)
3505 CONDBR(!isunordered (sp [0].data.f_r4, sp [1].data.f_r4) && sp[0].data.f_r4 >= sp[1].data.f_r4)
3506 MINT_IN_BREAK;
3507 MINT_IN_CASE(MINT_BGE_R8)
3508 CONDBR(!mono_isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f >= sp[1].data.f)
3509 MINT_IN_BREAK;
3510 MINT_IN_CASE(MINT_BGT_I4_S)
3511 BRELOP_S(i, >)
3512 MINT_IN_BREAK;
3513 MINT_IN_CASE(MINT_BGT_I8_S)
3514 BRELOP_S(l, >)
3515 MINT_IN_BREAK;
3516 MINT_IN_CASE(MINT_BGT_R4_S)
3517 CONDBR_S(!isunordered (sp [0].data.f_r4, sp [1].data.f_r4) && sp[0].data.f_r4 > sp[1].data.f_r4)
3518 MINT_IN_BREAK;
3519 MINT_IN_CASE(MINT_BGT_R8_S)
3520 CONDBR_S(!mono_isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f > sp[1].data.f)
3521 MINT_IN_BREAK;
3522 MINT_IN_CASE(MINT_BGT_I4)
3523 BRELOP(i, >)
3524 MINT_IN_BREAK;
3525 MINT_IN_CASE(MINT_BGT_I8)
3526 BRELOP(l, >)
3527 MINT_IN_BREAK;
3528 MINT_IN_CASE(MINT_BGT_R4)
3529 CONDBR(!isunordered (sp [0].data.f_r4, sp [1].data.f_r4) && sp[0].data.f_r4 > sp[1].data.f_r4)
3530 MINT_IN_BREAK;
3531 MINT_IN_CASE(MINT_BGT_R8)
3532 CONDBR(!mono_isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f > sp[1].data.f)
3533 MINT_IN_BREAK;
3534 MINT_IN_CASE(MINT_BLT_I4_S)
3535 BRELOP_S(i, <)
3536 MINT_IN_BREAK;
3537 MINT_IN_CASE(MINT_BLT_I8_S)
3538 BRELOP_S(l, <)
3539 MINT_IN_BREAK;
3540 MINT_IN_CASE(MINT_BLT_R4_S)
3541 CONDBR_S(!isunordered (sp [0].data.f_r4, sp [1].data.f_r4) && sp[0].data.f_r4 < sp[1].data.f_r4)
3542 MINT_IN_BREAK;
3543 MINT_IN_CASE(MINT_BLT_R8_S)
3544 CONDBR_S(!mono_isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f < sp[1].data.f)
3545 MINT_IN_BREAK;
3546 MINT_IN_CASE(MINT_BLT_I4)
3547 BRELOP(i, <)
3548 MINT_IN_BREAK;
3549 MINT_IN_CASE(MINT_BLT_I8)
3550 BRELOP(l, <)
3551 MINT_IN_BREAK;
3552 MINT_IN_CASE(MINT_BLT_R4)
3553 CONDBR(!isunordered (sp [0].data.f_r4, sp [1].data.f_r4) && sp[0].data.f_r4 < sp[1].data.f_r4)
3554 MINT_IN_BREAK;
3555 MINT_IN_CASE(MINT_BLT_R8)
3556 CONDBR(!mono_isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f < sp[1].data.f)
3557 MINT_IN_BREAK;
3558 MINT_IN_CASE(MINT_BLE_I4_S)
3559 BRELOP_S(i, <=)
3560 MINT_IN_BREAK;
3561 MINT_IN_CASE(MINT_BLE_I8_S)
3562 BRELOP_S(l, <=)
3563 MINT_IN_BREAK;
3564 MINT_IN_CASE(MINT_BLE_R4_S)
3565 CONDBR_S(!isunordered (sp [0].data.f_r4, sp [1].data.f_r4) && sp[0].data.f_r4 <= sp[1].data.f_r4)
3566 MINT_IN_BREAK;
3567 MINT_IN_CASE(MINT_BLE_R8_S)
3568 CONDBR_S(!mono_isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f <= sp[1].data.f)
3569 MINT_IN_BREAK;
3570 MINT_IN_CASE(MINT_BLE_I4)
3571 BRELOP(i, <=)
3572 MINT_IN_BREAK;
3573 MINT_IN_CASE(MINT_BLE_I8)
3574 BRELOP(l, <=)
3575 MINT_IN_BREAK;
3576 MINT_IN_CASE(MINT_BLE_R4)
3577 CONDBR(!isunordered (sp [0].data.f_r4, sp [1].data.f_r4) && sp[0].data.f_r4 <= sp[1].data.f_r4)
3578 MINT_IN_BREAK;
3579 MINT_IN_CASE(MINT_BLE_R8)
3580 CONDBR(!mono_isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f <= sp[1].data.f)
3581 MINT_IN_BREAK;
3582 MINT_IN_CASE(MINT_BNE_UN_I4_S)
3583 BRELOP_S(i, !=)
3584 MINT_IN_BREAK;
3585 MINT_IN_CASE(MINT_BNE_UN_I8_S)
3586 BRELOP_S(l, !=)
3587 MINT_IN_BREAK;
3588 MINT_IN_CASE(MINT_BNE_UN_R4_S)
3589 CONDBR_S(isunordered (sp [0].data.f_r4, sp [1].data.f_r4) || sp[0].data.f_r4 != sp[1].data.f_r4)
3590 MINT_IN_BREAK;
3591 MINT_IN_CASE(MINT_BNE_UN_R8_S)
3592 CONDBR_S(mono_isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f != sp[1].data.f)
3593 MINT_IN_BREAK;
3594 MINT_IN_CASE(MINT_BNE_UN_I4)
3595 BRELOP(i, !=)
3596 MINT_IN_BREAK;
3597 MINT_IN_CASE(MINT_BNE_UN_I8)
3598 BRELOP(l, !=)
3599 MINT_IN_BREAK;
3600 MINT_IN_CASE(MINT_BNE_UN_R4)
3601 CONDBR(isunordered (sp [0].data.f_r4, sp [1].data.f_r4) || sp[0].data.f_r4 != sp[1].data.f_r4)
3602 MINT_IN_BREAK;
3603 MINT_IN_CASE(MINT_BNE_UN_R8)
3604 CONDBR(mono_isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f != sp[1].data.f)
3605 MINT_IN_BREAK;
3607 #define BRELOP_S_CAST(datamem, op, type) \
3608 sp -= 2; \
3609 if ((type) sp[0].data.datamem op (type) sp[1].data.datamem) \
3610 ip += * (gint16 *)(ip + 1); \
3611 else \
3612 ip += 2;
3614 #define BRELOP_CAST(datamem, op, type) \
3615 sp -= 2; \
3616 if ((type) sp[0].data.datamem op (type) sp[1].data.datamem) \
3617 ip += (gint32)READ32(ip + 1); \
3618 else \
3619 ip += 3;
3621 MINT_IN_CASE(MINT_BGE_UN_I4_S)
3622 BRELOP_S_CAST(i, >=, guint32);
3623 MINT_IN_BREAK;
3624 MINT_IN_CASE(MINT_BGE_UN_I8_S)
3625 BRELOP_S_CAST(l, >=, guint64);
3626 MINT_IN_BREAK;
3627 MINT_IN_CASE(MINT_BGE_UN_R4_S)
3628 CONDBR_S(isunordered (sp [0].data.f_r4, sp [1].data.f_r4) || sp[0].data.f_r4 >= sp[1].data.f_r4)
3629 MINT_IN_BREAK;
3630 MINT_IN_CASE(MINT_BGE_UN_R8_S)
3631 CONDBR_S(mono_isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f >= sp[1].data.f)
3632 MINT_IN_BREAK;
3633 MINT_IN_CASE(MINT_BGE_UN_I4)
3634 BRELOP_CAST(i, >=, guint32);
3635 MINT_IN_BREAK;
3636 MINT_IN_CASE(MINT_BGE_UN_I8)
3637 BRELOP_CAST(l, >=, guint64);
3638 MINT_IN_BREAK;
3639 MINT_IN_CASE(MINT_BGE_UN_R4)
3640 CONDBR(isunordered (sp [0].data.f_r4, sp [1].data.f_r4) || sp[0].data.f_r4 >= sp[1].data.f_r4)
3641 MINT_IN_BREAK;
3642 MINT_IN_CASE(MINT_BGE_UN_R8)
3643 CONDBR(mono_isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f >= sp[1].data.f)
3644 MINT_IN_BREAK;
3645 MINT_IN_CASE(MINT_BGT_UN_I4_S)
3646 BRELOP_S_CAST(i, >, guint32);
3647 MINT_IN_BREAK;
3648 MINT_IN_CASE(MINT_BGT_UN_I8_S)
3649 BRELOP_S_CAST(l, >, guint64);
3650 MINT_IN_BREAK;
3651 MINT_IN_CASE(MINT_BGT_UN_R4_S)
3652 CONDBR_S(isunordered (sp [0].data.f_r4, sp [1].data.f_r4) || sp[0].data.f_r4 > sp[1].data.f_r4)
3653 MINT_IN_BREAK;
3654 MINT_IN_CASE(MINT_BGT_UN_R8_S)
3655 CONDBR_S(mono_isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f > sp[1].data.f)
3656 MINT_IN_BREAK;
3657 MINT_IN_CASE(MINT_BGT_UN_I4)
3658 BRELOP_CAST(i, >, guint32);
3659 MINT_IN_BREAK;
3660 MINT_IN_CASE(MINT_BGT_UN_I8)
3661 BRELOP_CAST(l, >, guint64);
3662 MINT_IN_BREAK;
3663 MINT_IN_CASE(MINT_BGT_UN_R4)
3664 CONDBR(isunordered (sp [0].data.f_r4, sp [1].data.f_r4) || sp[0].data.f_r4 > sp[1].data.f_r4)
3665 MINT_IN_BREAK;
3666 MINT_IN_CASE(MINT_BGT_UN_R8)
3667 CONDBR(mono_isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f > sp[1].data.f)
3668 MINT_IN_BREAK;
3669 MINT_IN_CASE(MINT_BLE_UN_I4_S)
3670 BRELOP_S_CAST(i, <=, guint32);
3671 MINT_IN_BREAK;
3672 MINT_IN_CASE(MINT_BLE_UN_I8_S)
3673 BRELOP_S_CAST(l, <=, guint64);
3674 MINT_IN_BREAK;
3675 MINT_IN_CASE(MINT_BLE_UN_R4_S)
3676 CONDBR_S(isunordered (sp [0].data.f_r4, sp [1].data.f_r4) || sp[0].data.f_r4 <= sp[1].data.f_r4)
3677 MINT_IN_BREAK;
3678 MINT_IN_CASE(MINT_BLE_UN_R8_S)
3679 CONDBR_S(mono_isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f <= sp[1].data.f)
3680 MINT_IN_BREAK;
3681 MINT_IN_CASE(MINT_BLE_UN_I4)
3682 BRELOP_CAST(i, <=, guint32);
3683 MINT_IN_BREAK;
3684 MINT_IN_CASE(MINT_BLE_UN_I8)
3685 BRELOP_CAST(l, <=, guint64);
3686 MINT_IN_BREAK;
3687 MINT_IN_CASE(MINT_BLE_UN_R4)
3688 CONDBR(isunordered (sp [0].data.f_r4, sp [1].data.f_r4) || sp[0].data.f_r4 <= sp[1].data.f_r4)
3689 MINT_IN_BREAK;
3690 MINT_IN_CASE(MINT_BLE_UN_R8)
3691 CONDBR(mono_isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f <= sp[1].data.f)
3692 MINT_IN_BREAK;
3693 MINT_IN_CASE(MINT_BLT_UN_I4_S)
3694 BRELOP_S_CAST(i, <, guint32);
3695 MINT_IN_BREAK;
3696 MINT_IN_CASE(MINT_BLT_UN_I8_S)
3697 BRELOP_S_CAST(l, <, guint64);
3698 MINT_IN_BREAK;
3699 MINT_IN_CASE(MINT_BLT_UN_R4_S)
3700 CONDBR_S(isunordered (sp [0].data.f_r4, sp [1].data.f_r4) || sp[0].data.f_r4 < sp[1].data.f_r4)
3701 MINT_IN_BREAK;
3702 MINT_IN_CASE(MINT_BLT_UN_R8_S)
3703 CONDBR_S(mono_isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f < sp[1].data.f)
3704 MINT_IN_BREAK;
3705 MINT_IN_CASE(MINT_BLT_UN_I4)
3706 BRELOP_CAST(i, <, guint32);
3707 MINT_IN_BREAK;
3708 MINT_IN_CASE(MINT_BLT_UN_I8)
3709 BRELOP_CAST(l, <, guint64);
3710 MINT_IN_BREAK;
3711 MINT_IN_CASE(MINT_BLT_UN_R4)
3712 CONDBR(isunordered (sp [0].data.f_r4, sp [1].data.f_r4) || sp[0].data.f_r4 < sp[1].data.f_r4)
3713 MINT_IN_BREAK;
3714 MINT_IN_CASE(MINT_BLT_UN_R8)
3715 CONDBR(mono_isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f < sp[1].data.f)
3716 MINT_IN_BREAK;
3717 MINT_IN_CASE(MINT_SWITCH) {
3718 guint32 n;
3719 const unsigned short *st;
3720 ++ip;
3721 n = READ32 (ip);
3722 ip += 2;
3723 st = ip + 2 * n;
3724 --sp;
3725 if ((guint32)sp->data.i < n) {
3726 gint offset;
3727 ip += 2 * (guint32)sp->data.i;
3728 offset = READ32 (ip);
3729 ip = ip + offset;
3730 } else {
3731 ip = st;
3733 MINT_IN_BREAK;
3735 MINT_IN_CASE(MINT_LDIND_I1_CHECK)
3736 if (!sp[-1].data.p)
3737 THROW_EX (mono_get_exception_null_reference (), ip);
3738 ++ip;
3739 sp[-1].data.i = *(gint8*)sp[-1].data.p;
3740 MINT_IN_BREAK;
3741 MINT_IN_CASE(MINT_LDIND_U1_CHECK)
3742 if (!sp[-1].data.p)
3743 THROW_EX (mono_get_exception_null_reference (), ip);
3744 ++ip;
3745 sp[-1].data.i = *(guint8*)sp[-1].data.p;
3746 MINT_IN_BREAK;
3747 MINT_IN_CASE(MINT_LDIND_I2_CHECK)
3748 if (!sp[-1].data.p)
3749 THROW_EX (mono_get_exception_null_reference (), ip);
3750 ++ip;
3751 sp[-1].data.i = *(gint16*)sp[-1].data.p;
3752 MINT_IN_BREAK;
3753 MINT_IN_CASE(MINT_LDIND_U2_CHECK)
3754 if (!sp[-1].data.p)
3755 THROW_EX (mono_get_exception_null_reference (), ip);
3756 ++ip;
3757 sp[-1].data.i = *(guint16*)sp[-1].data.p;
3758 MINT_IN_BREAK;
3759 MINT_IN_CASE(MINT_LDIND_I4_CHECK) /* Fall through */
3760 MINT_IN_CASE(MINT_LDIND_U4_CHECK)
3761 if (!sp[-1].data.p)
3762 THROW_EX (mono_get_exception_null_reference (), ip);
3763 ++ip;
3764 sp[-1].data.i = *(gint32*)sp[-1].data.p;
3765 MINT_IN_BREAK;
3766 MINT_IN_CASE(MINT_LDIND_I8_CHECK)
3767 if (!sp[-1].data.p)
3768 THROW_EX (mono_get_exception_null_reference (), ip);
3769 ++ip;
3770 #ifdef NO_UNALIGNED_ACCESS
3771 if ((gsize)sp [-1].data.p % SIZEOF_VOID_P)
3772 memcpy (&sp [-1].data.l, sp [-1].data.p, sizeof (gint64));
3773 else
3774 #endif
3775 sp[-1].data.l = *(gint64*)sp[-1].data.p;
3776 MINT_IN_BREAK;
3777 MINT_IN_CASE(MINT_LDIND_I) {
3778 guint16 offset = * (guint16 *)(ip + 1);
3779 sp[-1 - offset].data.p = *(gpointer*)sp[-1 - offset].data.p;
3780 ip += 2;
3781 MINT_IN_BREAK;
3783 MINT_IN_CASE(MINT_LDIND_I8) {
3784 guint16 offset = * (guint16 *)(ip + 1);
3785 #ifdef NO_UNALIGNED_ACCESS
3786 if ((gsize)sp [-1 - offset].data.p % SIZEOF_VOID_P)
3787 memcpy (&sp [-1 - offset].data.l, sp [-1 - offset].data.p, sizeof (gint64));
3788 else
3789 #endif
3790 sp[-1 - offset].data.l = *(gint64*)sp[-1 - offset].data.p;
3791 ip += 2;
3792 MINT_IN_BREAK;
3794 MINT_IN_CASE(MINT_LDIND_R4_CHECK)
3795 if (!sp[-1].data.p)
3796 THROW_EX (mono_get_exception_null_reference (), ip);
3797 ++ip;
3798 sp[-1].data.f_r4 = *(gfloat*)sp[-1].data.p;
3799 MINT_IN_BREAK;
3800 MINT_IN_CASE(MINT_LDIND_R8_CHECK)
3801 if (!sp[-1].data.p)
3802 THROW_EX (mono_get_exception_null_reference (), ip);
3803 ++ip;
3804 #ifdef NO_UNALIGNED_ACCESS
3805 if ((gsize)sp [-1].data.p % SIZEOF_VOID_P)
3806 memcpy (&sp [-1].data.f, sp [-1].data.p, sizeof (gdouble));
3807 else
3808 #endif
3809 sp[-1].data.f = *(gdouble*)sp[-1].data.p;
3810 MINT_IN_BREAK;
3811 MINT_IN_CASE(MINT_LDIND_REF)
3812 ++ip;
3813 sp[-1].data.p = *(gpointer*)sp[-1].data.p;
3814 MINT_IN_BREAK;
3815 MINT_IN_CASE(MINT_LDIND_REF_CHECK) {
3816 if (!sp [-1].data.p)
3817 THROW_EX (mono_get_exception_null_reference (), ip);
3818 ++ip;
3819 sp [-1].data.p = *(gpointer*)sp [-1].data.p;
3820 MINT_IN_BREAK;
3822 MINT_IN_CASE(MINT_STIND_REF)
3823 ++ip;
3824 sp -= 2;
3825 mono_gc_wbarrier_generic_store_internal (sp->data.p, sp [1].data.o);
3826 MINT_IN_BREAK;
3827 MINT_IN_CASE(MINT_STIND_I1)
3828 ++ip;
3829 sp -= 2;
3830 * (gint8 *) sp->data.p = (gint8)sp[1].data.i;
3831 MINT_IN_BREAK;
3832 MINT_IN_CASE(MINT_STIND_I2)
3833 ++ip;
3834 sp -= 2;
3835 * (gint16 *) sp->data.p = (gint16)sp[1].data.i;
3836 MINT_IN_BREAK;
3837 MINT_IN_CASE(MINT_STIND_I4)
3838 ++ip;
3839 sp -= 2;
3840 * (gint32 *) sp->data.p = sp[1].data.i;
3841 MINT_IN_BREAK;
3842 MINT_IN_CASE(MINT_STIND_I)
3843 ++ip;
3844 sp -= 2;
3845 * (mono_i *) sp->data.p = (mono_i)sp[1].data.p;
3846 MINT_IN_BREAK;
3847 MINT_IN_CASE(MINT_STIND_I8)
3848 ++ip;
3849 sp -= 2;
3850 #ifdef NO_UNALIGNED_ACCESS
3851 if ((gsize)sp->data.p % SIZEOF_VOID_P)
3852 memcpy (sp->data.p, &sp [1].data.l, sizeof (gint64));
3853 else
3854 #endif
3855 * (gint64 *) sp->data.p = sp[1].data.l;
3856 MINT_IN_BREAK;
3857 MINT_IN_CASE(MINT_STIND_R4)
3858 ++ip;
3859 sp -= 2;
3860 * (float *) sp->data.p = sp[1].data.f_r4;
3861 MINT_IN_BREAK;
3862 MINT_IN_CASE(MINT_STIND_R8)
3863 ++ip;
3864 sp -= 2;
3865 #ifdef NO_UNALIGNED_ACCESS
3866 if ((gsize)sp->data.p % SIZEOF_VOID_P)
3867 memcpy (sp->data.p, &sp [1].data.f, sizeof (double));
3868 else
3869 #endif
3870 * (double *) sp->data.p = sp[1].data.f;
3871 MINT_IN_BREAK;
3872 MINT_IN_CASE(MINT_MONO_ATOMIC_STORE_I4)
3873 ++ip;
3874 sp -= 2;
3875 mono_atomic_store_i32 ((gint32 *) sp->data.p, sp [1].data.i);
3876 MINT_IN_BREAK;
3877 #define BINOP(datamem, op) \
3878 --sp; \
3879 sp [-1].data.datamem = sp [-1].data.datamem op sp [0].data.datamem; \
3880 ++ip;
3881 MINT_IN_CASE(MINT_ADD_I4)
3882 BINOP(i, +);
3883 MINT_IN_BREAK;
3884 MINT_IN_CASE(MINT_ADD_I8)
3885 BINOP(l, +);
3886 MINT_IN_BREAK;
3887 MINT_IN_CASE(MINT_ADD_R4)
3888 BINOP(f_r4, +);
3889 MINT_IN_BREAK;
3890 MINT_IN_CASE(MINT_ADD_R8)
3891 BINOP(f, +);
3892 MINT_IN_BREAK;
3893 MINT_IN_CASE(MINT_ADD1_I4)
3894 ++sp [-1].data.i;
3895 ++ip;
3896 MINT_IN_BREAK;
3897 MINT_IN_CASE(MINT_ADD1_I8)
3898 ++sp [-1].data.l;
3899 ++ip;
3900 MINT_IN_BREAK;
3901 MINT_IN_CASE(MINT_SUB_I4)
3902 BINOP(i, -);
3903 MINT_IN_BREAK;
3904 MINT_IN_CASE(MINT_SUB_I8)
3905 BINOP(l, -);
3906 MINT_IN_BREAK;
3907 MINT_IN_CASE(MINT_SUB_R4)
3908 BINOP(f_r4, -);
3909 MINT_IN_BREAK;
3910 MINT_IN_CASE(MINT_SUB_R8)
3911 BINOP(f, -);
3912 MINT_IN_BREAK;
3913 MINT_IN_CASE(MINT_SUB1_I4)
3914 --sp [-1].data.i;
3915 ++ip;
3916 MINT_IN_BREAK;
3917 MINT_IN_CASE(MINT_SUB1_I8)
3918 --sp [-1].data.l;
3919 ++ip;
3920 MINT_IN_BREAK;
3921 MINT_IN_CASE(MINT_MUL_I4)
3922 BINOP(i, *);
3923 MINT_IN_BREAK;
3924 MINT_IN_CASE(MINT_MUL_I8)
3925 BINOP(l, *);
3926 MINT_IN_BREAK;
3927 MINT_IN_CASE(MINT_MUL_R4)
3928 BINOP(f_r4, *);
3929 MINT_IN_BREAK;
3930 MINT_IN_CASE(MINT_MUL_R8)
3931 BINOP(f, *);
3932 MINT_IN_BREAK;
3933 MINT_IN_CASE(MINT_DIV_I4)
3934 if (sp [-1].data.i == 0)
3935 THROW_EX (mono_get_exception_divide_by_zero (), ip);
3936 if (sp [-1].data.i == (-1) && sp [-2].data.i == G_MININT32)
3937 THROW_EX (mono_get_exception_overflow (), ip);
3938 BINOP(i, /);
3939 MINT_IN_BREAK;
3940 MINT_IN_CASE(MINT_DIV_I8)
3941 if (sp [-1].data.l == 0)
3942 THROW_EX (mono_get_exception_divide_by_zero (), ip);
3943 if (sp [-1].data.l == (-1) && sp [-2].data.l == G_MININT64)
3944 THROW_EX (mono_get_exception_overflow (), ip);
3945 BINOP(l, /);
3946 MINT_IN_BREAK;
3947 MINT_IN_CASE(MINT_DIV_R4)
3948 BINOP(f_r4, /);
3949 MINT_IN_BREAK;
3950 MINT_IN_CASE(MINT_DIV_R8)
3951 BINOP(f, /);
3952 MINT_IN_BREAK;
3954 #define BINOP_CAST(datamem, op, type) \
3955 --sp; \
3956 sp [-1].data.datamem = (type)sp [-1].data.datamem op (type)sp [0].data.datamem; \
3957 ++ip;
3958 MINT_IN_CASE(MINT_DIV_UN_I4)
3959 if (sp [-1].data.i == 0)
3960 THROW_EX (mono_get_exception_divide_by_zero (), ip);
3961 BINOP_CAST(i, /, guint32);
3962 MINT_IN_BREAK;
3963 MINT_IN_CASE(MINT_DIV_UN_I8)
3964 if (sp [-1].data.l == 0)
3965 THROW_EX (mono_get_exception_divide_by_zero (), ip);
3966 BINOP_CAST(l, /, guint64);
3967 MINT_IN_BREAK;
3968 MINT_IN_CASE(MINT_REM_I4)
3969 if (sp [-1].data.i == 0)
3970 THROW_EX (mono_get_exception_divide_by_zero (), ip);
3971 if (sp [-1].data.i == (-1) && sp [-2].data.i == G_MININT32)
3972 THROW_EX (mono_get_exception_overflow (), ip);
3973 BINOP(i, %);
3974 MINT_IN_BREAK;
3975 MINT_IN_CASE(MINT_REM_I8)
3976 if (sp [-1].data.l == 0)
3977 THROW_EX (mono_get_exception_divide_by_zero (), ip);
3978 if (sp [-1].data.l == (-1) && sp [-2].data.l == G_MININT64)
3979 THROW_EX (mono_get_exception_overflow (), ip);
3980 BINOP(l, %);
3981 MINT_IN_BREAK;
3982 MINT_IN_CASE(MINT_REM_R4)
3983 /* FIXME: what do we actually do here? */
3984 --sp;
3985 sp [-1].data.f_r4 = fmodf (sp [-1].data.f_r4, sp [0].data.f_r4);
3986 ++ip;
3987 MINT_IN_BREAK;
3988 MINT_IN_CASE(MINT_REM_R8)
3989 /* FIXME: what do we actually do here? */
3990 --sp;
3991 sp [-1].data.f = fmod (sp [-1].data.f, sp [0].data.f);
3992 ++ip;
3993 MINT_IN_BREAK;
3994 MINT_IN_CASE(MINT_REM_UN_I4)
3995 if (sp [-1].data.i == 0)
3996 THROW_EX (mono_get_exception_divide_by_zero (), ip);
3997 BINOP_CAST(i, %, guint32);
3998 MINT_IN_BREAK;
3999 MINT_IN_CASE(MINT_REM_UN_I8)
4000 if (sp [-1].data.l == 0)
4001 THROW_EX (mono_get_exception_divide_by_zero (), ip);
4002 BINOP_CAST(l, %, guint64);
4003 MINT_IN_BREAK;
4004 MINT_IN_CASE(MINT_AND_I4)
4005 BINOP(i, &);
4006 MINT_IN_BREAK;
4007 MINT_IN_CASE(MINT_AND_I8)
4008 BINOP(l, &);
4009 MINT_IN_BREAK;
4010 MINT_IN_CASE(MINT_OR_I4)
4011 BINOP(i, |);
4012 MINT_IN_BREAK;
4013 MINT_IN_CASE(MINT_OR_I8)
4014 BINOP(l, |);
4015 MINT_IN_BREAK;
4016 MINT_IN_CASE(MINT_XOR_I4)
4017 BINOP(i, ^);
4018 MINT_IN_BREAK;
4019 MINT_IN_CASE(MINT_XOR_I8)
4020 BINOP(l, ^);
4021 MINT_IN_BREAK;
4023 #define SHIFTOP(datamem, op) \
4024 --sp; \
4025 sp [-1].data.datamem = sp [-1].data.datamem op sp [0].data.i; \
4026 ++ip;
4028 MINT_IN_CASE(MINT_SHL_I4)
4029 SHIFTOP(i, <<);
4030 MINT_IN_BREAK;
4031 MINT_IN_CASE(MINT_SHL_I8)
4032 SHIFTOP(l, <<);
4033 MINT_IN_BREAK;
4034 MINT_IN_CASE(MINT_SHR_I4)
4035 SHIFTOP(i, >>);
4036 MINT_IN_BREAK;
4037 MINT_IN_CASE(MINT_SHR_I8)
4038 SHIFTOP(l, >>);
4039 MINT_IN_BREAK;
4040 MINT_IN_CASE(MINT_SHR_UN_I4)
4041 --sp;
4042 sp [-1].data.i = (guint32)sp [-1].data.i >> sp [0].data.i;
4043 ++ip;
4044 MINT_IN_BREAK;
4045 MINT_IN_CASE(MINT_SHR_UN_I8)
4046 --sp;
4047 sp [-1].data.l = (guint64)sp [-1].data.l >> sp [0].data.i;
4048 ++ip;
4049 MINT_IN_BREAK;
4050 MINT_IN_CASE(MINT_NEG_I4)
4051 sp [-1].data.i = - sp [-1].data.i;
4052 ++ip;
4053 MINT_IN_BREAK;
4054 MINT_IN_CASE(MINT_NEG_I8)
4055 sp [-1].data.l = - sp [-1].data.l;
4056 ++ip;
4057 MINT_IN_BREAK;
4058 MINT_IN_CASE(MINT_NEG_R4)
4059 sp [-1].data.f_r4 = - sp [-1].data.f_r4;
4060 ++ip;
4061 MINT_IN_BREAK;
4062 MINT_IN_CASE(MINT_NEG_R8)
4063 sp [-1].data.f = - sp [-1].data.f;
4064 ++ip;
4065 MINT_IN_BREAK;
4066 MINT_IN_CASE(MINT_NOT_I4)
4067 sp [-1].data.i = ~ sp [-1].data.i;
4068 ++ip;
4069 MINT_IN_BREAK;
4070 MINT_IN_CASE(MINT_NOT_I8)
4071 sp [-1].data.l = ~ sp [-1].data.l;
4072 ++ip;
4073 MINT_IN_BREAK;
4074 MINT_IN_CASE(MINT_CONV_I1_I4)
4075 sp [-1].data.i = (gint8)sp [-1].data.i;
4076 ++ip;
4077 MINT_IN_BREAK;
4078 MINT_IN_CASE(MINT_CONV_I1_I8)
4079 sp [-1].data.i = (gint8)sp [-1].data.l;
4080 ++ip;
4081 MINT_IN_BREAK;
4082 MINT_IN_CASE(MINT_CONV_I1_R4)
4083 sp [-1].data.i = (gint8) (gint32) sp [-1].data.f_r4;
4084 ++ip;
4085 MINT_IN_BREAK;
4086 MINT_IN_CASE(MINT_CONV_I1_R8)
4087 /* without gint32 cast, C compiler is allowed to use undefined
4088 * behaviour if data.f is bigger than >255. See conv.fpint section
4089 * in C standard:
4090 * > The conversion truncates; that is, the fractional part
4091 * > is discarded. The behavior is undefined if the truncated
4092 * > value cannot be represented in the destination type.
4093 * */
4094 sp [-1].data.i = (gint8) (gint32) sp [-1].data.f;
4095 ++ip;
4096 MINT_IN_BREAK;
4097 MINT_IN_CASE(MINT_CONV_U1_I4)
4098 sp [-1].data.i = (guint8)sp [-1].data.i;
4099 ++ip;
4100 MINT_IN_BREAK;
4101 MINT_IN_CASE(MINT_CONV_U1_I8)
4102 sp [-1].data.i = (guint8)sp [-1].data.l;
4103 ++ip;
4104 MINT_IN_BREAK;
4105 MINT_IN_CASE(MINT_CONV_U1_R4)
4106 sp [-1].data.i = (guint8) (guint32) sp [-1].data.f_r4;
4107 ++ip;
4108 MINT_IN_BREAK;
4109 MINT_IN_CASE(MINT_CONV_U1_R8)
4110 sp [-1].data.i = (guint8) (guint32) sp [-1].data.f;
4111 ++ip;
4112 MINT_IN_BREAK;
4113 MINT_IN_CASE(MINT_CONV_I2_I4)
4114 sp [-1].data.i = (gint16)sp [-1].data.i;
4115 ++ip;
4116 MINT_IN_BREAK;
4117 MINT_IN_CASE(MINT_CONV_I2_I8)
4118 sp [-1].data.i = (gint16)sp [-1].data.l;
4119 ++ip;
4120 MINT_IN_BREAK;
4121 MINT_IN_CASE(MINT_CONV_I2_R4)
4122 sp [-1].data.i = (gint16) (gint32) sp [-1].data.f_r4;
4123 ++ip;
4124 MINT_IN_BREAK;
4125 MINT_IN_CASE(MINT_CONV_I2_R8)
4126 sp [-1].data.i = (gint16) (gint32) sp [-1].data.f;
4127 ++ip;
4128 MINT_IN_BREAK;
4129 MINT_IN_CASE(MINT_CONV_U2_I4)
4130 sp [-1].data.i = (guint16)sp [-1].data.i;
4131 ++ip;
4132 MINT_IN_BREAK;
4133 MINT_IN_CASE(MINT_CONV_U2_I8)
4134 sp [-1].data.i = (guint16)sp [-1].data.l;
4135 ++ip;
4136 MINT_IN_BREAK;
4137 MINT_IN_CASE(MINT_CONV_U2_R4)
4138 sp [-1].data.i = (guint16) (guint32) sp [-1].data.f_r4;
4139 ++ip;
4140 MINT_IN_BREAK;
4141 MINT_IN_CASE(MINT_CONV_U2_R8)
4142 sp [-1].data.i = (guint16) (guint32) sp [-1].data.f;
4143 ++ip;
4144 MINT_IN_BREAK;
4145 MINT_IN_CASE(MINT_CONV_I4_R4)
4146 sp [-1].data.i = (gint32) sp [-1].data.f_r4;
4147 ++ip;
4148 MINT_IN_BREAK;
4149 MINT_IN_CASE(MINT_CONV_I4_R8)
4150 sp [-1].data.i = (gint32)sp [-1].data.f;
4151 ++ip;
4152 MINT_IN_BREAK;
4153 MINT_IN_CASE(MINT_CONV_U4_I8)
4154 MINT_IN_CASE(MINT_CONV_I4_I8)
4155 sp [-1].data.i = (gint32)sp [-1].data.l;
4156 ++ip;
4157 MINT_IN_BREAK;
4158 MINT_IN_CASE(MINT_CONV_I4_I8_SP)
4159 sp [-2].data.i = (gint32)sp [-2].data.l;
4160 ++ip;
4161 MINT_IN_BREAK;
4162 MINT_IN_CASE(MINT_CONV_U4_R4)
4163 /* needed on arm64 */
4164 if (isinf (sp [-1].data.f_r4))
4165 sp [-1].data.i = 0;
4166 /* needed by wasm */
4167 else if (isnan (sp [-1].data.f_r4))
4168 sp [-1].data.i = 0;
4169 else
4170 sp [-1].data.i = (guint32) sp [-1].data.f_r4;
4171 ++ip;
4172 MINT_IN_BREAK;
4173 MINT_IN_CASE(MINT_CONV_U4_R8)
4174 /* needed on arm64 */
4175 if (mono_isinf (sp [-1].data.f))
4176 sp [-1].data.i = 0;
4177 /* needed by wasm */
4178 else if (isnan (sp [-1].data.f))
4179 sp [-1].data.i = 0;
4180 else
4181 sp [-1].data.i = (guint32)sp [-1].data.f;
4182 ++ip;
4183 MINT_IN_BREAK;
4184 MINT_IN_CASE(MINT_CONV_I8_I4)
4185 sp [-1].data.l = sp [-1].data.i;
4186 ++ip;
4187 MINT_IN_BREAK;
4188 MINT_IN_CASE(MINT_CONV_I8_I4_SP)
4189 sp [-2].data.l = sp [-2].data.i;
4190 ++ip;
4191 MINT_IN_BREAK;
4192 MINT_IN_CASE(MINT_CONV_I8_U4)
4193 sp [-1].data.l = (guint32)sp [-1].data.i;
4194 ++ip;
4195 MINT_IN_BREAK;
4196 MINT_IN_CASE(MINT_CONV_I8_R4)
4197 sp [-1].data.l = (gint64) sp [-1].data.f_r4;
4198 ++ip;
4199 MINT_IN_BREAK;
4200 MINT_IN_CASE(MINT_CONV_I8_R8)
4201 sp [-1].data.l = (gint64)sp [-1].data.f;
4202 ++ip;
4203 MINT_IN_BREAK;
4204 MINT_IN_CASE(MINT_CONV_R4_I4)
4205 sp [-1].data.f_r4 = (float)sp [-1].data.i;
4206 ++ip;
4207 MINT_IN_BREAK;
4208 MINT_IN_CASE(MINT_CONV_R4_I8)
4209 sp [-1].data.f_r4 = (float)sp [-1].data.l;
4210 ++ip;
4211 MINT_IN_BREAK;
4212 MINT_IN_CASE(MINT_CONV_R4_R8)
4213 sp [-1].data.f_r4 = (float)sp [-1].data.f;
4214 ++ip;
4215 MINT_IN_BREAK;
4216 MINT_IN_CASE(MINT_CONV_R8_I4)
4217 sp [-1].data.f = (double)sp [-1].data.i;
4218 ++ip;
4219 MINT_IN_BREAK;
4220 MINT_IN_CASE(MINT_CONV_R8_I8)
4221 sp [-1].data.f = (double)sp [-1].data.l;
4222 ++ip;
4223 MINT_IN_BREAK;
4224 MINT_IN_CASE(MINT_CONV_R8_R4)
4225 sp [-1].data.f = (double) sp [-1].data.f_r4;
4226 ++ip;
4227 MINT_IN_BREAK;
4228 MINT_IN_CASE(MINT_CONV_R8_R4_SP)
4229 sp [-2].data.f = (double) sp [-2].data.f_r4;
4230 ++ip;
4231 MINT_IN_BREAK;
4232 MINT_IN_CASE(MINT_CONV_U8_I4)
4233 sp [-1].data.l = sp [-1].data.i & 0xffffffff;
4234 ++ip;
4235 MINT_IN_BREAK;
4236 MINT_IN_CASE(MINT_CONV_U8_R4)
4237 sp [-1].data.l = (guint64) sp [-1].data.f_r4;
4238 ++ip;
4239 MINT_IN_BREAK;
4240 MINT_IN_CASE(MINT_CONV_U8_R8)
4241 sp [-1].data.l = (guint64)sp [-1].data.f;
4242 ++ip;
4243 MINT_IN_BREAK;
4244 MINT_IN_CASE(MINT_CPOBJ) {
4245 c = (MonoClass*)imethod->data_items[* (guint16 *)(ip + 1)];
4246 g_assert (m_class_is_valuetype (c));
4247 /* if this assertion fails, we need to add a write barrier */
4248 g_assert (!MONO_TYPE_IS_REFERENCE (m_class_get_byval_arg (c)));
4249 stackval_from_data (m_class_get_byval_arg (c), (stackval*)sp [-2].data.p, sp [-1].data.p, FALSE);
4250 ip += 2;
4251 sp -= 2;
4252 MINT_IN_BREAK;
4254 MINT_IN_CASE(MINT_CPOBJ_VT) {
4255 c = (MonoClass*)imethod->data_items[* (guint16 *)(ip + 1)];
4256 mono_value_copy_internal (sp [-2].data.vt, sp [-1].data.vt, c);
4257 ip += 2;
4258 sp -= 2;
4259 MINT_IN_BREAK;
4261 MINT_IN_CASE(MINT_LDOBJ_VT) {
4262 int size = READ32(ip + 1);
4263 ip += 3;
4264 memcpy (vt_sp, sp [-1].data.p, size);
4265 sp [-1].data.p = vt_sp;
4266 vt_sp += ALIGN_TO (size, MINT_VT_ALIGNMENT);
4267 MINT_IN_BREAK;
4269 MINT_IN_CASE(MINT_LDSTR)
4270 sp->data.p = imethod->data_items [* (guint16 *)(ip + 1)];
4271 ++sp;
4272 ip += 2;
4273 MINT_IN_BREAK;
4274 MINT_IN_CASE(MINT_LDSTR_TOKEN) {
4275 MonoString *s = NULL;
4276 guint32 strtoken = (guint32)(gsize)imethod->data_items [* (guint16 *)(ip + 1)];
4278 MonoMethod *method = imethod->method;
4279 if (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD) {
4280 s = (MonoString*)mono_method_get_wrapper_data (method, strtoken);
4281 } else if (method->wrapper_type != MONO_WRAPPER_NONE) {
4282 s = mono_string_new_wrapper_internal ((const char*)mono_method_get_wrapper_data (method, strtoken));
4283 } else {
4284 g_assert_not_reached ();
4286 sp->data.p = s;
4287 ++sp;
4288 ip += 2;
4289 MINT_IN_BREAK;
4291 MINT_IN_CASE(MINT_NEWOBJ_ARRAY) {
4292 MonoClass *newobj_class;
4293 guint32 token = * (guint16 *)(ip + 1);
4294 guint16 param_count = * (guint16 *)(ip + 2);
4296 newobj_class = ((InterpMethod*) imethod->data_items [token])->method->klass;
4298 sp -= param_count;
4299 sp->data.p = ves_array_create (imethod->domain, newobj_class, param_count, sp, error);
4300 if (!mono_error_ok (error))
4301 THROW_EX (mono_error_convert_to_exception (error), ip);
4303 ++sp;
4304 ip += 3;
4305 MINT_IN_BREAK;
4307 MINT_IN_CASE(MINT_NEWOBJ_FAST)
4308 MINT_IN_CASE(MINT_NEWOBJ_VT_FAST)
4309 MINT_IN_CASE(MINT_NEWOBJ_VTST_FAST) {
4310 guint16 param_count;
4311 gboolean vt = *ip != MINT_NEWOBJ_FAST;
4312 stackval valuetype_this;
4314 frame->ip = ip;
4316 child_frame.imethod = (InterpMethod*) imethod->data_items [*(guint16*)(ip + 1)];
4317 param_count = *(guint16*)(ip + 2);
4319 if (param_count) {
4320 sp -= param_count;
4321 memmove (sp + 1, sp, param_count * sizeof (stackval));
4323 child_frame.stack_args = sp;
4325 if (vt) {
4326 gboolean vtst = *ip == MINT_NEWOBJ_VTST_FAST;
4327 if (vtst) {
4328 memset (vt_sp, 0, *(guint16*)(ip + 3));
4329 sp->data.p = vt_sp;
4330 valuetype_this.data.p = vt_sp;
4331 ip += 4;
4332 } else {
4333 memset (&valuetype_this, 0, sizeof (stackval));
4334 sp->data.p = &valuetype_this;
4335 ip += 3;
4337 } else {
4338 MonoVTable *vtable = (MonoVTable*) imethod->data_items [*(guint16*)(ip + 3)];
4339 if (G_UNLIKELY (!vtable->initialized)) {
4340 mono_runtime_class_init_full (vtable, error);
4341 if (!mono_error_ok (error))
4342 THROW_EX (mono_error_convert_to_exception (error), ip);
4344 o = mono_gc_alloc_obj (vtable, m_class_get_instance_size (vtable->klass));
4345 if (G_UNLIKELY (!o)) {
4346 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", m_class_get_instance_size (vtable->klass));
4347 THROW_EX (mono_error_convert_to_exception (error), ip);
4349 sp->data.p = o;
4350 ip += 4;
4353 interp_exec_method (&child_frame, context);
4355 CHECK_RESUME_STATE (context);
4357 if (vt)
4358 *sp = valuetype_this;
4359 else
4360 sp->data.p = o;
4361 ++sp;
4362 MINT_IN_BREAK;
4364 MINT_IN_CASE(MINT_NEWOBJ) {
4365 MonoClass *newobj_class;
4366 MonoMethodSignature *csig;
4367 stackval valuetype_this;
4368 guint32 token;
4369 stackval retval;
4371 frame->ip = ip;
4373 token = * (guint16 *)(ip + 1);
4374 ip += 2;
4376 child_frame.ip = NULL;
4377 child_frame.ex = NULL;
4379 child_frame.imethod = (InterpMethod*)imethod->data_items [token];
4380 csig = mono_method_signature_internal (child_frame.imethod->method);
4381 newobj_class = child_frame.imethod->method->klass;
4382 /*if (profiling_classes) {
4383 guint count = GPOINTER_TO_UINT (g_hash_table_lookup (profiling_classes, newobj_class));
4384 count++;
4385 g_hash_table_insert (profiling_classes, newobj_class, GUINT_TO_POINTER (count));
4388 g_assert (csig->hasthis);
4389 if (csig->param_count) {
4390 sp -= csig->param_count;
4391 memmove (sp + 1, sp, csig->param_count * sizeof (stackval));
4393 child_frame.stack_args = sp;
4396 * First arg is the object.
4398 if (m_class_is_valuetype (newobj_class)) {
4399 MonoType *t = m_class_get_byval_arg (newobj_class);
4400 memset (&valuetype_this, 0, sizeof (stackval));
4401 if (!m_class_is_enumtype (newobj_class) && (t->type == MONO_TYPE_VALUETYPE || (t->type == MONO_TYPE_GENERICINST && mono_type_generic_inst_is_valuetype (t)))) {
4402 sp->data.p = vt_sp;
4403 valuetype_this.data.p = vt_sp;
4404 } else {
4405 sp->data.p = &valuetype_this;
4407 } else {
4408 if (newobj_class != mono_defaults.string_class) {
4409 MonoVTable *vtable = mono_class_vtable_checked (imethod->domain, newobj_class, error);
4410 if (!mono_error_ok (error) || !mono_runtime_class_init_full (vtable, error))
4411 THROW_EX (mono_error_convert_to_exception (error), ip);
4412 o = mono_object_new_checked (imethod->domain, newobj_class, error);
4413 mono_error_cleanup (error); /* FIXME: don't swallow the error */
4414 EXCEPTION_CHECKPOINT;
4415 sp->data.p = o;
4416 #ifndef DISABLE_REMOTING
4417 if (mono_object_is_transparent_proxy (o)) {
4418 MonoMethod *remoting_invoke_method = mono_marshal_get_remoting_invoke_with_check (child_frame.imethod->method, error);
4419 mono_error_assert_ok (error);
4420 child_frame.imethod = mono_interp_get_imethod (imethod->domain, remoting_invoke_method, error);
4421 mono_error_assert_ok (error);
4423 #endif
4424 } else {
4425 sp->data.p = NULL;
4426 child_frame.retval = &retval;
4430 interp_exec_method (&child_frame, context);
4432 CHECK_RESUME_STATE (context);
4435 * a constructor returns void, but we need to return the object we created
4437 if (m_class_is_valuetype (newobj_class) && !m_class_is_enumtype (newobj_class)) {
4438 *sp = valuetype_this;
4439 } else if (newobj_class == mono_defaults.string_class) {
4440 *sp = retval;
4441 } else {
4442 sp->data.p = o;
4444 ++sp;
4445 MINT_IN_BREAK;
4447 MINT_IN_CASE(MINT_NEWOBJ_MAGIC) {
4448 frame->ip = ip;
4449 ip += 2;
4451 MINT_IN_BREAK;
4453 MINT_IN_CASE(MINT_INTRINS_BYREFERENCE_CTOR) {
4454 MonoMethodSignature *csig;
4455 guint32 token;
4457 frame->ip = ip;
4458 token = * (guint16 *)(ip + 1);
4459 ip += 2;
4461 InterpMethod *cmethod = (InterpMethod*)imethod->data_items [token];
4462 csig = mono_method_signature_internal (cmethod->method);
4464 g_assert (csig->hasthis);
4465 sp -= csig->param_count;
4467 gpointer arg0 = sp [0].data.p;
4469 gpointer *byreference_this = (gpointer*)vt_sp;
4470 *byreference_this = arg0;
4472 /* Followed by a VTRESULT opcode which will push the result on the stack */
4473 ++sp;
4474 MINT_IN_BREAK;
4476 MINT_IN_CASE(MINT_INTRINS_BYREFERENCE_GET_VALUE) {
4477 gpointer *byreference_this = (gpointer*)sp [-1].data.p;
4478 sp [-1].data.p = *byreference_this;
4479 ++ip;
4480 MINT_IN_BREAK;
4482 MINT_IN_CASE(MINT_INTRINS_UNSAFE_ADD_BYTE_OFFSET) {
4483 sp -= 2;
4484 sp [0].data.p = (guint8*)sp [0].data.p + sp [1].data.i;
4485 sp ++;
4486 ++ip;
4487 MINT_IN_BREAK;
4489 MINT_IN_CASE(MINT_INTRINS_UNSAFE_BYTE_OFFSET) {
4490 sp -= 2;
4491 sp [0].data.i = (guint8*)sp [1].data.p - (guint8*)sp [0].data.p;
4492 sp ++;
4493 ++ip;
4494 MINT_IN_BREAK;
4496 MINT_IN_CASE(MINT_INTRINS_RUNTIMEHELPERS_OBJECT_HAS_COMPONENT_SIZE) {
4497 sp -= 1;
4498 MonoObject *obj = sp [0].data.o;
4499 sp [0].data.i = (obj->vtable->flags & MONO_VT_FLAG_ARRAY_OR_STRING) != 0;
4500 sp ++;
4501 ++ip;
4502 MINT_IN_BREAK;
4504 MINT_IN_CASE(MINT_CASTCLASS_INTERFACE)
4505 MINT_IN_CASE(MINT_ISINST_INTERFACE) {
4506 gboolean isinst_instr = *ip == MINT_ISINST_INTERFACE;
4507 c = (MonoClass*)imethod->data_items [*(guint16 *)(ip + 1)];
4508 if ((o = sp [-1].data.o)) {
4509 gboolean isinst;
4510 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (o->vtable, m_class_get_interface_id (c))) {
4511 isinst = TRUE;
4512 } else if (m_class_is_array_special_interface (c) || mono_object_is_transparent_proxy (o)) {
4513 /* slow path */
4514 isinst = mono_object_isinst_checked (o, c, error) != NULL;
4515 mono_error_cleanup (error); /* FIXME: don't swallow the error */
4516 } else {
4517 isinst = FALSE;
4520 if (!isinst) {
4521 if (isinst_instr)
4522 sp [-1].data.p = NULL;
4523 else
4524 THROW_EX (mono_get_exception_invalid_cast (), ip);
4527 ip += 2;
4528 MINT_IN_BREAK;
4530 MINT_IN_CASE(MINT_CASTCLASS_COMMON)
4531 MINT_IN_CASE(MINT_ISINST_COMMON) {
4532 gboolean isinst_instr = *ip == MINT_ISINST_COMMON;
4533 c = (MonoClass*)imethod->data_items [*(guint16 *)(ip + 1)];
4534 if ((o = sp [-1].data.o)) {
4535 gboolean isinst = mono_class_has_parent_fast (o->vtable->klass, c);
4537 if (!isinst) {
4538 if (isinst_instr)
4539 sp [-1].data.p = NULL;
4540 else
4541 THROW_EX (mono_get_exception_invalid_cast (), ip);
4544 ip += 2;
4545 MINT_IN_BREAK;
4547 MINT_IN_CASE(MINT_CASTCLASS)
4548 MINT_IN_CASE(MINT_ISINST) {
4549 gboolean isinst_instr = *ip == MINT_ISINST;
4550 c = (MonoClass*)imethod->data_items [*(guint16 *)(ip + 1)];
4551 if ((o = sp [-1].data.o)) {
4552 MonoObject *isinst_obj = mono_object_isinst_checked (o, c, error);
4553 mono_error_cleanup (error); /* FIXME: don't swallow the error */
4554 if (!isinst_obj) {
4555 if (isinst_instr)
4556 sp [-1].data.p = NULL;
4557 else
4558 THROW_EX (mono_get_exception_invalid_cast (), ip);
4561 ip += 2;
4562 MINT_IN_BREAK;
4564 MINT_IN_CASE(MINT_CONV_R_UN_I4)
4565 sp [-1].data.f = (double)(guint32)sp [-1].data.i;
4566 ++ip;
4567 MINT_IN_BREAK;
4568 MINT_IN_CASE(MINT_CONV_R_UN_I8)
4569 sp [-1].data.f = (double)(guint64)sp [-1].data.l;
4570 ++ip;
4571 MINT_IN_BREAK;
4572 MINT_IN_CASE(MINT_UNBOX)
4573 c = (MonoClass*)imethod->data_items[*(guint16 *)(ip + 1)];
4575 o = sp [-1].data.o;
4576 if (!o)
4577 THROW_EX (mono_get_exception_null_reference (), ip);
4579 if (!(m_class_get_rank (o->vtable->klass) == 0 && m_class_get_element_class (o->vtable->klass) == m_class_get_element_class (c)))
4580 THROW_EX (mono_get_exception_invalid_cast (), ip);
4582 sp [-1].data.p = mono_object_unbox_internal (o);
4583 ip += 2;
4584 MINT_IN_BREAK;
4585 MINT_IN_CASE(MINT_THROW)
4586 --sp;
4587 if (!sp->data.p)
4588 sp->data.p = mono_get_exception_null_reference ();
4590 THROW_EX ((MonoException *)sp->data.p, ip);
4591 MINT_IN_BREAK;
4592 MINT_IN_CASE(MINT_CHECKPOINT)
4593 /* Do synchronous checking of abort requests */
4594 EXCEPTION_CHECKPOINT;
4595 ++ip;
4596 MINT_IN_BREAK;
4597 MINT_IN_CASE(MINT_SAFEPOINT)
4598 /* Do synchronous checking of abort requests */
4599 EXCEPTION_CHECKPOINT;
4600 /* Poll safepoint */
4601 mono_threads_safepoint ();
4602 ++ip;
4603 MINT_IN_BREAK;
4604 MINT_IN_CASE(MINT_LDFLDA_UNSAFE)
4605 o = sp [-1].data.o;
4606 sp[-1].data.p = (char *)o + * (guint16 *)(ip + 1);
4607 ip += 2;
4608 MINT_IN_BREAK;
4609 MINT_IN_CASE(MINT_LDFLDA)
4610 o = sp [-1].data.o;
4611 if (!o)
4612 THROW_EX (mono_get_exception_null_reference (), ip);
4613 sp[-1].data.p = (char *)o + * (guint16 *)(ip + 1);
4614 ip += 2;
4615 MINT_IN_BREAK;
4616 MINT_IN_CASE(MINT_CKNULL_N) {
4617 /* Same as CKNULL, but further down the stack */
4618 int n = *(guint16*)(ip + 1);
4619 o = sp [-n].data.o;
4620 if (!o)
4621 THROW_EX (mono_get_exception_null_reference (), ip);
4622 ip += 2;
4623 MINT_IN_BREAK;
4626 #define LDFLD_UNALIGNED(datamem, fieldtype, unaligned) \
4627 o = sp [-1].data.o; \
4628 if (!o) \
4629 THROW_EX (mono_get_exception_null_reference (), ip); \
4630 if (unaligned) \
4631 memcpy (&sp[-1].data.datamem, (char *)o + * (guint16 *)(ip + 1), sizeof (fieldtype)); \
4632 else \
4633 sp[-1].data.datamem = * (fieldtype *)((char *)o + * (guint16 *)(ip + 1)) ; \
4634 ip += 2;
4636 #define LDFLD(datamem, fieldtype) LDFLD_UNALIGNED(datamem, fieldtype, FALSE)
4638 MINT_IN_CASE(MINT_LDFLD_I1) LDFLD(i, gint8); MINT_IN_BREAK;
4639 MINT_IN_CASE(MINT_LDFLD_U1) LDFLD(i, guint8); MINT_IN_BREAK;
4640 MINT_IN_CASE(MINT_LDFLD_I2) LDFLD(i, gint16); MINT_IN_BREAK;
4641 MINT_IN_CASE(MINT_LDFLD_U2) LDFLD(i, guint16); MINT_IN_BREAK;
4642 MINT_IN_CASE(MINT_LDFLD_I4) LDFLD(i, gint32); MINT_IN_BREAK;
4643 MINT_IN_CASE(MINT_LDFLD_I8) LDFLD(l, gint64); MINT_IN_BREAK;
4644 MINT_IN_CASE(MINT_LDFLD_R4) LDFLD(f_r4, float); MINT_IN_BREAK;
4645 MINT_IN_CASE(MINT_LDFLD_R8) LDFLD(f, double); MINT_IN_BREAK;
4646 MINT_IN_CASE(MINT_LDFLD_O) LDFLD(p, gpointer); MINT_IN_BREAK;
4647 MINT_IN_CASE(MINT_LDFLD_P) LDFLD(p, gpointer); MINT_IN_BREAK;
4648 MINT_IN_CASE(MINT_LDFLD_I8_UNALIGNED) LDFLD_UNALIGNED(l, gint64, TRUE); MINT_IN_BREAK;
4649 MINT_IN_CASE(MINT_LDFLD_R8_UNALIGNED) LDFLD_UNALIGNED(f, double, TRUE); MINT_IN_BREAK;
4651 MINT_IN_CASE(MINT_LDFLD_VT) {
4652 o = sp [-1].data.o;
4653 if (!o)
4654 THROW_EX (mono_get_exception_null_reference (), ip);
4656 int size = READ32(ip + 2);
4657 sp [-1].data.p = vt_sp;
4658 memcpy (sp [-1].data.p, (char *)o + * (guint16 *)(ip + 1), size);
4659 vt_sp += ALIGN_TO (size, MINT_VT_ALIGNMENT);
4660 ip += 4;
4661 MINT_IN_BREAK;
4664 MINT_IN_CASE(MINT_LDRMFLD) {
4665 MonoClassField *field;
4666 char *addr;
4668 o = sp [-1].data.o;
4669 if (!o)
4670 THROW_EX (mono_get_exception_null_reference (), ip);
4671 field = (MonoClassField*)imethod->data_items[* (guint16 *)(ip + 1)];
4672 ip += 2;
4673 #ifndef DISABLE_REMOTING
4674 if (mono_object_is_transparent_proxy (o)) {
4675 gpointer tmp;
4676 MonoClass *klass = ((MonoTransparentProxy*)o)->remote_class->proxy_class;
4678 addr = (char*)mono_load_remote_field_checked (o, klass, field, &tmp, error);
4679 mono_error_cleanup (error); /* FIXME: don't swallow the error */
4680 } else
4681 #endif
4682 addr = (char*)o + field->offset;
4684 stackval_from_data (field->type, &sp [-1], addr, FALSE);
4685 MINT_IN_BREAK;
4688 MINT_IN_CASE(MINT_LDRMFLD_VT) {
4689 MonoClassField *field;
4690 char *addr;
4692 o = sp [-1].data.o;
4693 if (!o)
4694 THROW_EX (mono_get_exception_null_reference (), ip);
4696 field = (MonoClassField*)imethod->data_items[* (guint16 *)(ip + 1)];
4697 MonoClass *klass = mono_class_from_mono_type_internal (field->type);
4698 i32 = mono_class_value_size (klass, NULL);
4700 ip += 2;
4701 #ifndef DISABLE_REMOTING
4702 if (mono_object_is_transparent_proxy (o)) {
4703 gpointer tmp;
4704 MonoClass *klass = ((MonoTransparentProxy*)o)->remote_class->proxy_class;
4705 addr = (char*)mono_load_remote_field_checked (o, klass, field, &tmp, error);
4706 mono_error_cleanup (error); /* FIXME: don't swallow the error */
4707 } else
4708 #endif
4709 addr = (char*)o + field->offset;
4711 sp [-1].data.p = vt_sp;
4712 vt_sp += ALIGN_TO (i32, MINT_VT_ALIGNMENT);
4713 memcpy(sp [-1].data.p, addr, i32);
4714 MINT_IN_BREAK;
4717 #define STFLD_UNALIGNED(datamem, fieldtype, unaligned) \
4718 o = sp [-2].data.o; \
4719 if (!o) \
4720 THROW_EX (mono_get_exception_null_reference (), ip); \
4721 sp -= 2; \
4722 if (unaligned) \
4723 memcpy ((char *)o + * (guint16 *)(ip + 1), &sp[1].data.datamem, sizeof (fieldtype)); \
4724 else \
4725 * (fieldtype *)((char *)o + * (guint16 *)(ip + 1)) = sp[1].data.datamem; \
4726 ip += 2;
4728 #define STFLD(datamem, fieldtype) STFLD_UNALIGNED(datamem, fieldtype, FALSE)
4730 MINT_IN_CASE(MINT_STFLD_I1) STFLD(i, gint8); MINT_IN_BREAK;
4731 MINT_IN_CASE(MINT_STFLD_U1) STFLD(i, guint8); MINT_IN_BREAK;
4732 MINT_IN_CASE(MINT_STFLD_I2) STFLD(i, gint16); MINT_IN_BREAK;
4733 MINT_IN_CASE(MINT_STFLD_U2) STFLD(i, guint16); MINT_IN_BREAK;
4734 MINT_IN_CASE(MINT_STFLD_I4) STFLD(i, gint32); MINT_IN_BREAK;
4735 MINT_IN_CASE(MINT_STFLD_I8) STFLD(l, gint64); MINT_IN_BREAK;
4736 MINT_IN_CASE(MINT_STFLD_R4) STFLD(f_r4, float); MINT_IN_BREAK;
4737 MINT_IN_CASE(MINT_STFLD_R8) STFLD(f, double); MINT_IN_BREAK;
4738 MINT_IN_CASE(MINT_STFLD_P) STFLD(p, gpointer); MINT_IN_BREAK;
4739 MINT_IN_CASE(MINT_STFLD_O)
4740 o = sp [-2].data.o;
4741 if (!o)
4742 THROW_EX (mono_get_exception_null_reference (), ip);
4743 sp -= 2;
4744 mono_gc_wbarrier_set_field_internal (o, (char *) o + * (guint16 *)(ip + 1), sp [1].data.o);
4745 ip += 2;
4746 MINT_IN_BREAK;
4747 MINT_IN_CASE(MINT_STFLD_I8_UNALIGNED) STFLD_UNALIGNED(l, gint64, TRUE); MINT_IN_BREAK;
4748 MINT_IN_CASE(MINT_STFLD_R8_UNALIGNED) STFLD_UNALIGNED(f, double, TRUE); MINT_IN_BREAK;
4750 MINT_IN_CASE(MINT_STFLD_VT) {
4751 o = sp [-2].data.o;
4752 if (!o)
4753 THROW_EX (mono_get_exception_null_reference (), ip);
4754 sp -= 2;
4756 MonoClass *klass = (MonoClass*)imethod->data_items[* (guint16 *)(ip + 2)];
4757 i32 = mono_class_value_size (klass, NULL);
4759 guint16 offset = * (guint16 *)(ip + 1);
4760 mono_value_copy_internal ((char *) o + offset, sp [1].data.p, klass);
4762 vt_sp -= ALIGN_TO (i32, MINT_VT_ALIGNMENT);
4763 ip += 3;
4764 MINT_IN_BREAK;
4766 MINT_IN_CASE(MINT_STRMFLD) {
4767 MonoClassField *field;
4769 o = sp [-2].data.o;
4770 if (!o)
4771 THROW_EX (mono_get_exception_null_reference (), ip);
4773 field = (MonoClassField*)imethod->data_items[* (guint16 *)(ip + 1)];
4774 ip += 2;
4776 #ifndef DISABLE_REMOTING
4777 if (mono_object_is_transparent_proxy (o)) {
4778 MonoClass *klass = ((MonoTransparentProxy*)o)->remote_class->proxy_class;
4779 mono_store_remote_field_checked (o, klass, field, &sp [-1].data, error);
4780 mono_error_cleanup (error); /* FIXME: don't swallow the error */
4781 } else
4782 #endif
4783 stackval_to_data (field->type, &sp [-1], (char*)o + field->offset, FALSE);
4785 sp -= 2;
4786 MINT_IN_BREAK;
4788 MINT_IN_CASE(MINT_STRMFLD_VT) {
4789 MonoClassField *field;
4791 o = sp [-2].data.o;
4792 if (!o)
4793 THROW_EX (mono_get_exception_null_reference (), ip);
4794 field = (MonoClassField*)imethod->data_items[* (guint16 *)(ip + 1)];
4795 MonoClass *klass = mono_class_from_mono_type_internal (field->type);
4796 i32 = mono_class_value_size (klass, NULL);
4797 ip += 2;
4799 #ifndef DISABLE_REMOTING
4800 if (mono_object_is_transparent_proxy (o)) {
4801 MonoClass *klass = ((MonoTransparentProxy*)o)->remote_class->proxy_class;
4802 mono_store_remote_field_checked (o, klass, field, sp [-1].data.p, error);
4803 mono_error_cleanup (error); /* FIXME: don't swallow the error */
4804 } else
4805 #endif
4806 mono_value_copy_internal ((char *) o + field->offset, sp [-1].data.p, klass);
4808 sp -= 2;
4809 vt_sp -= ALIGN_TO (i32, MINT_VT_ALIGNMENT);
4810 MINT_IN_BREAK;
4812 MINT_IN_CASE(MINT_LDSFLDA) {
4813 MonoVTable *vtable = (MonoVTable*) imethod->data_items [*(guint16*)(ip + 1)];
4814 INIT_VTABLE (vtable);
4815 sp->data.p = imethod->data_items [*(guint16*)(ip + 2)];
4816 ip += 3;
4817 ++sp;
4818 MINT_IN_BREAK;
4821 MINT_IN_CASE(MINT_LDSSFLDA) {
4822 guint32 offset = READ32(ip + 1);
4823 sp->data.p = mono_get_special_static_data (offset);
4824 ip += 3;
4825 ++sp;
4826 MINT_IN_BREAK;
4829 /* We init class here to preserve cctor order */
4830 #define LDSFLD(datamem, fieldtype) { \
4831 MonoVTable *vtable = (MonoVTable*) imethod->data_items [*(guint16*)(ip + 1)]; \
4832 INIT_VTABLE (vtable); \
4833 sp[0].data.datamem = * (fieldtype *)(imethod->data_items [* (guint16 *)(ip + 2)]) ; \
4834 ip += 3; \
4835 sp++; \
4838 MINT_IN_CASE(MINT_LDSFLD_I1) LDSFLD(i, gint8); MINT_IN_BREAK;
4839 MINT_IN_CASE(MINT_LDSFLD_U1) LDSFLD(i, guint8); MINT_IN_BREAK;
4840 MINT_IN_CASE(MINT_LDSFLD_I2) LDSFLD(i, gint16); MINT_IN_BREAK;
4841 MINT_IN_CASE(MINT_LDSFLD_U2) LDSFLD(i, guint16); MINT_IN_BREAK;
4842 MINT_IN_CASE(MINT_LDSFLD_I4) LDSFLD(i, gint32); MINT_IN_BREAK;
4843 MINT_IN_CASE(MINT_LDSFLD_I8) LDSFLD(l, gint64); MINT_IN_BREAK;
4844 MINT_IN_CASE(MINT_LDSFLD_R4) LDSFLD(f_r4, float); MINT_IN_BREAK;
4845 MINT_IN_CASE(MINT_LDSFLD_R8) LDSFLD(f, double); MINT_IN_BREAK;
4846 MINT_IN_CASE(MINT_LDSFLD_O) LDSFLD(p, gpointer); MINT_IN_BREAK;
4847 MINT_IN_CASE(MINT_LDSFLD_P) LDSFLD(p, gpointer); MINT_IN_BREAK;
4849 MINT_IN_CASE(MINT_LDSFLD_VT) {
4850 MonoVTable *vtable = (MonoVTable*) imethod->data_items [*(guint16*)(ip + 1)];
4851 gpointer addr = imethod->data_items [*(guint16*)(ip + 2)];
4852 i32 = READ32(ip + 3);
4853 INIT_VTABLE (vtable);
4854 sp->data.p = vt_sp;
4856 memcpy (vt_sp, addr, i32);
4857 vt_sp += ALIGN_TO (i32, MINT_VT_ALIGNMENT);
4858 ip += 5;
4859 ++sp;
4860 MINT_IN_BREAK;
4863 #define LDTSFLD(datamem, fieldtype) { \
4864 guint32 offset = READ32(ip + 1); \
4865 MonoInternalThread *thread = mono_thread_internal_current (); \
4866 gpointer addr = ((char*)thread->static_data [offset & 0x3f]) + (offset >> 6); \
4867 sp[0].data.datamem = *(fieldtype*)addr; \
4868 ip += 3; \
4869 ++sp; \
4871 MINT_IN_CASE(MINT_LDTSFLD_I1) LDTSFLD(i, gint8); MINT_IN_BREAK;
4872 MINT_IN_CASE(MINT_LDTSFLD_U1) LDTSFLD(i, guint8); MINT_IN_BREAK;
4873 MINT_IN_CASE(MINT_LDTSFLD_I2) LDTSFLD(i, gint16); MINT_IN_BREAK;
4874 MINT_IN_CASE(MINT_LDTSFLD_U2) LDTSFLD(i, guint16); MINT_IN_BREAK;
4875 MINT_IN_CASE(MINT_LDTSFLD_I4) LDTSFLD(i, gint32); MINT_IN_BREAK;
4876 MINT_IN_CASE(MINT_LDTSFLD_I8) LDTSFLD(l, gint64); MINT_IN_BREAK;
4877 MINT_IN_CASE(MINT_LDTSFLD_R4) LDTSFLD(f_r4, float); MINT_IN_BREAK;
4878 MINT_IN_CASE(MINT_LDTSFLD_R8) LDTSFLD(f, double); MINT_IN_BREAK;
4879 MINT_IN_CASE(MINT_LDTSFLD_O) LDTSFLD(p, gpointer); MINT_IN_BREAK;
4880 MINT_IN_CASE(MINT_LDTSFLD_P) LDTSFLD(p, gpointer); MINT_IN_BREAK;
4882 MINT_IN_CASE(MINT_LDSSFLD) {
4883 MonoClassField *field = (MonoClassField*)imethod->data_items [* (guint16 *)(ip + 1)];
4884 guint32 offset = READ32(ip + 2);
4885 gpointer addr = mono_get_special_static_data (offset);
4886 stackval_from_data (field->type, sp, addr, FALSE);
4887 ip += 4;
4888 ++sp;
4889 MINT_IN_BREAK;
4891 MINT_IN_CASE(MINT_LDSSFLD_VT) {
4892 guint32 offset = READ32(ip + 1);
4893 gpointer addr = mono_get_special_static_data (offset);
4895 int size = READ32 (ip + 3);
4896 memcpy (vt_sp, addr, size);
4897 sp->data.p = vt_sp;
4898 vt_sp += ALIGN_TO (size, MINT_VT_ALIGNMENT);
4899 ip += 5;
4900 ++sp;
4901 MINT_IN_BREAK;
4903 #define STSFLD(datamem, fieldtype) { \
4904 MonoVTable *vtable = (MonoVTable*) imethod->data_items [*(guint16*)(ip + 1)]; \
4905 INIT_VTABLE (vtable); \
4906 sp --; \
4907 * (fieldtype *)(imethod->data_items [* (guint16 *)(ip + 2)]) = sp[0].data.datamem; \
4908 ip += 3; \
4911 MINT_IN_CASE(MINT_STSFLD_I1) STSFLD(i, gint8); MINT_IN_BREAK;
4912 MINT_IN_CASE(MINT_STSFLD_U1) STSFLD(i, guint8); MINT_IN_BREAK;
4913 MINT_IN_CASE(MINT_STSFLD_I2) STSFLD(i, gint16); MINT_IN_BREAK;
4914 MINT_IN_CASE(MINT_STSFLD_U2) STSFLD(i, guint16); MINT_IN_BREAK;
4915 MINT_IN_CASE(MINT_STSFLD_I4) STSFLD(i, gint32); MINT_IN_BREAK;
4916 MINT_IN_CASE(MINT_STSFLD_I8) STSFLD(l, gint64); MINT_IN_BREAK;
4917 MINT_IN_CASE(MINT_STSFLD_R4) STSFLD(f_r4, float); MINT_IN_BREAK;
4918 MINT_IN_CASE(MINT_STSFLD_R8) STSFLD(f, double); MINT_IN_BREAK;
4919 MINT_IN_CASE(MINT_STSFLD_P) STSFLD(p, gpointer); MINT_IN_BREAK;
4920 MINT_IN_CASE(MINT_STSFLD_O) STSFLD(p, gpointer); MINT_IN_BREAK;
4922 MINT_IN_CASE(MINT_STSFLD_VT) {
4923 MonoVTable *vtable = (MonoVTable*) imethod->data_items [*(guint16*)(ip + 1)];
4924 gpointer addr = imethod->data_items [*(guint16*)(ip + 2)];
4925 i32 = READ32(ip + 3);
4926 INIT_VTABLE (vtable);
4928 memcpy (addr, sp [-1].data.vt, i32);
4929 vt_sp -= ALIGN_TO (i32, MINT_VT_ALIGNMENT);
4930 ip += 4;
4931 --sp;
4932 MINT_IN_BREAK;
4935 #define STTSFLD(datamem, fieldtype) { \
4936 guint32 offset = READ32(ip + 1); \
4937 MonoInternalThread *thread = mono_thread_internal_current (); \
4938 gpointer addr = ((char*)thread->static_data [offset & 0x3f]) + (offset >> 6); \
4939 sp--; \
4940 *(fieldtype*)addr = sp[0].data.datamem; \
4941 ip += 3; \
4944 MINT_IN_CASE(MINT_STTSFLD_I1) STTSFLD(i, gint8); MINT_IN_BREAK;
4945 MINT_IN_CASE(MINT_STTSFLD_U1) STTSFLD(i, guint8); MINT_IN_BREAK;
4946 MINT_IN_CASE(MINT_STTSFLD_I2) STTSFLD(i, gint16); MINT_IN_BREAK;
4947 MINT_IN_CASE(MINT_STTSFLD_U2) STTSFLD(i, guint16); MINT_IN_BREAK;
4948 MINT_IN_CASE(MINT_STTSFLD_I4) STTSFLD(i, gint32); MINT_IN_BREAK;
4949 MINT_IN_CASE(MINT_STTSFLD_I8) STTSFLD(l, gint64); MINT_IN_BREAK;
4950 MINT_IN_CASE(MINT_STTSFLD_R4) STTSFLD(f_r4, float); MINT_IN_BREAK;
4951 MINT_IN_CASE(MINT_STTSFLD_R8) STTSFLD(f, double); MINT_IN_BREAK;
4952 MINT_IN_CASE(MINT_STTSFLD_P) STTSFLD(p, gpointer); MINT_IN_BREAK;
4953 MINT_IN_CASE(MINT_STTSFLD_O) STTSFLD(p, gpointer); MINT_IN_BREAK;
4955 MINT_IN_CASE(MINT_STSSFLD) {
4956 MonoClassField *field = (MonoClassField*)imethod->data_items [* (guint16 *)(ip + 1)];
4957 guint32 offset = READ32(ip + 2);
4958 gpointer addr = mono_get_special_static_data (offset);
4959 --sp;
4960 stackval_to_data (field->type, sp, addr, FALSE);
4961 ip += 4;
4962 MINT_IN_BREAK;
4964 MINT_IN_CASE(MINT_STSSFLD_VT) {
4965 guint32 offset = READ32(ip + 1);
4966 gpointer addr = mono_get_special_static_data (offset);
4967 --sp;
4968 int size = READ32 (ip + 3);
4969 memcpy (addr, sp->data.vt, size);
4970 vt_sp -= ALIGN_TO (size, MINT_VT_ALIGNMENT);
4971 ip += 5;
4972 MINT_IN_BREAK;
4975 MINT_IN_CASE(MINT_STOBJ_VT) {
4976 int size;
4977 c = (MonoClass*)imethod->data_items[* (guint16 *)(ip + 1)];
4978 ip += 2;
4979 size = mono_class_value_size (c, NULL);
4980 mono_value_copy_internal (sp [-2].data.p, sp [-1].data.p, c);
4981 vt_sp -= ALIGN_TO (size, MINT_VT_ALIGNMENT);
4982 sp -= 2;
4983 MINT_IN_BREAK;
4985 MINT_IN_CASE(MINT_CONV_OVF_I4_UN_R8)
4986 if (sp [-1].data.f < 0 || sp [-1].data.f > G_MAXINT32)
4987 THROW_EX (mono_get_exception_overflow (), ip);
4988 sp [-1].data.i = (gint32)sp [-1].data.f;
4989 ++ip;
4990 MINT_IN_BREAK;
4991 MINT_IN_CASE(MINT_CONV_OVF_U8_I4)
4992 if (sp [-1].data.i < 0)
4993 THROW_EX (mono_get_exception_overflow (), ip);
4994 sp [-1].data.l = sp [-1].data.i;
4995 ++ip;
4996 MINT_IN_BREAK;
4997 MINT_IN_CASE(MINT_CONV_OVF_U8_I8)
4998 if (sp [-1].data.l < 0)
4999 THROW_EX (mono_get_exception_overflow (), ip);
5000 ++ip;
5001 MINT_IN_BREAK;
5002 MINT_IN_CASE(MINT_CONV_OVF_I8_U8)
5003 if ((guint64) sp [-1].data.l > G_MAXINT64)
5004 THROW_EX (mono_get_exception_overflow (), ip);
5005 ++ip;
5006 MINT_IN_BREAK;
5007 MINT_IN_CASE(MINT_CONV_OVF_U8_R4)
5008 if (sp [-1].data.f_r4 < 0 || sp [-1].data.f_r4 > G_MAXUINT64 || isnan (sp [-1].data.f_r4))
5009 THROW_EX (mono_get_exception_overflow (), ip);
5010 sp [-1].data.l = (guint64)sp [-1].data.f_r4;
5011 ++ip;
5012 MINT_IN_BREAK;
5013 MINT_IN_CASE(MINT_CONV_OVF_U8_R8)
5014 if (sp [-1].data.f < 0 || sp [-1].data.f > G_MAXUINT64 || isnan (sp [-1].data.f))
5015 THROW_EX (mono_get_exception_overflow (), ip);
5016 sp [-1].data.l = (guint64)sp [-1].data.f;
5017 ++ip;
5018 MINT_IN_BREAK;
5019 MINT_IN_CASE(MINT_CONV_OVF_I8_UN_R8)
5020 if (sp [-1].data.f < 0 || sp [-1].data.f > G_MAXINT64)
5021 THROW_EX (mono_get_exception_overflow (), ip);
5022 sp [-1].data.l = (gint64)sp [-1].data.f;
5023 ++ip;
5024 MINT_IN_BREAK;
5025 MINT_IN_CASE(MINT_CONV_OVF_I8_R4)
5026 if (sp [-1].data.f_r4 < G_MININT64 || sp [-1].data.f_r4 > G_MAXINT64 || isnan (sp [-1].data.f_r4))
5027 THROW_EX (mono_get_exception_overflow (), ip);
5028 sp [-1].data.l = (gint64)sp [-1].data.f_r4;
5029 ++ip;
5030 MINT_IN_BREAK;
5031 MINT_IN_CASE(MINT_CONV_OVF_I8_R8)
5032 if (sp [-1].data.f < G_MININT64 || sp [-1].data.f > G_MAXINT64 || isnan (sp [-1].data.f))
5033 THROW_EX (mono_get_exception_overflow (), ip);
5034 sp [-1].data.l = (gint64)sp [-1].data.f;
5035 ++ip;
5036 MINT_IN_BREAK;
5037 MINT_IN_CASE(MINT_CONV_OVF_I4_UN_I8)
5038 if ((guint64)sp [-1].data.l > G_MAXINT32)
5039 THROW_EX (mono_get_exception_overflow (), ip);
5040 sp [-1].data.i = (gint32)sp [-1].data.l;
5041 ++ip;
5042 MINT_IN_BREAK;
5043 MINT_IN_CASE(MINT_BOX) {
5044 MonoVTable *vtable = (MonoVTable*)imethod->data_items [* (guint16 *)(ip + 1)];
5045 guint16 offset = * (guint16 *)(ip + 2);
5047 MonoObject *obj = mono_gc_alloc_obj (vtable, m_class_get_instance_size (vtable->klass));
5048 stackval_to_data (m_class_get_byval_arg (vtable->klass), &sp [-1 - offset], mono_object_get_data (obj), FALSE);
5050 sp [-1 - offset].data.p = obj;
5052 ip += 3;
5053 MINT_IN_BREAK;
5055 MINT_IN_CASE(MINT_BOX_VT) {
5056 MonoVTable *vtable = (MonoVTable*)imethod->data_items [* (guint16 *)(ip + 1)];
5057 c = vtable->klass;
5058 guint16 offset = * (guint16 *)(ip + 2);
5059 gboolean pop_vt_sp = !(offset & BOX_NOT_CLEAR_VT_SP);
5060 offset &= ~BOX_NOT_CLEAR_VT_SP;
5062 int size = mono_class_value_size (c, NULL);
5063 MonoObject *obj = mono_gc_alloc_obj (vtable, m_class_get_instance_size (vtable->klass));
5064 mono_value_copy_internal (mono_object_get_data (obj), sp [-1 - offset].data.p, c);
5066 sp [-1 - offset].data.p = obj;
5067 size = ALIGN_TO (size, MINT_VT_ALIGNMENT);
5068 if (pop_vt_sp)
5069 vt_sp -= size;
5071 ip += 3;
5072 MINT_IN_BREAK;
5074 MINT_IN_CASE(MINT_BOX_NULLABLE) {
5075 c = (MonoClass*)imethod->data_items [* (guint16 *)(ip + 1)];
5076 guint16 offset = * (guint16 *)(ip + 2);
5077 gboolean pop_vt_sp = !(offset & BOX_NOT_CLEAR_VT_SP);
5078 offset &= ~BOX_NOT_CLEAR_VT_SP;
5080 int size = mono_class_value_size (c, NULL);
5082 sp [-1 - offset].data.p = mono_nullable_box (sp [-1 - offset].data.p, c, error);
5083 mono_error_cleanup (error); /* FIXME: don't swallow the error */
5085 size = ALIGN_TO (size, MINT_VT_ALIGNMENT);
5086 if (pop_vt_sp)
5087 vt_sp -= size;
5089 ip += 3;
5090 MINT_IN_BREAK;
5092 MINT_IN_CASE(MINT_NEWARR)
5093 sp [-1].data.p = (MonoObject*) mono_array_new_checked (imethod->domain, (MonoClass*)imethod->data_items[*(guint16 *)(ip + 1)], sp [-1].data.i, error);
5094 if (!mono_error_ok (error)) {
5095 THROW_EX (mono_error_convert_to_exception (error), ip);
5097 mono_error_cleanup (error); /* FIXME: don't swallow the error */
5098 ip += 2;
5099 /*if (profiling_classes) {
5100 guint count = GPOINTER_TO_UINT (g_hash_table_lookup (profiling_classes, o->vtable->klass));
5101 count++;
5102 g_hash_table_insert (profiling_classes, o->vtable->klass, GUINT_TO_POINTER (count));
5105 MINT_IN_BREAK;
5106 MINT_IN_CASE(MINT_LDLEN)
5107 o = sp [-1].data.o;
5108 if (!o)
5109 THROW_EX (mono_get_exception_null_reference (), ip);
5110 sp [-1].data.nati = mono_array_length_internal ((MonoArray *)o);
5111 ++ip;
5112 MINT_IN_BREAK;
5113 MINT_IN_CASE(MINT_LDLEN_SPAN) {
5114 o = sp [-1].data.o;
5115 gsize offset_length = (gsize) *(gint16 *) (ip + 1);
5116 if (!o)
5117 THROW_EX (mono_get_exception_null_reference (), ip);
5118 sp [-1].data.nati = *(gint32 *) ((guint8 *) o + offset_length);
5119 ip += 2;
5120 MINT_IN_BREAK;
5122 MINT_IN_CASE(MINT_GETCHR) {
5123 MonoString *s;
5124 s = (MonoString*)sp [-2].data.p;
5125 if (!s)
5126 THROW_EX (mono_get_exception_null_reference (), ip);
5127 i32 = sp [-1].data.i;
5128 if (i32 < 0 || i32 >= mono_string_length_internal (s))
5129 THROW_EX (mono_get_exception_index_out_of_range (), ip);
5130 --sp;
5131 sp [-1].data.i = mono_string_chars_internal (s)[i32];
5132 ++ip;
5133 MINT_IN_BREAK;
5135 MINT_IN_CASE(MINT_GETITEM_SPAN) {
5136 guint8 *span = (guint8 *) sp [-2].data.p;
5137 int index = sp [-1].data.i;
5138 gsize element_size = (gsize) *(gint16 *) (ip + 1);
5139 gsize offset_length = (gsize) *(gint16 *) (ip + 2);
5140 gsize offset_pointer = (gsize) *(gint16 *) (ip + 3);
5141 sp--;
5143 if (!span)
5144 THROW_EX (mono_get_exception_null_reference (), ip);
5146 gint32 length = *(gint32 *) (span + offset_length);
5147 if (index < 0 || index >= length)
5148 THROW_EX (mono_get_exception_index_out_of_range (), ip);
5150 gpointer pointer = *(gpointer *)(span + offset_pointer);
5151 sp [-1].data.p = (guint8 *) pointer + index * element_size;
5153 ip += 4;
5154 MINT_IN_BREAK;
5156 MINT_IN_CASE(MINT_STRLEN)
5157 ++ip;
5158 o = sp [-1].data.o;
5159 if (!o)
5160 THROW_EX (mono_get_exception_null_reference (), ip);
5161 sp [-1].data.i = mono_string_length_internal ((MonoString*) o);
5162 MINT_IN_BREAK;
5163 MINT_IN_CASE(MINT_ARRAY_RANK)
5164 o = sp [-1].data.o;
5165 if (!o)
5166 THROW_EX (mono_get_exception_null_reference (), ip);
5167 sp [-1].data.i = m_class_get_rank (mono_object_class (sp [-1].data.p));
5168 ip++;
5169 MINT_IN_BREAK;
5170 MINT_IN_CASE(MINT_LDELEMA)
5171 MINT_IN_CASE(MINT_LDELEMA_TC) {
5172 gboolean needs_typecheck = *ip == MINT_LDELEMA_TC;
5174 MonoClass *klass = (MonoClass*)imethod->data_items [*(guint16 *) (ip + 1)];
5175 guint16 numargs = *(guint16 *) (ip + 2);
5176 ip += 3;
5177 sp -= numargs;
5179 o = sp [0].data.o;
5180 if (!o)
5181 THROW_EX (mono_get_exception_null_reference (), ip);
5182 sp->data.p = ves_array_element_address (frame, klass, (MonoArray *) o, &sp [1], needs_typecheck);
5183 if (frame->ex)
5184 THROW_EX (frame->ex, ip);
5185 ++sp;
5187 MINT_IN_BREAK;
5189 MINT_IN_CASE(MINT_LDELEM_I1) /* fall through */
5190 MINT_IN_CASE(MINT_LDELEM_U1) /* fall through */
5191 MINT_IN_CASE(MINT_LDELEM_I2) /* fall through */
5192 MINT_IN_CASE(MINT_LDELEM_U2) /* fall through */
5193 MINT_IN_CASE(MINT_LDELEM_I4) /* fall through */
5194 MINT_IN_CASE(MINT_LDELEM_U4) /* fall through */
5195 MINT_IN_CASE(MINT_LDELEM_I8) /* fall through */
5196 MINT_IN_CASE(MINT_LDELEM_I) /* fall through */
5197 MINT_IN_CASE(MINT_LDELEM_R4) /* fall through */
5198 MINT_IN_CASE(MINT_LDELEM_R8) /* fall through */
5199 MINT_IN_CASE(MINT_LDELEM_REF) /* fall through */
5200 MINT_IN_CASE(MINT_LDELEM_VT) {
5201 MonoArray *o;
5202 mono_u aindex;
5204 sp -= 2;
5206 o = (MonoArray*)sp [0].data.p;
5207 if (!o)
5208 THROW_EX (mono_get_exception_null_reference (), ip);
5210 aindex = sp [1].data.i;
5211 if (aindex >= mono_array_length_internal (o))
5212 THROW_EX (mono_get_exception_index_out_of_range (), ip);
5215 * FIXME: throw mono_get_exception_array_type_mismatch () if needed
5217 switch (*ip) {
5218 case MINT_LDELEM_I1:
5219 sp [0].data.i = mono_array_get_fast (o, gint8, aindex);
5220 break;
5221 case MINT_LDELEM_U1:
5222 sp [0].data.i = mono_array_get_fast (o, guint8, aindex);
5223 break;
5224 case MINT_LDELEM_I2:
5225 sp [0].data.i = mono_array_get_fast (o, gint16, aindex);
5226 break;
5227 case MINT_LDELEM_U2:
5228 sp [0].data.i = mono_array_get_fast (o, guint16, aindex);
5229 break;
5230 case MINT_LDELEM_I:
5231 sp [0].data.nati = mono_array_get_fast (o, mono_i, aindex);
5232 break;
5233 case MINT_LDELEM_I4:
5234 sp [0].data.i = mono_array_get_fast (o, gint32, aindex);
5235 break;
5236 case MINT_LDELEM_U4:
5237 sp [0].data.i = mono_array_get_fast (o, guint32, aindex);
5238 break;
5239 case MINT_LDELEM_I8:
5240 sp [0].data.l = mono_array_get_fast (o, guint64, aindex);
5241 break;
5242 case MINT_LDELEM_R4:
5243 sp [0].data.f_r4 = mono_array_get_fast (o, float, aindex);
5244 break;
5245 case MINT_LDELEM_R8:
5246 sp [0].data.f = mono_array_get_fast (o, double, aindex);
5247 break;
5248 case MINT_LDELEM_REF:
5249 sp [0].data.p = mono_array_get_fast (o, gpointer, aindex);
5250 break;
5251 case MINT_LDELEM_VT: {
5252 i32 = READ32 (ip + 1);
5253 char *src_addr = mono_array_addr_with_size_fast ((MonoArray *) o, i32, aindex);
5254 sp [0].data.vt = vt_sp;
5255 // Copying to vtstack. No wbarrier needed
5256 memcpy (sp [0].data.vt, src_addr, i32);
5257 vt_sp += ALIGN_TO (i32, MINT_VT_ALIGNMENT);
5258 ip += 2;
5259 break;
5261 default:
5262 ves_abort();
5265 ++ip;
5266 ++sp;
5267 MINT_IN_BREAK;
5269 MINT_IN_CASE(MINT_STELEM_I) /* fall through */
5270 MINT_IN_CASE(MINT_STELEM_I1) /* fall through */
5271 MINT_IN_CASE(MINT_STELEM_U1) /* fall through */
5272 MINT_IN_CASE(MINT_STELEM_I2) /* fall through */
5273 MINT_IN_CASE(MINT_STELEM_U2) /* fall through */
5274 MINT_IN_CASE(MINT_STELEM_I4) /* fall through */
5275 MINT_IN_CASE(MINT_STELEM_I8) /* fall through */
5276 MINT_IN_CASE(MINT_STELEM_R4) /* fall through */
5277 MINT_IN_CASE(MINT_STELEM_R8) /* fall through */
5278 MINT_IN_CASE(MINT_STELEM_REF) /* fall through */
5279 MINT_IN_CASE(MINT_STELEM_VT) {
5280 mono_u aindex;
5282 sp -= 3;
5284 o = sp [0].data.o;
5285 if (!o)
5286 THROW_EX (mono_get_exception_null_reference (), ip);
5288 aindex = sp [1].data.i;
5289 if (aindex >= mono_array_length_internal ((MonoArray *)o))
5290 THROW_EX (mono_get_exception_index_out_of_range (), ip);
5292 switch (*ip) {
5293 case MINT_STELEM_I:
5294 mono_array_set_fast ((MonoArray *)o, mono_i, aindex, sp [2].data.nati);
5295 break;
5296 case MINT_STELEM_I1:
5297 mono_array_set_fast ((MonoArray *)o, gint8, aindex, sp [2].data.i);
5298 break;
5299 case MINT_STELEM_U1:
5300 mono_array_set_fast ((MonoArray *) o, guint8, aindex, sp [2].data.i);
5301 break;
5302 case MINT_STELEM_I2:
5303 mono_array_set_fast ((MonoArray *)o, gint16, aindex, sp [2].data.i);
5304 break;
5305 case MINT_STELEM_U2:
5306 mono_array_set_fast ((MonoArray *)o, guint16, aindex, sp [2].data.i);
5307 break;
5308 case MINT_STELEM_I4:
5309 mono_array_set_fast ((MonoArray *)o, gint32, aindex, sp [2].data.i);
5310 break;
5311 case MINT_STELEM_I8:
5312 mono_array_set_fast ((MonoArray *)o, gint64, aindex, sp [2].data.l);
5313 break;
5314 case MINT_STELEM_R4:
5315 mono_array_set_fast ((MonoArray *)o, float, aindex, sp [2].data.f_r4);
5316 break;
5317 case MINT_STELEM_R8:
5318 mono_array_set_fast ((MonoArray *)o, double, aindex, sp [2].data.f);
5319 break;
5320 case MINT_STELEM_REF: {
5321 MonoObject *isinst_obj = mono_object_isinst_checked (sp [2].data.o, m_class_get_element_class (mono_object_class (o)), error);
5322 mono_error_cleanup (error); /* FIXME: don't swallow the error */
5323 if (sp [2].data.p && !isinst_obj)
5324 THROW_EX (mono_get_exception_array_type_mismatch (), ip);
5325 mono_array_setref_fast ((MonoArray *) o, aindex, sp [2].data.p);
5326 break;
5328 case MINT_STELEM_VT: {
5329 MonoClass *klass_vt = (MonoClass*)imethod->data_items [*(guint16 *) (ip + 1)];
5330 i32 = READ32 (ip + 2);
5331 char *dst_addr = mono_array_addr_with_size_fast ((MonoArray *) o, i32, aindex);
5333 mono_value_copy_internal (dst_addr, sp [2].data.vt, klass_vt);
5334 vt_sp -= ALIGN_TO (i32, MINT_VT_ALIGNMENT);
5335 ip += 3;
5336 break;
5338 default:
5339 ves_abort();
5342 ++ip;
5343 MINT_IN_BREAK;
5345 MINT_IN_CASE(MINT_CONV_OVF_I4_U4)
5346 if (sp [-1].data.i < 0)
5347 THROW_EX (mono_get_exception_overflow (), ip);
5348 ++ip;
5349 MINT_IN_BREAK;
5350 MINT_IN_CASE(MINT_CONV_OVF_I4_I8)
5351 if (sp [-1].data.l < G_MININT32 || sp [-1].data.l > G_MAXINT32)
5352 THROW_EX (mono_get_exception_overflow (), ip);
5353 sp [-1].data.i = (gint32) sp [-1].data.l;
5354 ++ip;
5355 MINT_IN_BREAK;
5356 MINT_IN_CASE(MINT_CONV_OVF_I4_U8)
5357 if (sp [-1].data.l < 0 || sp [-1].data.l > G_MAXINT32)
5358 THROW_EX (mono_get_exception_overflow (), ip);
5359 sp [-1].data.i = (gint32) sp [-1].data.l;
5360 ++ip;
5361 MINT_IN_BREAK;
5362 MINT_IN_CASE(MINT_CONV_OVF_I4_R4)
5363 if (sp [-1].data.f_r4 < G_MININT32 || sp [-1].data.f_r4 > G_MAXINT32)
5364 THROW_EX (mono_get_exception_overflow (), ip);
5365 sp [-1].data.i = (gint32) sp [-1].data.f_r4;
5366 ++ip;
5367 MINT_IN_BREAK;
5368 MINT_IN_CASE(MINT_CONV_OVF_I4_R8)
5369 if (sp [-1].data.f < G_MININT32 || sp [-1].data.f > G_MAXINT32)
5370 THROW_EX (mono_get_exception_overflow (), ip);
5371 sp [-1].data.i = (gint32) sp [-1].data.f;
5372 ++ip;
5373 MINT_IN_BREAK;
5374 MINT_IN_CASE(MINT_CONV_OVF_U4_I4)
5375 if (sp [-1].data.i < 0)
5376 THROW_EX (mono_get_exception_overflow (), ip);
5377 ++ip;
5378 MINT_IN_BREAK;
5379 MINT_IN_CASE(MINT_CONV_OVF_U4_I8)
5380 if (sp [-1].data.l < 0 || sp [-1].data.l > G_MAXUINT32)
5381 THROW_EX (mono_get_exception_overflow (), ip);
5382 sp [-1].data.i = (guint32) sp [-1].data.l;
5383 ++ip;
5384 MINT_IN_BREAK;
5385 MINT_IN_CASE(MINT_CONV_OVF_U4_R4)
5386 if (sp [-1].data.f_r4 < 0 || sp [-1].data.f_r4 > G_MAXUINT32)
5387 THROW_EX (mono_get_exception_overflow (), ip);
5388 sp [-1].data.i = (guint32) sp [-1].data.f_r4;
5389 ++ip;
5390 MINT_IN_BREAK;
5391 MINT_IN_CASE(MINT_CONV_OVF_U4_R8)
5392 if (sp [-1].data.f < 0 || sp [-1].data.f > G_MAXUINT32)
5393 THROW_EX (mono_get_exception_overflow (), ip);
5394 sp [-1].data.i = (guint32) sp [-1].data.f;
5395 ++ip;
5396 MINT_IN_BREAK;
5397 MINT_IN_CASE(MINT_CONV_OVF_I2_I4)
5398 if (sp [-1].data.i < G_MININT16 || sp [-1].data.i > G_MAXINT16)
5399 THROW_EX (mono_get_exception_overflow (), ip);
5400 ++ip;
5401 MINT_IN_BREAK;
5402 MINT_IN_CASE(MINT_CONV_OVF_I2_U4)
5403 if (sp [-1].data.i < 0 || sp [-1].data.i > G_MAXINT16)
5404 THROW_EX (mono_get_exception_overflow (), ip);
5405 ++ip;
5406 MINT_IN_BREAK;
5407 MINT_IN_CASE(MINT_CONV_OVF_I2_I8)
5408 if (sp [-1].data.l < G_MININT16 || sp [-1].data.l > G_MAXINT16)
5409 THROW_EX (mono_get_exception_overflow (), ip);
5410 sp [-1].data.i = (gint16) sp [-1].data.l;
5411 ++ip;
5412 MINT_IN_BREAK;
5413 MINT_IN_CASE(MINT_CONV_OVF_I2_U8)
5414 if (sp [-1].data.l < 0 || sp [-1].data.l > G_MAXINT16)
5415 THROW_EX (mono_get_exception_overflow (), ip);
5416 sp [-1].data.i = (gint16) sp [-1].data.l;
5417 ++ip;
5418 MINT_IN_BREAK;
5419 MINT_IN_CASE(MINT_CONV_OVF_I2_R8)
5420 if (sp [-1].data.f < G_MININT16 || sp [-1].data.f > G_MAXINT16)
5421 THROW_EX (mono_get_exception_overflow (), ip);
5422 sp [-1].data.i = (gint16) sp [-1].data.f;
5423 ++ip;
5424 MINT_IN_BREAK;
5425 MINT_IN_CASE(MINT_CONV_OVF_I2_UN_R8)
5426 if (sp [-1].data.f < 0 || sp [-1].data.f > G_MAXINT16)
5427 THROW_EX (mono_get_exception_overflow (), ip);
5428 sp [-1].data.i = (gint16) sp [-1].data.f;
5429 ++ip;
5430 MINT_IN_BREAK;
5431 MINT_IN_CASE(MINT_CONV_OVF_U2_I4)
5432 if (sp [-1].data.i < 0 || sp [-1].data.i > G_MAXUINT16)
5433 THROW_EX (mono_get_exception_overflow (), ip);
5434 ++ip;
5435 MINT_IN_BREAK;
5436 MINT_IN_CASE(MINT_CONV_OVF_U2_I8)
5437 if (sp [-1].data.l < 0 || sp [-1].data.l > G_MAXUINT16)
5438 THROW_EX (mono_get_exception_overflow (), ip);
5439 sp [-1].data.i = (guint16) sp [-1].data.l;
5440 ++ip;
5441 MINT_IN_BREAK;
5442 MINT_IN_CASE(MINT_CONV_OVF_U2_R8)
5443 if (sp [-1].data.f < 0 || sp [-1].data.f > G_MAXUINT16)
5444 THROW_EX (mono_get_exception_overflow (), ip);
5445 sp [-1].data.i = (guint16) sp [-1].data.f;
5446 ++ip;
5447 MINT_IN_BREAK;
5448 MINT_IN_CASE(MINT_CONV_OVF_I1_I4)
5449 if (sp [-1].data.i < G_MININT8 || sp [-1].data.i > G_MAXINT8)
5450 THROW_EX (mono_get_exception_overflow (), ip);
5451 ++ip;
5452 MINT_IN_BREAK;
5453 MINT_IN_CASE(MINT_CONV_OVF_I1_U4)
5454 if (sp [-1].data.i < 0 || sp [-1].data.i > G_MAXINT8)
5455 THROW_EX (mono_get_exception_overflow (), ip);
5456 ++ip;
5457 MINT_IN_BREAK;
5458 MINT_IN_CASE(MINT_CONV_OVF_I1_I8)
5459 if (sp [-1].data.l < G_MININT8 || sp [-1].data.l > G_MAXINT8)
5460 THROW_EX (mono_get_exception_overflow (), ip);
5461 sp [-1].data.i = (gint8) sp [-1].data.l;
5462 ++ip;
5463 MINT_IN_BREAK;
5464 MINT_IN_CASE(MINT_CONV_OVF_I1_U8)
5465 if (sp [-1].data.l < 0 || sp [-1].data.l > G_MAXINT8)
5466 THROW_EX (mono_get_exception_overflow (), ip);
5467 sp [-1].data.i = (gint8) sp [-1].data.l;
5468 ++ip;
5469 MINT_IN_BREAK;
5470 MINT_IN_CASE(MINT_CONV_OVF_I1_R8)
5471 if (sp [-1].data.f < G_MININT8 || sp [-1].data.f > G_MAXINT8)
5472 THROW_EX (mono_get_exception_overflow (), ip);
5473 sp [-1].data.i = (gint8) sp [-1].data.f;
5474 ++ip;
5475 MINT_IN_BREAK;
5476 MINT_IN_CASE(MINT_CONV_OVF_I1_UN_R8)
5477 if (sp [-1].data.f < 0 || sp [-1].data.f > G_MAXINT8)
5478 THROW_EX (mono_get_exception_overflow (), ip);
5479 sp [-1].data.i = (gint8) sp [-1].data.f;
5480 ++ip;
5481 MINT_IN_BREAK;
5482 MINT_IN_CASE(MINT_CONV_OVF_U1_I4)
5483 if (sp [-1].data.i < 0 || sp [-1].data.i > G_MAXUINT8)
5484 THROW_EX (mono_get_exception_overflow (), ip);
5485 ++ip;
5486 MINT_IN_BREAK;
5487 MINT_IN_CASE(MINT_CONV_OVF_U1_I8)
5488 if (sp [-1].data.l < 0 || sp [-1].data.l > G_MAXUINT8)
5489 THROW_EX (mono_get_exception_overflow (), ip);
5490 sp [-1].data.i = (guint8) sp [-1].data.l;
5491 ++ip;
5492 MINT_IN_BREAK;
5493 MINT_IN_CASE(MINT_CONV_OVF_U1_R8)
5494 if (sp [-1].data.f < 0 || sp [-1].data.f > G_MAXUINT8)
5495 THROW_EX (mono_get_exception_overflow (), ip);
5496 sp [-1].data.i = (guint8) sp [-1].data.f;
5497 ++ip;
5498 MINT_IN_BREAK;
5499 MINT_IN_CASE(MINT_CKFINITE)
5500 if (!mono_isfinite (sp [-1].data.f))
5501 THROW_EX (mono_get_exception_arithmetic (), ip);
5502 ++ip;
5503 MINT_IN_BREAK;
5504 MINT_IN_CASE(MINT_MKREFANY) {
5505 c = (MonoClass*)imethod->data_items [*(guint16 *)(ip + 1)];
5507 /* The value address is on the stack */
5508 gpointer addr = sp [-1].data.p;
5509 /* Push the typedref value on the stack */
5510 sp [-1].data.p = vt_sp;
5511 vt_sp += ALIGN_TO (sizeof (MonoTypedRef), MINT_VT_ALIGNMENT);
5513 MonoTypedRef *tref = (MonoTypedRef*)sp [-1].data.p;
5514 tref->klass = c;
5515 tref->type = m_class_get_byval_arg (c);
5516 tref->value = addr;
5518 ip += 2;
5519 MINT_IN_BREAK;
5521 MINT_IN_CASE(MINT_REFANYTYPE) {
5522 MonoTypedRef *tref = (MonoTypedRef*)sp [-1].data.p;
5523 MonoType *type = tref->type;
5525 vt_sp -= ALIGN_TO (sizeof (MonoTypedRef), MINT_VT_ALIGNMENT);
5526 sp [-1].data.p = vt_sp;
5527 vt_sp += 8;
5528 *(gpointer*)sp [-1].data.p = type;
5529 ip ++;
5530 MINT_IN_BREAK;
5532 MINT_IN_CASE(MINT_REFANYVAL) {
5533 MonoTypedRef *tref = (MonoTypedRef*)sp [-1].data.p;
5534 gpointer addr = tref->value;
5536 c = (MonoClass*)imethod->data_items [*(guint16 *)(ip + 1)];
5537 if (c != tref->klass)
5538 THROW_EX (mono_get_exception_invalid_cast (), ip);
5540 vt_sp -= ALIGN_TO (sizeof (MonoTypedRef), MINT_VT_ALIGNMENT);
5542 sp [-1].data.p = addr;
5543 ip += 2;
5544 MINT_IN_BREAK;
5546 MINT_IN_CASE(MINT_LDTOKEN)
5547 sp->data.p = vt_sp;
5548 vt_sp += 8;
5549 * (gpointer *)sp->data.p = imethod->data_items[*(guint16 *)(ip + 1)];
5550 ip += 2;
5551 ++sp;
5552 MINT_IN_BREAK;
5553 MINT_IN_CASE(MINT_ADD_OVF_I4)
5554 if (CHECK_ADD_OVERFLOW (sp [-2].data.i, sp [-1].data.i))
5555 THROW_EX (mono_get_exception_overflow (), ip);
5556 BINOP(i, +);
5557 MINT_IN_BREAK;
5558 MINT_IN_CASE(MINT_ADD_OVF_I8)
5559 if (CHECK_ADD_OVERFLOW64 (sp [-2].data.l, sp [-1].data.l))
5560 THROW_EX (mono_get_exception_overflow (), ip);
5561 BINOP(l, +);
5562 MINT_IN_BREAK;
5563 MINT_IN_CASE(MINT_ADD_OVF_UN_I4)
5564 if (CHECK_ADD_OVERFLOW_UN (sp [-2].data.i, sp [-1].data.i))
5565 THROW_EX (mono_get_exception_overflow (), ip);
5566 BINOP_CAST(i, +, guint32);
5567 MINT_IN_BREAK;
5568 MINT_IN_CASE(MINT_ADD_OVF_UN_I8)
5569 if (CHECK_ADD_OVERFLOW64_UN (sp [-2].data.l, sp [-1].data.l))
5570 THROW_EX (mono_get_exception_overflow (), ip);
5571 BINOP_CAST(l, +, guint64);
5572 MINT_IN_BREAK;
5573 MINT_IN_CASE(MINT_MUL_OVF_I4)
5574 if (CHECK_MUL_OVERFLOW (sp [-2].data.i, sp [-1].data.i))
5575 THROW_EX (mono_get_exception_overflow (), ip);
5576 BINOP(i, *);
5577 MINT_IN_BREAK;
5578 MINT_IN_CASE(MINT_MUL_OVF_I8)
5579 if (CHECK_MUL_OVERFLOW64 (sp [-2].data.l, sp [-1].data.l))
5580 THROW_EX (mono_get_exception_overflow (), ip);
5581 BINOP(l, *);
5582 MINT_IN_BREAK;
5583 MINT_IN_CASE(MINT_MUL_OVF_UN_I4)
5584 if (CHECK_MUL_OVERFLOW_UN (sp [-2].data.i, sp [-1].data.i))
5585 THROW_EX (mono_get_exception_overflow (), ip);
5586 BINOP_CAST(i, *, guint32);
5587 MINT_IN_BREAK;
5588 MINT_IN_CASE(MINT_MUL_OVF_UN_I8)
5589 if (CHECK_MUL_OVERFLOW64_UN (sp [-2].data.l, sp [-1].data.l))
5590 THROW_EX (mono_get_exception_overflow (), ip);
5591 BINOP_CAST(l, *, guint64);
5592 MINT_IN_BREAK;
5593 MINT_IN_CASE(MINT_SUB_OVF_I4)
5594 if (CHECK_SUB_OVERFLOW (sp [-2].data.i, sp [-1].data.i))
5595 THROW_EX (mono_get_exception_overflow (), ip);
5596 BINOP(i, -);
5597 MINT_IN_BREAK;
5598 MINT_IN_CASE(MINT_SUB_OVF_I8)
5599 if (CHECK_SUB_OVERFLOW64 (sp [-2].data.l, sp [-1].data.l))
5600 THROW_EX (mono_get_exception_overflow (), ip);
5601 BINOP(l, -);
5602 MINT_IN_BREAK;
5603 MINT_IN_CASE(MINT_SUB_OVF_UN_I4)
5604 if (CHECK_SUB_OVERFLOW_UN (sp [-2].data.i, sp [-1].data.i))
5605 THROW_EX (mono_get_exception_overflow (), ip);
5606 BINOP_CAST(i, -, guint32);
5607 MINT_IN_BREAK;
5608 MINT_IN_CASE(MINT_SUB_OVF_UN_I8)
5609 if (CHECK_SUB_OVERFLOW64_UN (sp [-2].data.l, sp [-1].data.l))
5610 THROW_EX (mono_get_exception_overflow (), ip);
5611 BINOP_CAST(l, -, guint64);
5612 MINT_IN_BREAK;
5613 MINT_IN_CASE(MINT_START_ABORT_PROT)
5614 mono_threads_begin_abort_protected_block ();
5615 ip ++;
5616 MINT_IN_BREAK;
5617 MINT_IN_CASE(MINT_ENDFINALLY) {
5618 ip ++;
5619 int clause_index = *ip;
5620 gboolean pending_abort = mono_threads_end_abort_protected_block ();
5622 if (clause_args && clause_index == clause_args->exit_clause)
5623 goto exit_frame;
5624 while (sp > frame->stack) {
5625 --sp;
5627 if (finally_ips) {
5628 ip = (const guint16*)finally_ips->data;
5629 finally_ips = g_slist_remove (finally_ips, ip);
5630 /* Throw abort after the last finally block to avoid confusing EH */
5631 if (pending_abort && !finally_ips)
5632 EXCEPTION_CHECKPOINT;
5633 goto main_loop;
5635 ves_abort();
5636 MINT_IN_BREAK;
5639 MINT_IN_CASE(MINT_LEAVE) /* Fall through */
5640 MINT_IN_CASE(MINT_LEAVE_S)
5641 while (sp > frame->stack) {
5642 --sp;
5644 frame->ip = ip;
5646 if (*ip == MINT_LEAVE_S) {
5647 ip += (short) *(ip + 1);
5648 } else {
5649 ip += (gint32) READ32 (ip + 1);
5651 endfinally_ip = ip;
5652 goto handle_finally;
5653 MINT_IN_BREAK;
5654 MINT_IN_CASE(MINT_LEAVE_CHECK)
5655 MINT_IN_CASE(MINT_LEAVE_S_CHECK)
5656 while (sp > frame->stack) {
5657 --sp;
5659 frame->ip = ip;
5661 if (imethod->method->wrapper_type != MONO_WRAPPER_RUNTIME_INVOKE) {
5662 stackval tmp_sp;
5664 child_frame.parent = frame;
5665 child_frame.imethod = NULL;
5667 * We need for mono_thread_get_undeniable_exception to be able to unwind
5668 * to check the abort threshold. For this to work we use child_frame as a
5669 * dummy frame that is stored in the lmf and serves as the transition frame
5671 do_icall_wrapper (&child_frame, NULL, MINT_ICALL_V_P, &tmp_sp, (gpointer)mono_thread_get_undeniable_exception);
5673 MonoException *abort_exc = (MonoException*)tmp_sp.data.p;
5674 if (abort_exc)
5675 THROW_EX (abort_exc, frame->ip);
5678 if (*ip == MINT_LEAVE_S_CHECK) {
5679 ip += (short) *(ip + 1);
5680 } else {
5681 ip += (gint32) READ32 (ip + 1);
5683 endfinally_ip = ip;
5684 goto handle_finally;
5685 MINT_IN_BREAK;
5686 MINT_IN_CASE(MINT_ICALL_V_V)
5687 MINT_IN_CASE(MINT_ICALL_V_P)
5688 MINT_IN_CASE(MINT_ICALL_P_V)
5689 MINT_IN_CASE(MINT_ICALL_P_P)
5690 MINT_IN_CASE(MINT_ICALL_PP_V)
5691 MINT_IN_CASE(MINT_ICALL_PP_P)
5692 MINT_IN_CASE(MINT_ICALL_PPP_V)
5693 MINT_IN_CASE(MINT_ICALL_PPP_P)
5694 MINT_IN_CASE(MINT_ICALL_PPPP_V)
5695 MINT_IN_CASE(MINT_ICALL_PPPP_P)
5696 MINT_IN_CASE(MINT_ICALL_PPPPP_V)
5697 MINT_IN_CASE(MINT_ICALL_PPPPP_P)
5698 MINT_IN_CASE(MINT_ICALL_PPPPPP_V)
5699 MINT_IN_CASE(MINT_ICALL_PPPPPP_P)
5700 frame->ip = ip;
5701 sp = do_icall_wrapper (frame, NULL, *ip, sp, imethod->data_items [*(guint16 *)(ip + 1)]);
5702 EXCEPTION_CHECKPOINT;
5703 CHECK_RESUME_STATE (context);
5704 ip += 2;
5705 MINT_IN_BREAK;
5706 MINT_IN_CASE(MINT_MONO_LDPTR)
5707 sp->data.p = imethod->data_items [*(guint16 *)(ip + 1)];
5708 ip += 2;
5709 ++sp;
5710 MINT_IN_BREAK;
5711 MINT_IN_CASE(MINT_MONO_NEWOBJ)
5712 sp->data.p = mono_object_new_checked (imethod->domain, (MonoClass*)imethod->data_items [*(guint16 *)(ip + 1)], error);
5713 mono_error_cleanup (error); /* FIXME: don't swallow the error */
5714 ip += 2;
5715 sp++;
5716 MINT_IN_BREAK;
5717 MINT_IN_CASE(MINT_MONO_FREE)
5718 ++ip;
5719 --sp;
5720 g_error ("that doesn't seem right");
5721 g_free (sp->data.p);
5722 MINT_IN_BREAK;
5723 MINT_IN_CASE(MINT_MONO_RETOBJ)
5724 ++ip;
5725 sp--;
5726 stackval_from_data (mono_method_signature_internal (imethod->method)->ret, frame->retval, sp->data.p,
5727 mono_method_signature_internal (imethod->method)->pinvoke);
5728 if (sp > frame->stack)
5729 g_warning ("retobj: more values on stack: %d", sp-frame->stack);
5730 goto exit_frame;
5731 MINT_IN_CASE(MINT_MONO_TLS) {
5732 MonoTlsKey key = (MonoTlsKey)*(gint32 *)(ip + 1);
5733 sp->data.p = mono_tls_get_tls_getter (key) (); // get function pointer and call it
5734 sp++;
5735 ip += 3;
5736 MINT_IN_BREAK;
5738 MINT_IN_CASE(MINT_MONO_MEMORY_BARRIER) {
5739 ++ip;
5740 mono_memory_barrier ();
5741 MINT_IN_BREAK;
5743 MINT_IN_CASE(MINT_MONO_LDDOMAIN)
5744 sp->data.p = mono_domain_get ();
5745 ++sp;
5746 ++ip;
5747 MINT_IN_BREAK;
5748 MINT_IN_CASE(MINT_SDB_INTR_LOC)
5749 if (G_UNLIKELY (ss_enabled)) {
5750 typedef void (*T) (void);
5751 static T ss_tramp;
5753 if (!ss_tramp) {
5754 void *tramp = mini_get_single_step_trampoline ();
5755 mono_memory_barrier ();
5756 ss_tramp = (T)tramp;
5760 * Make this point to the MINT_SDB_SEQ_POINT instruction which follows this since
5761 * the address of that instruction is stored as the seq point address.
5763 frame->ip = ip + 1;
5766 * Use the same trampoline as the JIT. This ensures that
5767 * the debugger has the context for the last interpreter
5768 * native frame.
5770 do_debugger_tramp (ss_tramp, frame);
5772 CHECK_RESUME_STATE (context);
5774 ++ip;
5775 MINT_IN_BREAK;
5776 MINT_IN_CASE(MINT_SDB_SEQ_POINT)
5777 /* Just a placeholder for a breakpoint */
5778 ++ip;
5779 MINT_IN_BREAK;
5780 MINT_IN_CASE(MINT_SDB_BREAKPOINT) {
5781 typedef void (*T) (void);
5782 static T bp_tramp;
5783 if (!bp_tramp) {
5784 void *tramp = mini_get_breakpoint_trampoline ();
5785 mono_memory_barrier ();
5786 bp_tramp = (T)tramp;
5789 frame->ip = ip;
5791 /* Use the same trampoline as the JIT */
5792 do_debugger_tramp (bp_tramp, frame);
5794 CHECK_RESUME_STATE (context);
5796 ++ip;
5797 MINT_IN_BREAK;
5800 #define RELOP(datamem, op) \
5801 --sp; \
5802 sp [-1].data.i = sp [-1].data.datamem op sp [0].data.datamem; \
5803 ++ip;
5805 #define RELOP_FP(datamem, op, noorder) \
5806 --sp; \
5807 if (mono_isunordered (sp [-1].data.datamem, sp [0].data.datamem)) \
5808 sp [-1].data.i = noorder; \
5809 else \
5810 sp [-1].data.i = sp [-1].data.datamem op sp [0].data.datamem; \
5811 ++ip;
5813 MINT_IN_CASE(MINT_CEQ_I4)
5814 RELOP(i, ==);
5815 MINT_IN_BREAK;
5816 MINT_IN_CASE(MINT_CEQ0_I4)
5817 sp [-1].data.i = (sp [-1].data.i == 0);
5818 ++ip;
5819 MINT_IN_BREAK;
5820 MINT_IN_CASE(MINT_CEQ_I8)
5821 RELOP(l, ==);
5822 MINT_IN_BREAK;
5823 MINT_IN_CASE(MINT_CEQ_R4)
5824 RELOP_FP(f_r4, ==, 0);
5825 MINT_IN_BREAK;
5826 MINT_IN_CASE(MINT_CEQ_R8)
5827 RELOP_FP(f, ==, 0);
5828 MINT_IN_BREAK;
5829 MINT_IN_CASE(MINT_CNE_I4)
5830 RELOP(i, !=);
5831 MINT_IN_BREAK;
5832 MINT_IN_CASE(MINT_CNE_I8)
5833 RELOP(l, !=);
5834 MINT_IN_BREAK;
5835 MINT_IN_CASE(MINT_CNE_R4)
5836 RELOP_FP(f_r4, !=, 1);
5837 MINT_IN_BREAK;
5838 MINT_IN_CASE(MINT_CNE_R8)
5839 RELOP_FP(f, !=, 1);
5840 MINT_IN_BREAK;
5841 MINT_IN_CASE(MINT_CGT_I4)
5842 RELOP(i, >);
5843 MINT_IN_BREAK;
5844 MINT_IN_CASE(MINT_CGT_I8)
5845 RELOP(l, >);
5846 MINT_IN_BREAK;
5847 MINT_IN_CASE(MINT_CGT_R4)
5848 RELOP_FP(f_r4, >, 0);
5849 MINT_IN_BREAK;
5850 MINT_IN_CASE(MINT_CGT_R8)
5851 RELOP_FP(f, >, 0);
5852 MINT_IN_BREAK;
5853 MINT_IN_CASE(MINT_CGE_I4)
5854 RELOP(i, >=);
5855 MINT_IN_BREAK;
5856 MINT_IN_CASE(MINT_CGE_I8)
5857 RELOP(l, >=);
5858 MINT_IN_BREAK;
5859 MINT_IN_CASE(MINT_CGE_R4)
5860 RELOP_FP(f_r4, >=, 0);
5861 MINT_IN_BREAK;
5862 MINT_IN_CASE(MINT_CGE_R8)
5863 RELOP_FP(f, >=, 0);
5864 MINT_IN_BREAK;
5866 #define RELOP_CAST(datamem, op, type) \
5867 --sp; \
5868 sp [-1].data.i = (type)sp [-1].data.datamem op (type)sp [0].data.datamem; \
5869 ++ip;
5871 MINT_IN_CASE(MINT_CGE_UN_I4)
5872 RELOP_CAST(l, >=, guint32);
5873 MINT_IN_BREAK;
5874 MINT_IN_CASE(MINT_CGE_UN_I8)
5875 RELOP_CAST(l, >=, guint64);
5876 MINT_IN_BREAK;
5878 MINT_IN_CASE(MINT_CGT_UN_I4)
5879 RELOP_CAST(i, >, guint32);
5880 MINT_IN_BREAK;
5881 MINT_IN_CASE(MINT_CGT_UN_I8)
5882 RELOP_CAST(l, >, guint64);
5883 MINT_IN_BREAK;
5884 MINT_IN_CASE(MINT_CGT_UN_R4)
5885 RELOP_FP(f_r4, >, 1);
5886 MINT_IN_BREAK;
5887 MINT_IN_CASE(MINT_CGT_UN_R8)
5888 RELOP_FP(f, >, 1);
5889 MINT_IN_BREAK;
5890 MINT_IN_CASE(MINT_CLT_I4)
5891 RELOP(i, <);
5892 MINT_IN_BREAK;
5893 MINT_IN_CASE(MINT_CLT_I8)
5894 RELOP(l, <);
5895 MINT_IN_BREAK;
5896 MINT_IN_CASE(MINT_CLT_R4)
5897 RELOP_FP(f_r4, <, 0);
5898 MINT_IN_BREAK;
5899 MINT_IN_CASE(MINT_CLT_R8)
5900 RELOP_FP(f, <, 0);
5901 MINT_IN_BREAK;
5902 MINT_IN_CASE(MINT_CLT_UN_I4)
5903 RELOP_CAST(i, <, guint32);
5904 MINT_IN_BREAK;
5905 MINT_IN_CASE(MINT_CLT_UN_I8)
5906 RELOP_CAST(l, <, guint64);
5907 MINT_IN_BREAK;
5908 MINT_IN_CASE(MINT_CLT_UN_R4)
5909 RELOP_FP(f_r4, <, 1);
5910 MINT_IN_BREAK;
5911 MINT_IN_CASE(MINT_CLT_UN_R8)
5912 RELOP_FP(f, <, 1);
5913 MINT_IN_BREAK;
5914 MINT_IN_CASE(MINT_CLE_I4)
5915 RELOP(i, <=);
5916 MINT_IN_BREAK;
5917 MINT_IN_CASE(MINT_CLE_I8)
5918 RELOP(l, <=);
5919 MINT_IN_BREAK;
5920 MINT_IN_CASE(MINT_CLE_UN_I4)
5921 RELOP_CAST(l, <=, guint32);
5922 MINT_IN_BREAK;
5923 MINT_IN_CASE(MINT_CLE_UN_I8)
5924 RELOP_CAST(l, <=, guint64);
5925 MINT_IN_BREAK;
5926 MINT_IN_CASE(MINT_CLE_R4)
5927 RELOP_FP(f_r4, <=, 0);
5928 MINT_IN_BREAK;
5929 MINT_IN_CASE(MINT_CLE_R8)
5930 RELOP_FP(f, <=, 0);
5931 MINT_IN_BREAK;
5933 #undef RELOP
5934 #undef RELOP_FP
5935 #undef RELOP_CAST
5937 MINT_IN_CASE(MINT_LDFTN) {
5938 sp->data.p = imethod->data_items [* (guint16 *)(ip + 1)];
5939 ++sp;
5940 ip += 2;
5941 MINT_IN_BREAK;
5943 MINT_IN_CASE(MINT_LDVIRTFTN) {
5944 InterpMethod *m = (InterpMethod*)imethod->data_items [* (guint16 *)(ip + 1)];
5945 ip += 2;
5946 --sp;
5947 if (!sp->data.p)
5948 THROW_EX (mono_get_exception_null_reference (), ip - 2);
5950 sp->data.p = get_virtual_method (m, sp->data.o);
5951 ++sp;
5952 MINT_IN_BREAK;
5954 MINT_IN_CASE(MINT_LDFTN_DYNAMIC) {
5955 ERROR_DECL (error);
5956 InterpMethod *m = mono_interp_get_imethod (mono_domain_get (), (MonoMethod*) sp [-1].data.p, error);
5957 mono_error_assert_ok (error);
5958 sp [-1].data.p = m;
5959 ip++;
5960 MINT_IN_BREAK;
5963 #define LDARG(datamem, argtype) \
5964 sp->data.datamem = (argtype) frame->stack_args [*(guint16 *)(ip + 1)].data.datamem; \
5965 ip += 2; \
5966 ++sp;
5968 MINT_IN_CASE(MINT_LDARG_I1) LDARG(i, gint8); MINT_IN_BREAK;
5969 MINT_IN_CASE(MINT_LDARG_U1) LDARG(i, guint8); MINT_IN_BREAK;
5970 MINT_IN_CASE(MINT_LDARG_I2) LDARG(i, gint16); MINT_IN_BREAK;
5971 MINT_IN_CASE(MINT_LDARG_U2) LDARG(i, guint16); MINT_IN_BREAK;
5972 MINT_IN_CASE(MINT_LDARG_I4) LDARG(i, gint32); MINT_IN_BREAK;
5973 MINT_IN_CASE(MINT_LDARG_I8) LDARG(l, gint64); MINT_IN_BREAK;
5974 MINT_IN_CASE(MINT_LDARG_R4) LDARG(f_r4, float); MINT_IN_BREAK;
5975 MINT_IN_CASE(MINT_LDARG_R8) LDARG(f, double); MINT_IN_BREAK;
5976 MINT_IN_CASE(MINT_LDARG_O) LDARG(p, gpointer); MINT_IN_BREAK;
5977 MINT_IN_CASE(MINT_LDARG_P) LDARG(p, gpointer); MINT_IN_BREAK;
5979 MINT_IN_CASE(MINT_LDARG_VT)
5980 sp->data.p = vt_sp;
5981 i32 = READ32(ip + 2);
5982 memcpy(sp->data.p, frame->stack_args [* (guint16 *)(ip + 1)].data.p, i32);
5983 vt_sp += ALIGN_TO (i32, MINT_VT_ALIGNMENT);
5984 ip += 4;
5985 ++sp;
5986 MINT_IN_BREAK;
5988 #define STARG(datamem, argtype) \
5989 --sp; \
5990 frame->stack_args [*(guint16 *)(ip + 1)].data.datamem = (argtype) sp->data.datamem; \
5991 ip += 2; \
5993 MINT_IN_CASE(MINT_STARG_I1) STARG(i, gint8); MINT_IN_BREAK;
5994 MINT_IN_CASE(MINT_STARG_U1) STARG(i, guint8); MINT_IN_BREAK;
5995 MINT_IN_CASE(MINT_STARG_I2) STARG(i, gint16); MINT_IN_BREAK;
5996 MINT_IN_CASE(MINT_STARG_U2) STARG(i, guint16); MINT_IN_BREAK;
5997 MINT_IN_CASE(MINT_STARG_I4) STARG(i, gint32); MINT_IN_BREAK;
5998 MINT_IN_CASE(MINT_STARG_I8) STARG(l, gint64); MINT_IN_BREAK;
5999 MINT_IN_CASE(MINT_STARG_R4) STARG(f_r4, float); MINT_IN_BREAK;
6000 MINT_IN_CASE(MINT_STARG_R8) STARG(f, double); MINT_IN_BREAK;
6001 MINT_IN_CASE(MINT_STARG_O) STARG(p, gpointer); MINT_IN_BREAK;
6002 MINT_IN_CASE(MINT_STARG_P) STARG(p, gpointer); MINT_IN_BREAK;
6004 MINT_IN_CASE(MINT_STARG_VT)
6005 i32 = READ32(ip + 2);
6006 --sp;
6007 memcpy(frame->stack_args [* (guint16 *)(ip + 1)].data.p, sp->data.p, i32);
6008 vt_sp -= ALIGN_TO (i32, MINT_VT_ALIGNMENT);
6009 ip += 4;
6010 MINT_IN_BREAK;
6012 MINT_IN_CASE(MINT_PROF_ENTER) {
6013 ip += 1;
6015 if (MONO_PROFILER_ENABLED (method_enter)) {
6016 MonoProfilerCallContext *prof_ctx = NULL;
6018 if (imethod->prof_flags & MONO_PROFILER_CALL_INSTRUMENTATION_ENTER_CONTEXT) {
6019 prof_ctx = g_new0 (MonoProfilerCallContext, 1);
6020 prof_ctx->interp_frame = frame;
6021 prof_ctx->method = imethod->method;
6024 MONO_PROFILER_RAISE (method_enter, (imethod->method, prof_ctx));
6026 g_free (prof_ctx);
6029 MINT_IN_BREAK;
6032 MINT_IN_CASE(MINT_TRACE_ENTER) {
6033 ip += 1;
6035 MonoProfilerCallContext *prof_ctx = g_alloca (sizeof (MonoProfilerCallContext));
6036 prof_ctx->interp_frame = frame;
6037 prof_ctx->method = imethod->method;
6039 mono_trace_enter_method (imethod->method, prof_ctx);
6040 MINT_IN_BREAK;
6043 MINT_IN_CASE(MINT_TRACE_EXIT) {
6044 ip += 1;
6046 MonoProfilerCallContext *prof_ctx = g_alloca (sizeof (MonoProfilerCallContext));
6047 prof_ctx->interp_frame = frame;
6048 prof_ctx->method = imethod->method;
6050 mono_trace_leave_method (imethod->method, prof_ctx);
6051 MINT_IN_BREAK;
6054 MINT_IN_CASE(MINT_LDARGA)
6055 sp->data.p = &frame->stack_args [* (guint16 *)(ip + 1)];
6056 ip += 2;
6057 ++sp;
6058 MINT_IN_BREAK;
6060 MINT_IN_CASE(MINT_LDARGA_VT)
6061 sp->data.p = frame->stack_args [* (guint16 *)(ip + 1)].data.p;
6062 ip += 2;
6063 ++sp;
6064 MINT_IN_BREAK;
6066 #define LDLOC(datamem, argtype) \
6067 sp->data.datamem = * (argtype *)(locals + * (guint16 *)(ip + 1)); \
6068 ip += 2; \
6069 ++sp;
6071 MINT_IN_CASE(MINT_LDLOC_I1) LDLOC(i, gint8); MINT_IN_BREAK;
6072 MINT_IN_CASE(MINT_LDLOC_U1) LDLOC(i, guint8); MINT_IN_BREAK;
6073 MINT_IN_CASE(MINT_LDLOC_I2) LDLOC(i, gint16); MINT_IN_BREAK;
6074 MINT_IN_CASE(MINT_LDLOC_U2) LDLOC(i, guint16); MINT_IN_BREAK;
6075 MINT_IN_CASE(MINT_LDLOC_I4) LDLOC(i, gint32); MINT_IN_BREAK;
6076 MINT_IN_CASE(MINT_LDLOC_I8) LDLOC(l, gint64); MINT_IN_BREAK;
6077 MINT_IN_CASE(MINT_LDLOC_R4) LDLOC(f_r4, float); MINT_IN_BREAK;
6078 MINT_IN_CASE(MINT_LDLOC_R8) LDLOC(f, double); MINT_IN_BREAK;
6079 MINT_IN_CASE(MINT_LDLOC_O) LDLOC(p, gpointer); MINT_IN_BREAK;
6080 MINT_IN_CASE(MINT_LDLOC_P) LDLOC(p, gpointer); MINT_IN_BREAK;
6082 MINT_IN_CASE(MINT_LDLOC_VT)
6083 sp->data.p = vt_sp;
6084 i32 = READ32(ip + 2);
6085 memcpy(sp->data.p, locals + * (guint16 *)(ip + 1), i32);
6086 vt_sp += ALIGN_TO (i32, MINT_VT_ALIGNMENT);
6087 ip += 4;
6088 ++sp;
6089 MINT_IN_BREAK;
6091 MINT_IN_CASE(MINT_LDLOCA_S)
6092 sp->data.p = locals + * (guint16 *)(ip + 1);
6093 ip += 2;
6094 ++sp;
6095 MINT_IN_BREAK;
6097 #define STLOC(datamem, argtype) \
6098 --sp; \
6099 * (argtype *)(locals + * (guint16 *)(ip + 1)) = sp->data.datamem; \
6100 ip += 2;
6102 MINT_IN_CASE(MINT_STLOC_I1) STLOC(i, gint8); MINT_IN_BREAK;
6103 MINT_IN_CASE(MINT_STLOC_U1) STLOC(i, guint8); MINT_IN_BREAK;
6104 MINT_IN_CASE(MINT_STLOC_I2) STLOC(i, gint16); MINT_IN_BREAK;
6105 MINT_IN_CASE(MINT_STLOC_U2) STLOC(i, guint16); MINT_IN_BREAK;
6106 MINT_IN_CASE(MINT_STLOC_I4) STLOC(i, gint32); MINT_IN_BREAK;
6107 MINT_IN_CASE(MINT_STLOC_I8) STLOC(l, gint64); MINT_IN_BREAK;
6108 MINT_IN_CASE(MINT_STLOC_R4) STLOC(f_r4, float); MINT_IN_BREAK;
6109 MINT_IN_CASE(MINT_STLOC_R8) STLOC(f, double); MINT_IN_BREAK;
6110 MINT_IN_CASE(MINT_STLOC_O) STLOC(p, gpointer); MINT_IN_BREAK;
6111 MINT_IN_CASE(MINT_STLOC_P) STLOC(p, gpointer); MINT_IN_BREAK;
6113 #define STLOC_NP(datamem, argtype) \
6114 * (argtype *)(locals + * (guint16 *)(ip + 1)) = sp [-1].data.datamem; \
6115 ip += 2;
6117 MINT_IN_CASE(MINT_STLOC_NP_I4) STLOC_NP(i, gint32); MINT_IN_BREAK;
6118 MINT_IN_CASE(MINT_STLOC_NP_O) STLOC_NP(p, gpointer); MINT_IN_BREAK;
6120 MINT_IN_CASE(MINT_STLOC_VT)
6121 i32 = READ32(ip + 2);
6122 --sp;
6123 memcpy(locals + * (guint16 *)(ip + 1), sp->data.p, i32);
6124 vt_sp -= ALIGN_TO (i32, MINT_VT_ALIGNMENT);
6125 ip += 4;
6126 MINT_IN_BREAK;
6128 MINT_IN_CASE(MINT_LOCALLOC) {
6129 if (sp != frame->stack + 1) /*FIX?*/
6130 THROW_EX (mono_get_exception_execution_engine (NULL), ip);
6132 int len = sp [-1].data.i;
6133 sp [-1].data.p = alloca (len);
6135 if (imethod->init_locals)
6136 memset (sp [-1].data.p, 0, len);
6137 ++ip;
6138 MINT_IN_BREAK;
6140 MINT_IN_CASE(MINT_ENDFILTER)
6141 /* top of stack is result of filter */
6142 frame->retval = &sp [-1];
6143 goto exit_frame;
6144 MINT_IN_CASE(MINT_INITOBJ)
6145 --sp;
6146 memset (sp->data.vt, 0, READ32(ip + 1));
6147 ip += 3;
6148 MINT_IN_BREAK;
6149 MINT_IN_CASE(MINT_CPBLK)
6150 sp -= 3;
6151 if (!sp [0].data.p || !sp [1].data.p)
6152 THROW_EX (mono_get_exception_null_reference(), ip - 1);
6153 ++ip;
6154 /* FIXME: value and size may be int64... */
6155 memcpy (sp [0].data.p, sp [1].data.p, sp [2].data.i);
6156 MINT_IN_BREAK;
6157 #if 0
6158 MINT_IN_CASE(MINT_CONSTRAINED_) {
6159 guint32 token;
6160 /* FIXME: implement */
6161 ++ip;
6162 token = READ32 (ip);
6163 ip += 2;
6164 MINT_IN_BREAK;
6166 #endif
6167 MINT_IN_CASE(MINT_INITBLK)
6168 sp -= 3;
6169 if (!sp [0].data.p)
6170 THROW_EX (mono_get_exception_null_reference(), ip - 1);
6171 ++ip;
6172 /* FIXME: value and size may be int64... */
6173 memset (sp [0].data.p, sp [1].data.i, sp [2].data.i);
6174 MINT_IN_BREAK;
6175 #if 0
6176 MINT_IN_CASE(MINT_NO_)
6177 /* FIXME: implement */
6178 ip += 2;
6179 MINT_IN_BREAK;
6180 #endif
6181 MINT_IN_CASE(MINT_RETHROW) {
6182 int exvar_offset = *(guint16*)(ip + 1);
6183 THROW_EX_GENERAL (*(MonoException**)(frame->locals + exvar_offset), ip, TRUE);
6184 MINT_IN_BREAK;
6186 MINT_IN_CASE(MINT_MONO_RETHROW) {
6188 * need to clarify what this should actually do:
6190 * Takes an exception from the stack and rethrows it.
6191 * This is useful for wrappers that don't want to have to
6192 * use CEE_THROW and lose the exception stacktrace.
6195 --sp;
6196 if (!sp->data.p)
6197 sp->data.p = mono_get_exception_null_reference ();
6199 THROW_EX_GENERAL ((MonoException *)sp->data.p, ip, TRUE);
6200 MINT_IN_BREAK;
6202 MINT_IN_CASE(MINT_LD_DELEGATE_METHOD_PTR) {
6203 MonoDelegate *del;
6205 --sp;
6206 del = (MonoDelegate*)sp->data.p;
6207 if (!del->interp_method) {
6208 /* Not created from interpreted code */
6209 ERROR_DECL (error);
6210 g_assert (del->method);
6211 del->interp_method = mono_interp_get_imethod (del->object.vtable->domain, del->method, error);
6212 mono_error_assert_ok (error);
6214 g_assert (del->interp_method);
6215 sp->data.p = del->interp_method;
6216 ++sp;
6217 ip += 1;
6218 MINT_IN_BREAK;
6220 MINT_IN_CASE(MINT_LD_DELEGATE_INVOKE_IMPL) {
6221 MonoDelegate *del;
6222 int n = *(guint16*)(ip + 1);
6223 del = (MonoDelegate*)sp [-n].data.p;
6224 if (!del->interp_invoke_impl) {
6226 * First time we are called. Set up the invoke wrapper. We might be able to do this
6227 * in ctor but we would need to handle AllocDelegateLike_internal separately
6229 ERROR_DECL (error);
6230 MonoMethod *invoke = mono_get_delegate_invoke_internal (del->object.vtable->klass);
6231 del->interp_invoke_impl = mono_interp_get_imethod (del->object.vtable->domain, mono_marshal_get_delegate_invoke (invoke, del), error);
6232 mono_error_assert_ok (error);
6234 sp ++;
6235 sp [-1].data.p = del->interp_invoke_impl;
6236 ip += 2;
6237 MINT_IN_BREAK;
6240 #define MATH_UNOP(mathfunc) \
6241 sp [-1].data.f = mathfunc (sp [-1].data.f); \
6242 ++ip;
6244 MINT_IN_CASE(MINT_ABS) MATH_UNOP(fabs); MINT_IN_BREAK;
6245 MINT_IN_CASE(MINT_ASIN) MATH_UNOP(asin); MINT_IN_BREAK;
6246 MINT_IN_CASE(MINT_ASINH) MATH_UNOP(asinh); MINT_IN_BREAK;
6247 MINT_IN_CASE(MINT_ACOS) MATH_UNOP(acos); MINT_IN_BREAK;
6248 MINT_IN_CASE(MINT_ACOSH) MATH_UNOP(acosh); MINT_IN_BREAK;
6249 MINT_IN_CASE(MINT_ATAN) MATH_UNOP(atan); MINT_IN_BREAK;
6250 MINT_IN_CASE(MINT_ATANH) MATH_UNOP(atanh); MINT_IN_BREAK;
6251 MINT_IN_CASE(MINT_COS) MATH_UNOP(cos); MINT_IN_BREAK;
6252 MINT_IN_CASE(MINT_CBRT) MATH_UNOP(cbrt); MINT_IN_BREAK;
6253 MINT_IN_CASE(MINT_COSH) MATH_UNOP(cosh); MINT_IN_BREAK;
6254 MINT_IN_CASE(MINT_SIN) MATH_UNOP(sin); MINT_IN_BREAK;
6255 MINT_IN_CASE(MINT_SQRT) MATH_UNOP(sqrt); MINT_IN_BREAK;
6256 MINT_IN_CASE(MINT_SINH) MATH_UNOP(sinh); MINT_IN_BREAK;
6257 MINT_IN_CASE(MINT_TAN) MATH_UNOP(tan); MINT_IN_BREAK;
6258 MINT_IN_CASE(MINT_TANH) MATH_UNOP(tanh); MINT_IN_BREAK;
6260 MINT_IN_CASE(MINT_INTRINS_ENUM_HASFLAG) {
6261 MonoClass *klass = (MonoClass*)imethod->data_items[* (guint16 *)(ip + 1)];
6262 guint64 a_val = 0, b_val = 0;
6264 stackval_to_data (m_class_get_byval_arg (klass), &sp [-2], &a_val, FALSE);
6265 stackval_to_data (m_class_get_byval_arg (klass), &sp [-1], &b_val, FALSE);
6266 sp--;
6267 sp [-1].data.i = (a_val & b_val) == b_val;
6268 ip += 2;
6269 MINT_IN_BREAK;
6271 MINT_IN_CASE(MINT_INTRINS_GET_HASHCODE) {
6272 sp [-1].data.i = mono_object_hash_internal (sp [-1].data.o);
6273 ip++;
6274 MINT_IN_BREAK;
6276 MINT_IN_CASE(MINT_INTRINS_GET_TYPE) {
6277 if (!sp[-1].data.o)
6278 THROW_EX (mono_get_exception_null_reference (), ip);
6279 sp [-1].data.o = (MonoObject*) sp [-1].data.o->vtable->type;
6280 ip++;
6281 MINT_IN_BREAK;
6284 MINT_IN_DEFAULT
6285 g_print ("Unimplemented opcode: %04x %s at 0x%x\n", *ip, mono_interp_opname[*ip], ip-imethod->code);
6286 THROW_EX (mono_get_exception_execution_engine ("Unimplemented opcode"), ip);
6290 g_assert_not_reached ();
6291 handle_finally:
6293 int i;
6294 guint32 ip_offset;
6295 MonoExceptionClause *clause;
6296 GSList *old_list = finally_ips;
6297 MonoMethod *method = imethod->method;
6299 #if DEBUG_INTERP
6300 if (tracing)
6301 g_print ("* Handle finally IL_%04x\n", endfinally_ip == NULL ? 0 : endfinally_ip - imethod->code);
6302 #endif
6303 if (imethod == NULL || (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
6304 || (method->iflags & (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL | METHOD_IMPL_ATTRIBUTE_RUNTIME))) {
6305 goto exit_frame;
6307 ip_offset = frame->ip - imethod->code;
6309 if (endfinally_ip != NULL)
6310 finally_ips = g_slist_prepend(finally_ips, (void *)endfinally_ip);
6312 for (i = imethod->num_clauses - 1; i >= 0; i--) {
6313 clause = &imethod->clauses [i];
6314 if (MONO_OFFSET_IN_CLAUSE (clause, ip_offset) && (endfinally_ip == NULL || !(MONO_OFFSET_IN_CLAUSE (clause, endfinally_ip - imethod->code)))) {
6315 if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY) {
6316 ip = imethod->code + clause->handler_offset;
6317 finally_ips = g_slist_prepend (finally_ips, (gpointer) ip);
6318 #if DEBUG_INTERP
6319 if (tracing)
6320 g_print ("* Found finally at IL_%04x with exception: %s\n", clause->handler_offset, frame->ex? "yes": "no");
6321 #endif
6326 endfinally_ip = NULL;
6328 if (old_list != finally_ips && finally_ips) {
6329 ip = (const guint16*)finally_ips->data;
6330 finally_ips = g_slist_remove (finally_ips, ip);
6331 sp = frame->stack; /* spec says stack should be empty at endfinally so it should be at the start too */
6332 vt_sp = (unsigned char *) sp + imethod->stack_size;
6333 goto main_loop;
6336 ves_abort();
6339 exit_frame:
6341 if (clause_args && clause_args->base_frame)
6342 memcpy (clause_args->base_frame->args, frame->args, imethod->alloca_size);
6344 if (!frame->ex && MONO_PROFILER_ENABLED (method_leave) &&
6345 imethod->prof_flags & MONO_PROFILER_CALL_INSTRUMENTATION_LEAVE) {
6346 MonoProfilerCallContext *prof_ctx = NULL;
6348 if (imethod->prof_flags & MONO_PROFILER_CALL_INSTRUMENTATION_LEAVE_CONTEXT) {
6349 prof_ctx = g_new0 (MonoProfilerCallContext, 1);
6350 prof_ctx->interp_frame = frame;
6351 prof_ctx->method = imethod->method;
6353 MonoType *rtype = mono_method_signature_internal (imethod->method)->ret;
6355 switch (rtype->type) {
6356 case MONO_TYPE_VOID:
6357 break;
6358 case MONO_TYPE_VALUETYPE:
6359 prof_ctx->return_value = frame->retval->data.p;
6360 break;
6361 default:
6362 prof_ctx->return_value = frame->retval;
6363 break;
6367 MONO_PROFILER_RAISE (method_leave, (imethod->method, prof_ctx));
6369 g_free (prof_ctx);
6370 } else if (frame->ex && imethod->prof_flags & MONO_PROFILER_CALL_INSTRUMENTATION_EXCEPTION_LEAVE)
6371 MONO_PROFILER_RAISE (method_exception_leave, (imethod->method, &frame->ex->object));
6373 DEBUG_LEAVE ();
6376 static void
6377 interp_parse_options (const char *options)
6379 char **args, **ptr;
6381 if (!options)
6382 return;
6384 args = g_strsplit (options, ",", -1);
6385 for (ptr = args; ptr && *ptr; ptr ++) {
6386 char *arg = *ptr;
6388 if (strncmp (arg, "jit=", 4) == 0)
6389 mono_interp_jit_classes = g_slist_prepend (mono_interp_jit_classes, arg + 4);
6390 if (strncmp (arg, "interp-only=", 4) == 0)
6391 mono_interp_only_classes = g_slist_prepend (mono_interp_only_classes, arg + strlen ("interp-only="));
6392 if (strncmp (arg, "-inline", 7) == 0)
6393 mono_interp_opt &= ~INTERP_OPT_INLINE;
6397 typedef int (*TestMethod) (void);
6400 * interp_set_resume_state:
6402 * Set the state the interpeter will continue to execute from after execution returns to the interpreter.
6404 static void
6405 interp_set_resume_state (MonoJitTlsData *jit_tls, MonoException *ex, MonoJitExceptionInfo *ei, MonoInterpFrameHandle interp_frame, gpointer handler_ip)
6407 ThreadContext *context;
6409 g_assert (jit_tls);
6410 context = (ThreadContext*)jit_tls->interp_context;
6411 g_assert (context);
6413 context->has_resume_state = TRUE;
6414 context->handler_frame = (InterpFrame*)interp_frame;
6415 context->handler_ei = ei;
6416 /* This is on the stack, so it doesn't need a wbarrier */
6417 context->handler_frame->ex = ex;
6418 /* Ditto */
6419 if (ei)
6420 *(MonoException**)(context->handler_frame->locals + ei->exvar_offset) = ex;
6421 context->handler_ip = (guint16*) handler_ip;
6425 * interp_run_finally:
6427 * Run the finally clause identified by CLAUSE_INDEX in the intepreter frame given by
6428 * frame->interp_frame.
6429 * Return TRUE if the finally clause threw an exception.
6431 static gboolean
6432 interp_run_finally (StackFrameInfo *frame, int clause_index, gpointer handler_ip, gpointer handler_ip_end)
6434 InterpFrame *iframe = (InterpFrame*)frame->interp_frame;
6435 ThreadContext *context = get_context ();
6436 const unsigned short *old_ip = iframe->ip;
6437 FrameClauseArgs clause_args;
6439 memset (&clause_args, 0, sizeof (FrameClauseArgs));
6440 clause_args.start_with_ip = (guint16*) handler_ip;
6441 clause_args.end_at_ip = (guint16*) handler_ip_end;
6442 clause_args.exit_clause = clause_index;
6444 interp_exec_method_full (iframe, context, &clause_args);
6445 if (context->has_resume_state) {
6446 return TRUE;
6447 } else {
6448 iframe->ip = old_ip;
6449 return FALSE;
6454 * interp_run_filter:
6456 * Run the filter clause identified by CLAUSE_INDEX in the intepreter frame given by
6457 * frame->interp_frame.
6459 static gboolean
6460 interp_run_filter (StackFrameInfo *frame, MonoException *ex, int clause_index, gpointer handler_ip, gpointer handler_ip_end)
6462 InterpFrame *iframe = (InterpFrame*)frame->interp_frame;
6463 ThreadContext *context = get_context ();
6464 InterpFrame child_frame;
6465 stackval retval;
6466 FrameClauseArgs clause_args;
6469 * Have to run the clause in a new frame which is a copy of IFRAME, since
6470 * during debugging, there are two copies of the frame on the stack.
6472 memset (&child_frame, 0, sizeof (InterpFrame));
6473 child_frame.imethod = iframe->imethod;
6474 child_frame.retval = &retval;
6475 child_frame.parent = iframe;
6476 child_frame.stack_args = iframe->stack_args;
6478 memset (&clause_args, 0, sizeof (FrameClauseArgs));
6479 clause_args.start_with_ip = (guint16*) handler_ip;
6480 clause_args.end_at_ip = (guint16*) handler_ip_end;
6481 clause_args.filter_exception = ex;
6482 clause_args.base_frame = iframe;
6484 interp_exec_method_full (&child_frame, context, &clause_args);
6485 /* ENDFILTER stores the result into child_frame->retval */
6486 return child_frame.retval->data.i ? TRUE : FALSE;
6489 typedef struct {
6490 InterpFrame *current;
6491 } StackIter;
6494 * interp_frame_iter_init:
6496 * Initialize an iterator for iterating through interpreted frames.
6498 static void
6499 interp_frame_iter_init (MonoInterpStackIter *iter, gpointer interp_exit_data)
6501 StackIter *stack_iter = (StackIter*)iter;
6503 stack_iter->current = (InterpFrame*)interp_exit_data;
6507 * interp_frame_iter_next:
6509 * Fill out FRAME with date for the next interpreter frame.
6511 static gboolean
6512 interp_frame_iter_next (MonoInterpStackIter *iter, StackFrameInfo *frame)
6514 StackIter *stack_iter = (StackIter*)iter;
6515 InterpFrame *iframe = stack_iter->current;
6517 memset (frame, 0, sizeof (StackFrameInfo));
6518 /* pinvoke frames doesn't have imethod set */
6519 while (iframe && !(iframe->imethod && iframe->imethod->code && iframe->imethod->jinfo))
6520 iframe = iframe->parent;
6521 if (!iframe)
6522 return FALSE;
6524 MonoMethod *method = iframe->imethod->method;
6525 frame->domain = iframe->imethod->domain;
6526 frame->interp_frame = iframe;
6527 frame->method = method;
6528 frame->actual_method = method;
6529 if (method && ((method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) || (method->iflags & (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL | METHOD_IMPL_ATTRIBUTE_RUNTIME)))) {
6530 frame->native_offset = -1;
6531 frame->type = FRAME_TYPE_MANAGED_TO_NATIVE;
6532 } else {
6533 frame->type = FRAME_TYPE_INTERP;
6534 /* This is the offset in the interpreter IR */
6535 frame->native_offset = (guint8*)iframe->ip - (guint8*)iframe->imethod->code;
6536 if (!method->wrapper_type || method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD)
6537 frame->managed = TRUE;
6539 frame->ji = iframe->imethod->jinfo;
6540 frame->frame_addr = iframe;
6542 stack_iter->current = iframe->parent;
6544 return TRUE;
6547 static MonoJitInfo*
6548 interp_find_jit_info (MonoDomain *domain, MonoMethod *method)
6550 InterpMethod* imethod;
6552 imethod = lookup_imethod (domain, method);
6553 if (imethod)
6554 return imethod->jinfo;
6555 else
6556 return NULL;
6559 static void
6560 interp_set_breakpoint (MonoJitInfo *jinfo, gpointer ip)
6562 guint16 *code = (guint16*)ip;
6563 g_assert (*code == MINT_SDB_SEQ_POINT);
6564 *code = MINT_SDB_BREAKPOINT;
6567 static void
6568 interp_clear_breakpoint (MonoJitInfo *jinfo, gpointer ip)
6570 guint16 *code = (guint16*)ip;
6571 g_assert (*code == MINT_SDB_BREAKPOINT);
6572 *code = MINT_SDB_SEQ_POINT;
6575 static MonoJitInfo*
6576 interp_frame_get_jit_info (MonoInterpFrameHandle frame)
6578 InterpFrame *iframe = (InterpFrame*)frame;
6580 g_assert (iframe->imethod);
6581 return iframe->imethod->jinfo;
6584 static gpointer
6585 interp_frame_get_ip (MonoInterpFrameHandle frame)
6587 InterpFrame *iframe = (InterpFrame*)frame;
6589 g_assert (iframe->imethod);
6590 return (gpointer)iframe->ip;
6593 static gpointer
6594 interp_frame_get_arg (MonoInterpFrameHandle frame, int pos)
6596 InterpFrame *iframe = (InterpFrame*)frame;
6597 MonoMethodSignature *sig;
6599 g_assert (iframe->imethod);
6601 sig = mono_method_signature_internal (iframe->imethod->method);
6602 return stackval_to_data_addr (sig->params [pos], &iframe->stack_args [pos + !!iframe->imethod->hasthis]);
6605 static gpointer
6606 interp_frame_get_local (MonoInterpFrameHandle frame, int pos)
6608 InterpFrame *iframe = (InterpFrame*)frame;
6610 g_assert (iframe->imethod);
6612 return iframe->locals + iframe->imethod->local_offsets [pos];
6615 static gpointer
6616 interp_frame_get_this (MonoInterpFrameHandle frame)
6618 InterpFrame *iframe = (InterpFrame*)frame;
6620 g_assert (iframe->imethod);
6621 g_assert (iframe->imethod->hasthis);
6622 return &iframe->stack_args [0].data.p;
6625 static MonoInterpFrameHandle
6626 interp_frame_get_parent (MonoInterpFrameHandle frame)
6628 InterpFrame *iframe = (InterpFrame*)frame;
6630 return iframe->parent;
6633 static void
6634 interp_start_single_stepping (void)
6636 ss_enabled = TRUE;
6639 static void
6640 interp_stop_single_stepping (void)
6642 ss_enabled = FALSE;
6645 static void
6646 register_interp_stats (void)
6648 mono_counters_init ();
6649 mono_counters_register ("Total transform time", MONO_COUNTER_INTERP | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_interp_stats.transform_time);
6650 mono_counters_register ("Methods inlined", MONO_COUNTER_INTERP | MONO_COUNTER_INT, &mono_interp_stats.inlined_methods);
6651 mono_counters_register ("Inline failures", MONO_COUNTER_INTERP | MONO_COUNTER_INT, &mono_interp_stats.inline_failures);
6654 void
6655 mono_ee_interp_init (const char *opts)
6657 g_assert (mono_ee_api_version () == MONO_EE_API_VERSION);
6658 g_assert (!interp_init_done);
6659 interp_init_done = TRUE;
6661 mono_native_tls_alloc (&thread_context_id, NULL);
6662 set_context (NULL);
6664 interp_parse_options (opts);
6665 if (mini_get_debug_options ()->mdb_optimizations)
6666 mono_interp_opt &= ~INTERP_OPT_INLINE;
6667 mono_interp_transform_init ();
6669 MonoEECallbacks c;
6670 #ifdef MONO_ARCH_HAVE_INTERP_ENTRY_TRAMPOLINE
6671 c.entry_from_trampoline = interp_entry_from_trampoline;
6672 #endif
6673 c.to_native_trampoline = interp_to_native_trampoline;
6674 c.create_method_pointer = interp_create_method_pointer;
6675 c.create_method_pointer_llvmonly = interp_create_method_pointer_llvmonly;
6676 c.runtime_invoke = interp_runtime_invoke;
6677 c.init_delegate = interp_init_delegate;
6678 c.delegate_ctor = interp_delegate_ctor;
6679 c.get_remoting_invoke = interp_get_remoting_invoke;
6680 c.set_resume_state = interp_set_resume_state;
6681 c.run_finally = interp_run_finally;
6682 c.run_filter = interp_run_filter;
6683 c.frame_iter_init = interp_frame_iter_init;
6684 c.frame_iter_next = interp_frame_iter_next;
6685 c.find_jit_info = interp_find_jit_info;
6686 c.set_breakpoint = interp_set_breakpoint;
6687 c.clear_breakpoint = interp_clear_breakpoint;
6688 c.frame_get_jit_info = interp_frame_get_jit_info;
6689 c.frame_get_ip = interp_frame_get_ip;
6690 c.frame_get_arg = interp_frame_get_arg;
6691 c.frame_get_local = interp_frame_get_local;
6692 c.frame_get_this = interp_frame_get_this;
6693 c.frame_get_parent = interp_frame_get_parent;
6694 c.frame_arg_to_data = interp_frame_arg_to_data;
6695 c.data_to_frame_arg = interp_data_to_frame_arg;
6696 c.frame_arg_to_storage = interp_frame_arg_to_storage;
6697 c.frame_arg_set_storage = interp_frame_arg_set_storage;
6698 c.start_single_stepping = interp_start_single_stepping;
6699 c.stop_single_stepping = interp_stop_single_stepping;
6700 mini_install_interp_callbacks (&c);
6702 register_interp_stats ();