[interp] Remove some null checks
[mono-project.git] / mono / mini / interp / interp.c
blobf6c4877f18452a0def1402f7ef24c670af528dc1
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 <signal.h>
25 #include <math.h>
26 #include <locale.h>
28 #include <mono/utils/gc_wrapper.h>
30 #ifdef HAVE_ALLOCA_H
31 # include <alloca.h>
32 #else
33 # ifdef __CYGWIN__
34 # define alloca __builtin_alloca
35 # endif
36 #endif
38 /* trim excessive headers */
39 #include <mono/metadata/image.h>
40 #include <mono/metadata/assembly-internals.h>
41 #include <mono/metadata/cil-coff.h>
42 #include <mono/metadata/mono-endian.h>
43 #include <mono/metadata/tabledefs.h>
44 #include <mono/metadata/tokentype.h>
45 #include <mono/metadata/loader.h>
46 #include <mono/metadata/threads.h>
47 #include <mono/metadata/threadpool.h>
48 #include <mono/metadata/profiler-private.h>
49 #include <mono/metadata/appdomain.h>
50 #include <mono/metadata/reflection.h>
51 #include <mono/metadata/exception.h>
52 #include <mono/metadata/verify.h>
53 #include <mono/metadata/opcodes.h>
54 #include <mono/metadata/debug-helpers.h>
55 #include <mono/metadata/mono-config.h>
56 #include <mono/metadata/marshal.h>
57 #include <mono/metadata/environment.h>
58 #include <mono/metadata/mono-debug.h>
59 #include <mono/metadata/gc-internals.h>
60 #include <mono/utils/atomic.h>
62 #include "interp.h"
63 #include "interp-internals.h"
64 #include "mintops.h"
65 #include "hacks.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/jit-icalls.h>
71 #include <mono/mini/debugger-agent.h>
72 #include <mono/mini/ee.h>
74 #ifdef TARGET_ARM
75 #include <mono/mini/mini-arm.h>
76 #endif
78 /* Mingw 2.1 doesnt need this any more, but leave it in for now for older versions */
79 #ifdef _WIN32
80 #define isnan _isnan
81 #define finite _finite
82 #endif
83 #ifndef HAVE_FINITE
84 #ifdef HAVE_ISFINITE
85 #define finite isfinite
86 #endif
87 #endif
89 static inline void
90 init_frame (InterpFrame *frame, InterpFrame *parent_frame, InterpMethod *rmethod, stackval *method_args, stackval *method_retval)
92 frame->parent = parent_frame;
93 frame->stack_args = method_args;
94 frame->retval = method_retval;
95 frame->imethod = rmethod;
96 frame->ex = NULL;
97 frame->ip = NULL;
98 frame->invoke_trap = 0;
101 #define INIT_FRAME(frame,parent_frame,method_args,method_retval,domain,mono_method,error) do { \
102 InterpMethod *_rmethod = mono_interp_get_imethod ((domain), (mono_method), (error)); \
103 init_frame ((frame), (parent_frame), _rmethod, (method_args), (method_retval)); \
104 } while (0)
107 * List of classes whose methods will be executed by transitioning to JITted code.
108 * Used for testing.
110 GSList *jit_classes;
111 /* If TRUE, interpreted code will be interrupted at function entry/backward branches */
112 static gboolean ss_enabled;
114 static gboolean interp_init_done = FALSE;
116 static char* dump_frame (InterpFrame *inv);
117 static MonoArray *get_trace_ips (MonoDomain *domain, InterpFrame *top);
118 static void interp_exec_method_full (InterpFrame *frame, ThreadContext *context, guint16 *start_with_ip, MonoException *filter_exception, int exit_at_finally, InterpFrame *base_frame);
119 static void interp_exec_method (InterpFrame *frame, ThreadContext *context);
121 typedef void (*ICallMethod) (InterpFrame *frame);
123 static MonoNativeTlsKey thread_context_id;
125 static char* dump_args (InterpFrame *inv);
127 #define DEBUG_INTERP 0
128 #define COUNT_OPS 0
129 #if DEBUG_INTERP
130 int mono_interp_traceopt = 2;
131 /* If true, then we output the opcodes as we interpret them */
132 static int global_tracing = 2;
134 static int debug_indent_level = 0;
136 static int break_on_method = 0;
137 static int nested_trace = 0;
138 static GList *db_methods = NULL;
140 static void
141 output_indent (void)
143 int h;
145 for (h = 0; h < debug_indent_level; h++)
146 g_print (" ");
149 static void
150 db_match_method (gpointer data, gpointer user_data)
152 MonoMethod *m = (MonoMethod*)user_data;
153 MonoMethodDesc *desc = data;
155 if (mono_method_desc_full_match (desc, m))
156 break_on_method = 1;
159 static void
160 debug_enter (InterpFrame *frame, int *tracing)
162 if (db_methods) {
163 g_list_foreach (db_methods, db_match_method, (gpointer)frame->imethod->method);
164 if (break_on_method)
165 *tracing = nested_trace ? (global_tracing = 2, 3) : 2;
166 break_on_method = 0;
168 if (*tracing) {
169 MonoMethod *method = frame->imethod->method;
170 char *mn, *args = dump_args (frame);
171 debug_indent_level++;
172 output_indent ();
173 mn = mono_method_full_name (method, FALSE);
174 g_print ("(%p) Entering %s (", mono_thread_internal_current (), mn);
175 g_free (mn);
176 g_print ("%s)\n", args);
177 g_free (args);
182 #define DEBUG_LEAVE() \
183 if (tracing) { \
184 char *mn, *args; \
185 args = dump_retval (frame); \
186 output_indent (); \
187 mn = mono_method_full_name (frame->imethod->method, FALSE); \
188 g_print ("(%p) Leaving %s", mono_thread_internal_current (), mn); \
189 g_free (mn); \
190 g_print (" => %s\n", args); \
191 g_free (args); \
192 debug_indent_level--; \
193 if (tracing == 3) global_tracing = 0; \
196 #else
198 int mono_interp_traceopt = 0;
199 static void debug_enter (InterpFrame *frame, int *tracing)
202 #define DEBUG_LEAVE()
204 #endif
206 static void
207 set_resume_state (ThreadContext *context, InterpFrame *frame)
209 frame->ex = NULL;
210 context->has_resume_state = 0;
211 context->handler_frame = NULL;
214 /* Set the current execution state to the resume state in context */
215 #define SET_RESUME_STATE(context) do { \
216 ip = (context)->handler_ip; \
217 /* spec says stack should be empty at endfinally so it should be at the start too */ \
218 sp = frame->stack; \
219 vt_sp = (unsigned char *) sp + rtm->stack_size; \
220 if (frame->ex) { \
221 sp->data.p = frame->ex; \
222 ++sp; \
224 set_resume_state ((context), (frame)); \
225 goto main_loop; \
226 } while (0)
228 static void
229 set_context (ThreadContext *context)
231 MonoJitTlsData *jit_tls;
233 mono_native_tls_set_value (thread_context_id, context);
234 jit_tls = mono_tls_get_jit_tls ();
235 if (jit_tls)
236 jit_tls->interp_context = context;
239 static void
240 ves_real_abort (int line, MonoMethod *mh,
241 const unsigned short *ip, stackval *stack, stackval *sp)
243 ERROR_DECL (error);
244 MonoMethodHeader *header = mono_method_get_header_checked (mh, error);
245 mono_error_cleanup (error); /* FIXME: don't swallow the error */
246 g_printerr ("Execution aborted in method: %s::%s\n", mh->klass->name, mh->name);
247 g_printerr ("Line=%d IP=0x%04lx, Aborted execution\n", line, ip-(const unsigned short *) header->code);
248 g_print ("0x%04x %02x\n", ip-(const unsigned short *) header->code, *ip);
249 mono_metadata_free_mh (header);
250 if (sp > stack)
251 printf ("\t[%ld] 0x%08x %0.5f\n", sp-stack, sp[-1].data.i, sp[-1].data.f);
254 #define ves_abort() \
255 do {\
256 ves_real_abort(__LINE__, frame->imethod->method, ip, frame->stack, sp); \
257 THROW_EX (mono_get_exception_execution_engine (NULL), ip); \
258 } while (0);
260 static InterpMethod*
261 lookup_imethod (MonoDomain *domain, MonoMethod *method)
263 InterpMethod *rtm;
264 MonoJitDomainInfo *info;
266 info = domain_jit_info (domain);
267 mono_domain_jit_code_hash_lock (domain);
268 rtm = mono_internal_hash_table_lookup (&info->interp_code_hash, method);
269 mono_domain_jit_code_hash_unlock (domain);
270 return rtm;
273 static gpointer
274 interp_get_remoting_invoke (gpointer imethod, MonoError *error)
276 #ifndef DISABLE_REMOTING
277 InterpMethod *imethod_cast = (InterpMethod*) imethod;
279 g_assert (mono_use_interpreter);
281 MonoMethod *remoting_invoke_method = mono_marshal_get_remoting_invoke (imethod_cast->method, error);
282 return_val_if_nok (error, NULL);
283 return mono_interp_get_imethod (mono_domain_get (), remoting_invoke_method, error);
284 #else
285 g_assert_not_reached ();
286 return NULL;
287 #endif
290 InterpMethod*
291 mono_interp_get_imethod (MonoDomain *domain, MonoMethod *method, MonoError *error)
293 InterpMethod *rtm;
294 MonoJitDomainInfo *info;
295 MonoMethodSignature *sig;
296 int i;
298 error_init (error);
300 info = domain_jit_info (domain);
301 mono_domain_jit_code_hash_lock (domain);
302 rtm = mono_internal_hash_table_lookup (&info->interp_code_hash, method);
303 mono_domain_jit_code_hash_unlock (domain);
304 if (rtm)
305 return rtm;
307 sig = mono_method_signature (method);
309 rtm = mono_domain_alloc0 (domain, sizeof (InterpMethod));
310 rtm->method = method;
311 rtm->domain = domain;
312 rtm->param_count = sig->param_count;
313 rtm->hasthis = sig->hasthis;
314 rtm->rtype = mini_get_underlying_type (sig->ret);
315 rtm->param_types = mono_domain_alloc0 (domain, sizeof (MonoType*) * sig->param_count);
316 for (i = 0; i < sig->param_count; ++i)
317 rtm->param_types [i] = mini_get_underlying_type (sig->params [i]);
319 mono_domain_jit_code_hash_lock (domain);
320 if (!mono_internal_hash_table_lookup (&info->interp_code_hash, method))
321 mono_internal_hash_table_insert (&info->interp_code_hash, method, rtm);
322 mono_domain_jit_code_hash_unlock (domain);
324 rtm->prof_flags = mono_profiler_get_call_instrumentation_flags (rtm->method);
326 return rtm;
329 static gpointer
330 interp_create_trampoline (MonoDomain *domain, MonoMethod *method, MonoError *error)
332 if (method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED)
333 method = mono_marshal_get_synchronized_wrapper (method);
334 return mono_interp_get_imethod (domain, method, error);
338 * interp_push_lmf:
340 * Push an LMF frame on the LMF stack
341 * to mark the transition to native code.
342 * This is needed for the native code to
343 * be able to do stack walks.
345 static void
346 interp_push_lmf (MonoLMFExt *ext, InterpFrame *frame)
348 memset (ext, 0, sizeof (MonoLMFExt));
349 ext->interp_exit = TRUE;
350 ext->interp_exit_data = frame;
352 mono_push_lmf (ext);
355 static void
356 interp_pop_lmf (MonoLMFExt *ext)
358 mono_pop_lmf (&ext->lmf);
361 static InterpMethod*
362 get_virtual_method (InterpMethod *imethod, MonoObject *obj)
364 MonoMethod *m = imethod->method;
365 MonoDomain *domain = imethod->domain;
366 InterpMethod *ret = NULL;
367 ERROR_DECL (error);
369 #ifndef DISABLE_REMOTING
370 if (mono_object_is_transparent_proxy (obj)) {
371 MonoMethod *remoting_invoke_method = mono_marshal_get_remoting_invoke_with_check (m, error);
372 mono_error_assert_ok (error);
373 ret = mono_interp_get_imethod (domain, remoting_invoke_method, error);
374 mono_error_assert_ok (error);
375 return ret;
377 #endif
379 if ((m->flags & METHOD_ATTRIBUTE_FINAL) || !(m->flags & METHOD_ATTRIBUTE_VIRTUAL)) {
380 if (m->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED) {
381 ret = mono_interp_get_imethod (domain, mono_marshal_get_synchronized_wrapper (m), error);
382 mono_error_cleanup (error); /* FIXME: don't swallow the error */
383 } else {
384 ret = imethod;
386 return ret;
389 mono_class_setup_vtable (obj->vtable->klass);
391 int slot = mono_method_get_vtable_slot (m);
392 if (mono_class_is_interface (m->klass)) {
393 g_assert (obj->vtable->klass != m->klass);
394 /* TODO: interface offset lookup is slow, go through IMT instead */
395 gboolean non_exact_match;
396 slot += mono_class_interface_offset_with_variance (obj->vtable->klass, m->klass, &non_exact_match);
399 MonoMethod *virtual_method = obj->vtable->klass->vtable [slot];
400 if (m->is_inflated && mono_method_get_context (m)->method_inst) {
401 MonoGenericContext context = { NULL, NULL };
403 if (mono_class_is_ginst (virtual_method->klass))
404 context.class_inst = mono_class_get_generic_class (virtual_method->klass)->context.class_inst;
405 else if (mono_class_is_gtd (virtual_method->klass))
406 context.class_inst = mono_class_get_generic_container (virtual_method->klass)->context.class_inst;
407 context.method_inst = mono_method_get_context (m)->method_inst;
409 virtual_method = mono_class_inflate_generic_method_checked (virtual_method, &context, error);
410 mono_error_cleanup (error); /* FIXME: don't swallow the error */
413 if (virtual_method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED) {
414 virtual_method = mono_marshal_get_synchronized_wrapper (virtual_method);
417 InterpMethod *virtual_imethod = mono_interp_get_imethod (domain, virtual_method, error);
418 mono_error_cleanup (error); /* FIXME: don't swallow the error */
419 return virtual_imethod;
422 static void inline
423 stackval_from_data (MonoType *type_, stackval *result, char *data, gboolean pinvoke)
425 MonoType *type = mini_native_type_replace_type (type_);
426 if (type->byref) {
427 switch (type->type) {
428 case MONO_TYPE_OBJECT:
429 case MONO_TYPE_CLASS:
430 case MONO_TYPE_STRING:
431 case MONO_TYPE_ARRAY:
432 case MONO_TYPE_SZARRAY:
433 break;
434 default:
435 break;
437 result->data.p = *(gpointer*)data;
438 return;
440 switch (type->type) {
441 case MONO_TYPE_VOID:
442 return;
443 case MONO_TYPE_I1:
444 result->data.i = *(gint8*)data;
445 return;
446 case MONO_TYPE_U1:
447 case MONO_TYPE_BOOLEAN:
448 result->data.i = *(guint8*)data;
449 return;
450 case MONO_TYPE_I2:
451 result->data.i = *(gint16*)data;
452 return;
453 case MONO_TYPE_U2:
454 case MONO_TYPE_CHAR:
455 result->data.i = *(guint16*)data;
456 return;
457 case MONO_TYPE_I4:
458 result->data.i = *(gint32*)data;
459 return;
460 case MONO_TYPE_U:
461 case MONO_TYPE_I:
462 result->data.nati = *(mono_i*)data;
463 return;
464 case MONO_TYPE_PTR:
465 result->data.p = *(gpointer*)data;
466 return;
467 case MONO_TYPE_U4:
468 result->data.i = *(guint32*)data;
469 return;
470 case MONO_TYPE_R4: {
471 float tmp;
472 /* memmove handles unaligned case */
473 memmove (&tmp, data, sizeof (float));
474 result->data.f = tmp;
475 return;
477 case MONO_TYPE_I8:
478 case MONO_TYPE_U8:
479 memmove (&result->data.l, data, sizeof (gint64));
480 return;
481 case MONO_TYPE_R8:
482 memmove (&result->data.f, data, sizeof (double));
483 return;
484 case MONO_TYPE_STRING:
485 case MONO_TYPE_SZARRAY:
486 case MONO_TYPE_CLASS:
487 case MONO_TYPE_OBJECT:
488 case MONO_TYPE_ARRAY:
489 result->data.p = *(gpointer*)data;
490 return;
491 case MONO_TYPE_VALUETYPE:
492 if (type->data.klass->enumtype) {
493 stackval_from_data (mono_class_enum_basetype (type->data.klass), result, data, pinvoke);
494 return;
495 } else if (pinvoke) {
496 memcpy (result->data.vt, data, mono_class_native_size (type->data.klass, NULL));
497 } else {
498 mono_value_copy (result->data.vt, data, type->data.klass);
500 return;
501 case MONO_TYPE_GENERICINST: {
502 if (mono_type_generic_inst_is_valuetype (type)) {
503 mono_value_copy (result->data.vt, data, mono_class_from_mono_type (type));
504 return;
506 stackval_from_data (&type->data.generic_class->container_class->byval_arg, result, data, pinvoke);
507 return;
509 default:
510 g_error ("got type 0x%02x", type->type);
514 static void inline
515 stackval_to_data (MonoType *type_, stackval *val, char *data, gboolean pinvoke)
517 MonoType *type = mini_native_type_replace_type (type_);
518 if (type->byref) {
519 gpointer *p = (gpointer*)data;
520 *p = val->data.p;
521 return;
523 /* printf ("TODAT0 %p\n", data); */
524 switch (type->type) {
525 case MONO_TYPE_I1:
526 case MONO_TYPE_U1: {
527 guint8 *p = (guint8*)data;
528 *p = val->data.i;
529 return;
531 case MONO_TYPE_BOOLEAN: {
532 guint8 *p = (guint8*)data;
533 *p = (val->data.i != 0);
534 return;
536 case MONO_TYPE_I2:
537 case MONO_TYPE_U2:
538 case MONO_TYPE_CHAR: {
539 guint16 *p = (guint16*)data;
540 *p = val->data.i;
541 return;
543 case MONO_TYPE_I: {
544 mono_i *p = (mono_i*)data;
545 /* In theory the value used by stloc should match the local var type
546 but in practice it sometimes doesn't (a int32 gets dup'd and stloc'd into
547 a native int - both by csc and mcs). Not sure what to do about sign extension
548 as it is outside the spec... doing the obvious */
549 *p = (mono_i)val->data.nati;
550 return;
552 case MONO_TYPE_U: {
553 mono_u *p = (mono_u*)data;
554 /* see above. */
555 *p = (mono_u)val->data.nati;
556 return;
558 case MONO_TYPE_I4:
559 case MONO_TYPE_U4: {
560 gint32 *p = (gint32*)data;
561 *p = val->data.i;
562 return;
564 case MONO_TYPE_I8:
565 case MONO_TYPE_U8: {
566 gint64 *p = (gint64*)data;
567 *p = val->data.l;
568 return;
570 case MONO_TYPE_R4: {
571 float *p = (float*)data;
572 *p = val->data.f;
573 return;
575 case MONO_TYPE_R8: {
576 double *p = (double*)data;
577 *p = val->data.f;
578 return;
580 case MONO_TYPE_STRING:
581 case MONO_TYPE_SZARRAY:
582 case MONO_TYPE_CLASS:
583 case MONO_TYPE_OBJECT:
584 case MONO_TYPE_ARRAY: {
585 gpointer *p = (gpointer *) data;
586 mono_gc_wbarrier_generic_store (p, val->data.p);
587 return;
589 case MONO_TYPE_PTR: {
590 gpointer *p = (gpointer *) data;
591 *p = val->data.p;
592 return;
594 case MONO_TYPE_VALUETYPE:
595 if (type->data.klass->enumtype) {
596 stackval_to_data (mono_class_enum_basetype (type->data.klass), val, data, pinvoke);
597 return;
598 } else if (pinvoke) {
599 memcpy (data, val->data.vt, mono_class_native_size (type->data.klass, NULL));
600 } else {
601 mono_value_copy (data, val->data.vt, type->data.klass);
603 return;
604 case MONO_TYPE_GENERICINST: {
605 MonoClass *container_class = type->data.generic_class->container_class;
607 if (container_class->valuetype && !container_class->enumtype) {
608 mono_value_copy (data, val->data.vt, mono_class_from_mono_type (type));
609 return;
611 stackval_to_data (&type->data.generic_class->container_class->byval_arg, val, data, pinvoke);
612 return;
614 default:
615 g_error ("got type %x", type->type);
620 * Same as stackval_to_data but return address of storage instead
621 * of copying the value.
623 static gpointer
624 stackval_to_data_addr (MonoType *type_, stackval *val)
626 MonoType *type = mini_native_type_replace_type (type_);
627 if (type->byref)
628 return &val->data.p;
630 switch (type->type) {
631 case MONO_TYPE_I1:
632 case MONO_TYPE_U1:
633 case MONO_TYPE_BOOLEAN:
634 case MONO_TYPE_I2:
635 case MONO_TYPE_U2:
636 case MONO_TYPE_CHAR:
637 case MONO_TYPE_I4:
638 case MONO_TYPE_U4:
639 return &val->data.i;
640 case MONO_TYPE_I:
641 case MONO_TYPE_U:
642 return &val->data.nati;
643 case MONO_TYPE_I8:
644 case MONO_TYPE_U8:
645 return &val->data.l;
646 case MONO_TYPE_R4:
647 case MONO_TYPE_R8:
648 return &val->data.f;
649 case MONO_TYPE_STRING:
650 case MONO_TYPE_SZARRAY:
651 case MONO_TYPE_CLASS:
652 case MONO_TYPE_OBJECT:
653 case MONO_TYPE_ARRAY:
654 case MONO_TYPE_PTR:
655 return &val->data.p;
656 case MONO_TYPE_VALUETYPE:
657 if (type->data.klass->enumtype)
658 return stackval_to_data_addr (mono_class_enum_basetype (type->data.klass), val);
659 else
660 return val->data.vt;
661 case MONO_TYPE_GENERICINST: {
662 MonoClass *container_class = type->data.generic_class->container_class;
664 if (container_class->valuetype && !container_class->enumtype)
665 return val->data.vt;
666 return stackval_to_data_addr (&type->data.generic_class->container_class->byval_arg, val);
668 default:
669 g_error ("got type %x", type->type);
674 * interp_throw:
675 * Throw an exception from the interpreter.
677 static MONO_NEVER_INLINE void
678 interp_throw (ThreadContext *context, MonoException *ex, InterpFrame *frame, gconstpointer ip, gboolean rethrow)
680 MonoLMFExt ext;
682 interp_push_lmf (&ext, frame);
683 frame->ip = ip;
684 frame->ex = ex;
686 if (!rethrow) {
687 ex->stack_trace = NULL;
688 ex->trace_ips = NULL;
691 MonoContext ctx;
692 memset (&ctx, 0, sizeof (MonoContext));
693 MONO_CONTEXT_SET_SP (&ctx, frame);
696 * Call the JIT EH code. The EH code will call back to us using:
697 * - mono_interp_set_resume_state ()/run_finally ()/run_filter ().
698 * Since ctx.ip is 0, this will start unwinding from the LMF frame
699 * pushed above, which points to our frames.
701 mono_handle_exception (&ctx, (MonoObject*)ex);
703 interp_pop_lmf (&ext);
705 g_assert (context->has_resume_state);
708 static void
709 fill_in_trace (MonoException *exception, InterpFrame *frame)
711 ERROR_DECL (error);
712 char *stack_trace = dump_frame (frame);
713 MonoDomain *domain = frame->imethod->domain;
714 (exception)->stack_trace = mono_string_new_checked (domain, stack_trace, error);
715 mono_error_cleanup (error); /* FIXME: don't swallow the error */
716 (exception)->trace_ips = get_trace_ips (domain, frame);
717 g_free (stack_trace);
720 #define FILL_IN_TRACE(exception, frame) fill_in_trace(exception, frame)
722 #define THROW_EX_GENERAL(exception,ex_ip, rethrow) \
723 do { \
724 interp_throw (context, (exception), (frame), (ex_ip), (rethrow)); \
725 if (frame == context->handler_frame) \
726 SET_RESUME_STATE (context); \
727 else \
728 goto exit_frame; \
729 } while (0)
731 #define THROW_EX(exception,ex_ip) THROW_EX_GENERAL ((exception), (ex_ip), FALSE)
734 * Its possible for child_frame.ex to contain an unthrown exception, if the transform phase
735 * produced one.
737 #define CHECK_CHILD_EX(child_frame, ip) do { \
738 if ((child_frame).ex) \
739 THROW_EX ((child_frame).ex, (ip)); \
740 } while (0)
742 #define EXCEPTION_CHECKPOINT \
743 do { \
744 if (*mono_thread_interruption_request_flag ()) { \
745 MonoException *exc = mono_thread_interruption_checkpoint (); \
746 if (exc) \
747 THROW_EX (exc, ip); \
749 } while (0)
752 static MonoObject*
753 ves_array_create (InterpFrame *frame, MonoDomain *domain, MonoClass *klass, MonoMethodSignature *sig, stackval *values)
755 uintptr_t *lengths;
756 intptr_t *lower_bounds;
757 MonoObject *obj;
758 ERROR_DECL (error);
759 int i;
761 lengths = alloca (sizeof (uintptr_t) * klass->rank * 2);
762 for (i = 0; i < sig->param_count; ++i) {
763 lengths [i] = values->data.i;
764 values ++;
766 if (klass->rank == sig->param_count) {
767 /* Only lengths provided. */
768 lower_bounds = NULL;
769 } else {
770 /* lower bounds are first. */
771 lower_bounds = (intptr_t *) lengths;
772 lengths += klass->rank;
774 obj = (MonoObject*) mono_array_new_full_checked (domain, klass, lengths, lower_bounds, error);
775 if (!mono_error_ok (error)) {
776 frame->ex = mono_error_convert_to_exception (error);
777 FILL_IN_TRACE (frame->ex, frame);
779 mono_error_cleanup (error); /* FIXME: don't swallow the error */
780 return obj;
783 static gint32
784 ves_array_calculate_index (MonoArray *ao, stackval *sp, InterpFrame *frame, gboolean safe)
786 g_assert (!frame->ex);
787 MonoClass *ac = ((MonoObject *) ao)->vtable->klass;
789 guint32 pos = 0;
790 if (ao->bounds) {
791 for (gint32 i = 0; i < ac->rank; i++) {
792 guint32 idx = sp [i].data.i;
793 guint32 lower = ao->bounds [i].lower_bound;
794 guint32 len = ao->bounds [i].length;
795 if (safe && (idx < lower || (idx - lower) >= len)) {
796 frame->ex = mono_get_exception_index_out_of_range ();
797 FILL_IN_TRACE (frame->ex, frame);
798 return -1;
800 pos = (pos * len) + idx - lower;
802 } else {
803 pos = sp [0].data.i;
804 if (safe && pos >= ao->max_length) {
805 frame->ex = mono_get_exception_index_out_of_range ();
806 FILL_IN_TRACE (frame->ex, frame);
807 return -1;
810 return pos;
813 static void
814 ves_array_set (InterpFrame *frame)
816 stackval *sp = frame->stack_args + 1;
818 MonoObject *o = frame->stack_args->data.p;
819 MonoArray *ao = (MonoArray *) o;
820 MonoClass *ac = o->vtable->klass;
822 g_assert (ac->rank >= 1);
824 gint32 pos = ves_array_calculate_index (ao, sp, frame, TRUE);
825 if (frame->ex)
826 return;
828 if (sp [ac->rank].data.p && !mono_object_class (o)->element_class->valuetype) {
829 ERROR_DECL (error);
830 MonoObject *isinst = mono_object_isinst_checked (sp [ac->rank].data.p, mono_object_class (o)->element_class, error);
831 mono_error_cleanup (error);
832 if (!isinst) {
833 frame->ex = mono_get_exception_array_type_mismatch ();
834 FILL_IN_TRACE (frame->ex, frame);
835 return;
839 gint32 esize = mono_array_element_size (ac);
840 gpointer ea = mono_array_addr_with_size (ao, esize, pos);
842 MonoType *mt = mono_method_signature (frame->imethod->method)->params [ac->rank];
843 stackval_to_data (mt, &sp [ac->rank], ea, FALSE);
846 static void
847 ves_array_get (InterpFrame *frame, gboolean safe)
849 stackval *sp = frame->stack_args + 1;
851 MonoObject *o = frame->stack_args->data.p;
852 MonoArray *ao = (MonoArray *) o;
853 MonoClass *ac = o->vtable->klass;
855 g_assert (ac->rank >= 1);
857 gint32 pos = ves_array_calculate_index (ao, sp, frame, safe);
858 if (frame->ex)
859 return;
861 gint32 esize = mono_array_element_size (ac);
862 gpointer ea = mono_array_addr_with_size (ao, esize, pos);
864 MonoType *mt = mono_method_signature (frame->imethod->method)->ret;
865 stackval_from_data (mt, frame->retval, ea, FALSE);
868 static gpointer
869 ves_array_element_address (InterpFrame *frame, MonoClass *required_type, MonoArray *ao, stackval *sp, gboolean needs_typecheck)
871 MonoClass *ac = ((MonoObject *) ao)->vtable->klass;
873 g_assert (ac->rank >= 1);
875 gint32 pos = ves_array_calculate_index (ao, sp, frame, TRUE);
876 if (frame->ex)
877 return NULL;
879 if (needs_typecheck && !mono_class_is_assignable_from (mono_object_class ((MonoObject *) ao)->element_class, required_type->element_class)) {
880 frame->ex = mono_get_exception_array_type_mismatch ();
881 FILL_IN_TRACE (frame->ex, frame);
882 return NULL;
884 gint32 esize = mono_array_element_size (ac);
885 return mono_array_addr_with_size (ao, esize, pos);
888 static void
889 interp_walk_stack_with_ctx (MonoInternalStackWalk func, MonoContext *ctx, MonoUnwindOptions options, void *user_data)
891 ThreadContext *context = mono_native_tls_get_value (thread_context_id);
893 if (!context)
894 return;
896 InterpFrame *frame = context->current_frame;
898 while (frame) {
899 MonoStackFrameInfo fi;
900 memset (&fi, 0, sizeof (MonoStackFrameInfo));
902 /* TODO: hack to make some asserts happy. */
903 fi.ji = (MonoJitInfo *) frame->imethod;
905 if (frame->imethod)
906 fi.method = fi.actual_method = frame->imethod->method;
908 if (!fi.method || (fi.method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) || (fi.method->iflags & (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL | METHOD_IMPL_ATTRIBUTE_RUNTIME))) {
909 fi.native_offset = -1;
910 fi.type = FRAME_TYPE_MANAGED_TO_NATIVE;
911 } else {
912 fi.type = FRAME_TYPE_MANAGED;
913 fi.native_offset = frame->ip - frame->imethod->code;
914 if (!fi.method->wrapper_type)
915 fi.managed = TRUE;
918 if (func (&fi, ctx, user_data))
919 return;
920 frame = frame->parent;
924 static MonoPIFunc mono_interp_to_native_trampoline = NULL;
926 #ifndef MONO_ARCH_HAVE_INTERP_PINVOKE_TRAMP
927 static InterpMethodArguments* build_args_from_sig (MonoMethodSignature *sig, InterpFrame *frame)
929 InterpMethodArguments *margs = g_malloc0 (sizeof (InterpMethodArguments));
931 #ifdef TARGET_ARM
932 g_assert (mono_arm_eabi_supported ());
933 int i8_align = mono_arm_i8_align ();
934 #endif
936 #ifdef TARGET_WASM
937 margs->sig = sig;
938 #endif
940 if (sig->hasthis)
941 margs->ilen++;
943 for (int i = 0; i < sig->param_count; i++) {
944 guint32 ptype = sig->params [i]->byref ? MONO_TYPE_PTR : sig->params [i]->type;
945 switch (ptype) {
946 case MONO_TYPE_BOOLEAN:
947 case MONO_TYPE_CHAR:
948 case MONO_TYPE_I1:
949 case MONO_TYPE_U1:
950 case MONO_TYPE_I2:
951 case MONO_TYPE_U2:
952 case MONO_TYPE_I4:
953 case MONO_TYPE_U4:
954 case MONO_TYPE_I:
955 case MONO_TYPE_U:
956 case MONO_TYPE_PTR:
957 case MONO_TYPE_SZARRAY:
958 case MONO_TYPE_CLASS:
959 case MONO_TYPE_OBJECT:
960 case MONO_TYPE_STRING:
961 case MONO_TYPE_VALUETYPE:
962 case MONO_TYPE_GENERICINST:
963 #if SIZEOF_VOID_P == 8
964 case MONO_TYPE_I8:
965 case MONO_TYPE_U8:
966 #endif
967 margs->ilen++;
968 break;
969 #if SIZEOF_VOID_P == 4
970 case MONO_TYPE_I8:
971 case MONO_TYPE_U8:
972 #ifdef TARGET_ARM
973 /* pairs begin at even registers */
974 if (i8_align == 8 && margs->ilen & 1)
975 margs->ilen++;
976 #endif
977 margs->ilen += 2;
978 break;
979 #endif
980 case MONO_TYPE_R4:
981 #if SIZEOF_VOID_P == 8
982 case MONO_TYPE_R8:
983 #endif
984 margs->flen++;
985 break;
986 #if SIZEOF_VOID_P == 4
987 case MONO_TYPE_R8:
988 margs->flen += 2;
989 break;
990 #endif
991 default:
992 g_error ("build_args_from_sig: not implemented yet (1): 0x%x\n", ptype);
996 if (margs->ilen > 0)
997 margs->iargs = g_malloc0 (sizeof (gpointer) * margs->ilen);
999 if (margs->flen > 0)
1000 margs->fargs = g_malloc0 (sizeof (double) * margs->flen);
1002 if (margs->ilen > INTERP_ICALL_TRAMP_IARGS)
1003 g_error ("build_args_from_sig: TODO, allocate gregs: %d\n", margs->ilen);
1005 if (margs->flen > INTERP_ICALL_TRAMP_FARGS)
1006 g_error ("build_args_from_sig: TODO, allocate fregs: %d\n", margs->flen);
1009 size_t int_i = 0;
1010 size_t int_f = 0;
1012 if (sig->hasthis) {
1013 margs->iargs [0] = frame->stack_args->data.p;
1014 int_i++;
1017 for (int i = 0; i < sig->param_count; i++) {
1018 guint32 ptype = sig->params [i]->byref ? MONO_TYPE_PTR : sig->params [i]->type;
1019 switch (ptype) {
1020 case MONO_TYPE_BOOLEAN:
1021 case MONO_TYPE_CHAR:
1022 case MONO_TYPE_I1:
1023 case MONO_TYPE_U1:
1024 case MONO_TYPE_I2:
1025 case MONO_TYPE_U2:
1026 case MONO_TYPE_I4:
1027 case MONO_TYPE_U4:
1028 case MONO_TYPE_I:
1029 case MONO_TYPE_U:
1030 case MONO_TYPE_PTR:
1031 case MONO_TYPE_SZARRAY:
1032 case MONO_TYPE_CLASS:
1033 case MONO_TYPE_OBJECT:
1034 case MONO_TYPE_STRING:
1035 case MONO_TYPE_VALUETYPE:
1036 case MONO_TYPE_GENERICINST:
1037 #if SIZEOF_VOID_P == 8
1038 case MONO_TYPE_I8:
1039 case MONO_TYPE_U8:
1040 #endif
1041 margs->iargs [int_i] = frame->stack_args [i].data.p;
1042 #if DEBUG_INTERP
1043 g_print ("build_args_from_sig: margs->iargs [%d]: %p (frame @ %d)\n", int_i, margs->iargs [int_i], i);
1044 #endif
1045 int_i++;
1046 break;
1047 #if SIZEOF_VOID_P == 4
1048 case MONO_TYPE_I8:
1049 case MONO_TYPE_U8: {
1050 stackval *sarg = &frame->stack_args [i];
1051 #ifdef TARGET_ARM
1052 /* pairs begin at even registers */
1053 if (i8_align == 8 && int_i & 1)
1054 int_i++;
1055 #endif
1056 margs->iargs [int_i] = (gpointer) sarg->data.pair.lo;
1057 int_i++;
1058 margs->iargs [int_i] = (gpointer) sarg->data.pair.hi;
1059 #if DEBUG_INTERP
1060 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);
1061 #endif
1062 int_i++;
1063 break;
1065 #endif
1066 case MONO_TYPE_R4:
1067 case MONO_TYPE_R8:
1068 if (ptype == MONO_TYPE_R4)
1069 * (float *) &(margs->fargs [int_f]) = (float) frame->stack_args [i].data.f;
1070 else
1071 margs->fargs [int_f] = frame->stack_args [i].data.f;
1072 #if DEBUG_INTERP
1073 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);
1074 #endif
1075 #if SIZEOF_VOID_P == 4
1076 int_f += 2;
1077 #else
1078 int_f++;
1079 #endif
1080 break;
1081 default:
1082 g_error ("build_args_from_sig: not implemented yet (2): 0x%x\n", ptype);
1086 switch (sig->ret->type) {
1087 case MONO_TYPE_BOOLEAN:
1088 case MONO_TYPE_CHAR:
1089 case MONO_TYPE_I1:
1090 case MONO_TYPE_U1:
1091 case MONO_TYPE_I2:
1092 case MONO_TYPE_U2:
1093 case MONO_TYPE_I4:
1094 case MONO_TYPE_U4:
1095 case MONO_TYPE_I:
1096 case MONO_TYPE_U:
1097 case MONO_TYPE_PTR:
1098 case MONO_TYPE_SZARRAY:
1099 case MONO_TYPE_CLASS:
1100 case MONO_TYPE_OBJECT:
1101 case MONO_TYPE_STRING:
1102 case MONO_TYPE_I8:
1103 case MONO_TYPE_U8:
1104 case MONO_TYPE_VALUETYPE:
1105 case MONO_TYPE_GENERICINST:
1106 margs->retval = &(frame->retval->data.p);
1107 margs->is_float_ret = 0;
1108 break;
1109 case MONO_TYPE_R4:
1110 case MONO_TYPE_R8:
1111 margs->retval = &(frame->retval->data.p);
1112 margs->is_float_ret = 1;
1113 break;
1114 case MONO_TYPE_VOID:
1115 margs->retval = NULL;
1116 break;
1117 default:
1118 g_error ("build_args_from_sig: ret type not implemented yet: 0x%x\n", sig->ret->type);
1121 return margs;
1123 #endif
1125 static void
1126 interp_frame_arg_to_data (MonoInterpFrameHandle frame, MonoMethodSignature *sig, int index, gpointer data)
1128 InterpFrame *iframe = (InterpFrame*)frame;
1130 if (index == -1)
1131 stackval_to_data (sig->ret, iframe->retval, data, TRUE);
1132 else
1133 stackval_to_data (sig->params [index], &iframe->stack_args [index], data, TRUE);
1136 static void
1137 interp_data_to_frame_arg (MonoInterpFrameHandle frame, MonoMethodSignature *sig, int index, gpointer data)
1139 InterpFrame *iframe = (InterpFrame*)frame;
1141 if (index == -1)
1142 stackval_from_data (sig->ret, iframe->retval, data, TRUE);
1143 else
1144 stackval_from_data (sig->params [index], &iframe->stack_args [index], data, TRUE);
1147 static gpointer
1148 interp_frame_arg_to_storage (MonoInterpFrameHandle frame, MonoMethodSignature *sig, int index)
1150 InterpFrame *iframe = (InterpFrame*)frame;
1152 if (index == -1)
1153 return stackval_to_data_addr (sig->ret, iframe->retval);
1154 else
1155 return stackval_to_data_addr (sig->params [index], &iframe->stack_args [index]);
1158 static MONO_NEVER_INLINE void
1159 ves_pinvoke_method (InterpFrame *frame, MonoMethodSignature *sig, MonoFuncV addr, gboolean string_ctor, ThreadContext *context)
1161 MonoLMFExt ext;
1163 frame->ex = NULL;
1165 g_assert (!frame->imethod);
1166 if (!mono_interp_to_native_trampoline) {
1167 if (mono_aot_only) {
1168 mono_interp_to_native_trampoline = mono_aot_get_trampoline ("interp_to_native_trampoline");
1169 } else {
1170 MonoTrampInfo *info;
1171 mono_interp_to_native_trampoline = mono_arch_get_interp_to_native_trampoline (&info);
1172 // TODO:
1173 // mono_tramp_info_register (info, NULL);
1176 #ifdef MONO_ARCH_HAVE_INTERP_PINVOKE_TRAMP
1177 CallContext ccontext;
1178 mono_arch_set_native_call_context (&ccontext, frame, sig);
1179 #else
1180 InterpMethodArguments *margs = build_args_from_sig (sig, frame);
1181 #endif
1183 #if DEBUG_INTERP
1184 g_print ("ICALL: mono_interp_to_native_trampoline = %p, addr = %p\n", mono_interp_to_native_trampoline, addr);
1185 #endif
1187 context->current_frame = frame;
1189 interp_push_lmf (&ext, frame);
1190 #ifdef MONO_ARCH_HAVE_INTERP_PINVOKE_TRAMP
1191 mono_interp_to_native_trampoline (addr, &ccontext);
1192 #else
1193 mono_interp_to_native_trampoline (addr, margs);
1194 #endif
1195 interp_pop_lmf (&ext);
1197 if (*mono_thread_interruption_request_flag ()) {
1198 MonoException *exc = mono_thread_interruption_checkpoint ();
1199 if (exc)
1200 interp_throw (context, exc, frame, NULL, FALSE);
1203 #ifdef MONO_ARCH_HAVE_INTERP_PINVOKE_TRAMP
1204 if (!frame->ex)
1205 mono_arch_get_native_call_context (&ccontext, frame, sig);
1206 #else
1207 if (!frame->ex && !MONO_TYPE_ISSTRUCT (sig->ret))
1208 stackval_from_data (sig->ret, frame->retval, (char*)&frame->retval->data.p, sig->pinvoke);
1210 g_free (margs->iargs);
1211 g_free (margs->fargs);
1212 g_free (margs);
1213 #endif
1216 static void
1217 interp_init_delegate (MonoDelegate *del)
1219 if (del->method)
1220 return;
1221 /* shouldn't need a write barrier because we don't write a MonoObject into the field */
1222 del->method = ((InterpMethod *) del->method_ptr)->method;
1226 * From the spec:
1227 * runtime specifies that the implementation of the method is automatically
1228 * provided by the runtime and is primarily used for the methods of delegates.
1230 static MONO_NEVER_INLINE void
1231 ves_imethod (InterpFrame *frame, ThreadContext *context)
1233 MonoMethod *method = frame->imethod->method;
1234 const char *name = method->name;
1235 MonoObject *obj = (MonoObject*) frame->stack_args->data.p;
1236 ERROR_DECL (error);
1238 mono_class_init (method->klass);
1240 if (method->klass == mono_defaults.array_class) {
1241 if (!strcmp (method->name, "UnsafeMov")) {
1242 /* TODO: layout checks */
1243 MonoType *mt = mono_method_signature (method)->ret;
1244 stackval_from_data (mt, frame->retval, (char *) frame->stack_args, FALSE);
1245 return;
1247 if (!strcmp (method->name, "UnsafeLoad")) {
1248 ves_array_get (frame, FALSE);
1249 return;
1251 } else if (mini_class_is_system_array (method->klass)) {
1252 if (!obj) {
1253 frame->ex = mono_get_exception_null_reference ();
1254 FILL_IN_TRACE (frame->ex, frame);
1255 return;
1257 if (*name == 'S' && (strcmp (name, "Set") == 0)) {
1258 ves_array_set (frame);
1259 return;
1261 if (*name == 'G' && (strcmp (name, "Get") == 0)) {
1262 ves_array_get (frame, TRUE);
1263 return;
1267 g_error ("Don't know how to exec runtime method %s.%s::%s",
1268 method->klass->name_space, method->klass->name,
1269 method->name);
1272 #if DEBUG_INTERP
1273 static char*
1274 dump_stack (stackval *stack, stackval *sp)
1276 stackval *s = stack;
1277 GString *str = g_string_new ("");
1279 if (sp == stack)
1280 return g_string_free (str, FALSE);
1282 while (s < sp) {
1283 g_string_append_printf (str, "[%p (%lld)] ", s->data.l, s->data.l);
1284 ++s;
1286 return g_string_free (str, FALSE);
1288 #endif
1290 static void
1291 dump_stackval (GString *str, stackval *s, MonoType *type)
1293 switch (type->type) {
1294 case MONO_TYPE_I1:
1295 case MONO_TYPE_U1:
1296 case MONO_TYPE_I2:
1297 case MONO_TYPE_U2:
1298 case MONO_TYPE_I4:
1299 case MONO_TYPE_U4:
1300 case MONO_TYPE_CHAR:
1301 case MONO_TYPE_BOOLEAN:
1302 g_string_append_printf (str, "[%d] ", s->data.i);
1303 break;
1304 case MONO_TYPE_STRING:
1305 case MONO_TYPE_SZARRAY:
1306 case MONO_TYPE_CLASS:
1307 case MONO_TYPE_OBJECT:
1308 case MONO_TYPE_ARRAY:
1309 case MONO_TYPE_PTR:
1310 case MONO_TYPE_I:
1311 case MONO_TYPE_U:
1312 g_string_append_printf (str, "[%p] ", s->data.p);
1313 break;
1314 case MONO_TYPE_VALUETYPE:
1315 if (type->data.klass->enumtype)
1316 g_string_append_printf (str, "[%d] ", s->data.i);
1317 else
1318 g_string_append_printf (str, "[vt:%p] ", s->data.p);
1319 break;
1320 case MONO_TYPE_R4:
1321 case MONO_TYPE_R8:
1322 g_string_append_printf (str, "[%g] ", s->data.f);
1323 break;
1324 case MONO_TYPE_I8:
1325 case MONO_TYPE_U8:
1326 default: {
1327 GString *res = g_string_new ("");
1328 mono_type_get_desc (res, type, TRUE);
1329 g_string_append_printf (str, "[{%s} %lld/0x%0llx] ", res->str, s->data.l, s->data.l);
1330 g_string_free (res, TRUE);
1331 break;
1336 #if DEBUG_INTERP
1337 static char*
1338 dump_retval (InterpFrame *inv)
1340 GString *str = g_string_new ("");
1341 MonoType *ret = mono_method_signature (inv->imethod->method)->ret;
1343 if (ret->type != MONO_TYPE_VOID)
1344 dump_stackval (str, inv->retval, ret);
1346 return g_string_free (str, FALSE);
1348 #endif
1350 static char*
1351 dump_args (InterpFrame *inv)
1353 GString *str = g_string_new ("");
1354 int i;
1355 MonoMethodSignature *signature = mono_method_signature (inv->imethod->method);
1357 if (signature->param_count == 0 && !signature->hasthis)
1358 return g_string_free (str, FALSE);
1360 if (signature->hasthis) {
1361 MonoMethod *method = inv->imethod->method;
1362 dump_stackval (str, inv->stack_args, &method->klass->byval_arg);
1365 for (i = 0; i < signature->param_count; ++i)
1366 dump_stackval (str, inv->stack_args + (!!signature->hasthis) + i, signature->params [i]);
1368 return g_string_free (str, FALSE);
1371 static char*
1372 dump_frame (InterpFrame *inv)
1374 GString *str = g_string_new ("");
1375 int i;
1376 char *args;
1377 ERROR_DECL (error);
1379 for (i = 0; inv; inv = inv->parent) {
1380 if (inv->imethod != NULL) {
1381 MonoMethod *method = inv->imethod->method;
1382 MonoClass *k;
1384 int codep = 0;
1385 const char * opname = "";
1386 char *name;
1387 gchar *source = NULL;
1389 k = method->klass;
1391 if ((method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) == 0 &&
1392 (method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) == 0) {
1393 MonoMethodHeader *hd = mono_method_get_header_checked (method, error);
1394 mono_error_cleanup (error); /* FIXME: don't swallow the error */
1396 if (hd != NULL) {
1397 if (inv->ip) {
1398 opname = mono_interp_opname [*inv->ip];
1399 codep = inv->ip - inv->imethod->code;
1400 source = g_strdup_printf ("%s:%d // (TODO: proper stacktrace)", method->name, codep);
1401 } else
1402 opname = "";
1404 #if 0
1405 MonoDebugSourceLocation *minfo = mono_debug_lookup_method (method);
1406 source = mono_debug_method_lookup_location (minfo, codep);
1407 #endif
1408 mono_metadata_free_mh (hd);
1411 args = dump_args (inv);
1412 name = mono_method_full_name (method, TRUE);
1413 if (source)
1414 g_string_append_printf (str, "#%d: 0x%05x %-10s in %s (%s) at %s\n", i, codep, opname, name, args, source);
1415 else
1416 g_string_append_printf (str, "#%d: 0x%05x %-10s in %s (%s)\n", i, codep, opname, name, args);
1417 g_free (name);
1418 g_free (args);
1419 g_free (source);
1420 ++i;
1423 return g_string_free (str, FALSE);
1426 static MonoArray *
1427 get_trace_ips (MonoDomain *domain, InterpFrame *top)
1429 int i;
1430 MonoArray *res;
1431 InterpFrame *inv;
1432 ERROR_DECL (error);
1434 for (i = 0, inv = top; inv; inv = inv->parent)
1435 if (inv->imethod != NULL)
1436 ++i;
1438 res = mono_array_new_checked (domain, mono_defaults.int_class, 3 * i, error);
1439 mono_error_cleanup (error); /* FIXME: don't swallow the error */
1441 for (i = 0, inv = top; inv; inv = inv->parent)
1442 if (inv->imethod != NULL) {
1443 mono_array_set (res, gpointer, i, inv->imethod);
1444 ++i;
1445 mono_array_set (res, gpointer, i, (gpointer)inv->ip);
1446 ++i;
1447 mono_array_set (res, gpointer, i, NULL);
1448 ++i;
1451 return res;
1455 #define MYGUINT64_MAX 18446744073709551615ULL
1456 #define MYGINT64_MAX 9223372036854775807LL
1457 #define MYGINT64_MIN (-MYGINT64_MAX -1LL)
1459 #define MYGUINT32_MAX 4294967295U
1460 #define MYGINT32_MAX 2147483647
1461 #define MYGINT32_MIN (-MYGINT32_MAX -1)
1463 #define CHECK_ADD_OVERFLOW(a,b) \
1464 (gint32)(b) >= 0 ? (gint32)(MYGINT32_MAX) - (gint32)(b) < (gint32)(a) ? -1 : 0 \
1465 : (gint32)(MYGINT32_MIN) - (gint32)(b) > (gint32)(a) ? +1 : 0
1467 #define CHECK_SUB_OVERFLOW(a,b) \
1468 (gint32)(b) < 0 ? (gint32)(MYGINT32_MAX) + (gint32)(b) < (gint32)(a) ? -1 : 0 \
1469 : (gint32)(MYGINT32_MIN) + (gint32)(b) > (gint32)(a) ? +1 : 0
1471 #define CHECK_ADD_OVERFLOW_UN(a,b) \
1472 (guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a) ? -1 : 0
1474 #define CHECK_SUB_OVERFLOW_UN(a,b) \
1475 (guint32)(a) < (guint32)(b) ? -1 : 0
1477 #define CHECK_ADD_OVERFLOW64(a,b) \
1478 (gint64)(b) >= 0 ? (gint64)(MYGINT64_MAX) - (gint64)(b) < (gint64)(a) ? -1 : 0 \
1479 : (gint64)(MYGINT64_MIN) - (gint64)(b) > (gint64)(a) ? +1 : 0
1481 #define CHECK_SUB_OVERFLOW64(a,b) \
1482 (gint64)(b) < 0 ? (gint64)(MYGINT64_MAX) + (gint64)(b) < (gint64)(a) ? -1 : 0 \
1483 : (gint64)(MYGINT64_MIN) + (gint64)(b) > (gint64)(a) ? +1 : 0
1485 #define CHECK_ADD_OVERFLOW64_UN(a,b) \
1486 (guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a) ? -1 : 0
1488 #define CHECK_SUB_OVERFLOW64_UN(a,b) \
1489 (guint64)(a) < (guint64)(b) ? -1 : 0
1491 #if SIZEOF_VOID_P == 4
1492 #define CHECK_ADD_OVERFLOW_NAT(a,b) CHECK_ADD_OVERFLOW(a,b)
1493 #define CHECK_ADD_OVERFLOW_NAT_UN(a,b) CHECK_ADD_OVERFLOW_UN(a,b)
1494 #else
1495 #define CHECK_ADD_OVERFLOW_NAT(a,b) CHECK_ADD_OVERFLOW64(a,b)
1496 #define CHECK_ADD_OVERFLOW_NAT_UN(a,b) CHECK_ADD_OVERFLOW64_UN(a,b)
1497 #endif
1499 /* Resolves to TRUE if the operands would overflow */
1500 #define CHECK_MUL_OVERFLOW(a,b) \
1501 ((gint32)(a) == 0) || ((gint32)(b) == 0) ? 0 : \
1502 (((gint32)(a) > 0) && ((gint32)(b) == -1)) ? FALSE : \
1503 (((gint32)(a) < 0) && ((gint32)(b) == -1)) ? (a == - MYGINT32_MAX) : \
1504 (((gint32)(a) > 0) && ((gint32)(b) > 0)) ? (gint32)(a) > ((MYGINT32_MAX) / (gint32)(b)) : \
1505 (((gint32)(a) > 0) && ((gint32)(b) < 0)) ? (gint32)(a) > ((MYGINT32_MIN) / (gint32)(b)) : \
1506 (((gint32)(a) < 0) && ((gint32)(b) > 0)) ? (gint32)(a) < ((MYGINT32_MIN) / (gint32)(b)) : \
1507 (gint32)(a) < ((MYGINT32_MAX) / (gint32)(b))
1509 #define CHECK_MUL_OVERFLOW_UN(a,b) \
1510 ((guint32)(a) == 0) || ((guint32)(b) == 0) ? 0 : \
1511 (guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a))
1513 #define CHECK_MUL_OVERFLOW64(a,b) \
1514 ((gint64)(a) == 0) || ((gint64)(b) == 0) ? 0 : \
1515 (((gint64)(a) > 0) && ((gint64)(b) == -1)) ? FALSE : \
1516 (((gint64)(a) < 0) && ((gint64)(b) == -1)) ? (a == - MYGINT64_MAX) : \
1517 (((gint64)(a) > 0) && ((gint64)(b) > 0)) ? (gint64)(a) > ((MYGINT64_MAX) / (gint64)(b)) : \
1518 (((gint64)(a) > 0) && ((gint64)(b) < 0)) ? (gint64)(a) > ((MYGINT64_MIN) / (gint64)(b)) : \
1519 (((gint64)(a) < 0) && ((gint64)(b) > 0)) ? (gint64)(a) < ((MYGINT64_MIN) / (gint64)(b)) : \
1520 (gint64)(a) < ((MYGINT64_MAX) / (gint64)(b))
1522 #define CHECK_MUL_OVERFLOW64_UN(a,b) \
1523 ((guint64)(a) == 0) || ((guint64)(b) == 0) ? 0 : \
1524 (guint64)(b) > ((MYGUINT64_MAX) / (guint64)(a))
1526 #if SIZEOF_VOID_P == 4
1527 #define CHECK_MUL_OVERFLOW_NAT(a,b) CHECK_MUL_OVERFLOW(a,b)
1528 #define CHECK_MUL_OVERFLOW_NAT_UN(a,b) CHECK_MUL_OVERFLOW_UN(a,b)
1529 #else
1530 #define CHECK_MUL_OVERFLOW_NAT(a,b) CHECK_MUL_OVERFLOW64(a,b)
1531 #define CHECK_MUL_OVERFLOW_NAT_UN(a,b) CHECK_MUL_OVERFLOW64_UN(a,b)
1532 #endif
1534 static MonoObject*
1535 interp_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError *error)
1537 InterpFrame frame, *old_frame;
1538 ThreadContext * volatile context = mono_native_tls_get_value (thread_context_id);
1539 MonoMethodSignature *sig = mono_method_signature (method);
1540 MonoClass *klass = mono_class_from_mono_type (sig->ret);
1541 stackval result;
1542 stackval *args;
1543 ThreadContext context_struct;
1545 error_init (error);
1546 if (exc)
1547 *exc = NULL;
1549 frame.ex = NULL;
1551 if (context == NULL) {
1552 context = &context_struct;
1553 memset (context, 0, sizeof (ThreadContext));
1554 set_context (context);
1555 } else {
1556 old_frame = context->current_frame;
1559 MonoDomain *domain = mono_domain_get ();
1561 MonoMethod *invoke_wrapper = mono_marshal_get_runtime_invoke_full (method, FALSE, TRUE);
1563 //* <code>MonoObject *runtime_invoke (MonoObject *this_obj, void **params, MonoObject **exc, void* method)</code>
1565 result.data.vt = alloca (mono_class_instance_size (klass));
1566 args = alloca (sizeof (stackval) * 4);
1568 if (sig->hasthis)
1569 args [0].data.p = obj;
1570 else
1571 args [0].data.p = NULL;
1572 args [1].data.p = params;
1573 args [2].data.p = exc;
1574 args [3].data.p = method;
1576 INIT_FRAME (&frame, context->current_frame, args, &result, domain, invoke_wrapper, error);
1578 if (exc)
1579 frame.invoke_trap = 1;
1581 interp_exec_method (&frame, context);
1583 if (context == &context_struct)
1584 set_context (NULL);
1585 else
1586 context->current_frame = old_frame;
1588 if (frame.ex) {
1589 if (exc) {
1590 *exc = (MonoObject*) frame.ex;
1591 return NULL;
1593 mono_error_set_exception_instance (error, frame.ex);
1594 return NULL;
1596 return result.data.p;
1599 typedef struct {
1600 InterpMethod *rmethod;
1601 gpointer this_arg;
1602 gpointer res;
1603 gpointer args [16];
1604 gpointer *many_args;
1605 } InterpEntryData;
1607 /* Main function for entering the interpreter from compiled code */
1608 static void
1609 interp_entry (InterpEntryData *data)
1611 InterpFrame frame;
1612 InterpMethod *rmethod = data->rmethod;
1613 ThreadContext *context = mono_native_tls_get_value (thread_context_id);
1614 ThreadContext context_struct;
1615 InterpFrame *old_frame;
1616 stackval result;
1617 stackval *args;
1618 MonoMethod *method;
1619 MonoMethodSignature *sig;
1620 MonoType *type;
1621 int i;
1623 method = rmethod->method;
1624 sig = mono_method_signature (method);
1626 // FIXME: Optimize this
1628 //printf ("%s\n", mono_method_full_name (method, 1));
1630 frame.ex = NULL;
1631 if (context == NULL) {
1632 context = &context_struct;
1633 memset (context, 0, sizeof (ThreadContext));
1634 set_context (context);
1635 } else {
1636 old_frame = context->current_frame;
1639 args = alloca (sizeof (stackval) * (sig->param_count + (sig->hasthis ? 1 : 0)));
1640 if (sig->hasthis)
1641 args [0].data.p = data->this_arg;
1643 gpointer *params;
1644 if (data->many_args)
1645 params = data->many_args;
1646 else
1647 params = data->args;
1648 for (i = 0; i < sig->param_count; ++i) {
1649 int a_index = i + (sig->hasthis ? 1 : 0);
1650 if (sig->params [i]->byref) {
1651 args [a_index].data.p = params [i];
1652 continue;
1654 type = rmethod->param_types [i];
1655 switch (type->type) {
1656 case MONO_TYPE_VALUETYPE:
1657 args [a_index].data.p = params [i];
1658 break;
1659 case MONO_TYPE_GENERICINST:
1660 if (MONO_TYPE_IS_REFERENCE (type))
1661 args [a_index].data.p = params [i];
1662 else
1663 args [a_index].data.vt = params [i];
1664 break;
1665 default:
1666 stackval_from_data (type, &args [a_index], params [i], FALSE);
1667 break;
1671 init_frame (&frame, NULL, data->rmethod, args, &result);
1673 type = rmethod->rtype;
1674 switch (type->type) {
1675 case MONO_TYPE_GENERICINST:
1676 if (!MONO_TYPE_IS_REFERENCE (type))
1677 frame.retval->data.vt = data->res;
1678 break;
1679 case MONO_TYPE_VALUETYPE:
1680 frame.retval->data.vt = data->res;
1681 break;
1682 default:
1683 break;
1686 interp_exec_method (&frame, context);
1687 if (context == &context_struct)
1688 set_context (NULL);
1689 else
1690 context->current_frame = old_frame;
1692 // FIXME:
1693 g_assert (frame.ex == NULL);
1695 type = rmethod->rtype;
1696 switch (type->type) {
1697 case MONO_TYPE_VOID:
1698 break;
1699 case MONO_TYPE_OBJECT:
1700 /* No need for a write barrier */
1701 *(MonoObject**)data->res = (MonoObject*)frame.retval->data.p;
1702 break;
1703 case MONO_TYPE_GENERICINST:
1704 if (MONO_TYPE_IS_REFERENCE (type)) {
1705 *(MonoObject**)data->res = *(MonoObject**)frame.retval->data.p;
1706 } else {
1707 /* Already set before the call */
1709 break;
1710 case MONO_TYPE_VALUETYPE:
1711 /* Already set before the call */
1712 break;
1713 default:
1714 stackval_to_data (type, frame.retval, data->res, FALSE);
1715 break;
1719 static MONO_NEVER_INLINE stackval *
1720 do_icall (ThreadContext *context, int op, stackval *sp, gpointer ptr)
1722 MonoLMFExt ext;
1723 interp_push_lmf (&ext, context->current_frame);
1725 switch (op) {
1726 case MINT_ICALL_V_V: {
1727 void (*func)(void) = ptr;
1728 func ();
1729 break;
1731 case MINT_ICALL_V_P: {
1732 gpointer (*func)(void) = ptr;
1733 sp++;
1734 sp [-1].data.p = func ();
1735 break;
1737 case MINT_ICALL_P_V: {
1738 void (*func)(gpointer) = ptr;
1739 func (sp [-1].data.p);
1740 sp --;
1741 break;
1743 case MINT_ICALL_P_P: {
1744 gpointer (*func)(gpointer) = ptr;
1745 sp [-1].data.p = func (sp [-1].data.p);
1746 break;
1748 case MINT_ICALL_PP_V: {
1749 void (*func)(gpointer,gpointer) = ptr;
1750 sp -= 2;
1751 func (sp [0].data.p, sp [1].data.p);
1752 break;
1754 case MINT_ICALL_PI_V: {
1755 void (*func)(gpointer,int) = ptr;
1756 sp -= 2;
1757 func (sp [0].data.p, sp [1].data.i);
1758 break;
1760 case MINT_ICALL_PP_P: {
1761 gpointer (*func)(gpointer,gpointer) = ptr;
1762 --sp;
1763 sp [-1].data.p = func (sp [-1].data.p, sp [0].data.p);
1764 break;
1766 case MINT_ICALL_PI_P: {
1767 gpointer (*func)(gpointer,int) = ptr;
1768 --sp;
1769 sp [-1].data.p = func (sp [-1].data.p, sp [0].data.i);
1770 break;
1772 case MINT_ICALL_PPP_V: {
1773 void (*func)(gpointer,gpointer,gpointer) = ptr;
1774 sp -= 3;
1775 func (sp [0].data.p, sp [1].data.p, sp [2].data.p);
1776 break;
1778 case MINT_ICALL_PPI_V: {
1779 void (*func)(gpointer,gpointer,int) = ptr;
1780 sp -= 3;
1781 func (sp [0].data.p, sp [1].data.p, sp [2].data.i);
1782 break;
1784 case MINT_ICALL_PII_P: {
1785 gpointer (*func)(gpointer,int,int) = ptr;
1786 sp -= 2;
1787 sp [-1].data.p = func (sp [-1].data.p, sp [0].data.i, sp [1].data.i);
1788 break;
1790 case MINT_ICALL_PPII_V: {
1791 gpointer (*func)(gpointer,gpointer,int,int) = ptr;
1792 sp -= 4;
1793 func (sp [0].data.p, sp [1].data.p, sp [2].data.i, sp [3].data.i);
1794 break;
1796 default:
1797 g_assert_not_reached ();
1800 interp_pop_lmf (&ext);
1801 return sp;
1804 static MONO_NEVER_INLINE stackval *
1805 do_jit_call (stackval *sp, unsigned char *vt_sp, ThreadContext *context, InterpFrame *frame, InterpMethod *rmethod)
1807 MonoMethodSignature *sig;
1808 MonoFtnDesc ftndesc;
1809 guint8 res_buf [256];
1810 MonoType *type;
1811 MonoLMFExt ext;
1813 //printf ("%s\n", mono_method_full_name (rmethod->method, 1));
1816 * Call JITted code through a gsharedvt_out wrapper. These wrappers receive every argument
1817 * by ref and return a return value using an explicit return value argument.
1819 if (!rmethod->jit_wrapper) {
1820 MonoMethod *method = rmethod->method;
1821 ERROR_DECL (error);
1823 sig = mono_method_signature (method);
1824 g_assert (sig);
1826 MonoMethod *wrapper = mini_get_gsharedvt_out_sig_wrapper (sig);
1827 //printf ("J: %s %s\n", mono_method_full_name (method, 1), mono_method_full_name (wrapper, 1));
1829 gpointer jit_wrapper = mono_jit_compile_method_jit_only (wrapper, error);
1830 mono_error_assert_ok (error);
1832 gpointer addr = mono_jit_compile_method_jit_only (method, error);
1833 g_assert (addr);
1834 mono_error_assert_ok (error);
1836 rmethod->jit_addr = addr;
1837 rmethod->jit_sig = sig;
1838 mono_memory_barrier ();
1839 rmethod->jit_wrapper = jit_wrapper;
1841 } else {
1842 sig = rmethod->jit_sig;
1845 sp -= sig->param_count;
1846 if (sig->hasthis)
1847 --sp;
1849 ftndesc.addr = rmethod->jit_addr;
1850 ftndesc.arg = NULL;
1852 // FIXME: Optimize this
1854 gpointer args [32];
1855 int pindex = 0;
1856 int stack_index = 0;
1857 if (rmethod->hasthis) {
1858 args [pindex ++] = sp [0].data.p;
1859 stack_index ++;
1861 type = rmethod->rtype;
1862 if (type->type != MONO_TYPE_VOID) {
1863 if (MONO_TYPE_ISSTRUCT (type))
1864 args [pindex ++] = vt_sp;
1865 else
1866 args [pindex ++] = res_buf;
1868 for (int i = 0; i < rmethod->param_count; ++i) {
1869 MonoType *t = rmethod->param_types [i];
1870 stackval *sval = &sp [stack_index + i];
1871 if (sig->params [i]->byref) {
1872 args [pindex ++] = sval->data.p;
1873 } else if (MONO_TYPE_ISSTRUCT (t)) {
1874 args [pindex ++] = sval->data.p;
1875 } else if (MONO_TYPE_IS_REFERENCE (t)) {
1876 args [pindex ++] = &sval->data.p;
1877 } else {
1878 switch (t->type) {
1879 case MONO_TYPE_I1:
1880 case MONO_TYPE_U1:
1881 case MONO_TYPE_I2:
1882 case MONO_TYPE_U2:
1883 case MONO_TYPE_I4:
1884 case MONO_TYPE_U4:
1885 case MONO_TYPE_VALUETYPE:
1886 args [pindex ++] = &sval->data.i;
1887 break;
1888 case MONO_TYPE_PTR:
1889 case MONO_TYPE_FNPTR:
1890 case MONO_TYPE_I:
1891 case MONO_TYPE_U:
1892 case MONO_TYPE_OBJECT:
1893 args [pindex ++] = &sval->data.p;
1894 break;
1895 case MONO_TYPE_I8:
1896 case MONO_TYPE_U8:
1897 args [pindex ++] = &sval->data.l;
1898 break;
1899 default:
1900 printf ("%s\n", mono_type_full_name (t));
1901 g_assert_not_reached ();
1906 interp_push_lmf (&ext, frame);
1908 switch (pindex) {
1909 case 0: {
1910 void (*func)(gpointer) = rmethod->jit_wrapper;
1912 func (&ftndesc);
1913 break;
1915 case 1: {
1916 void (*func)(gpointer, gpointer) = rmethod->jit_wrapper;
1918 func (args [0], &ftndesc);
1919 break;
1921 case 2: {
1922 void (*func)(gpointer, gpointer, gpointer) = rmethod->jit_wrapper;
1924 func (args [0], args [1], &ftndesc);
1925 break;
1927 case 3: {
1928 void (*func)(gpointer, gpointer, gpointer, gpointer) = rmethod->jit_wrapper;
1930 func (args [0], args [1], args [2], &ftndesc);
1931 break;
1933 case 4: {
1934 void (*func)(gpointer, gpointer, gpointer, gpointer, gpointer) = rmethod->jit_wrapper;
1936 func (args [0], args [1], args [2], args [3], &ftndesc);
1937 break;
1939 case 5: {
1940 void (*func)(gpointer, gpointer, gpointer, gpointer, gpointer, gpointer) = rmethod->jit_wrapper;
1942 func (args [0], args [1], args [2], args [3], args [4], &ftndesc);
1943 break;
1945 case 6: {
1946 void (*func)(gpointer, gpointer, gpointer, gpointer, gpointer, gpointer, gpointer) = rmethod->jit_wrapper;
1948 func (args [0], args [1], args [2], args [3], args [4], args [5], &ftndesc);
1949 break;
1951 case 7: {
1952 void (*func)(gpointer, gpointer, gpointer, gpointer, gpointer, gpointer, gpointer, gpointer) = rmethod->jit_wrapper;
1954 func (args [0], args [1], args [2], args [3], args [4], args [5], args [6], &ftndesc);
1955 break;
1957 default:
1958 g_assert_not_reached ();
1959 break;
1962 interp_pop_lmf (&ext);
1964 MonoType *rtype = rmethod->rtype;
1965 switch (rtype->type) {
1966 case MONO_TYPE_VOID:
1967 case MONO_TYPE_OBJECT:
1968 case MONO_TYPE_STRING:
1969 case MONO_TYPE_CLASS:
1970 case MONO_TYPE_ARRAY:
1971 case MONO_TYPE_SZARRAY:
1972 case MONO_TYPE_I:
1973 case MONO_TYPE_U:
1974 sp->data.p = *(gpointer*)res_buf;
1975 break;
1976 case MONO_TYPE_I1:
1977 sp->data.i = *(gint8*)res_buf;
1978 break;
1979 case MONO_TYPE_U1:
1980 sp->data.i = *(guint8*)res_buf;
1981 break;
1982 case MONO_TYPE_I2:
1983 sp->data.i = *(gint16*)res_buf;
1984 break;
1985 case MONO_TYPE_U2:
1986 sp->data.i = *(guint16*)res_buf;
1987 break;
1988 case MONO_TYPE_I4:
1989 sp->data.i = *(gint32*)res_buf;
1990 break;
1991 case MONO_TYPE_U4:
1992 sp->data.i = *(guint32*)res_buf;
1993 break;
1994 case MONO_TYPE_VALUETYPE:
1995 /* The result was written to vt_sp */
1996 sp->data.p = vt_sp;
1997 break;
1998 case MONO_TYPE_GENERICINST:
1999 if (MONO_TYPE_IS_REFERENCE (rtype)) {
2000 sp->data.p = *(gpointer*)res_buf;
2001 } else {
2002 /* The result was written to vt_sp */
2003 sp->data.p = vt_sp;
2005 break;
2006 default:
2007 g_print ("%s\n", mono_type_full_name (rtype));
2008 g_assert_not_reached ();
2009 break;
2012 return sp;
2015 static MONO_NEVER_INLINE void
2016 do_debugger_tramp (void (*tramp) (void), InterpFrame *frame)
2018 MonoLMFExt ext;
2019 interp_push_lmf (&ext, frame);
2020 tramp ();
2021 interp_pop_lmf (&ext);
2024 static MONO_NEVER_INLINE void
2025 do_transform_method (InterpFrame *frame, ThreadContext *context)
2027 MonoLMFExt ext;
2028 /* Don't push lmf if we have no interp data */
2029 gboolean push_lmf = frame->parent != NULL;
2031 /* Use the parent frame as the current frame is not complete yet */
2032 if (push_lmf)
2033 interp_push_lmf (&ext, frame->parent);
2035 frame->ex = mono_interp_transform_method (frame->imethod, context, frame);
2037 if (push_lmf)
2038 interp_pop_lmf (&ext);
2042 * These functions are the entry points into the interpreter from compiled code.
2043 * They are called by the interp_in wrappers. They have the following signature:
2044 * void (<optional this_arg>, <optional retval pointer>, <arg1>, ..., <argn>, <method ptr>)
2045 * They pack up their arguments into an InterpEntryData structure and call interp_entry ().
2046 * It would be possible for the wrappers to pack up the arguments etc, but that would make them bigger, and there are
2047 * more wrappers then these functions.
2048 * this/static * ret/void * 16 arguments -> 64 functions.
2051 #define MAX_INTERP_ENTRY_ARGS 8
2053 #define INTERP_ENTRY_BASE(_method, _this_arg, _res) \
2054 InterpEntryData data; \
2055 (data).rmethod = (_method); \
2056 (data).res = (_res); \
2057 (data).this_arg = (_this_arg); \
2058 (data).many_args = NULL;
2060 #define INTERP_ENTRY0(_this_arg, _res, _method) { \
2061 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2062 interp_entry (&data); \
2064 #define INTERP_ENTRY1(_this_arg, _res, _method) { \
2065 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2066 (data).args [0] = arg1; \
2067 interp_entry (&data); \
2069 #define INTERP_ENTRY2(_this_arg, _res, _method) { \
2070 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2071 (data).args [0] = arg1; \
2072 (data).args [1] = arg2; \
2073 interp_entry (&data); \
2075 #define INTERP_ENTRY3(_this_arg, _res, _method) { \
2076 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2077 (data).args [0] = arg1; \
2078 (data).args [1] = arg2; \
2079 (data).args [2] = arg3; \
2080 interp_entry (&data); \
2082 #define INTERP_ENTRY4(_this_arg, _res, _method) { \
2083 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2084 (data).args [0] = arg1; \
2085 (data).args [1] = arg2; \
2086 (data).args [2] = arg3; \
2087 (data).args [3] = arg4; \
2088 interp_entry (&data); \
2090 #define INTERP_ENTRY5(_this_arg, _res, _method) { \
2091 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2092 (data).args [0] = arg1; \
2093 (data).args [1] = arg2; \
2094 (data).args [2] = arg3; \
2095 (data).args [3] = arg4; \
2096 (data).args [4] = arg5; \
2097 interp_entry (&data); \
2099 #define INTERP_ENTRY6(_this_arg, _res, _method) { \
2100 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2101 (data).args [0] = arg1; \
2102 (data).args [1] = arg2; \
2103 (data).args [2] = arg3; \
2104 (data).args [3] = arg4; \
2105 (data).args [4] = arg5; \
2106 (data).args [5] = arg6; \
2107 interp_entry (&data); \
2109 #define INTERP_ENTRY7(_this_arg, _res, _method) { \
2110 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2111 (data).args [0] = arg1; \
2112 (data).args [1] = arg2; \
2113 (data).args [2] = arg3; \
2114 (data).args [3] = arg4; \
2115 (data).args [4] = arg5; \
2116 (data).args [5] = arg6; \
2117 (data).args [6] = arg7; \
2118 interp_entry (&data); \
2120 #define INTERP_ENTRY8(_this_arg, _res, _method) { \
2121 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2122 (data).args [0] = arg1; \
2123 (data).args [1] = arg2; \
2124 (data).args [2] = arg3; \
2125 (data).args [3] = arg4; \
2126 (data).args [4] = arg5; \
2127 (data).args [5] = arg6; \
2128 (data).args [6] = arg7; \
2129 (data).args [7] = arg8; \
2130 interp_entry (&data); \
2133 #define ARGLIST0 InterpMethod *rmethod
2134 #define ARGLIST1 gpointer arg1, InterpMethod *rmethod
2135 #define ARGLIST2 gpointer arg1, gpointer arg2, InterpMethod *rmethod
2136 #define ARGLIST3 gpointer arg1, gpointer arg2, gpointer arg3, InterpMethod *rmethod
2137 #define ARGLIST4 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, InterpMethod *rmethod
2138 #define ARGLIST5 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, gpointer arg5, InterpMethod *rmethod
2139 #define ARGLIST6 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, gpointer arg5, gpointer arg6, InterpMethod *rmethod
2140 #define ARGLIST7 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, gpointer arg5, gpointer arg6, gpointer arg7, InterpMethod *rmethod
2141 #define ARGLIST8 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, gpointer arg5, gpointer arg6, gpointer arg7, gpointer arg8, InterpMethod *rmethod
2143 static void interp_entry_static_0 (ARGLIST0) INTERP_ENTRY0 (NULL, NULL, rmethod)
2144 static void interp_entry_static_1 (ARGLIST1) INTERP_ENTRY1 (NULL, NULL, rmethod)
2145 static void interp_entry_static_2 (ARGLIST2) INTERP_ENTRY2 (NULL, NULL, rmethod)
2146 static void interp_entry_static_3 (ARGLIST3) INTERP_ENTRY3 (NULL, NULL, rmethod)
2147 static void interp_entry_static_4 (ARGLIST4) INTERP_ENTRY4 (NULL, NULL, rmethod)
2148 static void interp_entry_static_5 (ARGLIST5) INTERP_ENTRY5 (NULL, NULL, rmethod)
2149 static void interp_entry_static_6 (ARGLIST6) INTERP_ENTRY6 (NULL, NULL, rmethod)
2150 static void interp_entry_static_7 (ARGLIST7) INTERP_ENTRY7 (NULL, NULL, rmethod)
2151 static void interp_entry_static_8 (ARGLIST8) INTERP_ENTRY8 (NULL, NULL, rmethod)
2152 static void interp_entry_static_ret_0 (gpointer res, ARGLIST0) INTERP_ENTRY0 (NULL, res, rmethod)
2153 static void interp_entry_static_ret_1 (gpointer res, ARGLIST1) INTERP_ENTRY1 (NULL, res, rmethod)
2154 static void interp_entry_static_ret_2 (gpointer res, ARGLIST2) INTERP_ENTRY2 (NULL, res, rmethod)
2155 static void interp_entry_static_ret_3 (gpointer res, ARGLIST3) INTERP_ENTRY3 (NULL, res, rmethod)
2156 static void interp_entry_static_ret_4 (gpointer res, ARGLIST4) INTERP_ENTRY4 (NULL, res, rmethod)
2157 static void interp_entry_static_ret_5 (gpointer res, ARGLIST5) INTERP_ENTRY5 (NULL, res, rmethod)
2158 static void interp_entry_static_ret_6 (gpointer res, ARGLIST6) INTERP_ENTRY6 (NULL, res, rmethod)
2159 static void interp_entry_static_ret_7 (gpointer res, ARGLIST7) INTERP_ENTRY7 (NULL, res, rmethod)
2160 static void interp_entry_static_ret_8 (gpointer res, ARGLIST8) INTERP_ENTRY8 (NULL, res, rmethod)
2161 static void interp_entry_instance_0 (gpointer this_arg, ARGLIST0) INTERP_ENTRY0 (this_arg, NULL, rmethod)
2162 static void interp_entry_instance_1 (gpointer this_arg, ARGLIST1) INTERP_ENTRY1 (this_arg, NULL, rmethod)
2163 static void interp_entry_instance_2 (gpointer this_arg, ARGLIST2) INTERP_ENTRY2 (this_arg, NULL, rmethod)
2164 static void interp_entry_instance_3 (gpointer this_arg, ARGLIST3) INTERP_ENTRY3 (this_arg, NULL, rmethod)
2165 static void interp_entry_instance_4 (gpointer this_arg, ARGLIST4) INTERP_ENTRY4 (this_arg, NULL, rmethod)
2166 static void interp_entry_instance_5 (gpointer this_arg, ARGLIST5) INTERP_ENTRY5 (this_arg, NULL, rmethod)
2167 static void interp_entry_instance_6 (gpointer this_arg, ARGLIST6) INTERP_ENTRY6 (this_arg, NULL, rmethod)
2168 static void interp_entry_instance_7 (gpointer this_arg, ARGLIST7) INTERP_ENTRY7 (this_arg, NULL, rmethod)
2169 static void interp_entry_instance_8 (gpointer this_arg, ARGLIST8) INTERP_ENTRY8 (this_arg, NULL, rmethod)
2170 static void interp_entry_instance_ret_0 (gpointer this_arg, gpointer res, ARGLIST0) INTERP_ENTRY0 (this_arg, res, rmethod)
2171 static void interp_entry_instance_ret_1 (gpointer this_arg, gpointer res, ARGLIST1) INTERP_ENTRY1 (this_arg, res, rmethod)
2172 static void interp_entry_instance_ret_2 (gpointer this_arg, gpointer res, ARGLIST2) INTERP_ENTRY2 (this_arg, res, rmethod)
2173 static void interp_entry_instance_ret_3 (gpointer this_arg, gpointer res, ARGLIST3) INTERP_ENTRY3 (this_arg, res, rmethod)
2174 static void interp_entry_instance_ret_4 (gpointer this_arg, gpointer res, ARGLIST4) INTERP_ENTRY4 (this_arg, res, rmethod)
2175 static void interp_entry_instance_ret_5 (gpointer this_arg, gpointer res, ARGLIST5) INTERP_ENTRY5 (this_arg, res, rmethod)
2176 static void interp_entry_instance_ret_6 (gpointer this_arg, gpointer res, ARGLIST6) INTERP_ENTRY6 (this_arg, res, rmethod)
2177 static void interp_entry_instance_ret_7 (gpointer this_arg, gpointer res, ARGLIST7) INTERP_ENTRY7 (this_arg, res, rmethod)
2178 static void interp_entry_instance_ret_8 (gpointer this_arg, gpointer res, ARGLIST8) INTERP_ENTRY8 (this_arg, res, rmethod)
2180 #define INTERP_ENTRY_FUNCLIST(type) interp_entry_ ## type ## _0, interp_entry_ ## type ## _1, interp_entry_ ## type ## _2, interp_entry_ ## type ## _3, interp_entry_ ## type ## _4, interp_entry_ ## type ## _5, interp_entry_ ## type ## _6, interp_entry_ ## type ## _7, interp_entry_ ## type ## _8
2182 gpointer entry_funcs_static [MAX_INTERP_ENTRY_ARGS + 1] = { INTERP_ENTRY_FUNCLIST (static) };
2183 gpointer entry_funcs_static_ret [MAX_INTERP_ENTRY_ARGS + 1] = { INTERP_ENTRY_FUNCLIST (static_ret) };
2184 gpointer entry_funcs_instance [MAX_INTERP_ENTRY_ARGS + 1] = { INTERP_ENTRY_FUNCLIST (instance) };
2185 gpointer entry_funcs_instance_ret [MAX_INTERP_ENTRY_ARGS + 1] = { INTERP_ENTRY_FUNCLIST (instance_ret) };
2187 /* General version for methods with more than MAX_INTERP_ENTRY_ARGS arguments */
2188 static void
2189 interp_entry_general (gpointer this_arg, gpointer res, gpointer *args, gpointer rmethod)
2191 INTERP_ENTRY_BASE (rmethod, this_arg, res);
2192 data.many_args = args;
2193 interp_entry (&data);
2197 * interp_create_method_pointer:
2199 * Return a function pointer which can be used to call METHOD using the
2200 * interpreter. Return NULL for methods which are not supported.
2202 static gpointer
2203 interp_create_method_pointer (MonoMethod *method, MonoError *error)
2205 gpointer addr;
2206 MonoMethodSignature *sig = mono_method_signature (method);
2207 MonoMethod *wrapper;
2208 InterpMethod *rmethod = mono_interp_get_imethod (mono_domain_get (), method, error);
2210 /* HACK: method_ptr of delegate should point to a runtime method*/
2211 if (method->wrapper_type && (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD ||
2212 (method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE)))
2213 return rmethod;
2215 if (rmethod->jit_entry)
2216 return rmethod->jit_entry;
2217 wrapper = mini_get_interp_in_wrapper (sig);
2219 gpointer jit_wrapper = mono_jit_compile_method_jit_only (wrapper, error);
2220 mono_error_assertf_ok (error, "couldn't compile wrapper \"%s\" for \"%s\"", mono_method_get_full_name (wrapper), mono_method_get_full_name (method));
2222 gpointer entry_func;
2223 if (sig->param_count > MAX_INTERP_ENTRY_ARGS) {
2224 entry_func = interp_entry_general;
2225 } else if (sig->hasthis) {
2226 if (sig->ret->type == MONO_TYPE_VOID)
2227 entry_func = entry_funcs_instance [sig->param_count];
2228 else
2229 entry_func = entry_funcs_instance_ret [sig->param_count];
2230 } else {
2231 if (sig->ret->type == MONO_TYPE_VOID)
2232 entry_func = entry_funcs_static [sig->param_count];
2233 else
2234 entry_func = entry_funcs_static_ret [sig->param_count];
2236 g_assert (entry_func);
2238 /* This is the argument passed to the interp_in wrapper by the static rgctx trampoline */
2239 MonoFtnDesc *ftndesc = g_new0 (MonoFtnDesc, 1);
2240 ftndesc->addr = entry_func;
2241 ftndesc->arg = rmethod;
2242 mono_error_assert_ok (error);
2245 * The wrapper is called by compiled code, which doesn't pass the extra argument, so we pass it in the
2246 * rgctx register using a trampoline.
2249 if (mono_aot_only)
2250 addr = mono_aot_get_static_rgctx_trampoline (ftndesc, jit_wrapper);
2251 else
2252 addr = mono_arch_get_static_rgctx_trampoline (ftndesc, jit_wrapper);
2254 mono_memory_barrier ();
2255 rmethod->jit_entry = addr;
2257 return addr;
2260 #if COUNT_OPS
2261 static int opcode_counts[512];
2263 #define COUNT_OP(op) opcode_counts[op]++
2264 #else
2265 #define COUNT_OP(op)
2266 #endif
2268 #if DEBUG_INTERP
2269 #define DUMP_INSTR() \
2270 if (tracing > 1) { \
2271 char *ins; \
2272 if (sp > frame->stack) { \
2273 ins = dump_stack (frame->stack, sp); \
2274 } else { \
2275 ins = g_strdup (""); \
2277 sp->data.l = 0; \
2278 output_indent (); \
2279 char *mn = mono_method_full_name (frame->imethod->method, FALSE); \
2280 char *disasm = mono_interp_dis_mintop(rtm->code, ip); \
2281 g_print ("(%p) %s -> %s\t%d:%s\n", mono_thread_internal_current (), mn, disasm, vt_sp - vtalloc, ins); \
2282 g_free (mn); \
2283 g_free (ins); \
2284 g_free (disasm); \
2286 #else
2287 #define DUMP_INSTR()
2288 #endif
2290 #ifdef __GNUC__
2291 #define USE_COMPUTED_GOTO 1
2292 #endif
2293 #if USE_COMPUTED_GOTO
2294 #define MINT_IN_SWITCH(op) COUNT_OP(op); goto *in_labels[op];
2295 #define MINT_IN_CASE(x) LAB_ ## x:
2296 #if DEBUG_INTERP
2297 #define MINT_IN_BREAK if (tracing > 1) goto main_loop; else { COUNT_OP(*ip); goto *in_labels[*ip]; }
2298 #else
2299 #define MINT_IN_BREAK { COUNT_OP(*ip); goto *in_labels[*ip]; }
2300 #endif
2301 #define MINT_IN_DEFAULT mint_default: if (0) goto mint_default; /* make gcc shut up */
2302 #else
2303 #define MINT_IN_SWITCH(op) switch (op)
2304 #define MINT_IN_CASE(x) case x:
2305 #define MINT_IN_BREAK break
2306 #define MINT_IN_DEFAULT default:
2307 #endif
2310 * If EXIT_AT_FINALLY is not -1, exit after exiting the finally clause with that index.
2311 * If BASE_FRAME is not NULL, copy arguments/locals from BASE_FRAME.
2313 static void
2314 interp_exec_method_full (InterpFrame *frame, ThreadContext *context, guint16 *start_with_ip, MonoException *filter_exception, int exit_at_finally, InterpFrame *base_frame)
2316 InterpFrame child_frame;
2317 GSList *finally_ips = NULL;
2318 const unsigned short *endfinally_ip = NULL;
2319 const unsigned short *ip = NULL;
2320 register stackval *sp;
2321 InterpMethod *rtm = NULL;
2322 #if DEBUG_INTERP
2323 gint tracing = global_tracing;
2324 unsigned char *vtalloc;
2325 #else
2326 gint tracing = 0;
2327 #endif
2328 int i32;
2329 unsigned char *vt_sp;
2330 unsigned char *locals;
2331 ERROR_DECL (error);
2332 MonoObject *o = NULL;
2333 MonoClass *c;
2334 #if USE_COMPUTED_GOTO
2335 static void *in_labels[] = {
2336 #define OPDEF(a,b,c,d) \
2337 &&LAB_ ## a,
2338 #include "mintops.def"
2339 0 };
2340 #endif
2342 frame->ex = NULL;
2343 frame->ex_handler = NULL;
2344 frame->ip = NULL;
2345 frame->domain = mono_domain_get ();
2346 context->current_frame = frame;
2348 debug_enter (frame, &tracing);
2350 rtm = frame->imethod;
2351 if (!frame->imethod->transformed) {
2352 #if DEBUG_INTERP
2353 char *mn = mono_method_full_name (frame->imethod->method, TRUE);
2354 g_print ("(%p) Transforming %s\n", mono_thread_internal_current (), mn);
2355 g_free (mn);
2356 #endif
2358 do_transform_method (frame, context);
2359 if (frame->ex)
2360 THROW_EX (frame->ex, NULL);
2361 if (*mono_thread_interruption_request_flag ()) {
2362 MonoException *exc = mono_thread_interruption_checkpoint ();
2363 if (exc)
2364 THROW_EX (exc, NULL);
2369 if (!start_with_ip) {
2370 frame->args = alloca (rtm->alloca_size);
2371 memset (frame->args, 0, rtm->alloca_size);
2373 ip = rtm->code;
2374 } else {
2375 ip = start_with_ip;
2376 if (base_frame) {
2377 frame->args = alloca (rtm->alloca_size);
2378 memcpy (frame->args, base_frame->args, rtm->alloca_size);
2381 sp = frame->stack = (stackval *) ((char *) frame->args + rtm->args_size);
2382 vt_sp = (unsigned char *) sp + rtm->stack_size;
2383 #if DEBUG_INTERP
2384 vtalloc = vt_sp;
2385 #endif
2386 locals = (unsigned char *) vt_sp + rtm->vt_stack_size;
2387 frame->locals = locals;
2388 child_frame.parent = frame;
2390 if (filter_exception) {
2391 sp->data.p = filter_exception;
2392 sp++;
2396 * using while (ip < end) may result in a 15% performance drop,
2397 * but it may be useful for debug
2399 while (1) {
2400 main_loop:
2401 /* g_assert (sp >= frame->stack); */
2402 /* g_assert(vt_sp - vtalloc <= rtm->vt_stack_size); */
2403 DUMP_INSTR();
2404 MINT_IN_SWITCH (*ip) {
2405 MINT_IN_CASE(MINT_INITLOCALS)
2406 memset (locals, 0, rtm->locals_size);
2407 ++ip;
2408 MINT_IN_BREAK;
2409 MINT_IN_CASE(MINT_NOP)
2410 ++ip;
2411 MINT_IN_BREAK;
2412 MINT_IN_CASE(MINT_NIY)
2413 g_error ("mint_niy: instruction not implemented yet. This shouldn't happen.");
2414 MINT_IN_BREAK;
2415 MINT_IN_CASE(MINT_BREAK)
2416 ++ip;
2417 do_debugger_tramp (mono_debugger_agent_user_break, frame);
2418 MINT_IN_BREAK;
2419 MINT_IN_CASE(MINT_LDNULL)
2420 sp->data.p = NULL;
2421 ++ip;
2422 ++sp;
2423 MINT_IN_BREAK;
2424 MINT_IN_CASE(MINT_VTRESULT) {
2425 int ret_size = * (guint16 *)(ip + 1);
2426 unsigned char *ret_vt_sp = vt_sp;
2427 vt_sp -= READ32(ip + 2);
2428 if (ret_size > 0) {
2429 memmove (vt_sp, ret_vt_sp, ret_size);
2430 sp [-1].data.p = vt_sp;
2431 vt_sp += (ret_size + 7) & ~7;
2433 ip += 4;
2434 MINT_IN_BREAK;
2436 #define LDC(n) do { sp->data.i = (n); ++ip; ++sp; } while (0)
2437 MINT_IN_CASE(MINT_LDC_I4_M1)
2438 LDC(-1);
2439 MINT_IN_BREAK;
2440 MINT_IN_CASE(MINT_LDC_I4_0)
2441 LDC(0);
2442 MINT_IN_BREAK;
2443 MINT_IN_CASE(MINT_LDC_I4_1)
2444 LDC(1);
2445 MINT_IN_BREAK;
2446 MINT_IN_CASE(MINT_LDC_I4_2)
2447 LDC(2);
2448 MINT_IN_BREAK;
2449 MINT_IN_CASE(MINT_LDC_I4_3)
2450 LDC(3);
2451 MINT_IN_BREAK;
2452 MINT_IN_CASE(MINT_LDC_I4_4)
2453 LDC(4);
2454 MINT_IN_BREAK;
2455 MINT_IN_CASE(MINT_LDC_I4_5)
2456 LDC(5);
2457 MINT_IN_BREAK;
2458 MINT_IN_CASE(MINT_LDC_I4_6)
2459 LDC(6);
2460 MINT_IN_BREAK;
2461 MINT_IN_CASE(MINT_LDC_I4_7)
2462 LDC(7);
2463 MINT_IN_BREAK;
2464 MINT_IN_CASE(MINT_LDC_I4_8)
2465 LDC(8);
2466 MINT_IN_BREAK;
2467 MINT_IN_CASE(MINT_LDC_I4_S)
2468 sp->data.i = *(const short *)(ip + 1);
2469 ip += 2;
2470 ++sp;
2471 MINT_IN_BREAK;
2472 MINT_IN_CASE(MINT_LDC_I4)
2473 ++ip;
2474 sp->data.i = READ32 (ip);
2475 ip += 2;
2476 ++sp;
2477 MINT_IN_BREAK;
2478 MINT_IN_CASE(MINT_LDC_I8)
2479 ++ip;
2480 sp->data.l = READ64 (ip);
2481 ip += 4;
2482 ++sp;
2483 MINT_IN_BREAK;
2484 MINT_IN_CASE(MINT_LDC_R4) {
2485 guint32 val;
2486 ++ip;
2487 val = READ32(ip);
2488 sp->data.f = * (float *)&val;
2489 ip += 2;
2490 ++sp;
2491 MINT_IN_BREAK;
2493 MINT_IN_CASE(MINT_LDC_R8)
2494 sp->data.l = READ64 (ip + 1); /* note union usage */
2495 ip += 5;
2496 ++sp;
2497 MINT_IN_BREAK;
2498 MINT_IN_CASE(MINT_DUP)
2499 sp [0] = sp[-1];
2500 ++sp;
2501 ++ip;
2502 MINT_IN_BREAK;
2503 MINT_IN_CASE(MINT_DUP_VT)
2504 i32 = READ32 (ip + 1);
2505 sp->data.p = vt_sp;
2506 memcpy(sp->data.p, sp [-1].data.p, i32);
2507 vt_sp += (i32 + 7) & ~7;
2508 ++sp;
2509 ip += 3;
2510 MINT_IN_BREAK;
2511 MINT_IN_CASE(MINT_POP) {
2512 guint16 u16 = (* (guint16 *)(ip + 1)) + 1;
2513 if (u16 > 1)
2514 memmove (sp - u16, sp - 1, (u16 - 1) * sizeof (stackval));
2515 sp--;
2516 ip += 2;
2517 MINT_IN_BREAK;
2519 MINT_IN_CASE(MINT_JMP) {
2520 InterpMethod *new_method = rtm->data_items [* (guint16 *)(ip + 1)];
2521 gboolean realloc_frame = new_method->alloca_size > rtm->alloca_size;
2523 if (frame->imethod->prof_flags & MONO_PROFILER_CALL_INSTRUMENTATION_TAIL_CALL)
2524 MONO_PROFILER_RAISE (method_tail_call, (frame->imethod->method, new_method->method));
2526 if (!new_method->transformed) {
2527 frame->ip = ip;
2528 frame->ex = mono_interp_transform_method (new_method, context, NULL);
2529 if (frame->ex)
2530 goto exit_frame;
2532 ip += 2;
2533 rtm = frame->imethod = new_method;
2535 * We allocate the stack frame from scratch and store the arguments in the
2536 * locals again since it's possible for the caller stack frame to be smaller
2537 * than the callee stack frame (at the interp level)
2539 if (realloc_frame) {
2540 frame->args = alloca (rtm->alloca_size);
2541 memset (frame->args, 0, rtm->alloca_size);
2542 sp = frame->stack = (stackval *) ((char *) frame->args + rtm->args_size);
2544 vt_sp = (unsigned char *) sp + rtm->stack_size;
2545 #if DEBUG_INTERP
2546 vtalloc = vt_sp;
2547 #endif
2548 locals = vt_sp + rtm->vt_stack_size;
2549 frame->locals = locals;
2550 if (realloc_frame)
2551 ip = rtm->code;
2552 else
2553 ip = rtm->new_body_start; /* bypass storing input args from callers frame */
2554 MINT_IN_BREAK;
2556 MINT_IN_CASE(MINT_CALLI) {
2557 MonoMethodSignature *csignature;
2558 stackval *endsp = sp;
2560 frame->ip = ip;
2562 csignature = rtm->data_items [* (guint16 *)(ip + 1)];
2563 ip += 2;
2564 --sp;
2565 --endsp;
2566 child_frame.imethod = sp->data.p;
2568 sp->data.p = vt_sp;
2569 child_frame.retval = sp;
2570 /* decrement by the actual number of args */
2571 sp -= csignature->param_count;
2572 if (csignature->hasthis)
2573 --sp;
2574 child_frame.stack_args = sp;
2576 if (child_frame.imethod->method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) {
2577 child_frame.imethod = mono_interp_get_imethod (rtm->domain, mono_marshal_get_native_wrapper (child_frame.imethod->method, FALSE, FALSE), error);
2578 mono_error_cleanup (error); /* FIXME: don't swallow the error */
2581 if (csignature->hasthis) {
2582 MonoObject *this_arg = sp->data.p;
2584 if (this_arg->vtable->klass->valuetype) {
2585 gpointer *unboxed = mono_object_unbox (this_arg);
2586 sp [0].data.p = unboxed;
2590 interp_exec_method (&child_frame, context);
2592 context->current_frame = frame;
2594 if (context->has_resume_state) {
2595 if (frame == context->handler_frame)
2596 SET_RESUME_STATE (context);
2597 else
2598 goto exit_frame;
2601 CHECK_CHILD_EX (child_frame, ip - 2);
2603 /* need to handle typedbyref ... */
2604 if (csignature->ret->type != MONO_TYPE_VOID) {
2605 *sp = *endsp;
2606 sp++;
2608 MINT_IN_BREAK;
2610 MINT_IN_CASE(MINT_CALLI_NAT) {
2611 MonoMethodSignature *csignature;
2612 stackval *endsp = sp;
2613 unsigned char *code = NULL;
2615 frame->ip = ip;
2617 csignature = rtm->data_items [* (guint16 *)(ip + 1)];
2618 ip += 2;
2619 --sp;
2620 --endsp;
2621 code = sp->data.p;
2622 child_frame.imethod = NULL;
2624 sp->data.p = vt_sp;
2625 child_frame.retval = sp;
2626 /* decrement by the actual number of args */
2627 sp -= csignature->param_count;
2628 if (csignature->hasthis)
2629 --sp;
2630 child_frame.stack_args = sp;
2631 ves_pinvoke_method (&child_frame, csignature, (MonoFuncV) code, FALSE, context);
2633 context->current_frame = frame;
2635 if (context->has_resume_state) {
2636 if (frame == context->handler_frame)
2637 SET_RESUME_STATE (context);
2638 else
2639 goto exit_frame;
2642 CHECK_CHILD_EX (child_frame, ip - 2);
2644 /* need to handle typedbyref ... */
2645 if (csignature->ret->type != MONO_TYPE_VOID) {
2646 *sp = *endsp;
2647 sp++;
2649 MINT_IN_BREAK;
2651 MINT_IN_CASE(MINT_CALL) {
2652 stackval *endsp = sp;
2654 frame->ip = ip;
2656 child_frame.imethod = rtm->data_items [* (guint16 *)(ip + 1)];
2657 ip += 2;
2658 sp->data.p = vt_sp;
2659 child_frame.retval = sp;
2660 /* decrement by the actual number of args */
2661 sp -= child_frame.imethod->param_count + child_frame.imethod->hasthis;
2663 child_frame.stack_args = sp;
2665 interp_exec_method (&child_frame, context);
2667 context->current_frame = frame;
2669 if (context->has_resume_state) {
2670 if (frame == context->handler_frame)
2671 SET_RESUME_STATE (context);
2672 else
2673 goto exit_frame;
2675 CHECK_CHILD_EX (child_frame, ip - 2);
2677 /* need to handle typedbyref ... */
2678 *sp = *endsp;
2679 sp++;
2680 MINT_IN_BREAK;
2682 MINT_IN_CASE(MINT_VCALL) {
2683 frame->ip = ip;
2685 child_frame.imethod = rtm->data_items [* (guint16 *)(ip + 1)];
2686 ip += 2;
2688 sp->data.p = vt_sp;
2689 child_frame.retval = sp;
2690 /* decrement by the actual number of args */
2691 sp -= child_frame.imethod->param_count + child_frame.imethod->hasthis;
2692 child_frame.stack_args = sp;
2694 interp_exec_method (&child_frame, context);
2696 context->current_frame = frame;
2698 if (context->has_resume_state) {
2699 if (frame == context->handler_frame)
2700 SET_RESUME_STATE (context);
2701 else
2702 goto exit_frame;
2705 CHECK_CHILD_EX (child_frame, ip - 2);
2706 MINT_IN_BREAK;
2709 MINT_IN_CASE(MINT_JIT_CALL) {
2710 InterpMethod *rmethod = rtm->data_items [* (guint16 *)(ip + 1)];
2711 frame->ip = ip;
2712 ip += 2;
2713 sp = do_jit_call (sp, vt_sp, context, frame, rmethod);
2715 if (context->has_resume_state) {
2717 * If this bit is set, it means the call has thrown the exception, and we
2718 * reached this point because the EH code in mono_handle_exception ()
2719 * unwound all the JITted frames below us. mono_interp_set_resume_state ()
2720 * has set the fields in context to indicate where we have to resume execution.
2722 if (frame == context->handler_frame)
2723 SET_RESUME_STATE (context);
2724 else
2725 goto exit_frame;
2727 if (rmethod->rtype->type != MONO_TYPE_VOID)
2728 sp++;
2730 MINT_IN_BREAK;
2733 MINT_IN_CASE(MINT_CALLVIRT) {
2734 stackval *endsp = sp;
2735 MonoObject *this_arg;
2736 guint32 token;
2738 frame->ip = ip;
2740 token = * (unsigned short *)(ip + 1);
2741 ip += 2;
2742 child_frame.imethod = rtm->data_items [token];
2743 sp->data.p = vt_sp;
2744 child_frame.retval = sp;
2746 /* decrement by the actual number of args */
2747 sp -= child_frame.imethod->param_count + 1;
2748 child_frame.stack_args = sp;
2749 this_arg = sp->data.p;
2750 child_frame.imethod = get_virtual_method (child_frame.imethod, this_arg);
2752 MonoClass *this_class = this_arg->vtable->klass;
2753 if (this_class->valuetype && child_frame.imethod->method->klass->valuetype) {
2754 /* unbox */
2755 gpointer *unboxed = mono_object_unbox (this_arg);
2756 sp [0].data.p = unboxed;
2759 interp_exec_method (&child_frame, context);
2761 context->current_frame = frame;
2763 if (context->has_resume_state) {
2764 if (frame == context->handler_frame)
2765 SET_RESUME_STATE (context);
2766 else
2767 goto exit_frame;
2770 CHECK_CHILD_EX (child_frame, ip - 2);
2772 /* need to handle typedbyref ... */
2773 *sp = *endsp;
2774 sp++;
2775 MINT_IN_BREAK;
2777 MINT_IN_CASE(MINT_VCALLVIRT) {
2778 MonoObject *this_arg;
2779 guint32 token;
2781 frame->ip = ip;
2783 token = * (unsigned short *)(ip + 1);
2784 ip += 2;
2785 child_frame.imethod = rtm->data_items [token];
2786 sp->data.p = vt_sp;
2787 child_frame.retval = sp;
2789 /* decrement by the actual number of args */
2790 sp -= child_frame.imethod->param_count + 1;
2791 child_frame.stack_args = sp;
2792 this_arg = sp->data.p;
2793 child_frame.imethod = get_virtual_method (child_frame.imethod, this_arg);
2795 MonoClass *this_class = this_arg->vtable->klass;
2796 if (this_class->valuetype && child_frame.imethod->method->klass->valuetype) {
2797 gpointer *unboxed = mono_object_unbox (this_arg);
2798 sp [0].data.p = unboxed;
2801 interp_exec_method (&child_frame, context);
2803 context->current_frame = frame;
2805 if (context->has_resume_state) {
2806 if (frame == context->handler_frame)
2807 SET_RESUME_STATE (context);
2808 else
2809 goto exit_frame;
2812 CHECK_CHILD_EX (child_frame, ip - 2);
2813 MINT_IN_BREAK;
2815 MINT_IN_CASE(MINT_CALLRUN)
2816 ves_imethod (frame, context);
2817 if (frame->ex) {
2818 MonoException *fex = frame->ex;
2819 //frame = frame->parent;
2820 THROW_EX (fex, frame->ip);
2822 goto exit_frame;
2823 MINT_IN_CASE(MINT_RET)
2824 --sp;
2825 *frame->retval = *sp;
2826 if (sp > frame->stack)
2827 g_warning ("ret: more values on stack: %d", sp-frame->stack);
2828 goto exit_frame;
2829 MINT_IN_CASE(MINT_RET_VOID)
2830 if (sp > frame->stack)
2831 g_warning ("ret.void: more values on stack: %d %s", sp-frame->stack, mono_method_full_name (frame->imethod->method, TRUE));
2832 goto exit_frame;
2833 MINT_IN_CASE(MINT_RET_VT)
2834 i32 = READ32(ip + 1);
2835 --sp;
2836 memcpy(frame->retval->data.p, sp->data.p, i32);
2837 if (sp > frame->stack)
2838 g_warning ("ret.vt: more values on stack: %d", sp-frame->stack);
2839 goto exit_frame;
2840 MINT_IN_CASE(MINT_BR_S)
2841 /* Checkpoint to be able to handle aborts */
2842 EXCEPTION_CHECKPOINT;
2843 ip += (short) *(ip + 1);
2844 MINT_IN_BREAK;
2845 MINT_IN_CASE(MINT_BR)
2846 /* Checkpoint to be able to handle aborts */
2847 EXCEPTION_CHECKPOINT;
2848 ip += (gint32) READ32(ip + 1);
2849 MINT_IN_BREAK;
2850 #define ZEROP_S(datamem, op) \
2851 --sp; \
2852 if (sp->data.datamem op 0) \
2853 ip += * (gint16 *)(ip + 1); \
2854 else \
2855 ip += 2;
2857 #define ZEROP(datamem, op) \
2858 --sp; \
2859 if (sp->data.datamem op 0) \
2860 ip += READ32(ip + 1); \
2861 else \
2862 ip += 3;
2864 MINT_IN_CASE(MINT_BRFALSE_I4_S)
2865 ZEROP_S(i, ==);
2866 MINT_IN_BREAK;
2867 MINT_IN_CASE(MINT_BRFALSE_I8_S)
2868 ZEROP_S(l, ==);
2869 MINT_IN_BREAK;
2870 MINT_IN_CASE(MINT_BRFALSE_R8_S)
2871 ZEROP_S(f, ==);
2872 MINT_IN_BREAK;
2873 MINT_IN_CASE(MINT_BRFALSE_I4)
2874 ZEROP(i, ==);
2875 MINT_IN_BREAK;
2876 MINT_IN_CASE(MINT_BRFALSE_I8)
2877 ZEROP(l, ==);
2878 MINT_IN_BREAK;
2879 MINT_IN_CASE(MINT_BRFALSE_R8)
2880 ZEROP_S(f, ==);
2881 MINT_IN_BREAK;
2882 MINT_IN_CASE(MINT_BRTRUE_I4_S)
2883 ZEROP_S(i, !=);
2884 MINT_IN_BREAK;
2885 MINT_IN_CASE(MINT_BRTRUE_I8_S)
2886 ZEROP_S(l, !=);
2887 MINT_IN_BREAK;
2888 MINT_IN_CASE(MINT_BRTRUE_R8_S)
2889 ZEROP_S(f, !=);
2890 MINT_IN_BREAK;
2891 MINT_IN_CASE(MINT_BRTRUE_I4)
2892 ZEROP(i, !=);
2893 MINT_IN_BREAK;
2894 MINT_IN_CASE(MINT_BRTRUE_I8)
2895 ZEROP(l, !=);
2896 MINT_IN_BREAK;
2897 MINT_IN_CASE(MINT_BRTRUE_R8)
2898 ZEROP(f, !=);
2899 MINT_IN_BREAK;
2900 #define CONDBR_S(cond) \
2901 sp -= 2; \
2902 if (cond) \
2903 ip += * (gint16 *)(ip + 1); \
2904 else \
2905 ip += 2;
2906 #define BRELOP_S(datamem, op) \
2907 CONDBR_S(sp[0].data.datamem op sp[1].data.datamem)
2909 #define CONDBR(cond) \
2910 sp -= 2; \
2911 if (cond) \
2912 ip += READ32(ip + 1); \
2913 else \
2914 ip += 3;
2916 #define BRELOP(datamem, op) \
2917 CONDBR(sp[0].data.datamem op sp[1].data.datamem)
2919 MINT_IN_CASE(MINT_BEQ_I4_S)
2920 BRELOP_S(i, ==)
2921 MINT_IN_BREAK;
2922 MINT_IN_CASE(MINT_BEQ_I8_S)
2923 BRELOP_S(l, ==)
2924 MINT_IN_BREAK;
2925 MINT_IN_CASE(MINT_BEQ_R8_S)
2926 CONDBR_S(!isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f == sp[1].data.f)
2927 MINT_IN_BREAK;
2928 MINT_IN_CASE(MINT_BEQ_I4)
2929 BRELOP(i, ==)
2930 MINT_IN_BREAK;
2931 MINT_IN_CASE(MINT_BEQ_I8)
2932 BRELOP(l, ==)
2933 MINT_IN_BREAK;
2934 MINT_IN_CASE(MINT_BEQ_R8)
2935 CONDBR(!isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f == sp[1].data.f)
2936 MINT_IN_BREAK;
2937 MINT_IN_CASE(MINT_BGE_I4_S)
2938 BRELOP_S(i, >=)
2939 MINT_IN_BREAK;
2940 MINT_IN_CASE(MINT_BGE_I8_S)
2941 BRELOP_S(l, >=)
2942 MINT_IN_BREAK;
2943 MINT_IN_CASE(MINT_BGE_R8_S)
2944 CONDBR_S(!isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f >= sp[1].data.f)
2945 MINT_IN_BREAK;
2946 MINT_IN_CASE(MINT_BGE_I4)
2947 BRELOP(i, >=)
2948 MINT_IN_BREAK;
2949 MINT_IN_CASE(MINT_BGE_I8)
2950 BRELOP(l, >=)
2951 MINT_IN_BREAK;
2952 MINT_IN_CASE(MINT_BGE_R8)
2953 CONDBR(!isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f >= sp[1].data.f)
2954 MINT_IN_BREAK;
2955 MINT_IN_CASE(MINT_BGT_I4_S)
2956 BRELOP_S(i, >)
2957 MINT_IN_BREAK;
2958 MINT_IN_CASE(MINT_BGT_I8_S)
2959 BRELOP_S(l, >)
2960 MINT_IN_BREAK;
2961 MINT_IN_CASE(MINT_BGT_R8_S)
2962 CONDBR_S(!isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f > sp[1].data.f)
2963 MINT_IN_BREAK;
2964 MINT_IN_CASE(MINT_BGT_I4)
2965 BRELOP(i, >)
2966 MINT_IN_BREAK;
2967 MINT_IN_CASE(MINT_BGT_I8)
2968 BRELOP(l, >)
2969 MINT_IN_BREAK;
2970 MINT_IN_CASE(MINT_BGT_R8)
2971 CONDBR(!isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f > sp[1].data.f)
2972 MINT_IN_BREAK;
2973 MINT_IN_CASE(MINT_BLT_I4_S)
2974 BRELOP_S(i, <)
2975 MINT_IN_BREAK;
2976 MINT_IN_CASE(MINT_BLT_I8_S)
2977 BRELOP_S(l, <)
2978 MINT_IN_BREAK;
2979 MINT_IN_CASE(MINT_BLT_R8_S)
2980 CONDBR_S(!isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f < sp[1].data.f)
2981 MINT_IN_BREAK;
2982 MINT_IN_CASE(MINT_BLT_I4)
2983 BRELOP(i, <)
2984 MINT_IN_BREAK;
2985 MINT_IN_CASE(MINT_BLT_I8)
2986 BRELOP(l, <)
2987 MINT_IN_BREAK;
2988 MINT_IN_CASE(MINT_BLT_R8)
2989 CONDBR(!isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f < sp[1].data.f)
2990 MINT_IN_BREAK;
2991 MINT_IN_CASE(MINT_BLE_I4_S)
2992 BRELOP_S(i, <=)
2993 MINT_IN_BREAK;
2994 MINT_IN_CASE(MINT_BLE_I8_S)
2995 BRELOP_S(l, <=)
2996 MINT_IN_BREAK;
2997 MINT_IN_CASE(MINT_BLE_R8_S)
2998 CONDBR_S(!isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f <= sp[1].data.f)
2999 MINT_IN_BREAK;
3000 MINT_IN_CASE(MINT_BLE_I4)
3001 BRELOP(i, <=)
3002 MINT_IN_BREAK;
3003 MINT_IN_CASE(MINT_BLE_I8)
3004 BRELOP(l, <=)
3005 MINT_IN_BREAK;
3006 MINT_IN_CASE(MINT_BLE_R8)
3007 CONDBR(!isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f <= sp[1].data.f)
3008 MINT_IN_BREAK;
3009 MINT_IN_CASE(MINT_BNE_UN_I4_S)
3010 BRELOP_S(i, !=)
3011 MINT_IN_BREAK;
3012 MINT_IN_CASE(MINT_BNE_UN_I8_S)
3013 BRELOP_S(l, !=)
3014 MINT_IN_BREAK;
3015 MINT_IN_CASE(MINT_BNE_UN_R8_S)
3016 CONDBR_S(isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f != sp[1].data.f)
3017 MINT_IN_BREAK;
3018 MINT_IN_CASE(MINT_BNE_UN_I4)
3019 BRELOP(i, !=)
3020 MINT_IN_BREAK;
3021 MINT_IN_CASE(MINT_BNE_UN_I8)
3022 BRELOP(l, !=)
3023 MINT_IN_BREAK;
3024 MINT_IN_CASE(MINT_BNE_UN_R8)
3025 CONDBR(isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f != sp[1].data.f)
3026 MINT_IN_BREAK;
3028 #define BRELOP_S_CAST(datamem, op, type) \
3029 sp -= 2; \
3030 if ((type) sp[0].data.datamem op (type) sp[1].data.datamem) \
3031 ip += * (gint16 *)(ip + 1); \
3032 else \
3033 ip += 2;
3035 #define BRELOP_CAST(datamem, op, type) \
3036 sp -= 2; \
3037 if ((type) sp[0].data.datamem op (type) sp[1].data.datamem) \
3038 ip += READ32(ip + 1); \
3039 else \
3040 ip += 3;
3042 MINT_IN_CASE(MINT_BGE_UN_I4_S)
3043 BRELOP_S_CAST(i, >=, guint32);
3044 MINT_IN_BREAK;
3045 MINT_IN_CASE(MINT_BGE_UN_I8_S)
3046 BRELOP_S_CAST(l, >=, guint64);
3047 MINT_IN_BREAK;
3048 MINT_IN_CASE(MINT_BGE_UN_R8_S)
3049 CONDBR_S(isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f >= sp[1].data.f)
3050 MINT_IN_BREAK;
3051 MINT_IN_CASE(MINT_BGE_UN_I4)
3052 BRELOP_CAST(i, >=, guint32);
3053 MINT_IN_BREAK;
3054 MINT_IN_CASE(MINT_BGE_UN_I8)
3055 BRELOP_CAST(l, >=, guint64);
3056 MINT_IN_BREAK;
3057 MINT_IN_CASE(MINT_BGE_UN_R8)
3058 CONDBR(isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f >= sp[1].data.f)
3059 MINT_IN_BREAK;
3060 MINT_IN_CASE(MINT_BGT_UN_I4_S)
3061 BRELOP_S_CAST(i, >, guint32);
3062 MINT_IN_BREAK;
3063 MINT_IN_CASE(MINT_BGT_UN_I8_S)
3064 BRELOP_S_CAST(l, >, guint64);
3065 MINT_IN_BREAK;
3066 MINT_IN_CASE(MINT_BGT_UN_R8_S)
3067 CONDBR_S(isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f > sp[1].data.f)
3068 MINT_IN_BREAK;
3069 MINT_IN_CASE(MINT_BGT_UN_I4)
3070 BRELOP_CAST(i, >, guint32);
3071 MINT_IN_BREAK;
3072 MINT_IN_CASE(MINT_BGT_UN_I8)
3073 BRELOP_CAST(l, >, guint64);
3074 MINT_IN_BREAK;
3075 MINT_IN_CASE(MINT_BGT_UN_R8)
3076 CONDBR(isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f > sp[1].data.f)
3077 MINT_IN_BREAK;
3078 MINT_IN_CASE(MINT_BLE_UN_I4_S)
3079 BRELOP_S_CAST(i, <=, guint32);
3080 MINT_IN_BREAK;
3081 MINT_IN_CASE(MINT_BLE_UN_I8_S)
3082 BRELOP_S_CAST(l, <=, guint64);
3083 MINT_IN_BREAK;
3084 MINT_IN_CASE(MINT_BLE_UN_R8_S)
3085 CONDBR_S(isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f <= sp[1].data.f)
3086 MINT_IN_BREAK;
3087 MINT_IN_CASE(MINT_BLE_UN_I4)
3088 BRELOP_CAST(i, <=, guint32);
3089 MINT_IN_BREAK;
3090 MINT_IN_CASE(MINT_BLE_UN_I8)
3091 BRELOP_CAST(l, <=, guint64);
3092 MINT_IN_BREAK;
3093 MINT_IN_CASE(MINT_BLE_UN_R8)
3094 CONDBR(isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f <= sp[1].data.f)
3095 MINT_IN_BREAK;
3096 MINT_IN_CASE(MINT_BLT_UN_I4_S)
3097 BRELOP_S_CAST(i, <, guint32);
3098 MINT_IN_BREAK;
3099 MINT_IN_CASE(MINT_BLT_UN_I8_S)
3100 BRELOP_S_CAST(l, <, guint64);
3101 MINT_IN_BREAK;
3102 MINT_IN_CASE(MINT_BLT_UN_R8_S)
3103 CONDBR_S(isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f < sp[1].data.f)
3104 MINT_IN_BREAK;
3105 MINT_IN_CASE(MINT_BLT_UN_I4)
3106 BRELOP_CAST(i, <, guint32);
3107 MINT_IN_BREAK;
3108 MINT_IN_CASE(MINT_BLT_UN_I8)
3109 BRELOP_CAST(l, <, guint64);
3110 MINT_IN_BREAK;
3111 MINT_IN_CASE(MINT_BLT_UN_R8)
3112 CONDBR(isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f < sp[1].data.f)
3113 MINT_IN_BREAK;
3114 MINT_IN_CASE(MINT_SWITCH) {
3115 guint32 n;
3116 const unsigned short *st;
3117 ++ip;
3118 n = READ32 (ip);
3119 ip += 2;
3120 st = ip + 2 * n;
3121 --sp;
3122 if ((guint32)sp->data.i < n) {
3123 gint offset;
3124 ip += 2 * (guint32)sp->data.i;
3125 offset = READ32 (ip);
3126 ip = ip + offset;
3127 } else {
3128 ip = st;
3130 MINT_IN_BREAK;
3132 MINT_IN_CASE(MINT_LDIND_I1)
3133 ++ip;
3134 sp[-1].data.i = *(gint8*)sp[-1].data.p;
3135 MINT_IN_BREAK;
3136 MINT_IN_CASE(MINT_LDIND_U1)
3137 ++ip;
3138 sp[-1].data.i = *(guint8*)sp[-1].data.p;
3139 MINT_IN_BREAK;
3140 MINT_IN_CASE(MINT_LDIND_I2)
3141 ++ip;
3142 sp[-1].data.i = *(gint16*)sp[-1].data.p;
3143 MINT_IN_BREAK;
3144 MINT_IN_CASE(MINT_LDIND_U2)
3145 ++ip;
3146 sp[-1].data.i = *(guint16*)sp[-1].data.p;
3147 MINT_IN_BREAK;
3148 MINT_IN_CASE(MINT_LDIND_I4) /* Fall through */
3149 MINT_IN_CASE(MINT_LDIND_U4)
3150 ++ip;
3151 sp[-1].data.i = *(gint32*)sp[-1].data.p;
3152 MINT_IN_BREAK;
3153 MINT_IN_CASE(MINT_LDIND_I8)
3154 ++ip;
3155 /* memmove handles unaligned case */
3156 memmove (&sp [-1].data.l, sp [-1].data.p, sizeof (gint64));
3157 MINT_IN_BREAK;
3158 MINT_IN_CASE(MINT_LDIND_I) {
3159 guint16 offset = * (guint16 *)(ip + 1);
3160 sp[-1 - offset].data.p = *(gpointer*)sp[-1 - offset].data.p;
3161 ip += 2;
3162 MINT_IN_BREAK;
3164 MINT_IN_CASE(MINT_LDIND_R4)
3165 ++ip;
3166 sp[-1].data.f = *(gfloat*)sp[-1].data.p;
3167 MINT_IN_BREAK;
3168 MINT_IN_CASE(MINT_LDIND_R8)
3169 ++ip;
3170 sp[-1].data.f = *(gdouble*)sp[-1].data.p;
3171 MINT_IN_BREAK;
3172 MINT_IN_CASE(MINT_LDIND_REF)
3173 ++ip;
3174 sp[-1].data.p = *(gpointer*)sp[-1].data.p;
3175 MINT_IN_BREAK;
3176 MINT_IN_CASE(MINT_STIND_REF)
3177 ++ip;
3178 sp -= 2;
3179 mono_gc_wbarrier_generic_store (sp->data.p, sp [1].data.p);
3180 MINT_IN_BREAK;
3181 MINT_IN_CASE(MINT_STIND_I1)
3182 ++ip;
3183 sp -= 2;
3184 * (gint8 *) sp->data.p = (gint8)sp[1].data.i;
3185 MINT_IN_BREAK;
3186 MINT_IN_CASE(MINT_STIND_I2)
3187 ++ip;
3188 sp -= 2;
3189 * (gint16 *) sp->data.p = (gint16)sp[1].data.i;
3190 MINT_IN_BREAK;
3191 MINT_IN_CASE(MINT_STIND_I4)
3192 ++ip;
3193 sp -= 2;
3194 * (gint32 *) sp->data.p = sp[1].data.i;
3195 MINT_IN_BREAK;
3196 MINT_IN_CASE(MINT_STIND_I)
3197 ++ip;
3198 sp -= 2;
3199 * (mono_i *) sp->data.p = (mono_i)sp[1].data.p;
3200 MINT_IN_BREAK;
3201 MINT_IN_CASE(MINT_STIND_I8)
3202 ++ip;
3203 sp -= 2;
3204 * (gint64 *) sp->data.p = sp[1].data.l;
3205 MINT_IN_BREAK;
3206 MINT_IN_CASE(MINT_STIND_R4)
3207 ++ip;
3208 sp -= 2;
3209 * (float *) sp->data.p = (gfloat)sp[1].data.f;
3210 MINT_IN_BREAK;
3211 MINT_IN_CASE(MINT_STIND_R8)
3212 ++ip;
3213 sp -= 2;
3214 * (double *) sp->data.p = sp[1].data.f;
3215 MINT_IN_BREAK;
3216 MINT_IN_CASE(MINT_MONO_ATOMIC_STORE_I4)
3217 ++ip;
3218 sp -= 2;
3219 mono_atomic_store_i32 ((gint32 *) sp->data.p, sp [1].data.i);
3220 MINT_IN_BREAK;
3221 #define BINOP(datamem, op) \
3222 --sp; \
3223 sp [-1].data.datamem = sp [-1].data.datamem op sp [0].data.datamem; \
3224 ++ip;
3225 MINT_IN_CASE(MINT_ADD_I4)
3226 BINOP(i, +);
3227 MINT_IN_BREAK;
3228 MINT_IN_CASE(MINT_ADD_I8)
3229 BINOP(l, +);
3230 MINT_IN_BREAK;
3231 MINT_IN_CASE(MINT_ADD_R8)
3232 BINOP(f, +);
3233 MINT_IN_BREAK;
3234 MINT_IN_CASE(MINT_ADD1_I4)
3235 ++sp [-1].data.i;
3236 ++ip;
3237 MINT_IN_BREAK;
3238 MINT_IN_CASE(MINT_SUB_I4)
3239 BINOP(i, -);
3240 MINT_IN_BREAK;
3241 MINT_IN_CASE(MINT_SUB_I8)
3242 BINOP(l, -);
3243 MINT_IN_BREAK;
3244 MINT_IN_CASE(MINT_SUB_R8)
3245 BINOP(f, -);
3246 MINT_IN_BREAK;
3247 MINT_IN_CASE(MINT_SUB1_I4)
3248 --sp [-1].data.i;
3249 ++ip;
3250 MINT_IN_BREAK;
3251 MINT_IN_CASE(MINT_MUL_I4)
3252 BINOP(i, *);
3253 MINT_IN_BREAK;
3254 MINT_IN_CASE(MINT_MUL_I8)
3255 BINOP(l, *);
3256 MINT_IN_BREAK;
3257 MINT_IN_CASE(MINT_MUL_R8)
3258 BINOP(f, *);
3259 MINT_IN_BREAK;
3260 MINT_IN_CASE(MINT_DIV_I4)
3261 if (sp [-1].data.i == 0)
3262 THROW_EX (mono_get_exception_divide_by_zero (), ip);
3263 if (sp [-1].data.i == (-1))
3264 THROW_EX (mono_get_exception_overflow (), ip);
3265 BINOP(i, /);
3266 MINT_IN_BREAK;
3267 MINT_IN_CASE(MINT_DIV_I8)
3268 if (sp [-1].data.l == 0)
3269 THROW_EX (mono_get_exception_divide_by_zero (), ip);
3270 if (sp [-1].data.l == (-1))
3271 THROW_EX (mono_get_exception_overflow (), ip);
3272 BINOP(l, /);
3273 MINT_IN_BREAK;
3274 MINT_IN_CASE(MINT_DIV_R8)
3275 BINOP(f, /);
3276 MINT_IN_BREAK;
3278 #define BINOP_CAST(datamem, op, type) \
3279 --sp; \
3280 sp [-1].data.datamem = (type)sp [-1].data.datamem op (type)sp [0].data.datamem; \
3281 ++ip;
3282 MINT_IN_CASE(MINT_DIV_UN_I4)
3283 if (sp [-1].data.i == 0)
3284 THROW_EX (mono_get_exception_divide_by_zero (), ip);
3285 BINOP_CAST(i, /, guint32);
3286 MINT_IN_BREAK;
3287 MINT_IN_CASE(MINT_DIV_UN_I8)
3288 if (sp [-1].data.l == 0)
3289 THROW_EX (mono_get_exception_divide_by_zero (), ip);
3290 BINOP_CAST(l, /, guint64);
3291 MINT_IN_BREAK;
3292 MINT_IN_CASE(MINT_REM_I4)
3293 if (sp [-1].data.i == 0)
3294 THROW_EX (mono_get_exception_divide_by_zero (), ip);
3295 if (sp [-1].data.i == (-1))
3296 THROW_EX (mono_get_exception_overflow (), ip);
3297 BINOP(i, %);
3298 MINT_IN_BREAK;
3299 MINT_IN_CASE(MINT_REM_I8)
3300 if (sp [-1].data.l == 0)
3301 THROW_EX (mono_get_exception_divide_by_zero (), ip);
3302 if (sp [-1].data.l == (-1))
3303 THROW_EX (mono_get_exception_overflow (), ip);
3304 BINOP(l, %);
3305 MINT_IN_BREAK;
3306 MINT_IN_CASE(MINT_REM_R8)
3307 /* FIXME: what do we actually do here? */
3308 --sp;
3309 sp [-1].data.f = fmod (sp [-1].data.f, sp [0].data.f);
3310 ++ip;
3311 MINT_IN_BREAK;
3312 MINT_IN_CASE(MINT_REM_UN_I4)
3313 if (sp [-1].data.i == 0)
3314 THROW_EX (mono_get_exception_divide_by_zero (), ip);
3315 BINOP_CAST(i, %, guint32);
3316 MINT_IN_BREAK;
3317 MINT_IN_CASE(MINT_REM_UN_I8)
3318 if (sp [-1].data.l == 0)
3319 THROW_EX (mono_get_exception_divide_by_zero (), ip);
3320 BINOP_CAST(l, %, guint64);
3321 MINT_IN_BREAK;
3322 MINT_IN_CASE(MINT_AND_I4)
3323 BINOP(i, &);
3324 MINT_IN_BREAK;
3325 MINT_IN_CASE(MINT_AND_I8)
3326 BINOP(l, &);
3327 MINT_IN_BREAK;
3328 MINT_IN_CASE(MINT_OR_I4)
3329 BINOP(i, |);
3330 MINT_IN_BREAK;
3331 MINT_IN_CASE(MINT_OR_I8)
3332 BINOP(l, |);
3333 MINT_IN_BREAK;
3334 MINT_IN_CASE(MINT_XOR_I4)
3335 BINOP(i, ^);
3336 MINT_IN_BREAK;
3337 MINT_IN_CASE(MINT_XOR_I8)
3338 BINOP(l, ^);
3339 MINT_IN_BREAK;
3341 #define SHIFTOP(datamem, op) \
3342 --sp; \
3343 sp [-1].data.datamem = sp [-1].data.datamem op sp [0].data.i; \
3344 ++ip;
3346 MINT_IN_CASE(MINT_SHL_I4)
3347 SHIFTOP(i, <<);
3348 MINT_IN_BREAK;
3349 MINT_IN_CASE(MINT_SHL_I8)
3350 SHIFTOP(l, <<);
3351 MINT_IN_BREAK;
3352 MINT_IN_CASE(MINT_SHR_I4)
3353 SHIFTOP(i, >>);
3354 MINT_IN_BREAK;
3355 MINT_IN_CASE(MINT_SHR_I8)
3356 SHIFTOP(l, >>);
3357 MINT_IN_BREAK;
3358 MINT_IN_CASE(MINT_SHR_UN_I4)
3359 --sp;
3360 sp [-1].data.i = (guint32)sp [-1].data.i >> sp [0].data.i;
3361 ++ip;
3362 MINT_IN_BREAK;
3363 MINT_IN_CASE(MINT_SHR_UN_I8)
3364 --sp;
3365 sp [-1].data.l = (guint64)sp [-1].data.l >> sp [0].data.i;
3366 ++ip;
3367 MINT_IN_BREAK;
3368 MINT_IN_CASE(MINT_NEG_I4)
3369 sp [-1].data.i = - sp [-1].data.i;
3370 ++ip;
3371 MINT_IN_BREAK;
3372 MINT_IN_CASE(MINT_NEG_I8)
3373 sp [-1].data.l = - sp [-1].data.l;
3374 ++ip;
3375 MINT_IN_BREAK;
3376 MINT_IN_CASE(MINT_NEG_R8)
3377 sp [-1].data.f = - sp [-1].data.f;
3378 ++ip;
3379 MINT_IN_BREAK;
3380 MINT_IN_CASE(MINT_NOT_I4)
3381 sp [-1].data.i = ~ sp [-1].data.i;
3382 ++ip;
3383 MINT_IN_BREAK;
3384 MINT_IN_CASE(MINT_NOT_I8)
3385 sp [-1].data.l = ~ sp [-1].data.l;
3386 ++ip;
3387 MINT_IN_BREAK;
3388 MINT_IN_CASE(MINT_CONV_I1_I4)
3389 sp [-1].data.i = (gint8)sp [-1].data.i;
3390 ++ip;
3391 MINT_IN_BREAK;
3392 MINT_IN_CASE(MINT_CONV_I1_I8)
3393 sp [-1].data.i = (gint8)sp [-1].data.l;
3394 ++ip;
3395 MINT_IN_BREAK;
3396 MINT_IN_CASE(MINT_CONV_I1_R8)
3397 sp [-1].data.i = (gint8)sp [-1].data.f;
3398 ++ip;
3399 MINT_IN_BREAK;
3400 MINT_IN_CASE(MINT_CONV_U1_I4)
3401 sp [-1].data.i = (guint8)sp [-1].data.i;
3402 ++ip;
3403 MINT_IN_BREAK;
3404 MINT_IN_CASE(MINT_CONV_U1_I8)
3405 sp [-1].data.i = (guint8)sp [-1].data.l;
3406 ++ip;
3407 MINT_IN_BREAK;
3408 MINT_IN_CASE(MINT_CONV_U1_R8)
3409 sp [-1].data.i = (guint8)sp [-1].data.f;
3410 ++ip;
3411 MINT_IN_BREAK;
3412 MINT_IN_CASE(MINT_CONV_I2_I4)
3413 sp [-1].data.i = (gint16)sp [-1].data.i;
3414 ++ip;
3415 MINT_IN_BREAK;
3416 MINT_IN_CASE(MINT_CONV_I2_I8)
3417 sp [-1].data.i = (gint16)sp [-1].data.l;
3418 ++ip;
3419 MINT_IN_BREAK;
3420 MINT_IN_CASE(MINT_CONV_I2_R8)
3421 sp [-1].data.i = (gint16)sp [-1].data.f;
3422 ++ip;
3423 MINT_IN_BREAK;
3424 MINT_IN_CASE(MINT_CONV_U2_I4)
3425 sp [-1].data.i = (guint16)sp [-1].data.i;
3426 ++ip;
3427 MINT_IN_BREAK;
3428 MINT_IN_CASE(MINT_CONV_U2_I8)
3429 sp [-1].data.i = (guint16)sp [-1].data.l;
3430 ++ip;
3431 MINT_IN_BREAK;
3432 MINT_IN_CASE(MINT_CONV_U2_R8)
3433 sp [-1].data.i = (guint16)sp [-1].data.f;
3434 ++ip;
3435 MINT_IN_BREAK;
3436 MINT_IN_CASE(MINT_CONV_I4_R8)
3437 sp [-1].data.i = (gint32)sp [-1].data.f;
3438 ++ip;
3439 MINT_IN_BREAK;
3440 MINT_IN_CASE(MINT_CONV_U4_I8)
3441 MINT_IN_CASE(MINT_CONV_I4_I8)
3442 sp [-1].data.i = (gint32)sp [-1].data.l;
3443 ++ip;
3444 MINT_IN_BREAK;
3445 MINT_IN_CASE(MINT_CONV_I4_I8_SP)
3446 sp [-2].data.i = (gint32)sp [-2].data.l;
3447 ++ip;
3448 MINT_IN_BREAK;
3449 MINT_IN_CASE(MINT_CONV_U4_R8)
3450 /* needed on arm64 */
3451 if (isinf (sp [-1].data.f))
3452 sp [-1].data.i = 0;
3453 /* needed by wasm */
3454 else if (isnan (sp [-1].data.f))
3455 sp [-1].data.i = 0;
3456 else
3457 sp [-1].data.i = (guint32)sp [-1].data.f;
3458 ++ip;
3459 MINT_IN_BREAK;
3460 MINT_IN_CASE(MINT_CONV_I8_I4)
3461 sp [-1].data.l = sp [-1].data.i;
3462 ++ip;
3463 MINT_IN_BREAK;
3464 MINT_IN_CASE(MINT_CONV_I8_I4_SP)
3465 sp [-2].data.l = sp [-2].data.i;
3466 ++ip;
3467 MINT_IN_BREAK;
3468 MINT_IN_CASE(MINT_CONV_I8_U4)
3469 sp [-1].data.l = (guint32)sp [-1].data.i;
3470 ++ip;
3471 MINT_IN_BREAK;
3472 MINT_IN_CASE(MINT_CONV_I8_R8)
3473 sp [-1].data.l = (gint64)sp [-1].data.f;
3474 ++ip;
3475 MINT_IN_BREAK;
3476 MINT_IN_CASE(MINT_CONV_R4_I4)
3477 sp [-1].data.f = (float)sp [-1].data.i;
3478 ++ip;
3479 MINT_IN_BREAK;
3480 MINT_IN_CASE(MINT_CONV_R4_I8)
3481 sp [-1].data.f = (float)sp [-1].data.l;
3482 ++ip;
3483 MINT_IN_BREAK;
3484 MINT_IN_CASE(MINT_CONV_R4_R8)
3485 sp [-1].data.f = (float)sp [-1].data.f;
3486 ++ip;
3487 MINT_IN_BREAK;
3488 MINT_IN_CASE(MINT_CONV_R8_I4)
3489 sp [-1].data.f = (double)sp [-1].data.i;
3490 ++ip;
3491 MINT_IN_BREAK;
3492 MINT_IN_CASE(MINT_CONV_R8_I8)
3493 sp [-1].data.f = (double)sp [-1].data.l;
3494 ++ip;
3495 MINT_IN_BREAK;
3496 MINT_IN_CASE(MINT_CONV_U8_I4)
3497 sp [-1].data.l = sp [-1].data.i & 0xffffffff;
3498 ++ip;
3499 MINT_IN_BREAK;
3500 MINT_IN_CASE(MINT_CONV_U8_R8)
3501 sp [-1].data.l = (guint64)sp [-1].data.f;
3502 ++ip;
3503 MINT_IN_BREAK;
3504 MINT_IN_CASE(MINT_CPOBJ) {
3505 c = rtm->data_items[* (guint16 *)(ip + 1)];
3506 g_assert (c->valuetype);
3507 /* if this assertion fails, we need to add a write barrier */
3508 g_assert (!MONO_TYPE_IS_REFERENCE (&c->byval_arg));
3509 if (mint_type (&c->byval_arg) == MINT_TYPE_VT)
3510 stackval_from_data (&c->byval_arg, &sp [-2], sp [-1].data.p, FALSE);
3511 else
3512 stackval_from_data (&c->byval_arg, sp [-2].data.p, sp [-1].data.p, FALSE);
3513 ip += 2;
3514 sp -= 2;
3515 MINT_IN_BREAK;
3517 MINT_IN_CASE(MINT_LDOBJ) {
3518 void *p;
3519 c = rtm->data_items[* (guint16 *)(ip + 1)];
3520 ip += 2;
3521 p = sp [-1].data.p;
3522 if (mint_type (&c->byval_arg) == MINT_TYPE_VT && !c->enumtype) {
3523 int size = mono_class_value_size (c, NULL);
3524 sp [-1].data.p = vt_sp;
3525 vt_sp += (size + 7) & ~7;
3527 stackval_from_data (&c->byval_arg, &sp [-1], p, FALSE);
3528 MINT_IN_BREAK;
3530 MINT_IN_CASE(MINT_LDSTR)
3531 sp->data.p = rtm->data_items [* (guint16 *)(ip + 1)];
3532 ++sp;
3533 ip += 2;
3534 MINT_IN_BREAK;
3535 MINT_IN_CASE(MINT_NEWOBJ) {
3536 MonoClass *newobj_class;
3537 MonoMethodSignature *csig;
3538 stackval valuetype_this;
3539 guint32 token;
3540 stackval retval;
3542 frame->ip = ip;
3544 token = * (guint16 *)(ip + 1);
3545 ip += 2;
3547 child_frame.ip = NULL;
3548 child_frame.ex = NULL;
3550 child_frame.imethod = rtm->data_items [token];
3551 csig = mono_method_signature (child_frame.imethod->method);
3552 newobj_class = child_frame.imethod->method->klass;
3553 /*if (profiling_classes) {
3554 guint count = GPOINTER_TO_UINT (g_hash_table_lookup (profiling_classes, newobj_class));
3555 count++;
3556 g_hash_table_insert (profiling_classes, newobj_class, GUINT_TO_POINTER (count));
3559 if (newobj_class->parent == mono_defaults.array_class) {
3560 sp -= csig->param_count;
3561 child_frame.stack_args = sp;
3562 o = ves_array_create (&child_frame, rtm->domain, newobj_class, csig, sp);
3563 CHECK_CHILD_EX (child_frame, ip - 2);
3564 goto array_constructed;
3567 g_assert (csig->hasthis);
3568 if (csig->param_count) {
3569 sp -= csig->param_count;
3570 memmove (sp + 1, sp, csig->param_count * sizeof (stackval));
3572 child_frame.stack_args = sp;
3575 * First arg is the object.
3577 if (newobj_class->valuetype) {
3578 MonoType *t = &newobj_class->byval_arg;
3579 memset (&valuetype_this, 0, sizeof (stackval));
3580 if (!newobj_class->enumtype && (t->type == MONO_TYPE_VALUETYPE || (t->type == MONO_TYPE_GENERICINST && mono_type_generic_inst_is_valuetype (t)))) {
3581 sp->data.p = vt_sp;
3582 valuetype_this.data.p = vt_sp;
3583 } else {
3584 sp->data.p = &valuetype_this;
3586 } else {
3587 if (newobj_class != mono_defaults.string_class) {
3588 MonoVTable *vtable = mono_class_vtable_checked (rtm->domain, newobj_class, error);
3589 if (!mono_error_ok (error) || !mono_runtime_class_init_full (vtable, error))
3590 THROW_EX (mono_error_convert_to_exception (error), ip);
3591 o = mono_object_new_checked (rtm->domain, newobj_class, error);
3592 mono_error_cleanup (error); /* FIXME: don't swallow the error */
3593 EXCEPTION_CHECKPOINT;
3594 sp->data.p = o;
3595 #ifndef DISABLE_REMOTING
3596 if (mono_object_is_transparent_proxy (o)) {
3597 MonoMethod *remoting_invoke_method = mono_marshal_get_remoting_invoke_with_check (child_frame.imethod->method, error);
3598 mono_error_assert_ok (error);
3599 child_frame.imethod = mono_interp_get_imethod (rtm->domain, remoting_invoke_method, error);
3600 mono_error_assert_ok (error);
3602 #endif
3603 } else {
3604 sp->data.p = NULL;
3605 child_frame.retval = &retval;
3609 g_assert (csig->call_convention == MONO_CALL_DEFAULT);
3611 interp_exec_method (&child_frame, context);
3613 context->current_frame = frame;
3615 if (context->has_resume_state) {
3616 if (frame == context->handler_frame)
3617 SET_RESUME_STATE (context);
3618 else
3619 goto exit_frame;
3622 CHECK_CHILD_EX (child_frame, ip - 2);
3624 * a constructor returns void, but we need to return the object we created
3626 array_constructed:
3627 if (newobj_class->valuetype && !newobj_class->enumtype) {
3628 *sp = valuetype_this;
3629 } else if (newobj_class == mono_defaults.string_class) {
3630 *sp = retval;
3631 } else {
3632 sp->data.p = o;
3634 ++sp;
3635 MINT_IN_BREAK;
3637 MINT_IN_CASE(MINT_NEWOBJ_MAGIC) {
3638 guint32 token;
3640 frame->ip = ip;
3641 token = * (guint16 *)(ip + 1);
3642 ip += 2;
3644 MINT_IN_BREAK;
3646 MINT_IN_CASE(MINT_CASTCLASS)
3647 c = rtm->data_items [*(guint16 *)(ip + 1)];
3648 if ((o = sp [-1].data.p)) {
3649 MonoObject *isinst_obj = mono_object_isinst_checked (o, c, error);
3650 mono_error_cleanup (error); /* FIXME: don't swallow the error */
3651 if (!isinst_obj)
3652 THROW_EX (mono_get_exception_invalid_cast (), ip);
3654 ip += 2;
3655 MINT_IN_BREAK;
3656 MINT_IN_CASE(MINT_ISINST)
3657 c = rtm->data_items [*(guint16 *)(ip + 1)];
3658 if ((o = sp [-1].data.p)) {
3659 MonoObject *isinst_obj = mono_object_isinst_checked (o, c, error);
3660 mono_error_cleanup (error); /* FIXME: don't swallow the error */
3661 if (!isinst_obj)
3662 sp [-1].data.p = NULL;
3664 ip += 2;
3665 MINT_IN_BREAK;
3666 MINT_IN_CASE(MINT_CONV_R_UN_I4)
3667 sp [-1].data.f = (double)(guint32)sp [-1].data.i;
3668 ++ip;
3669 MINT_IN_BREAK;
3670 MINT_IN_CASE(MINT_CONV_R_UN_I8)
3671 sp [-1].data.f = (double)(guint64)sp [-1].data.l;
3672 ++ip;
3673 MINT_IN_BREAK;
3674 MINT_IN_CASE(MINT_UNBOX)
3675 c = rtm->data_items[*(guint16 *)(ip + 1)];
3677 o = sp [-1].data.p;
3678 if (!o)
3679 THROW_EX (mono_get_exception_null_reference (), ip);
3681 MonoObject *isinst_obj = mono_object_isinst_checked (o, c, error);
3682 mono_error_cleanup (error); /* FIXME: don't swallow the error */
3683 if (!(isinst_obj || ((o->vtable->klass->rank == 0) && (o->vtable->klass->element_class == c->element_class))))
3684 THROW_EX (mono_get_exception_invalid_cast (), ip);
3686 sp [-1].data.p = mono_object_unbox (o);
3687 ip += 2;
3688 MINT_IN_BREAK;
3689 MINT_IN_CASE(MINT_THROW)
3690 --sp;
3691 frame->ex_handler = NULL;
3692 if (!sp->data.p)
3693 sp->data.p = mono_get_exception_null_reference ();
3695 THROW_EX ((MonoException *)sp->data.p, ip);
3696 MINT_IN_BREAK;
3697 MINT_IN_CASE(MINT_LDFLDA_UNSAFE)
3698 o = sp [-1].data.p;
3699 sp[-1].data.p = (char *)o + * (guint16 *)(ip + 1);
3700 ip += 2;
3701 MINT_IN_BREAK;
3702 MINT_IN_CASE(MINT_LDFLDA)
3703 o = sp [-1].data.p;
3704 if (!o)
3705 THROW_EX (mono_get_exception_null_reference (), ip);
3706 sp[-1].data.p = (char *)o + * (guint16 *)(ip + 1);
3707 ip += 2;
3708 MINT_IN_BREAK;
3709 MINT_IN_CASE(MINT_CKNULL)
3710 o = sp [-1].data.p;
3711 if (!o)
3712 THROW_EX (mono_get_exception_null_reference (), ip);
3713 ++ip;
3714 MINT_IN_BREAK;
3715 MINT_IN_CASE(MINT_CKNULL_N) {
3716 /* Same as CKNULL, but further down the stack */
3717 int n = *(guint16*)(ip + 1);
3718 o = sp [-n].data.p;
3719 if (!o)
3720 THROW_EX (mono_get_exception_null_reference (), ip);
3721 ip += 2;
3722 MINT_IN_BREAK;
3725 #define LDFLD(datamem, fieldtype) \
3726 o = sp [-1].data.p; \
3727 if (!o) \
3728 THROW_EX (mono_get_exception_null_reference (), ip); \
3729 sp[-1].data.datamem = * (fieldtype *)((char *)o + * (guint16 *)(ip + 1)) ; \
3730 ip += 2;
3732 MINT_IN_CASE(MINT_LDFLD_I1) LDFLD(i, gint8); MINT_IN_BREAK;
3733 MINT_IN_CASE(MINT_LDFLD_U1) LDFLD(i, guint8); MINT_IN_BREAK;
3734 MINT_IN_CASE(MINT_LDFLD_I2) LDFLD(i, gint16); MINT_IN_BREAK;
3735 MINT_IN_CASE(MINT_LDFLD_U2) LDFLD(i, guint16); MINT_IN_BREAK;
3736 MINT_IN_CASE(MINT_LDFLD_I4) LDFLD(i, gint32); MINT_IN_BREAK;
3737 MINT_IN_CASE(MINT_LDFLD_I8) LDFLD(l, gint64); MINT_IN_BREAK;
3738 MINT_IN_CASE(MINT_LDFLD_R4) LDFLD(f, float); MINT_IN_BREAK;
3739 MINT_IN_CASE(MINT_LDFLD_R8) LDFLD(f, double); MINT_IN_BREAK;
3740 MINT_IN_CASE(MINT_LDFLD_O) LDFLD(p, gpointer); MINT_IN_BREAK;
3741 MINT_IN_CASE(MINT_LDFLD_P) LDFLD(p, gpointer); MINT_IN_BREAK;
3743 MINT_IN_CASE(MINT_LDFLD_VT)
3744 o = sp [-1].data.p;
3745 if (!o)
3746 THROW_EX (mono_get_exception_null_reference (), ip);
3748 MonoClassField *field = rtm->data_items[* (guint16 *)(ip + 2)];
3749 MonoClass *klass = mono_class_from_mono_type (field->type);
3750 i32 = mono_class_value_size (klass, NULL);
3752 sp [-1].data.p = vt_sp;
3753 memcpy (sp [-1].data.p, (char *)o + * (guint16 *)(ip + 1), i32);
3754 vt_sp += (i32 + 7) & ~7;
3755 ip += 3;
3756 MINT_IN_BREAK;
3758 MINT_IN_CASE(MINT_LDRMFLD) {
3759 gpointer tmp;
3760 MonoClassField *field;
3761 char *addr;
3763 o = sp [-1].data.p;
3764 if (!o)
3765 THROW_EX (mono_get_exception_null_reference (), ip);
3766 field = rtm->data_items[* (guint16 *)(ip + 1)];
3767 ip += 2;
3768 #ifndef DISABLE_REMOTING
3769 if (mono_object_is_transparent_proxy (o)) {
3770 MonoClass *klass = ((MonoTransparentProxy*)o)->remote_class->proxy_class;
3772 addr = mono_load_remote_field_checked (o, klass, field, &tmp, error);
3773 mono_error_cleanup (error); /* FIXME: don't swallow the error */
3774 } else
3775 #endif
3776 addr = (char*)o + field->offset;
3778 stackval_from_data (field->type, &sp [-1], addr, FALSE);
3779 MINT_IN_BREAK;
3782 MINT_IN_CASE(MINT_LDRMFLD_VT) {
3783 MonoClassField *field;
3784 char *addr;
3785 gpointer tmp;
3787 o = sp [-1].data.p;
3788 if (!o)
3789 THROW_EX (mono_get_exception_null_reference (), ip);
3791 field = rtm->data_items[* (guint16 *)(ip + 1)];
3792 MonoClass *klass = mono_class_from_mono_type (field->type);
3793 i32 = mono_class_value_size (klass, NULL);
3795 ip += 2;
3796 #ifndef DISABLE_REMOTING
3797 if (mono_object_is_transparent_proxy (o)) {
3798 MonoClass *klass = ((MonoTransparentProxy*)o)->remote_class->proxy_class;
3799 addr = mono_load_remote_field_checked (o, klass, field, &tmp, error);
3800 mono_error_cleanup (error); /* FIXME: don't swallow the error */
3801 } else
3802 #endif
3803 addr = (char*)o + field->offset;
3805 sp [-1].data.p = vt_sp;
3806 memcpy(sp [-1].data.p, (char *)o + * (guint16 *)(ip + 1), i32);
3807 vt_sp += (i32 + 7) & ~7;
3808 memcpy(sp [-1].data.p, addr, i32);
3809 MINT_IN_BREAK;
3812 #define STFLD(datamem, fieldtype) \
3813 o = sp [-2].data.p; \
3814 if (!o) \
3815 THROW_EX (mono_get_exception_null_reference (), ip); \
3816 sp -= 2; \
3817 * (fieldtype *)((char *)o + * (guint16 *)(ip + 1)) = sp[1].data.datamem; \
3818 ip += 2;
3820 MINT_IN_CASE(MINT_STFLD_I1) STFLD(i, gint8); MINT_IN_BREAK;
3821 MINT_IN_CASE(MINT_STFLD_U1) STFLD(i, guint8); MINT_IN_BREAK;
3822 MINT_IN_CASE(MINT_STFLD_I2) STFLD(i, gint16); MINT_IN_BREAK;
3823 MINT_IN_CASE(MINT_STFLD_U2) STFLD(i, guint16); MINT_IN_BREAK;
3824 MINT_IN_CASE(MINT_STFLD_I4) STFLD(i, gint32); MINT_IN_BREAK;
3825 MINT_IN_CASE(MINT_STFLD_I8) STFLD(l, gint64); MINT_IN_BREAK;
3826 MINT_IN_CASE(MINT_STFLD_R4) STFLD(f, float); MINT_IN_BREAK;
3827 MINT_IN_CASE(MINT_STFLD_R8) STFLD(f, double); MINT_IN_BREAK;
3828 MINT_IN_CASE(MINT_STFLD_P) STFLD(p, gpointer); MINT_IN_BREAK;
3829 MINT_IN_CASE(MINT_STFLD_O)
3830 o = sp [-2].data.p;
3831 if (!o)
3832 THROW_EX (mono_get_exception_null_reference (), ip);
3833 sp -= 2;
3834 mono_gc_wbarrier_set_field (o, (char *) o + * (guint16 *)(ip + 1), sp [1].data.p);
3835 ip += 2;
3836 MINT_IN_BREAK;
3838 MINT_IN_CASE(MINT_STFLD_VT) {
3839 o = sp [-2].data.p;
3840 if (!o)
3841 THROW_EX (mono_get_exception_null_reference (), ip);
3842 sp -= 2;
3844 MonoClassField *field = rtm->data_items[* (guint16 *)(ip + 2)];
3845 MonoClass *klass = mono_class_from_mono_type (field->type);
3846 i32 = mono_class_value_size (klass, NULL);
3848 guint16 offset = * (guint16 *)(ip + 1);
3849 mono_value_copy ((char *) o + offset, sp [1].data.p, klass);
3851 vt_sp -= (i32 + 7) & ~7;
3852 ip += 3;
3853 MINT_IN_BREAK;
3855 MINT_IN_CASE(MINT_STRMFLD) {
3856 MonoClassField *field;
3858 o = sp [-2].data.p;
3859 if (!o)
3860 THROW_EX (mono_get_exception_null_reference (), ip);
3862 field = rtm->data_items[* (guint16 *)(ip + 1)];
3863 ip += 2;
3865 #ifndef DISABLE_REMOTING
3866 if (mono_object_is_transparent_proxy (o)) {
3867 MonoClass *klass = ((MonoTransparentProxy*)o)->remote_class->proxy_class;
3868 mono_store_remote_field_checked (o, klass, field, &sp [-1].data, error);
3869 mono_error_cleanup (error); /* FIXME: don't swallow the error */
3870 } else
3871 #endif
3872 stackval_to_data (field->type, &sp [-1], (char*)o + field->offset, FALSE);
3874 sp -= 2;
3875 MINT_IN_BREAK;
3877 MINT_IN_CASE(MINT_STRMFLD_VT) {
3878 MonoClassField *field;
3880 o = sp [-2].data.p;
3881 if (!o)
3882 THROW_EX (mono_get_exception_null_reference (), ip);
3883 field = rtm->data_items[* (guint16 *)(ip + 1)];
3884 MonoClass *klass = mono_class_from_mono_type (field->type);
3885 i32 = mono_class_value_size (klass, NULL);
3886 ip += 2;
3888 #ifndef DISABLE_REMOTING
3889 if (mono_object_is_transparent_proxy (o)) {
3890 MonoClass *klass = ((MonoTransparentProxy*)o)->remote_class->proxy_class;
3891 mono_store_remote_field_checked (o, klass, field, &sp [-1].data, error);
3892 mono_error_cleanup (error); /* FIXME: don't swallow the error */
3893 } else
3894 #endif
3895 mono_value_copy ((char *) o + field->offset, sp [-1].data.p, klass);
3897 sp -= 2;
3898 vt_sp -= (i32 + 7) & ~7;
3899 MINT_IN_BREAK;
3901 MINT_IN_CASE(MINT_LDSFLDA) {
3902 MonoClassField *field = rtm->data_items[*(guint16 *)(ip + 1)];
3903 sp->data.p = mono_class_static_field_address (rtm->domain, field);
3904 EXCEPTION_CHECKPOINT;
3905 ip += 2;
3906 ++sp;
3907 MINT_IN_BREAK;
3909 MINT_IN_CASE(MINT_LDSFLD) {
3910 MonoClassField *field = rtm->data_items [* (guint16 *)(ip + 1)];
3911 gpointer addr = mono_class_static_field_address (rtm->domain, field);
3912 EXCEPTION_CHECKPOINT;
3913 stackval_from_data (field->type, sp, addr, FALSE);
3914 ip += 2;
3915 ++sp;
3916 MINT_IN_BREAK;
3918 MINT_IN_CASE(MINT_LDSFLD_VT) {
3919 MonoClassField *field = rtm->data_items [* (guint16 *)(ip + 1)];
3920 gpointer addr = mono_class_static_field_address (rtm->domain, field);
3921 EXCEPTION_CHECKPOINT;
3922 int size = READ32 (ip + 2);
3923 ip += 4;
3925 sp->data.p = vt_sp;
3926 vt_sp += (size + 7) & ~7;
3927 stackval_from_data (field->type, sp, addr, FALSE);
3928 ++sp;
3929 MINT_IN_BREAK;
3931 MINT_IN_CASE(MINT_STSFLD) {
3932 MonoClassField *field = rtm->data_items [* (guint16 *)(ip + 1)];
3933 gpointer addr = mono_class_static_field_address (rtm->domain, field);
3934 EXCEPTION_CHECKPOINT;
3935 ip += 2;
3936 --sp;
3937 stackval_to_data (field->type, sp, addr, FALSE);
3938 MINT_IN_BREAK;
3940 MINT_IN_CASE(MINT_STSFLD_VT) {
3941 MonoClassField *field = rtm->data_items [* (guint16 *)(ip + 1)];
3942 gpointer addr = mono_class_static_field_address (rtm->domain, field);
3943 EXCEPTION_CHECKPOINT;
3944 MonoClass *klass = mono_class_from_mono_type (field->type);
3945 i32 = mono_class_value_size (klass, NULL);
3946 ip += 2;
3948 --sp;
3949 stackval_to_data (field->type, sp, addr, FALSE);
3950 vt_sp -= (i32 + 7) & ~7;
3951 MINT_IN_BREAK;
3953 MINT_IN_CASE(MINT_STOBJ_VT) {
3954 int size;
3955 c = rtm->data_items[* (guint16 *)(ip + 1)];
3956 ip += 2;
3957 size = mono_class_value_size (c, NULL);
3958 memcpy(sp [-2].data.p, sp [-1].data.p, size);
3959 vt_sp -= (size + 7) & ~7;
3960 sp -= 2;
3961 MINT_IN_BREAK;
3963 MINT_IN_CASE(MINT_STOBJ) {
3964 c = rtm->data_items[* (guint16 *)(ip + 1)];
3965 ip += 2;
3967 g_assert (!c->byval_arg.byref);
3968 if (MONO_TYPE_IS_REFERENCE (&c->byval_arg))
3969 mono_gc_wbarrier_generic_store (sp [-2].data.p, sp [-1].data.p);
3970 else
3971 stackval_from_data (&c->byval_arg, sp [-2].data.p, (char *) &sp [-1].data.p, FALSE);
3972 sp -= 2;
3973 MINT_IN_BREAK;
3975 MINT_IN_CASE(MINT_CONV_OVF_I4_UN_R8)
3976 if (sp [-1].data.f < 0 || sp [-1].data.f > MYGUINT32_MAX)
3977 THROW_EX (mono_get_exception_overflow (), ip);
3978 sp [-1].data.i = (guint32)sp [-1].data.f;
3979 ++ip;
3980 MINT_IN_BREAK;
3981 MINT_IN_CASE(MINT_CONV_OVF_U8_I4)
3982 if (sp [-1].data.i < 0)
3983 THROW_EX (mono_get_exception_overflow (), ip);
3984 sp [-1].data.l = sp [-1].data.i;
3985 ++ip;
3986 MINT_IN_BREAK;
3987 MINT_IN_CASE(MINT_CONV_OVF_U8_I8)
3988 if (sp [-1].data.l < 0)
3989 THROW_EX (mono_get_exception_overflow (), ip);
3990 ++ip;
3991 MINT_IN_BREAK;
3992 MINT_IN_CASE(MINT_CONV_OVF_I8_U8)
3993 if ((guint64) sp [-1].data.l > MYGINT64_MAX)
3994 THROW_EX (mono_get_exception_overflow (), ip);
3995 ++ip;
3996 MINT_IN_BREAK;
3997 MINT_IN_CASE(MINT_CONV_OVF_U8_R8)
3998 MINT_IN_CASE(MINT_CONV_OVF_I8_UN_R8)
3999 if (sp [-1].data.f < 0 || sp [-1].data.f > MYGINT64_MAX)
4000 THROW_EX (mono_get_exception_overflow (), ip);
4001 sp [-1].data.l = (guint64)sp [-1].data.f;
4002 ++ip;
4003 MINT_IN_BREAK;
4004 MINT_IN_CASE(MINT_CONV_OVF_I8_R8)
4005 if (sp [-1].data.f < MYGINT64_MIN || sp [-1].data.f > MYGINT64_MAX)
4006 THROW_EX (mono_get_exception_overflow (), ip);
4007 sp [-1].data.l = (gint64)sp [-1].data.f;
4008 ++ip;
4009 MINT_IN_BREAK;
4010 MINT_IN_CASE(MINT_CONV_OVF_I4_UN_I8)
4011 if ((mono_u)sp [-1].data.l > MYGUINT32_MAX)
4012 THROW_EX (mono_get_exception_overflow (), ip);
4013 sp [-1].data.i = (mono_u)sp [-1].data.l;
4014 ++ip;
4015 MINT_IN_BREAK;
4016 MINT_IN_CASE(MINT_BOX) {
4017 c = rtm->data_items [* (guint16 *)(ip + 1)];
4018 guint16 offset = * (guint16 *)(ip + 2);
4019 gboolean pop_vt_sp = !(offset & BOX_NOT_CLEAR_VT_SP);
4020 offset &= ~BOX_NOT_CLEAR_VT_SP;
4022 if (mint_type (&c->byval_arg) == MINT_TYPE_VT && !c->enumtype && !(mono_class_is_magic_int (c) || mono_class_is_magic_float (c))) {
4023 int size = mono_class_value_size (c, NULL);
4024 sp [-1 - offset].data.p = mono_value_box_checked (rtm->domain, c, sp [-1 - offset].data.p, error);
4025 mono_error_cleanup (error); /* FIXME: don't swallow the error */
4026 size = (size + 7) & ~7;
4027 if (pop_vt_sp)
4028 vt_sp -= size;
4029 } else {
4030 stackval_to_data (&c->byval_arg, &sp [-1 - offset], (char *) &sp [-1 - offset], FALSE);
4031 sp [-1 - offset].data.p = mono_value_box_checked (rtm->domain, c, &sp [-1 - offset], error);
4032 mono_error_cleanup (error); /* FIXME: don't swallow the error */
4034 ip += 3;
4035 MINT_IN_BREAK;
4037 MINT_IN_CASE(MINT_NEWARR)
4038 sp [-1].data.p = (MonoObject*) mono_array_new_checked (rtm->domain, rtm->data_items[*(guint16 *)(ip + 1)], sp [-1].data.i, error);
4039 if (!mono_error_ok (error)) {
4040 THROW_EX (mono_error_convert_to_exception (error), ip);
4042 mono_error_cleanup (error); /* FIXME: don't swallow the error */
4043 ip += 2;
4044 /*if (profiling_classes) {
4045 guint count = GPOINTER_TO_UINT (g_hash_table_lookup (profiling_classes, o->vtable->klass));
4046 count++;
4047 g_hash_table_insert (profiling_classes, o->vtable->klass, GUINT_TO_POINTER (count));
4050 MINT_IN_BREAK;
4051 MINT_IN_CASE(MINT_LDLEN)
4052 o = sp [-1].data.p;
4053 if (!o)
4054 THROW_EX (mono_get_exception_null_reference (), ip);
4055 sp [-1].data.nati = mono_array_length ((MonoArray *)o);
4056 ++ip;
4057 MINT_IN_BREAK;
4058 MINT_IN_CASE(MINT_GETCHR) {
4059 MonoString *s;
4060 s = sp [-2].data.p;
4061 if (!s)
4062 THROW_EX (mono_get_exception_null_reference (), ip);
4063 i32 = sp [-1].data.i;
4064 if (i32 < 0 || i32 >= mono_string_length (s))
4065 THROW_EX (mono_get_exception_index_out_of_range (), ip);
4066 --sp;
4067 sp [-1].data.i = mono_string_chars(s)[i32];
4068 ++ip;
4069 MINT_IN_BREAK;
4071 MINT_IN_CASE(MINT_STRLEN)
4072 ++ip;
4073 o = sp [-1].data.p;
4074 if (!o)
4075 THROW_EX (mono_get_exception_null_reference (), ip);
4076 sp [-1].data.i = mono_string_length ((MonoString*) o);
4077 MINT_IN_BREAK;
4078 MINT_IN_CASE(MINT_ARRAY_RANK)
4079 o = sp [-1].data.p;
4080 if (!o)
4081 THROW_EX (mono_get_exception_null_reference (), ip);
4082 sp [-1].data.i = mono_object_class (sp [-1].data.p)->rank;
4083 ip++;
4084 MINT_IN_BREAK;
4085 MINT_IN_CASE(MINT_LDELEMA)
4086 MINT_IN_CASE(MINT_LDELEMA_TC) {
4087 gboolean needs_typecheck = *ip == MINT_LDELEMA_TC;
4089 MonoClass *klass = rtm->data_items [*(guint16 *) (ip + 1)];
4090 guint16 numargs = *(guint16 *) (ip + 2);
4091 ip += 3;
4092 sp -= numargs;
4094 o = sp [0].data.p;
4095 sp->data.p = ves_array_element_address (frame, klass, (MonoArray *) o, &sp [1], needs_typecheck);
4096 if (frame->ex)
4097 THROW_EX (frame->ex, ip);
4098 ++sp;
4100 MINT_IN_BREAK;
4102 MINT_IN_CASE(MINT_LDELEM_I1) /* fall through */
4103 MINT_IN_CASE(MINT_LDELEM_U1) /* fall through */
4104 MINT_IN_CASE(MINT_LDELEM_I2) /* fall through */
4105 MINT_IN_CASE(MINT_LDELEM_U2) /* fall through */
4106 MINT_IN_CASE(MINT_LDELEM_I4) /* fall through */
4107 MINT_IN_CASE(MINT_LDELEM_U4) /* fall through */
4108 MINT_IN_CASE(MINT_LDELEM_I8) /* fall through */
4109 MINT_IN_CASE(MINT_LDELEM_I) /* fall through */
4110 MINT_IN_CASE(MINT_LDELEM_R4) /* fall through */
4111 MINT_IN_CASE(MINT_LDELEM_R8) /* fall through */
4112 MINT_IN_CASE(MINT_LDELEM_REF) /* fall through */
4113 MINT_IN_CASE(MINT_LDELEM_VT) {
4114 MonoArray *o;
4115 mono_u aindex;
4117 sp -= 2;
4119 o = sp [0].data.p;
4120 if (!o)
4121 THROW_EX (mono_get_exception_null_reference (), ip);
4123 aindex = sp [1].data.i;
4124 if (aindex >= mono_array_length (o))
4125 THROW_EX (mono_get_exception_index_out_of_range (), ip);
4128 * FIXME: throw mono_get_exception_array_type_mismatch () if needed
4130 switch (*ip) {
4131 case MINT_LDELEM_I1:
4132 sp [0].data.i = mono_array_get (o, gint8, aindex);
4133 break;
4134 case MINT_LDELEM_U1:
4135 sp [0].data.i = mono_array_get (o, guint8, aindex);
4136 break;
4137 case MINT_LDELEM_I2:
4138 sp [0].data.i = mono_array_get (o, gint16, aindex);
4139 break;
4140 case MINT_LDELEM_U2:
4141 sp [0].data.i = mono_array_get (o, guint16, aindex);
4142 break;
4143 case MINT_LDELEM_I:
4144 sp [0].data.nati = mono_array_get (o, mono_i, aindex);
4145 break;
4146 case MINT_LDELEM_I4:
4147 sp [0].data.i = mono_array_get (o, gint32, aindex);
4148 break;
4149 case MINT_LDELEM_U4:
4150 sp [0].data.i = mono_array_get (o, guint32, aindex);
4151 break;
4152 case MINT_LDELEM_I8:
4153 sp [0].data.l = mono_array_get (o, guint64, aindex);
4154 break;
4155 case MINT_LDELEM_R4:
4156 sp [0].data.f = mono_array_get (o, float, aindex);
4157 break;
4158 case MINT_LDELEM_R8:
4159 sp [0].data.f = mono_array_get (o, double, aindex);
4160 break;
4161 case MINT_LDELEM_REF:
4162 sp [0].data.p = mono_array_get (o, gpointer, aindex);
4163 break;
4164 case MINT_LDELEM_VT: {
4165 MonoClass *klass_vt = rtm->data_items [*(guint16 *) (ip + 1)];
4166 i32 = READ32 (ip + 2);
4167 char *src_addr = mono_array_addr_with_size ((MonoArray *) o, i32, aindex);
4168 sp [0].data.vt = vt_sp;
4169 stackval_from_data (&klass_vt->byval_arg, sp, src_addr, FALSE);
4170 vt_sp += (i32 + 7) & ~7;
4171 ip += 3;
4172 break;
4174 default:
4175 ves_abort();
4178 ++ip;
4179 ++sp;
4180 MINT_IN_BREAK;
4182 MINT_IN_CASE(MINT_STELEM_I) /* fall through */
4183 MINT_IN_CASE(MINT_STELEM_I1) /* fall through */
4184 MINT_IN_CASE(MINT_STELEM_U1) /* fall through */
4185 MINT_IN_CASE(MINT_STELEM_I2) /* fall through */
4186 MINT_IN_CASE(MINT_STELEM_U2) /* fall through */
4187 MINT_IN_CASE(MINT_STELEM_I4) /* fall through */
4188 MINT_IN_CASE(MINT_STELEM_I8) /* fall through */
4189 MINT_IN_CASE(MINT_STELEM_R4) /* fall through */
4190 MINT_IN_CASE(MINT_STELEM_R8) /* fall through */
4191 MINT_IN_CASE(MINT_STELEM_REF) /* fall through */
4192 MINT_IN_CASE(MINT_STELEM_VT) {
4193 mono_u aindex;
4195 sp -= 3;
4197 o = sp [0].data.p;
4198 if (!o)
4199 THROW_EX (mono_get_exception_null_reference (), ip);
4201 aindex = sp [1].data.i;
4202 if (aindex >= mono_array_length ((MonoArray *)o))
4203 THROW_EX (mono_get_exception_index_out_of_range (), ip);
4205 switch (*ip) {
4206 case MINT_STELEM_I:
4207 mono_array_set ((MonoArray *)o, mono_i, aindex, sp [2].data.nati);
4208 break;
4209 case MINT_STELEM_I1:
4210 mono_array_set ((MonoArray *)o, gint8, aindex, sp [2].data.i);
4211 break;
4212 case MINT_STELEM_U1:
4213 mono_array_set ((MonoArray *) o, guint8, aindex, sp [2].data.i);
4214 break;
4215 case MINT_STELEM_I2:
4216 mono_array_set ((MonoArray *)o, gint16, aindex, sp [2].data.i);
4217 break;
4218 case MINT_STELEM_U2:
4219 mono_array_set ((MonoArray *)o, guint16, aindex, sp [2].data.i);
4220 break;
4221 case MINT_STELEM_I4:
4222 mono_array_set ((MonoArray *)o, gint32, aindex, sp [2].data.i);
4223 break;
4224 case MINT_STELEM_I8:
4225 mono_array_set ((MonoArray *)o, gint64, aindex, sp [2].data.l);
4226 break;
4227 case MINT_STELEM_R4:
4228 mono_array_set ((MonoArray *)o, float, aindex, sp [2].data.f);
4229 break;
4230 case MINT_STELEM_R8:
4231 mono_array_set ((MonoArray *)o, double, aindex, sp [2].data.f);
4232 break;
4233 case MINT_STELEM_REF: {
4234 MonoObject *isinst_obj = mono_object_isinst_checked (sp [2].data.p, mono_object_class (o)->element_class, error);
4235 mono_error_cleanup (error); /* FIXME: don't swallow the error */
4236 if (sp [2].data.p && !isinst_obj)
4237 THROW_EX (mono_get_exception_array_type_mismatch (), ip);
4238 mono_array_setref ((MonoArray *) o, aindex, sp [2].data.p);
4239 break;
4241 case MINT_STELEM_VT: {
4242 MonoClass *klass_vt = rtm->data_items [*(guint16 *) (ip + 1)];
4243 i32 = READ32 (ip + 2);
4244 char *dst_addr = mono_array_addr_with_size ((MonoArray *) o, i32, aindex);
4246 stackval_to_data (&klass_vt->byval_arg, &sp [2], dst_addr, FALSE);
4247 vt_sp -= (i32 + 7) & ~7;
4248 ip += 3;
4249 break;
4251 default:
4252 ves_abort();
4255 ++ip;
4256 MINT_IN_BREAK;
4258 MINT_IN_CASE(MINT_CONV_OVF_I4_U4)
4259 if (sp [-1].data.i < 0)
4260 THROW_EX (mono_get_exception_overflow (), ip);
4261 ++ip;
4262 MINT_IN_BREAK;
4263 MINT_IN_CASE(MINT_CONV_OVF_I4_I8)
4264 if (sp [-1].data.l < MYGINT32_MIN || sp [-1].data.l > MYGINT32_MAX)
4265 THROW_EX (mono_get_exception_overflow (), ip);
4266 sp [-1].data.i = (gint32) sp [-1].data.l;
4267 ++ip;
4268 MINT_IN_BREAK;
4269 MINT_IN_CASE(MINT_CONV_OVF_I4_U8)
4270 if (sp [-1].data.l < 0 || sp [-1].data.l > MYGINT32_MAX)
4271 THROW_EX (mono_get_exception_overflow (), ip);
4272 sp [-1].data.i = (gint32) sp [-1].data.l;
4273 ++ip;
4274 MINT_IN_BREAK;
4275 MINT_IN_CASE(MINT_CONV_OVF_I4_R8)
4276 if (sp [-1].data.f < MYGINT32_MIN || sp [-1].data.f > MYGINT32_MAX)
4277 THROW_EX (mono_get_exception_overflow (), ip);
4278 sp [-1].data.i = (gint32) sp [-1].data.f;
4279 ++ip;
4280 MINT_IN_BREAK;
4281 MINT_IN_CASE(MINT_CONV_OVF_U4_I4)
4282 if (sp [-1].data.i < 0)
4283 THROW_EX (mono_get_exception_overflow (), ip);
4284 ++ip;
4285 MINT_IN_BREAK;
4286 MINT_IN_CASE(MINT_CONV_OVF_U4_I8)
4287 if (sp [-1].data.l < 0 || sp [-1].data.l > MYGUINT32_MAX)
4288 THROW_EX (mono_get_exception_overflow (), ip);
4289 sp [-1].data.i = (guint32) sp [-1].data.l;
4290 ++ip;
4291 MINT_IN_BREAK;
4292 MINT_IN_CASE(MINT_CONV_OVF_U4_R8)
4293 if (sp [-1].data.f < 0 || sp [-1].data.f > MYGUINT32_MAX)
4294 THROW_EX (mono_get_exception_overflow (), ip);
4295 sp [-1].data.i = (guint32) sp [-1].data.f;
4296 ++ip;
4297 MINT_IN_BREAK;
4298 MINT_IN_CASE(MINT_CONV_OVF_I2_I4)
4299 if (sp [-1].data.i < -32768 || sp [-1].data.i > 32767)
4300 THROW_EX (mono_get_exception_overflow (), ip);
4301 ++ip;
4302 MINT_IN_BREAK;
4303 MINT_IN_CASE(MINT_CONV_OVF_I2_I8)
4304 if (sp [-1].data.l < -32768 || sp [-1].data.l > 32767)
4305 THROW_EX (mono_get_exception_overflow (), ip);
4306 sp [-1].data.i = (gint16) sp [-1].data.l;
4307 ++ip;
4308 MINT_IN_BREAK;
4309 MINT_IN_CASE(MINT_CONV_OVF_I2_R8)
4310 if (sp [-1].data.f < -32768 || sp [-1].data.f > 32767)
4311 THROW_EX (mono_get_exception_overflow (), ip);
4312 sp [-1].data.i = (gint16) sp [-1].data.f;
4313 ++ip;
4314 MINT_IN_BREAK;
4315 MINT_IN_CASE(MINT_CONV_OVF_U2_I4)
4316 if (sp [-1].data.i < 0 || sp [-1].data.i > 65535)
4317 THROW_EX (mono_get_exception_overflow (), ip);
4318 ++ip;
4319 MINT_IN_BREAK;
4320 MINT_IN_CASE(MINT_CONV_OVF_U2_I8)
4321 if (sp [-1].data.l < 0 || sp [-1].data.l > 65535)
4322 THROW_EX (mono_get_exception_overflow (), ip);
4323 sp [-1].data.i = (guint16) sp [-1].data.l;
4324 ++ip;
4325 MINT_IN_BREAK;
4326 MINT_IN_CASE(MINT_CONV_OVF_U2_R8)
4327 if (sp [-1].data.f < 0 || sp [-1].data.f > 65535)
4328 THROW_EX (mono_get_exception_overflow (), ip);
4329 sp [-1].data.i = (guint16) sp [-1].data.f;
4330 ++ip;
4331 MINT_IN_BREAK;
4332 MINT_IN_CASE(MINT_CONV_OVF_I1_I4)
4333 if (sp [-1].data.i < -128 || sp [-1].data.i > 127)
4334 THROW_EX (mono_get_exception_overflow (), ip);
4335 ++ip;
4336 MINT_IN_BREAK;
4337 MINT_IN_CASE(MINT_CONV_OVF_I1_I8)
4338 if (sp [-1].data.l < -128 || sp [-1].data.l > 127)
4339 THROW_EX (mono_get_exception_overflow (), ip);
4340 sp [-1].data.i = (gint8) sp [-1].data.l;
4341 ++ip;
4342 MINT_IN_BREAK;
4343 MINT_IN_CASE(MINT_CONV_OVF_I1_R8)
4344 if (sp [-1].data.f < -128 || sp [-1].data.f > 127)
4345 THROW_EX (mono_get_exception_overflow (), ip);
4346 sp [-1].data.i = (gint8) sp [-1].data.f;
4347 ++ip;
4348 MINT_IN_BREAK;
4349 MINT_IN_CASE(MINT_CONV_OVF_U1_I4)
4350 if (sp [-1].data.i < 0 || sp [-1].data.i > 255)
4351 THROW_EX (mono_get_exception_overflow (), ip);
4352 ++ip;
4353 MINT_IN_BREAK;
4354 MINT_IN_CASE(MINT_CONV_OVF_U1_I8)
4355 if (sp [-1].data.l < 0 || sp [-1].data.l > 255)
4356 THROW_EX (mono_get_exception_overflow (), ip);
4357 sp [-1].data.i = (guint8) sp [-1].data.l;
4358 ++ip;
4359 MINT_IN_BREAK;
4360 MINT_IN_CASE(MINT_CONV_OVF_U1_R8)
4361 if (sp [-1].data.f < 0 || sp [-1].data.f > 255)
4362 THROW_EX (mono_get_exception_overflow (), ip);
4363 sp [-1].data.i = (guint8) sp [-1].data.f;
4364 ++ip;
4365 MINT_IN_BREAK;
4366 #if 0
4367 MINT_IN_CASE(MINT_LDELEM)
4368 MINT_IN_CASE(MINT_STELEM)
4369 MINT_IN_CASE(MINT_UNBOX_ANY)
4370 #endif
4371 MINT_IN_CASE(MINT_CKFINITE)
4372 if (!isfinite(sp [-1].data.f))
4373 THROW_EX (mono_get_exception_arithmetic (), ip);
4374 ++ip;
4375 MINT_IN_BREAK;
4376 MINT_IN_CASE(MINT_MKREFANY) {
4377 c = rtm->data_items [*(guint16 *)(ip + 1)];
4379 /* The value address is on the stack */
4380 gpointer addr = sp [-1].data.p;
4381 /* Push the typedref value on the stack */
4382 sp [-1].data.p = vt_sp;
4383 vt_sp += sizeof (MonoTypedRef);
4385 MonoTypedRef *tref = sp [-1].data.p;
4386 tref->klass = c;
4387 tref->type = &c->byval_arg;
4388 tref->value = addr;
4390 ip += 2;
4391 MINT_IN_BREAK;
4393 MINT_IN_CASE(MINT_REFANYTYPE) {
4394 MonoTypedRef *tref = sp [-1].data.p;
4395 MonoType *type = tref->type;
4397 vt_sp -= sizeof (MonoTypedRef);
4398 sp [-1].data.p = vt_sp;
4399 vt_sp += 8;
4400 *(gpointer*)sp [-1].data.p = type;
4401 ip ++;
4402 MINT_IN_BREAK;
4404 MINT_IN_CASE(MINT_REFANYVAL) {
4405 MonoTypedRef *tref = sp [-1].data.p;
4406 gpointer addr = tref->value;
4408 vt_sp -= sizeof (MonoTypedRef);
4410 sp [-1].data.p = addr;
4411 ip ++;
4412 MINT_IN_BREAK;
4414 MINT_IN_CASE(MINT_LDTOKEN)
4415 sp->data.p = vt_sp;
4416 vt_sp += 8;
4417 * (gpointer *)sp->data.p = rtm->data_items[*(guint16 *)(ip + 1)];
4418 ip += 2;
4419 ++sp;
4420 MINT_IN_BREAK;
4421 MINT_IN_CASE(MINT_ADD_OVF_I4)
4422 if (CHECK_ADD_OVERFLOW (sp [-2].data.i, sp [-1].data.i))
4423 THROW_EX (mono_get_exception_overflow (), ip);
4424 BINOP(i, +);
4425 MINT_IN_BREAK;
4426 MINT_IN_CASE(MINT_ADD_OVF_I8)
4427 if (CHECK_ADD_OVERFLOW64 (sp [-2].data.l, sp [-1].data.l))
4428 THROW_EX (mono_get_exception_overflow (), ip);
4429 BINOP(l, +);
4430 MINT_IN_BREAK;
4431 MINT_IN_CASE(MINT_ADD_OVF_UN_I4)
4432 if (CHECK_ADD_OVERFLOW_UN (sp [-2].data.i, sp [-1].data.i))
4433 THROW_EX (mono_get_exception_overflow (), ip);
4434 BINOP_CAST(i, +, guint32);
4435 MINT_IN_BREAK;
4436 MINT_IN_CASE(MINT_ADD_OVF_UN_I8)
4437 if (CHECK_ADD_OVERFLOW64_UN (sp [-2].data.l, sp [-1].data.l))
4438 THROW_EX (mono_get_exception_overflow (), ip);
4439 BINOP_CAST(l, +, guint64);
4440 MINT_IN_BREAK;
4441 MINT_IN_CASE(MINT_MUL_OVF_I4)
4442 if (CHECK_MUL_OVERFLOW (sp [-2].data.i, sp [-1].data.i))
4443 THROW_EX (mono_get_exception_overflow (), ip);
4444 BINOP(i, *);
4445 MINT_IN_BREAK;
4446 MINT_IN_CASE(MINT_MUL_OVF_I8)
4447 if (CHECK_MUL_OVERFLOW64 (sp [-2].data.l, sp [-1].data.l))
4448 THROW_EX (mono_get_exception_overflow (), ip);
4449 BINOP(l, *);
4450 MINT_IN_BREAK;
4451 MINT_IN_CASE(MINT_MUL_OVF_UN_I4)
4452 if (CHECK_MUL_OVERFLOW_UN (sp [-2].data.i, sp [-1].data.i))
4453 THROW_EX (mono_get_exception_overflow (), ip);
4454 BINOP_CAST(i, *, guint32);
4455 MINT_IN_BREAK;
4456 MINT_IN_CASE(MINT_MUL_OVF_UN_I8)
4457 if (CHECK_MUL_OVERFLOW64_UN (sp [-2].data.l, sp [-1].data.l))
4458 THROW_EX (mono_get_exception_overflow (), ip);
4459 BINOP_CAST(l, *, guint64);
4460 MINT_IN_BREAK;
4461 MINT_IN_CASE(MINT_SUB_OVF_I4)
4462 if (CHECK_SUB_OVERFLOW (sp [-2].data.i, sp [-1].data.i))
4463 THROW_EX (mono_get_exception_overflow (), ip);
4464 BINOP(i, -);
4465 MINT_IN_BREAK;
4466 MINT_IN_CASE(MINT_SUB_OVF_I8)
4467 if (CHECK_SUB_OVERFLOW64 (sp [-2].data.l, sp [-1].data.l))
4468 THROW_EX (mono_get_exception_overflow (), ip);
4469 BINOP(l, -);
4470 MINT_IN_BREAK;
4471 MINT_IN_CASE(MINT_SUB_OVF_UN_I4)
4472 if (CHECK_SUB_OVERFLOW_UN (sp [-2].data.i, sp [-1].data.i))
4473 THROW_EX (mono_get_exception_overflow (), ip);
4474 BINOP_CAST(i, -, guint32);
4475 MINT_IN_BREAK;
4476 MINT_IN_CASE(MINT_SUB_OVF_UN_I8)
4477 if (CHECK_SUB_OVERFLOW64_UN (sp [-2].data.l, sp [-1].data.l))
4478 THROW_EX (mono_get_exception_overflow (), ip);
4479 BINOP_CAST(l, -, guint64);
4480 MINT_IN_BREAK;
4481 MINT_IN_CASE(MINT_START_ABORT_PROT)
4482 mono_threads_begin_abort_protected_block ();
4483 ip ++;
4484 MINT_IN_BREAK;
4485 MINT_IN_CASE(MINT_END_ABORT_PROT)
4486 /* FIXME We miss it if exception is thrown in finally clause */
4487 mono_threads_end_abort_protected_block ();
4488 ip ++;
4489 MINT_IN_BREAK;
4490 MINT_IN_CASE(MINT_ENDFINALLY)
4491 ip ++;
4492 int clause_index = *ip;
4493 if (clause_index == exit_at_finally)
4494 goto exit_frame;
4495 while (sp > frame->stack) {
4496 --sp;
4498 if (finally_ips) {
4499 ip = finally_ips->data;
4500 finally_ips = g_slist_remove (finally_ips, ip);
4501 goto main_loop;
4503 if (frame->ex)
4504 goto handle_catch;
4505 ves_abort();
4506 MINT_IN_BREAK;
4507 MINT_IN_CASE(MINT_LEAVE) /* Fall through */
4508 MINT_IN_CASE(MINT_LEAVE_S)
4509 while (sp > frame->stack) {
4510 --sp;
4512 frame->ip = ip;
4514 if (*ip == MINT_LEAVE_S) {
4515 ip += (short) *(ip + 1);
4516 } else {
4517 ip += (gint32) READ32 (ip + 1);
4519 endfinally_ip = ip;
4520 goto handle_finally;
4521 MINT_IN_BREAK;
4522 MINT_IN_CASE(MINT_LEAVE_CHECK)
4523 MINT_IN_CASE(MINT_LEAVE_S_CHECK)
4524 while (sp > frame->stack) {
4525 --sp;
4527 frame->ip = ip;
4529 if (frame->ex_handler != NULL && MONO_OFFSET_IN_HANDLER(frame->ex_handler, frame->ip - rtm->code)) {
4530 frame->ex_handler = NULL;
4531 frame->ex = NULL;
4534 if (frame->imethod->method->wrapper_type != MONO_WRAPPER_RUNTIME_INVOKE) {
4535 stackval tmp_sp;
4537 child_frame.parent = frame;
4538 child_frame.imethod = NULL;
4540 * We need for mono_thread_get_undeniable_exception to be able to unwind
4541 * to check the abort threshold. For this to work we use child_frame as a
4542 * dummy frame that is stored in the lmf and serves as the transition frame
4544 context->current_frame = &child_frame;
4545 do_icall (context, MINT_ICALL_V_P, &tmp_sp, mono_thread_get_undeniable_exception);
4546 context->current_frame = frame;
4548 MonoException *abort_exc = (MonoException*)tmp_sp.data.p;
4549 if (abort_exc)
4550 THROW_EX (abort_exc, frame->ip);
4553 if (*ip == MINT_LEAVE_S_CHECK) {
4554 ip += (short) *(ip + 1);
4555 } else {
4556 ip += (gint32) READ32 (ip + 1);
4558 endfinally_ip = ip;
4559 goto handle_finally;
4560 MINT_IN_BREAK;
4561 MINT_IN_CASE(MINT_ICALL_V_V)
4562 MINT_IN_CASE(MINT_ICALL_V_P)
4563 MINT_IN_CASE(MINT_ICALL_P_V)
4564 MINT_IN_CASE(MINT_ICALL_P_P)
4565 MINT_IN_CASE(MINT_ICALL_PP_V)
4566 MINT_IN_CASE(MINT_ICALL_PI_V)
4567 MINT_IN_CASE(MINT_ICALL_PP_P)
4568 MINT_IN_CASE(MINT_ICALL_PI_P)
4569 MINT_IN_CASE(MINT_ICALL_PPP_V)
4570 MINT_IN_CASE(MINT_ICALL_PPI_V)
4571 MINT_IN_CASE(MINT_ICALL_PII_P)
4572 MINT_IN_CASE(MINT_ICALL_PPII_V)
4573 sp = do_icall (context, *ip, sp, rtm->data_items [*(guint16 *)(ip + 1)]);
4574 EXCEPTION_CHECKPOINT;
4575 if (context->has_resume_state) {
4576 if (frame == context->handler_frame)
4577 SET_RESUME_STATE (context);
4578 else
4579 goto exit_frame;
4581 ip += 2;
4582 MINT_IN_BREAK;
4583 MINT_IN_CASE(MINT_MONO_LDPTR)
4584 sp->data.p = rtm->data_items [*(guint16 *)(ip + 1)];
4585 ip += 2;
4586 ++sp;
4587 MINT_IN_BREAK;
4588 MINT_IN_CASE(MINT_MONO_NEWOBJ)
4589 sp->data.p = mono_object_new_checked (rtm->domain, rtm->data_items [*(guint16 *)(ip + 1)], error);
4590 mono_error_cleanup (error); /* FIXME: don't swallow the error */
4591 ip += 2;
4592 sp++;
4593 MINT_IN_BREAK;
4594 MINT_IN_CASE(MINT_MONO_FREE)
4595 ++ip;
4596 --sp;
4597 g_error ("that doesn't seem right");
4598 g_free (sp->data.p);
4599 MINT_IN_BREAK;
4600 MINT_IN_CASE(MINT_MONO_RETOBJ)
4601 ++ip;
4602 sp--;
4603 stackval_from_data (mono_method_signature (frame->imethod->method)->ret, frame->retval, sp->data.p,
4604 mono_method_signature (frame->imethod->method)->pinvoke);
4605 if (sp > frame->stack)
4606 g_warning ("retobj: more values on stack: %d", sp-frame->stack);
4607 goto exit_frame;
4608 MINT_IN_CASE(MINT_MONO_TLS) {
4609 MonoTlsKey key = *(gint32 *)(ip + 1);
4610 sp->data.p = ((gpointer (*)(void)) mono_tls_get_tls_getter (key, FALSE)) ();
4611 sp++;
4612 ip += 3;
4613 MINT_IN_BREAK;
4615 MINT_IN_CASE(MINT_MONO_MEMORY_BARRIER) {
4616 ++ip;
4617 mono_memory_barrier ();
4618 MINT_IN_BREAK;
4620 MINT_IN_CASE(MINT_MONO_JIT_ATTACH) {
4621 ++ip;
4623 context->original_domain = NULL;
4624 MonoDomain *tls_domain = (MonoDomain *) ((gpointer (*)(void)) mono_tls_get_tls_getter (TLS_KEY_DOMAIN, FALSE)) ();
4625 gpointer tls_jit = ((gpointer (*)(void)) mono_tls_get_tls_getter (TLS_KEY_JIT_TLS, FALSE)) ();
4627 if (tls_domain != rtm->domain || !tls_jit)
4628 context->original_domain = mono_jit_thread_attach (rtm->domain);
4629 MINT_IN_BREAK;
4631 MINT_IN_CASE(MINT_MONO_JIT_DETACH)
4632 ++ip;
4633 mono_jit_set_domain (context->original_domain);
4634 MINT_IN_BREAK;
4635 MINT_IN_CASE(MINT_MONO_LDDOMAIN)
4636 sp->data.p = mono_domain_get ();
4637 ++sp;
4638 ++ip;
4639 MINT_IN_BREAK;
4640 MINT_IN_CASE(MINT_SDB_INTR_LOC)
4641 if (G_UNLIKELY (ss_enabled)) {
4642 static void (*ss_tramp) (void);
4644 if (!ss_tramp) {
4645 void *tramp = mini_get_single_step_trampoline ();
4646 mono_memory_barrier ();
4647 ss_tramp = tramp;
4651 * Make this point to the MINT_SDB_SEQ_POINT instruction which follows this since
4652 * the address of that instruction is stored as the seq point address.
4654 frame->ip = ip + 1;
4657 * Use the same trampoline as the JIT. This ensures that
4658 * the debugger has the context for the last interpreter
4659 * native frame.
4661 do_debugger_tramp (ss_tramp, frame);
4663 if (context->has_resume_state) {
4664 if (frame == context->handler_frame)
4665 SET_RESUME_STATE (context);
4666 else
4667 goto exit_frame;
4670 ++ip;
4671 MINT_IN_BREAK;
4672 MINT_IN_CASE(MINT_SDB_SEQ_POINT)
4673 /* Just a placeholder for a breakpoint */
4674 ++ip;
4675 MINT_IN_BREAK;
4676 MINT_IN_CASE(MINT_SDB_BREAKPOINT) {
4677 static void (*bp_tramp) (void);
4678 if (!bp_tramp) {
4679 void *tramp = mini_get_breakpoint_trampoline ();
4680 mono_memory_barrier ();
4681 bp_tramp = tramp;
4684 frame->ip = ip;
4686 /* Use the same trampoline as the JIT */
4687 do_debugger_tramp (bp_tramp, frame);
4689 if (context->has_resume_state) {
4690 if (frame == context->handler_frame)
4691 SET_RESUME_STATE (context);
4692 else
4693 goto exit_frame;
4696 ++ip;
4697 MINT_IN_BREAK;
4700 #define RELOP(datamem, op) \
4701 --sp; \
4702 sp [-1].data.i = sp [-1].data.datamem op sp [0].data.datamem; \
4703 ++ip;
4705 #define RELOP_FP(datamem, op, noorder) \
4706 --sp; \
4707 if (isunordered (sp [-1].data.datamem, sp [0].data.datamem)) \
4708 sp [-1].data.i = noorder; \
4709 else \
4710 sp [-1].data.i = sp [-1].data.datamem op sp [0].data.datamem; \
4711 ++ip;
4713 MINT_IN_CASE(MINT_CEQ_I4)
4714 RELOP(i, ==);
4715 MINT_IN_BREAK;
4716 MINT_IN_CASE(MINT_CEQ0_I4)
4717 sp [-1].data.i = (sp [-1].data.i == 0);
4718 ++ip;
4719 MINT_IN_BREAK;
4720 MINT_IN_CASE(MINT_CEQ_I8)
4721 RELOP(l, ==);
4722 MINT_IN_BREAK;
4723 MINT_IN_CASE(MINT_CEQ_R8)
4724 RELOP_FP(f, ==, 0);
4725 MINT_IN_BREAK;
4726 MINT_IN_CASE(MINT_CNE_I4)
4727 RELOP(i, !=);
4728 MINT_IN_BREAK;
4729 MINT_IN_CASE(MINT_CNE_I8)
4730 RELOP(l, !=);
4731 MINT_IN_BREAK;
4732 MINT_IN_CASE(MINT_CNE_R8)
4733 RELOP_FP(f, !=, 0);
4734 MINT_IN_BREAK;
4735 MINT_IN_CASE(MINT_CGT_I4)
4736 RELOP(i, >);
4737 MINT_IN_BREAK;
4738 MINT_IN_CASE(MINT_CGT_I8)
4739 RELOP(l, >);
4740 MINT_IN_BREAK;
4741 MINT_IN_CASE(MINT_CGT_R8)
4742 RELOP_FP(f, >, 0);
4743 MINT_IN_BREAK;
4744 MINT_IN_CASE(MINT_CGE_I4)
4745 RELOP(i, >=);
4746 MINT_IN_BREAK;
4747 MINT_IN_CASE(MINT_CGE_I8)
4748 RELOP(l, >=);
4749 MINT_IN_BREAK;
4750 MINT_IN_CASE(MINT_CGE_R8)
4751 RELOP_FP(f, >=, 0);
4752 MINT_IN_BREAK;
4754 #define RELOP_CAST(datamem, op, type) \
4755 --sp; \
4756 sp [-1].data.i = (type)sp [-1].data.datamem op (type)sp [0].data.datamem; \
4757 ++ip;
4759 MINT_IN_CASE(MINT_CGE_UN_I4)
4760 RELOP_CAST(l, >=, guint32);
4761 MINT_IN_BREAK;
4762 MINT_IN_CASE(MINT_CGE_UN_I8)
4763 RELOP_CAST(l, >=, guint64);
4764 MINT_IN_BREAK;
4766 MINT_IN_CASE(MINT_CGT_UN_I4)
4767 RELOP_CAST(i, >, guint32);
4768 MINT_IN_BREAK;
4769 MINT_IN_CASE(MINT_CGT_UN_I8)
4770 RELOP_CAST(l, >, guint64);
4771 MINT_IN_BREAK;
4772 MINT_IN_CASE(MINT_CGT_UN_R8)
4773 RELOP_FP(f, >, 1);
4774 MINT_IN_BREAK;
4775 MINT_IN_CASE(MINT_CLT_I4)
4776 RELOP(i, <);
4777 MINT_IN_BREAK;
4778 MINT_IN_CASE(MINT_CLT_I8)
4779 RELOP(l, <);
4780 MINT_IN_BREAK;
4781 MINT_IN_CASE(MINT_CLT_R8)
4782 RELOP_FP(f, <, 0);
4783 MINT_IN_BREAK;
4784 MINT_IN_CASE(MINT_CLT_UN_I4)
4785 RELOP_CAST(i, <, guint32);
4786 MINT_IN_BREAK;
4787 MINT_IN_CASE(MINT_CLT_UN_I8)
4788 RELOP_CAST(l, <, guint64);
4789 MINT_IN_BREAK;
4790 MINT_IN_CASE(MINT_CLT_UN_R8)
4791 RELOP_FP(f, <, 1);
4792 MINT_IN_BREAK;
4793 MINT_IN_CASE(MINT_CLE_I4)
4794 RELOP(i, <=);
4795 MINT_IN_BREAK;
4796 MINT_IN_CASE(MINT_CLE_I8)
4797 RELOP(l, <=);
4798 MINT_IN_BREAK;
4799 MINT_IN_CASE(MINT_CLE_UN_I4)
4800 RELOP_CAST(l, <=, guint32);
4801 MINT_IN_BREAK;
4802 MINT_IN_CASE(MINT_CLE_UN_I8)
4803 RELOP_CAST(l, <=, guint64);
4804 MINT_IN_BREAK;
4805 MINT_IN_CASE(MINT_CLE_R8)
4806 RELOP_FP(f, <=, 0);
4807 MINT_IN_BREAK;
4809 #undef RELOP
4810 #undef RELOP_FP
4811 #undef RELOP_CAST
4813 MINT_IN_CASE(MINT_LDFTN) {
4814 sp->data.p = rtm->data_items [* (guint16 *)(ip + 1)];
4815 ++sp;
4816 ip += 2;
4817 MINT_IN_BREAK;
4819 MINT_IN_CASE(MINT_LDVIRTFTN) {
4820 InterpMethod *m = rtm->data_items [* (guint16 *)(ip + 1)];
4821 ip += 2;
4822 --sp;
4823 if (!sp->data.p)
4824 THROW_EX (mono_get_exception_null_reference (), ip - 2);
4826 sp->data.p = get_virtual_method (m, sp->data.p);
4827 ++sp;
4828 MINT_IN_BREAK;
4831 #define LDARG(datamem, argtype) \
4832 sp->data.datamem = * (argtype *)(frame->args + * (guint16 *)(ip + 1)); \
4833 ip += 2; \
4834 ++sp;
4836 MINT_IN_CASE(MINT_LDARG_I1) LDARG(i, gint8); MINT_IN_BREAK;
4837 MINT_IN_CASE(MINT_LDARG_U1) LDARG(i, guint8); MINT_IN_BREAK;
4838 MINT_IN_CASE(MINT_LDARG_I2) LDARG(i, gint16); MINT_IN_BREAK;
4839 MINT_IN_CASE(MINT_LDARG_U2) LDARG(i, guint16); MINT_IN_BREAK;
4840 MINT_IN_CASE(MINT_LDARG_I4) LDARG(i, gint32); MINT_IN_BREAK;
4841 MINT_IN_CASE(MINT_LDARG_I8) LDARG(l, gint64); MINT_IN_BREAK;
4842 MINT_IN_CASE(MINT_LDARG_R4) LDARG(f, float); MINT_IN_BREAK;
4843 MINT_IN_CASE(MINT_LDARG_R8) LDARG(f, double); MINT_IN_BREAK;
4844 MINT_IN_CASE(MINT_LDARG_O) LDARG(p, gpointer); MINT_IN_BREAK;
4845 MINT_IN_CASE(MINT_LDARG_P) LDARG(p, gpointer); MINT_IN_BREAK;
4847 MINT_IN_CASE(MINT_LDARG_VT)
4848 sp->data.p = vt_sp;
4849 i32 = READ32(ip + 2);
4850 memcpy(sp->data.p, frame->args + * (guint16 *)(ip + 1), i32);
4851 vt_sp += (i32 + 7) & ~7;
4852 ip += 4;
4853 ++sp;
4854 MINT_IN_BREAK;
4856 #define STARG(datamem, argtype) \
4857 --sp; \
4858 * (argtype *)(frame->args + * (guint16 *)(ip + 1)) = sp->data.datamem; \
4859 ip += 2; \
4861 MINT_IN_CASE(MINT_STARG_I1) STARG(i, gint8); MINT_IN_BREAK;
4862 MINT_IN_CASE(MINT_STARG_U1) STARG(i, guint8); MINT_IN_BREAK;
4863 MINT_IN_CASE(MINT_STARG_I2) STARG(i, gint16); MINT_IN_BREAK;
4864 MINT_IN_CASE(MINT_STARG_U2) STARG(i, guint16); MINT_IN_BREAK;
4865 MINT_IN_CASE(MINT_STARG_I4) STARG(i, gint32); MINT_IN_BREAK;
4866 MINT_IN_CASE(MINT_STARG_I8) STARG(l, gint64); MINT_IN_BREAK;
4867 MINT_IN_CASE(MINT_STARG_R4) STARG(f, float); MINT_IN_BREAK;
4868 MINT_IN_CASE(MINT_STARG_R8) STARG(f, double); MINT_IN_BREAK;
4869 MINT_IN_CASE(MINT_STARG_O) STARG(p, gpointer); MINT_IN_BREAK;
4870 MINT_IN_CASE(MINT_STARG_P) STARG(p, gpointer); MINT_IN_BREAK;
4872 MINT_IN_CASE(MINT_STARG_VT)
4873 i32 = READ32(ip + 2);
4874 --sp;
4875 memcpy(frame->args + * (guint16 *)(ip + 1), sp->data.p, i32);
4876 vt_sp -= (i32 + 7) & ~7;
4877 ip += 4;
4878 MINT_IN_BREAK;
4880 #define STINARG(datamem, argtype) \
4881 do { \
4882 int n = * (guint16 *)(ip + 1); \
4883 * (argtype *)(frame->args + rtm->arg_offsets [n]) = frame->stack_args [n].data.datamem; \
4884 ip += 2; \
4885 } while (0)
4887 MINT_IN_CASE(MINT_STINARG_I1) STINARG(i, gint8); MINT_IN_BREAK;
4888 MINT_IN_CASE(MINT_STINARG_U1) STINARG(i, guint8); MINT_IN_BREAK;
4889 MINT_IN_CASE(MINT_STINARG_I2) STINARG(i, gint16); MINT_IN_BREAK;
4890 MINT_IN_CASE(MINT_STINARG_U2) STINARG(i, guint16); MINT_IN_BREAK;
4891 MINT_IN_CASE(MINT_STINARG_I4) STINARG(i, gint32); MINT_IN_BREAK;
4892 MINT_IN_CASE(MINT_STINARG_I8) STINARG(l, gint64); MINT_IN_BREAK;
4893 MINT_IN_CASE(MINT_STINARG_R4) STINARG(f, float); MINT_IN_BREAK;
4894 MINT_IN_CASE(MINT_STINARG_R8) STINARG(f, double); MINT_IN_BREAK;
4895 MINT_IN_CASE(MINT_STINARG_O) STINARG(p, gpointer); MINT_IN_BREAK;
4896 MINT_IN_CASE(MINT_STINARG_P) STINARG(p, gpointer); MINT_IN_BREAK;
4898 MINT_IN_CASE(MINT_STINARG_VT) {
4899 int n = * (guint16 *)(ip + 1);
4900 i32 = READ32(ip + 2);
4901 memcpy (frame->args + rtm->arg_offsets [n], frame->stack_args [n].data.p, i32);
4902 ip += 4;
4903 MINT_IN_BREAK;
4906 MINT_IN_CASE(MINT_PROF_ENTER) {
4907 ip += 1;
4909 if (MONO_PROFILER_ENABLED (method_enter)) {
4910 MonoProfilerCallContext *prof_ctx = NULL;
4912 if (frame->imethod->prof_flags & MONO_PROFILER_CALL_INSTRUMENTATION_ENTER_CONTEXT) {
4913 prof_ctx = g_new0 (MonoProfilerCallContext, 1);
4914 prof_ctx->interp_frame = frame;
4915 prof_ctx->method = frame->imethod->method;
4918 MONO_PROFILER_RAISE (method_enter, (frame->imethod->method, prof_ctx));
4920 g_free (prof_ctx);
4923 MINT_IN_BREAK;
4926 MINT_IN_CASE(MINT_LDARGA)
4927 sp->data.p = frame->args + * (guint16 *)(ip + 1);
4928 ip += 2;
4929 ++sp;
4930 MINT_IN_BREAK;
4932 #define LDLOC(datamem, argtype) \
4933 sp->data.datamem = * (argtype *)(locals + * (guint16 *)(ip + 1)); \
4934 ip += 2; \
4935 ++sp;
4937 MINT_IN_CASE(MINT_LDLOC_I1) LDLOC(i, gint8); MINT_IN_BREAK;
4938 MINT_IN_CASE(MINT_LDLOC_U1) LDLOC(i, guint8); MINT_IN_BREAK;
4939 MINT_IN_CASE(MINT_LDLOC_I2) LDLOC(i, gint16); MINT_IN_BREAK;
4940 MINT_IN_CASE(MINT_LDLOC_U2) LDLOC(i, guint16); MINT_IN_BREAK;
4941 MINT_IN_CASE(MINT_LDLOC_I4) LDLOC(i, gint32); MINT_IN_BREAK;
4942 MINT_IN_CASE(MINT_LDLOC_I8) LDLOC(l, gint64); MINT_IN_BREAK;
4943 MINT_IN_CASE(MINT_LDLOC_R4) LDLOC(f, float); MINT_IN_BREAK;
4944 MINT_IN_CASE(MINT_LDLOC_R8) LDLOC(f, double); MINT_IN_BREAK;
4945 MINT_IN_CASE(MINT_LDLOC_O) LDLOC(p, gpointer); MINT_IN_BREAK;
4946 MINT_IN_CASE(MINT_LDLOC_P) LDLOC(p, gpointer); MINT_IN_BREAK;
4948 MINT_IN_CASE(MINT_LDLOC_VT)
4949 sp->data.p = vt_sp;
4950 i32 = READ32(ip + 2);
4951 memcpy(sp->data.p, locals + * (guint16 *)(ip + 1), i32);
4952 vt_sp += (i32 + 7) & ~7;
4953 ip += 4;
4954 ++sp;
4955 MINT_IN_BREAK;
4957 MINT_IN_CASE(MINT_LDLOCA_S)
4958 sp->data.p = locals + * (guint16 *)(ip + 1);
4959 ip += 2;
4960 ++sp;
4961 MINT_IN_BREAK;
4963 #define STLOC(datamem, argtype) \
4964 --sp; \
4965 * (argtype *)(locals + * (guint16 *)(ip + 1)) = sp->data.datamem; \
4966 ip += 2;
4968 MINT_IN_CASE(MINT_STLOC_I1) STLOC(i, gint8); MINT_IN_BREAK;
4969 MINT_IN_CASE(MINT_STLOC_U1) STLOC(i, guint8); MINT_IN_BREAK;
4970 MINT_IN_CASE(MINT_STLOC_I2) STLOC(i, gint16); MINT_IN_BREAK;
4971 MINT_IN_CASE(MINT_STLOC_U2) STLOC(i, guint16); MINT_IN_BREAK;
4972 MINT_IN_CASE(MINT_STLOC_I4) STLOC(i, gint32); MINT_IN_BREAK;
4973 MINT_IN_CASE(MINT_STLOC_I8) STLOC(l, gint64); MINT_IN_BREAK;
4974 MINT_IN_CASE(MINT_STLOC_R4) STLOC(f, float); MINT_IN_BREAK;
4975 MINT_IN_CASE(MINT_STLOC_R8) STLOC(f, double); MINT_IN_BREAK;
4976 MINT_IN_CASE(MINT_STLOC_O) STLOC(p, gpointer); MINT_IN_BREAK;
4977 MINT_IN_CASE(MINT_STLOC_P) STLOC(p, gpointer); MINT_IN_BREAK;
4979 #define STLOC_NP(datamem, argtype) \
4980 * (argtype *)(locals + * (guint16 *)(ip + 1)) = sp [-1].data.datamem; \
4981 ip += 2;
4983 MINT_IN_CASE(MINT_STLOC_NP_I4) STLOC_NP(i, gint32); MINT_IN_BREAK;
4984 MINT_IN_CASE(MINT_STLOC_NP_O) STLOC_NP(p, gpointer); MINT_IN_BREAK;
4986 MINT_IN_CASE(MINT_STLOC_VT)
4987 i32 = READ32(ip + 2);
4988 --sp;
4989 memcpy(locals + * (guint16 *)(ip + 1), sp->data.p, i32);
4990 vt_sp -= (i32 + 7) & ~7;
4991 ip += 4;
4992 MINT_IN_BREAK;
4994 MINT_IN_CASE(MINT_LOCALLOC) {
4995 if (sp != frame->stack + 1) /*FIX?*/
4996 THROW_EX (mono_get_exception_execution_engine (NULL), ip);
4998 int len = sp [-1].data.i;
4999 sp [-1].data.p = alloca (len);
5001 if (frame->imethod->init_locals)
5002 memset (sp [-1].data.p, 0, len);
5003 ++ip;
5004 MINT_IN_BREAK;
5006 MINT_IN_CASE(MINT_ENDFILTER)
5007 /* top of stack is result of filter */
5008 frame->retval = &sp [-1];
5009 goto exit_frame;
5010 MINT_IN_CASE(MINT_INITOBJ)
5011 --sp;
5012 memset (sp->data.vt, 0, READ32(ip + 1));
5013 ip += 3;
5014 MINT_IN_BREAK;
5015 MINT_IN_CASE(MINT_CPBLK)
5016 sp -= 3;
5017 if (!sp [0].data.p || !sp [1].data.p)
5018 THROW_EX (mono_get_exception_null_reference(), ip - 1);
5019 ++ip;
5020 /* FIXME: value and size may be int64... */
5021 memcpy (sp [0].data.p, sp [1].data.p, sp [2].data.i);
5022 MINT_IN_BREAK;
5023 #if 0
5024 MINT_IN_CASE(MINT_CONSTRAINED_) {
5025 guint32 token;
5026 /* FIXME: implement */
5027 ++ip;
5028 token = READ32 (ip);
5029 ip += 2;
5030 MINT_IN_BREAK;
5032 #endif
5033 MINT_IN_CASE(MINT_INITBLK)
5034 sp -= 3;
5035 if (!sp [0].data.p)
5036 THROW_EX (mono_get_exception_null_reference(), ip - 1);
5037 ++ip;
5038 /* FIXME: value and size may be int64... */
5039 memset (sp [0].data.p, sp [1].data.i, sp [2].data.i);
5040 MINT_IN_BREAK;
5041 #if 0
5042 MINT_IN_CASE(MINT_NO_)
5043 /* FIXME: implement */
5044 ip += 2;
5045 MINT_IN_BREAK;
5046 #endif
5047 MINT_IN_CASE(MINT_RETHROW) {
5049 * need to clarify what this should actually do:
5050 * start the search from the last found handler in
5051 * this method or continue in the caller or what.
5052 * Also, do we need to run finally/fault handlers after a retrow?
5053 * Well, this implementation will follow the usual search
5054 * for an handler, considering the current ip as throw spot.
5055 * We need to NULL frame->ex_handler for the later code to
5056 * actually run the new found handler.
5058 int exvar_offset = *(guint16*)(ip + 1);
5059 frame->ex_handler = NULL;
5060 THROW_EX_GENERAL (*(MonoException**)(frame->locals + exvar_offset), ip - 1, TRUE);
5061 MINT_IN_BREAK;
5063 MINT_IN_DEFAULT
5064 g_print ("Unimplemented opcode: %04x %s at 0x%x\n", *ip, mono_interp_opname[*ip], ip-rtm->code);
5065 THROW_EX (mono_get_exception_execution_engine ("Unimplemented opcode"), ip);
5069 g_assert_not_reached ();
5070 handle_finally:
5072 int i;
5073 guint32 ip_offset;
5074 MonoExceptionClause *clause;
5075 GSList *old_list = finally_ips;
5076 MonoMethod *method = frame->imethod->method;
5078 #if DEBUG_INTERP
5079 if (tracing)
5080 g_print ("* Handle finally IL_%04x\n", endfinally_ip == NULL ? 0 : endfinally_ip - rtm->code);
5081 #endif
5082 if (rtm == NULL || (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
5083 || (method->iflags & (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL | METHOD_IMPL_ATTRIBUTE_RUNTIME))) {
5084 goto exit_frame;
5086 ip_offset = frame->ip - rtm->code;
5088 if (endfinally_ip != NULL)
5089 finally_ips = g_slist_prepend(finally_ips, (void *)endfinally_ip);
5090 for (i = 0; i < rtm->num_clauses; ++i)
5091 if (frame->ex_handler == &rtm->clauses [i])
5092 break;
5094 while (i > 0) {
5095 --i;
5096 clause = &rtm->clauses [i];
5097 if (MONO_OFFSET_IN_CLAUSE (clause, ip_offset) && (endfinally_ip == NULL || !(MONO_OFFSET_IN_CLAUSE (clause, endfinally_ip - rtm->code)))) {
5098 if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY) {
5099 ip = rtm->code + clause->handler_offset;
5100 finally_ips = g_slist_prepend (finally_ips, (gpointer) ip);
5101 #if DEBUG_INTERP
5102 if (tracing)
5103 g_print ("* Found finally at IL_%04x with exception: %s\n", clause->handler_offset, frame->ex? "yes": "no");
5104 #endif
5109 endfinally_ip = NULL;
5111 if (old_list != finally_ips && finally_ips) {
5112 ip = finally_ips->data;
5113 finally_ips = g_slist_remove (finally_ips, ip);
5114 sp = frame->stack; /* spec says stack should be empty at endfinally so it should be at the start too */
5115 vt_sp = (unsigned char *) sp + rtm->stack_size;
5116 goto main_loop;
5120 * If an exception is set, we need to execute the fault handler, too,
5121 * otherwise, we continue normally.
5123 if (frame->ex)
5124 goto handle_fault;
5125 ves_abort();
5127 handle_fault:
5129 int i;
5130 guint32 ip_offset;
5131 MonoExceptionClause *clause;
5132 GSList *old_list = finally_ips;
5134 #if DEBUG_INTERP
5135 if (tracing)
5136 g_print ("* Handle fault\n");
5137 #endif
5138 ip_offset = frame->ip - rtm->code;
5140 for (i = 0; i < rtm->num_clauses; ++i) {
5141 clause = &rtm->clauses [i];
5142 if (clause->flags == MONO_EXCEPTION_CLAUSE_FAULT && MONO_OFFSET_IN_CLAUSE (clause, ip_offset)) {
5143 ip = rtm->code + clause->handler_offset;
5144 finally_ips = g_slist_prepend (finally_ips, (gpointer) ip);
5145 #if DEBUG_INTERP
5146 if (tracing)
5147 g_print ("* Executing handler at IL_%04x\n", clause->handler_offset);
5148 #endif
5152 if (old_list != finally_ips && finally_ips) {
5153 ip = finally_ips->data;
5154 finally_ips = g_slist_remove (finally_ips, ip);
5155 sp = frame->stack; /* spec says stack should be empty at endfinally so it should be at the start too */
5156 vt_sp = (unsigned char *) sp + rtm->stack_size;
5157 goto main_loop;
5160 handle_catch:
5163 * If the handler for the exception was found in this method, we jump
5164 * to it right away, otherwise we return and let the caller run
5165 * the finally, fault and catch blocks.
5166 * This same code should be present in the endfault opcode, but it
5167 * is corrently not assigned in the ECMA specs: LAMESPEC.
5169 if (frame->ex_handler) {
5170 #if DEBUG_INTERP
5171 if (tracing)
5172 g_print ("* Executing handler at IL_%04x\n", frame->ex_handler->handler_offset);
5173 #endif
5174 ip = rtm->code + frame->ex_handler->handler_offset;
5175 sp = frame->stack;
5176 vt_sp = (unsigned char *) sp + rtm->stack_size;
5177 sp->data.p = frame->ex;
5178 ++sp;
5179 goto main_loop;
5181 goto check_lmf;
5184 check_lmf:
5186 /* make sure we don't miss to pop a LMF */
5187 MonoLMF *lmf= mono_get_lmf ();
5188 if (lmf && (gsize) lmf->previous_lmf & 2) {
5189 MonoLMFExt *ext = (MonoLMFExt *) lmf;
5190 if (ext->interp_exit && ext->interp_exit_data == frame->parent)
5191 interp_pop_lmf (ext);
5195 exit_frame:
5197 if (base_frame)
5198 memcpy (base_frame->args, frame->args, rtm->alloca_size);
5200 if (!frame->ex && MONO_PROFILER_ENABLED (method_leave) &&
5201 frame->imethod->prof_flags & MONO_PROFILER_CALL_INSTRUMENTATION_LEAVE) {
5202 MonoProfilerCallContext *prof_ctx = NULL;
5204 if (frame->imethod->prof_flags & MONO_PROFILER_CALL_INSTRUMENTATION_LEAVE_CONTEXT) {
5205 prof_ctx = g_new0 (MonoProfilerCallContext, 1);
5206 prof_ctx->interp_frame = frame;
5207 prof_ctx->method = frame->imethod->method;
5209 MonoType *rtype = mono_method_signature (frame->imethod->method)->ret;
5211 switch (rtype->type) {
5212 case MONO_TYPE_VOID:
5213 break;
5214 case MONO_TYPE_VALUETYPE:
5215 prof_ctx->return_value = frame->retval->data.p;
5216 break;
5217 default:
5218 prof_ctx->return_value = frame->retval;
5219 break;
5223 MONO_PROFILER_RAISE (method_leave, (frame->imethod->method, prof_ctx));
5225 g_free (prof_ctx);
5226 } else if (frame->ex && frame->imethod->prof_flags & MONO_PROFILER_CALL_INSTRUMENTATION_EXCEPTION_LEAVE)
5227 MONO_PROFILER_RAISE (method_exception_leave, (frame->imethod->method, &frame->ex->object));
5229 DEBUG_LEAVE ();
5232 static void
5233 interp_exec_method (InterpFrame *frame, ThreadContext *context)
5235 interp_exec_method_full (frame, context, NULL, NULL, -1, NULL);
5238 static void
5239 interp_parse_options (const char *options)
5241 char **args, **ptr;
5243 if (!options)
5244 return;
5246 args = g_strsplit (options, ",", -1);
5247 for (ptr = args; ptr && *ptr; ptr ++) {
5248 char *arg = *ptr;
5250 if (strncmp (arg, "jit=", 4) == 0)
5251 jit_classes = g_slist_prepend (jit_classes, arg + 4);
5255 typedef int (*TestMethod) (void);
5258 * interp_set_resume_state:
5260 * Set the state the interpeter will continue to execute from after execution returns to the interpreter.
5262 static void
5263 interp_set_resume_state (MonoJitTlsData *jit_tls, MonoException *ex, MonoJitExceptionInfo *ei, MonoInterpFrameHandle interp_frame, gpointer handler_ip)
5265 ThreadContext *context;
5267 g_assert (jit_tls);
5268 context = jit_tls->interp_context;
5269 g_assert (context);
5271 context->has_resume_state = TRUE;
5272 context->handler_frame = interp_frame;
5273 /* This is on the stack, so it doesn't need a wbarrier */
5274 context->handler_frame->ex = ex;
5275 /* Ditto */
5276 if (ei)
5277 *(MonoException**)(context->handler_frame->locals + ei->exvar_offset) = ex;
5278 context->handler_ip = handler_ip;
5282 * interp_run_finally:
5284 * Run the finally clause identified by CLAUSE_INDEX in the intepreter frame given by
5285 * frame->interp_frame.
5286 * Return TRUE if the finally clause threw an exception.
5288 static gboolean
5289 interp_run_finally (StackFrameInfo *frame, int clause_index, gpointer handler_ip)
5291 InterpFrame *iframe = frame->interp_frame;
5292 ThreadContext *context = mono_native_tls_get_value (thread_context_id);
5294 interp_exec_method_full (iframe, context, handler_ip, NULL, clause_index, NULL);
5295 if (context->has_resume_state)
5296 return TRUE;
5297 else
5298 return FALSE;
5302 * interp_run_filter:
5304 * Run the filter clause identified by CLAUSE_INDEX in the intepreter frame given by
5305 * frame->interp_frame.
5307 static gboolean
5308 interp_run_filter (StackFrameInfo *frame, MonoException *ex, int clause_index, gpointer handler_ip)
5310 InterpFrame *iframe = frame->interp_frame;
5311 ThreadContext *context = mono_native_tls_get_value (thread_context_id);
5312 InterpFrame child_frame;
5313 stackval retval;
5316 * Have to run the clause in a new frame which is a copy of IFRAME, since
5317 * during debugging, there are two copies of the frame on the stack.
5319 memset (&child_frame, 0, sizeof (InterpFrame));
5320 child_frame.imethod = iframe->imethod;
5321 child_frame.retval = &retval;
5322 child_frame.parent = iframe;
5324 interp_exec_method_full (&child_frame, context, handler_ip, ex, clause_index, iframe);
5325 /* ENDFILTER stores the result into child_frame->retval */
5326 return child_frame.retval->data.i ? TRUE : FALSE;
5329 typedef struct {
5330 InterpFrame *current;
5331 } StackIter;
5334 * interp_frame_iter_init:
5336 * Initialize an iterator for iterating through interpreted frames.
5338 static void
5339 interp_frame_iter_init (MonoInterpStackIter *iter, gpointer interp_exit_data)
5341 StackIter *stack_iter = (StackIter*)iter;
5343 stack_iter->current = (InterpFrame*)interp_exit_data;
5347 * interp_frame_iter_next:
5349 * Fill out FRAME with date for the next interpreter frame.
5351 static gboolean
5352 interp_frame_iter_next (MonoInterpStackIter *iter, StackFrameInfo *frame)
5354 StackIter *stack_iter = (StackIter*)iter;
5355 InterpFrame *iframe = stack_iter->current;
5357 memset (frame, 0, sizeof (StackFrameInfo));
5358 /* pinvoke frames doesn't have imethod set */
5359 while (iframe && !(iframe->imethod && iframe->imethod->code && iframe->imethod->jinfo))
5360 iframe = iframe->parent;
5361 if (!iframe)
5362 return FALSE;
5364 frame->type = FRAME_TYPE_INTERP;
5365 frame->domain = iframe->domain;
5366 frame->interp_frame = iframe;
5367 frame->method = iframe->imethod->method;
5368 frame->actual_method = frame->method;
5369 /* This is the offset in the interpreter IR */
5370 frame->native_offset = (guint8*)iframe->ip - (guint8*)iframe->imethod->code;
5371 frame->ji = iframe->imethod->jinfo;
5372 frame->managed = TRUE;
5373 frame->frame_addr = iframe;
5375 stack_iter->current = iframe->parent;
5377 return TRUE;
5380 static MonoJitInfo*
5381 interp_find_jit_info (MonoDomain *domain, MonoMethod *method)
5383 InterpMethod* rtm;
5385 rtm = lookup_imethod (domain, method);
5386 if (rtm)
5387 return rtm->jinfo;
5388 else
5389 return NULL;
5392 static void
5393 interp_set_breakpoint (MonoJitInfo *jinfo, gpointer ip)
5395 guint16 *code = (guint16*)ip;
5396 g_assert (*code == MINT_SDB_SEQ_POINT);
5397 *code = MINT_SDB_BREAKPOINT;
5400 static void
5401 interp_clear_breakpoint (MonoJitInfo *jinfo, gpointer ip)
5403 guint16 *code = (guint16*)ip;
5404 g_assert (*code == MINT_SDB_BREAKPOINT);
5405 *code = MINT_SDB_SEQ_POINT;
5408 static MonoJitInfo*
5409 interp_frame_get_jit_info (MonoInterpFrameHandle frame)
5411 InterpFrame *iframe = (InterpFrame*)frame;
5413 g_assert (iframe->imethod);
5414 return iframe->imethod->jinfo;
5417 static gpointer
5418 interp_frame_get_ip (MonoInterpFrameHandle frame)
5420 InterpFrame *iframe = (InterpFrame*)frame;
5422 g_assert (iframe->imethod);
5423 return (gpointer)iframe->ip;
5426 static gpointer
5427 interp_frame_get_arg (MonoInterpFrameHandle frame, int pos)
5429 InterpFrame *iframe = (InterpFrame*)frame;
5431 g_assert (iframe->imethod);
5433 int arg_offset = iframe->imethod->arg_offsets [pos + (iframe->imethod->hasthis ? 1 : 0)];
5435 return iframe->args + arg_offset;
5438 static gpointer
5439 interp_frame_get_local (MonoInterpFrameHandle frame, int pos)
5441 InterpFrame *iframe = (InterpFrame*)frame;
5443 g_assert (iframe->imethod);
5445 return iframe->locals + iframe->imethod->local_offsets [pos];
5448 static gpointer
5449 interp_frame_get_this (MonoInterpFrameHandle frame)
5451 InterpFrame *iframe = (InterpFrame*)frame;
5453 g_assert (iframe->imethod);
5454 g_assert (iframe->imethod->hasthis);
5456 int arg_offset = iframe->imethod->arg_offsets [0];
5458 return iframe->args + arg_offset;
5461 static MonoInterpFrameHandle
5462 interp_frame_get_parent (MonoInterpFrameHandle frame)
5464 InterpFrame *iframe = (InterpFrame*)frame;
5466 return iframe->parent;
5469 static void
5470 interp_start_single_stepping (void)
5472 ss_enabled = TRUE;
5475 static void
5476 interp_stop_single_stepping (void)
5478 ss_enabled = FALSE;
5481 void
5482 mono_ee_interp_init (const char *opts)
5484 g_assert (mono_ee_api_version () == MONO_EE_API_VERSION);
5485 g_assert (!interp_init_done);
5486 interp_init_done = TRUE;
5488 mono_native_tls_alloc (&thread_context_id, NULL);
5489 set_context (NULL);
5491 interp_parse_options (opts);
5492 mono_interp_transform_init ();
5494 MonoEECallbacks c;
5495 c.create_method_pointer = interp_create_method_pointer;
5496 c.runtime_invoke = interp_runtime_invoke;
5497 c.init_delegate = interp_init_delegate;
5498 c.get_remoting_invoke = interp_get_remoting_invoke;
5499 c.create_trampoline = interp_create_trampoline;
5500 c.walk_stack_with_ctx = interp_walk_stack_with_ctx;
5501 c.set_resume_state = interp_set_resume_state;
5502 c.run_finally = interp_run_finally;
5503 c.run_filter = interp_run_filter;
5504 c.frame_iter_init = interp_frame_iter_init;
5505 c.frame_iter_next = interp_frame_iter_next;
5506 c.find_jit_info = interp_find_jit_info;
5507 c.set_breakpoint = interp_set_breakpoint;
5508 c.clear_breakpoint = interp_clear_breakpoint;
5509 c.frame_get_jit_info = interp_frame_get_jit_info;
5510 c.frame_get_ip = interp_frame_get_ip;
5511 c.frame_get_arg = interp_frame_get_arg;
5512 c.frame_get_local = interp_frame_get_local;
5513 c.frame_get_this = interp_frame_get_this;
5514 c.frame_get_parent = interp_frame_get_parent;
5515 c.frame_arg_to_data = interp_frame_arg_to_data;
5516 c.data_to_frame_arg = interp_data_to_frame_arg;
5517 c.frame_arg_to_storage = interp_frame_arg_to_storage;
5518 c.start_single_stepping = interp_start_single_stepping;
5519 c.stop_single_stepping = interp_stop_single_stepping;
5520 mini_install_interp_callbacks (&c);