From f9dcaa74a99e1000b28ae89ab56ece6727bd28c0 Mon Sep 17 00:00:00 2001 From: Bernhard Urban Date: Mon, 27 Feb 2017 17:55:55 +0100 Subject: [interpreter] rename interpreter to interp for folks without autocompletion :P --- mono/mini/.gitignore | 2 +- mono/mini/Makefile.am.in | 24 +- mono/mini/driver.c | 2 +- mono/mini/interp/hacks.h | 153 + mono/mini/interp/interp-internals.h | 124 + mono/mini/interp/interp.c | 4550 ++++++++++++++++++++++++++++++ mono/mini/interp/interp.h | 22 + mono/mini/interp/mintops.c | 120 + mono/mini/interp/mintops.def | 506 ++++ mono/mini/interp/mintops.h | 58 + mono/mini/interp/transform.c | 3382 ++++++++++++++++++++++ mono/mini/interpreter/hacks.h | 153 - mono/mini/interpreter/interp-internals.h | 124 - mono/mini/interpreter/interp.c | 4550 ------------------------------ mono/mini/interpreter/interp.h | 22 - mono/mini/interpreter/mintops.c | 120 - mono/mini/interpreter/mintops.def | 506 ---- mono/mini/interpreter/mintops.h | 58 - mono/mini/interpreter/transform.c | 3382 ---------------------- mono/mini/mini-exceptions.c | 2 +- mono/mini/mini-runtime.c | 2 +- 21 files changed, 8931 insertions(+), 8931 deletions(-) create mode 100644 mono/mini/interp/hacks.h create mode 100644 mono/mini/interp/interp-internals.h create mode 100644 mono/mini/interp/interp.c create mode 100644 mono/mini/interp/interp.h create mode 100644 mono/mini/interp/mintops.c create mode 100644 mono/mini/interp/mintops.def create mode 100644 mono/mini/interp/mintops.h create mode 100644 mono/mini/interp/transform.c delete mode 100644 mono/mini/interpreter/hacks.h delete mode 100644 mono/mini/interpreter/interp-internals.h delete mode 100644 mono/mini/interpreter/interp.c delete mode 100644 mono/mini/interpreter/interp.h delete mode 100644 mono/mini/interpreter/mintops.c delete mode 100644 mono/mini/interpreter/mintops.def delete mode 100644 mono/mini/interpreter/mintops.h delete mode 100644 mono/mini/interpreter/transform.c diff --git a/mono/mini/.gitignore b/mono/mini/.gitignore index f53010594c7..af434f4218a 100644 --- a/mono/mini/.gitignore +++ b/mono/mini/.gitignore @@ -8,7 +8,7 @@ /*.dll /*.mdb /*.lo -/interpreter/*.lo +/interp/*.lo /*.loT /*.la /.libs diff --git a/mono/mini/Makefile.am.in b/mono/mini/Makefile.am.in index e231385c8c8..1aa2808c3dc 100755 --- a/mono/mini/Makefile.am.in +++ b/mono/mini/Makefile.am.in @@ -43,7 +43,7 @@ RUNTIME_EXECUTABLE = $(if $(BOEHM),$(top_builddir)/mono/mini/mono-boehm,$(top_bu MINI_RUNTIME = MONO_PATH=$(CLASS) $(RUNTIME_EXECUTABLE) TOOLS_RUNTIME = MONO_PATH=$(mcs_topdir)/class/lib/build $(top_builddir)/runtime/mono-wrapper -INTERPRETER_RUNTIME = $(MINI_RUNTIME) --interpreter +INTERP_RUNTIME = $(MINI_RUNTIME) --interpreter RUNTIME_AOTCHECK = MONO_PATH="$(CLASS)$(PLATFORM_PATH_SEPARATOR)." $(RUNTIME_EXECUTABLE) MCS = CSC_SDK_PATH_DISABLED= $(TOOLS_RUNTIME) $(CSC) -unsafe -nowarn:0162 -nologo -noconfig -r:$(CLASS)/mscorlib.dll -r:$(CLASS)/System.dll -r:$(CLASS)/System.Core.dll @@ -388,15 +388,15 @@ endif endif if ENABLE_INTERPRETER -interpreter_sources = \ - interpreter/hacks.h \ - interpreter/interp.h \ - interpreter/interp-internals.h \ - interpreter/interp.c \ - interpreter/mintops.h \ - interpreter/mintops.def \ - interpreter/mintops.c \ - interpreter/transform.c +interp_sources = \ + interp/hacks.h \ + interp/interp.h \ + interp/interp-internals.h \ + interp/interp.c \ + interp/mintops.h \ + interp/mintops.def \ + interp/mintops.c \ + interp/transform.c endif if ENABLE_LLVM @@ -628,7 +628,7 @@ os_sources = $(darwin_sources) $(posix_sources) monobin_platform_ldflags=-framework CoreFoundation -framework Foundation endif -libmini_la_SOURCES = $(common_sources) $(llvm_sources) $(llvm_runtime_sources) $(interpreter_sources) $(arch_sources) $(os_sources) +libmini_la_SOURCES = $(common_sources) $(llvm_sources) $(llvm_runtime_sources) $(interp_sources) $(arch_sources) $(os_sources) libmini_la_CFLAGS = $(mono_CFLAGS) libmonoboehm_2_0_la_SOURCES = @@ -753,7 +753,7 @@ rcheck: mono $(regtests) $(MINI_RUNTIME) --regression $(regtests) richeck: mono $(iregtests) - $(INTERPRETER_RUNTIME) --regression $(iregtests) + $(INTERP_RUNTIME) --regression $(iregtests) if ARM check-seq-points: diff --git a/mono/mini/driver.c b/mono/mini/driver.c index 860e1ca626f..9674a350f90 100644 --- a/mono/mini/driver.c +++ b/mono/mini/driver.c @@ -56,7 +56,7 @@ #include "mini.h" #include "jit.h" #include "aot-compiler.h" -#include "interpreter/interp.h" +#include "interp/interp.h" #include #include diff --git a/mono/mini/interp/hacks.h b/mono/mini/interp/hacks.h new file mode 100644 index 00000000000..9697ccbad6f --- /dev/null +++ b/mono/mini/interp/hacks.h @@ -0,0 +1,153 @@ +/* we need some special math function */ +#ifndef _ISOC99_SOURCE +#define _ISOC99_SOURCE +#endif +#include + +/* which are not defined on FreeBSD */ +#ifdef __GNUC__ + +#ifndef isunordered +# define isunordered(u, v) \ + (__extension__ \ + ({ __typeof__(u) __u = (u); __typeof__(v) __v = (v); \ + isnan(__u) || isnan(__v); })) +#endif + +#ifndef islessgreater +# define islessgreater(x, u) \ + (__extension__ \ + ({ __typeof__(x) __x = (x); __typeof__(y) __y = (y); \ + !isunordered (__x, __y) && (__x < __y) || (__y < __x); })) +#endif + +#ifndef islessequal +# define islessequal(x, y) \ + (__extension__ \ + ({ __typeof__(x) __x = (x); __typeof__(y) __y = (y); \ + !isunordered(__x, __y) && __x <= __y; })) +#endif + +#ifndef isless +# define isless(x, y) \ + (__extension__ \ + ({ __typeof__(x) __x = (x); __typeof__(y) __y = (y); \ + !isunordered(__x, __y) && __x < __y; })) +#endif + +#ifndef isgreater +# define isgreater(x, y) \ + (__extension__ \ + ({ __typeof__(x) __x = (x); __typeof__(y) __y = (y); \ + !isunordered(__x, __y) && __x > __y; })) +#endif + +#else + +/* isunordered seems to crash on HPUX when built 64 bits + so use generic implementation. +*/ +#if defined(__hpux) && SIZEOF_VOID_P == 8 +#undef isunordered +#undef islessgreater +#undef islessequal +#undef isless +#undef isgreater +#endif + +#ifndef isunordered +# define isunordered(u, v) (isnan(u) || isnan(v)) +#endif + +#ifndef islessgreater +# define islessgreater(x, u) (!isunordered (x, y) && (x < y) || (y < x)) +#endif + +#ifndef islessequal +# define islessequal(x, y) (!isunordered(x, y) && x <= y) +#endif + +#ifndef isless +# define isless(x, y) (!isunordered(x, y) && x < y) +#endif + +#ifndef isgreater +# define isgreater(x, y) (!isunordered(x, y) && x > y) +#endif + +#endif + +/* + * Attempt at using the goto label construct of GNU GCC: + * it turns out this does give some benefit: 5-15% speedup. + * Don't look at these macros, it hurts... + */ +#define GOTO_LABEL +#undef GOTO_LABEL +#ifdef GOTO_LABEL + +#define SWITCH(a) goto *goto_map [(a)]; +#define BREAK SWITCH(*ip) +#define CASE(l) l ## _LABEL: +#define DEFAULT \ + CEE_ILLEGAL_LABEL: \ + CEE_ENDMAC_LABEL: +#define SUB_SWITCH \ + CEE_PREFIX1_LABEL: \ + CEE_ARGLIST_LABEL: \ + CEE_CEQ_LABEL: \ + CEE_CGT_LABEL: \ + CEE_CGT_UN_LABEL: \ + CEE_CLT_LABEL: \ + CEE_CLT_UN_LABEL: \ + CEE_LDFTN_LABEL: \ + CEE_LDVIRTFTN_LABEL: \ + CEE_UNUSED56_LABEL: \ + CEE_LDARG_LABEL: \ + CEE_LDARGA_LABEL: \ + CEE_STARG_LABEL: \ + CEE_LDLOC_LABEL: \ + CEE_LDLOCA_LABEL: \ + CEE_STLOC_LABEL: \ + CEE_LOCALLOC_LABEL: \ + CEE_UNUSED57_LABEL: \ + CEE_ENDFILTER_LABEL: \ + CEE_UNALIGNED__LABEL: \ + CEE_VOLATILE__LABEL: \ + CEE_TAIL__LABEL: \ + CEE_INITOBJ_LABEL: \ + CEE_UNUSED68_LABEL: \ + CEE_CPBLK_LABEL: \ + CEE_INITBLK_LABEL: \ + CEE_UNUSED69_LABEL: \ + CEE_RETHROW_LABEL: \ + CEE_UNUSED_LABEL: \ + CEE_SIZEOF_LABEL: \ + CEE_REFANYTYPE_LABEL: \ + CEE_UNUSED52_LABEL: \ + CEE_UNUSED53_LABEL: \ + CEE_UNUSED54_LABEL: \ + CEE_UNUSED55_LABEL: \ + CEE_UNUSED70_LABEL: +#define GOTO_LABEL_VARS \ + const static void * const goto_map [] = {\ +#define OPDEF(a,b,c,d,e,f,g,h,i,j) \ \ + && a ## _LABEL, \ +#include "mono/cil/opcode.def" \ +#undef OPDEF \ + &&DUMMY_LABEL \ + }; \ + DUMMY_LABEL: + +#else + +#define SWITCH(a) switch(a) +#define BREAK break +#define CASE(l) case l: +#define DEFAULT \ + default: \ + g_error ("Unimplemented opcode: %x at 0x%x\n", *ip, ip-header->code); +#define SUB_SWITCH case 0xFE: +#define GOTO_LABEL_VARS + +#endif diff --git a/mono/mini/interp/interp-internals.h b/mono/mini/interp/interp-internals.h new file mode 100644 index 00000000000..f26e4ff57b3 --- /dev/null +++ b/mono/mini/interp/interp-internals.h @@ -0,0 +1,124 @@ +#ifndef __MONO_MINI_INTERPRETER_INTERNALS_H__ +#define __MONO_MINI_INTERPRETER_INTERNALS_H__ + +#include +#include +#include +#include +#include +#include +#include "config.h" + +enum { + VAL_I32 = 0, + VAL_DOUBLE = 1, + VAL_I64 = 2, + VAL_VALUET = 3, + VAL_POINTER = 4, + VAL_NATI = 0 + VAL_POINTER, + VAL_MP = 1 + VAL_POINTER, + VAL_TP = 2 + VAL_POINTER, + VAL_OBJ = 3 + VAL_POINTER +}; + +#if SIZEOF_VOID_P == 4 +typedef guint32 mono_u; +typedef gint32 mono_i; +#elif SIZEOF_VOID_P == 8 +typedef guint64 mono_u; +typedef gint64 mono_i; +#endif + +/* + * Value types are represented on the eval stack as pointers to the + * actual storage. The size field tells how much storage is allocated. + * A value type can't be larger than 16 MB. + */ +typedef struct { + union { + gint32 i; + gint64 l; + double f; + /* native size integer and pointer types */ + gpointer p; + mono_u nati; + gpointer vt; + } data; +#if defined(__ppc__) || defined(__powerpc__) + int pad; +#endif +} stackval; + +typedef struct _MonoInvocation MonoInvocation; + +typedef void (*MonoFuncV) (void); +typedef void (*MonoPIFunc) (MonoFuncV callme, void *margs); + +/* + * Structure representing a method transformed for the interpreter + * This is domain specific + */ +typedef struct _RuntimeMethod +{ + /* NOTE: These first two elements (method and + next_jit_code_hash) must be in the same order and at the + same offset as in MonoJitInfo, because of the jit_code_hash + internal hash table in MonoDomain. */ + MonoMethod *method; + struct _RuntimeMethod *next_jit_code_hash; + guint32 locals_size; + guint32 args_size; + guint32 stack_size; + guint32 vt_stack_size; + guint32 alloca_size; + unsigned short *code; + unsigned short *new_body_start; /* after all STINARG instrs */ + MonoPIFunc func; + int num_clauses; + MonoExceptionClause *clauses; + void **data_items; + int transformed; + guint32 *arg_offsets; + guint32 *local_offsets; + unsigned int param_count; + unsigned int hasthis; +} RuntimeMethod; + +struct _MonoInvocation { + MonoInvocation *parent; /* parent */ + RuntimeMethod *runtime_method; /* parent */ + MonoMethod *method; /* parent */ + stackval *retval; /* parent */ + char *args; + stackval *stack_args; /* parent */ + stackval *stack; + stackval *sp; /* For GC stack marking */ + /* exception info */ + unsigned char invoke_trap; + const unsigned short *ip; + MonoException *ex; + MonoExceptionClause *ex_handler; +}; + +typedef struct { + MonoDomain *domain; + MonoInvocation *base_frame; + MonoInvocation *current_frame; + MonoInvocation *env_frame; + jmp_buf *current_env; + unsigned char search_for_handler; + unsigned char managed_code; +} ThreadContext; + +extern int mono_interp_traceopt; + +MonoException * +mono_interp_transform_method (RuntimeMethod *runtime_method, ThreadContext *context); + +void +mono_interp_transform_init (void); + +RuntimeMethod * +mono_interp_get_runtime_method (MonoDomain *domain, MonoMethod *method, MonoError *error); + +#endif /* __MONO_MINI_INTERPRETER_INTERNALS_H__ */ diff --git a/mono/mini/interp/interp.c b/mono/mini/interp/interp.c new file mode 100644 index 00000000000..9c21f957355 --- /dev/null +++ b/mono/mini/interp/interp.c @@ -0,0 +1,4550 @@ +/* + * PLEASE NOTE: This is a research prototype. + * + * + * interp.c: Interpreter for CIL byte codes + * + * Authors: + * Paolo Molaro (lupus@ximian.com) + * Miguel de Icaza (miguel@ximian.com) + * Dietmar Maurer (dietmar@ximian.com) + * + * (C) 2001, 2002 Ximian, Inc. + */ +#ifndef __USE_ISOC99 +#define __USE_ISOC99 +#endif +#include "config.h" +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#ifdef HAVE_ALLOCA_H +# include +#else +# ifdef __CYGWIN__ +# define alloca __builtin_alloca +# endif +#endif + +/* trim excessive headers */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "interp.h" +#include "interp-internals.h" +#include "mintops.h" +#include "hacks.h" + +#include +#include + + +/* Mingw 2.1 doesnt need this any more, but leave it in for now for older versions */ +#ifdef _WIN32 +#define isnan _isnan +#define finite _finite +#endif +#ifndef HAVE_FINITE +#ifdef HAVE_ISFINITE +#define finite isfinite +#endif +#endif + +#define INIT_FRAME(frame,parent_frame,method_args,method_retval,domain,mono_method,error) \ + do { \ + (frame)->parent = (parent_frame); \ + (frame)->stack_args = (method_args); \ + (frame)->retval = (method_retval); \ + (frame)->runtime_method = mono_interp_get_runtime_method ((domain), (mono_method), (error)); \ + (frame)->ex = NULL; \ + (frame)->ip = NULL; \ + (frame)->invoke_trap = 0; \ + } while (0) + +void ves_exec_method (MonoInvocation *frame); + +static char* dump_stack (stackval *stack, stackval *sp); +static char* dump_frame (MonoInvocation *inv); +static MonoArray *get_trace_ips (MonoDomain *domain, MonoInvocation *top); +static void ves_exec_method_with_context (MonoInvocation *frame, ThreadContext *context); + +typedef void (*ICallMethod) (MonoInvocation *frame); + +static guint32 die_on_exception = 0; +static MonoNativeTlsKey thread_context_id; + +static char* dump_args (MonoInvocation *inv); + +#define DEBUG_INTERP 0 +#define COUNT_OPS 0 +#if DEBUG_INTERP +int mono_interp_traceopt = 2; +/* If true, then we output the opcodes as we interpret them */ +static int global_tracing = 2; + +static int debug_indent_level = 0; + +static int break_on_method = 0; +static int nested_trace = 0; +static GList *db_methods = NULL; + +static void +output_indent (void) +{ + int h; + + for (h = 0; h < debug_indent_level; h++) + g_print (" "); +} + +static void +db_match_method (gpointer data, gpointer user_data) +{ + MonoMethod *m = (MonoMethod*)user_data; + MonoMethodDesc *desc = data; + + if (mono_method_desc_full_match (desc, m)) + break_on_method = 1; +} + +static void debug_enter (MonoInvocation *frame, int *tracing) +{ + if (db_methods) { + g_list_foreach (db_methods, db_match_method, (gpointer)frame->runtime_method->method); + if (break_on_method) + *tracing = nested_trace ? (global_tracing = 2, 3) : 2; + break_on_method = 0; + } + if (*tracing) { + MonoMethod *method = frame->runtime_method->method; + char *mn, *args = dump_args (frame); + debug_indent_level++; + output_indent (); + mn = mono_method_full_name (method, FALSE); + g_print ("(%p) Entering %s (", mono_thread_internal_current (), mn); + g_free (mn); + g_print ("%s)\n", args); + g_free (args); + } + if (mono_profiler_events & MONO_PROFILE_ENTER_LEAVE) + mono_profiler_method_enter (frame->runtime_method->method); +} + + +#define DEBUG_LEAVE() \ + if (tracing) { \ + char *mn, *args; \ + args = dump_retval (frame); \ + output_indent (); \ + mn = mono_method_full_name (frame->runtime_method->method, FALSE); \ + g_print ("(%p) Leaving %s", mono_thread_internal_current (), mn); \ + g_free (mn); \ + g_print (" => %s\n", args); \ + g_free (args); \ + debug_indent_level--; \ + if (tracing == 3) global_tracing = 0; \ + } \ + if (mono_profiler_events & MONO_PROFILE_ENTER_LEAVE) \ + mono_profiler_method_leave (frame->runtime_method->method); + +#else + +int mono_interp_traceopt = 0; +static void debug_enter (MonoInvocation *frame, int *tracing) +{ +} +#define DEBUG_LEAVE() + +#endif + +static void +interp_ex_handler (MonoException *ex) { + MonoError error; + ThreadContext *context = mono_native_tls_get_value (thread_context_id); + char *stack_trace; + if (context == NULL) + return; + stack_trace = dump_frame (context->current_frame); + ex->stack_trace = mono_string_new (mono_domain_get(), stack_trace); + g_free (stack_trace); + if (context->current_env == NULL || strcmp(ex->object.vtable->klass->name, "ExecutionEngineException") == 0) { + char *strace = mono_string_to_utf8_checked (ex->stack_trace, &error); + mono_error_cleanup (&error); /* FIXME: don't swallow the error */ + fprintf(stderr, "Nothing can catch this exception: "); + fprintf(stderr, "%s", ex->object.vtable->klass->name); + if (ex->message != NULL) { + char *m = mono_string_to_utf8_checked (ex->message, &error); + mono_error_cleanup (&error); /* FIXME: don't swallow the error */ + fprintf(stderr, ": %s", m); + g_free(m); + } + fprintf(stderr, "\n%s\n", strace); + g_free (strace); + if (ex->inner_ex != NULL) { + ex = (MonoException *)ex->inner_ex; + fprintf(stderr, "Inner exception: %s", ex->object.vtable->klass->name); + if (ex->message != NULL) { + char *m = mono_string_to_utf8_checked (ex->message, &error); + mono_error_cleanup (&error); /* FIXME: don't swallow the error */ + fprintf(stderr, ": %s", m); + g_free(m); + } + strace = mono_string_to_utf8_checked (ex->stack_trace, &error); + mono_error_cleanup (&error); /* FIXME: don't swallow the error */ + fprintf(stderr, "\n"); + fprintf(stderr, "%s\n", strace); + g_free (strace); + } + /* wait for other threads to also collapse */ + // Sleep(1000); // TODO: proper sleep + exit(1); + } + context->env_frame->ex = ex; + context->search_for_handler = 1; + longjmp (*context->current_env, 1); +} + +static void +ves_real_abort (int line, MonoMethod *mh, + const unsigned short *ip, stackval *stack, stackval *sp) +{ + MonoError error; + fprintf (stderr, "Execution aborted in method: %s::%s\n", mh->klass->name, mh->name); + fprintf (stderr, "Line=%d IP=0x%04lx, Aborted execution\n", line, + ip-(const unsigned short *)mono_method_get_header_checked (mh, &error)->code); + mono_error_cleanup (&error); /* FIXME: don't swallow the error */ + g_print ("0x%04x %02x\n", + ip-(const unsigned short *)mono_method_get_header_checked (mh, &error)->code, *ip); + mono_error_cleanup (&error); /* FIXME: don't swallow the error */ + if (sp > stack) + printf ("\t[%ld] 0x%08x %0.5f\n", sp-stack, sp[-1].data.i, sp[-1].data.f); +} + +#define ves_abort() \ + do {\ + ves_real_abort(__LINE__, frame->runtime_method->method, ip, frame->stack, sp); \ + THROW_EX (mono_get_exception_execution_engine (NULL), ip); \ + } while (0); + +static mono_mutex_t runtime_method_lookup_section; + +RuntimeMethod* +mono_interp_get_runtime_method (MonoDomain *domain, MonoMethod *method, MonoError *error) +{ + RuntimeMethod *rtm; + error_init (error); + + mono_os_mutex_lock (&runtime_method_lookup_section); + if ((rtm = mono_internal_hash_table_lookup (&domain->jit_code_hash, method))) { + mono_os_mutex_unlock (&runtime_method_lookup_section); + return rtm; + } + rtm = mono_mempool_alloc (domain->mp, sizeof (RuntimeMethod)); + memset (rtm, 0, sizeof (*rtm)); + rtm->method = method; + rtm->param_count = mono_method_signature (method)->param_count; + rtm->hasthis = mono_method_signature (method)->hasthis; + mono_internal_hash_table_insert (&domain->jit_code_hash, method, rtm); + mono_os_mutex_unlock (&runtime_method_lookup_section); + + return rtm; +} + +static gpointer +interp_create_trampoline (MonoDomain *domain, MonoMethod *method, MonoError *error) +{ + if (method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED) + method = mono_marshal_get_synchronized_wrapper (method); + return mono_interp_get_runtime_method (domain, method, error); +} + +static inline RuntimeMethod* +get_virtual_method (MonoDomain *domain, RuntimeMethod *runtime_method, MonoObject *obj) +{ + MonoMethod *m = runtime_method->method; + MonoError error; + + if ((m->flags & METHOD_ATTRIBUTE_FINAL) || !(m->flags & METHOD_ATTRIBUTE_VIRTUAL)) { + RuntimeMethod *ret = NULL; + if (mono_object_is_transparent_proxy (obj)) { + ret = mono_interp_get_runtime_method (domain, mono_marshal_get_remoting_invoke (m), &error); + mono_error_cleanup (&error); /* FIXME: don't swallow the error */ + } else if (m->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED) { + ret = mono_interp_get_runtime_method (domain, mono_marshal_get_synchronized_wrapper (m), &error); + mono_error_cleanup (&error); /* FIXME: don't swallow the error */ + } else { + ret = runtime_method; + } + return ret; + } + + mono_class_setup_vtable (obj->vtable->klass); + + int slot = mono_method_get_vtable_slot (m); + if (mono_class_is_interface (m->klass)) { + g_assert (obj->vtable->klass != m->klass); + /* TODO: interface offset lookup is slow, go through IMT instead */ + slot += mono_class_interface_offset (obj->vtable->klass, m->klass); + } + + MonoMethod *virtual_method = obj->vtable->klass->vtable [slot]; + if (m->is_inflated && mono_method_get_context (m)->method_inst) { + MonoGenericContext context = { NULL, NULL }; + + if (mono_class_is_ginst (virtual_method->klass)) + context.class_inst = mono_class_get_generic_class (virtual_method->klass)->context.class_inst; + else if (mono_class_is_gtd (virtual_method->klass)) + context.class_inst = mono_class_get_generic_container (virtual_method->klass)->context.class_inst; + context.method_inst = mono_method_get_context (m)->method_inst; + + virtual_method = mono_class_inflate_generic_method_checked (virtual_method, &context, &error); + mono_error_cleanup (&error); /* FIXME: don't swallow the error */ + } + RuntimeMethod *virtual_runtime_method = mono_interp_get_runtime_method (domain, virtual_method, &error); + mono_error_cleanup (&error); /* FIXME: don't swallow the error */ + return virtual_runtime_method; +} + +static void inline +stackval_from_data (MonoType *type, stackval *result, char *data, gboolean pinvoke) +{ + if (type->byref) { + switch (type->type) { + case MONO_TYPE_OBJECT: + case MONO_TYPE_CLASS: + case MONO_TYPE_STRING: + case MONO_TYPE_ARRAY: + case MONO_TYPE_SZARRAY: + break; + default: + break; + } + result->data.p = *(gpointer*)data; + return; + } + switch (type->type) { + case MONO_TYPE_VOID: + return; + case MONO_TYPE_I1: + result->data.i = *(gint8*)data; + return; + case MONO_TYPE_U1: + case MONO_TYPE_BOOLEAN: + result->data.i = *(guint8*)data; + return; + case MONO_TYPE_I2: + result->data.i = *(gint16*)data; + return; + case MONO_TYPE_U2: + case MONO_TYPE_CHAR: + result->data.i = *(guint16*)data; + return; + case MONO_TYPE_I4: + result->data.i = *(gint32*)data; + return; + case MONO_TYPE_U: + case MONO_TYPE_I: + result->data.nati = *(mono_i*)data; + return; + case MONO_TYPE_PTR: + result->data.p = *(gpointer*)data; + return; + case MONO_TYPE_U4: + result->data.i = *(guint32*)data; + return; + case MONO_TYPE_R4: + result->data.f = *(float*)data; + return; + case MONO_TYPE_I8: + case MONO_TYPE_U8: + result->data.l = *(gint64*)data; + return; + case MONO_TYPE_R8: + result->data.f = *(double*)data; + return; + case MONO_TYPE_STRING: + case MONO_TYPE_SZARRAY: + case MONO_TYPE_CLASS: + case MONO_TYPE_OBJECT: + case MONO_TYPE_ARRAY: + result->data.p = *(gpointer*)data; + return; + case MONO_TYPE_VALUETYPE: + if (type->data.klass->enumtype) { + stackval_from_data (mono_class_enum_basetype (type->data.klass), result, data, pinvoke); + return; + } else + mono_value_copy (result->data.vt, data, type->data.klass); + return; + case MONO_TYPE_GENERICINST: + stackval_from_data (&type->data.generic_class->container_class->byval_arg, result, data, pinvoke); + return; + default: + g_warning ("got type 0x%02x", type->type); + g_assert_not_reached (); + } +} + +static void inline +stackval_to_data (MonoType *type, stackval *val, char *data, gboolean pinvoke) +{ + if (type->byref) { + gpointer *p = (gpointer*)data; + *p = val->data.p; + return; + } + /* printf ("TODAT0 %p\n", data); */ + switch (type->type) { + case MONO_TYPE_I1: + case MONO_TYPE_U1: { + guint8 *p = (guint8*)data; + *p = val->data.i; + return; + } + case MONO_TYPE_BOOLEAN: { + guint8 *p = (guint8*)data; + *p = (val->data.i != 0); + return; + } + case MONO_TYPE_I2: + case MONO_TYPE_U2: + case MONO_TYPE_CHAR: { + guint16 *p = (guint16*)data; + *p = val->data.i; + return; + } + case MONO_TYPE_I: { + mono_i *p = (mono_i*)data; + /* In theory the value used by stloc should match the local var type + but in practice it sometimes doesn't (a int32 gets dup'd and stloc'd into + a native int - both by csc and mcs). Not sure what to do about sign extension + as it is outside the spec... doing the obvious */ + *p = (mono_i)val->data.nati; + return; + } + case MONO_TYPE_U: { + mono_u *p = (mono_u*)data; + /* see above. */ + *p = (mono_u)val->data.nati; + return; + } + case MONO_TYPE_I4: + case MONO_TYPE_U4: { + gint32 *p = (gint32*)data; + *p = val->data.i; + return; + } + case MONO_TYPE_I8: + case MONO_TYPE_U8: { + gint64 *p = (gint64*)data; + *p = val->data.l; + return; + } + case MONO_TYPE_R4: { + float *p = (float*)data; + *p = val->data.f; + return; + } + case MONO_TYPE_R8: { + double *p = (double*)data; + *p = val->data.f; + return; + } + case MONO_TYPE_STRING: + case MONO_TYPE_SZARRAY: + case MONO_TYPE_CLASS: + case MONO_TYPE_OBJECT: + case MONO_TYPE_ARRAY: + case MONO_TYPE_PTR: { + gpointer *p = (gpointer*)data; + *p = val->data.p; + return; + } + case MONO_TYPE_VALUETYPE: + if (type->data.klass->enumtype) { + stackval_to_data (mono_class_enum_basetype (type->data.klass), val, data, pinvoke); + return; + } else + mono_value_copy (data, val->data.vt, type->data.klass); + return; + case MONO_TYPE_GENERICINST: + stackval_to_data (&type->data.generic_class->container_class->byval_arg, val, data, pinvoke); + return; + default: + g_warning ("got type %x", type->type); + g_assert_not_reached (); + } +} + +static void +fill_in_trace (MonoException *exception, MonoInvocation *frame) +{ + char *stack_trace = dump_frame (frame); + MonoDomain *domain = mono_domain_get(); + (exception)->stack_trace = mono_string_new (domain, stack_trace); + (exception)->trace_ips = get_trace_ips (domain, frame); + g_free (stack_trace); +} + +#define FILL_IN_TRACE(exception, frame) fill_in_trace(exception, frame) + +#define THROW_EX(exception,ex_ip) \ + do {\ + frame->ip = (ex_ip); \ + frame->ex = (MonoException*)(exception); \ + FILL_IN_TRACE(frame->ex, frame); \ + goto handle_exception; \ + } while (0) + +static MonoObject* +ves_array_create (MonoDomain *domain, MonoClass *klass, MonoMethodSignature *sig, stackval *values) +{ + uintptr_t *lengths; + intptr_t *lower_bounds; + MonoObject *obj; + MonoError error; + int i; + + lengths = alloca (sizeof (uintptr_t) * klass->rank * 2); + for (i = 0; i < sig->param_count; ++i) { + lengths [i] = values->data.i; + values ++; + } + if (klass->rank == sig->param_count) { + /* Only lengths provided. */ + lower_bounds = NULL; + } else { + /* lower bounds are first. */ + lower_bounds = (intptr_t *) lengths; + lengths += klass->rank; + } + obj = (MonoObject*) mono_array_new_full_checked (domain, klass, lengths, lower_bounds, &error); + mono_error_cleanup (&error); /* FIXME: don't swallow the error */ + return obj; +} + +static void +ves_array_set (MonoInvocation *frame) +{ + stackval *sp = frame->stack_args + 1; + MonoObject *o; + MonoArray *ao; + MonoClass *ac; + gint32 i, t, pos, esize; + gpointer ea; + MonoType *mt; + + o = frame->stack_args->data.p; + ao = (MonoArray *)o; + ac = o->vtable->klass; + + g_assert (ac->rank >= 1); + + pos = sp [0].data.i; + if (ao->bounds != NULL) { + pos -= ao->bounds [0].lower_bound; + for (i = 1; i < ac->rank; i++) { + if ((t = sp [i].data.i - ao->bounds [i].lower_bound) >= + ao->bounds [i].length) { + frame->ex = mono_get_exception_index_out_of_range (); + FILL_IN_TRACE(frame->ex, frame); + return; + } + pos = pos*ao->bounds [i].length + sp [i].data.i - + ao->bounds [i].lower_bound; + } + } else if (pos >= ao->max_length) { + frame->ex = mono_get_exception_index_out_of_range (); + FILL_IN_TRACE(frame->ex, frame); + return; + } + + if (sp [ac->rank].data.p && !mono_object_class (o)->element_class->valuetype) { + MonoError error; + MonoObject *isinst = mono_object_isinst_checked (sp [ac->rank].data.p, mono_object_class (o)->element_class, &error); + mono_error_cleanup (&error); + if (!isinst) { + frame->ex = mono_get_exception_array_type_mismatch (); + FILL_IN_TRACE (frame->ex, frame); + return; + } + } + + esize = mono_array_element_size (ac); + ea = mono_array_addr_with_size (ao, esize, pos); + + mt = mono_method_signature (frame->runtime_method->method)->params [ac->rank]; + stackval_to_data (mt, &sp [ac->rank], ea, FALSE); +} + +static void +ves_array_get (MonoInvocation *frame) +{ + stackval *sp = frame->stack_args + 1; + MonoObject *o; + MonoArray *ao; + MonoClass *ac; + gint32 i, t, pos, esize; + gpointer ea; + MonoType *mt; + + o = frame->stack_args->data.p; + ao = (MonoArray *)o; + ac = o->vtable->klass; + + g_assert (ac->rank >= 1); + + pos = sp [0].data.i; + if (ao->bounds != NULL) { + pos -= ao->bounds [0].lower_bound; + for (i = 1; i < ac->rank; i++) { + if ((t = sp [i].data.i - ao->bounds [i].lower_bound) >= + ao->bounds [i].length) { + frame->ex = mono_get_exception_index_out_of_range (); + FILL_IN_TRACE(frame->ex, frame); + return; + } + + pos = pos*ao->bounds [i].length + sp [i].data.i - + ao->bounds [i].lower_bound; + } + } else if (pos >= ao->max_length) { + frame->ex = mono_get_exception_index_out_of_range (); + FILL_IN_TRACE(frame->ex, frame); + return; + } + + esize = mono_array_element_size (ac); + ea = mono_array_addr_with_size (ao, esize, pos); + + mt = mono_method_signature (frame->runtime_method->method)->ret; + stackval_from_data (mt, frame->retval, ea, FALSE); +} + +static void +ves_array_element_address (MonoInvocation *frame) +{ + stackval *sp = frame->stack_args + 1; + MonoObject *o; + MonoArray *ao; + MonoClass *ac; + gint32 i, t, pos, esize; + gpointer ea; + + o = frame->stack_args->data.p; + ao = (MonoArray *)o; + ac = o->vtable->klass; + + g_assert (ac->rank >= 1); + + pos = sp [0].data.i; + if (ao->bounds != NULL) { + pos -= ao->bounds [0].lower_bound; + for (i = 1; i < ac->rank; i++) { + if ((t = sp [i].data.i - ao->bounds [i].lower_bound) >= + ao->bounds [i].length) { + frame->ex = mono_get_exception_index_out_of_range (); + FILL_IN_TRACE(frame->ex, frame); + return; + } + pos = pos*ao->bounds [i].length + sp [i].data.i - + ao->bounds [i].lower_bound; + } + } else if (pos >= ao->max_length) { + frame->ex = mono_get_exception_index_out_of_range (); + FILL_IN_TRACE(frame->ex, frame); + return; + } + + esize = mono_array_element_size (ac); + ea = mono_array_addr_with_size (ao, esize, pos); + + frame->retval->data.p = ea; +} + +void +interp_walk_stack_with_ctx (MonoInternalStackWalk func, MonoContext *ctx, MonoUnwindOptions options, void *user_data) +{ + MonoError error; + ThreadContext *context = mono_native_tls_get_value (thread_context_id); + + MonoInvocation *frame = context->current_frame; + + while (frame) { + MonoStackFrameInfo fi; + memset (&fi, 0, sizeof (MonoStackFrameInfo)); + + /* TODO: hack to make some asserts happy. */ + fi.ji = (MonoJitInfo *) frame->runtime_method; + + if (frame->runtime_method) + fi.method = fi.actual_method = frame->runtime_method->method; + + if (!fi.method || (fi.method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) || (fi.method->iflags & (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL | METHOD_IMPL_ATTRIBUTE_RUNTIME))) { + fi.il_offset = -1; + fi.type = FRAME_TYPE_MANAGED_TO_NATIVE; + } else { + MonoMethodHeader *hd = mono_method_get_header_checked (fi.method, &error); + mono_error_cleanup (&error); /* FIXME: don't swallow the error */ + fi.type = FRAME_TYPE_MANAGED; + fi.il_offset = frame->ip - (const unsigned short *) hd->code; + if (!fi.method->wrapper_type) + fi.managed = TRUE; + } + + if (func (&fi, ctx, user_data)) + return; + frame = frame->parent; + } + + g_assert (0); +} + +static MonoPIFunc mono_interp_enter_icall_trampoline = NULL; + +struct _MethodArguments { + size_t ilen; + gpointer *iargs; + size_t flen; + double *fargs; + gpointer *retval; + size_t is_float_ret; +}; + +typedef struct _MethodArguments MethodArguments; + +// TODO: this function is also arch dependent (register width). +static MethodArguments* build_args_from_sig (MonoMethodSignature *sig, MonoInvocation *frame) +{ + // TODO: don't malloc this data structure. + MethodArguments *margs = g_malloc0 (sizeof (MethodArguments)); + + if (sig->hasthis) + margs->ilen++; + + for (int i = 0; i < sig->param_count; i++) { + guint32 ptype = sig->params [i]->byref ? MONO_TYPE_PTR : sig->params [i]->type; + switch (ptype) { + case MONO_TYPE_BOOLEAN: + case MONO_TYPE_CHAR: + case MONO_TYPE_I1: + case MONO_TYPE_U1: + case MONO_TYPE_I2: + case MONO_TYPE_U2: + case MONO_TYPE_I4: + case MONO_TYPE_U4: + case MONO_TYPE_I: + case MONO_TYPE_U: + case MONO_TYPE_PTR: + case MONO_TYPE_SZARRAY: + case MONO_TYPE_CLASS: + case MONO_TYPE_OBJECT: + case MONO_TYPE_STRING: + case MONO_TYPE_I8: + case MONO_TYPE_VALUETYPE: + case MONO_TYPE_GENERICINST: + margs->ilen++; + break; + case MONO_TYPE_R4: + case MONO_TYPE_R8: + margs->flen++; + break; + default: + g_error ("build_args_from_sig: not implemented yet (1): 0x%x\n", ptype); + } + } + + if (margs->ilen > 0) + margs->iargs = g_malloc0 (sizeof (gpointer) * margs->ilen); + + if (margs->flen > 0) + margs->fargs = g_malloc0 (sizeof (double) * margs->flen); + + if (margs->ilen > 8) + g_error ("build_args_from_sig: TODO, allocate gregs: %d\n", margs->ilen); + + if (margs->flen > 3) + g_error ("build_args_from_sig: TODO, allocate fregs: %d\n", margs->flen); + + + size_t int_i = 0; + size_t int_f = 0; + + if (sig->hasthis) { + margs->iargs [0] = frame->stack_args->data.p; + int_i++; + } + + for (int i = 0; i < sig->param_count; i++) { + guint32 ptype = sig->params [i]->byref ? MONO_TYPE_PTR : sig->params [i]->type; + switch (ptype) { + case MONO_TYPE_BOOLEAN: + case MONO_TYPE_CHAR: + case MONO_TYPE_I1: + case MONO_TYPE_U1: + case MONO_TYPE_I2: + case MONO_TYPE_U2: + case MONO_TYPE_I4: + case MONO_TYPE_U4: + case MONO_TYPE_I: + case MONO_TYPE_U: + case MONO_TYPE_PTR: + case MONO_TYPE_SZARRAY: + case MONO_TYPE_CLASS: + case MONO_TYPE_OBJECT: + case MONO_TYPE_STRING: + case MONO_TYPE_I8: + case MONO_TYPE_VALUETYPE: + case MONO_TYPE_GENERICINST: + margs->iargs [int_i] = frame->stack_args [i].data.p; +#if DEBUG_INTERP + g_print ("build_args_from_sig: margs->iargs[%d]: %p (frame @ %d)\n", int_i, margs->iargs[int_i], i); +#endif + int_i++; + break; + case MONO_TYPE_R4: + case MONO_TYPE_R8: + margs->fargs [int_f] = frame->stack_args [i].data.f; + int_f++; + break; + default: + g_error ("build_args_from_sig: not implemented yet (2): 0x%x\n", ptype); + } + } + + switch (sig->ret->type) { + case MONO_TYPE_BOOLEAN: + case MONO_TYPE_CHAR: + case MONO_TYPE_I1: + case MONO_TYPE_U1: + case MONO_TYPE_I2: + case MONO_TYPE_U2: + case MONO_TYPE_I4: + case MONO_TYPE_U4: + case MONO_TYPE_I: + case MONO_TYPE_U: + case MONO_TYPE_PTR: + case MONO_TYPE_SZARRAY: + case MONO_TYPE_CLASS: + case MONO_TYPE_OBJECT: + case MONO_TYPE_STRING: + case MONO_TYPE_I8: + case MONO_TYPE_VALUETYPE: + case MONO_TYPE_GENERICINST: + margs->retval = &(frame->retval->data.p); + break; + case MONO_TYPE_R4: + case MONO_TYPE_R8: + margs->retval = &(frame->retval->data.p); + margs->is_float_ret = 1; + break; + case MONO_TYPE_VOID: + margs->retval = NULL; + break; + default: + g_error ("build_args_from_sig: ret type not implemented yet: 0x%x\n", sig->ret->type); + } + + return margs; +} + +static void +ves_pinvoke_method (MonoInvocation *frame, MonoMethodSignature *sig, MonoFuncV addr, gboolean string_ctor, ThreadContext *context) +{ + jmp_buf env; + MonoInvocation *old_frame = context->current_frame; + MonoInvocation *old_env_frame = context->env_frame; + jmp_buf *old_env = context->current_env; + + if (setjmp (env)) { + context->current_frame = old_frame; + context->env_frame = old_env_frame; + context->current_env = old_env; + context->managed_code = 1; + return; + } + + frame->ex = NULL; + context->env_frame = frame; + context->current_env = &env; + + g_assert (!frame->runtime_method); + if (!mono_interp_enter_icall_trampoline) { + MonoTrampInfo *info; + mono_interp_enter_icall_trampoline = mono_arch_get_enter_icall_trampoline (&info); + // TODO: + // mono_tramp_info_register (info, NULL); + } + + MethodArguments *margs = build_args_from_sig (sig, frame); +#if DEBUG_INTERP + g_print ("ICALL: mono_interp_enter_icall_trampoline = %p, addr = %p\n", mono_interp_enter_icall_trampoline, addr); + g_print ("margs(out): ilen=%d, flen=%d\n", margs->ilen, margs->flen); +#endif + + context->current_frame = frame; + context->managed_code = 0; + + mono_interp_enter_icall_trampoline (addr, margs); + + context->managed_code = 1; + /* domain can only be changed by native code */ + context->domain = mono_domain_get (); + + if (*mono_thread_interruption_request_flag ()) + mono_thread_interruption_checkpoint (); + + if (!MONO_TYPE_ISSTRUCT (sig->ret)) + stackval_from_data (sig->ret, frame->retval, (char*)&frame->retval->data.p, sig->pinvoke); + + context->current_frame = old_frame; + context->env_frame = old_env_frame; + context->current_env = old_env; + + g_free (margs->iargs); + g_free (margs->fargs); + g_free (margs); +} + +void +mono_interp_init_delegate (MonoDelegate *del) +{ + g_assert (!del->method); + del->method = ((RuntimeMethod *) del->method_ptr)->method; + g_assert (del->method); +} + +/* + * From the spec: + * runtime specifies that the implementation of the method is automatically + * provided by the runtime and is primarily used for the methods of delegates. + */ +static void +ves_runtime_method (MonoInvocation *frame, ThreadContext *context) +{ + MonoMethod *method = frame->runtime_method->method; + const char *name = method->name; + MonoObject *obj = (MonoObject*) frame->stack_args->data.p; + MonoObject *isinst_obj; + MonoError error; + + mono_class_init (method->klass); + + isinst_obj = mono_object_isinst_checked (obj, mono_defaults.array_class, &error); + mono_error_cleanup (&error); /* FIXME: don't swallow the error */ + if (obj && isinst_obj) { + if (*name == 'S' && (strcmp (name, "Set") == 0)) { + ves_array_set (frame); + return; + } + if (*name == 'G' && (strcmp (name, "Get") == 0)) { + ves_array_get (frame); + return; + } + if (*name == 'A' && (strcmp (name, "Address") == 0)) { + ves_array_element_address (frame); + return; + } + } + + g_error ("Don't know how to exec runtime method %s.%s::%s", + method->klass->name_space, method->klass->name, + method->name); +} + +static char* +dump_stack (stackval *stack, stackval *sp) +{ + stackval *s = stack; + GString *str = g_string_new (""); + + if (sp == stack) + return g_string_free (str, FALSE); + + while (s < sp) { + g_string_append_printf (str, "[%p (%lld)] ", s->data.l, s->data.l); + ++s; + } + return g_string_free (str, FALSE); +} + +static void +dump_stackval (GString *str, stackval *s, MonoType *type) +{ + switch (type->type) { + case MONO_TYPE_I1: + case MONO_TYPE_U1: + case MONO_TYPE_I2: + case MONO_TYPE_U2: + case MONO_TYPE_I4: + case MONO_TYPE_U4: + case MONO_TYPE_CHAR: + case MONO_TYPE_BOOLEAN: + g_string_append_printf (str, "[%d] ", s->data.i); + break; + case MONO_TYPE_STRING: + case MONO_TYPE_SZARRAY: + case MONO_TYPE_CLASS: + case MONO_TYPE_OBJECT: + case MONO_TYPE_ARRAY: + case MONO_TYPE_PTR: + case MONO_TYPE_I: + case MONO_TYPE_U: + g_string_append_printf (str, "[%p] ", s->data.p); + break; + case MONO_TYPE_VALUETYPE: + if (type->data.klass->enumtype) + g_string_append_printf (str, "[%d] ", s->data.i); + else + g_string_append_printf (str, "[vt:%p] ", s->data.p); + break; + case MONO_TYPE_R4: + case MONO_TYPE_R8: + g_string_append_printf (str, "[%g] ", s->data.f); + break; + case MONO_TYPE_I8: + case MONO_TYPE_U8: + default: { + GString *res = g_string_new (""); + mono_type_get_desc (res, type, TRUE); + g_string_append_printf (str, "[{%s} %lld/0x%0llx] ", res->str, s->data.l, s->data.l); + g_string_free (res, TRUE); + break; + } + } +} + +static char* +dump_args (MonoInvocation *inv) +{ + GString *str = g_string_new (""); + int i; + MonoMethodSignature *signature = mono_method_signature (inv->runtime_method->method); + + if (signature->param_count == 0 && !signature->hasthis) + return g_string_free (str, FALSE); + + if (signature->hasthis) { + MonoMethod *method = inv->runtime_method->method; + dump_stackval (str, inv->stack_args, &method->klass->byval_arg); + } + + for (i = 0; i < signature->param_count; ++i) + dump_stackval (str, inv->stack_args + (!!signature->hasthis) + i, signature->params [i]); + + return g_string_free (str, FALSE); +} + +static char* +dump_retval (MonoInvocation *inv) +{ + GString *str = g_string_new (""); + MonoType *ret = mono_method_signature (inv->runtime_method->method)->ret; + + if (ret->type != MONO_TYPE_VOID) + dump_stackval (str, inv->retval, ret); + + return g_string_free (str, FALSE); +} + +static char* +dump_frame (MonoInvocation *inv) +{ + GString *str = g_string_new (""); + int i; + char *args; + MonoError error; + + for (i = 0; inv; inv = inv->parent) { + if (inv->runtime_method != NULL) { + MonoMethod *method = inv->runtime_method->method; + MonoClass *k; + + int codep = 0; + const char * opname = ""; + char *name; + gchar *source = NULL; + + k = method->klass; + + if ((method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) == 0 && + (method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) == 0) { + MonoMethodHeader *hd = mono_method_get_header_checked (method, &error); + mono_error_cleanup (&error); /* FIXME: don't swallow the error */ + + if (hd != NULL) { + if (inv->ip) { + opname = mono_interp_opname [*inv->ip]; + codep = inv->ip - inv->runtime_method->code; + source = g_strdup_printf ("%s:%d // (TODO: proper stacktrace)", method->name, codep); + } else + opname = ""; + +#if 0 + MonoDebugSourceLocation *minfo = mono_debug_lookup_method (method); + source = mono_debug_method_lookup_location (minfo, codep); +#endif + } + } + args = dump_args (inv); + name = mono_method_full_name (method, TRUE); + if (source) + g_string_append_printf (str, "#%d: 0x%05x %-10s in %s (%s) at %s\n", i, codep, opname, name, args, source); + else + g_string_append_printf (str, "#%d: 0x%05x %-10s in %s (%s)\n", i, codep, opname, name, args); + g_free (name); + g_free (args); + g_free (source); + ++i; + } + } + return g_string_free (str, FALSE); +} + +static MonoArray * +get_trace_ips (MonoDomain *domain, MonoInvocation *top) +{ + int i; + MonoArray *res; + MonoInvocation *inv; + MonoError error; + + for (i = 0, inv = top; inv; inv = inv->parent) + if (inv->runtime_method != NULL) + ++i; + + res = mono_array_new_checked (domain, mono_defaults.int_class, 2 * i, &error); + mono_error_cleanup (&error); /* FIXME: don't swallow the error */ + + for (i = 0, inv = top; inv; inv = inv->parent) + if (inv->runtime_method != NULL) { + mono_array_set (res, gpointer, i, inv->runtime_method); + ++i; + mono_array_set (res, gpointer, i, (gpointer)inv->ip); + ++i; + } + + return res; +} + + +#define MYGUINT64_MAX 18446744073709551615ULL +#define MYGINT64_MAX 9223372036854775807LL +#define MYGINT64_MIN (-MYGINT64_MAX -1LL) + +#define MYGUINT32_MAX 4294967295U +#define MYGINT32_MAX 2147483647 +#define MYGINT32_MIN (-MYGINT32_MAX -1) + +#define CHECK_ADD_OVERFLOW(a,b) \ + (gint32)(b) >= 0 ? (gint32)(MYGINT32_MAX) - (gint32)(b) < (gint32)(a) ? -1 : 0 \ + : (gint32)(MYGINT32_MIN) - (gint32)(b) > (gint32)(a) ? +1 : 0 + +#define CHECK_SUB_OVERFLOW(a,b) \ + (gint32)(b) < 0 ? (gint32)(MYGINT32_MAX) + (gint32)(b) < (gint32)(a) ? -1 : 0 \ + : (gint32)(MYGINT32_MIN) + (gint32)(b) > (gint32)(a) ? +1 : 0 + +#define CHECK_ADD_OVERFLOW_UN(a,b) \ + (guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a) ? -1 : 0 + +#define CHECK_SUB_OVERFLOW_UN(a,b) \ + (guint32)(a) < (guint32)(b) ? -1 : 0 + +#define CHECK_ADD_OVERFLOW64(a,b) \ + (gint64)(b) >= 0 ? (gint64)(MYGINT64_MAX) - (gint64)(b) < (gint64)(a) ? -1 : 0 \ + : (gint64)(MYGINT64_MIN) - (gint64)(b) > (gint64)(a) ? +1 : 0 + +#define CHECK_SUB_OVERFLOW64(a,b) \ + (gint64)(b) < 0 ? (gint64)(MYGINT64_MAX) + (gint64)(b) < (gint64)(a) ? -1 : 0 \ + : (gint64)(MYGINT64_MIN) + (gint64)(b) > (gint64)(a) ? +1 : 0 + +#define CHECK_ADD_OVERFLOW64_UN(a,b) \ + (guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a) ? -1 : 0 + +#define CHECK_SUB_OVERFLOW64_UN(a,b) \ + (guint64)(a) < (guint64)(b) ? -1 : 0 + +#if SIZEOF_VOID_P == 4 +#define CHECK_ADD_OVERFLOW_NAT(a,b) CHECK_ADD_OVERFLOW(a,b) +#define CHECK_ADD_OVERFLOW_NAT_UN(a,b) CHECK_ADD_OVERFLOW_UN(a,b) +#else +#define CHECK_ADD_OVERFLOW_NAT(a,b) CHECK_ADD_OVERFLOW64(a,b) +#define CHECK_ADD_OVERFLOW_NAT_UN(a,b) CHECK_ADD_OVERFLOW64_UN(a,b) +#endif + +/* Resolves to TRUE if the operands would overflow */ +#define CHECK_MUL_OVERFLOW(a,b) \ + ((gint32)(a) == 0) || ((gint32)(b) == 0) ? 0 : \ + (((gint32)(a) > 0) && ((gint32)(b) == -1)) ? FALSE : \ + (((gint32)(a) < 0) && ((gint32)(b) == -1)) ? (a == - MYGINT32_MAX) : \ + (((gint32)(a) > 0) && ((gint32)(b) > 0)) ? (gint32)(a) > ((MYGINT32_MAX) / (gint32)(b)) : \ + (((gint32)(a) > 0) && ((gint32)(b) < 0)) ? (gint32)(a) > ((MYGINT32_MIN) / (gint32)(b)) : \ + (((gint32)(a) < 0) && ((gint32)(b) > 0)) ? (gint32)(a) < ((MYGINT32_MIN) / (gint32)(b)) : \ + (gint32)(a) < ((MYGINT32_MAX) / (gint32)(b)) + +#define CHECK_MUL_OVERFLOW_UN(a,b) \ + ((guint32)(a) == 0) || ((guint32)(b) == 0) ? 0 : \ + (guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a)) + +#define CHECK_MUL_OVERFLOW64(a,b) \ + ((gint64)(a) == 0) || ((gint64)(b) == 0) ? 0 : \ + (((gint64)(a) > 0) && ((gint64)(b) == -1)) ? FALSE : \ + (((gint64)(a) < 0) && ((gint64)(b) == -1)) ? (a == - MYGINT64_MAX) : \ + (((gint64)(a) > 0) && ((gint64)(b) > 0)) ? (gint64)(a) > ((MYGINT64_MAX) / (gint64)(b)) : \ + (((gint64)(a) > 0) && ((gint64)(b) < 0)) ? (gint64)(a) > ((MYGINT64_MIN) / (gint64)(b)) : \ + (((gint64)(a) < 0) && ((gint64)(b) > 0)) ? (gint64)(a) < ((MYGINT64_MIN) / (gint64)(b)) : \ + (gint64)(a) < ((MYGINT64_MAX) / (gint64)(b)) + +#define CHECK_MUL_OVERFLOW64_UN(a,b) \ + ((guint64)(a) == 0) || ((guint64)(b) == 0) ? 0 : \ + (guint64)(b) > ((MYGUINT64_MAX) / (guint64)(a)) + +#if SIZEOF_VOID_P == 4 +#define CHECK_MUL_OVERFLOW_NAT(a,b) CHECK_MUL_OVERFLOW(a,b) +#define CHECK_MUL_OVERFLOW_NAT_UN(a,b) CHECK_MUL_OVERFLOW_UN(a,b) +#else +#define CHECK_MUL_OVERFLOW_NAT(a,b) CHECK_MUL_OVERFLOW64(a,b) +#define CHECK_MUL_OVERFLOW_NAT_UN(a,b) CHECK_MUL_OVERFLOW64_UN(a,b) +#endif + +MonoObject* +mono_interp_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError *error) +{ + MonoInvocation frame; + ThreadContext * volatile context = mono_native_tls_get_value (thread_context_id); + MonoObject *retval = NULL; + MonoMethodSignature *sig = mono_method_signature (method); + MonoClass *klass = mono_class_from_mono_type (sig->ret); + int i, type, isobject = 0; + void *ret = NULL; + stackval result; + stackval *args = alloca (sizeof (stackval) * (sig->param_count + !!sig->hasthis)); + ThreadContext context_struct; + MonoInvocation *old_frame = NULL; + jmp_buf env; + + error_init (error); + + frame.ex = NULL; + + if (setjmp(env)) { + if (context != &context_struct) { + context->domain = mono_domain_get (); + context->current_frame = old_frame; + context->managed_code = 0; + } else + mono_native_tls_set_value (thread_context_id, NULL); + if (exc != NULL) + *exc = (MonoObject *)frame.ex; + return retval; + } + + if (context == NULL) { + context = &context_struct; + context_struct.base_frame = &frame; + context_struct.current_frame = NULL; + context_struct.env_frame = &frame; + context_struct.current_env = &env; + context_struct.search_for_handler = 0; + context_struct.managed_code = 0; + mono_native_tls_set_value (thread_context_id, context); + } + else + old_frame = context->current_frame; + + context->domain = mono_domain_get (); + + switch (sig->ret->type) { + case MONO_TYPE_VOID: + break; + case MONO_TYPE_STRING: + case MONO_TYPE_OBJECT: + case MONO_TYPE_CLASS: + case MONO_TYPE_ARRAY: + case MONO_TYPE_SZARRAY: + isobject = 1; + break; + case MONO_TYPE_VALUETYPE: + retval = mono_object_new_checked (context->domain, klass, error); + ret = ((char*)retval) + sizeof (MonoObject); + if (!sig->ret->data.klass->enumtype) + result.data.vt = ret; + break; + default: + retval = mono_object_new_checked (context->domain, klass, error); + ret = ((char*)retval) + sizeof (MonoObject); + break; + } + + if (sig->hasthis) + args [0].data.p = obj; + + for (i = 0; i < sig->param_count; ++i) { + int a_index = i + !!sig->hasthis; + if (sig->params [i]->byref) { + args [a_index].data.p = params [i]; + continue; + } + type = sig->params [i]->type; +handle_enum: + switch (type) { + case MONO_TYPE_U1: + case MONO_TYPE_I1: + case MONO_TYPE_BOOLEAN: + args [a_index].data.i = *(MonoBoolean*)params [i]; + break; + case MONO_TYPE_U2: + case MONO_TYPE_I2: + case MONO_TYPE_CHAR: + args [a_index].data.i = *(gint16*)params [i]; + break; +#if SIZEOF_VOID_P == 4 + case MONO_TYPE_U: /* use VAL_POINTER? */ + case MONO_TYPE_I: +#endif + case MONO_TYPE_U4: + case MONO_TYPE_I4: + args [a_index].data.i = *(gint32*)params [i]; + break; +#if SIZEOF_VOID_P == 8 + case MONO_TYPE_U: + case MONO_TYPE_I: +#endif + case MONO_TYPE_U8: + case MONO_TYPE_I8: + args [a_index].data.l = *(gint64*)params [i]; + break; + case MONO_TYPE_VALUETYPE: + if (sig->params [i]->data.klass->enumtype) { + type = mono_class_enum_basetype (sig->params [i]->data.klass)->type; + goto handle_enum; + } else { + args [a_index].data.p = params [i]; + } + break; + case MONO_TYPE_STRING: + case MONO_TYPE_CLASS: + case MONO_TYPE_ARRAY: + case MONO_TYPE_SZARRAY: + case MONO_TYPE_OBJECT: + args [a_index].data.p = params [i]; + break; + default: + g_error ("type 0x%x not handled in runtime invoke", sig->params [i]->type); + } + } + + if (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) + method = mono_marshal_get_native_wrapper (method, FALSE, FALSE); + INIT_FRAME (&frame,context->current_frame,args,&result,mono_get_root_domain (),method,error); + if (exc) + frame.invoke_trap = 1; + context->managed_code = 1; + ves_exec_method_with_context (&frame, context); + context->managed_code = 0; + if (context == &context_struct) + mono_native_tls_set_value (thread_context_id, NULL); + else + context->current_frame = old_frame; + if (frame.ex != NULL) { + if (exc != NULL) { + *exc = (MonoObject*) frame.ex; + return NULL; + } + if (context->current_env != NULL) { + context->env_frame->ex = frame.ex; + longjmp(*context->current_env, 1); + } + else + printf("dropped exception...\n"); + } + if (sig->ret->type == MONO_TYPE_VOID && !method->string_ctor) + return NULL; + if (isobject || method->string_ctor) + return result.data.p; + stackval_to_data (sig->ret, &result, ret, sig->pinvoke); + return retval; +} + +static stackval * +do_icall (ThreadContext *context, int op, stackval *sp, gpointer ptr) +{ + MonoInvocation *old_frame = context->current_frame; + MonoInvocation *old_env_frame = context->env_frame; + jmp_buf *old_env = context->current_env; + jmp_buf env; + + if (setjmp (env)) { + context->current_frame = old_frame; + context->env_frame = old_env_frame; + context->current_env = old_env; + context->managed_code = 1; + return sp; + } + + context->env_frame = context->current_frame; + context->current_env = &env; + context->managed_code = 0; + + switch (op) { + case MINT_ICALL_V_V: { + void (*func)() = ptr; + func (); + break; + } + case MINT_ICALL_V_P: { + gpointer (*func)() = ptr; + sp++; + sp [-1].data.p = func (); + break; + } + case MINT_ICALL_P_V: { + void (*func)(gpointer) = ptr; + func (sp [-1].data.p); + sp --; + break; + } + case MINT_ICALL_P_P: { + gpointer (*func)(gpointer) = ptr; + sp [-1].data.p = func (sp [-1].data.p); + break; + } + case MINT_ICALL_PP_V: { + void (*func)(gpointer,gpointer) = ptr; + sp -= 2; + func (sp [0].data.p, sp [1].data.p); + break; + } + case MINT_ICALL_PI_V: { + void (*func)(gpointer,int) = ptr; + sp -= 2; + func (sp [0].data.p, sp [1].data.i); + break; + } + case MINT_ICALL_PP_P: { + gpointer (*func)(gpointer,gpointer) = ptr; + --sp; + sp [-1].data.p = func (sp [-1].data.p, sp [0].data.p); + break; + } + case MINT_ICALL_PI_P: { + gpointer (*func)(gpointer,int) = ptr; + --sp; + sp [-1].data.p = func (sp [-1].data.p, sp [0].data.i); + break; + } + case MINT_ICALL_PPP_V: { + void (*func)(gpointer,gpointer,gpointer) = ptr; + sp -= 3; + func (sp [0].data.p, sp [1].data.p, sp [2].data.p); + break; + } + case MINT_ICALL_PPI_V: { + void (*func)(gpointer,gpointer,int) = ptr; + sp -= 3; + func (sp [0].data.p, sp [1].data.p, sp [2].data.i); + break; + } + default: + g_assert_not_reached (); + } + + context->env_frame = old_env_frame; + context->current_env = old_env; + + return sp; +} + +static mono_mutex_t create_method_pointer_mutex; + +static GHashTable *method_pointer_hash = NULL; + +static MonoMethod *method_pointers [2] = {0}; + +static MonoObject * +mp_tramp_0 (MonoObject *this_obj, void **params, MonoObject **exc, void *compiled_method) { + MonoError error; + void *params_real[] = {this_obj, ¶ms, &exc, &compiled_method}; + MonoObject *ret = mono_interp_runtime_invoke (method_pointers [0], NULL, params_real, NULL, &error); + mono_error_cleanup (&error); /* FIXME: don't swallow the error */ + return ret; +} + +static MonoObject * +mp_tramp_1 (MonoObject *this_obj, void **params, MonoObject **exc, void *compiled_method) { + MonoError error; + void *params_real[] = {this_obj, ¶ms, &exc, &compiled_method}; + MonoObject *ret = mono_interp_runtime_invoke (method_pointers [1], NULL, params_real, NULL, &error); + mono_error_cleanup (&error); /* FIXME: don't swallow the error */ + return ret; +} + +gpointer *mp_tramps[] = {(gpointer) mp_tramp_0, (gpointer) mp_tramp_1}; + +static int tramps_used = 0; + +gpointer +mono_interp_create_method_pointer (MonoMethod *method, MonoError *error) +{ + gpointer addr; + MonoJitInfo *ji; + + mono_os_mutex_lock (&create_method_pointer_mutex); + if (!method_pointer_hash) { + // FIXME: is registering method table as GC root really necessary? + // MONO_GC_REGISTER_ROOT_FIXED (method_pointer_hash); + method_pointer_hash = g_hash_table_new (NULL, NULL); + } + addr = g_hash_table_lookup (method_pointer_hash, method); + if (addr) { + mono_os_mutex_unlock (&create_method_pointer_mutex); + return addr; + } + + /* + * If it is a static P/Invoke method, we can just return the pointer + * to the method implementation. + */ + if (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL && ((MonoMethodPInvoke*) method)->addr) { + ji = g_new0 (MonoJitInfo, 1); + ji->d.method = method; + ji->code_size = 1; + ji->code_start = addr = ((MonoMethodPInvoke*) method)->addr; + + mono_jit_info_table_add (mono_get_root_domain (), ji); + } + else { + g_assert (method->wrapper_type == MONO_WRAPPER_RUNTIME_INVOKE); + g_assert (tramps_used < 2); + + /* FIXME: needs locking */ + method_pointers [tramps_used] = method; + addr = mp_tramps [tramps_used]; + tramps_used++; + } + + g_hash_table_insert (method_pointer_hash, method, addr); + mono_os_mutex_unlock (&create_method_pointer_mutex); + + return addr; +} + +#if COUNT_OPS +static int opcode_counts[512]; + +#define COUNT_OP(op) opcode_counts[op]++ +#else +#define COUNT_OP(op) +#endif + +#if DEBUG_INTERP +#define DUMP_INSTR() \ + if (tracing > 1) { \ + char *ins; \ + if (sp > frame->stack) { \ + ins = dump_stack (frame->stack, sp); \ + } else { \ + ins = g_strdup (""); \ + } \ + sp->data.l = 0; \ + output_indent (); \ + char *mn = mono_method_full_name (frame->runtime_method->method, FALSE); \ + g_print ("(%p) %s -> ", mono_thread_internal_current (), mn); \ + g_free (mn); \ + mono_interp_dis_mintop(rtm->code, ip); \ + g_print ("\t%d:%s\n", vt_sp - vtalloc, ins); \ + g_free (ins); \ + } +#else +#define DUMP_INSTR() +#endif + +#ifdef __GNUC__ +#define USE_COMPUTED_GOTO 1 +#endif +#if USE_COMPUTED_GOTO +#define MINT_IN_SWITCH(op) COUNT_OP(op); goto *in_labels[op]; +#define MINT_IN_CASE(x) LAB_ ## x: +#if DEBUG_INTERP +#define MINT_IN_BREAK if (tracing > 1) goto main_loop; else { COUNT_OP(*ip); goto *in_labels[*ip]; } +#else +#define MINT_IN_BREAK { COUNT_OP(*ip); goto *in_labels[*ip]; } +#endif +#define MINT_IN_DEFAULT mint_default: if (0) goto mint_default; /* make gcc shut up */ +#else +#define MINT_IN_SWITCH(op) switch (op) +#define MINT_IN_CASE(x) case x: +#define MINT_IN_BREAK break +#define MINT_IN_DEFAULT default: +#endif + +/* + * Defining this causes register allocation errors in some versions of gcc: + * error: unable to find a register to spill in class `SIREG' + */ +/* #define MINT_USE_DEDICATED_IP_REG */ + +static void +ves_exec_method_with_context (MonoInvocation *frame, ThreadContext *context) +{ + MonoInvocation child_frame; + GSList *finally_ips = NULL; + const unsigned short *endfinally_ip = NULL; +#if defined(__GNUC__) && defined (i386) && defined (MINT_USE_DEDICATED_IP_REG) + register const unsigned short *ip asm ("%esi"); +#else + register const unsigned short *ip; +#endif + register stackval *sp; + RuntimeMethod *rtm; +#if DEBUG_INTERP + gint tracing = global_tracing; + unsigned char *vtalloc; +#endif + int i32; + unsigned char *vt_sp; + unsigned char *locals; + MonoError error; + MonoObject *o = NULL; + MonoClass *c; +#if USE_COMPUTED_GOTO + static void *in_labels[] = { +#define OPDEF(a,b,c,d) \ + &&LAB_ ## a, +#include "mintops.def" + 0 }; +#endif + + frame->ex = NULL; + frame->ex_handler = NULL; + frame->ip = NULL; + context->current_frame = frame; + +#if DEBUG_INTERP + debug_enter (frame, &tracing); +#endif + + if (!frame->runtime_method->transformed) { + context->managed_code = 0; +#if DEBUG_INTERP + char *mn = mono_method_full_name (frame->runtime_method->method, FALSE); + g_print ("(%p) Transforming %s\n", mono_thread_internal_current (), mn); + g_free (mn); +#endif + frame->ex = mono_interp_transform_method (frame->runtime_method, context); + context->managed_code = 1; + if (frame->ex) { + rtm = NULL; + ip = NULL; + goto exit_frame; + } + } + + rtm = frame->runtime_method; + frame->args = alloca (rtm->alloca_size); + sp = frame->stack = (stackval *)((char *)frame->args + rtm->args_size); +#if DEBUG_INTERP + if (tracing > 1) + memset(sp, 0, rtm->stack_size); +#endif + vt_sp = (unsigned char *) sp + rtm->stack_size; +#if DEBUG_INTERP + vtalloc = vt_sp; +#endif + locals = (unsigned char *) vt_sp + rtm->vt_stack_size; + + child_frame.parent = frame; + + /* ready to go */ + ip = rtm->code; + + /* + * using while (ip < end) may result in a 15% performance drop, + * but it may be useful for debug + */ + while (1) { + main_loop: + /* g_assert (sp >= frame->stack); */ + /* g_assert(vt_sp - vtalloc <= rtm->vt_stack_size); */ + DUMP_INSTR(); + MINT_IN_SWITCH (*ip) { + MINT_IN_CASE(MINT_INITLOCALS) + memset (locals, 0, rtm->locals_size); + ++ip; + MINT_IN_BREAK; + MINT_IN_CASE(MINT_NOP) + ++ip; + MINT_IN_BREAK; + MINT_IN_CASE(MINT_BREAK) + ++ip; + G_BREAKPOINT (); /* this is not portable... */ + MINT_IN_BREAK; + MINT_IN_CASE(MINT_LDNULL) + sp->data.p = NULL; + ++ip; + ++sp; + MINT_IN_BREAK; + MINT_IN_CASE(MINT_VTRESULT) { + int ret_size = * (guint16 *)(ip + 1); + unsigned char *ret_vt_sp = vt_sp; + vt_sp -= READ32(ip + 2); + if (ret_size > 0) { + memmove (vt_sp, ret_vt_sp, ret_size); + sp [-1].data.p = vt_sp; + vt_sp += (ret_size + 7) & ~7; + } + ip += 4; + MINT_IN_BREAK; + } +#define LDC(n) do { sp->data.i = (n); ++ip; ++sp; } while (0) + MINT_IN_CASE(MINT_LDC_I4_M1) + LDC(-1); + MINT_IN_BREAK; + MINT_IN_CASE(MINT_LDC_I4_0) + LDC(0); + MINT_IN_BREAK; + MINT_IN_CASE(MINT_LDC_I4_1) + LDC(1); + MINT_IN_BREAK; + MINT_IN_CASE(MINT_LDC_I4_2) + LDC(2); + MINT_IN_BREAK; + MINT_IN_CASE(MINT_LDC_I4_3) + LDC(3); + MINT_IN_BREAK; + MINT_IN_CASE(MINT_LDC_I4_4) + LDC(4); + MINT_IN_BREAK; + MINT_IN_CASE(MINT_LDC_I4_5) + LDC(5); + MINT_IN_BREAK; + MINT_IN_CASE(MINT_LDC_I4_6) + LDC(6); + MINT_IN_BREAK; + MINT_IN_CASE(MINT_LDC_I4_7) + LDC(7); + MINT_IN_BREAK; + MINT_IN_CASE(MINT_LDC_I4_8) + LDC(8); + MINT_IN_BREAK; + MINT_IN_CASE(MINT_LDC_I4_S) + sp->data.i = *(const short *)(ip + 1); + ip += 2; + ++sp; + MINT_IN_BREAK; + MINT_IN_CASE(MINT_LDC_I4) + ++ip; + sp->data.i = READ32 (ip); + ip += 2; + ++sp; + MINT_IN_BREAK; + MINT_IN_CASE(MINT_LDC_I8) + ++ip; + sp->data.l = READ64 (ip); + ip += 4; + ++sp; + MINT_IN_BREAK; + MINT_IN_CASE(MINT_LDC_R4) { + guint32 val; + ++ip; + val = READ32(ip); + sp->data.f = * (float *)&val; + ip += 2; + ++sp; + MINT_IN_BREAK; + } + MINT_IN_CASE(MINT_LDC_R8) + sp->data.l = READ64 (ip + 1); /* note union usage */ + ip += 5; + ++sp; + MINT_IN_BREAK; + MINT_IN_CASE(MINT_DUP) + sp [0] = sp[-1]; + ++sp; + ++ip; + MINT_IN_BREAK; + MINT_IN_CASE(MINT_DUP_VT) + i32 = READ32 (ip + 1); + sp->data.p = vt_sp; + memcpy(sp->data.p, sp [-1].data.p, i32); + vt_sp += (i32 + 7) & ~7; + ++sp; + ip += 3; + MINT_IN_BREAK; + MINT_IN_CASE(MINT_POP) { + guint16 u16 = (* (guint16 *)(ip + 1)) + 1; + if (u16 > 1) + memmove (sp - u16, sp - 1, (u16 - 1) * sizeof (stackval)); + sp--; + ip += 2; + MINT_IN_BREAK; + } + MINT_IN_CASE(MINT_JMP) { + RuntimeMethod *new_method = rtm->data_items [* (guint16 *)(ip + 1)]; + if (!new_method->transformed) { + frame->ip = ip; + frame->ex = mono_interp_transform_method (new_method, context); + if (frame->ex) + goto exit_frame; + } + ip += 2; + if (new_method->alloca_size > rtm->alloca_size) + g_error ("MINT_JMP to method which needs more stack space (%d > %d)", new_method->alloca_size, rtm->alloca_size); + rtm = frame->runtime_method = new_method; + vt_sp = (unsigned char *) sp + rtm->stack_size; +#if DEBUG_INTERP + vtalloc = vt_sp; +#endif + locals = vt_sp + rtm->vt_stack_size; + ip = rtm->new_body_start; /* bypass storing input args from callers frame */ + MINT_IN_BREAK; + } + MINT_IN_CASE(MINT_CALLI) { + MonoMethodSignature *csignature; + stackval *endsp = sp; + + frame->ip = ip; + + csignature = rtm->data_items [* (guint16 *)(ip + 1)]; + ip += 2; + --sp; + --endsp; + child_frame.runtime_method = sp->data.p; + + sp->data.p = vt_sp; + child_frame.retval = sp; + /* decrement by the actual number of args */ + sp -= csignature->param_count; + if (csignature->hasthis) + --sp; + child_frame.stack_args = sp; + + /* `this' can be NULL for string:.ctor */ + if (csignature->hasthis && sp->data.p && mono_object_is_transparent_proxy (sp->data.p)) { + child_frame.runtime_method = mono_interp_get_runtime_method (context->domain, mono_marshal_get_remoting_invoke (child_frame.runtime_method->method), &error); + mono_error_cleanup (&error); /* FIXME: don't swallow the error */ + } else if (child_frame.runtime_method->method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) { + child_frame.runtime_method = mono_interp_get_runtime_method (context->domain, mono_marshal_get_native_wrapper (child_frame.runtime_method->method, FALSE, FALSE), &error); + mono_error_cleanup (&error); /* FIXME: don't swallow the error */ + } + + if (csignature->hasthis) { + MonoObject *this_arg = sp->data.p; + + if (this_arg->vtable->klass->valuetype) { + gpointer *unboxed = mono_object_unbox (this_arg); + sp [0].data.p = unboxed; + } + } + + ves_exec_method_with_context (&child_frame, context); + + context->current_frame = frame; + + if (child_frame.ex) { + /* + * An exception occurred, need to run finally, fault and catch handlers.. + */ + frame->ex = child_frame.ex; + goto handle_finally; + } + + /* need to handle typedbyref ... */ + if (csignature->ret->type != MONO_TYPE_VOID) { + *sp = *endsp; + sp++; + } + MINT_IN_BREAK; + } + MINT_IN_CASE(MINT_CALLI_NAT) { + MonoMethodSignature *csignature; + stackval *endsp = sp; + unsigned char *code = NULL; + + frame->ip = ip; + + csignature = rtm->data_items [* (guint16 *)(ip + 1)]; + ip += 2; + --sp; + --endsp; + code = sp->data.p; + child_frame.runtime_method = NULL; + + sp->data.p = vt_sp; + child_frame.retval = sp; + /* decrement by the actual number of args */ + sp -= csignature->param_count; + if (csignature->hasthis) + --sp; + child_frame.stack_args = sp; + ves_pinvoke_method (&child_frame, csignature, (MonoFuncV) code, FALSE, context); + + context->current_frame = frame; + + if (child_frame.ex) { + /* + * An exception occurred, need to run finally, fault and catch handlers.. + */ + frame->ex = child_frame.ex; + if (context->search_for_handler) { + context->search_for_handler = 0; + goto handle_exception; + } + goto handle_finally; + } + + /* need to handle typedbyref ... */ + if (csignature->ret->type != MONO_TYPE_VOID) { + *sp = *endsp; + sp++; + } + MINT_IN_BREAK; + } + MINT_IN_CASE(MINT_CALL) { + stackval *endsp = sp; + + frame->ip = ip; + + child_frame.runtime_method = rtm->data_items [* (guint16 *)(ip + 1)]; + ip += 2; + sp->data.p = vt_sp; + child_frame.retval = sp; + /* decrement by the actual number of args */ + sp -= child_frame.runtime_method->param_count; + if (child_frame.runtime_method->hasthis) + --sp; + child_frame.stack_args = sp; + + /* `this' can be NULL for string:.ctor */ + if (child_frame.runtime_method->hasthis && !child_frame.runtime_method->method->klass->valuetype && sp->data.p && mono_object_is_transparent_proxy (sp->data.p)) { + child_frame.runtime_method = mono_interp_get_runtime_method (context->domain, mono_marshal_get_remoting_invoke (child_frame.runtime_method->method), &error); + mono_error_cleanup (&error); /* FIXME: don't swallow the error */ + } + ves_exec_method_with_context (&child_frame, context); + + context->current_frame = frame; + + if (child_frame.ex) { + /* + * An exception occurred, need to run finally, fault and catch handlers.. + */ + frame->ex = child_frame.ex; + goto handle_finally; + } + + /* need to handle typedbyref ... */ + *sp = *endsp; + sp++; + MINT_IN_BREAK; + } + MINT_IN_CASE(MINT_VCALL) { + frame->ip = ip; + + child_frame.runtime_method = rtm->data_items [* (guint16 *)(ip + 1)]; + ip += 2; + + sp->data.p = vt_sp; + child_frame.retval = sp; + /* decrement by the actual number of args */ + sp -= child_frame.runtime_method->param_count; + if (child_frame.runtime_method->hasthis) + --sp; + child_frame.stack_args = sp; + + if (child_frame.runtime_method->hasthis && !child_frame.runtime_method->method->klass->valuetype && mono_object_is_transparent_proxy (sp->data.p)) { + child_frame.runtime_method = mono_interp_get_runtime_method (context->domain, mono_marshal_get_remoting_invoke (child_frame.runtime_method->method), &error); + mono_error_cleanup (&error); /* FIXME: don't swallow the error */ + } + + ves_exec_method_with_context (&child_frame, context); + + context->current_frame = frame; + + if (child_frame.ex) { + /* + * An exception occurred, need to run finally, fault and catch handlers.. + */ + frame->ex = child_frame.ex; + goto handle_finally; + } + MINT_IN_BREAK; + } + MINT_IN_CASE(MINT_CALLVIRT) { + stackval *endsp = sp; + MonoObject *this_arg; + guint32 token; + + frame->ip = ip; + + token = * (unsigned short *)(ip + 1); + ip += 2; + child_frame.runtime_method = rtm->data_items [token]; + sp->data.p = vt_sp; + child_frame.retval = sp; + + /* decrement by the actual number of args */ + sp -= child_frame.runtime_method->param_count + 1; + child_frame.stack_args = sp; + this_arg = sp->data.p; + if (!this_arg) + THROW_EX (mono_get_exception_null_reference(), ip - 2); + child_frame.runtime_method = get_virtual_method (context->domain, child_frame.runtime_method, this_arg); + + MonoClass *this_class = this_arg->vtable->klass; + if (this_class->valuetype && child_frame.runtime_method->method->klass->valuetype) { + /* unbox */ + gpointer *unboxed = mono_object_unbox (this_arg); + sp [0].data.p = unboxed; + } + + ves_exec_method_with_context (&child_frame, context); + + context->current_frame = frame; + + if (child_frame.ex) { + /* + * An exception occurred, need to run finally, fault and catch handlers.. + */ + frame->ex = child_frame.ex; + if (context->search_for_handler) { + context->search_for_handler = 0; + goto handle_exception; + } + goto handle_finally; + } + + /* need to handle typedbyref ... */ + *sp = *endsp; + sp++; + MINT_IN_BREAK; + } + MINT_IN_CASE(MINT_VCALLVIRT) { + MonoObject *this_arg; + guint32 token; + + frame->ip = ip; + + token = * (unsigned short *)(ip + 1); + ip += 2; + child_frame.runtime_method = rtm->data_items [token]; + sp->data.p = vt_sp; + child_frame.retval = sp; + + /* decrement by the actual number of args */ + sp -= child_frame.runtime_method->param_count + 1; + child_frame.stack_args = sp; + this_arg = sp->data.p; + if (!this_arg) + THROW_EX (mono_get_exception_null_reference(), ip - 2); + child_frame.runtime_method = get_virtual_method (context->domain, child_frame.runtime_method, this_arg); + + MonoClass *this_class = this_arg->vtable->klass; + if (this_class->valuetype && child_frame.runtime_method->method->klass->valuetype) { + gpointer *unboxed = mono_object_unbox (this_arg); + sp [0].data.p = unboxed; + } + + ves_exec_method_with_context (&child_frame, context); + + context->current_frame = frame; + + if (child_frame.ex) { + /* + * An exception occurred, need to run finally, fault and catch handlers.. + */ + frame->ex = child_frame.ex; + if (context->search_for_handler) { + context->search_for_handler = 0; + goto handle_exception; + } + goto handle_finally; + } + MINT_IN_BREAK; + } + MINT_IN_CASE(MINT_CALLRUN) + ves_runtime_method (frame, context); + if (frame->ex) { + rtm = NULL; + goto handle_exception; + } + goto exit_frame; + MINT_IN_CASE(MINT_RET) + --sp; + *frame->retval = *sp; + if (sp > frame->stack) + g_warning ("ret: more values on stack: %d", sp-frame->stack); + goto exit_frame; + MINT_IN_CASE(MINT_RET_VOID) + if (sp > frame->stack) + g_warning ("ret.void: more values on stack: %d", sp-frame->stack); + goto exit_frame; + MINT_IN_CASE(MINT_RET_VT) + i32 = READ32(ip + 1); + --sp; + memcpy(frame->retval->data.p, sp->data.p, i32); + if (sp > frame->stack) + g_warning ("ret.vt: more values on stack: %d", sp-frame->stack); + goto exit_frame; + MINT_IN_CASE(MINT_BR_S) + ip += (short) *(ip + 1); + MINT_IN_BREAK; + MINT_IN_CASE(MINT_BR) + ip += (gint32) READ32(ip + 1); + MINT_IN_BREAK; +#define ZEROP_S(datamem, op) \ + --sp; \ + if (sp->data.datamem op 0) \ + ip += * (gint16 *)(ip + 1); \ + else \ + ip += 2; + +#define ZEROP(datamem, op) \ + --sp; \ + if (sp->data.datamem op 0) \ + ip += READ32(ip + 1); \ + else \ + ip += 3; + + MINT_IN_CASE(MINT_BRFALSE_I4_S) + ZEROP_S(i, ==); + MINT_IN_BREAK; + MINT_IN_CASE(MINT_BRFALSE_I8_S) + ZEROP_S(l, ==); + MINT_IN_BREAK; + MINT_IN_CASE(MINT_BRFALSE_R8_S) + ZEROP_S(f, ==); + MINT_IN_BREAK; + MINT_IN_CASE(MINT_BRFALSE_I4) + ZEROP(i, ==); + MINT_IN_BREAK; + MINT_IN_CASE(MINT_BRFALSE_I8) + ZEROP(l, ==); + MINT_IN_BREAK; + MINT_IN_CASE(MINT_BRFALSE_R8) + ZEROP_S(f, ==); + MINT_IN_BREAK; + MINT_IN_CASE(MINT_BRTRUE_I4_S) + ZEROP_S(i, !=); + MINT_IN_BREAK; + MINT_IN_CASE(MINT_BRTRUE_I8_S) + ZEROP_S(l, !=); + MINT_IN_BREAK; + MINT_IN_CASE(MINT_BRTRUE_R8_S) + ZEROP_S(f, !=); + MINT_IN_BREAK; + MINT_IN_CASE(MINT_BRTRUE_I4) + ZEROP(i, !=); + MINT_IN_BREAK; + MINT_IN_CASE(MINT_BRTRUE_I8) + ZEROP(l, !=); + MINT_IN_BREAK; + MINT_IN_CASE(MINT_BRTRUE_R8) + ZEROP(f, !=); + MINT_IN_BREAK; +#define CONDBR_S(cond) \ + sp -= 2; \ + if (cond) \ + ip += * (gint16 *)(ip + 1); \ + else \ + ip += 2; +#define BRELOP_S(datamem, op) \ + CONDBR_S(sp[0].data.datamem op sp[1].data.datamem) + +#define CONDBR(cond) \ + sp -= 2; \ + if (cond) \ + ip += READ32(ip + 1); \ + else \ + ip += 3; + +#define BRELOP(datamem, op) \ + CONDBR(sp[0].data.datamem op sp[1].data.datamem) + + MINT_IN_CASE(MINT_BEQ_I4_S) + BRELOP_S(i, ==) + MINT_IN_BREAK; + MINT_IN_CASE(MINT_BEQ_I8_S) + BRELOP_S(l, ==) + MINT_IN_BREAK; + MINT_IN_CASE(MINT_BEQ_R8_S) + CONDBR_S(!isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f == sp[1].data.f) + MINT_IN_BREAK; + MINT_IN_CASE(MINT_BEQ_I4) + BRELOP(i, ==) + MINT_IN_BREAK; + MINT_IN_CASE(MINT_BEQ_I8) + BRELOP(l, ==) + MINT_IN_BREAK; + MINT_IN_CASE(MINT_BEQ_R8) + CONDBR(!isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f == sp[1].data.f) + MINT_IN_BREAK; + MINT_IN_CASE(MINT_BGE_I4_S) + BRELOP_S(i, >=) + MINT_IN_BREAK; + MINT_IN_CASE(MINT_BGE_I8_S) + BRELOP_S(l, >=) + MINT_IN_BREAK; + MINT_IN_CASE(MINT_BGE_R8_S) + CONDBR_S(!isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f >= sp[1].data.f) + MINT_IN_BREAK; + MINT_IN_CASE(MINT_BGE_I4) + BRELOP(i, >=) + MINT_IN_BREAK; + MINT_IN_CASE(MINT_BGE_I8) + BRELOP(l, >=) + MINT_IN_BREAK; + MINT_IN_CASE(MINT_BGE_R8) + CONDBR(!isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f >= sp[1].data.f) + MINT_IN_BREAK; + MINT_IN_CASE(MINT_BGT_I4_S) + BRELOP_S(i, >) + MINT_IN_BREAK; + MINT_IN_CASE(MINT_BGT_I8_S) + BRELOP_S(l, >) + MINT_IN_BREAK; + MINT_IN_CASE(MINT_BGT_R8_S) + CONDBR_S(!isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f > sp[1].data.f) + MINT_IN_BREAK; + MINT_IN_CASE(MINT_BGT_I4) + BRELOP(i, >) + MINT_IN_BREAK; + MINT_IN_CASE(MINT_BGT_I8) + BRELOP(l, >) + MINT_IN_BREAK; + MINT_IN_CASE(MINT_BGT_R8) + CONDBR(!isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f > sp[1].data.f) + MINT_IN_BREAK; + MINT_IN_CASE(MINT_BLT_I4_S) + BRELOP_S(i, <) + MINT_IN_BREAK; + MINT_IN_CASE(MINT_BLT_I8_S) + BRELOP_S(l, <) + MINT_IN_BREAK; + MINT_IN_CASE(MINT_BLT_R8_S) + CONDBR_S(!isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f < sp[1].data.f) + MINT_IN_BREAK; + MINT_IN_CASE(MINT_BLT_I4) + BRELOP(i, <) + MINT_IN_BREAK; + MINT_IN_CASE(MINT_BLT_I8) + BRELOP(l, <) + MINT_IN_BREAK; + MINT_IN_CASE(MINT_BLT_R8) + CONDBR(!isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f < sp[1].data.f) + MINT_IN_BREAK; + MINT_IN_CASE(MINT_BLE_I4_S) + BRELOP_S(i, <=) + MINT_IN_BREAK; + MINT_IN_CASE(MINT_BLE_I8_S) + BRELOP_S(l, <=) + MINT_IN_BREAK; + MINT_IN_CASE(MINT_BLE_R8_S) + CONDBR_S(!isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f <= sp[1].data.f) + MINT_IN_BREAK; + MINT_IN_CASE(MINT_BLE_I4) + BRELOP(i, <=) + MINT_IN_BREAK; + MINT_IN_CASE(MINT_BLE_I8) + BRELOP(l, <=) + MINT_IN_BREAK; + MINT_IN_CASE(MINT_BLE_R8) + CONDBR(!isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f <= sp[1].data.f) + MINT_IN_BREAK; + MINT_IN_CASE(MINT_BNE_UN_I4_S) + BRELOP_S(i, !=) + MINT_IN_BREAK; + MINT_IN_CASE(MINT_BNE_UN_I8_S) + BRELOP_S(l, !=) + MINT_IN_BREAK; + MINT_IN_CASE(MINT_BNE_UN_R8_S) + CONDBR_S(isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f != sp[1].data.f) + MINT_IN_BREAK; + MINT_IN_CASE(MINT_BNE_UN_I4) + BRELOP(i, !=) + MINT_IN_BREAK; + MINT_IN_CASE(MINT_BNE_UN_I8) + BRELOP(l, !=) + MINT_IN_BREAK; + MINT_IN_CASE(MINT_BNE_UN_R8) + CONDBR(isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f != sp[1].data.f) + MINT_IN_BREAK; + +#define BRELOP_S_CAST(datamem, op, type) \ + sp -= 2; \ + if ((type) sp[0].data.datamem op (type) sp[1].data.datamem) \ + ip += * (gint16 *)(ip + 1); \ + else \ + ip += 2; + +#define BRELOP_CAST(datamem, op, type) \ + sp -= 2; \ + if ((type) sp[0].data.datamem op (type) sp[1].data.datamem) \ + ip += READ32(ip + 1); \ + else \ + ip += 3; + + MINT_IN_CASE(MINT_BGE_UN_I4_S) + BRELOP_S_CAST(i, >=, guint32); + MINT_IN_BREAK; + MINT_IN_CASE(MINT_BGE_UN_I8_S) + BRELOP_S_CAST(l, >=, guint64); + MINT_IN_BREAK; + MINT_IN_CASE(MINT_BGE_UN_R8_S) + CONDBR_S(isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f >= sp[1].data.f) + MINT_IN_BREAK; + MINT_IN_CASE(MINT_BGE_UN_I4) + BRELOP_CAST(i, >=, guint32); + MINT_IN_BREAK; + MINT_IN_CASE(MINT_BGE_UN_I8) + BRELOP_CAST(l, >=, guint64); + MINT_IN_BREAK; + MINT_IN_CASE(MINT_BGE_UN_R8) + CONDBR(isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f >= sp[1].data.f) + MINT_IN_BREAK; + MINT_IN_CASE(MINT_BGT_UN_I4_S) + BRELOP_S_CAST(i, >, guint32); + MINT_IN_BREAK; + MINT_IN_CASE(MINT_BGT_UN_I8_S) + BRELOP_S_CAST(l, >, guint64); + MINT_IN_BREAK; + MINT_IN_CASE(MINT_BGT_UN_R8_S) + CONDBR_S(isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f > sp[1].data.f) + MINT_IN_BREAK; + MINT_IN_CASE(MINT_BGT_UN_I4) + BRELOP_CAST(i, >, guint32); + MINT_IN_BREAK; + MINT_IN_CASE(MINT_BGT_UN_I8) + BRELOP_CAST(l, >, guint64); + MINT_IN_BREAK; + MINT_IN_CASE(MINT_BGT_UN_R8) + CONDBR(isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f > sp[1].data.f) + MINT_IN_BREAK; + MINT_IN_CASE(MINT_BLE_UN_I4_S) + BRELOP_S_CAST(i, <=, guint32); + MINT_IN_BREAK; + MINT_IN_CASE(MINT_BLE_UN_I8_S) + BRELOP_S_CAST(l, <=, guint64); + MINT_IN_BREAK; + MINT_IN_CASE(MINT_BLE_UN_R8_S) + CONDBR_S(isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f <= sp[1].data.f) + MINT_IN_BREAK; + MINT_IN_CASE(MINT_BLE_UN_I4) + BRELOP_CAST(i, <=, guint32); + MINT_IN_BREAK; + MINT_IN_CASE(MINT_BLE_UN_I8) + BRELOP_CAST(l, <=, guint64); + MINT_IN_BREAK; + MINT_IN_CASE(MINT_BLE_UN_R8) + CONDBR(isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f <= sp[1].data.f) + MINT_IN_BREAK; + MINT_IN_CASE(MINT_BLT_UN_I4_S) + BRELOP_S_CAST(i, <, guint32); + MINT_IN_BREAK; + MINT_IN_CASE(MINT_BLT_UN_I8_S) + BRELOP_S_CAST(l, <, guint64); + MINT_IN_BREAK; + MINT_IN_CASE(MINT_BLT_UN_R8_S) + CONDBR_S(isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f < sp[1].data.f) + MINT_IN_BREAK; + MINT_IN_CASE(MINT_BLT_UN_I4) + BRELOP_CAST(i, <, guint32); + MINT_IN_BREAK; + MINT_IN_CASE(MINT_BLT_UN_I8) + BRELOP_CAST(l, <, guint64); + MINT_IN_BREAK; + MINT_IN_CASE(MINT_BLT_UN_R8) + CONDBR(isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f < sp[1].data.f) + MINT_IN_BREAK; + MINT_IN_CASE(MINT_SWITCH) { + guint32 n; + const unsigned short *st; + ++ip; + n = READ32 (ip); + ip += 2; + st = ip + 2 * n; + --sp; + if ((guint32)sp->data.i < n) { + gint offset; + ip += 2 * (guint32)sp->data.i; + offset = READ32 (ip); + ip = st + offset; + } else { + ip = st; + } + MINT_IN_BREAK; + } + MINT_IN_CASE(MINT_LDIND_I1) + ++ip; + sp[-1].data.i = *(gint8*)sp[-1].data.p; + MINT_IN_BREAK; + MINT_IN_CASE(MINT_LDIND_U1) + ++ip; + sp[-1].data.i = *(guint8*)sp[-1].data.p; + MINT_IN_BREAK; + MINT_IN_CASE(MINT_LDIND_I2) + ++ip; + sp[-1].data.i = *(gint16*)sp[-1].data.p; + MINT_IN_BREAK; + MINT_IN_CASE(MINT_LDIND_U2) + ++ip; + sp[-1].data.i = *(guint16*)sp[-1].data.p; + MINT_IN_BREAK; + MINT_IN_CASE(MINT_LDIND_I4) /* Fall through */ + MINT_IN_CASE(MINT_LDIND_U4) + ++ip; + sp[-1].data.i = *(gint32*)sp[-1].data.p; + MINT_IN_BREAK; + MINT_IN_CASE(MINT_LDIND_I8) + ++ip; + sp[-1].data.l = *(gint64*)sp[-1].data.p; + MINT_IN_BREAK; + MINT_IN_CASE(MINT_LDIND_I) { + guint16 offset = * (guint16 *)(ip + 1); + sp[-1 - offset].data.p = *(gpointer*)sp[-1 - offset].data.p; + ip += 2; + MINT_IN_BREAK; + } + MINT_IN_CASE(MINT_LDIND_R4) + ++ip; + sp[-1].data.f = *(gfloat*)sp[-1].data.p; + MINT_IN_BREAK; + MINT_IN_CASE(MINT_LDIND_R8) + ++ip; + sp[-1].data.f = *(gdouble*)sp[-1].data.p; + MINT_IN_BREAK; + MINT_IN_CASE(MINT_LDIND_REF) + ++ip; + sp[-1].data.p = *(gpointer*)sp[-1].data.p; + MINT_IN_BREAK; + MINT_IN_CASE(MINT_STIND_REF) + ++ip; + sp -= 2; + * (gpointer *) sp->data.p = sp[1].data.p; + MINT_IN_BREAK; + MINT_IN_CASE(MINT_STIND_I1) + ++ip; + sp -= 2; + * (gint8 *) sp->data.p = (gint8)sp[1].data.i; + MINT_IN_BREAK; + MINT_IN_CASE(MINT_STIND_I2) + ++ip; + sp -= 2; + * (gint16 *) sp->data.p = (gint16)sp[1].data.i; + MINT_IN_BREAK; + MINT_IN_CASE(MINT_STIND_I4) + ++ip; + sp -= 2; + * (gint32 *) sp->data.p = sp[1].data.i; + MINT_IN_BREAK; + MINT_IN_CASE(MINT_STIND_I) + ++ip; + sp -= 2; + * (mono_i *) sp->data.p = (mono_i)sp[1].data.p; + MINT_IN_BREAK; + MINT_IN_CASE(MINT_STIND_I8) + ++ip; + sp -= 2; + * (gint64 *) sp->data.p = sp[1].data.l; + MINT_IN_BREAK; + MINT_IN_CASE(MINT_STIND_R4) + ++ip; + sp -= 2; + * (float *) sp->data.p = (gfloat)sp[1].data.f; + MINT_IN_BREAK; + MINT_IN_CASE(MINT_STIND_R8) + ++ip; + sp -= 2; + * (double *) sp->data.p = sp[1].data.f; + MINT_IN_BREAK; +#define BINOP(datamem, op) \ + --sp; \ + sp [-1].data.datamem = sp [-1].data.datamem op sp [0].data.datamem; \ + ++ip; + MINT_IN_CASE(MINT_ADD_I4) + BINOP(i, +); + MINT_IN_BREAK; + MINT_IN_CASE(MINT_ADD_I8) + BINOP(l, +); + MINT_IN_BREAK; + MINT_IN_CASE(MINT_ADD_R8) + BINOP(f, +); + MINT_IN_BREAK; + MINT_IN_CASE(MINT_ADD1_I4) + ++sp [-1].data.i; + ++ip; + MINT_IN_BREAK; + MINT_IN_CASE(MINT_SUB_I4) + BINOP(i, -); + MINT_IN_BREAK; + MINT_IN_CASE(MINT_SUB_I8) + BINOP(l, -); + MINT_IN_BREAK; + MINT_IN_CASE(MINT_SUB_R8) + BINOP(f, -); + MINT_IN_BREAK; + MINT_IN_CASE(MINT_SUB1_I4) + --sp [-1].data.i; + ++ip; + MINT_IN_BREAK; + MINT_IN_CASE(MINT_MUL_I4) + BINOP(i, *); + MINT_IN_BREAK; + MINT_IN_CASE(MINT_MUL_I8) + BINOP(l, *); + MINT_IN_BREAK; + MINT_IN_CASE(MINT_MUL_R8) + BINOP(f, *); + MINT_IN_BREAK; + MINT_IN_CASE(MINT_DIV_I4) + if (sp [-1].data.i == 0) + THROW_EX (mono_get_exception_divide_by_zero (), ip); + if (sp [-1].data.i == (-1)) + THROW_EX (mono_get_exception_overflow (), ip); + BINOP(i, /); + MINT_IN_BREAK; + MINT_IN_CASE(MINT_DIV_I8) + if (sp [-1].data.l == 0) + THROW_EX (mono_get_exception_divide_by_zero (), ip); + if (sp [-1].data.l == (-1)) + THROW_EX (mono_get_exception_overflow (), ip); + BINOP(l, /); + MINT_IN_BREAK; + MINT_IN_CASE(MINT_DIV_R8) + BINOP(f, /); + MINT_IN_BREAK; + +#define BINOP_CAST(datamem, op, type) \ + --sp; \ + sp [-1].data.datamem = (type)sp [-1].data.datamem op (type)sp [0].data.datamem; \ + ++ip; + MINT_IN_CASE(MINT_DIV_UN_I4) + if (sp [-1].data.i == 0) + THROW_EX (mono_get_exception_divide_by_zero (), ip); + BINOP_CAST(i, /, guint32); + MINT_IN_BREAK; + MINT_IN_CASE(MINT_DIV_UN_I8) + if (sp [-1].data.l == 0) + THROW_EX (mono_get_exception_divide_by_zero (), ip); + BINOP_CAST(l, /, guint64); + MINT_IN_BREAK; + MINT_IN_CASE(MINT_REM_I4) + if (sp [-1].data.i == 0) + THROW_EX (mono_get_exception_divide_by_zero (), ip); + BINOP(i, %); + MINT_IN_BREAK; + MINT_IN_CASE(MINT_REM_I8) + if (sp [-1].data.l == 0) + THROW_EX (mono_get_exception_divide_by_zero (), ip); + BINOP(l, %); + MINT_IN_BREAK; + MINT_IN_CASE(MINT_REM_R8) + /* FIXME: what do we actually do here? */ + --sp; + sp [-1].data.f = fmod (sp [-1].data.f, sp [0].data.f); + ++ip; + MINT_IN_BREAK; + MINT_IN_CASE(MINT_REM_UN_I4) + if (sp [-1].data.i == 0) + THROW_EX (mono_get_exception_divide_by_zero (), ip); + BINOP_CAST(i, %, guint32); + MINT_IN_BREAK; + MINT_IN_CASE(MINT_REM_UN_I8) + if (sp [-1].data.l == 0) + THROW_EX (mono_get_exception_divide_by_zero (), ip); + BINOP_CAST(l, %, guint64); + MINT_IN_BREAK; + MINT_IN_CASE(MINT_AND_I4) + BINOP(i, &); + MINT_IN_BREAK; + MINT_IN_CASE(MINT_AND_I8) + BINOP(l, &); + MINT_IN_BREAK; + MINT_IN_CASE(MINT_OR_I4) + BINOP(i, |); + MINT_IN_BREAK; + MINT_IN_CASE(MINT_OR_I8) + BINOP(l, |); + MINT_IN_BREAK; + MINT_IN_CASE(MINT_XOR_I4) + BINOP(i, ^); + MINT_IN_BREAK; + MINT_IN_CASE(MINT_XOR_I8) + BINOP(l, ^); + MINT_IN_BREAK; + +#define SHIFTOP(datamem, op) \ + --sp; \ + sp [-1].data.datamem = sp [-1].data.datamem op sp [0].data.i; \ + ++ip; + + MINT_IN_CASE(MINT_SHL_I4) + SHIFTOP(i, <<); + MINT_IN_BREAK; + MINT_IN_CASE(MINT_SHL_I8) + SHIFTOP(l, <<); + MINT_IN_BREAK; + MINT_IN_CASE(MINT_SHR_I4) + SHIFTOP(i, >>); + MINT_IN_BREAK; + MINT_IN_CASE(MINT_SHR_I8) + SHIFTOP(l, >>); + MINT_IN_BREAK; + MINT_IN_CASE(MINT_SHR_UN_I4) + --sp; + sp [-1].data.i = (guint32)sp [-1].data.i >> sp [0].data.i; + ++ip; + MINT_IN_BREAK; + MINT_IN_CASE(MINT_SHR_UN_I8) + --sp; + sp [-1].data.l = (guint64)sp [-1].data.l >> sp [0].data.i; + ++ip; + MINT_IN_BREAK; + MINT_IN_CASE(MINT_NEG_I4) + sp [-1].data.i = - sp [-1].data.i; + ++ip; + MINT_IN_BREAK; + MINT_IN_CASE(MINT_NEG_I8) + sp [-1].data.l = - sp [-1].data.l; + ++ip; + MINT_IN_BREAK; + MINT_IN_CASE(MINT_NEG_R8) + sp [-1].data.f = - sp [-1].data.f; + ++ip; + MINT_IN_BREAK; + MINT_IN_CASE(MINT_NOT_I4) + sp [-1].data.i = ~ sp [-1].data.i; + ++ip; + MINT_IN_BREAK; + MINT_IN_CASE(MINT_NOT_I8) + sp [-1].data.l = ~ sp [-1].data.l; + ++ip; + MINT_IN_BREAK; + MINT_IN_CASE(MINT_CONV_I1_I4) + sp [-1].data.i = (gint8)sp [-1].data.i; + ++ip; + MINT_IN_BREAK; + MINT_IN_CASE(MINT_CONV_I1_I8) + sp [-1].data.i = (gint8)sp [-1].data.l; + ++ip; + MINT_IN_BREAK; + MINT_IN_CASE(MINT_CONV_I1_R8) + sp [-1].data.i = (gint8)sp [-1].data.f; + ++ip; + MINT_IN_BREAK; + MINT_IN_CASE(MINT_CONV_U1_I4) + sp [-1].data.i = (guint8)sp [-1].data.i; + ++ip; + MINT_IN_BREAK; + MINT_IN_CASE(MINT_CONV_U1_I8) + sp [-1].data.i = (guint8)sp [-1].data.l; + ++ip; + MINT_IN_BREAK; + MINT_IN_CASE(MINT_CONV_U1_R8) + sp [-1].data.i = (guint8)sp [-1].data.f; + ++ip; + MINT_IN_BREAK; + MINT_IN_CASE(MINT_CONV_I2_I4) + sp [-1].data.i = (gint16)sp [-1].data.i; + ++ip; + MINT_IN_BREAK; + MINT_IN_CASE(MINT_CONV_I2_I8) + sp [-1].data.i = (gint16)sp [-1].data.l; + ++ip; + MINT_IN_BREAK; + MINT_IN_CASE(MINT_CONV_I2_R8) + sp [-1].data.i = (gint16)sp [-1].data.f; + ++ip; + MINT_IN_BREAK; + MINT_IN_CASE(MINT_CONV_U2_I4) + sp [-1].data.i = (guint16)sp [-1].data.i; + ++ip; + MINT_IN_BREAK; + MINT_IN_CASE(MINT_CONV_U2_I8) + sp [-1].data.i = (guint16)sp [-1].data.l; + ++ip; + MINT_IN_BREAK; + MINT_IN_CASE(MINT_CONV_U2_R8) + sp [-1].data.i = (guint16)sp [-1].data.f; + ++ip; + MINT_IN_BREAK; + MINT_IN_CASE(MINT_CONV_I4_R8) + sp [-1].data.i = (gint32)sp [-1].data.f; + ++ip; + MINT_IN_BREAK; + MINT_IN_CASE(MINT_CONV_U4_I8) + MINT_IN_CASE(MINT_CONV_I4_I8) + sp [-1].data.i = (gint32)sp [-1].data.l; + ++ip; + MINT_IN_BREAK; + MINT_IN_CASE(MINT_CONV_I4_I8_SP) + sp [-2].data.i = (gint32)sp [-2].data.l; + ++ip; + MINT_IN_BREAK; + MINT_IN_CASE(MINT_CONV_U4_R8) + sp [-1].data.i = (guint32)sp [-1].data.f; + ++ip; + MINT_IN_BREAK; + MINT_IN_CASE(MINT_CONV_I8_I4) + sp [-1].data.l = sp [-1].data.i; + ++ip; + MINT_IN_BREAK; + MINT_IN_CASE(MINT_CONV_I8_I4_SP) + sp [-2].data.l = sp [-2].data.i; + ++ip; + MINT_IN_BREAK; + MINT_IN_CASE(MINT_CONV_I8_U4) + sp [-1].data.l = (guint32)sp [-1].data.i; + ++ip; + MINT_IN_BREAK; + MINT_IN_CASE(MINT_CONV_I8_R8) + sp [-1].data.l = (gint64)sp [-1].data.f; + ++ip; + MINT_IN_BREAK; + MINT_IN_CASE(MINT_CONV_R4_I4) + sp [-1].data.f = (float)sp [-1].data.i; + ++ip; + MINT_IN_BREAK; + MINT_IN_CASE(MINT_CONV_R4_I8) + sp [-1].data.f = (float)sp [-1].data.l; + ++ip; + MINT_IN_BREAK; + MINT_IN_CASE(MINT_CONV_R4_R8) + sp [-1].data.f = (float)sp [-1].data.f; + ++ip; + MINT_IN_BREAK; + MINT_IN_CASE(MINT_CONV_R8_I4) + sp [-1].data.f = (double)sp [-1].data.i; + ++ip; + MINT_IN_BREAK; + MINT_IN_CASE(MINT_CONV_R8_I8) + sp [-1].data.f = (double)sp [-1].data.l; + ++ip; + MINT_IN_BREAK; + MINT_IN_CASE(MINT_CONV_U8_I4) + sp [-1].data.l = sp [-1].data.i & 0xffffffff; + ++ip; + MINT_IN_BREAK; + MINT_IN_CASE(MINT_CONV_U8_R8) + sp [-1].data.l = (guint64)sp [-1].data.f; + ++ip; + MINT_IN_BREAK; +#if 0 + MINT_IN_CASE(MINT_CPOBJ) { + MonoClass *vtklass; + ++ip; + vtklass = rtm->data_items[READ32 (ip)]; + ip += 2; + sp -= 2; + memcpy (sp [0].data.p, sp [1].data.p, mono_class_value_size (vtklass, NULL)); + MINT_IN_BREAK; + } +#endif + MINT_IN_CASE(MINT_LDOBJ) { + int size; + void *p; + c = rtm->data_items[* (guint16 *)(ip + 1)]; + ip += 2; + if (c->byval_arg.type != MONO_TYPE_VALUETYPE || c->byval_arg.data.klass->enumtype) { + p = sp [-1].data.p; + stackval_from_data (&c->byval_arg, &sp [-1], p, FALSE); + } else { + size = mono_class_value_size (c, NULL); + p = sp [-1].data.p; + sp [-1].data.p = vt_sp; + memcpy(vt_sp, p, size); + vt_sp += (size + 7) & ~7; + } + MINT_IN_BREAK; + } + MINT_IN_CASE(MINT_LDSTR) + sp->data.p = rtm->data_items [* (guint16 *)(ip + 1)]; + ++sp; + ip += 2; + MINT_IN_BREAK; + MINT_IN_CASE(MINT_NEWOBJ) { + MonoClass *newobj_class; + MonoMethodSignature *csig; + stackval valuetype_this; + guint32 token; + stackval retval; + + frame->ip = ip; + + token = * (guint16 *)(ip + 1); + ip += 2; + + child_frame.runtime_method = rtm->data_items [token]; + csig = mono_method_signature (child_frame.runtime_method->method); + newobj_class = child_frame.runtime_method->method->klass; + /*if (profiling_classes) { + guint count = GPOINTER_TO_UINT (g_hash_table_lookup (profiling_classes, newobj_class)); + count++; + g_hash_table_insert (profiling_classes, newobj_class, GUINT_TO_POINTER (count)); + }*/ + + if (newobj_class->parent == mono_defaults.array_class) { + sp -= csig->param_count; + o = ves_array_create (context->domain, newobj_class, csig, sp); + goto array_constructed; + } + + g_assert (csig->hasthis); + if (csig->param_count) { + sp -= csig->param_count; + memmove (sp + 1, sp, csig->param_count * sizeof (stackval)); + } + child_frame.stack_args = sp; + + /* + * First arg is the object. + */ + if (newobj_class->valuetype) { + MonoType *t = &newobj_class->byval_arg; + if (!newobj_class->enumtype && (t->type == MONO_TYPE_VALUETYPE || (t->type == MONO_TYPE_GENERICINST && mono_type_generic_inst_is_valuetype (t)))) { + sp->data.p = vt_sp; + valuetype_this.data.p = vt_sp; + } else { + memset (&valuetype_this, 0, sizeof (stackval)); + sp->data.p = &valuetype_this; + } + } else { + if (newobj_class != mono_defaults.string_class) { + context->managed_code = 0; + o = mono_object_new_checked (context->domain, newobj_class, &error); + mono_error_cleanup (&error); /* FIXME: don't swallow the error */ + context->managed_code = 1; + if (*mono_thread_interruption_request_flag ()) + mono_thread_interruption_checkpoint (); + sp->data.p = o; + } else { + sp->data.p = NULL; + child_frame.retval = &retval; + } + } + + g_assert (csig->call_convention == MONO_CALL_DEFAULT); + + child_frame.ip = NULL; + child_frame.ex = NULL; + + ves_exec_method_with_context (&child_frame, context); + + context->current_frame = frame; + + if (child_frame.ex) { + /* + * An exception occurred, need to run finally, fault and catch handlers.. + */ + frame->ex = child_frame.ex; + goto handle_finally; + } + /* + * a constructor returns void, but we need to return the object we created + */ +array_constructed: + if (newobj_class->valuetype && !newobj_class->enumtype) { + *sp = valuetype_this; + } else if (newobj_class == mono_defaults.string_class) { + *sp = retval; + } else { + sp->data.p = o; + } + ++sp; + MINT_IN_BREAK; + } + MINT_IN_CASE(MINT_CASTCLASS) + c = rtm->data_items [*(guint16 *)(ip + 1)]; + if ((o = sp [-1].data.p)) { + MonoObject *isinst_obj = mono_object_isinst_checked (o, c, &error); + mono_error_cleanup (&error); /* FIXME: don't swallow the error */ + if (!isinst_obj) + THROW_EX (mono_get_exception_invalid_cast (), ip); + } + ip += 2; + MINT_IN_BREAK; + MINT_IN_CASE(MINT_ISINST) + c = rtm->data_items [*(guint16 *)(ip + 1)]; + if ((o = sp [-1].data.p)) { + MonoObject *isinst_obj = mono_object_isinst_checked (o, c, &error); + mono_error_cleanup (&error); /* FIXME: don't swallow the error */ + if (!isinst_obj) + sp [-1].data.p = NULL; + } + ip += 2; + MINT_IN_BREAK; + MINT_IN_CASE(MINT_CONV_R_UN_I4) + sp [-1].data.f = (double)(guint32)sp [-1].data.i; + ++ip; + MINT_IN_BREAK; + MINT_IN_CASE(MINT_CONV_R_UN_I8) + sp [-1].data.f = (double)(guint64)sp [-1].data.l; + ++ip; + MINT_IN_BREAK; + MINT_IN_CASE(MINT_UNBOX) + c = rtm->data_items[*(guint16 *)(ip + 1)]; + + o = sp [-1].data.p; + if (!o) + THROW_EX (mono_get_exception_null_reference (), ip); + + MonoObject *isinst_obj = mono_object_isinst_checked (o, c, &error); + mono_error_cleanup (&error); /* FIXME: don't swallow the error */ + if (!(isinst_obj || ((o->vtable->klass->rank == 0) && (o->vtable->klass->element_class == c->element_class)))) + THROW_EX (mono_get_exception_invalid_cast (), ip); + + if (c->byval_arg.type == MONO_TYPE_VALUETYPE && !c->enumtype) { + int size = mono_class_native_size (c, NULL); + sp [-1].data.p = vt_sp; + vt_sp += (size + 7) & ~7; + } + stackval_from_data (&c->byval_arg, &sp [-1], mono_object_unbox (o), FALSE); + ip += 2; + MINT_IN_BREAK; + MINT_IN_CASE(MINT_THROW) + --sp; + frame->ex_handler = NULL; + if (!sp->data.p) + sp->data.p = mono_get_exception_null_reference (); + THROW_EX ((MonoException *)sp->data.p, ip); + MINT_IN_BREAK; + MINT_IN_CASE(MINT_LDFLDA) + o = sp [-1].data.p; + if (!o) + THROW_EX (mono_get_exception_null_reference (), ip); + sp[-1].data.p = (char *)o + * (guint16 *)(ip + 1); + ip += 2; + MINT_IN_BREAK; + MINT_IN_CASE(MINT_CKNULL) + o = sp [-1].data.p; + if (!o) + THROW_EX (mono_get_exception_null_reference (), ip); + ++ip; + MINT_IN_BREAK; + +#define LDFLD(datamem, fieldtype) \ + o = sp [-1].data.p; \ + if (!o) \ + THROW_EX (mono_get_exception_null_reference (), ip); \ + sp[-1].data.datamem = * (fieldtype *)((char *)o + * (guint16 *)(ip + 1)) ; \ + ip += 2; + + MINT_IN_CASE(MINT_LDFLD_I1) LDFLD(i, gint8); MINT_IN_BREAK; + MINT_IN_CASE(MINT_LDFLD_U1) LDFLD(i, guint8); MINT_IN_BREAK; + MINT_IN_CASE(MINT_LDFLD_I2) LDFLD(i, gint16); MINT_IN_BREAK; + MINT_IN_CASE(MINT_LDFLD_U2) LDFLD(i, guint16); MINT_IN_BREAK; + MINT_IN_CASE(MINT_LDFLD_I4) LDFLD(i, gint32); MINT_IN_BREAK; + MINT_IN_CASE(MINT_LDFLD_I8) LDFLD(l, gint64); MINT_IN_BREAK; + MINT_IN_CASE(MINT_LDFLD_R4) LDFLD(f, float); MINT_IN_BREAK; + MINT_IN_CASE(MINT_LDFLD_R8) LDFLD(f, double); MINT_IN_BREAK; + MINT_IN_CASE(MINT_LDFLD_O) LDFLD(p, gpointer); MINT_IN_BREAK; + MINT_IN_CASE(MINT_LDFLD_P) LDFLD(p, gpointer); MINT_IN_BREAK; + + MINT_IN_CASE(MINT_LDFLD_VT) + o = sp [-1].data.p; + if (!o) + THROW_EX (mono_get_exception_null_reference (), ip); + i32 = READ32(ip + 2); + sp [-1].data.p = vt_sp; + memcpy(sp [-1].data.p, (char *)o + * (guint16 *)(ip + 1), i32); + vt_sp += (i32 + 7) & ~7; + ip += 4; + MINT_IN_BREAK; + + MINT_IN_CASE(MINT_LDRMFLD) { + gpointer tmp; + MonoClassField *field; + char *addr; + + o = sp [-1].data.p; + if (!o) + THROW_EX (mono_get_exception_null_reference (), ip); + field = rtm->data_items[* (guint16 *)(ip + 1)]; + ip += 2; + if (mono_object_is_transparent_proxy (o)) { + MonoClass *klass = ((MonoTransparentProxy*)o)->remote_class->proxy_class; + + addr = mono_load_remote_field_checked (o, klass, field, &tmp, &error); + mono_error_cleanup (&error); /* FIXME: don't swallow the error */ + } else { + addr = (char*)o + field->offset; + } + + stackval_from_data (field->type, &sp [-1], addr, FALSE); + MINT_IN_BREAK; + } + + MINT_IN_CASE(MINT_LDRMFLD_VT) { + MonoClassField *field; + char *addr; + gpointer tmp; + + o = sp [-1].data.p; + if (!o) + THROW_EX (mono_get_exception_null_reference (), ip); + field = rtm->data_items[* (guint16 *)(ip + 1)]; + i32 = READ32(ip + 2); + ip += 4; + if (mono_object_is_transparent_proxy (o)) { + MonoClass *klass = ((MonoTransparentProxy*)o)->remote_class->proxy_class; + addr = mono_load_remote_field_checked (o, klass, field, &tmp, &error); + mono_error_cleanup (&error); /* FIXME: don't swallow the error */ + } else { + addr = (char*)o + field->offset; + } + + sp [-1].data.p = vt_sp; + memcpy(sp [-1].data.p, (char *)o + * (guint16 *)(ip + 1), i32); + vt_sp += (i32 + 7) & ~7; + memcpy(sp [-1].data.p, addr, i32); + MINT_IN_BREAK; + } + +#define STFLD(datamem, fieldtype) \ + o = sp [-2].data.p; \ + if (!o) \ + THROW_EX (mono_get_exception_null_reference (), ip); \ + sp -= 2; \ + * (fieldtype *)((char *)o + * (guint16 *)(ip + 1)) = sp[1].data.datamem; \ + ip += 2; + + MINT_IN_CASE(MINT_STFLD_I1) STFLD(i, gint8); MINT_IN_BREAK; + MINT_IN_CASE(MINT_STFLD_U1) STFLD(i, guint8); MINT_IN_BREAK; + MINT_IN_CASE(MINT_STFLD_I2) STFLD(i, gint16); MINT_IN_BREAK; + MINT_IN_CASE(MINT_STFLD_U2) STFLD(i, guint16); MINT_IN_BREAK; + MINT_IN_CASE(MINT_STFLD_I4) STFLD(i, gint32); MINT_IN_BREAK; + MINT_IN_CASE(MINT_STFLD_I8) STFLD(l, gint64); MINT_IN_BREAK; + MINT_IN_CASE(MINT_STFLD_R4) STFLD(f, float); MINT_IN_BREAK; + MINT_IN_CASE(MINT_STFLD_R8) STFLD(f, double); MINT_IN_BREAK; + MINT_IN_CASE(MINT_STFLD_O) STFLD(p, gpointer); MINT_IN_BREAK; + MINT_IN_CASE(MINT_STFLD_P) STFLD(p, gpointer); MINT_IN_BREAK; + + MINT_IN_CASE(MINT_STFLD_VT) + o = sp [-2].data.p; + if (!o) + THROW_EX (mono_get_exception_null_reference (), ip); + i32 = READ32(ip + 2); + sp -= 2; + memcpy((char *)o + * (guint16 *)(ip + 1), sp [1].data.p, i32); + vt_sp -= (i32 + 7) & ~7; + ip += 4; + MINT_IN_BREAK; + + MINT_IN_CASE(MINT_STRMFLD) { + MonoClassField *field; + + o = sp [-2].data.p; + if (!o) + THROW_EX (mono_get_exception_null_reference (), ip); + + field = rtm->data_items[* (guint16 *)(ip + 1)]; + ip += 2; + + if (mono_object_is_transparent_proxy (o)) { + MonoClass *klass = ((MonoTransparentProxy*)o)->remote_class->proxy_class; + mono_store_remote_field_checked (o, klass, field, &sp [-1].data, &error); + mono_error_cleanup (&error); /* FIXME: don't swallow the error */ + } else + stackval_to_data (field->type, &sp [-1], (char*)o + field->offset, FALSE); + + sp -= 2; + MINT_IN_BREAK; + } + MINT_IN_CASE(MINT_STRMFLD_VT) { + MonoClassField *field; + + o = sp [-2].data.p; + if (!o) + THROW_EX (mono_get_exception_null_reference (), ip); + field = rtm->data_items[* (guint16 *)(ip + 1)]; + i32 = READ32(ip + 2); + ip += 4; + + if (mono_object_is_transparent_proxy (o)) { + MonoClass *klass = ((MonoTransparentProxy*)o)->remote_class->proxy_class; + mono_store_remote_field_checked (o, klass, field, &sp [-1].data, &error); + mono_error_cleanup (&error); /* FIXME: don't swallow the error */ + } else + memcpy((char*)o + field->offset, sp [-1].data.p, i32); + + sp -= 2; + vt_sp -= (i32 + 7) & ~7; + MINT_IN_BREAK; + } + MINT_IN_CASE(MINT_LDSFLDA) { + MonoClassField *field = rtm->data_items[*(guint16 *)(ip + 1)]; + sp->data.p = mono_class_static_field_address (context->domain, field); + ip += 2; + ++sp; + MINT_IN_BREAK; + } + MINT_IN_CASE(MINT_LDSFLD) { + MonoClassField *field = rtm->data_items [* (guint16 *)(ip + 1)]; + gpointer addr = mono_class_static_field_address (context->domain, field); + stackval_from_data (field->type, sp, addr, FALSE); + ip += 2; + ++sp; + MINT_IN_BREAK; + } + MINT_IN_CASE(MINT_LDSFLD_VT) { + MonoClassField *field = rtm->data_items [* (guint16 *)(ip + 1)]; + gpointer addr = mono_class_static_field_address (context->domain, field); + int size = READ32 (ip + 2); + ip += 4; + + sp->data.p = vt_sp; + vt_sp += (size + 7) & ~7; + stackval_from_data (field->type, sp, addr, FALSE); + ++sp; + MINT_IN_BREAK; + } + MINT_IN_CASE(MINT_STSFLD) { + MonoClassField *field = rtm->data_items [* (guint16 *)(ip + 1)]; + gpointer addr = mono_class_static_field_address (context->domain, field); + ip += 2; + --sp; + stackval_to_data (field->type, sp, addr, FALSE); + MINT_IN_BREAK; + } + MINT_IN_CASE(MINT_STSFLD_VT) { + MonoClassField *field = rtm->data_items [* (guint16 *)(ip + 1)]; + gpointer addr = mono_class_static_field_address (context->domain, field); + int size = READ32 (ip + 2); + ip += 4; + + --sp; + stackval_to_data (field->type, sp, addr, FALSE); + vt_sp -= (size + 7) & ~7; + MINT_IN_BREAK; + } + MINT_IN_CASE(MINT_STOBJ_VT) { + int size; + c = rtm->data_items[* (guint16 *)(ip + 1)]; + ip += 2; + size = mono_class_value_size (c, NULL); + memcpy(sp [-2].data.p, sp [-1].data.p, size); + vt_sp -= (size + 7) & ~7; + sp -= 2; + MINT_IN_BREAK; + } + MINT_IN_CASE(MINT_STOBJ) { + int size; + c = rtm->data_items[* (guint16 *)(ip + 1)]; + ip += 2; + size = mono_class_value_size (c, NULL); + memcpy(sp [-2].data.p, &sp [-1].data, size); + sp -= 2; + MINT_IN_BREAK; + } + MINT_IN_CASE(MINT_CONV_OVF_I4_UN_R8) + if (sp [-1].data.f < 0 || sp [-1].data.f > MYGUINT32_MAX) + THROW_EX (mono_get_exception_overflow (), ip); + sp [-1].data.i = (guint32)sp [-1].data.f; + ++ip; + MINT_IN_BREAK; + MINT_IN_CASE(MINT_CONV_OVF_U8_I4) + if (sp [-1].data.i < 0) + THROW_EX (mono_get_exception_overflow (), ip); + sp [-1].data.l = sp [-1].data.i; + ++ip; + MINT_IN_BREAK; + MINT_IN_CASE(MINT_CONV_OVF_U8_R8) + MINT_IN_CASE(MINT_CONV_OVF_I8_UN_R8) + if (sp [-1].data.f < 0 || sp [-1].data.f > 9223372036854775807LL) + THROW_EX (mono_get_exception_overflow (), ip); + sp [-1].data.l = (guint64)sp [-1].data.f; + ++ip; + MINT_IN_BREAK; + MINT_IN_CASE(MINT_CONV_OVF_I8_R8) + if (sp [-1].data.f < MYGINT64_MIN || sp [-1].data.f > MYGINT64_MAX) + THROW_EX (mono_get_exception_overflow (), ip); + sp [-1].data.l = (gint64)sp [-1].data.f; + ++ip; + MINT_IN_BREAK; + MINT_IN_CASE(MINT_CONV_OVF_I4_UN_I8) + if ((mono_u)sp [-1].data.l > MYGUINT32_MAX) + THROW_EX (mono_get_exception_overflow (), ip); + sp [-1].data.i = (mono_u)sp [-1].data.l; + ++ip; + MINT_IN_BREAK; + MINT_IN_CASE(MINT_BOX) { + c = rtm->data_items [* (guint16 *)(ip + 1)]; + guint16 offset = * (guint16 *)(ip + 2); + + if (c->byval_arg.type == MONO_TYPE_VALUETYPE && !c->enumtype) { + int size = mono_class_value_size (c, NULL); + sp [-1 - offset].data.p = mono_value_box_checked (context->domain, c, sp [-1 - offset].data.p, &error); + mono_error_cleanup (&error); /* FIXME: don't swallow the error */ + size = (size + 7) & ~7; + vt_sp -= size; + } else { + stackval_to_data (&c->byval_arg, &sp [-1 - offset], (char *) &sp [-1 - offset], FALSE); + sp [-1 - offset].data.p = mono_value_box_checked (context->domain, c, &sp [-1 - offset], &error); + mono_error_cleanup (&error); /* FIXME: don't swallow the error */ + } + ip += 3; + MINT_IN_BREAK; + } + MINT_IN_CASE(MINT_NEWARR) + sp [-1].data.p = (MonoObject*) mono_array_new_checked (context->domain, rtm->data_items[*(guint16 *)(ip + 1)], sp [-1].data.i, &error); + mono_error_cleanup (&error); /* FIXME: don't swallow the error */ + ip += 2; + /*if (profiling_classes) { + guint count = GPOINTER_TO_UINT (g_hash_table_lookup (profiling_classes, o->vtable->klass)); + count++; + g_hash_table_insert (profiling_classes, o->vtable->klass, GUINT_TO_POINTER (count)); + }*/ + + MINT_IN_BREAK; + MINT_IN_CASE(MINT_LDLEN) + o = sp [-1].data.p; + if (!o) + THROW_EX (mono_get_exception_null_reference (), ip); + sp [-1].data.nati = mono_array_length ((MonoArray *)o); + ++ip; + MINT_IN_BREAK; + MINT_IN_CASE(MINT_GETCHR) { + MonoString *s; + s = sp [-2].data.p; + if (!s) + THROW_EX (mono_get_exception_null_reference (), ip); + i32 = sp [-1].data.i; + if (i32 < 0 || i32 >= mono_string_length (s)) + THROW_EX (mono_get_exception_index_out_of_range (), ip); + --sp; + sp [-1].data.i = mono_string_chars(s)[i32]; + ++ip; + MINT_IN_BREAK; + } + MINT_IN_CASE(MINT_STRLEN) + ++ip; + sp [-1].data.i = mono_string_length ((MonoString*)sp [-1].data.p); + MINT_IN_BREAK; + MINT_IN_CASE(MINT_ARRAY_RANK) + o = sp [-1].data.p; + if (!o) + THROW_EX (mono_get_exception_null_reference (), ip); + sp [-1].data.i = mono_object_class (sp [-1].data.p)->rank; + ip++; + MINT_IN_BREAK; + MINT_IN_CASE(MINT_LDELEMA) { + guint32 esize; + mono_u aindex; + + /*token = READ32 (ip)*/; + ip += 2; + sp -= 2; + + o = sp [0].data.p; + + aindex = sp [1].data.i; + if (aindex >= mono_array_length ((MonoArray *) o)) + THROW_EX (mono_get_exception_index_out_of_range (), ip - 2); + + /* check the array element corresponds to token */ + esize = mono_array_element_size (((MonoArray *) o)->obj.vtable->klass); + + sp->data.p = mono_array_addr_with_size ((MonoArray *) o, esize, aindex); + ++sp; + MINT_IN_BREAK; + } + MINT_IN_CASE(MINT_LDELEM_I1) /* fall through */ + MINT_IN_CASE(MINT_LDELEM_U1) /* fall through */ + MINT_IN_CASE(MINT_LDELEM_I2) /* fall through */ + MINT_IN_CASE(MINT_LDELEM_U2) /* fall through */ + MINT_IN_CASE(MINT_LDELEM_I4) /* fall through */ + MINT_IN_CASE(MINT_LDELEM_U4) /* fall through */ + MINT_IN_CASE(MINT_LDELEM_I8) /* fall through */ + MINT_IN_CASE(MINT_LDELEM_I) /* fall through */ + MINT_IN_CASE(MINT_LDELEM_R4) /* fall through */ + MINT_IN_CASE(MINT_LDELEM_R8) /* fall through */ + MINT_IN_CASE(MINT_LDELEM_REF) /* fall through */ + MINT_IN_CASE(MINT_LDELEM_VT) { + MonoArray *o; + mono_u aindex; + + sp -= 2; + + o = sp [0].data.p; + if (!o) + THROW_EX (mono_get_exception_null_reference (), ip); + + aindex = sp [1].data.i; + if (aindex >= mono_array_length (o)) + THROW_EX (mono_get_exception_index_out_of_range (), ip); + + /* + * FIXME: throw mono_get_exception_array_type_mismatch () if needed + */ + switch (*ip) { + case MINT_LDELEM_I1: + sp [0].data.i = mono_array_get (o, gint8, aindex); + break; + case MINT_LDELEM_U1: + sp [0].data.i = mono_array_get (o, guint8, aindex); + break; + case MINT_LDELEM_I2: + sp [0].data.i = mono_array_get (o, gint16, aindex); + break; + case MINT_LDELEM_U2: + sp [0].data.i = mono_array_get (o, guint16, aindex); + break; + case MINT_LDELEM_I: + sp [0].data.nati = mono_array_get (o, mono_i, aindex); + break; + case MINT_LDELEM_I4: + sp [0].data.i = mono_array_get (o, gint32, aindex); + break; + case MINT_LDELEM_U4: + sp [0].data.i = mono_array_get (o, guint32, aindex); + break; + case MINT_LDELEM_I8: + sp [0].data.l = mono_array_get (o, guint64, aindex); + break; + case MINT_LDELEM_R4: + sp [0].data.f = mono_array_get (o, float, aindex); + break; + case MINT_LDELEM_R8: + sp [0].data.f = mono_array_get (o, double, aindex); + break; + case MINT_LDELEM_REF: + sp [0].data.p = mono_array_get (o, gpointer, aindex); + break; + case MINT_LDELEM_VT: { + MonoClass *klass_vt = rtm->data_items [*(guint16 *) (ip + 1)]; + i32 = READ32 (ip + 2); + char *src_addr = mono_array_addr_with_size ((MonoArray *) o, i32, aindex); + sp [0].data.vt = vt_sp; + stackval_from_data (&klass_vt->byval_arg, sp, src_addr, FALSE); + vt_sp += (i32 + 7) & ~7; + ip += 3; + break; + } + default: + ves_abort(); + } + + ++ip; + ++sp; + MINT_IN_BREAK; + } + MINT_IN_CASE(MINT_STELEM_I) /* fall through */ + MINT_IN_CASE(MINT_STELEM_I1) /* fall through */ + MINT_IN_CASE(MINT_STELEM_I2) /* fall through */ + MINT_IN_CASE(MINT_STELEM_I4) /* fall through */ + MINT_IN_CASE(MINT_STELEM_I8) /* fall through */ + MINT_IN_CASE(MINT_STELEM_R4) /* fall through */ + MINT_IN_CASE(MINT_STELEM_R8) /* fall through */ + MINT_IN_CASE(MINT_STELEM_REF) /* fall through */ + MINT_IN_CASE(MINT_STELEM_VT) { + mono_u aindex; + + sp -= 3; + + o = sp [0].data.p; + if (!o) + THROW_EX (mono_get_exception_null_reference (), ip); + + aindex = sp [1].data.i; + if (aindex >= mono_array_length ((MonoArray *)o)) + THROW_EX (mono_get_exception_index_out_of_range (), ip); + + switch (*ip) { + case MINT_STELEM_I: + mono_array_set ((MonoArray *)o, mono_i, aindex, sp [2].data.nati); + break; + case MINT_STELEM_I1: + mono_array_set ((MonoArray *)o, gint8, aindex, sp [2].data.i); + break; + case MINT_STELEM_I2: + mono_array_set ((MonoArray *)o, gint16, aindex, sp [2].data.i); + break; + case MINT_STELEM_I4: + mono_array_set ((MonoArray *)o, gint32, aindex, sp [2].data.i); + break; + case MINT_STELEM_I8: + mono_array_set ((MonoArray *)o, gint64, aindex, sp [2].data.l); + break; + case MINT_STELEM_R4: + mono_array_set ((MonoArray *)o, float, aindex, sp [2].data.f); + break; + case MINT_STELEM_R8: + mono_array_set ((MonoArray *)o, double, aindex, sp [2].data.f); + break; + case MINT_STELEM_REF: { + MonoObject *isinst_obj = mono_object_isinst_checked (sp [2].data.p, mono_object_class (o)->element_class, &error); + mono_error_cleanup (&error); /* FIXME: don't swallow the error */ + if (sp [2].data.p && !isinst_obj) + THROW_EX (mono_get_exception_array_type_mismatch (), ip); + mono_array_set ((MonoArray *)o, gpointer, aindex, sp [2].data.p); + break; + } + case MINT_STELEM_VT: { + MonoClass *klass_vt = rtm->data_items [*(guint16 *) (ip + 1)]; + i32 = READ32 (ip + 2); + char *dst_addr = mono_array_addr_with_size ((MonoArray *) o, i32, aindex); + + stackval_to_data (&klass_vt->byval_arg, &sp [2], dst_addr, FALSE); + vt_sp -= (i32 + 7) & ~7; + ip += 3; + break; + } + default: + ves_abort(); + } + + ++ip; + MINT_IN_BREAK; + } + MINT_IN_CASE(MINT_CONV_OVF_I4_U4) + if (sp [-1].data.i < 0) + THROW_EX (mono_get_exception_overflow (), ip); + ++ip; + MINT_IN_BREAK; + MINT_IN_CASE(MINT_CONV_OVF_I4_I8) + if (sp [-1].data.l < MYGINT32_MIN || sp [-1].data.l > MYGINT32_MAX) + THROW_EX (mono_get_exception_overflow (), ip); + sp [-1].data.i = (gint32) sp [-1].data.l; + ++ip; + MINT_IN_BREAK; + MINT_IN_CASE(MINT_CONV_OVF_I4_R8) + if (sp [-1].data.f < MYGINT32_MIN || sp [-1].data.f > MYGINT32_MAX) + THROW_EX (mono_get_exception_overflow (), ip); + sp [-1].data.i = (gint32) sp [-1].data.f; + ++ip; + MINT_IN_BREAK; + MINT_IN_CASE(MINT_CONV_OVF_U4_I4) + if (sp [-1].data.i < 0) + THROW_EX (mono_get_exception_overflow (), ip); + ++ip; + MINT_IN_BREAK; + MINT_IN_CASE(MINT_CONV_OVF_U4_I8) + if (sp [-1].data.l < 0 || sp [-1].data.l > MYGUINT32_MAX) + THROW_EX (mono_get_exception_overflow (), ip); + sp [-1].data.i = (guint32) sp [-1].data.l; + ++ip; + MINT_IN_BREAK; + MINT_IN_CASE(MINT_CONV_OVF_U4_R8) + if (sp [-1].data.f < 0 || sp [-1].data.f > MYGUINT32_MAX) + THROW_EX (mono_get_exception_overflow (), ip); + sp [-1].data.i = (guint32) sp [-1].data.f; + ++ip; + MINT_IN_BREAK; + MINT_IN_CASE(MINT_CONV_OVF_I2_I4) + if (sp [-1].data.i < -32768 || sp [-1].data.i > 32767) + THROW_EX (mono_get_exception_overflow (), ip); + ++ip; + MINT_IN_BREAK; + MINT_IN_CASE(MINT_CONV_OVF_I2_I8) + if (sp [-1].data.l < -32768 || sp [-1].data.l > 32767) + THROW_EX (mono_get_exception_overflow (), ip); + sp [-1].data.i = (gint16) sp [-1].data.l; + ++ip; + MINT_IN_BREAK; + MINT_IN_CASE(MINT_CONV_OVF_I2_R8) + if (sp [-1].data.f < -32768 || sp [-1].data.f > 32767) + THROW_EX (mono_get_exception_overflow (), ip); + sp [-1].data.i = (gint16) sp [-1].data.f; + ++ip; + MINT_IN_BREAK; + MINT_IN_CASE(MINT_CONV_OVF_U2_I4) + if (sp [-1].data.i < 0 || sp [-1].data.i > 65535) + THROW_EX (mono_get_exception_overflow (), ip); + ++ip; + MINT_IN_BREAK; + MINT_IN_CASE(MINT_CONV_OVF_U2_I8) + if (sp [-1].data.l < 0 || sp [-1].data.l > 65535) + THROW_EX (mono_get_exception_overflow (), ip); + sp [-1].data.i = (guint16) sp [-1].data.l; + ++ip; + MINT_IN_BREAK; + MINT_IN_CASE(MINT_CONV_OVF_U2_R8) + if (sp [-1].data.f < 0 || sp [-1].data.f > 65535) + THROW_EX (mono_get_exception_overflow (), ip); + sp [-1].data.i = (guint16) sp [-1].data.f; + ++ip; + MINT_IN_BREAK; + MINT_IN_CASE(MINT_CONV_OVF_I1_I4) + if (sp [-1].data.i < -128 || sp [-1].data.i > 127) + THROW_EX (mono_get_exception_overflow (), ip); + ++ip; + MINT_IN_BREAK; + MINT_IN_CASE(MINT_CONV_OVF_I1_I8) + if (sp [-1].data.l < -128 || sp [-1].data.l > 127) + THROW_EX (mono_get_exception_overflow (), ip); + sp [-1].data.i = (gint8) sp [-1].data.l; + ++ip; + MINT_IN_BREAK; + MINT_IN_CASE(MINT_CONV_OVF_I1_R8) + if (sp [-1].data.f < -128 || sp [-1].data.f > 127) + THROW_EX (mono_get_exception_overflow (), ip); + sp [-1].data.i = (gint8) sp [-1].data.f; + ++ip; + MINT_IN_BREAK; + MINT_IN_CASE(MINT_CONV_OVF_U1_I4) + if (sp [-1].data.i < 0 || sp [-1].data.i > 255) + THROW_EX (mono_get_exception_overflow (), ip); + ++ip; + MINT_IN_BREAK; + MINT_IN_CASE(MINT_CONV_OVF_U1_I8) + if (sp [-1].data.l < 0 || sp [-1].data.l > 255) + THROW_EX (mono_get_exception_overflow (), ip); + sp [-1].data.i = (guint8) sp [-1].data.l; + ++ip; + MINT_IN_BREAK; + MINT_IN_CASE(MINT_CONV_OVF_U1_R8) + if (sp [-1].data.f < 0 || sp [-1].data.f > 255) + THROW_EX (mono_get_exception_overflow (), ip); + sp [-1].data.i = (guint8) sp [-1].data.f; + ++ip; + MINT_IN_BREAK; +#if 0 + MINT_IN_CASE(MINT_LDELEM) + MINT_IN_CASE(MINT_STELEM) + MINT_IN_CASE(MINT_UNBOX_ANY) + + MINT_IN_CASE(MINT_REFANYVAL) ves_abort(); MINT_IN_BREAK; +#endif + MINT_IN_CASE(MINT_CKFINITE) + if (!isfinite(sp [-1].data.f)) + THROW_EX (mono_get_exception_arithmetic (), ip); + ++ip; + MINT_IN_BREAK; +#if 0 + MINT_IN_CASE(MINT_MKREFANY) ves_abort(); MINT_IN_BREAK; +#endif + MINT_IN_CASE(MINT_LDTOKEN) + sp->data.p = vt_sp; + vt_sp += 8; + * (gpointer *)sp->data.p = rtm->data_items[*(guint16 *)(ip + 1)]; + ip += 2; + ++sp; + MINT_IN_BREAK; + MINT_IN_CASE(MINT_ADD_OVF_I4) + if (CHECK_ADD_OVERFLOW (sp [-2].data.i, sp [-1].data.i)) + THROW_EX (mono_get_exception_overflow (), ip); + BINOP(i, +); + MINT_IN_BREAK; + MINT_IN_CASE(MINT_ADD_OVF_I8) + if (CHECK_ADD_OVERFLOW64 (sp [-2].data.l, sp [-1].data.l)) + THROW_EX (mono_get_exception_overflow (), ip); + BINOP(l, +); + MINT_IN_BREAK; + MINT_IN_CASE(MINT_ADD_OVF_UN_I4) + if (CHECK_ADD_OVERFLOW_UN (sp [-2].data.i, sp [-1].data.i)) + THROW_EX (mono_get_exception_overflow (), ip); + BINOP_CAST(i, +, guint32); + MINT_IN_BREAK; + MINT_IN_CASE(MINT_ADD_OVF_UN_I8) + if (CHECK_ADD_OVERFLOW64_UN (sp [-2].data.l, sp [-1].data.l)) + THROW_EX (mono_get_exception_overflow (), ip); + BINOP_CAST(l, +, guint64); + MINT_IN_BREAK; + MINT_IN_CASE(MINT_MUL_OVF_I4) + if (CHECK_MUL_OVERFLOW (sp [-2].data.i, sp [-1].data.i)) + THROW_EX (mono_get_exception_overflow (), ip); + BINOP(i, *); + MINT_IN_BREAK; + MINT_IN_CASE(MINT_MUL_OVF_I8) + if (CHECK_MUL_OVERFLOW64 (sp [-2].data.l, sp [-1].data.l)) + THROW_EX (mono_get_exception_overflow (), ip); + BINOP(l, *); + MINT_IN_BREAK; + MINT_IN_CASE(MINT_MUL_OVF_UN_I4) + if (CHECK_MUL_OVERFLOW_UN (sp [-2].data.i, sp [-1].data.i)) + THROW_EX (mono_get_exception_overflow (), ip); + BINOP_CAST(i, *, guint32); + MINT_IN_BREAK; + MINT_IN_CASE(MINT_MUL_OVF_UN_I8) + if (CHECK_MUL_OVERFLOW64_UN (sp [-2].data.l, sp [-1].data.l)) + THROW_EX (mono_get_exception_overflow (), ip); + BINOP_CAST(l, *, guint64); + MINT_IN_BREAK; + MINT_IN_CASE(MINT_SUB_OVF_I4) + if (CHECK_SUB_OVERFLOW (sp [-2].data.i, sp [-1].data.i)) + THROW_EX (mono_get_exception_overflow (), ip); + BINOP(i, -); + MINT_IN_BREAK; + MINT_IN_CASE(MINT_SUB_OVF_I8) + if (CHECK_SUB_OVERFLOW64 (sp [-2].data.l, sp [-1].data.l)) + THROW_EX (mono_get_exception_overflow (), ip); + BINOP(l, -); + MINT_IN_BREAK; + MINT_IN_CASE(MINT_SUB_OVF_UN_I4) + if (CHECK_SUB_OVERFLOW_UN (sp [-2].data.i, sp [-1].data.i)) + THROW_EX (mono_get_exception_overflow (), ip); + BINOP_CAST(i, -, guint32); + MINT_IN_BREAK; + MINT_IN_CASE(MINT_SUB_OVF_UN_I8) + if (CHECK_SUB_OVERFLOW64_UN (sp [-2].data.l, sp [-1].data.l)) + THROW_EX (mono_get_exception_overflow (), ip); + BINOP_CAST(l, -, guint64); + MINT_IN_BREAK; + MINT_IN_CASE(MINT_ENDFINALLY) + if (finally_ips) { + ip = finally_ips->data; + finally_ips = g_slist_remove (finally_ips, ip); + goto main_loop; + } + if (frame->ex) + goto handle_fault; + ves_abort(); + MINT_IN_BREAK; + MINT_IN_CASE(MINT_LEAVE) /* Fall through */ + MINT_IN_CASE(MINT_LEAVE_S) + while (sp > frame->stack) { + --sp; + } + frame->ip = ip; + if (*ip == MINT_LEAVE_S) { + ip += (short) *(ip + 1); + } else { + ip += (gint32) READ32 (ip + 1); + } + endfinally_ip = ip; + if (frame->ex_handler != NULL && MONO_OFFSET_IN_HANDLER(frame->ex_handler, frame->ip - rtm->code)) { + frame->ex_handler = NULL; + frame->ex = NULL; + } + goto handle_finally; + MINT_IN_BREAK; + MINT_IN_CASE(MINT_ICALL_V_V) + MINT_IN_CASE(MINT_ICALL_V_P) + MINT_IN_CASE(MINT_ICALL_P_V) + MINT_IN_CASE(MINT_ICALL_P_P) + MINT_IN_CASE(MINT_ICALL_PP_V) + MINT_IN_CASE(MINT_ICALL_PI_V) + MINT_IN_CASE(MINT_ICALL_PP_P) + MINT_IN_CASE(MINT_ICALL_PI_P) + MINT_IN_CASE(MINT_ICALL_PPP_V) + MINT_IN_CASE(MINT_ICALL_PPI_V) + sp = do_icall (context, *ip, sp, rtm->data_items [*(guint16 *)(ip + 1)]); + if (frame->ex != NULL) + goto handle_exception; + ip += 2; + MINT_IN_BREAK; + MINT_IN_CASE(MINT_MONO_LDPTR) + sp->data.p = rtm->data_items [*(guint16 *)(ip + 1)]; + ip += 2; + ++sp; + MINT_IN_BREAK; + MINT_IN_CASE(MINT_MONO_NEWOBJ) + sp->data.p = mono_object_new_checked (context->domain, rtm->data_items [*(guint16 *)(ip + 1)], &error); + mono_error_cleanup (&error); /* FIXME: don't swallow the error */ + ip += 2; + sp++; + MINT_IN_BREAK; + MINT_IN_CASE(MINT_MONO_FREE) + ++ip; + --sp; + g_error ("that doesn't seem right"); + g_free (sp->data.p); + MINT_IN_BREAK; + MINT_IN_CASE(MINT_MONO_RETOBJ) + ++ip; + sp--; + stackval_from_data (mono_method_signature (frame->runtime_method->method)->ret, frame->retval, sp->data.p, + mono_method_signature (frame->runtime_method->method)->pinvoke); + if (sp > frame->stack) + g_warning ("retobj: more values on stack: %d", sp-frame->stack); + goto exit_frame; + +#define RELOP(datamem, op) \ + --sp; \ + sp [-1].data.i = sp [-1].data.datamem op sp [0].data.datamem; \ + ++ip; + MINT_IN_CASE(MINT_CEQ_I4) + RELOP(i, ==); + MINT_IN_BREAK; + MINT_IN_CASE(MINT_CEQ0_I4) + sp [-1].data.i = (sp [-1].data.i == 0); + ++ip; + MINT_IN_BREAK; + MINT_IN_CASE(MINT_CEQ_I8) + RELOP(l, ==); + MINT_IN_BREAK; + MINT_IN_CASE(MINT_CEQ_R8) + --sp; + if (isunordered (sp [-1].data.f, sp [0].data.f)) + sp [-1].data.i = 0; + else + sp [-1].data.i = sp [-1].data.f == sp [0].data.f; + ++ip; + MINT_IN_BREAK; + MINT_IN_CASE(MINT_CGT_I4) + RELOP(i, >); + MINT_IN_BREAK; + MINT_IN_CASE(MINT_CGT_I8) + RELOP(l, >); + MINT_IN_BREAK; + MINT_IN_CASE(MINT_CGT_R8) + --sp; + if (isunordered (sp [-1].data.f, sp [0].data.f)) + sp [-1].data.i = 0; + else + sp [-1].data.i = sp [-1].data.f > sp [0].data.f; + ++ip; + MINT_IN_BREAK; + +#define RELOP_CAST(datamem, op, type) \ + --sp; \ + sp [-1].data.i = (type)sp [-1].data.datamem op (type)sp [0].data.datamem; \ + ++ip; + + MINT_IN_CASE(MINT_CGT_UN_I4) + RELOP_CAST(i, >, guint32); + MINT_IN_BREAK; + MINT_IN_CASE(MINT_CGT_UN_I8) + RELOP_CAST(l, >, guint64); + MINT_IN_BREAK; + MINT_IN_CASE(MINT_CGT_UN_R8) + --sp; + if (isunordered (sp [-1].data.f, sp [0].data.f)) + sp [-1].data.i = 1; + else + sp [-1].data.i = sp [-1].data.f > sp [0].data.f; + ++ip; + MINT_IN_BREAK; + MINT_IN_CASE(MINT_CLT_I4) + RELOP(i, <); + MINT_IN_BREAK; + MINT_IN_CASE(MINT_CLT_I8) + RELOP(l, <); + MINT_IN_BREAK; + MINT_IN_CASE(MINT_CLT_R8) + --sp; + if (isunordered (sp [-1].data.f, sp [0].data.f)) + sp [-1].data.i = 0; + else + sp [-1].data.i = sp [-1].data.f < sp [0].data.f; + ++ip; + MINT_IN_BREAK; + MINT_IN_CASE(MINT_CLT_UN_I4) + RELOP_CAST(i, <, guint32); + MINT_IN_BREAK; + MINT_IN_CASE(MINT_CLT_UN_I8) + RELOP_CAST(l, <, guint64); + MINT_IN_BREAK; + MINT_IN_CASE(MINT_CLT_UN_R8) + --sp; + if (isunordered (sp [-1].data.f, sp [0].data.f)) + sp [-1].data.i = 1; + else + sp [-1].data.i = sp [-1].data.f < sp [0].data.f; + ++ip; + MINT_IN_BREAK; + MINT_IN_CASE(MINT_LDFTN) { + sp->data.p = rtm->data_items [* (guint16 *)(ip + 1)]; + ++sp; + ip += 2; + MINT_IN_BREAK; + } + MINT_IN_CASE(MINT_LDVIRTFTN) { + RuntimeMethod *m = rtm->data_items [* (guint16 *)(ip + 1)]; + ip += 2; + --sp; + if (!sp->data.p) + THROW_EX (mono_get_exception_null_reference (), ip - 2); + + sp->data.p = get_virtual_method (context->domain, m, sp->data.p); + ++sp; + MINT_IN_BREAK; + } + + MINT_IN_CASE(MINT_LDTHISA) + g_error ("should not happen"); + // sp->data.p = &frame->obj; + ++ip; + ++sp; + MINT_IN_BREAK; + +#define LDARG(datamem, argtype) \ + sp->data.datamem = * (argtype *)(frame->args + * (guint16 *)(ip + 1)); \ + ip += 2; \ + ++sp; + + MINT_IN_CASE(MINT_LDARG_I1) LDARG(i, gint8); MINT_IN_BREAK; + MINT_IN_CASE(MINT_LDARG_U1) LDARG(i, guint8); MINT_IN_BREAK; + MINT_IN_CASE(MINT_LDARG_I2) LDARG(i, gint16); MINT_IN_BREAK; + MINT_IN_CASE(MINT_LDARG_U2) LDARG(i, guint16); MINT_IN_BREAK; + MINT_IN_CASE(MINT_LDARG_I4) LDARG(i, gint32); MINT_IN_BREAK; + MINT_IN_CASE(MINT_LDARG_I8) LDARG(l, gint64); MINT_IN_BREAK; + MINT_IN_CASE(MINT_LDARG_R4) LDARG(f, float); MINT_IN_BREAK; + MINT_IN_CASE(MINT_LDARG_R8) LDARG(f, double); MINT_IN_BREAK; + MINT_IN_CASE(MINT_LDARG_O) LDARG(p, gpointer); MINT_IN_BREAK; + MINT_IN_CASE(MINT_LDARG_P) LDARG(p, gpointer); MINT_IN_BREAK; + + MINT_IN_CASE(MINT_LDARG_VT) + sp->data.p = vt_sp; + i32 = READ32(ip + 2); + memcpy(sp->data.p, frame->args + * (guint16 *)(ip + 1), i32); + vt_sp += (i32 + 7) & ~7; + ip += 4; + ++sp; + MINT_IN_BREAK; + +#define STARG(datamem, argtype) \ + --sp; \ + * (argtype *)(frame->args + * (guint16 *)(ip + 1)) = sp->data.datamem; \ + ip += 2; \ + + MINT_IN_CASE(MINT_STARG_I1) STARG(i, gint8); MINT_IN_BREAK; + MINT_IN_CASE(MINT_STARG_U1) STARG(i, guint8); MINT_IN_BREAK; + MINT_IN_CASE(MINT_STARG_I2) STARG(i, gint16); MINT_IN_BREAK; + MINT_IN_CASE(MINT_STARG_U2) STARG(i, guint16); MINT_IN_BREAK; + MINT_IN_CASE(MINT_STARG_I4) STARG(i, gint32); MINT_IN_BREAK; + MINT_IN_CASE(MINT_STARG_I8) STARG(l, gint64); MINT_IN_BREAK; + MINT_IN_CASE(MINT_STARG_R4) STARG(f, float); MINT_IN_BREAK; + MINT_IN_CASE(MINT_STARG_R8) STARG(f, double); MINT_IN_BREAK; + MINT_IN_CASE(MINT_STARG_O) STARG(p, gpointer); MINT_IN_BREAK; + MINT_IN_CASE(MINT_STARG_P) STARG(p, gpointer); MINT_IN_BREAK; + + MINT_IN_CASE(MINT_STARG_VT) + i32 = READ32(ip + 2); + --sp; + memcpy(frame->args + * (guint16 *)(ip + 1), sp->data.p, i32); + vt_sp -= (i32 + 7) & ~7; + ip += 4; + MINT_IN_BREAK; + +#define STINARG(datamem, argtype) \ + do { \ + int n = * (guint16 *)(ip + 1); \ + * (argtype *)(frame->args + rtm->arg_offsets [n]) = frame->stack_args [n].data.datamem; \ + ip += 2; \ + } while (0) + + MINT_IN_CASE(MINT_STINARG_I1) STINARG(i, gint8); MINT_IN_BREAK; + MINT_IN_CASE(MINT_STINARG_U1) STINARG(i, guint8); MINT_IN_BREAK; + MINT_IN_CASE(MINT_STINARG_I2) STINARG(i, gint16); MINT_IN_BREAK; + MINT_IN_CASE(MINT_STINARG_U2) STINARG(i, guint16); MINT_IN_BREAK; + MINT_IN_CASE(MINT_STINARG_I4) STINARG(i, gint32); MINT_IN_BREAK; + MINT_IN_CASE(MINT_STINARG_I8) STINARG(l, gint64); MINT_IN_BREAK; + MINT_IN_CASE(MINT_STINARG_R4) STINARG(f, float); MINT_IN_BREAK; + MINT_IN_CASE(MINT_STINARG_R8) STINARG(f, double); MINT_IN_BREAK; + MINT_IN_CASE(MINT_STINARG_O) STINARG(p, gpointer); MINT_IN_BREAK; + MINT_IN_CASE(MINT_STINARG_P) STINARG(p, gpointer); MINT_IN_BREAK; + + MINT_IN_CASE(MINT_STINARG_VT) { + int n = * (guint16 *)(ip + 1); + i32 = READ32(ip + 2); + memcpy (frame->args + rtm->arg_offsets [n], frame->stack_args [n].data.p, i32); + ip += 4; + MINT_IN_BREAK; + } + + MINT_IN_CASE(MINT_LDARGA) + sp->data.p = frame->args + * (guint16 *)(ip + 1); + ip += 2; + ++sp; + MINT_IN_BREAK; + +#define LDLOC(datamem, argtype) \ + sp->data.datamem = * (argtype *)(locals + * (guint16 *)(ip + 1)); \ + ip += 2; \ + ++sp; + + MINT_IN_CASE(MINT_LDLOC_I1) LDLOC(i, gint8); MINT_IN_BREAK; + MINT_IN_CASE(MINT_LDLOC_U1) LDLOC(i, guint8); MINT_IN_BREAK; + MINT_IN_CASE(MINT_LDLOC_I2) LDLOC(i, gint16); MINT_IN_BREAK; + MINT_IN_CASE(MINT_LDLOC_U2) LDLOC(i, guint16); MINT_IN_BREAK; + MINT_IN_CASE(MINT_LDLOC_I4) LDLOC(i, gint32); MINT_IN_BREAK; + MINT_IN_CASE(MINT_LDLOC_I8) LDLOC(l, gint64); MINT_IN_BREAK; + MINT_IN_CASE(MINT_LDLOC_R4) LDLOC(f, float); MINT_IN_BREAK; + MINT_IN_CASE(MINT_LDLOC_R8) LDLOC(f, double); MINT_IN_BREAK; + MINT_IN_CASE(MINT_LDLOC_O) LDLOC(p, gpointer); MINT_IN_BREAK; + MINT_IN_CASE(MINT_LDLOC_P) LDLOC(p, gpointer); MINT_IN_BREAK; + + MINT_IN_CASE(MINT_LDLOC_VT) + sp->data.p = vt_sp; + i32 = READ32(ip + 2); + memcpy(sp->data.p, locals + * (guint16 *)(ip + 1), i32); + vt_sp += (i32 + 7) & ~7; + ip += 4; + ++sp; + MINT_IN_BREAK; + + MINT_IN_CASE(MINT_LDLOCA_S) + sp->data.p = locals + * (guint16 *)(ip + 1); + ip += 2; + ++sp; + MINT_IN_BREAK; + +#define STLOC(datamem, argtype) \ + --sp; \ + * (argtype *)(locals + * (guint16 *)(ip + 1)) = sp->data.datamem; \ + ip += 2; + + MINT_IN_CASE(MINT_STLOC_I1) STLOC(i, gint8); MINT_IN_BREAK; + MINT_IN_CASE(MINT_STLOC_U1) STLOC(i, guint8); MINT_IN_BREAK; + MINT_IN_CASE(MINT_STLOC_I2) STLOC(i, gint16); MINT_IN_BREAK; + MINT_IN_CASE(MINT_STLOC_U2) STLOC(i, guint16); MINT_IN_BREAK; + MINT_IN_CASE(MINT_STLOC_I4) STLOC(i, gint32); MINT_IN_BREAK; + MINT_IN_CASE(MINT_STLOC_I8) STLOC(l, gint64); MINT_IN_BREAK; + MINT_IN_CASE(MINT_STLOC_R4) STLOC(f, float); MINT_IN_BREAK; + MINT_IN_CASE(MINT_STLOC_R8) STLOC(f, double); MINT_IN_BREAK; + MINT_IN_CASE(MINT_STLOC_O) STLOC(p, gpointer); MINT_IN_BREAK; + MINT_IN_CASE(MINT_STLOC_P) STLOC(p, gpointer); MINT_IN_BREAK; + +#define STLOC_NP(datamem, argtype) \ + * (argtype *)(locals + * (guint16 *)(ip + 1)) = sp [-1].data.datamem; \ + ip += 2; + + MINT_IN_CASE(MINT_STLOC_NP_I4) STLOC_NP(i, gint32); MINT_IN_BREAK; + MINT_IN_CASE(MINT_STLOC_NP_O) STLOC_NP(p, gpointer); MINT_IN_BREAK; + + MINT_IN_CASE(MINT_STLOC_VT) + i32 = READ32(ip + 2); + --sp; + memcpy(locals + * (guint16 *)(ip + 1), sp->data.p, i32); + vt_sp -= (i32 + 7) & ~7; + ip += 4; + MINT_IN_BREAK; + + MINT_IN_CASE(MINT_LOCALLOC) + if (sp != frame->stack + 1) /*FIX?*/ + THROW_EX (mono_get_exception_execution_engine (NULL), ip); + sp [-1].data.p = alloca (sp [-1].data.i); + ++ip; + MINT_IN_BREAK; +#if 0 + MINT_IN_CASE(MINT_ENDFILTER) ves_abort(); MINT_IN_BREAK; +#endif + MINT_IN_CASE(MINT_INITOBJ) + --sp; + memset (sp->data.vt, 0, READ32(ip + 1)); + ip += 3; + MINT_IN_BREAK; + MINT_IN_CASE(MINT_CPBLK) + sp -= 3; + if (!sp [0].data.p || !sp [1].data.p) + THROW_EX (mono_get_exception_null_reference(), ip - 1); + ++ip; + /* FIXME: value and size may be int64... */ + memcpy (sp [0].data.p, sp [1].data.p, sp [2].data.i); + MINT_IN_BREAK; +#if 0 + MINT_IN_CASE(MINT_CONSTRAINED_) { + guint32 token; + /* FIXME: implement */ + ++ip; + token = READ32 (ip); + ip += 2; + MINT_IN_BREAK; + } +#endif + MINT_IN_CASE(MINT_INITBLK) + sp -= 3; + if (!sp [0].data.p) + THROW_EX (mono_get_exception_null_reference(), ip - 1); + ++ip; + /* FIXME: value and size may be int64... */ + memset (sp [0].data.p, sp [1].data.i, sp [2].data.i); + MINT_IN_BREAK; +#if 0 + MINT_IN_CASE(MINT_NO_) + /* FIXME: implement */ + ip += 2; + MINT_IN_BREAK; +#endif + MINT_IN_CASE(MINT_RETHROW) + /* + * need to clarify what this should actually do: + * start the search from the last found handler in + * this method or continue in the caller or what. + * Also, do we need to run finally/fault handlers after a retrow? + * Well, this implementation will follow the usual search + * for an handler, considering the current ip as throw spot. + * We need to NULL frame->ex_handler for the later code to + * actually run the new found handler. + */ + frame->ex_handler = NULL; + THROW_EX (frame->ex, ip - 1); + MINT_IN_BREAK; + MINT_IN_DEFAULT + g_print ("Unimplemented opcode: %04x %s at 0x%x\n", *ip, mono_interp_opname[*ip], ip-rtm->code); + THROW_EX (mono_get_exception_execution_engine ("Unimplemented opcode"), ip); + } + } + + g_assert_not_reached (); + /* + * Exception handling code. + * The exception object is stored in frame->ex. + */ + + handle_exception: + { + int i; + guint32 ip_offset; + MonoInvocation *inv; + MonoExceptionClause *clause; + /*char *message;*/ + MonoObject *ex_obj; + +#if DEBUG_INTERP + if (tracing) + g_print ("* Handling exception '%s' at IL_%04x\n", + frame->ex == NULL ? "** Unknown **" : mono_object_class (frame->ex)->name, + rtm == NULL ? 0 : frame->ip - rtm->code); +#endif + if (die_on_exception) + goto die_on_ex; + + for (inv = frame; inv; inv = inv->parent) { + MonoMethod *method; + if (inv->runtime_method == NULL) + continue; + method = inv->runtime_method->method; + if (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) + continue; + if (method->iflags & (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL | METHOD_IMPL_ATTRIBUTE_RUNTIME)) + continue; + if (inv->ip == NULL) + continue; + ip_offset = inv->ip - inv->runtime_method->code; + inv->ex_handler = NULL; /* clear this in case we are trhowing an exception while handling one - this one wins */ + for (i = 0; i < inv->runtime_method->num_clauses; ++i) { + clause = &inv->runtime_method->clauses [i]; + if (clause->flags <= 1 && MONO_OFFSET_IN_CLAUSE (clause, ip_offset)) { + if (!clause->flags) { + MonoObject *isinst_obj = mono_object_isinst_checked ((MonoObject*)frame->ex, clause->data.catch_class, &error); + mono_error_cleanup (&error); /* FIXME: don't swallow the error */ + if (isinst_obj) { + /* + * OK, we found an handler, now we need to execute the finally + * and fault blocks before branching to the handler code. + */ + inv->ex_handler = clause; +#if DEBUG_INTERP + if (tracing) + g_print ("* Found handler at '%s'\n", method->name); +#endif + goto handle_finally; + } + } else { + /* FIXME: handle filter clauses */ + g_assert (0); + } + } + } + } + /* + * If we get here, no handler was found: print a stack trace. + */ + for (inv = frame; inv; inv = inv->parent) { + if (inv->invoke_trap) + goto handle_finally; + } +die_on_ex: + ex_obj = (MonoObject*)frame->ex; + mono_unhandled_exception (ex_obj); + exit (1); + } + handle_finally: + { + int i; + guint32 ip_offset; + MonoExceptionClause *clause; + GSList *old_list = finally_ips; + MonoMethod *method = frame->runtime_method->method; + MonoMethodHeader *header = mono_method_get_header_checked (method, &error); + mono_error_cleanup (&error); /* FIXME: don't swallow the error */ + +#if DEBUG_INTERP + if (tracing) + g_print ("* Handle finally IL_%04x\n", endfinally_ip == NULL ? 0 : endfinally_ip - rtm->code); +#endif + if (rtm == NULL || (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) + || (method->iflags & (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL | METHOD_IMPL_ATTRIBUTE_RUNTIME))) { + goto exit_frame; + } + ip_offset = frame->ip - rtm->code; + + if (endfinally_ip != NULL) + finally_ips = g_slist_prepend(finally_ips, (void *)endfinally_ip); + for (i = 0; i < header->num_clauses; ++i) + if (frame->ex_handler == &rtm->clauses [i]) + break; + while (i > 0) { + --i; + clause = &rtm->clauses [i]; + if (MONO_OFFSET_IN_CLAUSE (clause, ip_offset) && (endfinally_ip == NULL || !(MONO_OFFSET_IN_CLAUSE (clause, endfinally_ip - rtm->code)))) { + if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY) { + ip = rtm->code + clause->handler_offset; + finally_ips = g_slist_prepend (finally_ips, (gpointer) ip); +#if DEBUG_INTERP + if (tracing) + g_print ("* Found finally at IL_%04x with exception: %s\n", clause->handler_offset, frame->ex? "yes": "no"); +#endif + } + } + } + + endfinally_ip = NULL; + + if (old_list != finally_ips && finally_ips) { + ip = finally_ips->data; + finally_ips = g_slist_remove (finally_ips, ip); + sp = frame->stack; /* spec says stack should be empty at endfinally so it should be at the start too */ + goto main_loop; + } + + /* + * If an exception is set, we need to execute the fault handler, too, + * otherwise, we continue normally. + */ + if (frame->ex) + goto handle_fault; + ves_abort(); + } + handle_fault: + { + int i; + guint32 ip_offset; + MonoExceptionClause *clause; + MonoMethod *method = frame->runtime_method->method; + MonoMethodHeader *header = mono_method_get_header_checked (method, &error); + mono_error_cleanup (&error); /* FIXME: don't swallow the error */ + +#if DEBUG_INTERP + if (tracing) + g_print ("* Handle fault\n"); +#endif + ip_offset = frame->ip - rtm->code; + for (i = 0; i < header->num_clauses; ++i) { + clause = &rtm->clauses [i]; + if (clause->flags == MONO_EXCEPTION_CLAUSE_FAULT && MONO_OFFSET_IN_CLAUSE (clause, ip_offset)) { + ip = rtm->code + clause->handler_offset; +#if DEBUG_INTERP + if (tracing) + g_print ("* Executing handler at IL_%04x\n", clause->handler_offset); +#endif + goto main_loop; + } + } + /* + * If the handler for the exception was found in this method, we jump + * to it right away, otherwise we return and let the caller run + * the finally, fault and catch blocks. + * This same code should be present in the endfault opcode, but it + * is corrently not assigned in the ECMA specs: LAMESPEC. + */ + if (frame->ex_handler) { +#if DEBUG_INTERP + if (tracing) + g_print ("* Executing handler at IL_%04x\n", frame->ex_handler->handler_offset); +#endif + ip = rtm->code + frame->ex_handler->handler_offset; + sp = frame->stack; + vt_sp = (unsigned char *) sp + rtm->stack_size; + sp->data.p = frame->ex; + ++sp; + goto main_loop; + } + goto exit_frame; + } +exit_frame: + DEBUG_LEAVE (); +} + +void +ves_exec_method (MonoInvocation *frame) +{ + ThreadContext *context = mono_native_tls_get_value (thread_context_id); + ThreadContext context_struct; + MonoError error; + jmp_buf env; + + frame->ex = NULL; + + if (setjmp(env)) { + mono_unhandled_exception ((MonoObject*)frame->ex); + return; + } + if (context == NULL) { + context = &context_struct; + context_struct.domain = mono_domain_get (); + context_struct.base_frame = frame; + context_struct.current_frame = NULL; + context_struct.env_frame = frame; + context_struct.current_env = &env; + context_struct.search_for_handler = 0; + context_struct.managed_code = 0; + mono_native_tls_set_value (thread_context_id, context); + } + frame->ip = NULL; + frame->parent = context->current_frame; + frame->runtime_method = mono_interp_get_runtime_method (context->domain, frame->method, &error); + mono_error_cleanup (&error); /* FIXME: don't swallow the error */ + context->managed_code = 1; + ves_exec_method_with_context (frame, context); + context->managed_code = 0; + if (frame->ex) { + if (context != &context_struct && context->current_env) { + context->env_frame->ex = frame->ex; + longjmp (*context->current_env, 1); + } + else + mono_unhandled_exception ((MonoObject*)frame->ex); + } + if (context->base_frame == frame) + mono_native_tls_set_value (thread_context_id, NULL); + else + context->current_frame = frame->parent; +} + +static int +ves_exec (MonoDomain *domain, MonoAssembly *assembly, int argc, char *argv[]) +{ + MonoImage *image = mono_assembly_get_image (assembly); + MonoMethod *method; + MonoError error; + int rval; + + method = mono_get_method_checked (image, mono_image_get_entry_point (image), NULL, NULL, &error); + mono_error_cleanup (&error); /* FIXME: don't swallow the error */ + + if (!method) + g_error ("No entry point method found in %s", mono_image_get_filename (image)); + + rval = mono_runtime_run_main_checked (method, argc, argv, &error); + mono_error_cleanup (&error); /* FIXME: don't swallow the error */ + return rval; +} + +static void +usage (void) +{ + fprintf (stderr, + "mint %s, the Mono ECMA CLI interpreter, (C) 2001, 2002 Ximian, Inc.\n\n" + "Usage is: mint [options] executable args...\n\n", VERSION); + fprintf (stderr, + "Runtime Debugging:\n" +#ifdef DEBUG_INTERP + " --debug\n" +#endif + " --dieonex\n" + " --noptr\t\t\tdon't print pointer addresses in trace output\n" + " --opcode-count\n" + " --print-vtable\n" + " --traceclassinit\n" + "\n" + "Development:\n" + " --debug method_name\n" + " --profile\n" + " --trace\n" + " --traceops\n" + " --regression\n" + "\n" + "Runtime:\n" + " --config filename load the specified config file instead of the default\n" + " --workers n maximum number of worker threads\n" + ); + exit (1); +} + +static MonoBoolean +interp_ves_icall_get_frame_info (gint32 skip, MonoBoolean need_file_info, + MonoReflectionMethod **method, + gint32 *iloffset, gint32 *native_offset, + MonoString **file, gint32 *line, gint32 *column) +{ + ThreadContext *context = mono_native_tls_get_value (thread_context_id); + MonoInvocation *inv = context->current_frame; + MonoError error; + int i; + + for (i = 0; inv && i < skip; inv = inv->parent) + if (inv->runtime_method != NULL) + ++i; + + if (iloffset) + *iloffset = 0; + if (native_offset) + *native_offset = 0; + if (method) { + if (inv == NULL) { + *method = NULL; + } else { + *method = mono_method_get_object_checked (context->domain, inv->runtime_method->method, NULL, &error); + mono_error_cleanup (&error); /* FIXME: don't swallow the error */ + } + } + if (line) + *line = 0; + if (need_file_info) { + if (column) + *column = 0; + if (file) + *file = mono_string_new (mono_domain_get (), "unknown"); + } + + return TRUE; +} + +static MonoArray * +interp_ves_icall_get_trace (MonoException *exc, gint32 skip, MonoBoolean need_file_info) +{ + MonoDomain *domain = mono_domain_get (); + MonoArray *res; + MonoArray *ta = exc->trace_ips; + MonoError error; + int i, len; + + if (ta == NULL) { + /* Exception is not thrown yet */ + MonoArray *array = mono_array_new_checked (domain, mono_defaults.stack_frame_class, 0, &error); + mono_error_cleanup (&error); /* FIXME: don't swallow the error */ + return array; + } + + len = mono_array_length (ta); + + res = mono_array_new_checked (domain, mono_defaults.stack_frame_class, len > skip ? len - skip : 0, &error); + mono_error_cleanup (&error); /* FIXME: don't swallow the error */ + + for (i = skip; i < len / 2; i++) { + MonoStackFrame *sf = (MonoStackFrame *)mono_object_new_checked (domain, mono_defaults.stack_frame_class, &error); + mono_error_cleanup (&error); /* FIXME: don't swallow the error */ + gushort *ip = mono_array_get (ta, gpointer, 2 * i + 1); + RuntimeMethod *rtm = mono_array_get (ta, gpointer, 2 * i); + + if (rtm != NULL) { + sf->method = mono_method_get_object_checked (domain, rtm->method, NULL, &error); + mono_error_cleanup (&error); /* FIXME: don't swallow the error */ + sf->native_offset = ip - rtm->code; + } + +#if 0 + sf->il_offset = mono_debug_il_offset_from_address (ji->method, sf->native_offset, domain); + + if (need_file_info) { + gchar *filename; + + filename = mono_debug_source_location_from_address (ji->method, sf->native_offset, &sf->line, domain); + + sf->filename = filename? mono_string_new (domain, filename): NULL; + sf->column = 0; + + g_free (filename); + } +#endif + + mono_array_set (res, gpointer, i, sf); + } + + return res; +} + +void +mono_interp_init () +{ + mono_native_tls_alloc (&thread_context_id, NULL); + mono_native_tls_set_value (thread_context_id, NULL); + mono_os_mutex_init_recursive (&runtime_method_lookup_section); + mono_os_mutex_init_recursive (&create_method_pointer_mutex); + + mono_interp_transform_init (); +} + +typedef int (*TestMethod) (void); + +static void +interp_regression_step (MonoImage *image, int verbose, int *total_run, int *total, GTimer *timer, MonoDomain *domain) +{ + int result, expected, failed, cfailed, run; + double elapsed, transform_time; + int i; + MonoObject *result_obj; + static gboolean filter_method_init = FALSE; + static const char *filter_method = NULL; + + g_print ("Test run: image=%s\n", mono_image_get_filename (image)); + cfailed = failed = run = 0; + transform_time = elapsed = 0.0; + +#if 0 + /* fixme: ugly hack - delete all previously compiled methods */ + if (domain_jit_info (domain)) { + g_hash_table_destroy (domain_jit_info (domain)->jit_trampoline_hash); + domain_jit_info (domain)->jit_trampoline_hash = g_hash_table_new (mono_aligned_addr_hash, NULL); + mono_internal_hash_table_destroy (&(domain->jit_code_hash)); + mono_jit_code_hash_init (&(domain->jit_code_hash)); + } +#endif + + g_timer_start (timer); + for (i = 0; i < mono_image_get_table_rows (image, MONO_TABLE_METHOD); ++i) { + MonoObject *exc = NULL; + MonoError error; + MonoMethod *method = mono_get_method_checked (image, MONO_TOKEN_METHOD_DEF | (i + 1), NULL, NULL, &error); + if (!method) { + mono_error_cleanup (&error); /* FIXME don't swallow the error */ + continue; + } + + if (!filter_method_init) { + filter_method = g_getenv ("INTERP_FILTER_METHOD"); + filter_method_init = TRUE; + } + gboolean filter = FALSE; + if (filter_method) { + const char *name = filter_method; + + if ((strchr (name, '.') > name) || strchr (name, ':')) { + MonoMethodDesc *desc = mono_method_desc_new (name, TRUE); + filter = mono_method_desc_full_match (desc, method); + mono_method_desc_free (desc); + } else { + filter = strcmp (method->name, name) == 0; + } + } else { /* no filter, check for `Category' attribute on method */ + filter = TRUE; + MonoCustomAttrInfo* ainfo = mono_custom_attrs_from_method_checked (method, &error); + mono_error_cleanup (&error); + + if (ainfo) { + int j; + for (j = 0; j < ainfo->num_attrs && filter; ++j) { + MonoCustomAttrEntry *centry = &ainfo->attrs [j]; + if (centry->ctor == NULL) + continue; + + MonoClass *klass = centry->ctor->klass; + if (strcmp (klass->name, "CategoryAttribute")) + continue; + + MonoObject *obj = mono_custom_attrs_get_attr_checked (ainfo, klass, &error); + /* FIXME: there is an ordering problem if there're multiple attributes, do this instead: + * MonoObject *obj = create_custom_attr (ainfo->image, centry->ctor, centry->data, centry->data_size, &error); */ + mono_error_cleanup (&error); + MonoMethod *getter = mono_class_get_method_from_name (klass, "get_Category", -1); + MonoObject *str = mono_interp_runtime_invoke (getter, obj, NULL, &exc, &error); + mono_error_cleanup (&error); + char *utf8_str = mono_string_to_utf8_checked ((MonoString *) str, &error); + mono_error_cleanup (&error); + if (!strcmp (utf8_str, "!INTERPRETER")) { + g_print ("skip %s...\n", method->name); + filter = FALSE; + } + } + } + } + if (strncmp (method->name, "test_", 5) == 0 && filter) { + MonoError interp_error; + MonoObject *exc = NULL; + + result_obj = mono_interp_runtime_invoke (method, NULL, NULL, &exc, &interp_error); + if (!mono_error_ok (&interp_error)) { + cfailed++; + g_print ("Test '%s' execution failed.\n", method->name); + } else if (exc != NULL) { + g_print ("Exception in Test '%s' occured:\n", method->name); + mono_object_describe (exc); + run++; + failed++; + } else { + result = *(gint32 *) mono_object_unbox (result_obj); + expected = atoi (method->name + 5); // FIXME: oh no. + run++; + + if (result != expected) { + failed++; + g_print ("Test '%s' failed result (got %d, expected %d).\n", method->name, result, expected); + } + } + } + } + g_timer_stop (timer); + elapsed = g_timer_elapsed (timer, NULL); + if (failed > 0 || cfailed > 0){ + g_print ("Results: total tests: %d, failed: %d, cfailed: %d (pass: %.2f%%)\n", + run, failed, cfailed, 100.0*(run-failed-cfailed)/run); + } else { + g_print ("Results: total tests: %d, all pass \n", run); + } + + g_print ("Elapsed time: %f secs (%f, %f)\n\n", elapsed, + elapsed - transform_time, transform_time); + *total += failed + cfailed; + *total_run += run; +} +static int +interp_regression (MonoImage *image, int verbose, int *total_run) +{ + MonoMethod *method; + GTimer *timer = g_timer_new (); + MonoDomain *domain = mono_domain_get (); + guint32 i; + int total; + + /* load the metadata */ + for (i = 0; i < mono_image_get_table_rows (image, MONO_TABLE_METHOD); ++i) { + MonoError error; + method = mono_get_method_checked (image, MONO_TOKEN_METHOD_DEF | (i + 1), NULL, NULL, &error); + if (!method) { + mono_error_cleanup (&error); + continue; + } + mono_class_init (method->klass); + } + + total = 0; + *total_run = 0; + interp_regression_step (image, verbose, total_run, &total, timer, domain); + + g_timer_destroy (timer); + return total; +} + +int +mono_interp_regression_list (int verbose, int count, char *images []) +{ + int i, total, total_run, run; + + total_run = total = 0; + for (i = 0; i < count; ++i) { + MonoAssembly *ass = mono_assembly_open (images [i], NULL); + if (!ass) { + g_warning ("failed to load assembly: %s", images [i]); + continue; + } + total += interp_regression (mono_assembly_get_image (ass), verbose, &run); + total_run += run; + } + if (total > 0) { + g_print ("Overall results: tests: %d, failed: %d (pass: %.2f%%)\n", total_run, total, 100.0*(total_run-total)/total_run); + } else { + g_print ("Overall results: tests: %d, 100%% pass\n", total_run); + } + + return total; +} + diff --git a/mono/mini/interp/interp.h b/mono/mini/interp/interp.h new file mode 100644 index 00000000000..59428a882f2 --- /dev/null +++ b/mono/mini/interp/interp.h @@ -0,0 +1,22 @@ +#ifndef __MONO_MINI_INTERPRETER_H__ +#define __MONO_MINI_INTERPRETER_H__ +#include + +int +mono_interp_regression_list (int verbose, int count, char *images []); + +void +mono_interp_init (void); + +gpointer +mono_interp_create_method_pointer (MonoMethod *method, MonoError *error); + +MonoObject* +mono_interp_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError *error); + +void +mono_interp_init_delegate (MonoDelegate *del); + +void +interp_walk_stack_with_ctx (MonoInternalStackWalk func, MonoContext *ctx, MonoUnwindOptions options, void *user_data); +#endif /* __MONO_MINI_INTERPRETER_H__ */ diff --git a/mono/mini/interp/mintops.c b/mono/mini/interp/mintops.c new file mode 100644 index 00000000000..5b4d69269e8 --- /dev/null +++ b/mono/mini/interp/mintops.c @@ -0,0 +1,120 @@ +/* + * Utilities for handling interpreter VM instructions + * + * Authors: + * Bernie Solomon (bernard@ugsolutions.com) + * + */ +#include +#include +#include "mintops.h" + +#define OPDEF(a,b,c,d) \ + b, +const char *mono_interp_opname[] = { +#include "mintops.def" + "" +}; +#undef OPDEF + +#define OPDEF(a,b,c,d) \ + c, +unsigned char mono_interp_oplen[] = { +#include "mintops.def" + 0 +}; +#undef OPDEF + + +#define OPDEF(a,b,c,d) \ + d, +MintOpArgType mono_interp_opargtype[] = { +#include "mintops.def" + 0 +}; +#undef OPDEF + +const guint16 * +mono_interp_dis_mintop(const guint16 *base, const guint16 *ip) +{ + int len = mono_interp_oplen [*ip]; + guint32 token; + int target; + if (len < 0 || len > 10) { + g_print ("op %d len %d\n", *ip, len); + g_assert_not_reached (); + } else if (len == 0) { /* SWITCH */ + int n = READ32 (ip + 1); + len = 3 + n * 2; + } + + g_print ("IL_%04x: %-10s", ip - base, mono_interp_opname [*ip]); + switch (mono_interp_opargtype [*ip]) { + case MintOpNoArgs: + break; + case MintOpUShortInt: + g_print (" %u", * (guint16 *)(ip + 1)); + break; + case MintOpTwoShorts: + g_print (" %u,%u", * (guint16 *)(ip + 1), * (guint16 *)(ip + 2)); + break; + case MintOpShortAndInt: + g_print (" %u,%u", * (guint16 *)(ip + 1), (guint32)READ32(ip + 2)); + break; + case MintOpShortInt: + g_print (" %d", * (short *)(ip + 1)); + break; + case MintOpClassToken: + case MintOpMethodToken: + case MintOpFieldToken: + token = * (guint16 *)(ip + 1); + g_print (" %u", token); + break; + case MintOpInt: + g_print (" %d", (gint32)READ32 (ip + 1)); + break; + case MintOpLongInt: + g_print (" %lld", (gint64)READ64 (ip + 1)); + break; + case MintOpFloat: { + gint32 tmp = READ32 (ip + 1); + g_print (" %g", * (float *)&tmp); + break; + } + case MintOpDouble: { + gint64 tmp = READ64 (ip + 1); + g_print (" %g", * (double *)&tmp); + break; + } + case MintOpShortBranch: + target = ip + * (short *)(ip + 1) - base; + g_print (" IL_%04x", target); + break; + case MintOpBranch: + target = ip + (gint32)READ32 (ip + 1) - base; + g_print (" IL_%04x", target); + break; + case MintOpSwitch: { + const guint16 *p = ip + 1; + int sval = (gint32)READ32 (p); + int i; + p += 2; + g_print ("("); + for (i = 0; i < sval; ++i) { + int offset; + if (i > 0) + g_print (", "); + offset = (gint32)READ32 (p); + g_print ("IL_%04x", ip - base + 3 + 2 * sval + offset); + p += 2; + } + g_print (")"); + break; + } + default: + g_print("unknown arg type\n"); + } + + return ip + len; +} + diff --git a/mono/mini/interp/mintops.def b/mono/mini/interp/mintops.def new file mode 100644 index 00000000000..54c5422b27e --- /dev/null +++ b/mono/mini/interp/mintops.def @@ -0,0 +1,506 @@ +/* + * Definitions of VM instructions executed by interp.c + * + * Authors: + * Bernie Solomon (bernard@ugsolutions.com) + * + */ + +/* OPDEF (opsymbol, opstring, oplength, optype) */ + +OPDEF(MINT_NOP, "nop", 1, MintOpNoArgs) +OPDEF(MINT_BREAK, "break", 1, MintOpNoArgs) +OPDEF(MINT_LDNULL, "ldnull", 1, MintOpNoArgs) +OPDEF(MINT_DUP, "dup", 1, MintOpNoArgs) +OPDEF(MINT_DUP_VT, "dup.vt", 3, MintOpInt) +OPDEF(MINT_POP, "pop", 2, MintOpShortInt) + +OPDEF(MINT_RET, "ret", 1, MintOpNoArgs) +OPDEF(MINT_RET_VOID, "ret.void", 1, MintOpNoArgs) +OPDEF(MINT_RET_VT, "ret.vt", 3, MintOpInt) + +OPDEF(MINT_VTRESULT, "vtresult", 4, MintOpShortAndInt) /*FIX should be unsigned*/ + +OPDEF(MINT_LDC_I4_M1, "ldc.i4.m1", 1, MintOpNoArgs) +OPDEF(MINT_LDC_I4_0, "ldc.i4.0", 1, MintOpNoArgs) +OPDEF(MINT_LDC_I4_1, "ldc.i4.1", 1, MintOpNoArgs) +OPDEF(MINT_LDC_I4_2, "ldc.i4.2", 1, MintOpNoArgs) +OPDEF(MINT_LDC_I4_3, "ldc.i4.3", 1, MintOpNoArgs) +OPDEF(MINT_LDC_I4_4, "ldc.i4.4", 1, MintOpNoArgs) +OPDEF(MINT_LDC_I4_5, "ldc.i4.5", 1, MintOpNoArgs) +OPDEF(MINT_LDC_I4_6, "ldc.i4.6", 1, MintOpNoArgs) +OPDEF(MINT_LDC_I4_7, "ldc.i4.7", 1, MintOpNoArgs) +OPDEF(MINT_LDC_I4_8, "ldc.i4.8", 1, MintOpNoArgs) + +OPDEF(MINT_LDC_I4_S, "ldc.i4.s", 2, MintOpShortInt) +OPDEF(MINT_LDC_I4, "ldc.i4", 3, MintOpInt) +OPDEF(MINT_LDC_I8, "ldc.i8", 5, MintOpLongInt) + +OPDEF(MINT_LDC_R4, "ldc.r4", 3, MintOpFloat) +OPDEF(MINT_LDC_R8, "ldc.r8", 5, MintOpDouble) + +OPDEF(MINT_LDARG_I1, "ldarg.i1", 2, MintOpUShortInt) +OPDEF(MINT_LDARG_U1, "ldarg.u1", 2, MintOpUShortInt) +OPDEF(MINT_LDARG_I2, "ldarg.i2", 2, MintOpUShortInt) +OPDEF(MINT_LDARG_U2, "ldarg.u2", 2, MintOpUShortInt) +OPDEF(MINT_LDARG_I4, "ldarg.i4", 2, MintOpUShortInt) +OPDEF(MINT_LDARG_I8, "ldarg.i8", 2, MintOpUShortInt) +OPDEF(MINT_LDARG_R4, "ldarg.r4", 2, MintOpUShortInt) +OPDEF(MINT_LDARG_R8, "ldarg.r8", 2, MintOpUShortInt) +OPDEF(MINT_LDARG_O, "ldarg.o", 2, MintOpUShortInt) +OPDEF(MINT_LDARG_P, "ldarg.p", 2, MintOpUShortInt) +OPDEF(MINT_LDARG_VT, "ldarg.vt", 4, MintOpShortAndInt) + +OPDEF(MINT_STARG_I1, "starg.i1", 2, MintOpUShortInt) +OPDEF(MINT_STARG_U1, "starg.u1", 2, MintOpUShortInt) +OPDEF(MINT_STARG_I2, "starg.i2", 2, MintOpUShortInt) +OPDEF(MINT_STARG_U2, "starg.u2", 2, MintOpUShortInt) +OPDEF(MINT_STARG_I4, "starg.i4", 2, MintOpUShortInt) +OPDEF(MINT_STARG_I8, "starg.i8", 2, MintOpUShortInt) +OPDEF(MINT_STARG_R4, "starg.r4", 2, MintOpUShortInt) +OPDEF(MINT_STARG_R8, "starg.r8", 2, MintOpUShortInt) +OPDEF(MINT_STARG_O, "starg.o", 2, MintOpUShortInt) +OPDEF(MINT_STARG_P, "starg.p", 2, MintOpUShortInt) +OPDEF(MINT_STARG_VT, "starg.vt", 4, MintOpShortAndInt) + +OPDEF(MINT_STINARG_I1, "stinarg.i1", 2, MintOpUShortInt) +OPDEF(MINT_STINARG_U1, "stinarg.u1", 2, MintOpUShortInt) +OPDEF(MINT_STINARG_I2, "stinarg.i2", 2, MintOpUShortInt) +OPDEF(MINT_STINARG_U2, "stinarg.u2", 2, MintOpUShortInt) +OPDEF(MINT_STINARG_I4, "stinarg.i4", 2, MintOpUShortInt) +OPDEF(MINT_STINARG_I8, "stinarg.i8", 2, MintOpUShortInt) +OPDEF(MINT_STINARG_R4, "stinarg.r4", 2, MintOpUShortInt) +OPDEF(MINT_STINARG_R8, "stinarg.r8", 2, MintOpUShortInt) +OPDEF(MINT_STINARG_O, "stinarg.o", 2, MintOpUShortInt) +OPDEF(MINT_STINARG_P, "stinarg.p", 2, MintOpUShortInt) +OPDEF(MINT_STINARG_VT, "stinarg.vt", 4, MintOpShortAndInt) + +OPDEF(MINT_LDARGA, "ldarga", 2, MintOpUShortInt) +OPDEF(MINT_LDTHISA, "ldthisa", 1, MintOpNoArgs) + +OPDEF(MINT_LDFLD_I1, "ldfld.i1", 2, MintOpUShortInt) +OPDEF(MINT_LDFLD_U1, "ldfld.u1", 2, MintOpUShortInt) +OPDEF(MINT_LDFLD_I2, "ldfld.i2", 2, MintOpUShortInt) +OPDEF(MINT_LDFLD_U2, "ldfld.u2", 2, MintOpUShortInt) +OPDEF(MINT_LDFLD_I4, "ldfld.i4", 2, MintOpUShortInt) +OPDEF(MINT_LDFLD_I8, "ldfld.i8", 2, MintOpUShortInt) +OPDEF(MINT_LDFLD_R4, "ldfld.r4", 2, MintOpUShortInt) +OPDEF(MINT_LDFLD_R8, "ldfld.r8", 2, MintOpUShortInt) +OPDEF(MINT_LDFLD_O, "ldfld.o", 2, MintOpUShortInt) +OPDEF(MINT_LDFLD_P, "ldfld.p", 2, MintOpUShortInt) +OPDEF(MINT_LDFLD_VT, "ldfld.vt", 4, MintOpShortAndInt) + +OPDEF(MINT_LDRMFLD, "ldrmfld", 2, MintOpFieldToken) +OPDEF(MINT_LDRMFLD_VT, "ldrmfld.vt", 4, MintOpShortAndInt) + +OPDEF(MINT_LDFLDA, "ldflda", 2, MintOpUShortInt) + +OPDEF(MINT_STFLD_I1, "stfld.i1", 2, MintOpUShortInt) +OPDEF(MINT_STFLD_U1, "stfld.u1", 2, MintOpUShortInt) +OPDEF(MINT_STFLD_I2, "stfld.i2", 2, MintOpUShortInt) +OPDEF(MINT_STFLD_U2, "stfld.u2", 2, MintOpUShortInt) +OPDEF(MINT_STFLD_I4, "stfld.i4", 2, MintOpUShortInt) +OPDEF(MINT_STFLD_I8, "stfld.i8", 2, MintOpUShortInt) +OPDEF(MINT_STFLD_R4, "stfld.r4", 2, MintOpUShortInt) +OPDEF(MINT_STFLD_R8, "stfld.r8", 2, MintOpUShortInt) +OPDEF(MINT_STFLD_O, "stfld.o", 2, MintOpUShortInt) +OPDEF(MINT_STFLD_P, "stfld.p", 2, MintOpUShortInt) +OPDEF(MINT_STFLD_VT, "stfld.vt", 4, MintOpShortAndInt) + +OPDEF(MINT_STRMFLD, "strmfld", 2, MintOpFieldToken) +OPDEF(MINT_STRMFLD_VT, "strmfld.vt", 4, MintOpShortAndInt) + +OPDEF(MINT_LDSFLD, "ldsfld", 2, MintOpFieldToken) +OPDEF(MINT_LDSFLD_VT, "ldsfld.vt", 4, MintOpShortAndInt) +OPDEF(MINT_STSFLD, "stsfld", 2, MintOpUShortInt) +OPDEF(MINT_STSFLD_VT, "stsfld.vt", 4, MintOpShortAndInt) +OPDEF(MINT_LDSFLDA, "ldsflda", 2, MintOpUShortInt) + +OPDEF(MINT_LDLOC_I1, "ldloc.i1", 2, MintOpUShortInt) +OPDEF(MINT_LDLOC_U1, "ldloc.u1", 2, MintOpUShortInt) +OPDEF(MINT_LDLOC_I2, "ldloc.i2", 2, MintOpUShortInt) +OPDEF(MINT_LDLOC_U2, "ldloc.u2", 2, MintOpUShortInt) +OPDEF(MINT_LDLOC_I4, "ldloc.i4", 2, MintOpUShortInt) +OPDEF(MINT_LDLOC_I8, "ldloc.i8", 2, MintOpUShortInt) +OPDEF(MINT_LDLOC_R4, "ldloc.r4", 2, MintOpUShortInt) +OPDEF(MINT_LDLOC_R8, "ldloc.r8", 2, MintOpUShortInt) +OPDEF(MINT_LDLOC_O, "ldloc.o", 2, MintOpUShortInt) +OPDEF(MINT_LDLOC_P, "ldloc.p", 2, MintOpUShortInt) +OPDEF(MINT_LDLOC_VT, "ldloc.vt", 4, MintOpShortAndInt) + +OPDEF(MINT_STLOC_I1, "stloc.i1", 2, MintOpUShortInt) +OPDEF(MINT_STLOC_U1, "stloc.u1", 2, MintOpUShortInt) +OPDEF(MINT_STLOC_I2, "stloc.i2", 2, MintOpUShortInt) +OPDEF(MINT_STLOC_U2, "stloc.u2", 2, MintOpUShortInt) +OPDEF(MINT_STLOC_I4, "stloc.i4", 2, MintOpUShortInt) +OPDEF(MINT_STLOC_I8, "stloc.i8", 2, MintOpUShortInt) +OPDEF(MINT_STLOC_R4, "stloc.r4", 2, MintOpUShortInt) +OPDEF(MINT_STLOC_R8, "stloc.r8", 2, MintOpUShortInt) +OPDEF(MINT_STLOC_O, "stloc.o", 2, MintOpUShortInt) +OPDEF(MINT_STLOC_P, "stloc.p", 2, MintOpUShortInt) +OPDEF(MINT_STLOC_VT, "stloc.vt", 4, MintOpShortAndInt) + +OPDEF(MINT_STLOC_NP_I4, "stloc.np.i4", 2, MintOpUShortInt) +OPDEF(MINT_STLOC_NP_O, "stloc.np.o", 2, MintOpUShortInt) + +OPDEF(MINT_LDLOCA_S, "ldloca.s", 2, MintOpUShortInt) + +OPDEF(MINT_LDIND_I1, "ldind.i1", 1, MintOpNoArgs) +OPDEF(MINT_LDIND_U1, "ldind.u1", 1, MintOpNoArgs) +OPDEF(MINT_LDIND_I2, "ldind.i2", 1, MintOpNoArgs) +OPDEF(MINT_LDIND_U2, "ldind.u2", 1, MintOpNoArgs) +OPDEF(MINT_LDIND_I4, "ldind.i4", 1, MintOpNoArgs) +OPDEF(MINT_LDIND_U4, "ldind.u4", 1, MintOpNoArgs) +OPDEF(MINT_LDIND_I8, "ldind.i8", 1, MintOpNoArgs) +OPDEF(MINT_LDIND_I, "ldind.i", 2, MintOpUShortInt) +OPDEF(MINT_LDIND_R4, "ldind.r4", 1, MintOpNoArgs) +OPDEF(MINT_LDIND_R8, "ldind.r8", 1, MintOpNoArgs) +OPDEF(MINT_LDIND_REF, "ldind.ref", 1, MintOpNoArgs) +OPDEF(MINT_STIND_I1, "stind.i1", 1, MintOpNoArgs) +OPDEF(MINT_STIND_I2, "stind.i2", 1, MintOpNoArgs) +OPDEF(MINT_STIND_I4, "stind.i4", 1, MintOpNoArgs) +OPDEF(MINT_STIND_I8, "stind.i8", 1, MintOpNoArgs) +OPDEF(MINT_STIND_I, "stind.i", 1, MintOpNoArgs) +OPDEF(MINT_STIND_R4, "stind.r4", 1, MintOpNoArgs) +OPDEF(MINT_STIND_R8, "stind.r8", 1, MintOpNoArgs) +OPDEF(MINT_STIND_REF, "stind.ref", 1, MintOpNoArgs) + +OPDEF(MINT_BR, "br", 3, MintOpBranch) +OPDEF(MINT_LEAVE, "leave", 3, MintOpBranch) +OPDEF(MINT_BR_S, "br.s", 2, MintOpShortBranch) +OPDEF(MINT_LEAVE_S, "leave.s", 2, MintOpShortBranch) + +OPDEF(MINT_THROW, "throw", 1, MintOpNoArgs) +OPDEF(MINT_RETHROW, "rethrow", 1, MintOpNoArgs) +OPDEF(MINT_ENDFINALLY, "endfinally", 1, MintOpNoArgs) + +OPDEF(MINT_BRFALSE_I4, "brfalse.i4", 3, MintOpBranch) +OPDEF(MINT_BRFALSE_I8, "brfalse.i8", 3, MintOpBranch) +OPDEF(MINT_BRFALSE_R8, "brfalse.r8", 3, MintOpBranch) +OPDEF(MINT_BRTRUE_I4, "brtrue.i4", 3, MintOpBranch) +OPDEF(MINT_BRTRUE_I8, "brtrue.i8", 3, MintOpBranch) +OPDEF(MINT_BRTRUE_R8, "brtrue.r8", 3, MintOpBranch) + +OPDEF(MINT_BRFALSE_I4_S, "brfalse.i4.s", 2, MintOpShortBranch) +OPDEF(MINT_BRFALSE_I8_S, "brfalse.i8.s", 2, MintOpShortBranch) +OPDEF(MINT_BRFALSE_R8_S, "brfalse.r8.s", 2, MintOpShortBranch) +OPDEF(MINT_BRTRUE_I4_S, "brtrue.i4.s", 2, MintOpShortBranch) +OPDEF(MINT_BRTRUE_I8_S, "brtrue.i8.s", 2, MintOpShortBranch) +OPDEF(MINT_BRTRUE_R8_S, "brtrue.r8.s", 2, MintOpShortBranch) + +OPDEF(MINT_BEQ_I4, "beq.i4", 3, MintOpBranch) +OPDEF(MINT_BEQ_I8, "beq.i8", 3, MintOpBranch) +OPDEF(MINT_BEQ_R8, "beq.r8", 3, MintOpBranch) +OPDEF(MINT_BGE_I4, "bge.i4", 3, MintOpBranch) +OPDEF(MINT_BGE_I8, "bge.i8", 3, MintOpBranch) +OPDEF(MINT_BGE_R8, "bge.r8", 3, MintOpBranch) +OPDEF(MINT_BGT_I4, "bgt.i4", 3, MintOpBranch) +OPDEF(MINT_BGT_I8, "bgt.i8", 3, MintOpBranch) +OPDEF(MINT_BGT_R8, "bgt.r8", 3, MintOpBranch) +OPDEF(MINT_BLT_I4, "blt.i4", 3, MintOpBranch) +OPDEF(MINT_BLT_I8, "blt.i8", 3, MintOpBranch) +OPDEF(MINT_BLT_R8, "blt.r8", 3, MintOpBranch) +OPDEF(MINT_BLE_I4, "ble.i4", 3, MintOpBranch) +OPDEF(MINT_BLE_I8, "ble.i8", 3, MintOpBranch) +OPDEF(MINT_BLE_R8, "ble.r8", 3, MintOpBranch) + +OPDEF(MINT_BNE_UN_I4, "bne.un.i4", 3, MintOpBranch) +OPDEF(MINT_BNE_UN_I8, "bne.un.i8", 3, MintOpBranch) +OPDEF(MINT_BNE_UN_R8, "bne.un.r8", 3, MintOpBranch) +OPDEF(MINT_BGE_UN_I4, "bge.un.i4", 3, MintOpBranch) +OPDEF(MINT_BGE_UN_I8, "bge.un.i8", 3, MintOpBranch) +OPDEF(MINT_BGE_UN_R8, "bge.un.r8", 3, MintOpBranch) +OPDEF(MINT_BGT_UN_I4, "bgt.un.i4", 3, MintOpBranch) +OPDEF(MINT_BGT_UN_I8, "bgt.un.i8", 3, MintOpBranch) +OPDEF(MINT_BGT_UN_R8, "bgt.un.r8", 3, MintOpBranch) +OPDEF(MINT_BLE_UN_I4, "ble.un.i4", 3, MintOpBranch) +OPDEF(MINT_BLE_UN_I8, "ble.un.i8", 3, MintOpBranch) +OPDEF(MINT_BLE_UN_R8, "ble.un.r8", 3, MintOpBranch) +OPDEF(MINT_BLT_UN_I4, "blt.un.i4", 3, MintOpBranch) +OPDEF(MINT_BLT_UN_I8, "blt.un.i8", 3, MintOpBranch) +OPDEF(MINT_BLT_UN_R8, "blt.un.r8", 3, MintOpBranch) + +OPDEF(MINT_BEQ_I4_S, "beq.i4.s", 2, MintOpShortBranch) +OPDEF(MINT_BEQ_I8_S, "beq.i8.s", 2, MintOpShortBranch) +OPDEF(MINT_BEQ_R8_S, "beq.r8.s", 2, MintOpShortBranch) +OPDEF(MINT_BGE_I4_S, "bge.i4.s", 2, MintOpShortBranch) +OPDEF(MINT_BGE_I8_S, "bge.i8.s", 2, MintOpShortBranch) +OPDEF(MINT_BGE_R8_S, "bge.r8.s", 2, MintOpShortBranch) +OPDEF(MINT_BGT_I4_S, "bgt.i4.s", 2, MintOpShortBranch) +OPDEF(MINT_BGT_I8_S, "bgt.i8.s", 2, MintOpShortBranch) +OPDEF(MINT_BGT_R8_S, "bgt.r8.s", 2, MintOpShortBranch) +OPDEF(MINT_BLT_I4_S, "blt.i4.s", 2, MintOpShortBranch) +OPDEF(MINT_BLT_I8_S, "blt.i8.s", 2, MintOpShortBranch) +OPDEF(MINT_BLT_R8_S, "blt.r8.s", 2, MintOpShortBranch) +OPDEF(MINT_BLE_I4_S, "ble.i4.s", 2, MintOpShortBranch) +OPDEF(MINT_BLE_I8_S, "ble.i8.s", 2, MintOpShortBranch) +OPDEF(MINT_BLE_R8_S, "ble.r8.s", 2, MintOpShortBranch) + +OPDEF(MINT_BNE_UN_I4_S, "bne.un.i4.s", 2, MintOpShortBranch) +OPDEF(MINT_BNE_UN_I8_S, "bne.un.i8.s", 2, MintOpShortBranch) +OPDEF(MINT_BNE_UN_R8_S, "bne.un.r8.s", 2, MintOpShortBranch) +OPDEF(MINT_BGE_UN_I4_S, "bge.un.i4.s", 2, MintOpShortBranch) +OPDEF(MINT_BGE_UN_I8_S, "bge.un.i8.s", 2, MintOpShortBranch) +OPDEF(MINT_BGE_UN_R8_S, "bge.un.r8.s", 2, MintOpShortBranch) +OPDEF(MINT_BGT_UN_I4_S, "bgt.un.i4.s", 2, MintOpShortBranch) +OPDEF(MINT_BGT_UN_I8_S, "bgt.un.i8.s", 2, MintOpShortBranch) +OPDEF(MINT_BGT_UN_R8_S, "bgt.un.r8.s", 2, MintOpShortBranch) +OPDEF(MINT_BLE_UN_I4_S, "ble.un.i4.s", 2, MintOpShortBranch) +OPDEF(MINT_BLE_UN_I8_S, "ble.un.i8.s", 2, MintOpShortBranch) +OPDEF(MINT_BLE_UN_R8_S, "ble.un.r8.s", 2, MintOpShortBranch) +OPDEF(MINT_BLT_UN_I4_S, "blt.un.i4.s", 2, MintOpShortBranch) +OPDEF(MINT_BLT_UN_I8_S, "blt.un.i8.s", 2, MintOpShortBranch) +OPDEF(MINT_BLT_UN_R8_S, "blt.un.r8.s", 2, MintOpShortBranch) + +OPDEF(MINT_SWITCH, "switch", 0, MintOpSwitch) + +OPDEF(MINT_LDSTR, "ldstr", 2, MintOpMethodToken) /* not really */ + +OPDEF(MINT_CALL, "call", 2, MintOpMethodToken) +OPDEF(MINT_VCALL, "vcall", 2, MintOpMethodToken) +OPDEF(MINT_CALLVIRT, "callvirt", 2, MintOpMethodToken) +OPDEF(MINT_VCALLVIRT, "vcallvirt", 2, MintOpMethodToken) +OPDEF(MINT_CALLI, "calli", 2, MintOpMethodToken) +OPDEF(MINT_CALLI_NAT, "calli.nat", 2, MintOpMethodToken) +OPDEF(MINT_JMP, "jmp", 2, MintOpMethodToken) + +OPDEF(MINT_CALLRUN, "callrun", 1, MintOpNoArgs) + +OPDEF(MINT_NEWOBJ, "newobj", 2, MintOpMethodToken) +OPDEF(MINT_INITOBJ, "initobj", 3, MintOpInt) +OPDEF(MINT_CASTCLASS, "castclass", 2, MintOpClassToken) +OPDEF(MINT_ISINST, "isinst", 2, MintOpClassToken) +OPDEF(MINT_NEWARR, "newarr", 2, MintOpClassToken) +OPDEF(MINT_BOX, "box", 3, MintOpTwoShorts) +OPDEF(MINT_UNBOX, "unbox", 2, MintOpClassToken) +OPDEF(MINT_LDTOKEN, "ldtoken", 2, MintOpClassToken) /* not really */ +OPDEF(MINT_LDFTN, "ldftn", 2, MintOpMethodToken) +OPDEF(MINT_LDVIRTFTN, "ldvirtftn", 2, MintOpMethodToken) +OPDEF(MINT_LDOBJ, "ldobj", 2, MintOpClassToken) +OPDEF(MINT_STOBJ, "stobj", 2, MintOpClassToken) +OPDEF(MINT_STOBJ_VT, "stobj.vt", 2, MintOpClassToken) +OPDEF(MINT_CPBLK, "cpblk", 1, MintOpNoArgs) +OPDEF(MINT_INITBLK, "initblk", 1, MintOpNoArgs) +OPDEF(MINT_LOCALLOC, "localloc", 1, MintOpNoArgs) +OPDEF(MINT_INITLOCALS, "initlocals", 1, MintOpNoArgs) + +OPDEF(MINT_LDELEM_I, "ldelem.i", 1, MintOpNoArgs) +OPDEF(MINT_LDELEM_I1, "ldelem.i1", 1, MintOpNoArgs) +OPDEF(MINT_LDELEM_U1, "ldelem.u1", 1, MintOpNoArgs) +OPDEF(MINT_LDELEM_I2, "ldelem.i2", 1, MintOpNoArgs) +OPDEF(MINT_LDELEM_U2, "ldelem.u2", 1, MintOpNoArgs) +OPDEF(MINT_LDELEM_I4, "ldelem.i4", 1, MintOpNoArgs) +OPDEF(MINT_LDELEM_U4, "ldelem.u4", 1, MintOpNoArgs) +OPDEF(MINT_LDELEM_I8, "ldelem.i8", 1, MintOpNoArgs) +OPDEF(MINT_LDELEM_R4, "ldelem.r4", 1, MintOpNoArgs) +OPDEF(MINT_LDELEM_R8, "ldelem.r8", 1, MintOpNoArgs) +OPDEF(MINT_LDELEM_REF, "ldelem.ref", 1, MintOpNoArgs) +OPDEF(MINT_LDELEM_VT, "ldelem.vt", 4, MintOpShortAndInt) + +OPDEF(MINT_LDELEMA, "ldelema", 2, MintOpClassToken) + +OPDEF(MINT_STELEM_I, "stelem.i", 1, MintOpNoArgs) +OPDEF(MINT_STELEM_I1, "stelem.i1", 1, MintOpNoArgs) +OPDEF(MINT_STELEM_I2, "stelem.i2", 1, MintOpNoArgs) +OPDEF(MINT_STELEM_I4, "stelem.i4", 1, MintOpNoArgs) +OPDEF(MINT_STELEM_I8, "stelem.i8", 1, MintOpNoArgs) +OPDEF(MINT_STELEM_R4, "stelem.r4", 1, MintOpNoArgs) +OPDEF(MINT_STELEM_R8, "stelem.r8", 1, MintOpNoArgs) +OPDEF(MINT_STELEM_REF, "stelem.ref", 1, MintOpNoArgs) +OPDEF(MINT_STELEM_VT, "stelem.vt", 4, MintOpShortAndInt) + +OPDEF(MINT_LDLEN, "ldlen", 1, MintOpNoArgs) + +OPDEF(MINT_ADD_I4, "add.i4", 1, MintOpNoArgs) +OPDEF(MINT_ADD_I8, "add.i8", 1, MintOpNoArgs) +OPDEF(MINT_ADD_R8, "add.r8", 1, MintOpNoArgs) + +OPDEF(MINT_ADD1_I4, "add1.i4", 1, MintOpNoArgs) + +OPDEF(MINT_SUB_I4, "sub.i4", 1, MintOpNoArgs) +OPDEF(MINT_SUB_I8, "sub.i8", 1, MintOpNoArgs) +OPDEF(MINT_SUB_R8, "sub.r8", 1, MintOpNoArgs) + +OPDEF(MINT_SUB1_I4, "sub1.i4", 1, MintOpNoArgs) + +OPDEF(MINT_MUL_I4, "mul.i4", 1, MintOpNoArgs) +OPDEF(MINT_MUL_I8, "mul.i8", 1, MintOpNoArgs) +OPDEF(MINT_MUL_R8, "mul.r8", 1, MintOpNoArgs) + +OPDEF(MINT_DIV_I4, "div.i4", 1, MintOpNoArgs) +OPDEF(MINT_DIV_I8, "div.i8", 1, MintOpNoArgs) +OPDEF(MINT_DIV_R8, "div.r8", 1, MintOpNoArgs) + +OPDEF(MINT_DIV_UN_I4, "div.un.i4", 1, MintOpNoArgs) +OPDEF(MINT_DIV_UN_I8, "div.un.i8", 1, MintOpNoArgs) + +OPDEF(MINT_ADD_OVF_I4, "add.ovf.i4", 1, MintOpNoArgs) +OPDEF(MINT_ADD_OVF_I8, "add.ovf.i8", 1, MintOpNoArgs) + +OPDEF(MINT_ADD_OVF_UN_I4, "add.ovf.un.i4", 1, MintOpNoArgs) +OPDEF(MINT_ADD_OVF_UN_I8, "add.ovf.un.i8", 1, MintOpNoArgs) + +OPDEF(MINT_MUL_OVF_I4, "mul.ovf.i4", 1, MintOpNoArgs) +OPDEF(MINT_MUL_OVF_I8, "mul.ovf.i8", 1, MintOpNoArgs) + +OPDEF(MINT_MUL_OVF_UN_I4, "mul.ovf.un.i4", 1, MintOpNoArgs) +OPDEF(MINT_MUL_OVF_UN_I8, "mul.ovf.un.i8", 1, MintOpNoArgs) + +OPDEF(MINT_SUB_OVF_I4, "sub.ovf.i4", 1, MintOpNoArgs) +OPDEF(MINT_SUB_OVF_I8, "sub.ovf.i8", 1, MintOpNoArgs) + +OPDEF(MINT_SUB_OVF_UN_I4, "sub.ovf.un.i4", 1, MintOpNoArgs) +OPDEF(MINT_SUB_OVF_UN_I8, "sub.ovf.un.i8", 1, MintOpNoArgs) + +OPDEF(MINT_NEG_I4, "neg.i4", 1, MintOpNoArgs) +OPDEF(MINT_NEG_I8, "neg.i8", 1, MintOpNoArgs) +OPDEF(MINT_NEG_R8, "neg.r8", 1, MintOpNoArgs) + +OPDEF(MINT_NOT_I4, "not.i4", 1, MintOpNoArgs) +OPDEF(MINT_NOT_I8, "not.i8", 1, MintOpNoArgs) + +OPDEF(MINT_AND_I4, "and.i4", 1, MintOpNoArgs) +OPDEF(MINT_AND_I8, "and.i8", 1, MintOpNoArgs) + +OPDEF(MINT_OR_I4, "or.i4", 1, MintOpNoArgs) +OPDEF(MINT_OR_I8, "or.i8", 1, MintOpNoArgs) + +OPDEF(MINT_XOR_I4, "xor.i4", 1, MintOpNoArgs) +OPDEF(MINT_XOR_I8, "xor.i8", 1, MintOpNoArgs) + +OPDEF(MINT_REM_I4, "rem.i4", 1, MintOpNoArgs) +OPDEF(MINT_REM_I8, "rem.i8", 1, MintOpNoArgs) +OPDEF(MINT_REM_R8, "rem.r8", 1, MintOpNoArgs) + +OPDEF(MINT_REM_UN_I4, "rem.un.i4", 1, MintOpNoArgs) +OPDEF(MINT_REM_UN_I8, "rem.un.i8", 1, MintOpNoArgs) + +OPDEF(MINT_SHR_UN_I4, "shr.un.i4", 1, MintOpNoArgs) +OPDEF(MINT_SHR_UN_I8, "shr.un.i8", 1, MintOpNoArgs) +OPDEF(MINT_SHL_I4, "shl.i4", 1, MintOpNoArgs) +OPDEF(MINT_SHL_I8, "shl.i8", 1, MintOpNoArgs) +OPDEF(MINT_SHR_I4, "shr.i4", 1, MintOpNoArgs) +OPDEF(MINT_SHR_I8, "shr.i8", 1, MintOpNoArgs) + +OPDEF(MINT_CONV_R_UN_I4, "conv.r.un.i4", 1, MintOpNoArgs) +OPDEF(MINT_CONV_R_UN_I8, "conv.r.un.i8", 1, MintOpNoArgs) + +OPDEF(MINT_CONV_I1_I4, "conv.i1.i4", 1, MintOpNoArgs) +OPDEF(MINT_CONV_I1_I8, "conv.i1.i8", 1, MintOpNoArgs) +OPDEF(MINT_CONV_I1_R8, "conv.i1.r8", 1, MintOpNoArgs) + +OPDEF(MINT_CONV_U1_I4, "conv.u1.i4", 1, MintOpNoArgs) +OPDEF(MINT_CONV_U1_I8, "conv.u1.i8", 1, MintOpNoArgs) +OPDEF(MINT_CONV_U1_R8, "conv.u1.r8", 1, MintOpNoArgs) + +OPDEF(MINT_CONV_I2_I4, "conv.i2.i4", 1, MintOpNoArgs) +OPDEF(MINT_CONV_I2_I8, "conv.i2.i8", 1, MintOpNoArgs) +OPDEF(MINT_CONV_I2_R8, "conv.i2.r8", 1, MintOpNoArgs) + +OPDEF(MINT_CONV_U2_I4, "conv.u2.i4", 1, MintOpNoArgs) +OPDEF(MINT_CONV_U2_I8, "conv.u2.i8", 1, MintOpNoArgs) +OPDEF(MINT_CONV_U2_R8, "conv.u2.r8", 1, MintOpNoArgs) + +OPDEF(MINT_CONV_I4_I8, "conv.i4.i8", 1, MintOpNoArgs) +OPDEF(MINT_CONV_I4_R8, "conv.i4.r8", 1, MintOpNoArgs) + +OPDEF(MINT_CONV_U4_I8, "conv.u4.i8", 1, MintOpNoArgs) +OPDEF(MINT_CONV_U4_R8, "conv.u4.r8", 1, MintOpNoArgs) + +OPDEF(MINT_CONV_I8_I4, "conv.i8.i4", 1, MintOpNoArgs) +OPDEF(MINT_CONV_I8_U4, "conv.i8.u4", 1, MintOpNoArgs) +OPDEF(MINT_CONV_I8_R8, "conv.i8.r8", 1, MintOpNoArgs) + +OPDEF(MINT_CONV_R4_I4, "conv.r4.i4", 1, MintOpNoArgs) +OPDEF(MINT_CONV_R4_I8, "conv.r4.i8", 1, MintOpNoArgs) +OPDEF(MINT_CONV_R4_R8, "conv.r4.r8", 1, MintOpNoArgs) + +OPDEF(MINT_CONV_R8_I4, "conv.r8.i4", 1, MintOpNoArgs) +OPDEF(MINT_CONV_R8_I8, "conv.r8.i8", 1, MintOpNoArgs) + +OPDEF(MINT_CONV_I4_I8_SP, "conv.i4.i8.sp", 1, MintOpNoArgs) /* special for narrowing sp[-2] on 64 bits */ +OPDEF(MINT_CONV_I8_I4_SP, "conv.i8.i4.sp", 1, MintOpNoArgs) /* special for widening sp[-2] on 64 bits */ + +OPDEF(MINT_CONV_U8_I4, "conv.u8.i4", 1, MintOpNoArgs) +OPDEF(MINT_CONV_U8_R8, "conv.u8.r8", 1, MintOpNoArgs) + +OPDEF(MINT_CONV_OVF_I1_I4, "conv.ovf.i1.i4", 1, MintOpNoArgs) +OPDEF(MINT_CONV_OVF_I1_I8, "conv.ovf.i1.i8", 1, MintOpNoArgs) +OPDEF(MINT_CONV_OVF_I1_R8, "conv.ovf.i1.r8", 1, MintOpNoArgs) + +OPDEF(MINT_CONV_OVF_U1_I4, "conv.ovf.u1.i4", 1, MintOpNoArgs) +OPDEF(MINT_CONV_OVF_U1_I8, "conv.ovf.u1.i8", 1, MintOpNoArgs) +OPDEF(MINT_CONV_OVF_U1_R8, "conv.ovf.u1.r8", 1, MintOpNoArgs) + +OPDEF(MINT_CONV_OVF_I2_I4, "conv.ovf.i2.i4", 1, MintOpNoArgs) +OPDEF(MINT_CONV_OVF_I2_I8, "conv.ovf.i2.i8", 1, MintOpNoArgs) +OPDEF(MINT_CONV_OVF_I2_R8, "conv.ovf.i2.r8", 1, MintOpNoArgs) + +OPDEF(MINT_CONV_OVF_U2_I4, "conv.ovf.u2.i4", 1, MintOpNoArgs) +OPDEF(MINT_CONV_OVF_U2_I8, "conv.ovf.u2.i8", 1, MintOpNoArgs) +OPDEF(MINT_CONV_OVF_U2_R8, "conv.ovf.u2.r8", 1, MintOpNoArgs) + +OPDEF(MINT_CONV_OVF_I4_U4, "conv.ovf.i4.u4", 1, MintOpNoArgs) +OPDEF(MINT_CONV_OVF_I4_I8, "conv.ovf.i4.i8", 1, MintOpNoArgs) +OPDEF(MINT_CONV_OVF_I4_R8, "conv.ovf.i4.r8", 1, MintOpNoArgs) + +OPDEF(MINT_CONV_OVF_I4_UN_I8, "conv.ovf.i4.un.i8", 1, MintOpNoArgs) +OPDEF(MINT_CONV_OVF_I4_UN_R8, "conv.ovf.i4.un.r8", 1, MintOpNoArgs) + +OPDEF(MINT_CONV_OVF_U4_I4, "conv.ovf.u4.i4", 1, MintOpNoArgs) +OPDEF(MINT_CONV_OVF_U4_I8, "conv.ovf.u4.i8", 1, MintOpNoArgs) +OPDEF(MINT_CONV_OVF_U4_R8, "conv.ovf.u4.r8", 1, MintOpNoArgs) + +OPDEF(MINT_CONV_OVF_I8_R8, "conv.ovf.i8.r8", 1, MintOpNoArgs) + +OPDEF(MINT_CONV_OVF_I8_UN_R8, "conv.ovf.i8.un.r8", 1, MintOpNoArgs) + +OPDEF(MINT_CONV_OVF_U8_I4, "conv.ovf.u8.i4", 1, MintOpNoArgs) +OPDEF(MINT_CONV_OVF_U8_R8, "conv.ovf.u8.r8", 1, MintOpNoArgs) + +OPDEF(MINT_CEQ_I4, "ceq.i4", 1, MintOpNoArgs) +OPDEF(MINT_CEQ_I8, "ceq.i8", 1, MintOpNoArgs) +OPDEF(MINT_CEQ_R8, "ceq.r8", 1, MintOpNoArgs) + +OPDEF(MINT_CEQ0_I4, "ceq0.i4", 1, MintOpNoArgs) + +OPDEF(MINT_CGT_I4, "cgt.i4", 1, MintOpNoArgs) +OPDEF(MINT_CGT_I8, "cgt.i8", 1, MintOpNoArgs) +OPDEF(MINT_CGT_R8, "cgt.r8", 1, MintOpNoArgs) + +OPDEF(MINT_CGT_UN_I4, "cgt.un.i4", 1, MintOpNoArgs) +OPDEF(MINT_CGT_UN_I8, "cgt.un.i8", 1, MintOpNoArgs) +OPDEF(MINT_CGT_UN_R8, "cgt.un.r8", 1, MintOpNoArgs) + +OPDEF(MINT_CLT_I4, "clt.i4", 1, MintOpNoArgs) +OPDEF(MINT_CLT_I8, "clt.i8", 1, MintOpNoArgs) +OPDEF(MINT_CLT_R8, "clt.r8", 1, MintOpNoArgs) + +OPDEF(MINT_CLT_UN_I4, "clt.un.i4", 1, MintOpNoArgs) +OPDEF(MINT_CLT_UN_I8, "clt.un.i8", 1, MintOpNoArgs) +OPDEF(MINT_CLT_UN_R8, "clt.un.r8", 1, MintOpNoArgs) + +OPDEF(MINT_CKFINITE, "ckfinite", 1, MintOpNoArgs) + +OPDEF(MINT_CKNULL, "cknull", 1, MintOpNoArgs) + +OPDEF(MINT_GETCHR, "getchr", 1, MintOpNoArgs) +OPDEF(MINT_STRLEN, "strlen", 1, MintOpNoArgs) +OPDEF(MINT_ARRAY_RANK, "array_rank", 1, MintOpNoArgs) + +OPDEF(MINT_ICALL_V_V, "mono_icall_v_v", 2, MintOpClassToken) /* not really */ +OPDEF(MINT_ICALL_V_P, "mono_icall_v_p", 2, MintOpClassToken) +OPDEF(MINT_ICALL_P_V, "mono_icall_p_v", 2, MintOpClassToken) +OPDEF(MINT_ICALL_P_P, "mono_icall_p_p", 2, MintOpClassToken) +OPDEF(MINT_ICALL_PP_V, "mono_icall_pp_v", 2, MintOpClassToken) +OPDEF(MINT_ICALL_PI_V, "mono_icall_pi_v", 2, MintOpClassToken) +OPDEF(MINT_ICALL_PP_P, "mono_icall_pp_p", 2, MintOpClassToken) +OPDEF(MINT_ICALL_PI_P, "mono_icall_pi_p", 2, MintOpClassToken) +OPDEF(MINT_ICALL_PPP_V, "mono_icall_ppp_v", 2, MintOpClassToken) +OPDEF(MINT_ICALL_PPI_V, "mono_icall_ppi_v", 2, MintOpClassToken) +OPDEF(MINT_MONO_LDPTR, "mono_ldptr", 2, MintOpClassToken) +OPDEF(MINT_MONO_NEWOBJ, "mono_newobj", 2, MintOpClassToken) +OPDEF(MINT_MONO_RETOBJ, "mono_retobj", 1, MintOpNoArgs) +OPDEF(MINT_MONO_FREE, "mono_free", 1, MintOpNoArgs) + + diff --git a/mono/mini/interp/mintops.h b/mono/mini/interp/mintops.h new file mode 100644 index 00000000000..e787526e2fe --- /dev/null +++ b/mono/mini/interp/mintops.h @@ -0,0 +1,58 @@ +#ifndef __INTERPRETER_MINTOPS_H +#define __INTERPRETER_MINTOPS_H + +#include + +typedef enum +{ + MintOpNoArgs, + MintOpShortInt, + MintOpUShortInt, + MintOpInt, + MintOpLongInt, + MintOpFloat, + MintOpDouble, + MintOpBranch, + MintOpShortBranch, + MintOpSwitch, + MintOpMethodToken, + MintOpFieldToken, + MintOpClassToken, + MintOpTwoShorts, + MintOpShortAndInt +} MintOpArgType; + +#define OPDEF(a,b,c,d) \ + a, +enum { +#include "mintops.def" + MINT_LASTOP +}; +#undef OPDEF + +#if NO_UNALIGNED_ACCESS +# if G_BYTE_ORDER == G_LITTLE_ENDIAN +#define READ32(x) (((guint16 *)(x)) [0] | ((guint16 *)(x)) [1] << 16) +#define READ64(x) ((guint64)((guint16 *)(x)) [0] | \ + (guint64)((guint16 *)(x)) [1] << 16 | \ + (guint64)((guint16 *)(x)) [2] << 32 | \ + (guint64)((guint16 *)(x)) [3] << 48) +# else +#define READ32(x) (((guint16 *)(x)) [0] << 16 | ((guint16 *)(x)) [1]) +#define READ64(x) ((guint64)((guint16 *)(x)) [0] << 48 | \ + (guint64)((guint16 *)(x)) [1] << 32 | \ + (guint64)((guint16 *)(x)) [2] << 16 | \ + (guint64)((guint16 *)(x)) [3]) +# endif +#else /* unaligned access OK */ +#define READ32(x) (*(guint32 *)(x)) +#define READ64(x) (*(guint64 *)(x)) +#endif + +extern const char *mono_interp_opname[]; +extern unsigned char mono_interp_oplen[]; +extern MintOpArgType mono_interp_opargtype[]; +extern const guint16 *mono_interp_dis_mintop(const unsigned short *base, const guint16 *ip); + +#endif + diff --git a/mono/mini/interp/transform.c b/mono/mini/interp/transform.c new file mode 100644 index 00000000000..e5e2ec931d3 --- /dev/null +++ b/mono/mini/interp/transform.c @@ -0,0 +1,3382 @@ +/* + * transform CIL into different opcodes for more + * efficient interpretation + * + * Written by Bernie Solomon (bernard@ugsolutions.com) + * Copyright (c) 2004. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "mintops.h" +#include "interp-internals.h" +#include "interp.h" + +// TODO: export from marshal.c +MonoDelegate* mono_ftnptr_to_delegate (MonoClass *klass, gpointer ftn); + +#define DEBUG 0 + +typedef struct +{ + MonoClass *klass; + unsigned char type; + unsigned char flags; +} StackInfo; + +typedef struct +{ + MonoMethod *method; + MonoMethodHeader *header; + RuntimeMethod *rtm; + const unsigned char *il_code; + const unsigned char *ip; + const unsigned char *last_ip; + const unsigned char *in_start; + int code_size; + int *in_offsets; + int *forward_refs; + StackInfo **stack_state; + int *stack_height; + int *vt_stack_size; + unsigned char *is_bb_start; + unsigned short *new_code; + unsigned short *new_code_end; + unsigned short *new_ip; + unsigned short *last_new_ip; + unsigned int max_code_size; + StackInfo *stack; + StackInfo *sp; + unsigned int max_stack_height; + unsigned int vt_sp; + unsigned int max_vt_sp; + int n_data_items; + int max_data_items; + void **data_items; + GHashTable *data_hash; +} TransformData; + +#define MINT_TYPE_I1 0 +#define MINT_TYPE_U1 1 +#define MINT_TYPE_I2 2 +#define MINT_TYPE_U2 3 +#define MINT_TYPE_I4 4 +#define MINT_TYPE_I8 5 +#define MINT_TYPE_R4 6 +#define MINT_TYPE_R8 7 +#define MINT_TYPE_O 8 +#define MINT_TYPE_P 9 +#define MINT_TYPE_VT 10 + +#define STACK_TYPE_I4 0 +#define STACK_TYPE_I8 1 +#define STACK_TYPE_R8 2 +#define STACK_TYPE_O 3 +#define STACK_TYPE_VT 4 +#define STACK_TYPE_MP 5 +#define STACK_TYPE_F 6 + +static const char *stack_type_string [] = { "I4", "I8", "R8", "O ", "VT", "MP", "F " }; + +#if SIZEOF_VOID_P == 8 +#define STACK_TYPE_I STACK_TYPE_I8 +#else +#define STACK_TYPE_I STACK_TYPE_I4 +#endif + +static int stack_type [] = { + STACK_TYPE_I4, /*I1*/ + STACK_TYPE_I4, /*U1*/ + STACK_TYPE_I4, /*I2*/ + STACK_TYPE_I4, /*U2*/ + STACK_TYPE_I4, /*I4*/ + STACK_TYPE_I8, /*I8*/ + STACK_TYPE_R8, /*R4*/ + STACK_TYPE_R8, /*R8*/ + STACK_TYPE_O, /*O*/ + STACK_TYPE_MP, /*P*/ + STACK_TYPE_VT +}; + +static void +grow_code (TransformData *td) +{ + unsigned int old_ip_offset = td->new_ip - td->new_code; + unsigned int old_last_ip_offset = td->last_new_ip - td->new_code; + g_assert (old_ip_offset <= td->max_code_size); + td->new_code = g_realloc (td->new_code, (td->max_code_size *= 2) * sizeof (td->new_code [0])); + td->new_code_end = td->new_code + td->max_code_size; + td->new_ip = td->new_code + old_ip_offset; + td->last_new_ip = td->new_code + old_last_ip_offset; +} + +#define ENSURE_CODE(td, n) \ + do { \ + if ((td)->new_ip + (n) > (td)->new_code_end) \ + grow_code (td); \ + } while (0) + +#define ADD_CODE(td, n) \ + do { \ + if ((td)->new_ip == (td)->new_code_end) \ + grow_code (td); \ + *(td)->new_ip++ = (n); \ + } while (0) + +#define CHECK_STACK(td, n) \ + do { \ + int stack_size = (td)->sp - (td)->stack; \ + if (stack_size < (n)) \ + g_warning ("%s.%s: not enough values (%d < %d) on stack at %04x", \ + (td)->method->klass->name, (td)->method->name, \ + stack_size, n, (td)->ip - (td)->il_code); \ + } while (0) + +#define ENSURE_I4(td, sp_off) \ + do { \ + if ((td)->sp [-sp_off].type == STACK_TYPE_I8) \ + ADD_CODE(td, sp_off == 1 ? MINT_CONV_I4_I8 : MINT_CONV_I4_I8_SP); \ + } while (0) + +static void +handle_branch(TransformData *td, int short_op, int long_op, int offset) +{ + int shorten_branch = 0; + int target = td->ip + offset - td->il_code; + if (target < 0 || target >= td->code_size) + g_assert_not_reached (); + if (offset > 0 && td->stack_height [target] < 0) { + td->stack_height [target] = td->sp - td->stack; + if (td->stack_height [target] > 0) + td->stack_state [target] = g_memdup (td->stack, td->stack_height [target] * sizeof (td->stack [0])); + td->vt_stack_size [target] = td->vt_sp; + } + if (offset < 0) { + offset = td->in_offsets [target] - (td->new_ip - td->new_code); + if (offset >= -32768) { + shorten_branch = 1; + } + } else { + int prev = td->forward_refs [target]; + td->forward_refs [td->ip - td->il_code] = prev; + td->forward_refs [target] = td->ip - td->il_code; + offset = 0; + if (td->header->code_size <= 25000) /* FIX to be precise somehow? */ + shorten_branch = 1; + } + if (shorten_branch) { + ADD_CODE(td, short_op); + ADD_CODE(td, offset); + } else { + ADD_CODE(td, long_op); + ADD_CODE(td, * (unsigned short *)(&offset)); + ADD_CODE(td, * ((unsigned short *)&offset + 1)); + } +} + +static void +one_arg_branch(TransformData *td, int mint_op, int offset) +{ + int type = td->sp [-1].type == STACK_TYPE_O || td->sp [-1].type == STACK_TYPE_MP ? STACK_TYPE_I : td->sp [-1].type; + int long_op = mint_op + type - STACK_TYPE_I4; + int short_op = long_op + MINT_BRFALSE_I4_S - MINT_BRFALSE_I4; + CHECK_STACK(td, 1); + --td->sp; + handle_branch (td, short_op, long_op, offset); +} + +static void +two_arg_branch(TransformData *td, int mint_op, int offset) +{ + int type1 = td->sp [-1].type == STACK_TYPE_O || td->sp [-1].type == STACK_TYPE_MP ? STACK_TYPE_I : td->sp [-1].type; + int type2 = td->sp [-2].type == STACK_TYPE_O || td->sp [-2].type == STACK_TYPE_MP ? STACK_TYPE_I : td->sp [-2].type; + int long_op = mint_op + type1 - STACK_TYPE_I4; + int short_op = long_op + MINT_BEQ_I4_S - MINT_BEQ_I4; + CHECK_STACK(td, 2); + if (type1 == STACK_TYPE_I4 && type2 == STACK_TYPE_I8) { + ADD_CODE(td, MINT_CONV_I8_I4); + td->in_offsets [td->ip - td->il_code]++; + } else if (type1 == STACK_TYPE_I8 && type2 == STACK_TYPE_I4) { + ADD_CODE(td, MINT_CONV_I8_I4_SP); + td->in_offsets [td->ip - td->il_code]++; + } else if (type1 != type2) { + g_warning("%s.%s: branch type mismatch %d %d", + td->method->klass->name, td->method->name, + td->sp [-1].type, td->sp [-2].type); + } + td->sp -= 2; + handle_branch (td, short_op, long_op, offset); +} + +static void +unary_arith_op(TransformData *td, int mint_op) +{ + int op = mint_op + td->sp [-1].type - STACK_TYPE_I4; + CHECK_STACK(td, 1); + ADD_CODE(td, op); +} + +static void +binary_arith_op(TransformData *td, int mint_op) +{ + int type1 = td->sp [-2].type; + int type2 = td->sp [-1].type; + int op; +#if SIZEOF_VOID_P == 8 + if ((type1 == STACK_TYPE_MP || type1 == STACK_TYPE_I8) && type2 == STACK_TYPE_I4) { + ADD_CODE(td, MINT_CONV_I8_I4); + type2 = STACK_TYPE_I8; + } + if (type1 == STACK_TYPE_I4 && (type2 == STACK_TYPE_MP || type2 == STACK_TYPE_I8)) { + ADD_CODE(td, MINT_CONV_I8_I4_SP); + type1 = STACK_TYPE_I8; + td->sp [-2].type = STACK_TYPE_I8; + } +#endif + if (type1 == STACK_TYPE_MP) + type1 = STACK_TYPE_I; + if (type2 == STACK_TYPE_MP) + type2 = STACK_TYPE_I; + if (type1 != type2) { + g_warning("%s.%s: %04x arith type mismatch %s %d %d", + td->method->klass->name, td->method->name, + td->ip - td->il_code, mono_interp_opname[mint_op], type1, type2); + } + op = mint_op + type1 - STACK_TYPE_I4; + CHECK_STACK(td, 2); + ADD_CODE(td, op); + --td->sp; +} + +static void +binary_int_op(TransformData *td, int mint_op) +{ + int op = mint_op + td->sp [-1].type - STACK_TYPE_I4; + CHECK_STACK(td, 2); + if (td->sp [-1].type != td->sp [-2].type) + g_warning("%s.%s: int type mismatch", td->method->klass->name, td->method->name); + ADD_CODE(td, op); + --td->sp; +} + +static void +shift_op(TransformData *td, int mint_op) +{ + int op = mint_op + td->sp [-2].type - STACK_TYPE_I4; + CHECK_STACK(td, 2); + if (td->sp [-1].type != STACK_TYPE_I4) { + g_warning("%s.%s: shift type mismatch %d", + td->method->klass->name, td->method->name, + td->sp [-2].type); + } + ADD_CODE(td, op); + --td->sp; +} + +static int +mint_type(MonoType *type) +{ + if (type->byref) + return MINT_TYPE_P; +enum_type: + switch (type->type) { + case MONO_TYPE_I1: + return MINT_TYPE_I1; + case MONO_TYPE_U1: + case MONO_TYPE_BOOLEAN: + return MINT_TYPE_U1; + case MONO_TYPE_I2: + return MINT_TYPE_I2; + case MONO_TYPE_U2: + case MONO_TYPE_CHAR: + return MINT_TYPE_U2; + case MONO_TYPE_I4: + case MONO_TYPE_U4: + return MINT_TYPE_I4; + case MONO_TYPE_I: + case MONO_TYPE_U: +#if SIZEOF_VOID_P == 4 + return MINT_TYPE_I4; +#else + return MINT_TYPE_I8; +#endif + case MONO_TYPE_PTR: + return MINT_TYPE_P; + case MONO_TYPE_R4: + return MINT_TYPE_R4; + case MONO_TYPE_I8: + case MONO_TYPE_U8: + return MINT_TYPE_I8; + case MONO_TYPE_R8: + return MINT_TYPE_R8; + case MONO_TYPE_STRING: + case MONO_TYPE_SZARRAY: + case MONO_TYPE_CLASS: + case MONO_TYPE_OBJECT: + case MONO_TYPE_ARRAY: + return MINT_TYPE_O; + case MONO_TYPE_VALUETYPE: + if (type->data.klass->enumtype) { + type = mono_class_enum_basetype (type->data.klass); + goto enum_type; + } else + return MINT_TYPE_VT; + case MONO_TYPE_GENERICINST: + type = &type->data.generic_class->container_class->byval_arg; + goto enum_type; + default: + g_warning ("got type 0x%02x", type->type); + g_assert_not_reached (); + } + return -1; +} + +static int +can_store (int stack_type, int var_type) +{ + if (stack_type == STACK_TYPE_O || stack_type == STACK_TYPE_MP) + stack_type = STACK_TYPE_I; + if (var_type == STACK_TYPE_O || var_type == STACK_TYPE_MP) + var_type = STACK_TYPE_I; + return stack_type == var_type; +} + +#define SET_SIMPLE_TYPE(s, ty) \ + do { \ + (s)->type = (ty); \ + (s)->flags = 0; \ + (s)->klass = NULL; \ + } while (0) + +#define SET_TYPE(s, ty, k) \ + do { \ + (s)->type = (ty); \ + (s)->flags = 0; \ + (s)->klass = k; \ + } while (0) + +#define PUSH_SIMPLE_TYPE(td, ty) \ + do { \ + int sp_height; \ + (td)->sp++; \ + sp_height = (td)->sp - (td)->stack; \ + if (sp_height > (td)->max_stack_height) \ + (td)->max_stack_height = sp_height; \ + SET_SIMPLE_TYPE((td)->sp - 1, ty); \ + } while (0) + +#define PUSH_TYPE(td, ty, k) \ + do { \ + int sp_height; \ + (td)->sp++; \ + sp_height = (td)->sp - (td)->stack; \ + if (sp_height > (td)->max_stack_height) \ + (td)->max_stack_height = sp_height; \ + SET_TYPE((td)->sp - 1, ty, k); \ + } while (0) + +#define PUSH_VT(td, size) \ + do { \ + (td)->vt_sp += ((size) + 7) & ~7; \ + if ((td)->vt_sp > (td)->max_vt_sp) \ + (td)->max_vt_sp = (td)->vt_sp; \ + } while (0) + +#define POP_VT(td, size) \ + do { \ + (td)->vt_sp -= ((size) + 7) & ~7; \ + } while (0) + +#if NO_UNALIGNED_ACCESS +#define WRITE32(td, v) \ + do { \ + ENSURE_CODE(td, 2); \ + * (guint16 *)((td)->new_ip) = * (guint16 *)(v); \ + * ((guint16 *)((td)->new_ip) + 1) = * ((guint16 *)(v) + 1); \ + (td)->new_ip += 2; \ + } while (0) + +#define WRITE64(td, v) \ + do { \ + ENSURE_CODE(td, 4); \ + * (guint16 *)((td)->new_ip) = * (guint16 *)(v); \ + * ((guint16 *)((td)->new_ip) + 1) = * ((guint16 *)(v) + 1); \ + * ((guint16 *)((td)->new_ip) + 2) = * ((guint16 *)(v) + 2); \ + * ((guint16 *)((td)->new_ip) + 3) = * ((guint16 *)(v) + 3); \ + (td)->new_ip += 4; \ + } while (0) +#else +#define WRITE32(td, v) \ + do { \ + ENSURE_CODE(td, 2); \ + * (guint32 *)((td)->new_ip) = * (guint32 *)(v); \ + (td)->new_ip += 2; \ + } while (0) + +#define WRITE64(td, v) \ + do { \ + ENSURE_CODE(td, 4); \ + * (guint64 *)((td)->new_ip) = * (guint64 *)(v); \ + (td)->new_ip += 4; \ + } while (0) + +#endif + +static void +load_arg(TransformData *td, int n) +{ + int mt; + MonoClass *klass = NULL; + MonoType *type; + + gboolean hasthis = mono_method_signature (td->method)->hasthis; + if (hasthis && n == 0) + type = &td->method->klass->byval_arg; + else + type = mono_method_signature (td->method)->params [hasthis ? n - 1 : n]; + + mt = mint_type (type); + if (mt == MINT_TYPE_VT) { + gint32 size; + klass = mono_class_from_mono_type (type); + if (mono_method_signature (td->method)->pinvoke) + size = mono_class_native_size (klass, NULL); + else + size = mono_class_value_size (klass, NULL); + + if (hasthis && n == 0) { + mt = MINT_TYPE_P; + ADD_CODE (td, MINT_LDARG_P); + ADD_CODE (td, td->rtm->arg_offsets [n]); /* FIX for large offset */ + klass = NULL; + } else { + PUSH_VT (td, size); + ADD_CODE (td, MINT_LDARG_VT); + ADD_CODE (td, td->rtm->arg_offsets [n]); /* FIX for large offset */ + WRITE32 (td, &size); + } + } else { + if (hasthis && n == 0) { + mt = MINT_TYPE_P; + ADD_CODE (td, MINT_LDARG_P); + ADD_CODE (td, td->rtm->arg_offsets [n]); /* FIX for large offset */ + klass = NULL; + } else { + ADD_CODE(td, MINT_LDARG_I1 + (mt - MINT_TYPE_I1)); + ADD_CODE(td, td->rtm->arg_offsets [n]); /* FIX for large offset */ + if (mt == MINT_TYPE_O) + klass = mono_class_from_mono_type (type); + } + } + PUSH_TYPE(td, stack_type[mt], klass); +} + +static void +store_arg(TransformData *td, int n) +{ + int mt; + CHECK_STACK (td, 1); + MonoType *type; + + gboolean hasthis = mono_method_signature (td->method)->hasthis; + if (hasthis && n == 0) + type = &td->method->klass->byval_arg; + else + type = mono_method_signature (td->method)->params [n - !!hasthis]; + + mt = mint_type (type); + if (mt == MINT_TYPE_VT) { + gint32 size; + g_error ("data.klass"); + if (mono_method_signature (td->method)->pinvoke) + size = mono_class_native_size (type->data.klass, NULL); + else + size = mono_class_value_size (type->data.klass, NULL); + ADD_CODE(td, MINT_STARG_VT); + ADD_CODE(td, n); + WRITE32(td, &size); + if (td->sp [-1].type == STACK_TYPE_VT) + POP_VT(td, size); + } else { + ADD_CODE(td, MINT_STARG_I1 + (mt - MINT_TYPE_I1)); + ADD_CODE(td, td->rtm->arg_offsets [n]); + } + --td->sp; +} + +static void +store_inarg(TransformData *td, int n) +{ + MonoType *type; + gboolean hasthis = mono_method_signature (td->method)->hasthis; + if (hasthis && n == 0) + type = &td->method->klass->byval_arg; + else + type = mono_method_signature (td->method)->params [n - !!hasthis]; + + int mt = mint_type (type); + if (hasthis && n == 0) { + ADD_CODE (td, MINT_STINARG_P); + ADD_CODE (td, n); + return; + } + if (mt == MINT_TYPE_VT) { + MonoClass *klass = mono_class_from_mono_type (type); + gint32 size; + if (mono_method_signature (td->method)->pinvoke) + size = mono_class_native_size (klass, NULL); + else + size = mono_class_value_size (klass, NULL); + ADD_CODE(td, MINT_STINARG_VT); + ADD_CODE(td, n); + WRITE32(td, &size); + } else { + ADD_CODE(td, MINT_STINARG_I1 + (mt - MINT_TYPE_I1)); + ADD_CODE(td, n); + } +} + +static void +load_local(TransformData *td, int n) +{ + MonoType *type = td->header->locals [n]; + int mt = mint_type (type); + int offset = td->rtm->local_offsets [n]; + MonoClass *klass = NULL; + if (mt == MINT_TYPE_VT) { + klass = mono_class_from_mono_type (type); + gint32 size = mono_class_value_size (klass, NULL); + PUSH_VT(td, size); + ADD_CODE(td, MINT_LDLOC_VT); + ADD_CODE(td, offset); /*FIX for large offset */ + WRITE32(td, &size); + } else { + g_assert (mt < MINT_TYPE_VT); + if (mt == MINT_TYPE_I4 && !td->is_bb_start [td->in_start - td->il_code] && td->last_new_ip != NULL && + td->last_new_ip [0] == MINT_STLOC_I4 && td->last_new_ip [1] == offset) { + td->last_new_ip [0] = MINT_STLOC_NP_I4; + } else if (mt == MINT_TYPE_O && !td->is_bb_start [td->in_start - td->il_code] && td->last_new_ip != NULL && + td->last_new_ip [0] == MINT_STLOC_O && td->last_new_ip [1] == offset) { + td->last_new_ip [0] = MINT_STLOC_NP_O; + } else { + ADD_CODE(td, MINT_LDLOC_I1 + (mt - MINT_TYPE_I1)); + ADD_CODE(td, offset); /*FIX for large offset */ + } + if (mt == MINT_TYPE_O) + klass = mono_class_from_mono_type (type); + } + PUSH_TYPE(td, stack_type[mt], klass); +} + +static void +store_local(TransformData *td, int n) +{ + MonoType *type = td->header->locals [n]; + int mt = mint_type (type); + int offset = td->rtm->local_offsets [n]; + CHECK_STACK (td, 1); +#if SIZEOF_VOID_P == 8 + if (td->sp [-1].type == STACK_TYPE_I4 && stack_type [mt] == STACK_TYPE_I8) { + ADD_CODE(td, MINT_CONV_I8_I4); + td->sp [-1].type = STACK_TYPE_I8; + } +#endif + if (!can_store(td->sp [-1].type, stack_type [mt])) { + g_warning("%s.%s: Store local stack type mismatch %d %d", + td->method->klass->name, td->method->name, + stack_type [mt], td->sp [-1].type); + } + if (mt == MINT_TYPE_VT) { + MonoClass *klass = mono_class_from_mono_type (type); + gint32 size = mono_class_value_size (klass, NULL); + ADD_CODE(td, MINT_STLOC_VT); + ADD_CODE(td, offset); /*FIX for large offset */ + WRITE32(td, &size); + if (td->sp [-1].type == STACK_TYPE_VT) + POP_VT(td, size); + } else { + g_assert (mt < MINT_TYPE_VT); + ADD_CODE(td, MINT_STLOC_I1 + (mt - MINT_TYPE_I1)); + ADD_CODE(td, offset); /*FIX for large offset */ + } + --td->sp; +} + +#define SIMPLE_OP(td, op) \ + do { \ + ADD_CODE(&td, op); \ + ++td.ip; \ + } while (0) + +static guint16 +get_data_item_index (TransformData *td, void *ptr) +{ + gpointer p = g_hash_table_lookup (td->data_hash, ptr); + guint index; + if (p != NULL) + return GPOINTER_TO_UINT (p) - 1; + if (td->max_data_items == td->n_data_items) { + td->max_data_items = td->n_data_items == 0 ? 16 : 2 * td->max_data_items; + td->data_items = g_realloc (td->data_items, td->max_data_items * sizeof(td->data_items [0])); + } + index = td->n_data_items; + td->data_items [index] = ptr; + ++td->n_data_items; + g_hash_table_insert (td->data_hash, ptr, GUINT_TO_POINTER (index + 1)); + return index; +} + +static void +interp_transform_call (TransformData *td, MonoMethod *method, MonoMethod *target_method, MonoDomain *domain, MonoGenericContext *generic_context, unsigned char *is_bb_start, int body_start_offset, MonoClass *constrained_class) +{ + MonoImage *image = method->klass->image; + MonoMethodSignature *csignature; + MonoError error; + int virtual = *td->ip == CEE_CALLVIRT; + int calli = *td->ip == CEE_CALLI || *td->ip == CEE_MONO_CALLI_EXTRA_ARG; + int i; + guint32 vt_stack_used = 0; + guint32 vt_res_size = 0; + int op = -1; + int native = 0; + int is_void = 0; + + guint32 token = read32 (td->ip + 1); + + if (target_method == NULL) { + if (calli) { + CHECK_STACK(td, 1); + native = (method->wrapper_type != MONO_WRAPPER_DELEGATE_INVOKE && td->sp [-1].type == STACK_TYPE_I); + --td->sp; + if (method->wrapper_type != MONO_WRAPPER_NONE) + csignature = (MonoMethodSignature *)mono_method_get_wrapper_data (method, token); + else + csignature = mono_metadata_parse_signature (image, token); + + if (generic_context) { + csignature = mono_inflate_generic_signature (csignature, generic_context, &error); + mono_error_cleanup (&error); /* FIXME: don't swallow the error */ + } + + target_method = NULL; + } else { + if (method->wrapper_type == MONO_WRAPPER_NONE) + target_method = mono_get_method_full (image, token, NULL, generic_context); + else + target_method = (MonoMethod *)mono_method_get_wrapper_data (method, token); + csignature = mono_method_signature (target_method); + if (target_method->klass == mono_defaults.string_class) { + if (target_method->name [0] == 'g') { + if (strcmp (target_method->name, "get_Chars") == 0) + op = MINT_GETCHR; + else if (strcmp (target_method->name, "get_Length") == 0) + op = MINT_STRLEN; + } + } else if (target_method->klass == mono_defaults.array_class) { + if (strcmp (target_method->name, "get_Rank") == 0) + op = MINT_ARRAY_RANK; + else if (strcmp (target_method->name, "get_Length") == 0) + op = MINT_LDLEN; + } + } + } else { + csignature = mono_method_signature (target_method); + } + + /* TODO: that's oddly specific? */ + if (generic_context && target_method && !strcmp ("Invoke", target_method->name) && target_method->klass->parent == mono_defaults.multicastdelegate_class) { + csignature = mono_inflate_generic_signature (csignature, generic_context, &error); + mono_error_cleanup (&error); /* FIXME: don't swallow the error */ + } + + if (constrained_class) { + if (constrained_class->enumtype && !strcmp (target_method->name, "GetHashCode")) { + /* Use the corresponding method from the base type to avoid boxing */ + MonoType *base_type = mono_class_enum_basetype (constrained_class); + g_assert (base_type); + constrained_class = mono_class_from_mono_type (base_type); + target_method = mono_class_get_method_from_name (constrained_class, target_method->name, 0); + g_assert (target_method); + } + } + + if (constrained_class) { + mono_class_setup_vtable (constrained_class); +#if DEBUG_INTERP + g_print ("CONSTRAINED.CALLVIRT: %s::%s. %s (%p) ->\n", target_method->klass->name, target_method->name, mono_signature_full_name (target_method->signature), target_method); +#endif + target_method = mono_get_method_constrained_with_method (image, target_method, constrained_class, generic_context, &error); +#if DEBUG_INTERP + g_print (" : %s::%s. %s (%p)\n", target_method->klass->name, target_method->name, mono_signature_full_name (target_method->signature), target_method); +#endif + mono_error_cleanup (&error); /* FIXME: don't swallow the error */ + mono_class_setup_vtable (target_method->klass); + + if (constrained_class->valuetype && (target_method->klass == mono_defaults.object_class || target_method->klass == mono_defaults.enum_class->parent || target_method->klass == mono_defaults.enum_class)) { + if (target_method->klass == mono_defaults.enum_class && (td->sp - csignature->param_count - 1)->type == STACK_TYPE_MP) { + /* managed pointer on the stack, we need to deref that puppy */ + ADD_CODE (td, MINT_LDIND_I); + ADD_CODE (td, csignature->param_count); + } + ADD_CODE (td, MINT_BOX); + ADD_CODE (td, get_data_item_index (td, constrained_class)); + ADD_CODE (td, csignature->param_count); + } else if (!constrained_class->valuetype) { + /* managed pointer on the stack, we need to deref that puppy */ + ADD_CODE (td, MINT_LDIND_I); + ADD_CODE (td, csignature->param_count); + } else { + g_assert (target_method->klass->valuetype); + virtual = FALSE; + } + } + + if (target_method) + mono_class_init (target_method->klass); + + CHECK_STACK (td, csignature->param_count + csignature->hasthis); + if (!calli && (!virtual || (target_method->flags & METHOD_ATTRIBUTE_VIRTUAL) == 0) && + (target_method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) == 0 && + (target_method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) == 0) { + int called_inited = mono_class_vtable (domain, target_method->klass)->initialized; + MonoMethodHeader *mheader = mono_method_get_header (target_method); + + if (/*mono_metadata_signature_equal (method->signature, target_method->signature) */ method == target_method && *(td->ip + 5) == CEE_RET) { + int offset; + if (mono_interp_traceopt) + g_print ("Optimize tail call of %s.%s\n", target_method->klass->name, target_method->name); + for (i = csignature->param_count - 1; i >= 0; --i) + store_arg (td, i + csignature->hasthis); + + if (csignature->hasthis) { + g_error ("STTHIS removal"); + // ADD_CODE(td, MINT_STTHIS); + --td->sp; + } + ADD_CODE(td, MINT_BR_S); + offset = body_start_offset - ((td->new_ip - 1) - td->new_code); + ADD_CODE(td, offset); + if (!is_bb_start [td->ip + 5 - td->il_code]) + ++td->ip; /* gobble the CEE_RET if it isn't branched to */ + td->ip += 5; + return; + } else { + /* mheader might not exist if this is a delegate invoc, etc */ + if (mheader && *mheader->code == CEE_RET && called_inited) { + if (mono_interp_traceopt) + g_print ("Inline (empty) call of %s.%s\n", target_method->klass->name, target_method->name); + for (i = 0; i < csignature->param_count; i++) + ADD_CODE (td, MINT_POP); /*FIX: vt */ + ADD_CODE (td, 0); + if (csignature->hasthis) { + if (virtual) + ADD_CODE(td, MINT_CKNULL); + ADD_CODE (td, MINT_POP); + ADD_CODE (td, 0); + } + td->sp -= csignature->param_count + csignature->hasthis; + td->ip += 5; + return; + } + } + } + if (method->wrapper_type == MONO_WRAPPER_NONE && target_method != NULL) { + if (target_method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) + target_method = mono_marshal_get_native_wrapper (target_method, FALSE, FALSE); + if (!virtual && target_method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED) + target_method = mono_marshal_get_synchronized_wrapper (target_method); + } + g_assert (csignature->call_convention == MONO_CALL_DEFAULT || csignature->call_convention == MONO_CALL_C); + td->sp -= csignature->param_count + !!csignature->hasthis; + for (i = 0; i < csignature->param_count; ++i) { + if (td->sp [i + !!csignature->hasthis].type == STACK_TYPE_VT) { + gint32 size; + MonoClass *klass = mono_class_from_mono_type (csignature->params [i]); + if (csignature->pinvoke && method->wrapper_type != MONO_WRAPPER_NONE) + size = mono_class_native_size (klass, NULL); + else + size = mono_class_value_size (klass, NULL); + size = (size + 7) & ~7; + vt_stack_used += size; + } + } + + /* need to handle typedbyref ... */ + if (csignature->ret->type != MONO_TYPE_VOID) { + int mt = mint_type(csignature->ret); + MonoClass *klass = mono_class_from_mono_type (csignature->ret); + if (mt == MINT_TYPE_VT) { + if (csignature->pinvoke && method->wrapper_type != MONO_WRAPPER_NONE) + vt_res_size = mono_class_native_size (klass, NULL); + else + vt_res_size = mono_class_value_size (klass, NULL); + PUSH_VT(td, vt_res_size); + } + PUSH_TYPE(td, stack_type[mt], klass); + } else + is_void = TRUE; + + if (op >= 0) { + ADD_CODE(td, op); +#if SIZEOF_VOID_P == 8 + if (op == MINT_LDLEN) + ADD_CODE(td, MINT_CONV_I4_I8); +#endif + } else { + if (calli) + ADD_CODE(td, native ? MINT_CALLI_NAT : MINT_CALLI); + else if (virtual) + ADD_CODE(td, is_void ? MINT_VCALLVIRT : MINT_CALLVIRT); + else + ADD_CODE(td, is_void ? MINT_VCALL : MINT_CALL); + + if (calli) { + ADD_CODE(td, get_data_item_index (td, (void *)csignature)); + } else { + ADD_CODE(td, get_data_item_index (td, (void *)mono_interp_get_runtime_method (domain, target_method, &error))); + mono_error_cleanup (&error); /* FIXME: don't swallow the error */ + } + } + td->ip += 5; + if (vt_stack_used != 0 || vt_res_size != 0) { + ADD_CODE(td, MINT_VTRESULT); + ADD_CODE(td, vt_res_size); + WRITE32(td, &vt_stack_used); + td->vt_sp -= vt_stack_used; + } +} + +static void +generate (MonoMethod *method, RuntimeMethod *rtm, unsigned char *is_bb_start, MonoGenericContext *generic_context) +{ + MonoMethodHeader *header = mono_method_get_header (method); + MonoMethodSignature *signature = mono_method_signature (method); + MonoImage *image = method->klass->image; + MonoDomain *domain = mono_domain_get (); + MonoClass *constrained_class = NULL; + MonoError error; + int offset, mt; + int i; + int i32; + MonoClass *klass; + MonoClassField *field; + const unsigned char *end; + int new_in_start_offset; + int body_start_offset; + int target; + guint32 token; + TransformData td; + int generating_code = 1; + + memset(&td, 0, sizeof(td)); + td.method = method; + td.rtm = rtm; + td.is_bb_start = is_bb_start; + td.il_code = header->code; + td.code_size = header->code_size; + td.header = header; + td.max_code_size = td.code_size; + td.new_code = (unsigned short *)g_malloc(td.max_code_size * sizeof(gushort)); + td.new_code_end = td.new_code + td.max_code_size; + td.in_offsets = g_malloc0(header->code_size * sizeof(int)); + td.forward_refs = g_malloc(header->code_size * sizeof(int)); + td.stack_state = g_malloc0(header->code_size * sizeof(StackInfo *)); + td.stack_height = g_malloc(header->code_size * sizeof(int)); + td.vt_stack_size = g_malloc(header->code_size * sizeof(int)); + td.n_data_items = 0; + td.max_data_items = 0; + td.data_items = NULL; + td.data_hash = g_hash_table_new (NULL, NULL); + rtm->data_items = td.data_items; + for (i = 0; i < header->code_size; i++) { + td.forward_refs [i] = -1; + td.stack_height [i] = -1; + } + td.new_ip = td.new_code; + td.last_new_ip = NULL; + + td.stack = g_malloc0(header->max_stack * sizeof(td.stack[0])); + td.sp = td.stack; + td.max_stack_height = 0; + + for (i = 0; i < header->num_clauses; i++) { + MonoExceptionClause *c = header->clauses + i; + td.stack_height [c->handler_offset] = 0; + td.vt_stack_size [c->handler_offset] = 0; + td.is_bb_start [c->handler_offset] = 1; + if (c->flags == MONO_EXCEPTION_CLAUSE_NONE) { + td.stack_height [c->handler_offset] = 1; + td.stack_state [c->handler_offset] = g_malloc0(sizeof(StackInfo)); + td.stack_state [c->handler_offset][0].type = STACK_TYPE_O; + td.stack_state [c->handler_offset][0].klass = NULL; /*FIX*/ + } + } + + td.ip = header->code; + end = td.ip + header->code_size; + + if (mono_interp_traceopt) { + char *tmp = mono_disasm_code (NULL, method, td.ip, end); + char *name = mono_method_full_name (method, TRUE); + g_print ("Method %s, original code:\n", name); + g_print ("%s\n", tmp); + g_free (tmp); + g_free (name); + } + + if (signature->hasthis) + store_inarg (&td, 0); + for (i = 0; i < signature->param_count; i++) + store_inarg (&td, i + !!signature->hasthis); + + body_start_offset = td.new_ip - td.new_code; + + for (i = 0; i < header->num_locals; i++) { + int mt = mint_type(header->locals [i]); + if (mt == MINT_TYPE_VT || mt == MINT_TYPE_O) { + ADD_CODE(&td, MINT_INITLOCALS); + break; + } + } + + while (td.ip < end) { + int in_offset; + + g_assert (td.sp >= td.stack); + g_assert (td.vt_sp < 0x10000000); + in_offset = td.ip - header->code; + td.in_offsets [in_offset] = td.new_ip - td.new_code; + new_in_start_offset = td.new_ip - td.new_code; + td.in_start = td.ip; + while (td.forward_refs [in_offset] >= 0) { + int j = td.forward_refs [in_offset]; + int slot; + td.forward_refs [in_offset] = td.forward_refs [j]; + if (td.in_offsets [j] < 0) { + int old_switch_offset = -td.in_offsets [j]; + int new_switch_offset = td.in_offsets [old_switch_offset]; + int switch_case = (j - old_switch_offset - 5) / 4; + int n_cases = read32 (header->code + old_switch_offset + 1); + offset = (td.new_ip - td.new_code) - (new_switch_offset + 2 * n_cases + 3); + slot = new_switch_offset + 3 + 2 * switch_case; + td.new_code [slot] = * (unsigned short *)(&offset); + td.new_code [slot + 1] = * ((unsigned short *)&offset + 1); + } else { + int op = td.new_code [td.in_offsets [j]]; + if (mono_interp_opargtype [op] == MintOpShortBranch) { + offset = (td.new_ip - td.new_code) - td.in_offsets [j]; + g_assert (offset <= 32767); + slot = td.in_offsets [j] + 1; + td.new_code [slot] = offset; + } else { + offset = (td.new_ip - td.new_code) - td.in_offsets [j]; + slot = td.in_offsets [j] + 1; + td.new_code [slot] = * (unsigned short *)(&offset); + td.new_code [slot + 1] = * ((unsigned short *)&offset + 1); + } + } + } + if (td.stack_height [in_offset] >= 0) { + g_assert (is_bb_start [in_offset]); + if (td.stack_height [in_offset] > 0) + memcpy (td.stack, td.stack_state [in_offset], td.stack_height [in_offset] * sizeof(td.stack [0])); + td.sp = td.stack + td.stack_height [in_offset]; + td.vt_sp = td.vt_stack_size [in_offset]; + } + if (is_bb_start [in_offset]) { + generating_code = 1; + } + if (!generating_code) { + while (td.ip < end && !is_bb_start [td.ip - td.il_code]) + ++td.ip; + continue; + } + if (mono_interp_traceopt > 1) { + printf("IL_%04lx %s %-10s -> IL_%04lx, sp %ld, %s %-12s vt_sp %u (max %u)\n", + td.ip - td.il_code, + td.is_bb_start [td.ip - td.il_code] == 3 ? "<>" : + td.is_bb_start [td.ip - td.il_code] == 2 ? "< " : + td.is_bb_start [td.ip - td.il_code] == 1 ? " >" : " ", + mono_opcode_name (*td.ip), td.new_ip - td.new_code, td.sp - td.stack, + td.sp > td.stack ? stack_type_string [td.sp [-1].type] : " ", + (td.sp > td.stack && (td.sp [-1].type == STACK_TYPE_O || td.sp [-1].type == STACK_TYPE_VT)) ? (td.sp [-1].klass == NULL ? "?" : td.sp [-1].klass->name) : "", + td.vt_sp, td.max_vt_sp); + } + switch (*td.ip) { + case CEE_NOP: + /* lose it */ + ++td.ip; + break; + case CEE_BREAK: + SIMPLE_OP(td, MINT_BREAK); + break; + case CEE_LDARG_0: + case CEE_LDARG_1: + case CEE_LDARG_2: + case CEE_LDARG_3: + load_arg (&td, *td.ip - CEE_LDARG_0); + ++td.ip; + break; + case CEE_LDLOC_0: + case CEE_LDLOC_1: + case CEE_LDLOC_2: + case CEE_LDLOC_3: + load_local (&td, *td.ip - CEE_LDLOC_0); + ++td.ip; + break; + case CEE_STLOC_0: + case CEE_STLOC_1: + case CEE_STLOC_2: + case CEE_STLOC_3: + store_local (&td, *td.ip - CEE_STLOC_0); + ++td.ip; + break; + case CEE_LDARG_S: + load_arg (&td, ((guint8 *)td.ip)[1]); + td.ip += 2; + break; + case CEE_LDARGA_S: { + /* NOTE: n includes this */ + int n = ((guint8 *)td.ip)[1]; + if (n == 0 && signature->hasthis) { + g_error ("LDTHISA: NOPE"); + ADD_CODE(&td, MINT_LDTHISA); + } + else { + ADD_CODE(&td, MINT_LDARGA); + ADD_CODE(&td, td.rtm->arg_offsets [n]); + } + PUSH_SIMPLE_TYPE(&td, STACK_TYPE_MP); + td.ip += 2; + break; + } + case CEE_STARG_S: + store_arg (&td, ((guint8 *)td.ip)[1]); + td.ip += 2; + break; + case CEE_LDLOC_S: + load_local (&td, ((guint8 *)td.ip)[1]); + td.ip += 2; + break; + case CEE_LDLOCA_S: + ADD_CODE(&td, MINT_LDLOCA_S); + ADD_CODE(&td, td.rtm->local_offsets [((guint8 *)td.ip)[1]]); + PUSH_SIMPLE_TYPE(&td, STACK_TYPE_MP); + td.ip += 2; + break; + case CEE_STLOC_S: + store_local (&td, ((guint8 *)td.ip)[1]); + td.ip += 2; + break; + case CEE_LDNULL: + SIMPLE_OP(td, MINT_LDNULL); + PUSH_TYPE(&td, STACK_TYPE_O, NULL); + break; + case CEE_LDC_I4_M1: + SIMPLE_OP(td, MINT_LDC_I4_M1); + PUSH_SIMPLE_TYPE(&td, STACK_TYPE_I4); + break; + case CEE_LDC_I4_0: + if (!td.is_bb_start[td.ip + 1 - td.il_code] && td.ip [1] == 0xfe && td.ip [2] == CEE_CEQ && + td.sp > td.stack && td.sp [-1].type == STACK_TYPE_I4) { + SIMPLE_OP(td, MINT_CEQ0_I4); + td.ip += 2; + } else { + SIMPLE_OP(td, MINT_LDC_I4_0); + PUSH_SIMPLE_TYPE(&td, STACK_TYPE_I4); + } + break; + case CEE_LDC_I4_1: + if (!td.is_bb_start[td.ip + 1 - td.il_code] && + (td.ip [1] == CEE_ADD || td.ip [1] == CEE_SUB) && td.sp [-1].type == STACK_TYPE_I4) { + ADD_CODE(&td, td.ip [1] == CEE_ADD ? MINT_ADD1_I4 : MINT_SUB1_I4); + td.ip += 2; + } else { + SIMPLE_OP(td, MINT_LDC_I4_1); + PUSH_SIMPLE_TYPE(&td, STACK_TYPE_I4); + } + break; + case CEE_LDC_I4_2: + case CEE_LDC_I4_3: + case CEE_LDC_I4_4: + case CEE_LDC_I4_5: + case CEE_LDC_I4_6: + case CEE_LDC_I4_7: + case CEE_LDC_I4_8: + SIMPLE_OP(td, (*td.ip - CEE_LDC_I4_0) + MINT_LDC_I4_0); + PUSH_SIMPLE_TYPE(&td, STACK_TYPE_I4); + break; + case CEE_LDC_I4_S: + ADD_CODE(&td, MINT_LDC_I4_S); + ADD_CODE(&td, ((gint8 *) td.ip) [1]); + td.ip += 2; + PUSH_SIMPLE_TYPE(&td, STACK_TYPE_I4); + break; + case CEE_LDC_I4: + i32 = read32 (td.ip + 1); + ADD_CODE(&td, MINT_LDC_I4); + WRITE32(&td, &i32); + td.ip += 5; + PUSH_SIMPLE_TYPE(&td, STACK_TYPE_I4); + break; + case CEE_LDC_I8: { + gint64 val = read64 (td.ip + 1); + ADD_CODE(&td, MINT_LDC_I8); + WRITE64(&td, &val); + td.ip += 9; + PUSH_SIMPLE_TYPE(&td, STACK_TYPE_I8); + break; + } + case CEE_LDC_R4: { + float val; + readr4 (td.ip + 1, &val); + ADD_CODE(&td, MINT_LDC_R4); + WRITE32(&td, &val); + td.ip += 5; + PUSH_SIMPLE_TYPE(&td, STACK_TYPE_R8); + break; + } + case CEE_LDC_R8: { + double val; + readr8 (td.ip + 1, &val); + ADD_CODE(&td, MINT_LDC_R8); + WRITE64(&td, &val); + td.ip += 9; + PUSH_SIMPLE_TYPE(&td, STACK_TYPE_R8); + break; + } + case CEE_DUP: { + int type = td.sp [-1].type; + MonoClass *klass = td.sp [-1].klass; + if (td.sp [-1].type == STACK_TYPE_VT) { + gint32 size = mono_class_value_size (klass, NULL); + PUSH_VT(&td, size); + ADD_CODE(&td, MINT_DUP_VT); + WRITE32(&td, &size); + td.ip ++; + } else + SIMPLE_OP(td, MINT_DUP); + PUSH_TYPE(&td, type, klass); + break; + } + case CEE_POP: + CHECK_STACK(&td, 1); + SIMPLE_OP(td, MINT_POP); + ADD_CODE (&td, 0); + if (td.sp [-1].type == STACK_TYPE_VT) { + int size = mono_class_value_size (td.sp [-1].klass, NULL); + size = (size + 7) & ~7; + ADD_CODE(&td, MINT_VTRESULT); + ADD_CODE(&td, 0); + WRITE32(&td, &size); + td.vt_sp -= size; + } + --td.sp; + break; + case CEE_JMP: { + MonoMethod *m; + if (td.sp > td.stack) + g_warning ("CEE_JMP: stack must be empty"); + token = read32 (td.ip + 1); + m = mono_get_method_full (image, token, NULL, generic_context); + ADD_CODE (&td, MINT_JMP); + ADD_CODE (&td, get_data_item_index (&td, mono_interp_get_runtime_method (domain, m, &error))); + mono_error_cleanup (&error); /* FIXME: don't swallow the error */ + td.ip += 5; + break; + } + case CEE_CALLVIRT: /* Fall through */ + case CEE_CALLI: /* Fall through */ + case CEE_CALL: { + interp_transform_call (&td, method, NULL, domain, generic_context, is_bb_start, body_start_offset, constrained_class); + constrained_class = NULL; + break; + } + case CEE_RET: { + int vt_size = 0; + if (signature->ret->type != MONO_TYPE_VOID) { + --td.sp; + MonoClass *klass = mono_class_from_mono_type (signature->ret); + if (mint_type (&klass->byval_arg) == MINT_TYPE_VT) { + vt_size = mono_class_value_size (klass, NULL); + vt_size = (vt_size + 7) & ~7; + } + } + if (td.sp > td.stack) + g_warning ("%s.%s: CEE_RET: more values on stack: %d", td.method->klass->name, td.method->name, td.sp - td.stack); + if (td.vt_sp != vt_size) + g_error ("%s.%s: CEE_RET: value type stack: %d vs. %d", td.method->klass->name, td.method->name, td.vt_sp, vt_size); + if (vt_size == 0) + SIMPLE_OP(td, signature->ret->type == MONO_TYPE_VOID ? MINT_RET_VOID : MINT_RET); + else { + ADD_CODE(&td, MINT_RET_VT); + WRITE32(&td, &vt_size); + ++td.ip; + } + generating_code = 0; + break; + } + case CEE_BR: + handle_branch (&td, MINT_BR_S, MINT_BR, 5 + read32 (td.ip + 1)); + td.ip += 5; + generating_code = 0; + break; + case CEE_BR_S: + handle_branch (&td, MINT_BR_S, MINT_BR, 2 + (gint8)td.ip [1]); + td.ip += 2; + generating_code = 0; + break; + case CEE_BRFALSE: + one_arg_branch (&td, MINT_BRFALSE_I4, 5 + read32 (td.ip + 1)); + td.ip += 5; + break; + case CEE_BRFALSE_S: + one_arg_branch (&td, MINT_BRFALSE_I4, 2 + (gint8)td.ip [1]); + td.ip += 2; + break; + case CEE_BRTRUE: + one_arg_branch (&td, MINT_BRTRUE_I4, 5 + read32 (td.ip + 1)); + td.ip += 5; + break; + case CEE_BRTRUE_S: + one_arg_branch (&td, MINT_BRTRUE_I4, 2 + (gint8)td.ip [1]); + td.ip += 2; + break; + case CEE_BEQ: + two_arg_branch (&td, MINT_BEQ_I4, 5 + read32 (td.ip + 1)); + td.ip += 5; + break; + case CEE_BEQ_S: + two_arg_branch (&td, MINT_BEQ_I4, 2 + (gint8) td.ip [1]); + td.ip += 2; + break; + case CEE_BGE: + two_arg_branch (&td, MINT_BGE_I4, 5 + read32 (td.ip + 1)); + td.ip += 5; + break; + case CEE_BGE_S: + two_arg_branch (&td, MINT_BGE_I4, 2 + (gint8) td.ip [1]); + td.ip += 2; + break; + case CEE_BGT: + two_arg_branch (&td, MINT_BGT_I4, 5 + read32 (td.ip + 1)); + td.ip += 5; + break; + case CEE_BGT_S: + two_arg_branch (&td, MINT_BGT_I4, 2 + (gint8) td.ip [1]); + td.ip += 2; + break; + case CEE_BLT: + two_arg_branch (&td, MINT_BLT_I4, 5 + read32 (td.ip + 1)); + td.ip += 5; + break; + case CEE_BLT_S: + two_arg_branch (&td, MINT_BLT_I4, 2 + (gint8) td.ip [1]); + td.ip += 2; + break; + case CEE_BLE: + two_arg_branch (&td, MINT_BLE_I4, 5 + read32 (td.ip + 1)); + td.ip += 5; + break; + case CEE_BLE_S: + two_arg_branch (&td, MINT_BLE_I4, 2 + (gint8) td.ip [1]); + td.ip += 2; + break; + case CEE_BNE_UN: + two_arg_branch (&td, MINT_BNE_UN_I4, 5 + read32 (td.ip + 1)); + td.ip += 5; + break; + case CEE_BNE_UN_S: + two_arg_branch (&td, MINT_BNE_UN_I4, 2 + (gint8) td.ip [1]); + td.ip += 2; + break; + case CEE_BGE_UN: + two_arg_branch (&td, MINT_BGE_UN_I4, 5 + read32 (td.ip + 1)); + td.ip += 5; + break; + case CEE_BGE_UN_S: + two_arg_branch (&td, MINT_BGE_UN_I4, 2 + (gint8) td.ip [1]); + td.ip += 2; + break; + case CEE_BGT_UN: + two_arg_branch (&td, MINT_BGT_UN_I4, 5 + read32 (td.ip + 1)); + td.ip += 5; + break; + case CEE_BGT_UN_S: + two_arg_branch (&td, MINT_BGT_UN_I4, 2 + (gint8) td.ip [1]); + td.ip += 2; + break; + case CEE_BLE_UN: + two_arg_branch (&td, MINT_BLE_UN_I4, 5 + read32 (td.ip + 1)); + td.ip += 5; + break; + case CEE_BLE_UN_S: + two_arg_branch (&td, MINT_BLE_UN_I4, 2 + (gint8) td.ip [1]); + td.ip += 2; + break; + case CEE_BLT_UN: + two_arg_branch (&td, MINT_BLT_UN_I4, 5 + read32 (td.ip + 1)); + td.ip += 5; + break; + case CEE_BLT_UN_S: + two_arg_branch (&td, MINT_BLT_UN_I4, 2 + (gint8) td.ip [1]); + td.ip += 2; + break; + case CEE_SWITCH: { + guint32 n; + const unsigned char *next_ip; + const unsigned char *base_ip = td.ip; + unsigned short *next_new_ip; + ++td.ip; + n = read32 (td.ip); + ADD_CODE(&td, MINT_SWITCH); + ADD_CODE(&td, * (unsigned short *)(&n)); + ADD_CODE(&td, * ((unsigned short *)&n + 1)); + td.ip += 4; + next_ip = td.ip + n * 4; + next_new_ip = td.new_ip + n * 2; + for (i = 0; i < n; i++) { + offset = read32 (td.ip); + target = next_ip - td.il_code + offset; + if (offset < 0) + target = td.in_offsets [target] - (next_new_ip - td.new_code); + else { + int prev = td.forward_refs [target]; + td.forward_refs [td.ip - td.il_code] = prev; + td.forward_refs [target] = td.ip - td.il_code; + td.in_offsets [td.ip - td.il_code] = - (base_ip - td.il_code); + } + ADD_CODE(&td, * (unsigned short *)(&target)); + ADD_CODE(&td, * ((unsigned short *)&target + 1)); + td.ip += 4; + } + --td.sp; + break; + } + case CEE_LDIND_I1: + CHECK_STACK (&td, 1); + SIMPLE_OP (td, MINT_LDIND_I1); + SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I4); + break; + case CEE_LDIND_U1: + CHECK_STACK (&td, 1); + SIMPLE_OP (td, MINT_LDIND_U1); + SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I4); + break; + case CEE_LDIND_I2: + CHECK_STACK (&td, 1); + SIMPLE_OP (td, MINT_LDIND_I2); + SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I4); + break; + case CEE_LDIND_U2: + CHECK_STACK (&td, 1); + SIMPLE_OP (td, MINT_LDIND_U2); + SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I4); + break; + case CEE_LDIND_I4: + CHECK_STACK (&td, 1); + SIMPLE_OP (td, MINT_LDIND_I4); + SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I4); + break; + case CEE_LDIND_U4: + CHECK_STACK (&td, 1); + SIMPLE_OP (td, MINT_LDIND_U4); + SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I4); + break; + case CEE_LDIND_I8: + CHECK_STACK (&td, 1); + SIMPLE_OP (td, MINT_LDIND_I8); + SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I8); + break; + case CEE_LDIND_I: + CHECK_STACK (&td, 1); + SIMPLE_OP (td, MINT_LDIND_I); + ADD_CODE (&td, 0); + SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I); + break; + case CEE_LDIND_R4: + CHECK_STACK (&td, 1); + SIMPLE_OP (td, MINT_LDIND_R4); + SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_R8); + break; + case CEE_LDIND_R8: + CHECK_STACK (&td, 1); + SIMPLE_OP (td, MINT_LDIND_R8); + SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_R8); + break; + case CEE_LDIND_REF: + CHECK_STACK (&td, 1); + SIMPLE_OP (td, MINT_LDIND_REF); + SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_O); + break; + case CEE_STIND_REF: + CHECK_STACK (&td, 2); + SIMPLE_OP (td, MINT_STIND_REF); + td.sp -= 2; + break; + case CEE_STIND_I1: + CHECK_STACK (&td, 2); + SIMPLE_OP (td, MINT_STIND_I1); + td.sp -= 2; + break; + case CEE_STIND_I2: + CHECK_STACK (&td, 2); + SIMPLE_OP (td, MINT_STIND_I2); + td.sp -= 2; + break; + case CEE_STIND_I4: + CHECK_STACK (&td, 2); + SIMPLE_OP (td, MINT_STIND_I4); + td.sp -= 2; + break; + case CEE_STIND_I: + CHECK_STACK (&td, 2); + SIMPLE_OP (td, MINT_STIND_I); + td.sp -= 2; + break; + case CEE_STIND_I8: + CHECK_STACK (&td, 2); + SIMPLE_OP (td, MINT_STIND_I8); + td.sp -= 2; + break; + case CEE_STIND_R4: + CHECK_STACK (&td, 2); + SIMPLE_OP (td, MINT_STIND_R4); + td.sp -= 2; + break; + case CEE_STIND_R8: + CHECK_STACK (&td, 2); + SIMPLE_OP (td, MINT_STIND_R8); + td.sp -= 2; + break; + case CEE_ADD: + binary_arith_op(&td, MINT_ADD_I4); + ++td.ip; + break; + case CEE_SUB: + binary_arith_op(&td, MINT_SUB_I4); + ++td.ip; + break; + case CEE_MUL: + binary_arith_op(&td, MINT_MUL_I4); + ++td.ip; + break; + case CEE_DIV: + binary_arith_op(&td, MINT_DIV_I4); + ++td.ip; + break; + case CEE_DIV_UN: + binary_arith_op(&td, MINT_DIV_UN_I4); + ++td.ip; + break; + case CEE_REM: + binary_int_op (&td, MINT_REM_I4); + ++td.ip; + break; + case CEE_REM_UN: + binary_int_op (&td, MINT_REM_UN_I4); + ++td.ip; + break; + case CEE_AND: + binary_int_op (&td, MINT_AND_I4); + ++td.ip; + break; + case CEE_OR: + binary_int_op (&td, MINT_OR_I4); + ++td.ip; + break; + case CEE_XOR: + binary_int_op (&td, MINT_XOR_I4); + ++td.ip; + break; + case CEE_SHL: + shift_op (&td, MINT_SHL_I4); + ++td.ip; + break; + case CEE_SHR: + shift_op (&td, MINT_SHR_I4); + ++td.ip; + break; + case CEE_SHR_UN: + shift_op (&td, MINT_SHR_UN_I4); + ++td.ip; + break; + case CEE_NEG: + unary_arith_op (&td, MINT_NEG_I4); + ++td.ip; + break; + case CEE_NOT: + unary_arith_op (&td, MINT_NOT_I4); + ++td.ip; + break; + case CEE_CONV_U1: + CHECK_STACK (&td, 1); + switch (td.sp [-1].type) { + case STACK_TYPE_R8: + ADD_CODE(&td, MINT_CONV_U1_R8); + break; + case STACK_TYPE_I4: + ADD_CODE(&td, MINT_CONV_U1_I4); + break; + case STACK_TYPE_I8: + ADD_CODE(&td, MINT_CONV_U1_I8); + break; + default: + g_assert_not_reached (); + } + ++td.ip; + SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I4); + break; + case CEE_CONV_I1: + CHECK_STACK (&td, 1); + switch (td.sp [-1].type) { + case STACK_TYPE_R8: + ADD_CODE(&td, MINT_CONV_I1_R8); + break; + case STACK_TYPE_I4: + ADD_CODE(&td, MINT_CONV_I1_I4); + break; + case STACK_TYPE_I8: + ADD_CODE(&td, MINT_CONV_I1_I8); + break; + default: + g_assert_not_reached (); + } + ++td.ip; + SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I4); + break; + case CEE_CONV_U2: + CHECK_STACK (&td, 1); + switch (td.sp [-1].type) { + case STACK_TYPE_R8: + ADD_CODE(&td, MINT_CONV_U2_R8); + break; + case STACK_TYPE_I4: + ADD_CODE(&td, MINT_CONV_U2_I4); + break; + case STACK_TYPE_I8: + ADD_CODE(&td, MINT_CONV_U2_I8); + break; + default: + g_assert_not_reached (); + } + ++td.ip; + SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I4); + break; + case CEE_CONV_I2: + CHECK_STACK (&td, 1); + switch (td.sp [-1].type) { + case STACK_TYPE_R8: + ADD_CODE(&td, MINT_CONV_I2_R8); + break; + case STACK_TYPE_I4: + ADD_CODE(&td, MINT_CONV_I2_I4); + break; + case STACK_TYPE_I8: + ADD_CODE(&td, MINT_CONV_I2_I8); + break; + default: + g_assert_not_reached (); + } + ++td.ip; + SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I4); + break; + case CEE_CONV_U: + CHECK_STACK (&td, 1); + switch (td.sp [-1].type) { + case STACK_TYPE_R8: +#if SIZEOF_VOID_P == 4 + ADD_CODE(&td, MINT_CONV_U4_R8); +#else + ADD_CODE(&td, MINT_CONV_U8_R8); +#endif + break; + case STACK_TYPE_I4: +#if SIZEOF_VOID_P == 8 + ADD_CODE(&td, MINT_CONV_U8_I4); +#endif + break; + case STACK_TYPE_I8: +#if SIZEOF_VOID_P == 4 + ADD_CODE(&td, MINT_CONV_U4_I8); +#endif + break; + case STACK_TYPE_MP: + break; + default: + g_assert_not_reached (); + } + ++td.ip; + SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I); + break; + case CEE_CONV_I: + CHECK_STACK (&td, 1); + switch (td.sp [-1].type) { + case STACK_TYPE_R8: +#if SIZEOF_VOID_P == 8 + ADD_CODE(&td, MINT_CONV_I8_R8); +#else + ADD_CODE(&td, MINT_CONV_I4_R8); +#endif + break; + case STACK_TYPE_I4: +#if SIZEOF_VOID_P == 8 + ADD_CODE(&td, MINT_CONV_I8_I4); +#endif + break; + case STACK_TYPE_O: + break; + case STACK_TYPE_MP: + break; + case STACK_TYPE_I8: +#if SIZEOF_VOID_P == 4 + ADD_CODE(&td, MINT_CONV_I4_I8); +#endif + break; + default: + g_assert_not_reached (); + } + ++td.ip; + SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I); + break; + case CEE_CONV_U4: + CHECK_STACK (&td, 1); + switch (td.sp [-1].type) { + case STACK_TYPE_R8: + ADD_CODE(&td, MINT_CONV_U4_R8); + break; + case STACK_TYPE_I4: + break; + case STACK_TYPE_I8: + ADD_CODE(&td, MINT_CONV_U4_I8); + break; + case STACK_TYPE_MP: +#if SIZEOF_VOID_P == 8 + ADD_CODE(&td, MINT_CONV_U4_I8); +#endif + break; + default: + g_assert_not_reached (); + } + ++td.ip; + SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I4); + break; + case CEE_CONV_I4: + CHECK_STACK (&td, 1); + switch (td.sp [-1].type) { + case STACK_TYPE_R8: + ADD_CODE(&td, MINT_CONV_I4_R8); + break; + case STACK_TYPE_I4: + break; + case STACK_TYPE_I8: + ADD_CODE(&td, MINT_CONV_I4_I8); + break; + case STACK_TYPE_MP: +#if SIZEOF_VOID_P == 8 + ADD_CODE(&td, MINT_CONV_I4_I8); +#endif + break; + default: + g_assert_not_reached (); + } + ++td.ip; + SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I4); + break; + case CEE_CONV_I8: + CHECK_STACK (&td, 1); + switch (td.sp [-1].type) { + case STACK_TYPE_R8: + ADD_CODE(&td, MINT_CONV_I8_R8); + break; + case STACK_TYPE_I4: + ADD_CODE(&td, MINT_CONV_I8_I4); + break; + case STACK_TYPE_I8: + break; + case STACK_TYPE_MP: +#if SIZEOF_VOID_P == 4 + ADD_CODE(&td, MINT_CONV_I8_I4); +#endif + break; + default: + g_assert_not_reached (); + } + ++td.ip; + SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I8); + break; + case CEE_CONV_R4: + CHECK_STACK (&td, 1); + switch (td.sp [-1].type) { + case STACK_TYPE_R8: + ADD_CODE(&td, MINT_CONV_R4_R8); + break; + case STACK_TYPE_I8: + ADD_CODE(&td, MINT_CONV_R4_I8); + break; + case STACK_TYPE_I4: + ADD_CODE(&td, MINT_CONV_R4_I4); + break; + default: + g_assert_not_reached (); + } + ++td.ip; + SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_R8); + break; + case CEE_CONV_R8: + CHECK_STACK (&td, 1); + switch (td.sp [-1].type) { + case STACK_TYPE_I4: + ADD_CODE(&td, MINT_CONV_R8_I4); + break; + case STACK_TYPE_I8: + ADD_CODE(&td, MINT_CONV_R8_I8); + break; + case STACK_TYPE_R8: + break; + default: + g_assert_not_reached (); + } + ++td.ip; + SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_R8); + break; + case CEE_CONV_U8: + CHECK_STACK (&td, 1); + switch (td.sp [-1].type) { + case STACK_TYPE_I4: + ADD_CODE(&td, MINT_CONV_U8_I4); + break; + case STACK_TYPE_I8: + break; + case STACK_TYPE_R8: + ADD_CODE(&td, MINT_CONV_U8_R8); + break; + case STACK_TYPE_MP: +#if SIZEOF_VOID_P == 4 + ADD_CODE(&td, MINT_CONV_U8_I4); +#endif + break; + default: + g_assert_not_reached (); + } + ++td.ip; + SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I8); + break; +#if 0 + case CEE_CPOBJ: { + MonoClass *vtklass; + ++ip; + vtklass = mono_class_get_full (image, read32 (ip), generic_context); + ip += 4; + sp -= 2; + memcpy (sp [0].data.p, sp [1].data.p, mono_class_value_size (vtklass, NULL)); + break; + } +#endif + case CEE_LDOBJ: { + int size; + CHECK_STACK (&td, 1); + + token = read32 (td.ip + 1); + + if (method->wrapper_type != MONO_WRAPPER_NONE) + klass = (MonoClass *)mono_method_get_wrapper_data (method, token); + else + klass = mono_class_get_full (image, token, generic_context); + + ADD_CODE(&td, MINT_LDOBJ); + ADD_CODE(&td, get_data_item_index(&td, klass)); + if (mint_type (&klass->byval_arg) == MINT_TYPE_VT) { + size = mono_class_value_size (klass, NULL); + PUSH_VT(&td, size); + } + td.ip += 5; + SET_TYPE(td.sp - 1, stack_type[mint_type(&klass->byval_arg)], klass); + break; + } + case CEE_LDSTR: { + MonoString *s; + token = mono_metadata_token_index (read32 (td.ip + 1)); + td.ip += 5; + if (method->wrapper_type != MONO_WRAPPER_NONE) { + s = mono_string_new_wrapper( + mono_method_get_wrapper_data (method, token)); + } + else + s = mono_ldstr (domain, image, token); + ADD_CODE(&td, MINT_LDSTR); + ADD_CODE(&td, get_data_item_index (&td, s)); + PUSH_TYPE(&td, STACK_TYPE_O, mono_defaults.string_class); + break; + } + case CEE_NEWOBJ: { + MonoMethod *m; + MonoMethodSignature *csignature; + guint32 vt_stack_used = 0; + guint32 vt_res_size = 0; + + td.ip++; + token = read32 (td.ip); + td.ip += 4; + + if (method->wrapper_type != MONO_WRAPPER_NONE) + m = (MonoMethod *)mono_method_get_wrapper_data (method, token); + else + m = mono_get_method_full (image, token, NULL, generic_context); + + csignature = mono_method_signature (m); + klass = m->klass; + td.sp -= csignature->param_count; + ADD_CODE(&td, MINT_NEWOBJ); + ADD_CODE(&td, get_data_item_index (&td, mono_interp_get_runtime_method (domain, m, &error))); + mono_error_cleanup (&error); /* FIXME: don't swallow the error */ + + if (mint_type (&klass->byval_arg) == MINT_TYPE_VT) { + vt_res_size = mono_class_value_size (klass, NULL); + PUSH_VT (&td, vt_res_size); + } + for (i = 0; i < csignature->param_count; ++i) { + int mt = mint_type(csignature->params [i]); + if (mt == MINT_TYPE_VT) { + MonoClass *k = mono_class_from_mono_type (csignature->params [i]); + gint32 size = mono_class_value_size (k, NULL); + size = (size + 7) & ~7; + vt_stack_used += size; + } + } + if (vt_stack_used != 0 || vt_res_size != 0) { + ADD_CODE(&td, MINT_VTRESULT); + ADD_CODE(&td, vt_res_size); + WRITE32(&td, &vt_stack_used); + td.vt_sp -= vt_stack_used; + } + PUSH_TYPE (&td, stack_type [mint_type (&klass->byval_arg)], klass); + break; + } + case CEE_CASTCLASS: + CHECK_STACK (&td, 1); + token = read32 (td.ip + 1); + klass = mono_class_get_full (image, token, generic_context); + ADD_CODE(&td, MINT_CASTCLASS); + ADD_CODE(&td, get_data_item_index (&td, klass)); + td.sp [-1].klass = klass; + td.ip += 5; + break; + case CEE_ISINST: + CHECK_STACK (&td, 1); + token = read32 (td.ip + 1); + klass = mono_class_get_full (image, token, generic_context); + ADD_CODE(&td, MINT_ISINST); + ADD_CODE(&td, get_data_item_index (&td, klass)); + td.ip += 5; + break; + case CEE_CONV_R_UN: + switch (td.sp [-1].type) { + case STACK_TYPE_R8: + break; + case STACK_TYPE_I8: + ADD_CODE(&td, MINT_CONV_R_UN_I8); + break; + case STACK_TYPE_I4: + ADD_CODE(&td, MINT_CONV_R_UN_I4); + break; + default: + g_assert_not_reached (); + } + SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_R8); + ++td.ip; + break; + case CEE_UNBOX: + CHECK_STACK (&td, 1); + token = read32 (td.ip + 1); + + if (method->wrapper_type != MONO_WRAPPER_NONE) + klass = (MonoClass *)mono_method_get_wrapper_data (method, token); + else + klass = mono_class_get_full (image, token, generic_context); + + if (mono_class_is_nullable (klass)) { + g_error ("cee_unbox: implement Nullable"); + } + + ADD_CODE(&td, MINT_UNBOX); + ADD_CODE(&td, get_data_item_index (&td, klass)); + SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_MP); + td.ip += 5; + break; + case CEE_UNBOX_ANY: + CHECK_STACK (&td, 1); + token = read32 (td.ip + 1); + + g_assert (method->wrapper_type == MONO_WRAPPER_NONE); + klass = mono_class_get_full (image, token, generic_context); + + if (mini_type_is_reference (&klass->byval_arg)) { + g_error ("unbox_any: generic class is reference type"); + } else if (mono_class_is_nullable (klass)) { + MonoMethod *target_method = mono_class_get_method_from_name (klass, "Unbox", 1); + /* td.ip is incremented by interp_transform_call */ + interp_transform_call (&td, method, target_method, domain, generic_context, is_bb_start, body_start_offset, NULL); + } else { + int mt = mint_type (&klass->byval_arg); + ADD_CODE (&td, MINT_UNBOX); + ADD_CODE (&td, get_data_item_index (&td, klass)); + SET_TYPE (td.sp - 1, stack_type [mt], klass); + if (mt == MINT_TYPE_VT) { + int size = mono_class_value_size (klass, NULL); + PUSH_VT (&td, size); + } + td.ip += 5; + } + + break; + case CEE_THROW: + CHECK_STACK (&td, 1); + SIMPLE_OP (td, MINT_THROW); + --td.sp; + generating_code = 0; + break; + case CEE_LDFLDA: + CHECK_STACK (&td, 1); + token = read32 (td.ip + 1); + field = mono_field_from_token (image, token, &klass, generic_context); + mono_class_init (klass); + mt = mint_type(field->type); + ADD_CODE(&td, MINT_LDFLDA); + ADD_CODE(&td, klass->valuetype ? field->offset - sizeof(MonoObject) : field->offset); + td.ip += 5; + SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_MP); + break; + case CEE_LDFLD: { + CHECK_STACK (&td, 1); + token = read32 (td.ip + 1); + field = mono_field_from_token (image, token, &klass, generic_context); + mono_class_init (klass); + + MonoClass *field_klass = mono_class_from_mono_type (field->type); + mt = mint_type (&field_klass->byval_arg); + if (klass->marshalbyref) { + ADD_CODE(&td, mt == MINT_TYPE_VT ? MINT_LDRMFLD_VT : MINT_LDRMFLD); + ADD_CODE(&td, get_data_item_index (&td, field)); + } else { + ADD_CODE(&td, MINT_LDFLD_I1 + mt - MINT_TYPE_I1); + ADD_CODE(&td, klass->valuetype ? field->offset - sizeof(MonoObject) : field->offset); + } + if (mt == MINT_TYPE_VT) { + int size = mono_class_value_size (field_klass, NULL); + PUSH_VT(&td, size); + WRITE32(&td, &size); + } + if (td.sp [-1].type == STACK_TYPE_VT) { + int size = mono_class_value_size (klass, NULL); + size = (size + 7) & ~7; + td.vt_sp -= size; + ADD_CODE (&td, MINT_VTRESULT); + ADD_CODE (&td, 0); + WRITE32 (&td, &size); + } + td.ip += 5; + SET_TYPE(td.sp - 1, stack_type [mt], field_klass); + break; + } + case CEE_STFLD: + CHECK_STACK (&td, 2); + token = read32 (td.ip + 1); + field = mono_field_from_token (image, token, &klass, generic_context); + mono_class_init (klass); + mt = mint_type(field->type); + if (klass->marshalbyref) { + ADD_CODE(&td, mt == MINT_TYPE_VT ? MINT_STRMFLD_VT : MINT_STRMFLD); + ADD_CODE(&td, get_data_item_index (&td, field)); + } else { + ADD_CODE(&td, MINT_STFLD_I1 + mt - MINT_TYPE_I1); + ADD_CODE(&td, klass->valuetype ? field->offset - sizeof(MonoObject) : field->offset); + } + if (mt == MINT_TYPE_VT) { + MonoClass *klass = mono_class_from_mono_type (field->type); + int size = mono_class_value_size (klass, NULL); + POP_VT(&td, size); + WRITE32(&td, &size); + } + td.ip += 5; + td.sp -= 2; + break; + case CEE_LDSFLDA: + token = read32 (td.ip + 1); + field = mono_field_from_token (image, token, &klass, generic_context); + ADD_CODE(&td, MINT_LDSFLDA); + ADD_CODE(&td, get_data_item_index (&td, field)); + td.ip += 5; + PUSH_SIMPLE_TYPE(&td, STACK_TYPE_MP); + break; + case CEE_LDSFLD: + token = read32 (td.ip + 1); + field = mono_field_from_token (image, token, &klass, generic_context); + mt = mint_type(field->type); + ADD_CODE(&td, mt == MINT_TYPE_VT ? MINT_LDSFLD_VT : MINT_LDSFLD); + ADD_CODE(&td, get_data_item_index (&td, field)); + klass = NULL; + if (mt == MINT_TYPE_VT) { + MonoClass *klass = mono_class_from_mono_type (field->type); + int size = mono_class_value_size (klass, NULL); + PUSH_VT(&td, size); + WRITE32(&td, &size); + klass = field->type->data.klass; + } else { + if (mt == MINT_TYPE_O) + klass = mono_class_from_mono_type (field->type); + } + td.ip += 5; + PUSH_TYPE(&td, stack_type [mt], klass); + break; + case CEE_STSFLD: + CHECK_STACK (&td, 1); + token = read32 (td.ip + 1); + field = mono_field_from_token (image, token, &klass, generic_context); + mt = mint_type(field->type); + ADD_CODE(&td, mt == MINT_TYPE_VT ? MINT_STSFLD_VT : MINT_STSFLD); + ADD_CODE(&td, get_data_item_index (&td, field)); + if (mt == MINT_TYPE_VT) { + MonoClass *klass = mono_class_from_mono_type (field->type); + int size = mono_class_value_size (klass, NULL); + POP_VT (&td, size); + WRITE32 (&td, &size); + } + td.ip += 5; + --td.sp; + break; + case CEE_STOBJ: { + int size; + token = read32 (td.ip + 1); + + if (method->wrapper_type != MONO_WRAPPER_NONE) + klass = (MonoClass *)mono_method_get_wrapper_data (method, token); + else + klass = mono_class_get_full (image, token, generic_context); + + ADD_CODE(&td, td.sp [-1].type == STACK_TYPE_VT ? MINT_STOBJ_VT : MINT_STOBJ); + ADD_CODE(&td, get_data_item_index (&td, klass)); + if (td.sp [-1].type == STACK_TYPE_VT) { + size = mono_class_value_size (klass, NULL); + size = (size + 7) & ~7; + td.vt_sp -= size; + } + td.ip += 5; + td.sp -= 2; + break; + } + case CEE_CONV_OVF_I_UN: + CHECK_STACK (&td, 1); + switch (td.sp [-1].type) { + case STACK_TYPE_R8: +#if SIZEOF_VOID_P == 8 + ADD_CODE(&td, MINT_CONV_OVF_I8_UN_R8); +#else + ADD_CODE(&td, MINT_CONV_OVF_I4_UN_R8); +#endif + break; + case STACK_TYPE_I8: + /*FIX*/ + break; + case STACK_TYPE_I4: +#if SIZEOF_VOID_P == 8 + ADD_CODE(&td, MINT_CONV_I8_U4); +#endif + break; + default: + g_assert_not_reached (); + break; + } + SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I8); + ++td.ip; + break; + case CEE_CONV_OVF_I8_UN: + CHECK_STACK (&td, 1); + switch (td.sp [-1].type) { + case STACK_TYPE_R8: + ADD_CODE(&td, MINT_CONV_OVF_I8_UN_R8); + break; + case STACK_TYPE_I8: + break; + case STACK_TYPE_I4: + ADD_CODE(&td, MINT_CONV_I8_U4); + break; + default: + g_assert_not_reached (); + break; + } + SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I8); + ++td.ip; + break; + case CEE_BOX: { + int size; + CHECK_STACK (&td, 1); + token = read32 (td.ip + 1); + if (method->wrapper_type != MONO_WRAPPER_NONE) + klass = (MonoClass *)mono_method_get_wrapper_data (method, token); + else + klass = mono_class_get_full (image, token, generic_context); + + if (mono_class_is_nullable (klass)) { + MonoMethod *target_method = mono_class_get_method_from_name (klass, "Box", 1); + /* td.ip is incremented by interp_transform_call */ + interp_transform_call (&td, method, target_method, domain, generic_context, is_bb_start, body_start_offset, NULL); + } else if (!klass->valuetype) { + /* already boxed, do nothing. */ + td.ip += 5; + } else { + if (mint_type (&klass->byval_arg) == MINT_TYPE_VT && !klass->enumtype) { + size = mono_class_value_size (klass, NULL); + size = (size + 7) & ~7; + td.vt_sp -= size; + } + ADD_CODE(&td, MINT_BOX); + ADD_CODE(&td, get_data_item_index (&td, klass)); + ADD_CODE (&td, 0); + SET_TYPE(td.sp - 1, STACK_TYPE_O, klass); + td.ip += 5; + } + + break; + } + case CEE_NEWARR: + CHECK_STACK (&td, 1); + token = read32 (td.ip + 1); + + if (method->wrapper_type != MONO_WRAPPER_NONE) + klass = (MonoClass *)mono_method_get_wrapper_data (method, token); + else + klass = mono_class_get_full (image, token, generic_context); + + ADD_CODE(&td, MINT_NEWARR); + ADD_CODE(&td, get_data_item_index (&td, klass)); + SET_TYPE(td.sp - 1, STACK_TYPE_O, klass); + td.ip += 5; + break; + case CEE_LDLEN: + CHECK_STACK (&td, 1); + SIMPLE_OP (td, MINT_LDLEN); + SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I); + break; + case CEE_LDELEMA: + CHECK_STACK (&td, 2); + ENSURE_I4 (&td, 1); + token = read32 (td.ip + 1); + + if (method->wrapper_type != MONO_WRAPPER_NONE) + klass = (MonoClass *)mono_method_get_wrapper_data (method, token); + else + klass = mono_class_get_full (image, token, generic_context); + + ADD_CODE(&td, MINT_LDELEMA); + ADD_CODE(&td, get_data_item_index (&td, klass)); + td.ip += 5; + --td.sp; + SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_MP); + break; + case CEE_LDELEM_I1: + CHECK_STACK (&td, 2); + ENSURE_I4 (&td, 1); + SIMPLE_OP (td, MINT_LDELEM_I1); + --td.sp; + SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I4); + break; + case CEE_LDELEM_U1: + CHECK_STACK (&td, 2); + ENSURE_I4 (&td, 1); + SIMPLE_OP (td, MINT_LDELEM_U1); + --td.sp; + SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I4); + break; + case CEE_LDELEM_I2: + CHECK_STACK (&td, 2); + ENSURE_I4 (&td, 1); + SIMPLE_OP (td, MINT_LDELEM_I2); + --td.sp; + SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I4); + break; + case CEE_LDELEM_U2: + CHECK_STACK (&td, 2); + ENSURE_I4 (&td, 1); + SIMPLE_OP (td, MINT_LDELEM_U2); + --td.sp; + SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I4); + break; + case CEE_LDELEM_I4: + CHECK_STACK (&td, 2); + ENSURE_I4 (&td, 1); + SIMPLE_OP (td, MINT_LDELEM_I4); + --td.sp; + SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I4); + break; + case CEE_LDELEM_U4: + CHECK_STACK (&td, 2); + ENSURE_I4 (&td, 1); + SIMPLE_OP (td, MINT_LDELEM_U4); + --td.sp; + SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I4); + break; + case CEE_LDELEM_I8: + CHECK_STACK (&td, 2); + ENSURE_I4 (&td, 1); + SIMPLE_OP (td, MINT_LDELEM_I8); + --td.sp; + SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I8); + break; + case CEE_LDELEM_I: + CHECK_STACK (&td, 2); + ENSURE_I4 (&td, 1); + SIMPLE_OP (td, MINT_LDELEM_I); + --td.sp; + SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I); + break; + case CEE_LDELEM_R4: + CHECK_STACK (&td, 2); + ENSURE_I4 (&td, 1); + SIMPLE_OP (td, MINT_LDELEM_R4); + --td.sp; + SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_R8); + break; + case CEE_LDELEM_R8: + CHECK_STACK (&td, 2); + ENSURE_I4 (&td, 1); + SIMPLE_OP (td, MINT_LDELEM_R8); + --td.sp; + SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_R8); + break; + case CEE_LDELEM_REF: + CHECK_STACK (&td, 2); + ENSURE_I4 (&td, 1); + SIMPLE_OP (td, MINT_LDELEM_REF); + --td.sp; + SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_O); + break; + case CEE_LDELEM: + CHECK_STACK (&td, 2); + token = read32 (td.ip + 1); + klass = mono_class_get_full (image, token, generic_context); + switch (mint_type (&klass->byval_arg)) { + case MINT_TYPE_I1: + ENSURE_I4 (&td, 1); + SIMPLE_OP (td, MINT_LDELEM_I1); + --td.sp; + SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I4); + break; + case MINT_TYPE_U1: + ENSURE_I4 (&td, 1); + SIMPLE_OP (td, MINT_LDELEM_U1); + --td.sp; + SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I4); + break; + case MINT_TYPE_U2: + ENSURE_I4 (&td, 1); + SIMPLE_OP (td, MINT_LDELEM_U2); + --td.sp; + SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I4); + break; + case MINT_TYPE_I2: + ENSURE_I4 (&td, 1); + SIMPLE_OP (td, MINT_LDELEM_I2); + --td.sp; + SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I4); + break; + case MINT_TYPE_I4: + ENSURE_I4 (&td, 1); + SIMPLE_OP (td, MINT_LDELEM_I4); + --td.sp; + SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I4); + break; + case MINT_TYPE_I8: + ENSURE_I4 (&td, 1); + SIMPLE_OP (td, MINT_LDELEM_I8); + --td.sp; + SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I8); + break; + case MINT_TYPE_R4: + ENSURE_I4 (&td, 1); + SIMPLE_OP (td, MINT_LDELEM_R4); + --td.sp; + SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_R8); + break; + case MINT_TYPE_R8: + ENSURE_I4 (&td, 1); + SIMPLE_OP (td, MINT_LDELEM_R8); + --td.sp; + SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_R8); + break; + case MINT_TYPE_O: + ENSURE_I4 (&td, 1); + SIMPLE_OP (td, MINT_LDELEM_REF); + --td.sp; + SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_O); + break; + case MINT_TYPE_VT: { + int size = mono_class_value_size (klass, NULL); + ENSURE_I4 (&td, 1); + SIMPLE_OP (td, MINT_LDELEM_VT); + ADD_CODE (&td, get_data_item_index (&td, klass)); + WRITE32 (&td, &size); + --td.sp; + SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_VT); + PUSH_VT (&td, size); + break; + } + default: { + GString *res = g_string_new (""); + mono_type_get_desc (res, &klass->byval_arg, TRUE); + g_print ("LDELEM: %s -> %d (%s)\n", klass->name, mint_type (&klass->byval_arg), res->str); + g_string_free (res, TRUE); + g_assert (0); + break; + } + } + td.ip += 4; + break; + case CEE_STELEM_I: + CHECK_STACK (&td, 3); + ENSURE_I4 (&td, 2); + SIMPLE_OP (td, MINT_STELEM_I); + td.sp -= 3; + break; + case CEE_STELEM_I1: + CHECK_STACK (&td, 3); + ENSURE_I4 (&td, 2); + SIMPLE_OP (td, MINT_STELEM_I1); + td.sp -= 3; + break; + case CEE_STELEM_I2: + CHECK_STACK (&td, 3); + ENSURE_I4 (&td, 2); + SIMPLE_OP (td, MINT_STELEM_I2); + td.sp -= 3; + break; + case CEE_STELEM_I4: + CHECK_STACK (&td, 3); + ENSURE_I4 (&td, 2); + SIMPLE_OP (td, MINT_STELEM_I4); + td.sp -= 3; + break; + case CEE_STELEM_I8: + CHECK_STACK (&td, 3); + ENSURE_I4 (&td, 2); + SIMPLE_OP (td, MINT_STELEM_I8); + td.sp -= 3; + break; + case CEE_STELEM_R4: + CHECK_STACK (&td, 3); + ENSURE_I4 (&td, 2); + SIMPLE_OP (td, MINT_STELEM_R4); + td.sp -= 3; + break; + case CEE_STELEM_R8: + CHECK_STACK (&td, 3); + ENSURE_I4 (&td, 2); + SIMPLE_OP (td, MINT_STELEM_R8); + td.sp -= 3; + break; + case CEE_STELEM_REF: + CHECK_STACK (&td, 3); + ENSURE_I4 (&td, 2); + SIMPLE_OP (td, MINT_STELEM_REF); + td.sp -= 3; + break; + case CEE_STELEM: + CHECK_STACK (&td, 3); + ENSURE_I4 (&td, 2); + token = read32 (td.ip + 1); + klass = mono_class_get_full (image, token, generic_context); + switch (mint_type (&klass->byval_arg)) { + case MINT_TYPE_I4: + SIMPLE_OP (td, MINT_STELEM_I4); + break; + case MINT_TYPE_O: + SIMPLE_OP (td, MINT_STELEM_REF); + break; + case MINT_TYPE_VT: { + int size = mono_class_value_size (klass, NULL); + SIMPLE_OP (td, MINT_STELEM_VT); + ADD_CODE (&td, get_data_item_index (&td, klass)); + WRITE32 (&td, &size); + POP_VT (&td, size); + break; + } + default: { + GString *res = g_string_new (""); + mono_type_get_desc (res, &klass->byval_arg, TRUE); + g_print ("STELEM: %s -> %d (%s)\n", klass->name, mint_type (&klass->byval_arg), res->str); + g_string_free (res, TRUE); + g_assert (0); + break; + } + } + td.ip += 4; + td.sp -= 3; + break; +#if 0 + case CEE_CONV_OVF_U1: + + case CEE_CONV_OVF_I8: + +#if SIZEOF_VOID_P == 8 + case CEE_CONV_OVF_U: +#endif + case CEE_REFANYVAL: ves_abort(); break; +#endif + case CEE_CKFINITE: + CHECK_STACK (&td, 1); + SIMPLE_OP (td, MINT_CKFINITE); + break; + case CEE_CONV_OVF_I1: + case CEE_CONV_OVF_I1_UN: + CHECK_STACK (&td, 1); + switch (td.sp [-1].type) { + case STACK_TYPE_R8: + ADD_CODE(&td, MINT_CONV_OVF_I1_R8); + break; + case STACK_TYPE_I4: + ADD_CODE(&td, MINT_CONV_OVF_I1_I4); + break; + case STACK_TYPE_I8: + ADD_CODE(&td, MINT_CONV_OVF_I1_I8); + break; + default: + g_assert_not_reached (); + } + ++td.ip; + SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I4); + break; + case CEE_CONV_OVF_U1: + case CEE_CONV_OVF_U1_UN: + CHECK_STACK (&td, 1); + switch (td.sp [-1].type) { + case STACK_TYPE_R8: + ADD_CODE(&td, MINT_CONV_OVF_U1_R8); + break; + case STACK_TYPE_I4: + ADD_CODE(&td, MINT_CONV_OVF_U1_I4); + break; + case STACK_TYPE_I8: + ADD_CODE(&td, MINT_CONV_OVF_U1_I8); + break; + default: + g_assert_not_reached (); + } + ++td.ip; + SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I4); + break; + case CEE_CONV_OVF_I2: + case CEE_CONV_OVF_I2_UN: + CHECK_STACK (&td, 1); + switch (td.sp [-1].type) { + case STACK_TYPE_R8: + ADD_CODE(&td, MINT_CONV_OVF_I2_R8); + break; + case STACK_TYPE_I4: + ADD_CODE(&td, MINT_CONV_OVF_I2_I4); + break; + case STACK_TYPE_I8: + ADD_CODE(&td, MINT_CONV_OVF_I2_I8); + break; + default: + g_assert_not_reached (); + } + ++td.ip; + SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I4); + break; + case CEE_CONV_OVF_U2_UN: + case CEE_CONV_OVF_U2: + CHECK_STACK (&td, 1); + switch (td.sp [-1].type) { + case STACK_TYPE_R8: + ADD_CODE(&td, MINT_CONV_OVF_U2_R8); + break; + case STACK_TYPE_I4: + ADD_CODE(&td, MINT_CONV_OVF_U2_I4); + break; + case STACK_TYPE_I8: + ADD_CODE(&td, MINT_CONV_OVF_U2_I8); + break; + default: + g_assert_not_reached (); + } + ++td.ip; + SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I4); + break; +#if SIZEOF_VOID_P == 4 + case CEE_CONV_OVF_I: +#endif + case CEE_CONV_OVF_I4: + case CEE_CONV_OVF_I4_UN: + CHECK_STACK (&td, 1); + switch (td.sp [-1].type) { + case STACK_TYPE_R8: + ADD_CODE(&td, MINT_CONV_OVF_I4_R8); + break; + case STACK_TYPE_I4: + if (*td.ip == CEE_CONV_OVF_I4_UN) + ADD_CODE(&td, MINT_CONV_OVF_I4_U4); + break; + case STACK_TYPE_I8: + ADD_CODE(&td, MINT_CONV_OVF_I4_I8); + break; + default: + g_assert_not_reached (); + } + ++td.ip; + SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I4); + break; +#if SIZEOF_VOID_P == 4 + case CEE_CONV_OVF_U: +#endif + case CEE_CONV_OVF_U4: + case CEE_CONV_OVF_U4_UN: + CHECK_STACK (&td, 1); + switch (td.sp [-1].type) { + case STACK_TYPE_R8: + ADD_CODE(&td, MINT_CONV_OVF_U4_R8); + break; + case STACK_TYPE_I4: + if (*td.ip != CEE_CONV_OVF_U4_UN) + ADD_CODE(&td, MINT_CONV_OVF_U4_I4); + break; + case STACK_TYPE_I8: + ADD_CODE(&td, MINT_CONV_OVF_U4_I8); + break; + default: + g_assert_not_reached (); + } + ++td.ip; + SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I4); + break; +#if SIZEOF_VOID_P == 8 + case CEE_CONV_OVF_I: +#endif + case CEE_CONV_OVF_I8: + CHECK_STACK (&td, 1); + switch (td.sp [-1].type) { + case STACK_TYPE_R8: + ADD_CODE(&td, MINT_CONV_OVF_I8_R8); + break; + case STACK_TYPE_I4: + ADD_CODE(&td, MINT_CONV_I8_I4); + break; + case STACK_TYPE_I8: + break; + default: + g_assert_not_reached (); + } + ++td.ip; + SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I8); + break; +#if SIZEOF_VOID_P == 8 + case CEE_CONV_OVF_U: +#endif + case CEE_CONV_OVF_U8: + CHECK_STACK (&td, 1); + switch (td.sp [-1].type) { + case STACK_TYPE_R8: + ADD_CODE(&td, MINT_CONV_OVF_U8_R8); + break; + case STACK_TYPE_I4: + ADD_CODE(&td, MINT_CONV_OVF_U8_I4); + break; + case STACK_TYPE_I8: + break; + default: + g_assert_not_reached (); + } + ++td.ip; + SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I8); + break; + case CEE_LDTOKEN: { + int size; + gpointer handle; + token = read32 (td.ip + 1); + if (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD || method->wrapper_type == MONO_WRAPPER_SYNCHRONIZED) { + handle = mono_method_get_wrapper_data (method, token); + klass = (MonoClass *) mono_method_get_wrapper_data (method, token + 1); + if (klass == mono_defaults.typehandle_class) + handle = &((MonoClass *) handle)->byval_arg; + } else { + handle = mono_ldtoken (image, token, &klass, generic_context); + } + mt = mint_type(&klass->byval_arg); + g_assert (mt == MINT_TYPE_VT); + size = mono_class_value_size (klass, NULL); + g_assert (size == sizeof(gpointer)); + PUSH_VT(&td, sizeof(gpointer)); + ADD_CODE(&td, MINT_LDTOKEN); + ADD_CODE(&td, get_data_item_index (&td, handle)); + PUSH_SIMPLE_TYPE(&td, stack_type [mt]); + td.ip += 5; + break; + } + case CEE_ADD_OVF: + binary_arith_op(&td, MINT_ADD_OVF_I4); + ++td.ip; + break; + case CEE_ADD_OVF_UN: + binary_arith_op(&td, MINT_ADD_OVF_UN_I4); + ++td.ip; + break; + case CEE_MUL_OVF: + binary_arith_op(&td, MINT_MUL_OVF_I4); + ++td.ip; + break; + case CEE_MUL_OVF_UN: + binary_arith_op(&td, MINT_MUL_OVF_UN_I4); + ++td.ip; + break; + case CEE_SUB_OVF: + binary_arith_op(&td, MINT_SUB_OVF_I4); + ++td.ip; + break; + case CEE_SUB_OVF_UN: + binary_arith_op(&td, MINT_SUB_OVF_UN_I4); + ++td.ip; + break; + case CEE_ENDFINALLY: + SIMPLE_OP (td, MINT_ENDFINALLY); + generating_code = 0; + break; + case CEE_LEAVE: + td.sp = td.stack; + handle_branch (&td, MINT_LEAVE_S, MINT_LEAVE, 5 + read32 (td.ip + 1)); + td.ip += 5; + generating_code = 0; + break; + case CEE_LEAVE_S: + td.sp = td.stack; + handle_branch (&td, MINT_LEAVE_S, MINT_LEAVE, 2 + (gint8)td.ip [1]); + td.ip += 2; + generating_code = 0; + break; + case CEE_UNUSED41: + ++td.ip; + switch (*td.ip) { + case CEE_MONO_CALLI_EXTRA_ARG: + /* Same as CEE_CALLI, except that we drop the extra arg required for llvm specific behaviour */ + ADD_CODE (&td, MINT_POP); + ADD_CODE (&td, 1); + --td.sp; + interp_transform_call (&td, method, NULL, domain, generic_context, is_bb_start, body_start_offset, NULL); + break; + case CEE_MONO_JIT_ICALL_ADDR: { + guint32 token; + gpointer func; + MonoJitICallInfo *info; + + token = read32 (td.ip + 1); + td.ip += 5; + func = mono_method_get_wrapper_data (method, token); + info = mono_find_jit_icall_by_addr (func); + + ADD_CODE (&td, MINT_LDFTN); + ADD_CODE (&td, get_data_item_index (&td, func)); + PUSH_SIMPLE_TYPE (&td, STACK_TYPE_I); + break; + } + case CEE_MONO_ICALL: { + guint32 token; + gpointer func; + MonoJitICallInfo *info; + + token = read32 (td.ip + 1); + td.ip += 5; + func = mono_method_get_wrapper_data (method, token); + info = mono_find_jit_icall_by_addr (func); + g_assert (info); + + CHECK_STACK (&td, info->sig->param_count); + switch (info->sig->param_count) { + case 0: + if (MONO_TYPE_IS_VOID (info->sig->ret)) + ADD_CODE (&td,MINT_ICALL_V_V); + else + ADD_CODE (&td, MINT_ICALL_V_P); + break; + case 1: + if (MONO_TYPE_IS_VOID (info->sig->ret)) + ADD_CODE (&td,MINT_ICALL_P_V); + else + ADD_CODE (&td,MINT_ICALL_P_P); + break; + case 2: + if (MONO_TYPE_IS_VOID (info->sig->ret)) { + if (info->sig->params [1]->type == MONO_TYPE_I4) + ADD_CODE (&td,MINT_ICALL_PI_V); + else + ADD_CODE (&td,MINT_ICALL_PP_V); + } else { + if (info->sig->params [1]->type == MONO_TYPE_I4) + ADD_CODE (&td,MINT_ICALL_PI_P); + else + ADD_CODE (&td,MINT_ICALL_PP_P); + } + break; + case 3: + g_assert (MONO_TYPE_IS_VOID (info->sig->ret)); + if (info->sig->params [2]->type == MONO_TYPE_I4) + ADD_CODE (&td,MINT_ICALL_PPI_V); + else + ADD_CODE (&td,MINT_ICALL_PPP_V); + break; + default: + g_assert_not_reached (); + } + + if (func == mono_ftnptr_to_delegate) { + g_error ("TODO: ?"); + } + ADD_CODE(&td, get_data_item_index (&td, func)); + td.sp -= info->sig->param_count; + + if (!MONO_TYPE_IS_VOID (info->sig->ret)) { + td.sp ++; + SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I); + } + break; + } + case CEE_MONO_VTADDR: { + int size; + CHECK_STACK (&td, 1); + if (method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) + size = mono_class_native_size(td.sp [-1].klass, NULL); + else + size = mono_class_value_size(td.sp [-1].klass, NULL); + size = (size + 7) & ~7; + ADD_CODE(&td, MINT_VTRESULT); + ADD_CODE(&td, 0); + WRITE32(&td, &size); + td.vt_sp -= size; + ++td.ip; + SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_MP); + break; + } + case CEE_MONO_LDPTR: + case CEE_MONO_CLASSCONST: + token = read32 (td.ip + 1); + td.ip += 5; + ADD_CODE(&td, MINT_MONO_LDPTR); + ADD_CODE(&td, get_data_item_index (&td, mono_method_get_wrapper_data (method, token))); + td.sp [0].type = STACK_TYPE_I; + ++td.sp; + break; + case CEE_MONO_OBJADDR: + CHECK_STACK (&td, 1); + ++td.ip; + td.sp[-1].type = STACK_TYPE_MP; + /* do nothing? */ + break; + case CEE_MONO_NEWOBJ: + token = read32 (td.ip + 1); + td.ip += 5; + ADD_CODE(&td, MINT_MONO_NEWOBJ); + ADD_CODE(&td, get_data_item_index (&td, mono_method_get_wrapper_data (method, token))); + td.sp [0].type = STACK_TYPE_O; + ++td.sp; + break; + case CEE_MONO_RETOBJ: + CHECK_STACK (&td, 1); + token = read32 (td.ip + 1); + td.ip += 5; + ADD_CODE(&td, MINT_MONO_RETOBJ); + td.sp--; + + klass = (MonoClass *)mono_method_get_wrapper_data (method, token); + + /*stackval_from_data (signature->ret, frame->retval, sp->data.vt, signature->pinvoke);*/ + + if (td.sp > td.stack) + g_warning ("CEE_MONO_RETOBJ: more values on stack: %d", td.sp-td.stack); + break; + case CEE_MONO_LDNATIVEOBJ: + token = read32 (td.ip + 1); + td.ip += 5; + klass = (MonoClass *)mono_method_get_wrapper_data (method, token); + g_assert(klass->valuetype); + SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_MP); + break; + case CEE_MONO_SAVE_LMF: + case CEE_MONO_RESTORE_LMF: + case CEE_MONO_NOT_TAKEN: + ++td.ip; + break; + case CEE_MONO_LDPTR_INT_REQ_FLAG: + ADD_CODE (&td, MINT_MONO_LDPTR); + ADD_CODE (&td, get_data_item_index (&td, mono_thread_interruption_request_flag ())); + PUSH_TYPE (&td, STACK_TYPE_MP, NULL); + ++td.ip; + break; + default: + g_error ("transform.c: Unimplemented opcode: 0xF0 %02x at 0x%x\n", *td.ip, td.ip-header->code); + } + break; +#if 0 + case CEE_PREFIX7: + case CEE_PREFIX6: + case CEE_PREFIX5: + case CEE_PREFIX4: + case CEE_PREFIX3: + case CEE_PREFIX2: + case CEE_PREFIXREF: ves_abort(); break; +#endif + /* + * Note: Exceptions thrown when executing a prefixed opcode need + * to take into account the number of prefix bytes (usually the + * throw point is just (ip - n_prefix_bytes). + */ + case CEE_PREFIX1: + ++td.ip; + switch (*td.ip) { +#if 0 + case CEE_ARGLIST: ves_abort(); break; +#endif + case CEE_CEQ: + CHECK_STACK(&td, 2); + if (td.sp [-1].type == STACK_TYPE_O || td.sp [-1].type == STACK_TYPE_MP) + ADD_CODE(&td, MINT_CEQ_I4 + STACK_TYPE_I - STACK_TYPE_I4); + else + ADD_CODE(&td, MINT_CEQ_I4 + td.sp [-1].type - STACK_TYPE_I4); + --td.sp; + SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I4); + ++td.ip; + break; + case CEE_CGT: + CHECK_STACK(&td, 2); + if (td.sp [-1].type == STACK_TYPE_O || td.sp [-1].type == STACK_TYPE_MP) + ADD_CODE(&td, MINT_CGT_I4 + STACK_TYPE_I - STACK_TYPE_I4); + else + ADD_CODE(&td, MINT_CGT_I4 + td.sp [-1].type - STACK_TYPE_I4); + --td.sp; + SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I4); + ++td.ip; + break; + case CEE_CGT_UN: + CHECK_STACK(&td, 2); + if (td.sp [-1].type == STACK_TYPE_O || td.sp [-1].type == STACK_TYPE_MP) + ADD_CODE(&td, MINT_CGT_UN_I4 + STACK_TYPE_I - STACK_TYPE_I4); + else + ADD_CODE(&td, MINT_CGT_UN_I4 + td.sp [-1].type - STACK_TYPE_I4); + --td.sp; + SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I4); + ++td.ip; + break; + case CEE_CLT: + CHECK_STACK(&td, 2); + if (td.sp [-1].type == STACK_TYPE_O || td.sp [-1].type == STACK_TYPE_MP) + ADD_CODE(&td, MINT_CLT_I4 + STACK_TYPE_I - STACK_TYPE_I4); + else + ADD_CODE(&td, MINT_CLT_I4 + td.sp [-1].type - STACK_TYPE_I4); + --td.sp; + SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I4); + ++td.ip; + break; + case CEE_CLT_UN: + CHECK_STACK(&td, 2); + if (td.sp [-1].type == STACK_TYPE_O || td.sp [-1].type == STACK_TYPE_MP) + ADD_CODE(&td, MINT_CLT_UN_I4 + STACK_TYPE_I - STACK_TYPE_I4); + else + ADD_CODE(&td, MINT_CLT_UN_I4 + td.sp [-1].type - STACK_TYPE_I4); + --td.sp; + SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I4); + ++td.ip; + break; + case CEE_LDVIRTFTN: /* fallthrough */ + case CEE_LDFTN: { + MonoMethod *m; + if (*td.ip == CEE_LDVIRTFTN) { + CHECK_STACK (&td, 1); + --td.sp; + } + token = read32 (td.ip + 1); + if (method->wrapper_type != MONO_WRAPPER_NONE) + m = (MonoMethod *)mono_method_get_wrapper_data (method, token); + else + m = mono_get_method_full (image, token, NULL, generic_context); + + if (method->wrapper_type == MONO_WRAPPER_NONE && m->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED) + m = mono_marshal_get_synchronized_wrapper (m); + + ADD_CODE(&td, *td.ip == CEE_LDFTN ? MINT_LDFTN : MINT_LDVIRTFTN); + ADD_CODE(&td, get_data_item_index (&td, mono_interp_get_runtime_method (domain, m, &error))); + mono_error_cleanup (&error); /* FIXME: don't swallow the error */ + td.ip += 5; + PUSH_SIMPLE_TYPE (&td, STACK_TYPE_F); + break; + } + case CEE_LDARG: + load_arg (&td, read16 (td.ip + 1)); + td.ip += 3; + break; + case CEE_LDARGA: { + int n = read16 (td.ip + 1); + if (n == 0 && signature->hasthis) { + g_error ("LDTHISA: NOPE"); + ADD_CODE(&td, MINT_LDTHISA); + } + else { + ADD_CODE(&td, MINT_LDARGA); + ADD_CODE(&td, td.rtm->arg_offsets [n]); /* FIX for large offsets */ + } + PUSH_SIMPLE_TYPE(&td, STACK_TYPE_MP); + td.ip += 3; + break; + } + case CEE_STARG: + store_arg (&td, read16 (td.ip + 1)); + td.ip += 3; + break; + case CEE_LDLOC: + load_local (&td, read16 (td.ip + 1)); + td.ip += 3; + break; + case CEE_LDLOCA: + ADD_CODE(&td, MINT_LDLOCA_S); + ADD_CODE(&td, td.rtm->local_offsets [read16 (td.ip + 1)]); + PUSH_SIMPLE_TYPE(&td, STACK_TYPE_MP); + td.ip += 3; + break; + case CEE_STLOC: + store_local (&td, read16 (td.ip + 1)); + td.ip += 3; + break; + case CEE_LOCALLOC: + CHECK_STACK (&td, 1); +#if SIZEOF_VOID_P == 8 + if (td.sp [-1].type == STACK_TYPE_I8) + ADD_CODE(&td, MINT_CONV_I4_I8); +#endif + ADD_CODE(&td, MINT_LOCALLOC); + if (td.sp != td.stack + 1) + g_warning("CEE_LOCALLOC: stack not empty"); + ++td.ip; + SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_MP); + break; +#if 0 + case CEE_UNUSED57: ves_abort(); break; + case CEE_ENDFILTER: ves_abort(); break; +#endif + case CEE_UNALIGNED_: + ++td.ip; + /* FIX: should do something? */; + break; + case CEE_VOLATILE_: + ++td.ip; + /* FIX: should do something? */; + break; + case CEE_TAIL_: + ++td.ip; + /* FIX: should do something? */; + break; + case CEE_INITOBJ: + CHECK_STACK(&td, 1); + token = read32 (td.ip + 1); + klass = mono_class_get_full (image, token, generic_context); + ADD_CODE(&td, MINT_INITOBJ); + i32 = mono_class_value_size (klass, NULL); + WRITE32(&td, &i32); + td.ip += 5; + --td.sp; + break; + case CEE_CPBLK: + CHECK_STACK(&td, 3); + /* FIX? convert length to I8? */ + ADD_CODE(&td, MINT_CPBLK); + td.sp -= 3; + ++td.ip; + break; + case CEE_CONSTRAINED_: + token = read32 (td.ip + 1); + constrained_class = mono_class_get_full (image, token, generic_context); + mono_class_init (constrained_class); + td.ip += 5; + break; + case CEE_INITBLK: + CHECK_STACK(&td, 3); + ADD_CODE(&td, MINT_INITBLK); + td.sp -= 3; + break; +#if 0 + case CEE_NO_: + /* FIXME: implement */ + ip += 2; + break; +#endif + case CEE_RETHROW: + SIMPLE_OP (td, MINT_RETHROW); + generating_code = 0; + break; + case CEE_SIZEOF: { + gint32 size; + token = read32 (td.ip + 1); + td.ip += 5; + if (mono_metadata_token_table (token) == MONO_TABLE_TYPESPEC) { + int align; + MonoType *type = mono_type_create_from_typespec (image, token); + size = mono_type_size (type, &align); + } else { + guint32 align; + MonoClass *szclass = mono_class_get_full (image, token, generic_context); + mono_class_init (szclass); +#if 0 + if (!szclass->valuetype) + THROW_EX (mono_exception_from_name (mono_defaults.corlib, "System", "InvalidProgramException"), ip - 5); +#endif + size = mono_class_value_size (szclass, &align); + } + ADD_CODE(&td, MINT_LDC_I4); + WRITE32(&td, &size); + PUSH_SIMPLE_TYPE(&td, STACK_TYPE_I4); + break; + } +#if 0 + case CEE_REFANYTYPE: ves_abort(); break; +#endif + default: + g_error ("transform.c: Unimplemented opcode: 0xFE %02x (%s) at 0x%x\n", *td.ip, mono_opcode_name (256 + *td.ip), td.ip-header->code); + } + break; + default: + g_error ("transform.c: Unimplemented opcode: %02x at 0x%x\n", *td.ip, td.ip-header->code); + } + + if (td.new_ip - td.new_code != new_in_start_offset) + td.last_new_ip = td.new_code + new_in_start_offset; + else if (td.is_bb_start [td.in_start - td.il_code]) + td.is_bb_start [td.ip - td.il_code] = 1; + + td.last_ip = td.in_start; + } + + if (mono_interp_traceopt) { + const guint16 *p = td.new_code; + printf("Runtime method: %p, VT stack size: %d\n", rtm, td.max_vt_sp); + printf("Calculated stack size: %d, stated size: %d\n", td.max_stack_height, header->max_stack); + while (p < td.new_ip) { + p = mono_interp_dis_mintop(td.new_code, p); + printf("\n"); + } + } + + rtm->clauses = mono_mempool_alloc (domain->mp, header->num_clauses * sizeof(MonoExceptionClause)); + memcpy (rtm->clauses, header->clauses, header->num_clauses * sizeof(MonoExceptionClause)); + rtm->code = mono_mempool_alloc (domain->mp, (td.new_ip - td.new_code) * sizeof(gushort)); + memcpy (rtm->code, td.new_code, (td.new_ip - td.new_code) * sizeof(gushort)); + g_free (td.new_code); + rtm->new_body_start = rtm->code + body_start_offset; + rtm->num_clauses = header->num_clauses; + for (i = 0; i < header->num_clauses; i++) { + MonoExceptionClause *c = rtm->clauses + i; + int end_off = c->try_offset + c->try_len; + c->try_offset = td.in_offsets [c->try_offset]; + c->try_len = td.in_offsets [end_off] - c->try_offset; + end_off = c->handler_offset + c->handler_len; + c->handler_offset = td.in_offsets [c->handler_offset]; + c->handler_len = td.in_offsets [end_off] - c->handler_offset; + } + rtm->vt_stack_size = td.max_vt_sp; + rtm->alloca_size = rtm->locals_size + rtm->args_size + rtm->vt_stack_size + rtm->stack_size; + rtm->data_items = mono_mempool_alloc (domain->mp, td.n_data_items * sizeof (td.data_items [0])); + memcpy (rtm->data_items, td.data_items, td.n_data_items * sizeof (td.data_items [0])); + g_free (td.in_offsets); + g_free (td.forward_refs); + for (i = 0; i < header->code_size; ++i) + g_free (td.stack_state [i]); + g_free (td.stack_state); + g_free (td.stack_height); + g_free (td.vt_stack_size); + g_free (td.data_items); + g_hash_table_destroy (td.data_hash); +} + +static mono_mutex_t calc_section; + +void +mono_interp_transform_init (void) +{ + mono_os_mutex_init_recursive(&calc_section); +} + +MonoException * +mono_interp_transform_method (RuntimeMethod *runtime_method, ThreadContext *context) +{ + int i, align, size, offset; + MonoMethod *method = runtime_method->method; + MonoImage *image = method->klass->image; + MonoMethodHeader *header = mono_method_get_header (method); + MonoMethodSignature *signature = mono_method_signature (method); + register const unsigned char *ip, *end; + const MonoOpcode *opcode; + MonoMethod *m; + MonoClass *class; + MonoDomain *domain = mono_domain_get (); + unsigned char *is_bb_start; + int in; + MonoVTable *method_class_vt; + int backwards; + MonoGenericContext *generic_context = NULL; + + // g_printerr ("TRANSFORM(0x%016lx): begin %s::%s\n", mono_thread_current (), method->klass->name, method->name); + method_class_vt = mono_class_vtable (domain, runtime_method->method->klass); + if (!method_class_vt->initialized) { + jmp_buf env; + MonoInvocation *last_env_frame = context->env_frame; + jmp_buf *old_env = context->current_env; + + if (setjmp(env)) { + MonoException *failed = context->env_frame->ex; + context->env_frame->ex = NULL; + context->env_frame = last_env_frame; + context->current_env = old_env; + return failed; + } + context->env_frame = context->current_frame; + context->current_env = &env; + mono_runtime_class_init (method_class_vt); + context->env_frame = last_env_frame; + context->current_env = old_env; + } + + mono_profiler_method_jit (method); /* sort of... */ + + if (mono_method_signature (method)->is_inflated) + generic_context = mono_method_get_context (method); + else { + MonoGenericContainer *generic_container = mono_method_get_generic_container (method); + if (generic_container) + generic_context = &generic_container->context; + } + + if (method->iflags & (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL | METHOD_IMPL_ATTRIBUTE_RUNTIME)) { + MonoMethod *nm = NULL; + mono_os_mutex_lock(&calc_section); + if (runtime_method->transformed) { + mono_os_mutex_unlock(&calc_section); + g_error ("FIXME: no jit info?"); + mono_profiler_method_end_jit (method, NULL, MONO_PROFILE_OK); + return NULL; + } + + /* assumes all internal calls with an array this are built in... */ + if (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL && (! mono_method_signature (method)->hasthis || method->klass->rank == 0)) { + nm = mono_marshal_get_native_wrapper (method, TRUE, FALSE); + signature = mono_method_signature (nm); + } else { + const char *name = method->name; + if (method->klass->parent == mono_defaults.multicastdelegate_class) { + if (*name == '.' && (strcmp (name, ".ctor") == 0)) { + MonoJitICallInfo *mi = mono_find_jit_icall_by_name ("ves_icall_mono_delegate_ctor"); + g_assert (mi); + char *wrapper_name = g_strdup_printf ("__icall_wrapper_%s", mi->name); + nm = mono_marshal_get_icall_wrapper (mi->sig, wrapper_name, mi->func, TRUE); + } else if (*name == 'I' && (strcmp (name, "Invoke") == 0)) { + nm = mono_marshal_get_delegate_invoke (method, NULL); + } else if (*name == 'B' && (strcmp (name, "BeginInvoke") == 0)) { + nm = mono_marshal_get_delegate_begin_invoke (method); + } else if (*name == 'E' && (strcmp (name, "EndInvoke") == 0)) { + nm = mono_marshal_get_delegate_end_invoke (method); + } + } + if (nm == NULL) { + runtime_method->code = g_malloc(sizeof(short)); + runtime_method->code[0] = MINT_CALLRUN; + } + } + if (nm == NULL) { + runtime_method->stack_size = sizeof (stackval); /* for tracing */ + runtime_method->alloca_size = runtime_method->stack_size; + runtime_method->transformed = TRUE; + mono_os_mutex_unlock(&calc_section); + mono_profiler_method_end_jit (method, NULL, MONO_PROFILE_OK); + return NULL; + } + method = nm; + header = mono_method_get_header (nm); + mono_os_mutex_unlock(&calc_section); + } + g_assert ((signature->param_count + signature->hasthis) < 1000); + g_assert (header->max_stack < 10000); + /* intern the strings in the method. */ + ip = header->code; + end = ip + header->code_size; + + is_bb_start = g_malloc0(header->code_size); + is_bb_start [0] = 1; + while (ip < end) { + in = *ip; + if (in == 0xfe) { + ip++; + in = *ip + 256; + } + else if (in == 0xf0) { + ip++; + in = *ip + MONO_CEE_MONO_ICALL; + } + opcode = &mono_opcodes [in]; + switch (opcode->argument) { + case MonoInlineNone: + ++ip; + break; + case MonoInlineString: + if (method->wrapper_type == MONO_WRAPPER_NONE) + mono_ldstr (domain, image, mono_metadata_token_index (read32 (ip + 1))); + ip += 5; + break; + case MonoInlineType: + if (method->wrapper_type == MONO_WRAPPER_NONE) { + class = mono_class_get_full (image, read32 (ip + 1), generic_context); + mono_class_init (class); + /* quick fix to not do this for the fake ptr classes - probably should not be getting the vtable at all here */ +#if 0 + g_error ("FIXME: interface method lookup: %s (in method %s)", class->name, method->name); + if (!(class->flags & TYPE_ATTRIBUTE_INTERFACE) && class->interface_offsets != NULL) + mono_class_vtable (domain, class); +#endif + } + ip += 5; + break; + case MonoInlineMethod: + if (method->wrapper_type == MONO_WRAPPER_NONE && *ip != CEE_CALLI) { + m = mono_get_method_full (image, read32 (ip + 1), NULL, generic_context); + if (m == NULL) { + g_free (is_bb_start); + g_error ("FIXME: where to get method and class string?"); + return NULL; + // return mono_get_exception_missing_method (); + } + mono_class_init (m->klass); + if (!mono_class_is_interface (m->klass)) + mono_class_vtable (domain, m->klass); + } + ip += 5; + break; + case MonoInlineField: + case MonoInlineSig: + case MonoInlineI: + case MonoInlineTok: + case MonoShortInlineR: + ip += 5; + break; + case MonoInlineBrTarget: + offset = read32 (ip + 1); + ip += 5; + backwards = offset < 0; + offset += ip - header->code; + g_assert (offset >= 0 && offset < header->code_size); + is_bb_start [offset] |= backwards ? 2 : 1; + break; + case MonoShortInlineBrTarget: + offset = ((gint8 *)ip) [1]; + ip += 2; + backwards = offset < 0; + offset += ip - header->code; + g_assert (offset >= 0 && offset < header->code_size); + is_bb_start [offset] |= backwards ? 2 : 1; + break; + case MonoInlineVar: + ip += 3; + break; + case MonoShortInlineVar: + case MonoShortInlineI: + ip += 2; + break; + case MonoInlineSwitch: { + guint32 n; + const unsigned char *next_ip; + ++ip; + n = read32 (ip); + ip += 4; + next_ip = ip + 4 * n; + for (i = 0; i < n; i++) { + offset = read32 (ip); + backwards = offset < 0; + offset += next_ip - header->code; + g_assert (offset >= 0 && offset < header->code_size); + is_bb_start [offset] |= backwards ? 2 : 1; + ip += 4; + } + break; + } + case MonoInlineR: + case MonoInlineI8: + ip += 9; + break; + default: + g_assert_not_reached (); + } + } + // g_printerr ("TRANSFORM(0x%016lx): end %s::%s\n", mono_thread_current (), method->klass->name, method->name); + + /* the rest needs to be locked so it is only done once */ + mono_os_mutex_lock(&calc_section); + if (runtime_method->transformed) { + mono_os_mutex_unlock(&calc_section); + g_free (is_bb_start); + mono_profiler_method_end_jit (method, NULL, MONO_PROFILE_OK); + return NULL; + } + + runtime_method->local_offsets = g_malloc (header->num_locals * sizeof(guint32)); + runtime_method->stack_size = (sizeof (stackval) + 2) * header->max_stack; /* + 1 for returns of called functions + 1 for 0-ing in trace*/ + runtime_method->stack_size = (runtime_method->stack_size + 7) & ~7; + offset = 0; + for (i = 0; i < header->num_locals; ++i) { + size = mono_type_size (header->locals [i], &align); + offset += align - 1; + offset &= ~(align - 1); + runtime_method->local_offsets [i] = offset; + offset += size; + } + offset = (offset + 7) & ~7; + runtime_method->locals_size = offset; + g_assert (runtime_method->locals_size < 65536); + offset = 0; + runtime_method->arg_offsets = g_malloc ((!!signature->hasthis + signature->param_count) * sizeof(guint32)); + + if (signature->hasthis) { + g_assert (!signature->pinvoke); + size = mono_type_stack_size (&method->klass->byval_arg, &align); + offset += align - 1; + offset &= ~(align - 1); + runtime_method->arg_offsets [0] = offset; + offset += size; + } + + for (i = 0; i < signature->param_count; ++i) { + if (signature->pinvoke) { + guint32 dummy; + size = mono_type_native_stack_size (signature->params [i], &dummy); + align = 8; + } + else + size = mono_type_stack_size (signature->params [i], &align); + offset += align - 1; + offset &= ~(align - 1); + runtime_method->arg_offsets [i + !!signature->hasthis] = offset; + offset += size; + } + offset = (offset + 7) & ~7; + runtime_method->args_size = offset; + g_assert (runtime_method->args_size < 10000); + + generate (method, runtime_method, is_bb_start, generic_context); + + g_free (is_bb_start); + + mono_profiler_method_end_jit (method, NULL, MONO_PROFILE_OK); + runtime_method->transformed = TRUE; + mono_os_mutex_unlock(&calc_section); + + return NULL; +} + diff --git a/mono/mini/interpreter/hacks.h b/mono/mini/interpreter/hacks.h deleted file mode 100644 index 9697ccbad6f..00000000000 --- a/mono/mini/interpreter/hacks.h +++ /dev/null @@ -1,153 +0,0 @@ -/* we need some special math function */ -#ifndef _ISOC99_SOURCE -#define _ISOC99_SOURCE -#endif -#include - -/* which are not defined on FreeBSD */ -#ifdef __GNUC__ - -#ifndef isunordered -# define isunordered(u, v) \ - (__extension__ \ - ({ __typeof__(u) __u = (u); __typeof__(v) __v = (v); \ - isnan(__u) || isnan(__v); })) -#endif - -#ifndef islessgreater -# define islessgreater(x, u) \ - (__extension__ \ - ({ __typeof__(x) __x = (x); __typeof__(y) __y = (y); \ - !isunordered (__x, __y) && (__x < __y) || (__y < __x); })) -#endif - -#ifndef islessequal -# define islessequal(x, y) \ - (__extension__ \ - ({ __typeof__(x) __x = (x); __typeof__(y) __y = (y); \ - !isunordered(__x, __y) && __x <= __y; })) -#endif - -#ifndef isless -# define isless(x, y) \ - (__extension__ \ - ({ __typeof__(x) __x = (x); __typeof__(y) __y = (y); \ - !isunordered(__x, __y) && __x < __y; })) -#endif - -#ifndef isgreater -# define isgreater(x, y) \ - (__extension__ \ - ({ __typeof__(x) __x = (x); __typeof__(y) __y = (y); \ - !isunordered(__x, __y) && __x > __y; })) -#endif - -#else - -/* isunordered seems to crash on HPUX when built 64 bits - so use generic implementation. -*/ -#if defined(__hpux) && SIZEOF_VOID_P == 8 -#undef isunordered -#undef islessgreater -#undef islessequal -#undef isless -#undef isgreater -#endif - -#ifndef isunordered -# define isunordered(u, v) (isnan(u) || isnan(v)) -#endif - -#ifndef islessgreater -# define islessgreater(x, u) (!isunordered (x, y) && (x < y) || (y < x)) -#endif - -#ifndef islessequal -# define islessequal(x, y) (!isunordered(x, y) && x <= y) -#endif - -#ifndef isless -# define isless(x, y) (!isunordered(x, y) && x < y) -#endif - -#ifndef isgreater -# define isgreater(x, y) (!isunordered(x, y) && x > y) -#endif - -#endif - -/* - * Attempt at using the goto label construct of GNU GCC: - * it turns out this does give some benefit: 5-15% speedup. - * Don't look at these macros, it hurts... - */ -#define GOTO_LABEL -#undef GOTO_LABEL -#ifdef GOTO_LABEL - -#define SWITCH(a) goto *goto_map [(a)]; -#define BREAK SWITCH(*ip) -#define CASE(l) l ## _LABEL: -#define DEFAULT \ - CEE_ILLEGAL_LABEL: \ - CEE_ENDMAC_LABEL: -#define SUB_SWITCH \ - CEE_PREFIX1_LABEL: \ - CEE_ARGLIST_LABEL: \ - CEE_CEQ_LABEL: \ - CEE_CGT_LABEL: \ - CEE_CGT_UN_LABEL: \ - CEE_CLT_LABEL: \ - CEE_CLT_UN_LABEL: \ - CEE_LDFTN_LABEL: \ - CEE_LDVIRTFTN_LABEL: \ - CEE_UNUSED56_LABEL: \ - CEE_LDARG_LABEL: \ - CEE_LDARGA_LABEL: \ - CEE_STARG_LABEL: \ - CEE_LDLOC_LABEL: \ - CEE_LDLOCA_LABEL: \ - CEE_STLOC_LABEL: \ - CEE_LOCALLOC_LABEL: \ - CEE_UNUSED57_LABEL: \ - CEE_ENDFILTER_LABEL: \ - CEE_UNALIGNED__LABEL: \ - CEE_VOLATILE__LABEL: \ - CEE_TAIL__LABEL: \ - CEE_INITOBJ_LABEL: \ - CEE_UNUSED68_LABEL: \ - CEE_CPBLK_LABEL: \ - CEE_INITBLK_LABEL: \ - CEE_UNUSED69_LABEL: \ - CEE_RETHROW_LABEL: \ - CEE_UNUSED_LABEL: \ - CEE_SIZEOF_LABEL: \ - CEE_REFANYTYPE_LABEL: \ - CEE_UNUSED52_LABEL: \ - CEE_UNUSED53_LABEL: \ - CEE_UNUSED54_LABEL: \ - CEE_UNUSED55_LABEL: \ - CEE_UNUSED70_LABEL: -#define GOTO_LABEL_VARS \ - const static void * const goto_map [] = {\ -#define OPDEF(a,b,c,d,e,f,g,h,i,j) \ \ - && a ## _LABEL, \ -#include "mono/cil/opcode.def" \ -#undef OPDEF \ - &&DUMMY_LABEL \ - }; \ - DUMMY_LABEL: - -#else - -#define SWITCH(a) switch(a) -#define BREAK break -#define CASE(l) case l: -#define DEFAULT \ - default: \ - g_error ("Unimplemented opcode: %x at 0x%x\n", *ip, ip-header->code); -#define SUB_SWITCH case 0xFE: -#define GOTO_LABEL_VARS - -#endif diff --git a/mono/mini/interpreter/interp-internals.h b/mono/mini/interpreter/interp-internals.h deleted file mode 100644 index f26e4ff57b3..00000000000 --- a/mono/mini/interpreter/interp-internals.h +++ /dev/null @@ -1,124 +0,0 @@ -#ifndef __MONO_MINI_INTERPRETER_INTERNALS_H__ -#define __MONO_MINI_INTERPRETER_INTERNALS_H__ - -#include -#include -#include -#include -#include -#include -#include "config.h" - -enum { - VAL_I32 = 0, - VAL_DOUBLE = 1, - VAL_I64 = 2, - VAL_VALUET = 3, - VAL_POINTER = 4, - VAL_NATI = 0 + VAL_POINTER, - VAL_MP = 1 + VAL_POINTER, - VAL_TP = 2 + VAL_POINTER, - VAL_OBJ = 3 + VAL_POINTER -}; - -#if SIZEOF_VOID_P == 4 -typedef guint32 mono_u; -typedef gint32 mono_i; -#elif SIZEOF_VOID_P == 8 -typedef guint64 mono_u; -typedef gint64 mono_i; -#endif - -/* - * Value types are represented on the eval stack as pointers to the - * actual storage. The size field tells how much storage is allocated. - * A value type can't be larger than 16 MB. - */ -typedef struct { - union { - gint32 i; - gint64 l; - double f; - /* native size integer and pointer types */ - gpointer p; - mono_u nati; - gpointer vt; - } data; -#if defined(__ppc__) || defined(__powerpc__) - int pad; -#endif -} stackval; - -typedef struct _MonoInvocation MonoInvocation; - -typedef void (*MonoFuncV) (void); -typedef void (*MonoPIFunc) (MonoFuncV callme, void *margs); - -/* - * Structure representing a method transformed for the interpreter - * This is domain specific - */ -typedef struct _RuntimeMethod -{ - /* NOTE: These first two elements (method and - next_jit_code_hash) must be in the same order and at the - same offset as in MonoJitInfo, because of the jit_code_hash - internal hash table in MonoDomain. */ - MonoMethod *method; - struct _RuntimeMethod *next_jit_code_hash; - guint32 locals_size; - guint32 args_size; - guint32 stack_size; - guint32 vt_stack_size; - guint32 alloca_size; - unsigned short *code; - unsigned short *new_body_start; /* after all STINARG instrs */ - MonoPIFunc func; - int num_clauses; - MonoExceptionClause *clauses; - void **data_items; - int transformed; - guint32 *arg_offsets; - guint32 *local_offsets; - unsigned int param_count; - unsigned int hasthis; -} RuntimeMethod; - -struct _MonoInvocation { - MonoInvocation *parent; /* parent */ - RuntimeMethod *runtime_method; /* parent */ - MonoMethod *method; /* parent */ - stackval *retval; /* parent */ - char *args; - stackval *stack_args; /* parent */ - stackval *stack; - stackval *sp; /* For GC stack marking */ - /* exception info */ - unsigned char invoke_trap; - const unsigned short *ip; - MonoException *ex; - MonoExceptionClause *ex_handler; -}; - -typedef struct { - MonoDomain *domain; - MonoInvocation *base_frame; - MonoInvocation *current_frame; - MonoInvocation *env_frame; - jmp_buf *current_env; - unsigned char search_for_handler; - unsigned char managed_code; -} ThreadContext; - -extern int mono_interp_traceopt; - -MonoException * -mono_interp_transform_method (RuntimeMethod *runtime_method, ThreadContext *context); - -void -mono_interp_transform_init (void); - -RuntimeMethod * -mono_interp_get_runtime_method (MonoDomain *domain, MonoMethod *method, MonoError *error); - -#endif /* __MONO_MINI_INTERPRETER_INTERNALS_H__ */ diff --git a/mono/mini/interpreter/interp.c b/mono/mini/interpreter/interp.c deleted file mode 100644 index 9c21f957355..00000000000 --- a/mono/mini/interpreter/interp.c +++ /dev/null @@ -1,4550 +0,0 @@ -/* - * PLEASE NOTE: This is a research prototype. - * - * - * interp.c: Interpreter for CIL byte codes - * - * Authors: - * Paolo Molaro (lupus@ximian.com) - * Miguel de Icaza (miguel@ximian.com) - * Dietmar Maurer (dietmar@ximian.com) - * - * (C) 2001, 2002 Ximian, Inc. - */ -#ifndef __USE_ISOC99 -#define __USE_ISOC99 -#endif -#include "config.h" -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#ifdef HAVE_ALLOCA_H -# include -#else -# ifdef __CYGWIN__ -# define alloca __builtin_alloca -# endif -#endif - -/* trim excessive headers */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "interp.h" -#include "interp-internals.h" -#include "mintops.h" -#include "hacks.h" - -#include -#include - - -/* Mingw 2.1 doesnt need this any more, but leave it in for now for older versions */ -#ifdef _WIN32 -#define isnan _isnan -#define finite _finite -#endif -#ifndef HAVE_FINITE -#ifdef HAVE_ISFINITE -#define finite isfinite -#endif -#endif - -#define INIT_FRAME(frame,parent_frame,method_args,method_retval,domain,mono_method,error) \ - do { \ - (frame)->parent = (parent_frame); \ - (frame)->stack_args = (method_args); \ - (frame)->retval = (method_retval); \ - (frame)->runtime_method = mono_interp_get_runtime_method ((domain), (mono_method), (error)); \ - (frame)->ex = NULL; \ - (frame)->ip = NULL; \ - (frame)->invoke_trap = 0; \ - } while (0) - -void ves_exec_method (MonoInvocation *frame); - -static char* dump_stack (stackval *stack, stackval *sp); -static char* dump_frame (MonoInvocation *inv); -static MonoArray *get_trace_ips (MonoDomain *domain, MonoInvocation *top); -static void ves_exec_method_with_context (MonoInvocation *frame, ThreadContext *context); - -typedef void (*ICallMethod) (MonoInvocation *frame); - -static guint32 die_on_exception = 0; -static MonoNativeTlsKey thread_context_id; - -static char* dump_args (MonoInvocation *inv); - -#define DEBUG_INTERP 0 -#define COUNT_OPS 0 -#if DEBUG_INTERP -int mono_interp_traceopt = 2; -/* If true, then we output the opcodes as we interpret them */ -static int global_tracing = 2; - -static int debug_indent_level = 0; - -static int break_on_method = 0; -static int nested_trace = 0; -static GList *db_methods = NULL; - -static void -output_indent (void) -{ - int h; - - for (h = 0; h < debug_indent_level; h++) - g_print (" "); -} - -static void -db_match_method (gpointer data, gpointer user_data) -{ - MonoMethod *m = (MonoMethod*)user_data; - MonoMethodDesc *desc = data; - - if (mono_method_desc_full_match (desc, m)) - break_on_method = 1; -} - -static void debug_enter (MonoInvocation *frame, int *tracing) -{ - if (db_methods) { - g_list_foreach (db_methods, db_match_method, (gpointer)frame->runtime_method->method); - if (break_on_method) - *tracing = nested_trace ? (global_tracing = 2, 3) : 2; - break_on_method = 0; - } - if (*tracing) { - MonoMethod *method = frame->runtime_method->method; - char *mn, *args = dump_args (frame); - debug_indent_level++; - output_indent (); - mn = mono_method_full_name (method, FALSE); - g_print ("(%p) Entering %s (", mono_thread_internal_current (), mn); - g_free (mn); - g_print ("%s)\n", args); - g_free (args); - } - if (mono_profiler_events & MONO_PROFILE_ENTER_LEAVE) - mono_profiler_method_enter (frame->runtime_method->method); -} - - -#define DEBUG_LEAVE() \ - if (tracing) { \ - char *mn, *args; \ - args = dump_retval (frame); \ - output_indent (); \ - mn = mono_method_full_name (frame->runtime_method->method, FALSE); \ - g_print ("(%p) Leaving %s", mono_thread_internal_current (), mn); \ - g_free (mn); \ - g_print (" => %s\n", args); \ - g_free (args); \ - debug_indent_level--; \ - if (tracing == 3) global_tracing = 0; \ - } \ - if (mono_profiler_events & MONO_PROFILE_ENTER_LEAVE) \ - mono_profiler_method_leave (frame->runtime_method->method); - -#else - -int mono_interp_traceopt = 0; -static void debug_enter (MonoInvocation *frame, int *tracing) -{ -} -#define DEBUG_LEAVE() - -#endif - -static void -interp_ex_handler (MonoException *ex) { - MonoError error; - ThreadContext *context = mono_native_tls_get_value (thread_context_id); - char *stack_trace; - if (context == NULL) - return; - stack_trace = dump_frame (context->current_frame); - ex->stack_trace = mono_string_new (mono_domain_get(), stack_trace); - g_free (stack_trace); - if (context->current_env == NULL || strcmp(ex->object.vtable->klass->name, "ExecutionEngineException") == 0) { - char *strace = mono_string_to_utf8_checked (ex->stack_trace, &error); - mono_error_cleanup (&error); /* FIXME: don't swallow the error */ - fprintf(stderr, "Nothing can catch this exception: "); - fprintf(stderr, "%s", ex->object.vtable->klass->name); - if (ex->message != NULL) { - char *m = mono_string_to_utf8_checked (ex->message, &error); - mono_error_cleanup (&error); /* FIXME: don't swallow the error */ - fprintf(stderr, ": %s", m); - g_free(m); - } - fprintf(stderr, "\n%s\n", strace); - g_free (strace); - if (ex->inner_ex != NULL) { - ex = (MonoException *)ex->inner_ex; - fprintf(stderr, "Inner exception: %s", ex->object.vtable->klass->name); - if (ex->message != NULL) { - char *m = mono_string_to_utf8_checked (ex->message, &error); - mono_error_cleanup (&error); /* FIXME: don't swallow the error */ - fprintf(stderr, ": %s", m); - g_free(m); - } - strace = mono_string_to_utf8_checked (ex->stack_trace, &error); - mono_error_cleanup (&error); /* FIXME: don't swallow the error */ - fprintf(stderr, "\n"); - fprintf(stderr, "%s\n", strace); - g_free (strace); - } - /* wait for other threads to also collapse */ - // Sleep(1000); // TODO: proper sleep - exit(1); - } - context->env_frame->ex = ex; - context->search_for_handler = 1; - longjmp (*context->current_env, 1); -} - -static void -ves_real_abort (int line, MonoMethod *mh, - const unsigned short *ip, stackval *stack, stackval *sp) -{ - MonoError error; - fprintf (stderr, "Execution aborted in method: %s::%s\n", mh->klass->name, mh->name); - fprintf (stderr, "Line=%d IP=0x%04lx, Aborted execution\n", line, - ip-(const unsigned short *)mono_method_get_header_checked (mh, &error)->code); - mono_error_cleanup (&error); /* FIXME: don't swallow the error */ - g_print ("0x%04x %02x\n", - ip-(const unsigned short *)mono_method_get_header_checked (mh, &error)->code, *ip); - mono_error_cleanup (&error); /* FIXME: don't swallow the error */ - if (sp > stack) - printf ("\t[%ld] 0x%08x %0.5f\n", sp-stack, sp[-1].data.i, sp[-1].data.f); -} - -#define ves_abort() \ - do {\ - ves_real_abort(__LINE__, frame->runtime_method->method, ip, frame->stack, sp); \ - THROW_EX (mono_get_exception_execution_engine (NULL), ip); \ - } while (0); - -static mono_mutex_t runtime_method_lookup_section; - -RuntimeMethod* -mono_interp_get_runtime_method (MonoDomain *domain, MonoMethod *method, MonoError *error) -{ - RuntimeMethod *rtm; - error_init (error); - - mono_os_mutex_lock (&runtime_method_lookup_section); - if ((rtm = mono_internal_hash_table_lookup (&domain->jit_code_hash, method))) { - mono_os_mutex_unlock (&runtime_method_lookup_section); - return rtm; - } - rtm = mono_mempool_alloc (domain->mp, sizeof (RuntimeMethod)); - memset (rtm, 0, sizeof (*rtm)); - rtm->method = method; - rtm->param_count = mono_method_signature (method)->param_count; - rtm->hasthis = mono_method_signature (method)->hasthis; - mono_internal_hash_table_insert (&domain->jit_code_hash, method, rtm); - mono_os_mutex_unlock (&runtime_method_lookup_section); - - return rtm; -} - -static gpointer -interp_create_trampoline (MonoDomain *domain, MonoMethod *method, MonoError *error) -{ - if (method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED) - method = mono_marshal_get_synchronized_wrapper (method); - return mono_interp_get_runtime_method (domain, method, error); -} - -static inline RuntimeMethod* -get_virtual_method (MonoDomain *domain, RuntimeMethod *runtime_method, MonoObject *obj) -{ - MonoMethod *m = runtime_method->method; - MonoError error; - - if ((m->flags & METHOD_ATTRIBUTE_FINAL) || !(m->flags & METHOD_ATTRIBUTE_VIRTUAL)) { - RuntimeMethod *ret = NULL; - if (mono_object_is_transparent_proxy (obj)) { - ret = mono_interp_get_runtime_method (domain, mono_marshal_get_remoting_invoke (m), &error); - mono_error_cleanup (&error); /* FIXME: don't swallow the error */ - } else if (m->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED) { - ret = mono_interp_get_runtime_method (domain, mono_marshal_get_synchronized_wrapper (m), &error); - mono_error_cleanup (&error); /* FIXME: don't swallow the error */ - } else { - ret = runtime_method; - } - return ret; - } - - mono_class_setup_vtable (obj->vtable->klass); - - int slot = mono_method_get_vtable_slot (m); - if (mono_class_is_interface (m->klass)) { - g_assert (obj->vtable->klass != m->klass); - /* TODO: interface offset lookup is slow, go through IMT instead */ - slot += mono_class_interface_offset (obj->vtable->klass, m->klass); - } - - MonoMethod *virtual_method = obj->vtable->klass->vtable [slot]; - if (m->is_inflated && mono_method_get_context (m)->method_inst) { - MonoGenericContext context = { NULL, NULL }; - - if (mono_class_is_ginst (virtual_method->klass)) - context.class_inst = mono_class_get_generic_class (virtual_method->klass)->context.class_inst; - else if (mono_class_is_gtd (virtual_method->klass)) - context.class_inst = mono_class_get_generic_container (virtual_method->klass)->context.class_inst; - context.method_inst = mono_method_get_context (m)->method_inst; - - virtual_method = mono_class_inflate_generic_method_checked (virtual_method, &context, &error); - mono_error_cleanup (&error); /* FIXME: don't swallow the error */ - } - RuntimeMethod *virtual_runtime_method = mono_interp_get_runtime_method (domain, virtual_method, &error); - mono_error_cleanup (&error); /* FIXME: don't swallow the error */ - return virtual_runtime_method; -} - -static void inline -stackval_from_data (MonoType *type, stackval *result, char *data, gboolean pinvoke) -{ - if (type->byref) { - switch (type->type) { - case MONO_TYPE_OBJECT: - case MONO_TYPE_CLASS: - case MONO_TYPE_STRING: - case MONO_TYPE_ARRAY: - case MONO_TYPE_SZARRAY: - break; - default: - break; - } - result->data.p = *(gpointer*)data; - return; - } - switch (type->type) { - case MONO_TYPE_VOID: - return; - case MONO_TYPE_I1: - result->data.i = *(gint8*)data; - return; - case MONO_TYPE_U1: - case MONO_TYPE_BOOLEAN: - result->data.i = *(guint8*)data; - return; - case MONO_TYPE_I2: - result->data.i = *(gint16*)data; - return; - case MONO_TYPE_U2: - case MONO_TYPE_CHAR: - result->data.i = *(guint16*)data; - return; - case MONO_TYPE_I4: - result->data.i = *(gint32*)data; - return; - case MONO_TYPE_U: - case MONO_TYPE_I: - result->data.nati = *(mono_i*)data; - return; - case MONO_TYPE_PTR: - result->data.p = *(gpointer*)data; - return; - case MONO_TYPE_U4: - result->data.i = *(guint32*)data; - return; - case MONO_TYPE_R4: - result->data.f = *(float*)data; - return; - case MONO_TYPE_I8: - case MONO_TYPE_U8: - result->data.l = *(gint64*)data; - return; - case MONO_TYPE_R8: - result->data.f = *(double*)data; - return; - case MONO_TYPE_STRING: - case MONO_TYPE_SZARRAY: - case MONO_TYPE_CLASS: - case MONO_TYPE_OBJECT: - case MONO_TYPE_ARRAY: - result->data.p = *(gpointer*)data; - return; - case MONO_TYPE_VALUETYPE: - if (type->data.klass->enumtype) { - stackval_from_data (mono_class_enum_basetype (type->data.klass), result, data, pinvoke); - return; - } else - mono_value_copy (result->data.vt, data, type->data.klass); - return; - case MONO_TYPE_GENERICINST: - stackval_from_data (&type->data.generic_class->container_class->byval_arg, result, data, pinvoke); - return; - default: - g_warning ("got type 0x%02x", type->type); - g_assert_not_reached (); - } -} - -static void inline -stackval_to_data (MonoType *type, stackval *val, char *data, gboolean pinvoke) -{ - if (type->byref) { - gpointer *p = (gpointer*)data; - *p = val->data.p; - return; - } - /* printf ("TODAT0 %p\n", data); */ - switch (type->type) { - case MONO_TYPE_I1: - case MONO_TYPE_U1: { - guint8 *p = (guint8*)data; - *p = val->data.i; - return; - } - case MONO_TYPE_BOOLEAN: { - guint8 *p = (guint8*)data; - *p = (val->data.i != 0); - return; - } - case MONO_TYPE_I2: - case MONO_TYPE_U2: - case MONO_TYPE_CHAR: { - guint16 *p = (guint16*)data; - *p = val->data.i; - return; - } - case MONO_TYPE_I: { - mono_i *p = (mono_i*)data; - /* In theory the value used by stloc should match the local var type - but in practice it sometimes doesn't (a int32 gets dup'd and stloc'd into - a native int - both by csc and mcs). Not sure what to do about sign extension - as it is outside the spec... doing the obvious */ - *p = (mono_i)val->data.nati; - return; - } - case MONO_TYPE_U: { - mono_u *p = (mono_u*)data; - /* see above. */ - *p = (mono_u)val->data.nati; - return; - } - case MONO_TYPE_I4: - case MONO_TYPE_U4: { - gint32 *p = (gint32*)data; - *p = val->data.i; - return; - } - case MONO_TYPE_I8: - case MONO_TYPE_U8: { - gint64 *p = (gint64*)data; - *p = val->data.l; - return; - } - case MONO_TYPE_R4: { - float *p = (float*)data; - *p = val->data.f; - return; - } - case MONO_TYPE_R8: { - double *p = (double*)data; - *p = val->data.f; - return; - } - case MONO_TYPE_STRING: - case MONO_TYPE_SZARRAY: - case MONO_TYPE_CLASS: - case MONO_TYPE_OBJECT: - case MONO_TYPE_ARRAY: - case MONO_TYPE_PTR: { - gpointer *p = (gpointer*)data; - *p = val->data.p; - return; - } - case MONO_TYPE_VALUETYPE: - if (type->data.klass->enumtype) { - stackval_to_data (mono_class_enum_basetype (type->data.klass), val, data, pinvoke); - return; - } else - mono_value_copy (data, val->data.vt, type->data.klass); - return; - case MONO_TYPE_GENERICINST: - stackval_to_data (&type->data.generic_class->container_class->byval_arg, val, data, pinvoke); - return; - default: - g_warning ("got type %x", type->type); - g_assert_not_reached (); - } -} - -static void -fill_in_trace (MonoException *exception, MonoInvocation *frame) -{ - char *stack_trace = dump_frame (frame); - MonoDomain *domain = mono_domain_get(); - (exception)->stack_trace = mono_string_new (domain, stack_trace); - (exception)->trace_ips = get_trace_ips (domain, frame); - g_free (stack_trace); -} - -#define FILL_IN_TRACE(exception, frame) fill_in_trace(exception, frame) - -#define THROW_EX(exception,ex_ip) \ - do {\ - frame->ip = (ex_ip); \ - frame->ex = (MonoException*)(exception); \ - FILL_IN_TRACE(frame->ex, frame); \ - goto handle_exception; \ - } while (0) - -static MonoObject* -ves_array_create (MonoDomain *domain, MonoClass *klass, MonoMethodSignature *sig, stackval *values) -{ - uintptr_t *lengths; - intptr_t *lower_bounds; - MonoObject *obj; - MonoError error; - int i; - - lengths = alloca (sizeof (uintptr_t) * klass->rank * 2); - for (i = 0; i < sig->param_count; ++i) { - lengths [i] = values->data.i; - values ++; - } - if (klass->rank == sig->param_count) { - /* Only lengths provided. */ - lower_bounds = NULL; - } else { - /* lower bounds are first. */ - lower_bounds = (intptr_t *) lengths; - lengths += klass->rank; - } - obj = (MonoObject*) mono_array_new_full_checked (domain, klass, lengths, lower_bounds, &error); - mono_error_cleanup (&error); /* FIXME: don't swallow the error */ - return obj; -} - -static void -ves_array_set (MonoInvocation *frame) -{ - stackval *sp = frame->stack_args + 1; - MonoObject *o; - MonoArray *ao; - MonoClass *ac; - gint32 i, t, pos, esize; - gpointer ea; - MonoType *mt; - - o = frame->stack_args->data.p; - ao = (MonoArray *)o; - ac = o->vtable->klass; - - g_assert (ac->rank >= 1); - - pos = sp [0].data.i; - if (ao->bounds != NULL) { - pos -= ao->bounds [0].lower_bound; - for (i = 1; i < ac->rank; i++) { - if ((t = sp [i].data.i - ao->bounds [i].lower_bound) >= - ao->bounds [i].length) { - frame->ex = mono_get_exception_index_out_of_range (); - FILL_IN_TRACE(frame->ex, frame); - return; - } - pos = pos*ao->bounds [i].length + sp [i].data.i - - ao->bounds [i].lower_bound; - } - } else if (pos >= ao->max_length) { - frame->ex = mono_get_exception_index_out_of_range (); - FILL_IN_TRACE(frame->ex, frame); - return; - } - - if (sp [ac->rank].data.p && !mono_object_class (o)->element_class->valuetype) { - MonoError error; - MonoObject *isinst = mono_object_isinst_checked (sp [ac->rank].data.p, mono_object_class (o)->element_class, &error); - mono_error_cleanup (&error); - if (!isinst) { - frame->ex = mono_get_exception_array_type_mismatch (); - FILL_IN_TRACE (frame->ex, frame); - return; - } - } - - esize = mono_array_element_size (ac); - ea = mono_array_addr_with_size (ao, esize, pos); - - mt = mono_method_signature (frame->runtime_method->method)->params [ac->rank]; - stackval_to_data (mt, &sp [ac->rank], ea, FALSE); -} - -static void -ves_array_get (MonoInvocation *frame) -{ - stackval *sp = frame->stack_args + 1; - MonoObject *o; - MonoArray *ao; - MonoClass *ac; - gint32 i, t, pos, esize; - gpointer ea; - MonoType *mt; - - o = frame->stack_args->data.p; - ao = (MonoArray *)o; - ac = o->vtable->klass; - - g_assert (ac->rank >= 1); - - pos = sp [0].data.i; - if (ao->bounds != NULL) { - pos -= ao->bounds [0].lower_bound; - for (i = 1; i < ac->rank; i++) { - if ((t = sp [i].data.i - ao->bounds [i].lower_bound) >= - ao->bounds [i].length) { - frame->ex = mono_get_exception_index_out_of_range (); - FILL_IN_TRACE(frame->ex, frame); - return; - } - - pos = pos*ao->bounds [i].length + sp [i].data.i - - ao->bounds [i].lower_bound; - } - } else if (pos >= ao->max_length) { - frame->ex = mono_get_exception_index_out_of_range (); - FILL_IN_TRACE(frame->ex, frame); - return; - } - - esize = mono_array_element_size (ac); - ea = mono_array_addr_with_size (ao, esize, pos); - - mt = mono_method_signature (frame->runtime_method->method)->ret; - stackval_from_data (mt, frame->retval, ea, FALSE); -} - -static void -ves_array_element_address (MonoInvocation *frame) -{ - stackval *sp = frame->stack_args + 1; - MonoObject *o; - MonoArray *ao; - MonoClass *ac; - gint32 i, t, pos, esize; - gpointer ea; - - o = frame->stack_args->data.p; - ao = (MonoArray *)o; - ac = o->vtable->klass; - - g_assert (ac->rank >= 1); - - pos = sp [0].data.i; - if (ao->bounds != NULL) { - pos -= ao->bounds [0].lower_bound; - for (i = 1; i < ac->rank; i++) { - if ((t = sp [i].data.i - ao->bounds [i].lower_bound) >= - ao->bounds [i].length) { - frame->ex = mono_get_exception_index_out_of_range (); - FILL_IN_TRACE(frame->ex, frame); - return; - } - pos = pos*ao->bounds [i].length + sp [i].data.i - - ao->bounds [i].lower_bound; - } - } else if (pos >= ao->max_length) { - frame->ex = mono_get_exception_index_out_of_range (); - FILL_IN_TRACE(frame->ex, frame); - return; - } - - esize = mono_array_element_size (ac); - ea = mono_array_addr_with_size (ao, esize, pos); - - frame->retval->data.p = ea; -} - -void -interp_walk_stack_with_ctx (MonoInternalStackWalk func, MonoContext *ctx, MonoUnwindOptions options, void *user_data) -{ - MonoError error; - ThreadContext *context = mono_native_tls_get_value (thread_context_id); - - MonoInvocation *frame = context->current_frame; - - while (frame) { - MonoStackFrameInfo fi; - memset (&fi, 0, sizeof (MonoStackFrameInfo)); - - /* TODO: hack to make some asserts happy. */ - fi.ji = (MonoJitInfo *) frame->runtime_method; - - if (frame->runtime_method) - fi.method = fi.actual_method = frame->runtime_method->method; - - if (!fi.method || (fi.method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) || (fi.method->iflags & (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL | METHOD_IMPL_ATTRIBUTE_RUNTIME))) { - fi.il_offset = -1; - fi.type = FRAME_TYPE_MANAGED_TO_NATIVE; - } else { - MonoMethodHeader *hd = mono_method_get_header_checked (fi.method, &error); - mono_error_cleanup (&error); /* FIXME: don't swallow the error */ - fi.type = FRAME_TYPE_MANAGED; - fi.il_offset = frame->ip - (const unsigned short *) hd->code; - if (!fi.method->wrapper_type) - fi.managed = TRUE; - } - - if (func (&fi, ctx, user_data)) - return; - frame = frame->parent; - } - - g_assert (0); -} - -static MonoPIFunc mono_interp_enter_icall_trampoline = NULL; - -struct _MethodArguments { - size_t ilen; - gpointer *iargs; - size_t flen; - double *fargs; - gpointer *retval; - size_t is_float_ret; -}; - -typedef struct _MethodArguments MethodArguments; - -// TODO: this function is also arch dependent (register width). -static MethodArguments* build_args_from_sig (MonoMethodSignature *sig, MonoInvocation *frame) -{ - // TODO: don't malloc this data structure. - MethodArguments *margs = g_malloc0 (sizeof (MethodArguments)); - - if (sig->hasthis) - margs->ilen++; - - for (int i = 0; i < sig->param_count; i++) { - guint32 ptype = sig->params [i]->byref ? MONO_TYPE_PTR : sig->params [i]->type; - switch (ptype) { - case MONO_TYPE_BOOLEAN: - case MONO_TYPE_CHAR: - case MONO_TYPE_I1: - case MONO_TYPE_U1: - case MONO_TYPE_I2: - case MONO_TYPE_U2: - case MONO_TYPE_I4: - case MONO_TYPE_U4: - case MONO_TYPE_I: - case MONO_TYPE_U: - case MONO_TYPE_PTR: - case MONO_TYPE_SZARRAY: - case MONO_TYPE_CLASS: - case MONO_TYPE_OBJECT: - case MONO_TYPE_STRING: - case MONO_TYPE_I8: - case MONO_TYPE_VALUETYPE: - case MONO_TYPE_GENERICINST: - margs->ilen++; - break; - case MONO_TYPE_R4: - case MONO_TYPE_R8: - margs->flen++; - break; - default: - g_error ("build_args_from_sig: not implemented yet (1): 0x%x\n", ptype); - } - } - - if (margs->ilen > 0) - margs->iargs = g_malloc0 (sizeof (gpointer) * margs->ilen); - - if (margs->flen > 0) - margs->fargs = g_malloc0 (sizeof (double) * margs->flen); - - if (margs->ilen > 8) - g_error ("build_args_from_sig: TODO, allocate gregs: %d\n", margs->ilen); - - if (margs->flen > 3) - g_error ("build_args_from_sig: TODO, allocate fregs: %d\n", margs->flen); - - - size_t int_i = 0; - size_t int_f = 0; - - if (sig->hasthis) { - margs->iargs [0] = frame->stack_args->data.p; - int_i++; - } - - for (int i = 0; i < sig->param_count; i++) { - guint32 ptype = sig->params [i]->byref ? MONO_TYPE_PTR : sig->params [i]->type; - switch (ptype) { - case MONO_TYPE_BOOLEAN: - case MONO_TYPE_CHAR: - case MONO_TYPE_I1: - case MONO_TYPE_U1: - case MONO_TYPE_I2: - case MONO_TYPE_U2: - case MONO_TYPE_I4: - case MONO_TYPE_U4: - case MONO_TYPE_I: - case MONO_TYPE_U: - case MONO_TYPE_PTR: - case MONO_TYPE_SZARRAY: - case MONO_TYPE_CLASS: - case MONO_TYPE_OBJECT: - case MONO_TYPE_STRING: - case MONO_TYPE_I8: - case MONO_TYPE_VALUETYPE: - case MONO_TYPE_GENERICINST: - margs->iargs [int_i] = frame->stack_args [i].data.p; -#if DEBUG_INTERP - g_print ("build_args_from_sig: margs->iargs[%d]: %p (frame @ %d)\n", int_i, margs->iargs[int_i], i); -#endif - int_i++; - break; - case MONO_TYPE_R4: - case MONO_TYPE_R8: - margs->fargs [int_f] = frame->stack_args [i].data.f; - int_f++; - break; - default: - g_error ("build_args_from_sig: not implemented yet (2): 0x%x\n", ptype); - } - } - - switch (sig->ret->type) { - case MONO_TYPE_BOOLEAN: - case MONO_TYPE_CHAR: - case MONO_TYPE_I1: - case MONO_TYPE_U1: - case MONO_TYPE_I2: - case MONO_TYPE_U2: - case MONO_TYPE_I4: - case MONO_TYPE_U4: - case MONO_TYPE_I: - case MONO_TYPE_U: - case MONO_TYPE_PTR: - case MONO_TYPE_SZARRAY: - case MONO_TYPE_CLASS: - case MONO_TYPE_OBJECT: - case MONO_TYPE_STRING: - case MONO_TYPE_I8: - case MONO_TYPE_VALUETYPE: - case MONO_TYPE_GENERICINST: - margs->retval = &(frame->retval->data.p); - break; - case MONO_TYPE_R4: - case MONO_TYPE_R8: - margs->retval = &(frame->retval->data.p); - margs->is_float_ret = 1; - break; - case MONO_TYPE_VOID: - margs->retval = NULL; - break; - default: - g_error ("build_args_from_sig: ret type not implemented yet: 0x%x\n", sig->ret->type); - } - - return margs; -} - -static void -ves_pinvoke_method (MonoInvocation *frame, MonoMethodSignature *sig, MonoFuncV addr, gboolean string_ctor, ThreadContext *context) -{ - jmp_buf env; - MonoInvocation *old_frame = context->current_frame; - MonoInvocation *old_env_frame = context->env_frame; - jmp_buf *old_env = context->current_env; - - if (setjmp (env)) { - context->current_frame = old_frame; - context->env_frame = old_env_frame; - context->current_env = old_env; - context->managed_code = 1; - return; - } - - frame->ex = NULL; - context->env_frame = frame; - context->current_env = &env; - - g_assert (!frame->runtime_method); - if (!mono_interp_enter_icall_trampoline) { - MonoTrampInfo *info; - mono_interp_enter_icall_trampoline = mono_arch_get_enter_icall_trampoline (&info); - // TODO: - // mono_tramp_info_register (info, NULL); - } - - MethodArguments *margs = build_args_from_sig (sig, frame); -#if DEBUG_INTERP - g_print ("ICALL: mono_interp_enter_icall_trampoline = %p, addr = %p\n", mono_interp_enter_icall_trampoline, addr); - g_print ("margs(out): ilen=%d, flen=%d\n", margs->ilen, margs->flen); -#endif - - context->current_frame = frame; - context->managed_code = 0; - - mono_interp_enter_icall_trampoline (addr, margs); - - context->managed_code = 1; - /* domain can only be changed by native code */ - context->domain = mono_domain_get (); - - if (*mono_thread_interruption_request_flag ()) - mono_thread_interruption_checkpoint (); - - if (!MONO_TYPE_ISSTRUCT (sig->ret)) - stackval_from_data (sig->ret, frame->retval, (char*)&frame->retval->data.p, sig->pinvoke); - - context->current_frame = old_frame; - context->env_frame = old_env_frame; - context->current_env = old_env; - - g_free (margs->iargs); - g_free (margs->fargs); - g_free (margs); -} - -void -mono_interp_init_delegate (MonoDelegate *del) -{ - g_assert (!del->method); - del->method = ((RuntimeMethod *) del->method_ptr)->method; - g_assert (del->method); -} - -/* - * From the spec: - * runtime specifies that the implementation of the method is automatically - * provided by the runtime and is primarily used for the methods of delegates. - */ -static void -ves_runtime_method (MonoInvocation *frame, ThreadContext *context) -{ - MonoMethod *method = frame->runtime_method->method; - const char *name = method->name; - MonoObject *obj = (MonoObject*) frame->stack_args->data.p; - MonoObject *isinst_obj; - MonoError error; - - mono_class_init (method->klass); - - isinst_obj = mono_object_isinst_checked (obj, mono_defaults.array_class, &error); - mono_error_cleanup (&error); /* FIXME: don't swallow the error */ - if (obj && isinst_obj) { - if (*name == 'S' && (strcmp (name, "Set") == 0)) { - ves_array_set (frame); - return; - } - if (*name == 'G' && (strcmp (name, "Get") == 0)) { - ves_array_get (frame); - return; - } - if (*name == 'A' && (strcmp (name, "Address") == 0)) { - ves_array_element_address (frame); - return; - } - } - - g_error ("Don't know how to exec runtime method %s.%s::%s", - method->klass->name_space, method->klass->name, - method->name); -} - -static char* -dump_stack (stackval *stack, stackval *sp) -{ - stackval *s = stack; - GString *str = g_string_new (""); - - if (sp == stack) - return g_string_free (str, FALSE); - - while (s < sp) { - g_string_append_printf (str, "[%p (%lld)] ", s->data.l, s->data.l); - ++s; - } - return g_string_free (str, FALSE); -} - -static void -dump_stackval (GString *str, stackval *s, MonoType *type) -{ - switch (type->type) { - case MONO_TYPE_I1: - case MONO_TYPE_U1: - case MONO_TYPE_I2: - case MONO_TYPE_U2: - case MONO_TYPE_I4: - case MONO_TYPE_U4: - case MONO_TYPE_CHAR: - case MONO_TYPE_BOOLEAN: - g_string_append_printf (str, "[%d] ", s->data.i); - break; - case MONO_TYPE_STRING: - case MONO_TYPE_SZARRAY: - case MONO_TYPE_CLASS: - case MONO_TYPE_OBJECT: - case MONO_TYPE_ARRAY: - case MONO_TYPE_PTR: - case MONO_TYPE_I: - case MONO_TYPE_U: - g_string_append_printf (str, "[%p] ", s->data.p); - break; - case MONO_TYPE_VALUETYPE: - if (type->data.klass->enumtype) - g_string_append_printf (str, "[%d] ", s->data.i); - else - g_string_append_printf (str, "[vt:%p] ", s->data.p); - break; - case MONO_TYPE_R4: - case MONO_TYPE_R8: - g_string_append_printf (str, "[%g] ", s->data.f); - break; - case MONO_TYPE_I8: - case MONO_TYPE_U8: - default: { - GString *res = g_string_new (""); - mono_type_get_desc (res, type, TRUE); - g_string_append_printf (str, "[{%s} %lld/0x%0llx] ", res->str, s->data.l, s->data.l); - g_string_free (res, TRUE); - break; - } - } -} - -static char* -dump_args (MonoInvocation *inv) -{ - GString *str = g_string_new (""); - int i; - MonoMethodSignature *signature = mono_method_signature (inv->runtime_method->method); - - if (signature->param_count == 0 && !signature->hasthis) - return g_string_free (str, FALSE); - - if (signature->hasthis) { - MonoMethod *method = inv->runtime_method->method; - dump_stackval (str, inv->stack_args, &method->klass->byval_arg); - } - - for (i = 0; i < signature->param_count; ++i) - dump_stackval (str, inv->stack_args + (!!signature->hasthis) + i, signature->params [i]); - - return g_string_free (str, FALSE); -} - -static char* -dump_retval (MonoInvocation *inv) -{ - GString *str = g_string_new (""); - MonoType *ret = mono_method_signature (inv->runtime_method->method)->ret; - - if (ret->type != MONO_TYPE_VOID) - dump_stackval (str, inv->retval, ret); - - return g_string_free (str, FALSE); -} - -static char* -dump_frame (MonoInvocation *inv) -{ - GString *str = g_string_new (""); - int i; - char *args; - MonoError error; - - for (i = 0; inv; inv = inv->parent) { - if (inv->runtime_method != NULL) { - MonoMethod *method = inv->runtime_method->method; - MonoClass *k; - - int codep = 0; - const char * opname = ""; - char *name; - gchar *source = NULL; - - k = method->klass; - - if ((method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) == 0 && - (method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) == 0) { - MonoMethodHeader *hd = mono_method_get_header_checked (method, &error); - mono_error_cleanup (&error); /* FIXME: don't swallow the error */ - - if (hd != NULL) { - if (inv->ip) { - opname = mono_interp_opname [*inv->ip]; - codep = inv->ip - inv->runtime_method->code; - source = g_strdup_printf ("%s:%d // (TODO: proper stacktrace)", method->name, codep); - } else - opname = ""; - -#if 0 - MonoDebugSourceLocation *minfo = mono_debug_lookup_method (method); - source = mono_debug_method_lookup_location (minfo, codep); -#endif - } - } - args = dump_args (inv); - name = mono_method_full_name (method, TRUE); - if (source) - g_string_append_printf (str, "#%d: 0x%05x %-10s in %s (%s) at %s\n", i, codep, opname, name, args, source); - else - g_string_append_printf (str, "#%d: 0x%05x %-10s in %s (%s)\n", i, codep, opname, name, args); - g_free (name); - g_free (args); - g_free (source); - ++i; - } - } - return g_string_free (str, FALSE); -} - -static MonoArray * -get_trace_ips (MonoDomain *domain, MonoInvocation *top) -{ - int i; - MonoArray *res; - MonoInvocation *inv; - MonoError error; - - for (i = 0, inv = top; inv; inv = inv->parent) - if (inv->runtime_method != NULL) - ++i; - - res = mono_array_new_checked (domain, mono_defaults.int_class, 2 * i, &error); - mono_error_cleanup (&error); /* FIXME: don't swallow the error */ - - for (i = 0, inv = top; inv; inv = inv->parent) - if (inv->runtime_method != NULL) { - mono_array_set (res, gpointer, i, inv->runtime_method); - ++i; - mono_array_set (res, gpointer, i, (gpointer)inv->ip); - ++i; - } - - return res; -} - - -#define MYGUINT64_MAX 18446744073709551615ULL -#define MYGINT64_MAX 9223372036854775807LL -#define MYGINT64_MIN (-MYGINT64_MAX -1LL) - -#define MYGUINT32_MAX 4294967295U -#define MYGINT32_MAX 2147483647 -#define MYGINT32_MIN (-MYGINT32_MAX -1) - -#define CHECK_ADD_OVERFLOW(a,b) \ - (gint32)(b) >= 0 ? (gint32)(MYGINT32_MAX) - (gint32)(b) < (gint32)(a) ? -1 : 0 \ - : (gint32)(MYGINT32_MIN) - (gint32)(b) > (gint32)(a) ? +1 : 0 - -#define CHECK_SUB_OVERFLOW(a,b) \ - (gint32)(b) < 0 ? (gint32)(MYGINT32_MAX) + (gint32)(b) < (gint32)(a) ? -1 : 0 \ - : (gint32)(MYGINT32_MIN) + (gint32)(b) > (gint32)(a) ? +1 : 0 - -#define CHECK_ADD_OVERFLOW_UN(a,b) \ - (guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a) ? -1 : 0 - -#define CHECK_SUB_OVERFLOW_UN(a,b) \ - (guint32)(a) < (guint32)(b) ? -1 : 0 - -#define CHECK_ADD_OVERFLOW64(a,b) \ - (gint64)(b) >= 0 ? (gint64)(MYGINT64_MAX) - (gint64)(b) < (gint64)(a) ? -1 : 0 \ - : (gint64)(MYGINT64_MIN) - (gint64)(b) > (gint64)(a) ? +1 : 0 - -#define CHECK_SUB_OVERFLOW64(a,b) \ - (gint64)(b) < 0 ? (gint64)(MYGINT64_MAX) + (gint64)(b) < (gint64)(a) ? -1 : 0 \ - : (gint64)(MYGINT64_MIN) + (gint64)(b) > (gint64)(a) ? +1 : 0 - -#define CHECK_ADD_OVERFLOW64_UN(a,b) \ - (guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a) ? -1 : 0 - -#define CHECK_SUB_OVERFLOW64_UN(a,b) \ - (guint64)(a) < (guint64)(b) ? -1 : 0 - -#if SIZEOF_VOID_P == 4 -#define CHECK_ADD_OVERFLOW_NAT(a,b) CHECK_ADD_OVERFLOW(a,b) -#define CHECK_ADD_OVERFLOW_NAT_UN(a,b) CHECK_ADD_OVERFLOW_UN(a,b) -#else -#define CHECK_ADD_OVERFLOW_NAT(a,b) CHECK_ADD_OVERFLOW64(a,b) -#define CHECK_ADD_OVERFLOW_NAT_UN(a,b) CHECK_ADD_OVERFLOW64_UN(a,b) -#endif - -/* Resolves to TRUE if the operands would overflow */ -#define CHECK_MUL_OVERFLOW(a,b) \ - ((gint32)(a) == 0) || ((gint32)(b) == 0) ? 0 : \ - (((gint32)(a) > 0) && ((gint32)(b) == -1)) ? FALSE : \ - (((gint32)(a) < 0) && ((gint32)(b) == -1)) ? (a == - MYGINT32_MAX) : \ - (((gint32)(a) > 0) && ((gint32)(b) > 0)) ? (gint32)(a) > ((MYGINT32_MAX) / (gint32)(b)) : \ - (((gint32)(a) > 0) && ((gint32)(b) < 0)) ? (gint32)(a) > ((MYGINT32_MIN) / (gint32)(b)) : \ - (((gint32)(a) < 0) && ((gint32)(b) > 0)) ? (gint32)(a) < ((MYGINT32_MIN) / (gint32)(b)) : \ - (gint32)(a) < ((MYGINT32_MAX) / (gint32)(b)) - -#define CHECK_MUL_OVERFLOW_UN(a,b) \ - ((guint32)(a) == 0) || ((guint32)(b) == 0) ? 0 : \ - (guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a)) - -#define CHECK_MUL_OVERFLOW64(a,b) \ - ((gint64)(a) == 0) || ((gint64)(b) == 0) ? 0 : \ - (((gint64)(a) > 0) && ((gint64)(b) == -1)) ? FALSE : \ - (((gint64)(a) < 0) && ((gint64)(b) == -1)) ? (a == - MYGINT64_MAX) : \ - (((gint64)(a) > 0) && ((gint64)(b) > 0)) ? (gint64)(a) > ((MYGINT64_MAX) / (gint64)(b)) : \ - (((gint64)(a) > 0) && ((gint64)(b) < 0)) ? (gint64)(a) > ((MYGINT64_MIN) / (gint64)(b)) : \ - (((gint64)(a) < 0) && ((gint64)(b) > 0)) ? (gint64)(a) < ((MYGINT64_MIN) / (gint64)(b)) : \ - (gint64)(a) < ((MYGINT64_MAX) / (gint64)(b)) - -#define CHECK_MUL_OVERFLOW64_UN(a,b) \ - ((guint64)(a) == 0) || ((guint64)(b) == 0) ? 0 : \ - (guint64)(b) > ((MYGUINT64_MAX) / (guint64)(a)) - -#if SIZEOF_VOID_P == 4 -#define CHECK_MUL_OVERFLOW_NAT(a,b) CHECK_MUL_OVERFLOW(a,b) -#define CHECK_MUL_OVERFLOW_NAT_UN(a,b) CHECK_MUL_OVERFLOW_UN(a,b) -#else -#define CHECK_MUL_OVERFLOW_NAT(a,b) CHECK_MUL_OVERFLOW64(a,b) -#define CHECK_MUL_OVERFLOW_NAT_UN(a,b) CHECK_MUL_OVERFLOW64_UN(a,b) -#endif - -MonoObject* -mono_interp_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError *error) -{ - MonoInvocation frame; - ThreadContext * volatile context = mono_native_tls_get_value (thread_context_id); - MonoObject *retval = NULL; - MonoMethodSignature *sig = mono_method_signature (method); - MonoClass *klass = mono_class_from_mono_type (sig->ret); - int i, type, isobject = 0; - void *ret = NULL; - stackval result; - stackval *args = alloca (sizeof (stackval) * (sig->param_count + !!sig->hasthis)); - ThreadContext context_struct; - MonoInvocation *old_frame = NULL; - jmp_buf env; - - error_init (error); - - frame.ex = NULL; - - if (setjmp(env)) { - if (context != &context_struct) { - context->domain = mono_domain_get (); - context->current_frame = old_frame; - context->managed_code = 0; - } else - mono_native_tls_set_value (thread_context_id, NULL); - if (exc != NULL) - *exc = (MonoObject *)frame.ex; - return retval; - } - - if (context == NULL) { - context = &context_struct; - context_struct.base_frame = &frame; - context_struct.current_frame = NULL; - context_struct.env_frame = &frame; - context_struct.current_env = &env; - context_struct.search_for_handler = 0; - context_struct.managed_code = 0; - mono_native_tls_set_value (thread_context_id, context); - } - else - old_frame = context->current_frame; - - context->domain = mono_domain_get (); - - switch (sig->ret->type) { - case MONO_TYPE_VOID: - break; - case MONO_TYPE_STRING: - case MONO_TYPE_OBJECT: - case MONO_TYPE_CLASS: - case MONO_TYPE_ARRAY: - case MONO_TYPE_SZARRAY: - isobject = 1; - break; - case MONO_TYPE_VALUETYPE: - retval = mono_object_new_checked (context->domain, klass, error); - ret = ((char*)retval) + sizeof (MonoObject); - if (!sig->ret->data.klass->enumtype) - result.data.vt = ret; - break; - default: - retval = mono_object_new_checked (context->domain, klass, error); - ret = ((char*)retval) + sizeof (MonoObject); - break; - } - - if (sig->hasthis) - args [0].data.p = obj; - - for (i = 0; i < sig->param_count; ++i) { - int a_index = i + !!sig->hasthis; - if (sig->params [i]->byref) { - args [a_index].data.p = params [i]; - continue; - } - type = sig->params [i]->type; -handle_enum: - switch (type) { - case MONO_TYPE_U1: - case MONO_TYPE_I1: - case MONO_TYPE_BOOLEAN: - args [a_index].data.i = *(MonoBoolean*)params [i]; - break; - case MONO_TYPE_U2: - case MONO_TYPE_I2: - case MONO_TYPE_CHAR: - args [a_index].data.i = *(gint16*)params [i]; - break; -#if SIZEOF_VOID_P == 4 - case MONO_TYPE_U: /* use VAL_POINTER? */ - case MONO_TYPE_I: -#endif - case MONO_TYPE_U4: - case MONO_TYPE_I4: - args [a_index].data.i = *(gint32*)params [i]; - break; -#if SIZEOF_VOID_P == 8 - case MONO_TYPE_U: - case MONO_TYPE_I: -#endif - case MONO_TYPE_U8: - case MONO_TYPE_I8: - args [a_index].data.l = *(gint64*)params [i]; - break; - case MONO_TYPE_VALUETYPE: - if (sig->params [i]->data.klass->enumtype) { - type = mono_class_enum_basetype (sig->params [i]->data.klass)->type; - goto handle_enum; - } else { - args [a_index].data.p = params [i]; - } - break; - case MONO_TYPE_STRING: - case MONO_TYPE_CLASS: - case MONO_TYPE_ARRAY: - case MONO_TYPE_SZARRAY: - case MONO_TYPE_OBJECT: - args [a_index].data.p = params [i]; - break; - default: - g_error ("type 0x%x not handled in runtime invoke", sig->params [i]->type); - } - } - - if (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) - method = mono_marshal_get_native_wrapper (method, FALSE, FALSE); - INIT_FRAME (&frame,context->current_frame,args,&result,mono_get_root_domain (),method,error); - if (exc) - frame.invoke_trap = 1; - context->managed_code = 1; - ves_exec_method_with_context (&frame, context); - context->managed_code = 0; - if (context == &context_struct) - mono_native_tls_set_value (thread_context_id, NULL); - else - context->current_frame = old_frame; - if (frame.ex != NULL) { - if (exc != NULL) { - *exc = (MonoObject*) frame.ex; - return NULL; - } - if (context->current_env != NULL) { - context->env_frame->ex = frame.ex; - longjmp(*context->current_env, 1); - } - else - printf("dropped exception...\n"); - } - if (sig->ret->type == MONO_TYPE_VOID && !method->string_ctor) - return NULL; - if (isobject || method->string_ctor) - return result.data.p; - stackval_to_data (sig->ret, &result, ret, sig->pinvoke); - return retval; -} - -static stackval * -do_icall (ThreadContext *context, int op, stackval *sp, gpointer ptr) -{ - MonoInvocation *old_frame = context->current_frame; - MonoInvocation *old_env_frame = context->env_frame; - jmp_buf *old_env = context->current_env; - jmp_buf env; - - if (setjmp (env)) { - context->current_frame = old_frame; - context->env_frame = old_env_frame; - context->current_env = old_env; - context->managed_code = 1; - return sp; - } - - context->env_frame = context->current_frame; - context->current_env = &env; - context->managed_code = 0; - - switch (op) { - case MINT_ICALL_V_V: { - void (*func)() = ptr; - func (); - break; - } - case MINT_ICALL_V_P: { - gpointer (*func)() = ptr; - sp++; - sp [-1].data.p = func (); - break; - } - case MINT_ICALL_P_V: { - void (*func)(gpointer) = ptr; - func (sp [-1].data.p); - sp --; - break; - } - case MINT_ICALL_P_P: { - gpointer (*func)(gpointer) = ptr; - sp [-1].data.p = func (sp [-1].data.p); - break; - } - case MINT_ICALL_PP_V: { - void (*func)(gpointer,gpointer) = ptr; - sp -= 2; - func (sp [0].data.p, sp [1].data.p); - break; - } - case MINT_ICALL_PI_V: { - void (*func)(gpointer,int) = ptr; - sp -= 2; - func (sp [0].data.p, sp [1].data.i); - break; - } - case MINT_ICALL_PP_P: { - gpointer (*func)(gpointer,gpointer) = ptr; - --sp; - sp [-1].data.p = func (sp [-1].data.p, sp [0].data.p); - break; - } - case MINT_ICALL_PI_P: { - gpointer (*func)(gpointer,int) = ptr; - --sp; - sp [-1].data.p = func (sp [-1].data.p, sp [0].data.i); - break; - } - case MINT_ICALL_PPP_V: { - void (*func)(gpointer,gpointer,gpointer) = ptr; - sp -= 3; - func (sp [0].data.p, sp [1].data.p, sp [2].data.p); - break; - } - case MINT_ICALL_PPI_V: { - void (*func)(gpointer,gpointer,int) = ptr; - sp -= 3; - func (sp [0].data.p, sp [1].data.p, sp [2].data.i); - break; - } - default: - g_assert_not_reached (); - } - - context->env_frame = old_env_frame; - context->current_env = old_env; - - return sp; -} - -static mono_mutex_t create_method_pointer_mutex; - -static GHashTable *method_pointer_hash = NULL; - -static MonoMethod *method_pointers [2] = {0}; - -static MonoObject * -mp_tramp_0 (MonoObject *this_obj, void **params, MonoObject **exc, void *compiled_method) { - MonoError error; - void *params_real[] = {this_obj, ¶ms, &exc, &compiled_method}; - MonoObject *ret = mono_interp_runtime_invoke (method_pointers [0], NULL, params_real, NULL, &error); - mono_error_cleanup (&error); /* FIXME: don't swallow the error */ - return ret; -} - -static MonoObject * -mp_tramp_1 (MonoObject *this_obj, void **params, MonoObject **exc, void *compiled_method) { - MonoError error; - void *params_real[] = {this_obj, ¶ms, &exc, &compiled_method}; - MonoObject *ret = mono_interp_runtime_invoke (method_pointers [1], NULL, params_real, NULL, &error); - mono_error_cleanup (&error); /* FIXME: don't swallow the error */ - return ret; -} - -gpointer *mp_tramps[] = {(gpointer) mp_tramp_0, (gpointer) mp_tramp_1}; - -static int tramps_used = 0; - -gpointer -mono_interp_create_method_pointer (MonoMethod *method, MonoError *error) -{ - gpointer addr; - MonoJitInfo *ji; - - mono_os_mutex_lock (&create_method_pointer_mutex); - if (!method_pointer_hash) { - // FIXME: is registering method table as GC root really necessary? - // MONO_GC_REGISTER_ROOT_FIXED (method_pointer_hash); - method_pointer_hash = g_hash_table_new (NULL, NULL); - } - addr = g_hash_table_lookup (method_pointer_hash, method); - if (addr) { - mono_os_mutex_unlock (&create_method_pointer_mutex); - return addr; - } - - /* - * If it is a static P/Invoke method, we can just return the pointer - * to the method implementation. - */ - if (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL && ((MonoMethodPInvoke*) method)->addr) { - ji = g_new0 (MonoJitInfo, 1); - ji->d.method = method; - ji->code_size = 1; - ji->code_start = addr = ((MonoMethodPInvoke*) method)->addr; - - mono_jit_info_table_add (mono_get_root_domain (), ji); - } - else { - g_assert (method->wrapper_type == MONO_WRAPPER_RUNTIME_INVOKE); - g_assert (tramps_used < 2); - - /* FIXME: needs locking */ - method_pointers [tramps_used] = method; - addr = mp_tramps [tramps_used]; - tramps_used++; - } - - g_hash_table_insert (method_pointer_hash, method, addr); - mono_os_mutex_unlock (&create_method_pointer_mutex); - - return addr; -} - -#if COUNT_OPS -static int opcode_counts[512]; - -#define COUNT_OP(op) opcode_counts[op]++ -#else -#define COUNT_OP(op) -#endif - -#if DEBUG_INTERP -#define DUMP_INSTR() \ - if (tracing > 1) { \ - char *ins; \ - if (sp > frame->stack) { \ - ins = dump_stack (frame->stack, sp); \ - } else { \ - ins = g_strdup (""); \ - } \ - sp->data.l = 0; \ - output_indent (); \ - char *mn = mono_method_full_name (frame->runtime_method->method, FALSE); \ - g_print ("(%p) %s -> ", mono_thread_internal_current (), mn); \ - g_free (mn); \ - mono_interp_dis_mintop(rtm->code, ip); \ - g_print ("\t%d:%s\n", vt_sp - vtalloc, ins); \ - g_free (ins); \ - } -#else -#define DUMP_INSTR() -#endif - -#ifdef __GNUC__ -#define USE_COMPUTED_GOTO 1 -#endif -#if USE_COMPUTED_GOTO -#define MINT_IN_SWITCH(op) COUNT_OP(op); goto *in_labels[op]; -#define MINT_IN_CASE(x) LAB_ ## x: -#if DEBUG_INTERP -#define MINT_IN_BREAK if (tracing > 1) goto main_loop; else { COUNT_OP(*ip); goto *in_labels[*ip]; } -#else -#define MINT_IN_BREAK { COUNT_OP(*ip); goto *in_labels[*ip]; } -#endif -#define MINT_IN_DEFAULT mint_default: if (0) goto mint_default; /* make gcc shut up */ -#else -#define MINT_IN_SWITCH(op) switch (op) -#define MINT_IN_CASE(x) case x: -#define MINT_IN_BREAK break -#define MINT_IN_DEFAULT default: -#endif - -/* - * Defining this causes register allocation errors in some versions of gcc: - * error: unable to find a register to spill in class `SIREG' - */ -/* #define MINT_USE_DEDICATED_IP_REG */ - -static void -ves_exec_method_with_context (MonoInvocation *frame, ThreadContext *context) -{ - MonoInvocation child_frame; - GSList *finally_ips = NULL; - const unsigned short *endfinally_ip = NULL; -#if defined(__GNUC__) && defined (i386) && defined (MINT_USE_DEDICATED_IP_REG) - register const unsigned short *ip asm ("%esi"); -#else - register const unsigned short *ip; -#endif - register stackval *sp; - RuntimeMethod *rtm; -#if DEBUG_INTERP - gint tracing = global_tracing; - unsigned char *vtalloc; -#endif - int i32; - unsigned char *vt_sp; - unsigned char *locals; - MonoError error; - MonoObject *o = NULL; - MonoClass *c; -#if USE_COMPUTED_GOTO - static void *in_labels[] = { -#define OPDEF(a,b,c,d) \ - &&LAB_ ## a, -#include "mintops.def" - 0 }; -#endif - - frame->ex = NULL; - frame->ex_handler = NULL; - frame->ip = NULL; - context->current_frame = frame; - -#if DEBUG_INTERP - debug_enter (frame, &tracing); -#endif - - if (!frame->runtime_method->transformed) { - context->managed_code = 0; -#if DEBUG_INTERP - char *mn = mono_method_full_name (frame->runtime_method->method, FALSE); - g_print ("(%p) Transforming %s\n", mono_thread_internal_current (), mn); - g_free (mn); -#endif - frame->ex = mono_interp_transform_method (frame->runtime_method, context); - context->managed_code = 1; - if (frame->ex) { - rtm = NULL; - ip = NULL; - goto exit_frame; - } - } - - rtm = frame->runtime_method; - frame->args = alloca (rtm->alloca_size); - sp = frame->stack = (stackval *)((char *)frame->args + rtm->args_size); -#if DEBUG_INTERP - if (tracing > 1) - memset(sp, 0, rtm->stack_size); -#endif - vt_sp = (unsigned char *) sp + rtm->stack_size; -#if DEBUG_INTERP - vtalloc = vt_sp; -#endif - locals = (unsigned char *) vt_sp + rtm->vt_stack_size; - - child_frame.parent = frame; - - /* ready to go */ - ip = rtm->code; - - /* - * using while (ip < end) may result in a 15% performance drop, - * but it may be useful for debug - */ - while (1) { - main_loop: - /* g_assert (sp >= frame->stack); */ - /* g_assert(vt_sp - vtalloc <= rtm->vt_stack_size); */ - DUMP_INSTR(); - MINT_IN_SWITCH (*ip) { - MINT_IN_CASE(MINT_INITLOCALS) - memset (locals, 0, rtm->locals_size); - ++ip; - MINT_IN_BREAK; - MINT_IN_CASE(MINT_NOP) - ++ip; - MINT_IN_BREAK; - MINT_IN_CASE(MINT_BREAK) - ++ip; - G_BREAKPOINT (); /* this is not portable... */ - MINT_IN_BREAK; - MINT_IN_CASE(MINT_LDNULL) - sp->data.p = NULL; - ++ip; - ++sp; - MINT_IN_BREAK; - MINT_IN_CASE(MINT_VTRESULT) { - int ret_size = * (guint16 *)(ip + 1); - unsigned char *ret_vt_sp = vt_sp; - vt_sp -= READ32(ip + 2); - if (ret_size > 0) { - memmove (vt_sp, ret_vt_sp, ret_size); - sp [-1].data.p = vt_sp; - vt_sp += (ret_size + 7) & ~7; - } - ip += 4; - MINT_IN_BREAK; - } -#define LDC(n) do { sp->data.i = (n); ++ip; ++sp; } while (0) - MINT_IN_CASE(MINT_LDC_I4_M1) - LDC(-1); - MINT_IN_BREAK; - MINT_IN_CASE(MINT_LDC_I4_0) - LDC(0); - MINT_IN_BREAK; - MINT_IN_CASE(MINT_LDC_I4_1) - LDC(1); - MINT_IN_BREAK; - MINT_IN_CASE(MINT_LDC_I4_2) - LDC(2); - MINT_IN_BREAK; - MINT_IN_CASE(MINT_LDC_I4_3) - LDC(3); - MINT_IN_BREAK; - MINT_IN_CASE(MINT_LDC_I4_4) - LDC(4); - MINT_IN_BREAK; - MINT_IN_CASE(MINT_LDC_I4_5) - LDC(5); - MINT_IN_BREAK; - MINT_IN_CASE(MINT_LDC_I4_6) - LDC(6); - MINT_IN_BREAK; - MINT_IN_CASE(MINT_LDC_I4_7) - LDC(7); - MINT_IN_BREAK; - MINT_IN_CASE(MINT_LDC_I4_8) - LDC(8); - MINT_IN_BREAK; - MINT_IN_CASE(MINT_LDC_I4_S) - sp->data.i = *(const short *)(ip + 1); - ip += 2; - ++sp; - MINT_IN_BREAK; - MINT_IN_CASE(MINT_LDC_I4) - ++ip; - sp->data.i = READ32 (ip); - ip += 2; - ++sp; - MINT_IN_BREAK; - MINT_IN_CASE(MINT_LDC_I8) - ++ip; - sp->data.l = READ64 (ip); - ip += 4; - ++sp; - MINT_IN_BREAK; - MINT_IN_CASE(MINT_LDC_R4) { - guint32 val; - ++ip; - val = READ32(ip); - sp->data.f = * (float *)&val; - ip += 2; - ++sp; - MINT_IN_BREAK; - } - MINT_IN_CASE(MINT_LDC_R8) - sp->data.l = READ64 (ip + 1); /* note union usage */ - ip += 5; - ++sp; - MINT_IN_BREAK; - MINT_IN_CASE(MINT_DUP) - sp [0] = sp[-1]; - ++sp; - ++ip; - MINT_IN_BREAK; - MINT_IN_CASE(MINT_DUP_VT) - i32 = READ32 (ip + 1); - sp->data.p = vt_sp; - memcpy(sp->data.p, sp [-1].data.p, i32); - vt_sp += (i32 + 7) & ~7; - ++sp; - ip += 3; - MINT_IN_BREAK; - MINT_IN_CASE(MINT_POP) { - guint16 u16 = (* (guint16 *)(ip + 1)) + 1; - if (u16 > 1) - memmove (sp - u16, sp - 1, (u16 - 1) * sizeof (stackval)); - sp--; - ip += 2; - MINT_IN_BREAK; - } - MINT_IN_CASE(MINT_JMP) { - RuntimeMethod *new_method = rtm->data_items [* (guint16 *)(ip + 1)]; - if (!new_method->transformed) { - frame->ip = ip; - frame->ex = mono_interp_transform_method (new_method, context); - if (frame->ex) - goto exit_frame; - } - ip += 2; - if (new_method->alloca_size > rtm->alloca_size) - g_error ("MINT_JMP to method which needs more stack space (%d > %d)", new_method->alloca_size, rtm->alloca_size); - rtm = frame->runtime_method = new_method; - vt_sp = (unsigned char *) sp + rtm->stack_size; -#if DEBUG_INTERP - vtalloc = vt_sp; -#endif - locals = vt_sp + rtm->vt_stack_size; - ip = rtm->new_body_start; /* bypass storing input args from callers frame */ - MINT_IN_BREAK; - } - MINT_IN_CASE(MINT_CALLI) { - MonoMethodSignature *csignature; - stackval *endsp = sp; - - frame->ip = ip; - - csignature = rtm->data_items [* (guint16 *)(ip + 1)]; - ip += 2; - --sp; - --endsp; - child_frame.runtime_method = sp->data.p; - - sp->data.p = vt_sp; - child_frame.retval = sp; - /* decrement by the actual number of args */ - sp -= csignature->param_count; - if (csignature->hasthis) - --sp; - child_frame.stack_args = sp; - - /* `this' can be NULL for string:.ctor */ - if (csignature->hasthis && sp->data.p && mono_object_is_transparent_proxy (sp->data.p)) { - child_frame.runtime_method = mono_interp_get_runtime_method (context->domain, mono_marshal_get_remoting_invoke (child_frame.runtime_method->method), &error); - mono_error_cleanup (&error); /* FIXME: don't swallow the error */ - } else if (child_frame.runtime_method->method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) { - child_frame.runtime_method = mono_interp_get_runtime_method (context->domain, mono_marshal_get_native_wrapper (child_frame.runtime_method->method, FALSE, FALSE), &error); - mono_error_cleanup (&error); /* FIXME: don't swallow the error */ - } - - if (csignature->hasthis) { - MonoObject *this_arg = sp->data.p; - - if (this_arg->vtable->klass->valuetype) { - gpointer *unboxed = mono_object_unbox (this_arg); - sp [0].data.p = unboxed; - } - } - - ves_exec_method_with_context (&child_frame, context); - - context->current_frame = frame; - - if (child_frame.ex) { - /* - * An exception occurred, need to run finally, fault and catch handlers.. - */ - frame->ex = child_frame.ex; - goto handle_finally; - } - - /* need to handle typedbyref ... */ - if (csignature->ret->type != MONO_TYPE_VOID) { - *sp = *endsp; - sp++; - } - MINT_IN_BREAK; - } - MINT_IN_CASE(MINT_CALLI_NAT) { - MonoMethodSignature *csignature; - stackval *endsp = sp; - unsigned char *code = NULL; - - frame->ip = ip; - - csignature = rtm->data_items [* (guint16 *)(ip + 1)]; - ip += 2; - --sp; - --endsp; - code = sp->data.p; - child_frame.runtime_method = NULL; - - sp->data.p = vt_sp; - child_frame.retval = sp; - /* decrement by the actual number of args */ - sp -= csignature->param_count; - if (csignature->hasthis) - --sp; - child_frame.stack_args = sp; - ves_pinvoke_method (&child_frame, csignature, (MonoFuncV) code, FALSE, context); - - context->current_frame = frame; - - if (child_frame.ex) { - /* - * An exception occurred, need to run finally, fault and catch handlers.. - */ - frame->ex = child_frame.ex; - if (context->search_for_handler) { - context->search_for_handler = 0; - goto handle_exception; - } - goto handle_finally; - } - - /* need to handle typedbyref ... */ - if (csignature->ret->type != MONO_TYPE_VOID) { - *sp = *endsp; - sp++; - } - MINT_IN_BREAK; - } - MINT_IN_CASE(MINT_CALL) { - stackval *endsp = sp; - - frame->ip = ip; - - child_frame.runtime_method = rtm->data_items [* (guint16 *)(ip + 1)]; - ip += 2; - sp->data.p = vt_sp; - child_frame.retval = sp; - /* decrement by the actual number of args */ - sp -= child_frame.runtime_method->param_count; - if (child_frame.runtime_method->hasthis) - --sp; - child_frame.stack_args = sp; - - /* `this' can be NULL for string:.ctor */ - if (child_frame.runtime_method->hasthis && !child_frame.runtime_method->method->klass->valuetype && sp->data.p && mono_object_is_transparent_proxy (sp->data.p)) { - child_frame.runtime_method = mono_interp_get_runtime_method (context->domain, mono_marshal_get_remoting_invoke (child_frame.runtime_method->method), &error); - mono_error_cleanup (&error); /* FIXME: don't swallow the error */ - } - ves_exec_method_with_context (&child_frame, context); - - context->current_frame = frame; - - if (child_frame.ex) { - /* - * An exception occurred, need to run finally, fault and catch handlers.. - */ - frame->ex = child_frame.ex; - goto handle_finally; - } - - /* need to handle typedbyref ... */ - *sp = *endsp; - sp++; - MINT_IN_BREAK; - } - MINT_IN_CASE(MINT_VCALL) { - frame->ip = ip; - - child_frame.runtime_method = rtm->data_items [* (guint16 *)(ip + 1)]; - ip += 2; - - sp->data.p = vt_sp; - child_frame.retval = sp; - /* decrement by the actual number of args */ - sp -= child_frame.runtime_method->param_count; - if (child_frame.runtime_method->hasthis) - --sp; - child_frame.stack_args = sp; - - if (child_frame.runtime_method->hasthis && !child_frame.runtime_method->method->klass->valuetype && mono_object_is_transparent_proxy (sp->data.p)) { - child_frame.runtime_method = mono_interp_get_runtime_method (context->domain, mono_marshal_get_remoting_invoke (child_frame.runtime_method->method), &error); - mono_error_cleanup (&error); /* FIXME: don't swallow the error */ - } - - ves_exec_method_with_context (&child_frame, context); - - context->current_frame = frame; - - if (child_frame.ex) { - /* - * An exception occurred, need to run finally, fault and catch handlers.. - */ - frame->ex = child_frame.ex; - goto handle_finally; - } - MINT_IN_BREAK; - } - MINT_IN_CASE(MINT_CALLVIRT) { - stackval *endsp = sp; - MonoObject *this_arg; - guint32 token; - - frame->ip = ip; - - token = * (unsigned short *)(ip + 1); - ip += 2; - child_frame.runtime_method = rtm->data_items [token]; - sp->data.p = vt_sp; - child_frame.retval = sp; - - /* decrement by the actual number of args */ - sp -= child_frame.runtime_method->param_count + 1; - child_frame.stack_args = sp; - this_arg = sp->data.p; - if (!this_arg) - THROW_EX (mono_get_exception_null_reference(), ip - 2); - child_frame.runtime_method = get_virtual_method (context->domain, child_frame.runtime_method, this_arg); - - MonoClass *this_class = this_arg->vtable->klass; - if (this_class->valuetype && child_frame.runtime_method->method->klass->valuetype) { - /* unbox */ - gpointer *unboxed = mono_object_unbox (this_arg); - sp [0].data.p = unboxed; - } - - ves_exec_method_with_context (&child_frame, context); - - context->current_frame = frame; - - if (child_frame.ex) { - /* - * An exception occurred, need to run finally, fault and catch handlers.. - */ - frame->ex = child_frame.ex; - if (context->search_for_handler) { - context->search_for_handler = 0; - goto handle_exception; - } - goto handle_finally; - } - - /* need to handle typedbyref ... */ - *sp = *endsp; - sp++; - MINT_IN_BREAK; - } - MINT_IN_CASE(MINT_VCALLVIRT) { - MonoObject *this_arg; - guint32 token; - - frame->ip = ip; - - token = * (unsigned short *)(ip + 1); - ip += 2; - child_frame.runtime_method = rtm->data_items [token]; - sp->data.p = vt_sp; - child_frame.retval = sp; - - /* decrement by the actual number of args */ - sp -= child_frame.runtime_method->param_count + 1; - child_frame.stack_args = sp; - this_arg = sp->data.p; - if (!this_arg) - THROW_EX (mono_get_exception_null_reference(), ip - 2); - child_frame.runtime_method = get_virtual_method (context->domain, child_frame.runtime_method, this_arg); - - MonoClass *this_class = this_arg->vtable->klass; - if (this_class->valuetype && child_frame.runtime_method->method->klass->valuetype) { - gpointer *unboxed = mono_object_unbox (this_arg); - sp [0].data.p = unboxed; - } - - ves_exec_method_with_context (&child_frame, context); - - context->current_frame = frame; - - if (child_frame.ex) { - /* - * An exception occurred, need to run finally, fault and catch handlers.. - */ - frame->ex = child_frame.ex; - if (context->search_for_handler) { - context->search_for_handler = 0; - goto handle_exception; - } - goto handle_finally; - } - MINT_IN_BREAK; - } - MINT_IN_CASE(MINT_CALLRUN) - ves_runtime_method (frame, context); - if (frame->ex) { - rtm = NULL; - goto handle_exception; - } - goto exit_frame; - MINT_IN_CASE(MINT_RET) - --sp; - *frame->retval = *sp; - if (sp > frame->stack) - g_warning ("ret: more values on stack: %d", sp-frame->stack); - goto exit_frame; - MINT_IN_CASE(MINT_RET_VOID) - if (sp > frame->stack) - g_warning ("ret.void: more values on stack: %d", sp-frame->stack); - goto exit_frame; - MINT_IN_CASE(MINT_RET_VT) - i32 = READ32(ip + 1); - --sp; - memcpy(frame->retval->data.p, sp->data.p, i32); - if (sp > frame->stack) - g_warning ("ret.vt: more values on stack: %d", sp-frame->stack); - goto exit_frame; - MINT_IN_CASE(MINT_BR_S) - ip += (short) *(ip + 1); - MINT_IN_BREAK; - MINT_IN_CASE(MINT_BR) - ip += (gint32) READ32(ip + 1); - MINT_IN_BREAK; -#define ZEROP_S(datamem, op) \ - --sp; \ - if (sp->data.datamem op 0) \ - ip += * (gint16 *)(ip + 1); \ - else \ - ip += 2; - -#define ZEROP(datamem, op) \ - --sp; \ - if (sp->data.datamem op 0) \ - ip += READ32(ip + 1); \ - else \ - ip += 3; - - MINT_IN_CASE(MINT_BRFALSE_I4_S) - ZEROP_S(i, ==); - MINT_IN_BREAK; - MINT_IN_CASE(MINT_BRFALSE_I8_S) - ZEROP_S(l, ==); - MINT_IN_BREAK; - MINT_IN_CASE(MINT_BRFALSE_R8_S) - ZEROP_S(f, ==); - MINT_IN_BREAK; - MINT_IN_CASE(MINT_BRFALSE_I4) - ZEROP(i, ==); - MINT_IN_BREAK; - MINT_IN_CASE(MINT_BRFALSE_I8) - ZEROP(l, ==); - MINT_IN_BREAK; - MINT_IN_CASE(MINT_BRFALSE_R8) - ZEROP_S(f, ==); - MINT_IN_BREAK; - MINT_IN_CASE(MINT_BRTRUE_I4_S) - ZEROP_S(i, !=); - MINT_IN_BREAK; - MINT_IN_CASE(MINT_BRTRUE_I8_S) - ZEROP_S(l, !=); - MINT_IN_BREAK; - MINT_IN_CASE(MINT_BRTRUE_R8_S) - ZEROP_S(f, !=); - MINT_IN_BREAK; - MINT_IN_CASE(MINT_BRTRUE_I4) - ZEROP(i, !=); - MINT_IN_BREAK; - MINT_IN_CASE(MINT_BRTRUE_I8) - ZEROP(l, !=); - MINT_IN_BREAK; - MINT_IN_CASE(MINT_BRTRUE_R8) - ZEROP(f, !=); - MINT_IN_BREAK; -#define CONDBR_S(cond) \ - sp -= 2; \ - if (cond) \ - ip += * (gint16 *)(ip + 1); \ - else \ - ip += 2; -#define BRELOP_S(datamem, op) \ - CONDBR_S(sp[0].data.datamem op sp[1].data.datamem) - -#define CONDBR(cond) \ - sp -= 2; \ - if (cond) \ - ip += READ32(ip + 1); \ - else \ - ip += 3; - -#define BRELOP(datamem, op) \ - CONDBR(sp[0].data.datamem op sp[1].data.datamem) - - MINT_IN_CASE(MINT_BEQ_I4_S) - BRELOP_S(i, ==) - MINT_IN_BREAK; - MINT_IN_CASE(MINT_BEQ_I8_S) - BRELOP_S(l, ==) - MINT_IN_BREAK; - MINT_IN_CASE(MINT_BEQ_R8_S) - CONDBR_S(!isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f == sp[1].data.f) - MINT_IN_BREAK; - MINT_IN_CASE(MINT_BEQ_I4) - BRELOP(i, ==) - MINT_IN_BREAK; - MINT_IN_CASE(MINT_BEQ_I8) - BRELOP(l, ==) - MINT_IN_BREAK; - MINT_IN_CASE(MINT_BEQ_R8) - CONDBR(!isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f == sp[1].data.f) - MINT_IN_BREAK; - MINT_IN_CASE(MINT_BGE_I4_S) - BRELOP_S(i, >=) - MINT_IN_BREAK; - MINT_IN_CASE(MINT_BGE_I8_S) - BRELOP_S(l, >=) - MINT_IN_BREAK; - MINT_IN_CASE(MINT_BGE_R8_S) - CONDBR_S(!isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f >= sp[1].data.f) - MINT_IN_BREAK; - MINT_IN_CASE(MINT_BGE_I4) - BRELOP(i, >=) - MINT_IN_BREAK; - MINT_IN_CASE(MINT_BGE_I8) - BRELOP(l, >=) - MINT_IN_BREAK; - MINT_IN_CASE(MINT_BGE_R8) - CONDBR(!isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f >= sp[1].data.f) - MINT_IN_BREAK; - MINT_IN_CASE(MINT_BGT_I4_S) - BRELOP_S(i, >) - MINT_IN_BREAK; - MINT_IN_CASE(MINT_BGT_I8_S) - BRELOP_S(l, >) - MINT_IN_BREAK; - MINT_IN_CASE(MINT_BGT_R8_S) - CONDBR_S(!isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f > sp[1].data.f) - MINT_IN_BREAK; - MINT_IN_CASE(MINT_BGT_I4) - BRELOP(i, >) - MINT_IN_BREAK; - MINT_IN_CASE(MINT_BGT_I8) - BRELOP(l, >) - MINT_IN_BREAK; - MINT_IN_CASE(MINT_BGT_R8) - CONDBR(!isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f > sp[1].data.f) - MINT_IN_BREAK; - MINT_IN_CASE(MINT_BLT_I4_S) - BRELOP_S(i, <) - MINT_IN_BREAK; - MINT_IN_CASE(MINT_BLT_I8_S) - BRELOP_S(l, <) - MINT_IN_BREAK; - MINT_IN_CASE(MINT_BLT_R8_S) - CONDBR_S(!isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f < sp[1].data.f) - MINT_IN_BREAK; - MINT_IN_CASE(MINT_BLT_I4) - BRELOP(i, <) - MINT_IN_BREAK; - MINT_IN_CASE(MINT_BLT_I8) - BRELOP(l, <) - MINT_IN_BREAK; - MINT_IN_CASE(MINT_BLT_R8) - CONDBR(!isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f < sp[1].data.f) - MINT_IN_BREAK; - MINT_IN_CASE(MINT_BLE_I4_S) - BRELOP_S(i, <=) - MINT_IN_BREAK; - MINT_IN_CASE(MINT_BLE_I8_S) - BRELOP_S(l, <=) - MINT_IN_BREAK; - MINT_IN_CASE(MINT_BLE_R8_S) - CONDBR_S(!isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f <= sp[1].data.f) - MINT_IN_BREAK; - MINT_IN_CASE(MINT_BLE_I4) - BRELOP(i, <=) - MINT_IN_BREAK; - MINT_IN_CASE(MINT_BLE_I8) - BRELOP(l, <=) - MINT_IN_BREAK; - MINT_IN_CASE(MINT_BLE_R8) - CONDBR(!isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f <= sp[1].data.f) - MINT_IN_BREAK; - MINT_IN_CASE(MINT_BNE_UN_I4_S) - BRELOP_S(i, !=) - MINT_IN_BREAK; - MINT_IN_CASE(MINT_BNE_UN_I8_S) - BRELOP_S(l, !=) - MINT_IN_BREAK; - MINT_IN_CASE(MINT_BNE_UN_R8_S) - CONDBR_S(isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f != sp[1].data.f) - MINT_IN_BREAK; - MINT_IN_CASE(MINT_BNE_UN_I4) - BRELOP(i, !=) - MINT_IN_BREAK; - MINT_IN_CASE(MINT_BNE_UN_I8) - BRELOP(l, !=) - MINT_IN_BREAK; - MINT_IN_CASE(MINT_BNE_UN_R8) - CONDBR(isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f != sp[1].data.f) - MINT_IN_BREAK; - -#define BRELOP_S_CAST(datamem, op, type) \ - sp -= 2; \ - if ((type) sp[0].data.datamem op (type) sp[1].data.datamem) \ - ip += * (gint16 *)(ip + 1); \ - else \ - ip += 2; - -#define BRELOP_CAST(datamem, op, type) \ - sp -= 2; \ - if ((type) sp[0].data.datamem op (type) sp[1].data.datamem) \ - ip += READ32(ip + 1); \ - else \ - ip += 3; - - MINT_IN_CASE(MINT_BGE_UN_I4_S) - BRELOP_S_CAST(i, >=, guint32); - MINT_IN_BREAK; - MINT_IN_CASE(MINT_BGE_UN_I8_S) - BRELOP_S_CAST(l, >=, guint64); - MINT_IN_BREAK; - MINT_IN_CASE(MINT_BGE_UN_R8_S) - CONDBR_S(isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f >= sp[1].data.f) - MINT_IN_BREAK; - MINT_IN_CASE(MINT_BGE_UN_I4) - BRELOP_CAST(i, >=, guint32); - MINT_IN_BREAK; - MINT_IN_CASE(MINT_BGE_UN_I8) - BRELOP_CAST(l, >=, guint64); - MINT_IN_BREAK; - MINT_IN_CASE(MINT_BGE_UN_R8) - CONDBR(isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f >= sp[1].data.f) - MINT_IN_BREAK; - MINT_IN_CASE(MINT_BGT_UN_I4_S) - BRELOP_S_CAST(i, >, guint32); - MINT_IN_BREAK; - MINT_IN_CASE(MINT_BGT_UN_I8_S) - BRELOP_S_CAST(l, >, guint64); - MINT_IN_BREAK; - MINT_IN_CASE(MINT_BGT_UN_R8_S) - CONDBR_S(isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f > sp[1].data.f) - MINT_IN_BREAK; - MINT_IN_CASE(MINT_BGT_UN_I4) - BRELOP_CAST(i, >, guint32); - MINT_IN_BREAK; - MINT_IN_CASE(MINT_BGT_UN_I8) - BRELOP_CAST(l, >, guint64); - MINT_IN_BREAK; - MINT_IN_CASE(MINT_BGT_UN_R8) - CONDBR(isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f > sp[1].data.f) - MINT_IN_BREAK; - MINT_IN_CASE(MINT_BLE_UN_I4_S) - BRELOP_S_CAST(i, <=, guint32); - MINT_IN_BREAK; - MINT_IN_CASE(MINT_BLE_UN_I8_S) - BRELOP_S_CAST(l, <=, guint64); - MINT_IN_BREAK; - MINT_IN_CASE(MINT_BLE_UN_R8_S) - CONDBR_S(isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f <= sp[1].data.f) - MINT_IN_BREAK; - MINT_IN_CASE(MINT_BLE_UN_I4) - BRELOP_CAST(i, <=, guint32); - MINT_IN_BREAK; - MINT_IN_CASE(MINT_BLE_UN_I8) - BRELOP_CAST(l, <=, guint64); - MINT_IN_BREAK; - MINT_IN_CASE(MINT_BLE_UN_R8) - CONDBR(isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f <= sp[1].data.f) - MINT_IN_BREAK; - MINT_IN_CASE(MINT_BLT_UN_I4_S) - BRELOP_S_CAST(i, <, guint32); - MINT_IN_BREAK; - MINT_IN_CASE(MINT_BLT_UN_I8_S) - BRELOP_S_CAST(l, <, guint64); - MINT_IN_BREAK; - MINT_IN_CASE(MINT_BLT_UN_R8_S) - CONDBR_S(isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f < sp[1].data.f) - MINT_IN_BREAK; - MINT_IN_CASE(MINT_BLT_UN_I4) - BRELOP_CAST(i, <, guint32); - MINT_IN_BREAK; - MINT_IN_CASE(MINT_BLT_UN_I8) - BRELOP_CAST(l, <, guint64); - MINT_IN_BREAK; - MINT_IN_CASE(MINT_BLT_UN_R8) - CONDBR(isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f < sp[1].data.f) - MINT_IN_BREAK; - MINT_IN_CASE(MINT_SWITCH) { - guint32 n; - const unsigned short *st; - ++ip; - n = READ32 (ip); - ip += 2; - st = ip + 2 * n; - --sp; - if ((guint32)sp->data.i < n) { - gint offset; - ip += 2 * (guint32)sp->data.i; - offset = READ32 (ip); - ip = st + offset; - } else { - ip = st; - } - MINT_IN_BREAK; - } - MINT_IN_CASE(MINT_LDIND_I1) - ++ip; - sp[-1].data.i = *(gint8*)sp[-1].data.p; - MINT_IN_BREAK; - MINT_IN_CASE(MINT_LDIND_U1) - ++ip; - sp[-1].data.i = *(guint8*)sp[-1].data.p; - MINT_IN_BREAK; - MINT_IN_CASE(MINT_LDIND_I2) - ++ip; - sp[-1].data.i = *(gint16*)sp[-1].data.p; - MINT_IN_BREAK; - MINT_IN_CASE(MINT_LDIND_U2) - ++ip; - sp[-1].data.i = *(guint16*)sp[-1].data.p; - MINT_IN_BREAK; - MINT_IN_CASE(MINT_LDIND_I4) /* Fall through */ - MINT_IN_CASE(MINT_LDIND_U4) - ++ip; - sp[-1].data.i = *(gint32*)sp[-1].data.p; - MINT_IN_BREAK; - MINT_IN_CASE(MINT_LDIND_I8) - ++ip; - sp[-1].data.l = *(gint64*)sp[-1].data.p; - MINT_IN_BREAK; - MINT_IN_CASE(MINT_LDIND_I) { - guint16 offset = * (guint16 *)(ip + 1); - sp[-1 - offset].data.p = *(gpointer*)sp[-1 - offset].data.p; - ip += 2; - MINT_IN_BREAK; - } - MINT_IN_CASE(MINT_LDIND_R4) - ++ip; - sp[-1].data.f = *(gfloat*)sp[-1].data.p; - MINT_IN_BREAK; - MINT_IN_CASE(MINT_LDIND_R8) - ++ip; - sp[-1].data.f = *(gdouble*)sp[-1].data.p; - MINT_IN_BREAK; - MINT_IN_CASE(MINT_LDIND_REF) - ++ip; - sp[-1].data.p = *(gpointer*)sp[-1].data.p; - MINT_IN_BREAK; - MINT_IN_CASE(MINT_STIND_REF) - ++ip; - sp -= 2; - * (gpointer *) sp->data.p = sp[1].data.p; - MINT_IN_BREAK; - MINT_IN_CASE(MINT_STIND_I1) - ++ip; - sp -= 2; - * (gint8 *) sp->data.p = (gint8)sp[1].data.i; - MINT_IN_BREAK; - MINT_IN_CASE(MINT_STIND_I2) - ++ip; - sp -= 2; - * (gint16 *) sp->data.p = (gint16)sp[1].data.i; - MINT_IN_BREAK; - MINT_IN_CASE(MINT_STIND_I4) - ++ip; - sp -= 2; - * (gint32 *) sp->data.p = sp[1].data.i; - MINT_IN_BREAK; - MINT_IN_CASE(MINT_STIND_I) - ++ip; - sp -= 2; - * (mono_i *) sp->data.p = (mono_i)sp[1].data.p; - MINT_IN_BREAK; - MINT_IN_CASE(MINT_STIND_I8) - ++ip; - sp -= 2; - * (gint64 *) sp->data.p = sp[1].data.l; - MINT_IN_BREAK; - MINT_IN_CASE(MINT_STIND_R4) - ++ip; - sp -= 2; - * (float *) sp->data.p = (gfloat)sp[1].data.f; - MINT_IN_BREAK; - MINT_IN_CASE(MINT_STIND_R8) - ++ip; - sp -= 2; - * (double *) sp->data.p = sp[1].data.f; - MINT_IN_BREAK; -#define BINOP(datamem, op) \ - --sp; \ - sp [-1].data.datamem = sp [-1].data.datamem op sp [0].data.datamem; \ - ++ip; - MINT_IN_CASE(MINT_ADD_I4) - BINOP(i, +); - MINT_IN_BREAK; - MINT_IN_CASE(MINT_ADD_I8) - BINOP(l, +); - MINT_IN_BREAK; - MINT_IN_CASE(MINT_ADD_R8) - BINOP(f, +); - MINT_IN_BREAK; - MINT_IN_CASE(MINT_ADD1_I4) - ++sp [-1].data.i; - ++ip; - MINT_IN_BREAK; - MINT_IN_CASE(MINT_SUB_I4) - BINOP(i, -); - MINT_IN_BREAK; - MINT_IN_CASE(MINT_SUB_I8) - BINOP(l, -); - MINT_IN_BREAK; - MINT_IN_CASE(MINT_SUB_R8) - BINOP(f, -); - MINT_IN_BREAK; - MINT_IN_CASE(MINT_SUB1_I4) - --sp [-1].data.i; - ++ip; - MINT_IN_BREAK; - MINT_IN_CASE(MINT_MUL_I4) - BINOP(i, *); - MINT_IN_BREAK; - MINT_IN_CASE(MINT_MUL_I8) - BINOP(l, *); - MINT_IN_BREAK; - MINT_IN_CASE(MINT_MUL_R8) - BINOP(f, *); - MINT_IN_BREAK; - MINT_IN_CASE(MINT_DIV_I4) - if (sp [-1].data.i == 0) - THROW_EX (mono_get_exception_divide_by_zero (), ip); - if (sp [-1].data.i == (-1)) - THROW_EX (mono_get_exception_overflow (), ip); - BINOP(i, /); - MINT_IN_BREAK; - MINT_IN_CASE(MINT_DIV_I8) - if (sp [-1].data.l == 0) - THROW_EX (mono_get_exception_divide_by_zero (), ip); - if (sp [-1].data.l == (-1)) - THROW_EX (mono_get_exception_overflow (), ip); - BINOP(l, /); - MINT_IN_BREAK; - MINT_IN_CASE(MINT_DIV_R8) - BINOP(f, /); - MINT_IN_BREAK; - -#define BINOP_CAST(datamem, op, type) \ - --sp; \ - sp [-1].data.datamem = (type)sp [-1].data.datamem op (type)sp [0].data.datamem; \ - ++ip; - MINT_IN_CASE(MINT_DIV_UN_I4) - if (sp [-1].data.i == 0) - THROW_EX (mono_get_exception_divide_by_zero (), ip); - BINOP_CAST(i, /, guint32); - MINT_IN_BREAK; - MINT_IN_CASE(MINT_DIV_UN_I8) - if (sp [-1].data.l == 0) - THROW_EX (mono_get_exception_divide_by_zero (), ip); - BINOP_CAST(l, /, guint64); - MINT_IN_BREAK; - MINT_IN_CASE(MINT_REM_I4) - if (sp [-1].data.i == 0) - THROW_EX (mono_get_exception_divide_by_zero (), ip); - BINOP(i, %); - MINT_IN_BREAK; - MINT_IN_CASE(MINT_REM_I8) - if (sp [-1].data.l == 0) - THROW_EX (mono_get_exception_divide_by_zero (), ip); - BINOP(l, %); - MINT_IN_BREAK; - MINT_IN_CASE(MINT_REM_R8) - /* FIXME: what do we actually do here? */ - --sp; - sp [-1].data.f = fmod (sp [-1].data.f, sp [0].data.f); - ++ip; - MINT_IN_BREAK; - MINT_IN_CASE(MINT_REM_UN_I4) - if (sp [-1].data.i == 0) - THROW_EX (mono_get_exception_divide_by_zero (), ip); - BINOP_CAST(i, %, guint32); - MINT_IN_BREAK; - MINT_IN_CASE(MINT_REM_UN_I8) - if (sp [-1].data.l == 0) - THROW_EX (mono_get_exception_divide_by_zero (), ip); - BINOP_CAST(l, %, guint64); - MINT_IN_BREAK; - MINT_IN_CASE(MINT_AND_I4) - BINOP(i, &); - MINT_IN_BREAK; - MINT_IN_CASE(MINT_AND_I8) - BINOP(l, &); - MINT_IN_BREAK; - MINT_IN_CASE(MINT_OR_I4) - BINOP(i, |); - MINT_IN_BREAK; - MINT_IN_CASE(MINT_OR_I8) - BINOP(l, |); - MINT_IN_BREAK; - MINT_IN_CASE(MINT_XOR_I4) - BINOP(i, ^); - MINT_IN_BREAK; - MINT_IN_CASE(MINT_XOR_I8) - BINOP(l, ^); - MINT_IN_BREAK; - -#define SHIFTOP(datamem, op) \ - --sp; \ - sp [-1].data.datamem = sp [-1].data.datamem op sp [0].data.i; \ - ++ip; - - MINT_IN_CASE(MINT_SHL_I4) - SHIFTOP(i, <<); - MINT_IN_BREAK; - MINT_IN_CASE(MINT_SHL_I8) - SHIFTOP(l, <<); - MINT_IN_BREAK; - MINT_IN_CASE(MINT_SHR_I4) - SHIFTOP(i, >>); - MINT_IN_BREAK; - MINT_IN_CASE(MINT_SHR_I8) - SHIFTOP(l, >>); - MINT_IN_BREAK; - MINT_IN_CASE(MINT_SHR_UN_I4) - --sp; - sp [-1].data.i = (guint32)sp [-1].data.i >> sp [0].data.i; - ++ip; - MINT_IN_BREAK; - MINT_IN_CASE(MINT_SHR_UN_I8) - --sp; - sp [-1].data.l = (guint64)sp [-1].data.l >> sp [0].data.i; - ++ip; - MINT_IN_BREAK; - MINT_IN_CASE(MINT_NEG_I4) - sp [-1].data.i = - sp [-1].data.i; - ++ip; - MINT_IN_BREAK; - MINT_IN_CASE(MINT_NEG_I8) - sp [-1].data.l = - sp [-1].data.l; - ++ip; - MINT_IN_BREAK; - MINT_IN_CASE(MINT_NEG_R8) - sp [-1].data.f = - sp [-1].data.f; - ++ip; - MINT_IN_BREAK; - MINT_IN_CASE(MINT_NOT_I4) - sp [-1].data.i = ~ sp [-1].data.i; - ++ip; - MINT_IN_BREAK; - MINT_IN_CASE(MINT_NOT_I8) - sp [-1].data.l = ~ sp [-1].data.l; - ++ip; - MINT_IN_BREAK; - MINT_IN_CASE(MINT_CONV_I1_I4) - sp [-1].data.i = (gint8)sp [-1].data.i; - ++ip; - MINT_IN_BREAK; - MINT_IN_CASE(MINT_CONV_I1_I8) - sp [-1].data.i = (gint8)sp [-1].data.l; - ++ip; - MINT_IN_BREAK; - MINT_IN_CASE(MINT_CONV_I1_R8) - sp [-1].data.i = (gint8)sp [-1].data.f; - ++ip; - MINT_IN_BREAK; - MINT_IN_CASE(MINT_CONV_U1_I4) - sp [-1].data.i = (guint8)sp [-1].data.i; - ++ip; - MINT_IN_BREAK; - MINT_IN_CASE(MINT_CONV_U1_I8) - sp [-1].data.i = (guint8)sp [-1].data.l; - ++ip; - MINT_IN_BREAK; - MINT_IN_CASE(MINT_CONV_U1_R8) - sp [-1].data.i = (guint8)sp [-1].data.f; - ++ip; - MINT_IN_BREAK; - MINT_IN_CASE(MINT_CONV_I2_I4) - sp [-1].data.i = (gint16)sp [-1].data.i; - ++ip; - MINT_IN_BREAK; - MINT_IN_CASE(MINT_CONV_I2_I8) - sp [-1].data.i = (gint16)sp [-1].data.l; - ++ip; - MINT_IN_BREAK; - MINT_IN_CASE(MINT_CONV_I2_R8) - sp [-1].data.i = (gint16)sp [-1].data.f; - ++ip; - MINT_IN_BREAK; - MINT_IN_CASE(MINT_CONV_U2_I4) - sp [-1].data.i = (guint16)sp [-1].data.i; - ++ip; - MINT_IN_BREAK; - MINT_IN_CASE(MINT_CONV_U2_I8) - sp [-1].data.i = (guint16)sp [-1].data.l; - ++ip; - MINT_IN_BREAK; - MINT_IN_CASE(MINT_CONV_U2_R8) - sp [-1].data.i = (guint16)sp [-1].data.f; - ++ip; - MINT_IN_BREAK; - MINT_IN_CASE(MINT_CONV_I4_R8) - sp [-1].data.i = (gint32)sp [-1].data.f; - ++ip; - MINT_IN_BREAK; - MINT_IN_CASE(MINT_CONV_U4_I8) - MINT_IN_CASE(MINT_CONV_I4_I8) - sp [-1].data.i = (gint32)sp [-1].data.l; - ++ip; - MINT_IN_BREAK; - MINT_IN_CASE(MINT_CONV_I4_I8_SP) - sp [-2].data.i = (gint32)sp [-2].data.l; - ++ip; - MINT_IN_BREAK; - MINT_IN_CASE(MINT_CONV_U4_R8) - sp [-1].data.i = (guint32)sp [-1].data.f; - ++ip; - MINT_IN_BREAK; - MINT_IN_CASE(MINT_CONV_I8_I4) - sp [-1].data.l = sp [-1].data.i; - ++ip; - MINT_IN_BREAK; - MINT_IN_CASE(MINT_CONV_I8_I4_SP) - sp [-2].data.l = sp [-2].data.i; - ++ip; - MINT_IN_BREAK; - MINT_IN_CASE(MINT_CONV_I8_U4) - sp [-1].data.l = (guint32)sp [-1].data.i; - ++ip; - MINT_IN_BREAK; - MINT_IN_CASE(MINT_CONV_I8_R8) - sp [-1].data.l = (gint64)sp [-1].data.f; - ++ip; - MINT_IN_BREAK; - MINT_IN_CASE(MINT_CONV_R4_I4) - sp [-1].data.f = (float)sp [-1].data.i; - ++ip; - MINT_IN_BREAK; - MINT_IN_CASE(MINT_CONV_R4_I8) - sp [-1].data.f = (float)sp [-1].data.l; - ++ip; - MINT_IN_BREAK; - MINT_IN_CASE(MINT_CONV_R4_R8) - sp [-1].data.f = (float)sp [-1].data.f; - ++ip; - MINT_IN_BREAK; - MINT_IN_CASE(MINT_CONV_R8_I4) - sp [-1].data.f = (double)sp [-1].data.i; - ++ip; - MINT_IN_BREAK; - MINT_IN_CASE(MINT_CONV_R8_I8) - sp [-1].data.f = (double)sp [-1].data.l; - ++ip; - MINT_IN_BREAK; - MINT_IN_CASE(MINT_CONV_U8_I4) - sp [-1].data.l = sp [-1].data.i & 0xffffffff; - ++ip; - MINT_IN_BREAK; - MINT_IN_CASE(MINT_CONV_U8_R8) - sp [-1].data.l = (guint64)sp [-1].data.f; - ++ip; - MINT_IN_BREAK; -#if 0 - MINT_IN_CASE(MINT_CPOBJ) { - MonoClass *vtklass; - ++ip; - vtklass = rtm->data_items[READ32 (ip)]; - ip += 2; - sp -= 2; - memcpy (sp [0].data.p, sp [1].data.p, mono_class_value_size (vtklass, NULL)); - MINT_IN_BREAK; - } -#endif - MINT_IN_CASE(MINT_LDOBJ) { - int size; - void *p; - c = rtm->data_items[* (guint16 *)(ip + 1)]; - ip += 2; - if (c->byval_arg.type != MONO_TYPE_VALUETYPE || c->byval_arg.data.klass->enumtype) { - p = sp [-1].data.p; - stackval_from_data (&c->byval_arg, &sp [-1], p, FALSE); - } else { - size = mono_class_value_size (c, NULL); - p = sp [-1].data.p; - sp [-1].data.p = vt_sp; - memcpy(vt_sp, p, size); - vt_sp += (size + 7) & ~7; - } - MINT_IN_BREAK; - } - MINT_IN_CASE(MINT_LDSTR) - sp->data.p = rtm->data_items [* (guint16 *)(ip + 1)]; - ++sp; - ip += 2; - MINT_IN_BREAK; - MINT_IN_CASE(MINT_NEWOBJ) { - MonoClass *newobj_class; - MonoMethodSignature *csig; - stackval valuetype_this; - guint32 token; - stackval retval; - - frame->ip = ip; - - token = * (guint16 *)(ip + 1); - ip += 2; - - child_frame.runtime_method = rtm->data_items [token]; - csig = mono_method_signature (child_frame.runtime_method->method); - newobj_class = child_frame.runtime_method->method->klass; - /*if (profiling_classes) { - guint count = GPOINTER_TO_UINT (g_hash_table_lookup (profiling_classes, newobj_class)); - count++; - g_hash_table_insert (profiling_classes, newobj_class, GUINT_TO_POINTER (count)); - }*/ - - if (newobj_class->parent == mono_defaults.array_class) { - sp -= csig->param_count; - o = ves_array_create (context->domain, newobj_class, csig, sp); - goto array_constructed; - } - - g_assert (csig->hasthis); - if (csig->param_count) { - sp -= csig->param_count; - memmove (sp + 1, sp, csig->param_count * sizeof (stackval)); - } - child_frame.stack_args = sp; - - /* - * First arg is the object. - */ - if (newobj_class->valuetype) { - MonoType *t = &newobj_class->byval_arg; - if (!newobj_class->enumtype && (t->type == MONO_TYPE_VALUETYPE || (t->type == MONO_TYPE_GENERICINST && mono_type_generic_inst_is_valuetype (t)))) { - sp->data.p = vt_sp; - valuetype_this.data.p = vt_sp; - } else { - memset (&valuetype_this, 0, sizeof (stackval)); - sp->data.p = &valuetype_this; - } - } else { - if (newobj_class != mono_defaults.string_class) { - context->managed_code = 0; - o = mono_object_new_checked (context->domain, newobj_class, &error); - mono_error_cleanup (&error); /* FIXME: don't swallow the error */ - context->managed_code = 1; - if (*mono_thread_interruption_request_flag ()) - mono_thread_interruption_checkpoint (); - sp->data.p = o; - } else { - sp->data.p = NULL; - child_frame.retval = &retval; - } - } - - g_assert (csig->call_convention == MONO_CALL_DEFAULT); - - child_frame.ip = NULL; - child_frame.ex = NULL; - - ves_exec_method_with_context (&child_frame, context); - - context->current_frame = frame; - - if (child_frame.ex) { - /* - * An exception occurred, need to run finally, fault and catch handlers.. - */ - frame->ex = child_frame.ex; - goto handle_finally; - } - /* - * a constructor returns void, but we need to return the object we created - */ -array_constructed: - if (newobj_class->valuetype && !newobj_class->enumtype) { - *sp = valuetype_this; - } else if (newobj_class == mono_defaults.string_class) { - *sp = retval; - } else { - sp->data.p = o; - } - ++sp; - MINT_IN_BREAK; - } - MINT_IN_CASE(MINT_CASTCLASS) - c = rtm->data_items [*(guint16 *)(ip + 1)]; - if ((o = sp [-1].data.p)) { - MonoObject *isinst_obj = mono_object_isinst_checked (o, c, &error); - mono_error_cleanup (&error); /* FIXME: don't swallow the error */ - if (!isinst_obj) - THROW_EX (mono_get_exception_invalid_cast (), ip); - } - ip += 2; - MINT_IN_BREAK; - MINT_IN_CASE(MINT_ISINST) - c = rtm->data_items [*(guint16 *)(ip + 1)]; - if ((o = sp [-1].data.p)) { - MonoObject *isinst_obj = mono_object_isinst_checked (o, c, &error); - mono_error_cleanup (&error); /* FIXME: don't swallow the error */ - if (!isinst_obj) - sp [-1].data.p = NULL; - } - ip += 2; - MINT_IN_BREAK; - MINT_IN_CASE(MINT_CONV_R_UN_I4) - sp [-1].data.f = (double)(guint32)sp [-1].data.i; - ++ip; - MINT_IN_BREAK; - MINT_IN_CASE(MINT_CONV_R_UN_I8) - sp [-1].data.f = (double)(guint64)sp [-1].data.l; - ++ip; - MINT_IN_BREAK; - MINT_IN_CASE(MINT_UNBOX) - c = rtm->data_items[*(guint16 *)(ip + 1)]; - - o = sp [-1].data.p; - if (!o) - THROW_EX (mono_get_exception_null_reference (), ip); - - MonoObject *isinst_obj = mono_object_isinst_checked (o, c, &error); - mono_error_cleanup (&error); /* FIXME: don't swallow the error */ - if (!(isinst_obj || ((o->vtable->klass->rank == 0) && (o->vtable->klass->element_class == c->element_class)))) - THROW_EX (mono_get_exception_invalid_cast (), ip); - - if (c->byval_arg.type == MONO_TYPE_VALUETYPE && !c->enumtype) { - int size = mono_class_native_size (c, NULL); - sp [-1].data.p = vt_sp; - vt_sp += (size + 7) & ~7; - } - stackval_from_data (&c->byval_arg, &sp [-1], mono_object_unbox (o), FALSE); - ip += 2; - MINT_IN_BREAK; - MINT_IN_CASE(MINT_THROW) - --sp; - frame->ex_handler = NULL; - if (!sp->data.p) - sp->data.p = mono_get_exception_null_reference (); - THROW_EX ((MonoException *)sp->data.p, ip); - MINT_IN_BREAK; - MINT_IN_CASE(MINT_LDFLDA) - o = sp [-1].data.p; - if (!o) - THROW_EX (mono_get_exception_null_reference (), ip); - sp[-1].data.p = (char *)o + * (guint16 *)(ip + 1); - ip += 2; - MINT_IN_BREAK; - MINT_IN_CASE(MINT_CKNULL) - o = sp [-1].data.p; - if (!o) - THROW_EX (mono_get_exception_null_reference (), ip); - ++ip; - MINT_IN_BREAK; - -#define LDFLD(datamem, fieldtype) \ - o = sp [-1].data.p; \ - if (!o) \ - THROW_EX (mono_get_exception_null_reference (), ip); \ - sp[-1].data.datamem = * (fieldtype *)((char *)o + * (guint16 *)(ip + 1)) ; \ - ip += 2; - - MINT_IN_CASE(MINT_LDFLD_I1) LDFLD(i, gint8); MINT_IN_BREAK; - MINT_IN_CASE(MINT_LDFLD_U1) LDFLD(i, guint8); MINT_IN_BREAK; - MINT_IN_CASE(MINT_LDFLD_I2) LDFLD(i, gint16); MINT_IN_BREAK; - MINT_IN_CASE(MINT_LDFLD_U2) LDFLD(i, guint16); MINT_IN_BREAK; - MINT_IN_CASE(MINT_LDFLD_I4) LDFLD(i, gint32); MINT_IN_BREAK; - MINT_IN_CASE(MINT_LDFLD_I8) LDFLD(l, gint64); MINT_IN_BREAK; - MINT_IN_CASE(MINT_LDFLD_R4) LDFLD(f, float); MINT_IN_BREAK; - MINT_IN_CASE(MINT_LDFLD_R8) LDFLD(f, double); MINT_IN_BREAK; - MINT_IN_CASE(MINT_LDFLD_O) LDFLD(p, gpointer); MINT_IN_BREAK; - MINT_IN_CASE(MINT_LDFLD_P) LDFLD(p, gpointer); MINT_IN_BREAK; - - MINT_IN_CASE(MINT_LDFLD_VT) - o = sp [-1].data.p; - if (!o) - THROW_EX (mono_get_exception_null_reference (), ip); - i32 = READ32(ip + 2); - sp [-1].data.p = vt_sp; - memcpy(sp [-1].data.p, (char *)o + * (guint16 *)(ip + 1), i32); - vt_sp += (i32 + 7) & ~7; - ip += 4; - MINT_IN_BREAK; - - MINT_IN_CASE(MINT_LDRMFLD) { - gpointer tmp; - MonoClassField *field; - char *addr; - - o = sp [-1].data.p; - if (!o) - THROW_EX (mono_get_exception_null_reference (), ip); - field = rtm->data_items[* (guint16 *)(ip + 1)]; - ip += 2; - if (mono_object_is_transparent_proxy (o)) { - MonoClass *klass = ((MonoTransparentProxy*)o)->remote_class->proxy_class; - - addr = mono_load_remote_field_checked (o, klass, field, &tmp, &error); - mono_error_cleanup (&error); /* FIXME: don't swallow the error */ - } else { - addr = (char*)o + field->offset; - } - - stackval_from_data (field->type, &sp [-1], addr, FALSE); - MINT_IN_BREAK; - } - - MINT_IN_CASE(MINT_LDRMFLD_VT) { - MonoClassField *field; - char *addr; - gpointer tmp; - - o = sp [-1].data.p; - if (!o) - THROW_EX (mono_get_exception_null_reference (), ip); - field = rtm->data_items[* (guint16 *)(ip + 1)]; - i32 = READ32(ip + 2); - ip += 4; - if (mono_object_is_transparent_proxy (o)) { - MonoClass *klass = ((MonoTransparentProxy*)o)->remote_class->proxy_class; - addr = mono_load_remote_field_checked (o, klass, field, &tmp, &error); - mono_error_cleanup (&error); /* FIXME: don't swallow the error */ - } else { - addr = (char*)o + field->offset; - } - - sp [-1].data.p = vt_sp; - memcpy(sp [-1].data.p, (char *)o + * (guint16 *)(ip + 1), i32); - vt_sp += (i32 + 7) & ~7; - memcpy(sp [-1].data.p, addr, i32); - MINT_IN_BREAK; - } - -#define STFLD(datamem, fieldtype) \ - o = sp [-2].data.p; \ - if (!o) \ - THROW_EX (mono_get_exception_null_reference (), ip); \ - sp -= 2; \ - * (fieldtype *)((char *)o + * (guint16 *)(ip + 1)) = sp[1].data.datamem; \ - ip += 2; - - MINT_IN_CASE(MINT_STFLD_I1) STFLD(i, gint8); MINT_IN_BREAK; - MINT_IN_CASE(MINT_STFLD_U1) STFLD(i, guint8); MINT_IN_BREAK; - MINT_IN_CASE(MINT_STFLD_I2) STFLD(i, gint16); MINT_IN_BREAK; - MINT_IN_CASE(MINT_STFLD_U2) STFLD(i, guint16); MINT_IN_BREAK; - MINT_IN_CASE(MINT_STFLD_I4) STFLD(i, gint32); MINT_IN_BREAK; - MINT_IN_CASE(MINT_STFLD_I8) STFLD(l, gint64); MINT_IN_BREAK; - MINT_IN_CASE(MINT_STFLD_R4) STFLD(f, float); MINT_IN_BREAK; - MINT_IN_CASE(MINT_STFLD_R8) STFLD(f, double); MINT_IN_BREAK; - MINT_IN_CASE(MINT_STFLD_O) STFLD(p, gpointer); MINT_IN_BREAK; - MINT_IN_CASE(MINT_STFLD_P) STFLD(p, gpointer); MINT_IN_BREAK; - - MINT_IN_CASE(MINT_STFLD_VT) - o = sp [-2].data.p; - if (!o) - THROW_EX (mono_get_exception_null_reference (), ip); - i32 = READ32(ip + 2); - sp -= 2; - memcpy((char *)o + * (guint16 *)(ip + 1), sp [1].data.p, i32); - vt_sp -= (i32 + 7) & ~7; - ip += 4; - MINT_IN_BREAK; - - MINT_IN_CASE(MINT_STRMFLD) { - MonoClassField *field; - - o = sp [-2].data.p; - if (!o) - THROW_EX (mono_get_exception_null_reference (), ip); - - field = rtm->data_items[* (guint16 *)(ip + 1)]; - ip += 2; - - if (mono_object_is_transparent_proxy (o)) { - MonoClass *klass = ((MonoTransparentProxy*)o)->remote_class->proxy_class; - mono_store_remote_field_checked (o, klass, field, &sp [-1].data, &error); - mono_error_cleanup (&error); /* FIXME: don't swallow the error */ - } else - stackval_to_data (field->type, &sp [-1], (char*)o + field->offset, FALSE); - - sp -= 2; - MINT_IN_BREAK; - } - MINT_IN_CASE(MINT_STRMFLD_VT) { - MonoClassField *field; - - o = sp [-2].data.p; - if (!o) - THROW_EX (mono_get_exception_null_reference (), ip); - field = rtm->data_items[* (guint16 *)(ip + 1)]; - i32 = READ32(ip + 2); - ip += 4; - - if (mono_object_is_transparent_proxy (o)) { - MonoClass *klass = ((MonoTransparentProxy*)o)->remote_class->proxy_class; - mono_store_remote_field_checked (o, klass, field, &sp [-1].data, &error); - mono_error_cleanup (&error); /* FIXME: don't swallow the error */ - } else - memcpy((char*)o + field->offset, sp [-1].data.p, i32); - - sp -= 2; - vt_sp -= (i32 + 7) & ~7; - MINT_IN_BREAK; - } - MINT_IN_CASE(MINT_LDSFLDA) { - MonoClassField *field = rtm->data_items[*(guint16 *)(ip + 1)]; - sp->data.p = mono_class_static_field_address (context->domain, field); - ip += 2; - ++sp; - MINT_IN_BREAK; - } - MINT_IN_CASE(MINT_LDSFLD) { - MonoClassField *field = rtm->data_items [* (guint16 *)(ip + 1)]; - gpointer addr = mono_class_static_field_address (context->domain, field); - stackval_from_data (field->type, sp, addr, FALSE); - ip += 2; - ++sp; - MINT_IN_BREAK; - } - MINT_IN_CASE(MINT_LDSFLD_VT) { - MonoClassField *field = rtm->data_items [* (guint16 *)(ip + 1)]; - gpointer addr = mono_class_static_field_address (context->domain, field); - int size = READ32 (ip + 2); - ip += 4; - - sp->data.p = vt_sp; - vt_sp += (size + 7) & ~7; - stackval_from_data (field->type, sp, addr, FALSE); - ++sp; - MINT_IN_BREAK; - } - MINT_IN_CASE(MINT_STSFLD) { - MonoClassField *field = rtm->data_items [* (guint16 *)(ip + 1)]; - gpointer addr = mono_class_static_field_address (context->domain, field); - ip += 2; - --sp; - stackval_to_data (field->type, sp, addr, FALSE); - MINT_IN_BREAK; - } - MINT_IN_CASE(MINT_STSFLD_VT) { - MonoClassField *field = rtm->data_items [* (guint16 *)(ip + 1)]; - gpointer addr = mono_class_static_field_address (context->domain, field); - int size = READ32 (ip + 2); - ip += 4; - - --sp; - stackval_to_data (field->type, sp, addr, FALSE); - vt_sp -= (size + 7) & ~7; - MINT_IN_BREAK; - } - MINT_IN_CASE(MINT_STOBJ_VT) { - int size; - c = rtm->data_items[* (guint16 *)(ip + 1)]; - ip += 2; - size = mono_class_value_size (c, NULL); - memcpy(sp [-2].data.p, sp [-1].data.p, size); - vt_sp -= (size + 7) & ~7; - sp -= 2; - MINT_IN_BREAK; - } - MINT_IN_CASE(MINT_STOBJ) { - int size; - c = rtm->data_items[* (guint16 *)(ip + 1)]; - ip += 2; - size = mono_class_value_size (c, NULL); - memcpy(sp [-2].data.p, &sp [-1].data, size); - sp -= 2; - MINT_IN_BREAK; - } - MINT_IN_CASE(MINT_CONV_OVF_I4_UN_R8) - if (sp [-1].data.f < 0 || sp [-1].data.f > MYGUINT32_MAX) - THROW_EX (mono_get_exception_overflow (), ip); - sp [-1].data.i = (guint32)sp [-1].data.f; - ++ip; - MINT_IN_BREAK; - MINT_IN_CASE(MINT_CONV_OVF_U8_I4) - if (sp [-1].data.i < 0) - THROW_EX (mono_get_exception_overflow (), ip); - sp [-1].data.l = sp [-1].data.i; - ++ip; - MINT_IN_BREAK; - MINT_IN_CASE(MINT_CONV_OVF_U8_R8) - MINT_IN_CASE(MINT_CONV_OVF_I8_UN_R8) - if (sp [-1].data.f < 0 || sp [-1].data.f > 9223372036854775807LL) - THROW_EX (mono_get_exception_overflow (), ip); - sp [-1].data.l = (guint64)sp [-1].data.f; - ++ip; - MINT_IN_BREAK; - MINT_IN_CASE(MINT_CONV_OVF_I8_R8) - if (sp [-1].data.f < MYGINT64_MIN || sp [-1].data.f > MYGINT64_MAX) - THROW_EX (mono_get_exception_overflow (), ip); - sp [-1].data.l = (gint64)sp [-1].data.f; - ++ip; - MINT_IN_BREAK; - MINT_IN_CASE(MINT_CONV_OVF_I4_UN_I8) - if ((mono_u)sp [-1].data.l > MYGUINT32_MAX) - THROW_EX (mono_get_exception_overflow (), ip); - sp [-1].data.i = (mono_u)sp [-1].data.l; - ++ip; - MINT_IN_BREAK; - MINT_IN_CASE(MINT_BOX) { - c = rtm->data_items [* (guint16 *)(ip + 1)]; - guint16 offset = * (guint16 *)(ip + 2); - - if (c->byval_arg.type == MONO_TYPE_VALUETYPE && !c->enumtype) { - int size = mono_class_value_size (c, NULL); - sp [-1 - offset].data.p = mono_value_box_checked (context->domain, c, sp [-1 - offset].data.p, &error); - mono_error_cleanup (&error); /* FIXME: don't swallow the error */ - size = (size + 7) & ~7; - vt_sp -= size; - } else { - stackval_to_data (&c->byval_arg, &sp [-1 - offset], (char *) &sp [-1 - offset], FALSE); - sp [-1 - offset].data.p = mono_value_box_checked (context->domain, c, &sp [-1 - offset], &error); - mono_error_cleanup (&error); /* FIXME: don't swallow the error */ - } - ip += 3; - MINT_IN_BREAK; - } - MINT_IN_CASE(MINT_NEWARR) - sp [-1].data.p = (MonoObject*) mono_array_new_checked (context->domain, rtm->data_items[*(guint16 *)(ip + 1)], sp [-1].data.i, &error); - mono_error_cleanup (&error); /* FIXME: don't swallow the error */ - ip += 2; - /*if (profiling_classes) { - guint count = GPOINTER_TO_UINT (g_hash_table_lookup (profiling_classes, o->vtable->klass)); - count++; - g_hash_table_insert (profiling_classes, o->vtable->klass, GUINT_TO_POINTER (count)); - }*/ - - MINT_IN_BREAK; - MINT_IN_CASE(MINT_LDLEN) - o = sp [-1].data.p; - if (!o) - THROW_EX (mono_get_exception_null_reference (), ip); - sp [-1].data.nati = mono_array_length ((MonoArray *)o); - ++ip; - MINT_IN_BREAK; - MINT_IN_CASE(MINT_GETCHR) { - MonoString *s; - s = sp [-2].data.p; - if (!s) - THROW_EX (mono_get_exception_null_reference (), ip); - i32 = sp [-1].data.i; - if (i32 < 0 || i32 >= mono_string_length (s)) - THROW_EX (mono_get_exception_index_out_of_range (), ip); - --sp; - sp [-1].data.i = mono_string_chars(s)[i32]; - ++ip; - MINT_IN_BREAK; - } - MINT_IN_CASE(MINT_STRLEN) - ++ip; - sp [-1].data.i = mono_string_length ((MonoString*)sp [-1].data.p); - MINT_IN_BREAK; - MINT_IN_CASE(MINT_ARRAY_RANK) - o = sp [-1].data.p; - if (!o) - THROW_EX (mono_get_exception_null_reference (), ip); - sp [-1].data.i = mono_object_class (sp [-1].data.p)->rank; - ip++; - MINT_IN_BREAK; - MINT_IN_CASE(MINT_LDELEMA) { - guint32 esize; - mono_u aindex; - - /*token = READ32 (ip)*/; - ip += 2; - sp -= 2; - - o = sp [0].data.p; - - aindex = sp [1].data.i; - if (aindex >= mono_array_length ((MonoArray *) o)) - THROW_EX (mono_get_exception_index_out_of_range (), ip - 2); - - /* check the array element corresponds to token */ - esize = mono_array_element_size (((MonoArray *) o)->obj.vtable->klass); - - sp->data.p = mono_array_addr_with_size ((MonoArray *) o, esize, aindex); - ++sp; - MINT_IN_BREAK; - } - MINT_IN_CASE(MINT_LDELEM_I1) /* fall through */ - MINT_IN_CASE(MINT_LDELEM_U1) /* fall through */ - MINT_IN_CASE(MINT_LDELEM_I2) /* fall through */ - MINT_IN_CASE(MINT_LDELEM_U2) /* fall through */ - MINT_IN_CASE(MINT_LDELEM_I4) /* fall through */ - MINT_IN_CASE(MINT_LDELEM_U4) /* fall through */ - MINT_IN_CASE(MINT_LDELEM_I8) /* fall through */ - MINT_IN_CASE(MINT_LDELEM_I) /* fall through */ - MINT_IN_CASE(MINT_LDELEM_R4) /* fall through */ - MINT_IN_CASE(MINT_LDELEM_R8) /* fall through */ - MINT_IN_CASE(MINT_LDELEM_REF) /* fall through */ - MINT_IN_CASE(MINT_LDELEM_VT) { - MonoArray *o; - mono_u aindex; - - sp -= 2; - - o = sp [0].data.p; - if (!o) - THROW_EX (mono_get_exception_null_reference (), ip); - - aindex = sp [1].data.i; - if (aindex >= mono_array_length (o)) - THROW_EX (mono_get_exception_index_out_of_range (), ip); - - /* - * FIXME: throw mono_get_exception_array_type_mismatch () if needed - */ - switch (*ip) { - case MINT_LDELEM_I1: - sp [0].data.i = mono_array_get (o, gint8, aindex); - break; - case MINT_LDELEM_U1: - sp [0].data.i = mono_array_get (o, guint8, aindex); - break; - case MINT_LDELEM_I2: - sp [0].data.i = mono_array_get (o, gint16, aindex); - break; - case MINT_LDELEM_U2: - sp [0].data.i = mono_array_get (o, guint16, aindex); - break; - case MINT_LDELEM_I: - sp [0].data.nati = mono_array_get (o, mono_i, aindex); - break; - case MINT_LDELEM_I4: - sp [0].data.i = mono_array_get (o, gint32, aindex); - break; - case MINT_LDELEM_U4: - sp [0].data.i = mono_array_get (o, guint32, aindex); - break; - case MINT_LDELEM_I8: - sp [0].data.l = mono_array_get (o, guint64, aindex); - break; - case MINT_LDELEM_R4: - sp [0].data.f = mono_array_get (o, float, aindex); - break; - case MINT_LDELEM_R8: - sp [0].data.f = mono_array_get (o, double, aindex); - break; - case MINT_LDELEM_REF: - sp [0].data.p = mono_array_get (o, gpointer, aindex); - break; - case MINT_LDELEM_VT: { - MonoClass *klass_vt = rtm->data_items [*(guint16 *) (ip + 1)]; - i32 = READ32 (ip + 2); - char *src_addr = mono_array_addr_with_size ((MonoArray *) o, i32, aindex); - sp [0].data.vt = vt_sp; - stackval_from_data (&klass_vt->byval_arg, sp, src_addr, FALSE); - vt_sp += (i32 + 7) & ~7; - ip += 3; - break; - } - default: - ves_abort(); - } - - ++ip; - ++sp; - MINT_IN_BREAK; - } - MINT_IN_CASE(MINT_STELEM_I) /* fall through */ - MINT_IN_CASE(MINT_STELEM_I1) /* fall through */ - MINT_IN_CASE(MINT_STELEM_I2) /* fall through */ - MINT_IN_CASE(MINT_STELEM_I4) /* fall through */ - MINT_IN_CASE(MINT_STELEM_I8) /* fall through */ - MINT_IN_CASE(MINT_STELEM_R4) /* fall through */ - MINT_IN_CASE(MINT_STELEM_R8) /* fall through */ - MINT_IN_CASE(MINT_STELEM_REF) /* fall through */ - MINT_IN_CASE(MINT_STELEM_VT) { - mono_u aindex; - - sp -= 3; - - o = sp [0].data.p; - if (!o) - THROW_EX (mono_get_exception_null_reference (), ip); - - aindex = sp [1].data.i; - if (aindex >= mono_array_length ((MonoArray *)o)) - THROW_EX (mono_get_exception_index_out_of_range (), ip); - - switch (*ip) { - case MINT_STELEM_I: - mono_array_set ((MonoArray *)o, mono_i, aindex, sp [2].data.nati); - break; - case MINT_STELEM_I1: - mono_array_set ((MonoArray *)o, gint8, aindex, sp [2].data.i); - break; - case MINT_STELEM_I2: - mono_array_set ((MonoArray *)o, gint16, aindex, sp [2].data.i); - break; - case MINT_STELEM_I4: - mono_array_set ((MonoArray *)o, gint32, aindex, sp [2].data.i); - break; - case MINT_STELEM_I8: - mono_array_set ((MonoArray *)o, gint64, aindex, sp [2].data.l); - break; - case MINT_STELEM_R4: - mono_array_set ((MonoArray *)o, float, aindex, sp [2].data.f); - break; - case MINT_STELEM_R8: - mono_array_set ((MonoArray *)o, double, aindex, sp [2].data.f); - break; - case MINT_STELEM_REF: { - MonoObject *isinst_obj = mono_object_isinst_checked (sp [2].data.p, mono_object_class (o)->element_class, &error); - mono_error_cleanup (&error); /* FIXME: don't swallow the error */ - if (sp [2].data.p && !isinst_obj) - THROW_EX (mono_get_exception_array_type_mismatch (), ip); - mono_array_set ((MonoArray *)o, gpointer, aindex, sp [2].data.p); - break; - } - case MINT_STELEM_VT: { - MonoClass *klass_vt = rtm->data_items [*(guint16 *) (ip + 1)]; - i32 = READ32 (ip + 2); - char *dst_addr = mono_array_addr_with_size ((MonoArray *) o, i32, aindex); - - stackval_to_data (&klass_vt->byval_arg, &sp [2], dst_addr, FALSE); - vt_sp -= (i32 + 7) & ~7; - ip += 3; - break; - } - default: - ves_abort(); - } - - ++ip; - MINT_IN_BREAK; - } - MINT_IN_CASE(MINT_CONV_OVF_I4_U4) - if (sp [-1].data.i < 0) - THROW_EX (mono_get_exception_overflow (), ip); - ++ip; - MINT_IN_BREAK; - MINT_IN_CASE(MINT_CONV_OVF_I4_I8) - if (sp [-1].data.l < MYGINT32_MIN || sp [-1].data.l > MYGINT32_MAX) - THROW_EX (mono_get_exception_overflow (), ip); - sp [-1].data.i = (gint32) sp [-1].data.l; - ++ip; - MINT_IN_BREAK; - MINT_IN_CASE(MINT_CONV_OVF_I4_R8) - if (sp [-1].data.f < MYGINT32_MIN || sp [-1].data.f > MYGINT32_MAX) - THROW_EX (mono_get_exception_overflow (), ip); - sp [-1].data.i = (gint32) sp [-1].data.f; - ++ip; - MINT_IN_BREAK; - MINT_IN_CASE(MINT_CONV_OVF_U4_I4) - if (sp [-1].data.i < 0) - THROW_EX (mono_get_exception_overflow (), ip); - ++ip; - MINT_IN_BREAK; - MINT_IN_CASE(MINT_CONV_OVF_U4_I8) - if (sp [-1].data.l < 0 || sp [-1].data.l > MYGUINT32_MAX) - THROW_EX (mono_get_exception_overflow (), ip); - sp [-1].data.i = (guint32) sp [-1].data.l; - ++ip; - MINT_IN_BREAK; - MINT_IN_CASE(MINT_CONV_OVF_U4_R8) - if (sp [-1].data.f < 0 || sp [-1].data.f > MYGUINT32_MAX) - THROW_EX (mono_get_exception_overflow (), ip); - sp [-1].data.i = (guint32) sp [-1].data.f; - ++ip; - MINT_IN_BREAK; - MINT_IN_CASE(MINT_CONV_OVF_I2_I4) - if (sp [-1].data.i < -32768 || sp [-1].data.i > 32767) - THROW_EX (mono_get_exception_overflow (), ip); - ++ip; - MINT_IN_BREAK; - MINT_IN_CASE(MINT_CONV_OVF_I2_I8) - if (sp [-1].data.l < -32768 || sp [-1].data.l > 32767) - THROW_EX (mono_get_exception_overflow (), ip); - sp [-1].data.i = (gint16) sp [-1].data.l; - ++ip; - MINT_IN_BREAK; - MINT_IN_CASE(MINT_CONV_OVF_I2_R8) - if (sp [-1].data.f < -32768 || sp [-1].data.f > 32767) - THROW_EX (mono_get_exception_overflow (), ip); - sp [-1].data.i = (gint16) sp [-1].data.f; - ++ip; - MINT_IN_BREAK; - MINT_IN_CASE(MINT_CONV_OVF_U2_I4) - if (sp [-1].data.i < 0 || sp [-1].data.i > 65535) - THROW_EX (mono_get_exception_overflow (), ip); - ++ip; - MINT_IN_BREAK; - MINT_IN_CASE(MINT_CONV_OVF_U2_I8) - if (sp [-1].data.l < 0 || sp [-1].data.l > 65535) - THROW_EX (mono_get_exception_overflow (), ip); - sp [-1].data.i = (guint16) sp [-1].data.l; - ++ip; - MINT_IN_BREAK; - MINT_IN_CASE(MINT_CONV_OVF_U2_R8) - if (sp [-1].data.f < 0 || sp [-1].data.f > 65535) - THROW_EX (mono_get_exception_overflow (), ip); - sp [-1].data.i = (guint16) sp [-1].data.f; - ++ip; - MINT_IN_BREAK; - MINT_IN_CASE(MINT_CONV_OVF_I1_I4) - if (sp [-1].data.i < -128 || sp [-1].data.i > 127) - THROW_EX (mono_get_exception_overflow (), ip); - ++ip; - MINT_IN_BREAK; - MINT_IN_CASE(MINT_CONV_OVF_I1_I8) - if (sp [-1].data.l < -128 || sp [-1].data.l > 127) - THROW_EX (mono_get_exception_overflow (), ip); - sp [-1].data.i = (gint8) sp [-1].data.l; - ++ip; - MINT_IN_BREAK; - MINT_IN_CASE(MINT_CONV_OVF_I1_R8) - if (sp [-1].data.f < -128 || sp [-1].data.f > 127) - THROW_EX (mono_get_exception_overflow (), ip); - sp [-1].data.i = (gint8) sp [-1].data.f; - ++ip; - MINT_IN_BREAK; - MINT_IN_CASE(MINT_CONV_OVF_U1_I4) - if (sp [-1].data.i < 0 || sp [-1].data.i > 255) - THROW_EX (mono_get_exception_overflow (), ip); - ++ip; - MINT_IN_BREAK; - MINT_IN_CASE(MINT_CONV_OVF_U1_I8) - if (sp [-1].data.l < 0 || sp [-1].data.l > 255) - THROW_EX (mono_get_exception_overflow (), ip); - sp [-1].data.i = (guint8) sp [-1].data.l; - ++ip; - MINT_IN_BREAK; - MINT_IN_CASE(MINT_CONV_OVF_U1_R8) - if (sp [-1].data.f < 0 || sp [-1].data.f > 255) - THROW_EX (mono_get_exception_overflow (), ip); - sp [-1].data.i = (guint8) sp [-1].data.f; - ++ip; - MINT_IN_BREAK; -#if 0 - MINT_IN_CASE(MINT_LDELEM) - MINT_IN_CASE(MINT_STELEM) - MINT_IN_CASE(MINT_UNBOX_ANY) - - MINT_IN_CASE(MINT_REFANYVAL) ves_abort(); MINT_IN_BREAK; -#endif - MINT_IN_CASE(MINT_CKFINITE) - if (!isfinite(sp [-1].data.f)) - THROW_EX (mono_get_exception_arithmetic (), ip); - ++ip; - MINT_IN_BREAK; -#if 0 - MINT_IN_CASE(MINT_MKREFANY) ves_abort(); MINT_IN_BREAK; -#endif - MINT_IN_CASE(MINT_LDTOKEN) - sp->data.p = vt_sp; - vt_sp += 8; - * (gpointer *)sp->data.p = rtm->data_items[*(guint16 *)(ip + 1)]; - ip += 2; - ++sp; - MINT_IN_BREAK; - MINT_IN_CASE(MINT_ADD_OVF_I4) - if (CHECK_ADD_OVERFLOW (sp [-2].data.i, sp [-1].data.i)) - THROW_EX (mono_get_exception_overflow (), ip); - BINOP(i, +); - MINT_IN_BREAK; - MINT_IN_CASE(MINT_ADD_OVF_I8) - if (CHECK_ADD_OVERFLOW64 (sp [-2].data.l, sp [-1].data.l)) - THROW_EX (mono_get_exception_overflow (), ip); - BINOP(l, +); - MINT_IN_BREAK; - MINT_IN_CASE(MINT_ADD_OVF_UN_I4) - if (CHECK_ADD_OVERFLOW_UN (sp [-2].data.i, sp [-1].data.i)) - THROW_EX (mono_get_exception_overflow (), ip); - BINOP_CAST(i, +, guint32); - MINT_IN_BREAK; - MINT_IN_CASE(MINT_ADD_OVF_UN_I8) - if (CHECK_ADD_OVERFLOW64_UN (sp [-2].data.l, sp [-1].data.l)) - THROW_EX (mono_get_exception_overflow (), ip); - BINOP_CAST(l, +, guint64); - MINT_IN_BREAK; - MINT_IN_CASE(MINT_MUL_OVF_I4) - if (CHECK_MUL_OVERFLOW (sp [-2].data.i, sp [-1].data.i)) - THROW_EX (mono_get_exception_overflow (), ip); - BINOP(i, *); - MINT_IN_BREAK; - MINT_IN_CASE(MINT_MUL_OVF_I8) - if (CHECK_MUL_OVERFLOW64 (sp [-2].data.l, sp [-1].data.l)) - THROW_EX (mono_get_exception_overflow (), ip); - BINOP(l, *); - MINT_IN_BREAK; - MINT_IN_CASE(MINT_MUL_OVF_UN_I4) - if (CHECK_MUL_OVERFLOW_UN (sp [-2].data.i, sp [-1].data.i)) - THROW_EX (mono_get_exception_overflow (), ip); - BINOP_CAST(i, *, guint32); - MINT_IN_BREAK; - MINT_IN_CASE(MINT_MUL_OVF_UN_I8) - if (CHECK_MUL_OVERFLOW64_UN (sp [-2].data.l, sp [-1].data.l)) - THROW_EX (mono_get_exception_overflow (), ip); - BINOP_CAST(l, *, guint64); - MINT_IN_BREAK; - MINT_IN_CASE(MINT_SUB_OVF_I4) - if (CHECK_SUB_OVERFLOW (sp [-2].data.i, sp [-1].data.i)) - THROW_EX (mono_get_exception_overflow (), ip); - BINOP(i, -); - MINT_IN_BREAK; - MINT_IN_CASE(MINT_SUB_OVF_I8) - if (CHECK_SUB_OVERFLOW64 (sp [-2].data.l, sp [-1].data.l)) - THROW_EX (mono_get_exception_overflow (), ip); - BINOP(l, -); - MINT_IN_BREAK; - MINT_IN_CASE(MINT_SUB_OVF_UN_I4) - if (CHECK_SUB_OVERFLOW_UN (sp [-2].data.i, sp [-1].data.i)) - THROW_EX (mono_get_exception_overflow (), ip); - BINOP_CAST(i, -, guint32); - MINT_IN_BREAK; - MINT_IN_CASE(MINT_SUB_OVF_UN_I8) - if (CHECK_SUB_OVERFLOW64_UN (sp [-2].data.l, sp [-1].data.l)) - THROW_EX (mono_get_exception_overflow (), ip); - BINOP_CAST(l, -, guint64); - MINT_IN_BREAK; - MINT_IN_CASE(MINT_ENDFINALLY) - if (finally_ips) { - ip = finally_ips->data; - finally_ips = g_slist_remove (finally_ips, ip); - goto main_loop; - } - if (frame->ex) - goto handle_fault; - ves_abort(); - MINT_IN_BREAK; - MINT_IN_CASE(MINT_LEAVE) /* Fall through */ - MINT_IN_CASE(MINT_LEAVE_S) - while (sp > frame->stack) { - --sp; - } - frame->ip = ip; - if (*ip == MINT_LEAVE_S) { - ip += (short) *(ip + 1); - } else { - ip += (gint32) READ32 (ip + 1); - } - endfinally_ip = ip; - if (frame->ex_handler != NULL && MONO_OFFSET_IN_HANDLER(frame->ex_handler, frame->ip - rtm->code)) { - frame->ex_handler = NULL; - frame->ex = NULL; - } - goto handle_finally; - MINT_IN_BREAK; - MINT_IN_CASE(MINT_ICALL_V_V) - MINT_IN_CASE(MINT_ICALL_V_P) - MINT_IN_CASE(MINT_ICALL_P_V) - MINT_IN_CASE(MINT_ICALL_P_P) - MINT_IN_CASE(MINT_ICALL_PP_V) - MINT_IN_CASE(MINT_ICALL_PI_V) - MINT_IN_CASE(MINT_ICALL_PP_P) - MINT_IN_CASE(MINT_ICALL_PI_P) - MINT_IN_CASE(MINT_ICALL_PPP_V) - MINT_IN_CASE(MINT_ICALL_PPI_V) - sp = do_icall (context, *ip, sp, rtm->data_items [*(guint16 *)(ip + 1)]); - if (frame->ex != NULL) - goto handle_exception; - ip += 2; - MINT_IN_BREAK; - MINT_IN_CASE(MINT_MONO_LDPTR) - sp->data.p = rtm->data_items [*(guint16 *)(ip + 1)]; - ip += 2; - ++sp; - MINT_IN_BREAK; - MINT_IN_CASE(MINT_MONO_NEWOBJ) - sp->data.p = mono_object_new_checked (context->domain, rtm->data_items [*(guint16 *)(ip + 1)], &error); - mono_error_cleanup (&error); /* FIXME: don't swallow the error */ - ip += 2; - sp++; - MINT_IN_BREAK; - MINT_IN_CASE(MINT_MONO_FREE) - ++ip; - --sp; - g_error ("that doesn't seem right"); - g_free (sp->data.p); - MINT_IN_BREAK; - MINT_IN_CASE(MINT_MONO_RETOBJ) - ++ip; - sp--; - stackval_from_data (mono_method_signature (frame->runtime_method->method)->ret, frame->retval, sp->data.p, - mono_method_signature (frame->runtime_method->method)->pinvoke); - if (sp > frame->stack) - g_warning ("retobj: more values on stack: %d", sp-frame->stack); - goto exit_frame; - -#define RELOP(datamem, op) \ - --sp; \ - sp [-1].data.i = sp [-1].data.datamem op sp [0].data.datamem; \ - ++ip; - MINT_IN_CASE(MINT_CEQ_I4) - RELOP(i, ==); - MINT_IN_BREAK; - MINT_IN_CASE(MINT_CEQ0_I4) - sp [-1].data.i = (sp [-1].data.i == 0); - ++ip; - MINT_IN_BREAK; - MINT_IN_CASE(MINT_CEQ_I8) - RELOP(l, ==); - MINT_IN_BREAK; - MINT_IN_CASE(MINT_CEQ_R8) - --sp; - if (isunordered (sp [-1].data.f, sp [0].data.f)) - sp [-1].data.i = 0; - else - sp [-1].data.i = sp [-1].data.f == sp [0].data.f; - ++ip; - MINT_IN_BREAK; - MINT_IN_CASE(MINT_CGT_I4) - RELOP(i, >); - MINT_IN_BREAK; - MINT_IN_CASE(MINT_CGT_I8) - RELOP(l, >); - MINT_IN_BREAK; - MINT_IN_CASE(MINT_CGT_R8) - --sp; - if (isunordered (sp [-1].data.f, sp [0].data.f)) - sp [-1].data.i = 0; - else - sp [-1].data.i = sp [-1].data.f > sp [0].data.f; - ++ip; - MINT_IN_BREAK; - -#define RELOP_CAST(datamem, op, type) \ - --sp; \ - sp [-1].data.i = (type)sp [-1].data.datamem op (type)sp [0].data.datamem; \ - ++ip; - - MINT_IN_CASE(MINT_CGT_UN_I4) - RELOP_CAST(i, >, guint32); - MINT_IN_BREAK; - MINT_IN_CASE(MINT_CGT_UN_I8) - RELOP_CAST(l, >, guint64); - MINT_IN_BREAK; - MINT_IN_CASE(MINT_CGT_UN_R8) - --sp; - if (isunordered (sp [-1].data.f, sp [0].data.f)) - sp [-1].data.i = 1; - else - sp [-1].data.i = sp [-1].data.f > sp [0].data.f; - ++ip; - MINT_IN_BREAK; - MINT_IN_CASE(MINT_CLT_I4) - RELOP(i, <); - MINT_IN_BREAK; - MINT_IN_CASE(MINT_CLT_I8) - RELOP(l, <); - MINT_IN_BREAK; - MINT_IN_CASE(MINT_CLT_R8) - --sp; - if (isunordered (sp [-1].data.f, sp [0].data.f)) - sp [-1].data.i = 0; - else - sp [-1].data.i = sp [-1].data.f < sp [0].data.f; - ++ip; - MINT_IN_BREAK; - MINT_IN_CASE(MINT_CLT_UN_I4) - RELOP_CAST(i, <, guint32); - MINT_IN_BREAK; - MINT_IN_CASE(MINT_CLT_UN_I8) - RELOP_CAST(l, <, guint64); - MINT_IN_BREAK; - MINT_IN_CASE(MINT_CLT_UN_R8) - --sp; - if (isunordered (sp [-1].data.f, sp [0].data.f)) - sp [-1].data.i = 1; - else - sp [-1].data.i = sp [-1].data.f < sp [0].data.f; - ++ip; - MINT_IN_BREAK; - MINT_IN_CASE(MINT_LDFTN) { - sp->data.p = rtm->data_items [* (guint16 *)(ip + 1)]; - ++sp; - ip += 2; - MINT_IN_BREAK; - } - MINT_IN_CASE(MINT_LDVIRTFTN) { - RuntimeMethod *m = rtm->data_items [* (guint16 *)(ip + 1)]; - ip += 2; - --sp; - if (!sp->data.p) - THROW_EX (mono_get_exception_null_reference (), ip - 2); - - sp->data.p = get_virtual_method (context->domain, m, sp->data.p); - ++sp; - MINT_IN_BREAK; - } - - MINT_IN_CASE(MINT_LDTHISA) - g_error ("should not happen"); - // sp->data.p = &frame->obj; - ++ip; - ++sp; - MINT_IN_BREAK; - -#define LDARG(datamem, argtype) \ - sp->data.datamem = * (argtype *)(frame->args + * (guint16 *)(ip + 1)); \ - ip += 2; \ - ++sp; - - MINT_IN_CASE(MINT_LDARG_I1) LDARG(i, gint8); MINT_IN_BREAK; - MINT_IN_CASE(MINT_LDARG_U1) LDARG(i, guint8); MINT_IN_BREAK; - MINT_IN_CASE(MINT_LDARG_I2) LDARG(i, gint16); MINT_IN_BREAK; - MINT_IN_CASE(MINT_LDARG_U2) LDARG(i, guint16); MINT_IN_BREAK; - MINT_IN_CASE(MINT_LDARG_I4) LDARG(i, gint32); MINT_IN_BREAK; - MINT_IN_CASE(MINT_LDARG_I8) LDARG(l, gint64); MINT_IN_BREAK; - MINT_IN_CASE(MINT_LDARG_R4) LDARG(f, float); MINT_IN_BREAK; - MINT_IN_CASE(MINT_LDARG_R8) LDARG(f, double); MINT_IN_BREAK; - MINT_IN_CASE(MINT_LDARG_O) LDARG(p, gpointer); MINT_IN_BREAK; - MINT_IN_CASE(MINT_LDARG_P) LDARG(p, gpointer); MINT_IN_BREAK; - - MINT_IN_CASE(MINT_LDARG_VT) - sp->data.p = vt_sp; - i32 = READ32(ip + 2); - memcpy(sp->data.p, frame->args + * (guint16 *)(ip + 1), i32); - vt_sp += (i32 + 7) & ~7; - ip += 4; - ++sp; - MINT_IN_BREAK; - -#define STARG(datamem, argtype) \ - --sp; \ - * (argtype *)(frame->args + * (guint16 *)(ip + 1)) = sp->data.datamem; \ - ip += 2; \ - - MINT_IN_CASE(MINT_STARG_I1) STARG(i, gint8); MINT_IN_BREAK; - MINT_IN_CASE(MINT_STARG_U1) STARG(i, guint8); MINT_IN_BREAK; - MINT_IN_CASE(MINT_STARG_I2) STARG(i, gint16); MINT_IN_BREAK; - MINT_IN_CASE(MINT_STARG_U2) STARG(i, guint16); MINT_IN_BREAK; - MINT_IN_CASE(MINT_STARG_I4) STARG(i, gint32); MINT_IN_BREAK; - MINT_IN_CASE(MINT_STARG_I8) STARG(l, gint64); MINT_IN_BREAK; - MINT_IN_CASE(MINT_STARG_R4) STARG(f, float); MINT_IN_BREAK; - MINT_IN_CASE(MINT_STARG_R8) STARG(f, double); MINT_IN_BREAK; - MINT_IN_CASE(MINT_STARG_O) STARG(p, gpointer); MINT_IN_BREAK; - MINT_IN_CASE(MINT_STARG_P) STARG(p, gpointer); MINT_IN_BREAK; - - MINT_IN_CASE(MINT_STARG_VT) - i32 = READ32(ip + 2); - --sp; - memcpy(frame->args + * (guint16 *)(ip + 1), sp->data.p, i32); - vt_sp -= (i32 + 7) & ~7; - ip += 4; - MINT_IN_BREAK; - -#define STINARG(datamem, argtype) \ - do { \ - int n = * (guint16 *)(ip + 1); \ - * (argtype *)(frame->args + rtm->arg_offsets [n]) = frame->stack_args [n].data.datamem; \ - ip += 2; \ - } while (0) - - MINT_IN_CASE(MINT_STINARG_I1) STINARG(i, gint8); MINT_IN_BREAK; - MINT_IN_CASE(MINT_STINARG_U1) STINARG(i, guint8); MINT_IN_BREAK; - MINT_IN_CASE(MINT_STINARG_I2) STINARG(i, gint16); MINT_IN_BREAK; - MINT_IN_CASE(MINT_STINARG_U2) STINARG(i, guint16); MINT_IN_BREAK; - MINT_IN_CASE(MINT_STINARG_I4) STINARG(i, gint32); MINT_IN_BREAK; - MINT_IN_CASE(MINT_STINARG_I8) STINARG(l, gint64); MINT_IN_BREAK; - MINT_IN_CASE(MINT_STINARG_R4) STINARG(f, float); MINT_IN_BREAK; - MINT_IN_CASE(MINT_STINARG_R8) STINARG(f, double); MINT_IN_BREAK; - MINT_IN_CASE(MINT_STINARG_O) STINARG(p, gpointer); MINT_IN_BREAK; - MINT_IN_CASE(MINT_STINARG_P) STINARG(p, gpointer); MINT_IN_BREAK; - - MINT_IN_CASE(MINT_STINARG_VT) { - int n = * (guint16 *)(ip + 1); - i32 = READ32(ip + 2); - memcpy (frame->args + rtm->arg_offsets [n], frame->stack_args [n].data.p, i32); - ip += 4; - MINT_IN_BREAK; - } - - MINT_IN_CASE(MINT_LDARGA) - sp->data.p = frame->args + * (guint16 *)(ip + 1); - ip += 2; - ++sp; - MINT_IN_BREAK; - -#define LDLOC(datamem, argtype) \ - sp->data.datamem = * (argtype *)(locals + * (guint16 *)(ip + 1)); \ - ip += 2; \ - ++sp; - - MINT_IN_CASE(MINT_LDLOC_I1) LDLOC(i, gint8); MINT_IN_BREAK; - MINT_IN_CASE(MINT_LDLOC_U1) LDLOC(i, guint8); MINT_IN_BREAK; - MINT_IN_CASE(MINT_LDLOC_I2) LDLOC(i, gint16); MINT_IN_BREAK; - MINT_IN_CASE(MINT_LDLOC_U2) LDLOC(i, guint16); MINT_IN_BREAK; - MINT_IN_CASE(MINT_LDLOC_I4) LDLOC(i, gint32); MINT_IN_BREAK; - MINT_IN_CASE(MINT_LDLOC_I8) LDLOC(l, gint64); MINT_IN_BREAK; - MINT_IN_CASE(MINT_LDLOC_R4) LDLOC(f, float); MINT_IN_BREAK; - MINT_IN_CASE(MINT_LDLOC_R8) LDLOC(f, double); MINT_IN_BREAK; - MINT_IN_CASE(MINT_LDLOC_O) LDLOC(p, gpointer); MINT_IN_BREAK; - MINT_IN_CASE(MINT_LDLOC_P) LDLOC(p, gpointer); MINT_IN_BREAK; - - MINT_IN_CASE(MINT_LDLOC_VT) - sp->data.p = vt_sp; - i32 = READ32(ip + 2); - memcpy(sp->data.p, locals + * (guint16 *)(ip + 1), i32); - vt_sp += (i32 + 7) & ~7; - ip += 4; - ++sp; - MINT_IN_BREAK; - - MINT_IN_CASE(MINT_LDLOCA_S) - sp->data.p = locals + * (guint16 *)(ip + 1); - ip += 2; - ++sp; - MINT_IN_BREAK; - -#define STLOC(datamem, argtype) \ - --sp; \ - * (argtype *)(locals + * (guint16 *)(ip + 1)) = sp->data.datamem; \ - ip += 2; - - MINT_IN_CASE(MINT_STLOC_I1) STLOC(i, gint8); MINT_IN_BREAK; - MINT_IN_CASE(MINT_STLOC_U1) STLOC(i, guint8); MINT_IN_BREAK; - MINT_IN_CASE(MINT_STLOC_I2) STLOC(i, gint16); MINT_IN_BREAK; - MINT_IN_CASE(MINT_STLOC_U2) STLOC(i, guint16); MINT_IN_BREAK; - MINT_IN_CASE(MINT_STLOC_I4) STLOC(i, gint32); MINT_IN_BREAK; - MINT_IN_CASE(MINT_STLOC_I8) STLOC(l, gint64); MINT_IN_BREAK; - MINT_IN_CASE(MINT_STLOC_R4) STLOC(f, float); MINT_IN_BREAK; - MINT_IN_CASE(MINT_STLOC_R8) STLOC(f, double); MINT_IN_BREAK; - MINT_IN_CASE(MINT_STLOC_O) STLOC(p, gpointer); MINT_IN_BREAK; - MINT_IN_CASE(MINT_STLOC_P) STLOC(p, gpointer); MINT_IN_BREAK; - -#define STLOC_NP(datamem, argtype) \ - * (argtype *)(locals + * (guint16 *)(ip + 1)) = sp [-1].data.datamem; \ - ip += 2; - - MINT_IN_CASE(MINT_STLOC_NP_I4) STLOC_NP(i, gint32); MINT_IN_BREAK; - MINT_IN_CASE(MINT_STLOC_NP_O) STLOC_NP(p, gpointer); MINT_IN_BREAK; - - MINT_IN_CASE(MINT_STLOC_VT) - i32 = READ32(ip + 2); - --sp; - memcpy(locals + * (guint16 *)(ip + 1), sp->data.p, i32); - vt_sp -= (i32 + 7) & ~7; - ip += 4; - MINT_IN_BREAK; - - MINT_IN_CASE(MINT_LOCALLOC) - if (sp != frame->stack + 1) /*FIX?*/ - THROW_EX (mono_get_exception_execution_engine (NULL), ip); - sp [-1].data.p = alloca (sp [-1].data.i); - ++ip; - MINT_IN_BREAK; -#if 0 - MINT_IN_CASE(MINT_ENDFILTER) ves_abort(); MINT_IN_BREAK; -#endif - MINT_IN_CASE(MINT_INITOBJ) - --sp; - memset (sp->data.vt, 0, READ32(ip + 1)); - ip += 3; - MINT_IN_BREAK; - MINT_IN_CASE(MINT_CPBLK) - sp -= 3; - if (!sp [0].data.p || !sp [1].data.p) - THROW_EX (mono_get_exception_null_reference(), ip - 1); - ++ip; - /* FIXME: value and size may be int64... */ - memcpy (sp [0].data.p, sp [1].data.p, sp [2].data.i); - MINT_IN_BREAK; -#if 0 - MINT_IN_CASE(MINT_CONSTRAINED_) { - guint32 token; - /* FIXME: implement */ - ++ip; - token = READ32 (ip); - ip += 2; - MINT_IN_BREAK; - } -#endif - MINT_IN_CASE(MINT_INITBLK) - sp -= 3; - if (!sp [0].data.p) - THROW_EX (mono_get_exception_null_reference(), ip - 1); - ++ip; - /* FIXME: value and size may be int64... */ - memset (sp [0].data.p, sp [1].data.i, sp [2].data.i); - MINT_IN_BREAK; -#if 0 - MINT_IN_CASE(MINT_NO_) - /* FIXME: implement */ - ip += 2; - MINT_IN_BREAK; -#endif - MINT_IN_CASE(MINT_RETHROW) - /* - * need to clarify what this should actually do: - * start the search from the last found handler in - * this method or continue in the caller or what. - * Also, do we need to run finally/fault handlers after a retrow? - * Well, this implementation will follow the usual search - * for an handler, considering the current ip as throw spot. - * We need to NULL frame->ex_handler for the later code to - * actually run the new found handler. - */ - frame->ex_handler = NULL; - THROW_EX (frame->ex, ip - 1); - MINT_IN_BREAK; - MINT_IN_DEFAULT - g_print ("Unimplemented opcode: %04x %s at 0x%x\n", *ip, mono_interp_opname[*ip], ip-rtm->code); - THROW_EX (mono_get_exception_execution_engine ("Unimplemented opcode"), ip); - } - } - - g_assert_not_reached (); - /* - * Exception handling code. - * The exception object is stored in frame->ex. - */ - - handle_exception: - { - int i; - guint32 ip_offset; - MonoInvocation *inv; - MonoExceptionClause *clause; - /*char *message;*/ - MonoObject *ex_obj; - -#if DEBUG_INTERP - if (tracing) - g_print ("* Handling exception '%s' at IL_%04x\n", - frame->ex == NULL ? "** Unknown **" : mono_object_class (frame->ex)->name, - rtm == NULL ? 0 : frame->ip - rtm->code); -#endif - if (die_on_exception) - goto die_on_ex; - - for (inv = frame; inv; inv = inv->parent) { - MonoMethod *method; - if (inv->runtime_method == NULL) - continue; - method = inv->runtime_method->method; - if (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) - continue; - if (method->iflags & (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL | METHOD_IMPL_ATTRIBUTE_RUNTIME)) - continue; - if (inv->ip == NULL) - continue; - ip_offset = inv->ip - inv->runtime_method->code; - inv->ex_handler = NULL; /* clear this in case we are trhowing an exception while handling one - this one wins */ - for (i = 0; i < inv->runtime_method->num_clauses; ++i) { - clause = &inv->runtime_method->clauses [i]; - if (clause->flags <= 1 && MONO_OFFSET_IN_CLAUSE (clause, ip_offset)) { - if (!clause->flags) { - MonoObject *isinst_obj = mono_object_isinst_checked ((MonoObject*)frame->ex, clause->data.catch_class, &error); - mono_error_cleanup (&error); /* FIXME: don't swallow the error */ - if (isinst_obj) { - /* - * OK, we found an handler, now we need to execute the finally - * and fault blocks before branching to the handler code. - */ - inv->ex_handler = clause; -#if DEBUG_INTERP - if (tracing) - g_print ("* Found handler at '%s'\n", method->name); -#endif - goto handle_finally; - } - } else { - /* FIXME: handle filter clauses */ - g_assert (0); - } - } - } - } - /* - * If we get here, no handler was found: print a stack trace. - */ - for (inv = frame; inv; inv = inv->parent) { - if (inv->invoke_trap) - goto handle_finally; - } -die_on_ex: - ex_obj = (MonoObject*)frame->ex; - mono_unhandled_exception (ex_obj); - exit (1); - } - handle_finally: - { - int i; - guint32 ip_offset; - MonoExceptionClause *clause; - GSList *old_list = finally_ips; - MonoMethod *method = frame->runtime_method->method; - MonoMethodHeader *header = mono_method_get_header_checked (method, &error); - mono_error_cleanup (&error); /* FIXME: don't swallow the error */ - -#if DEBUG_INTERP - if (tracing) - g_print ("* Handle finally IL_%04x\n", endfinally_ip == NULL ? 0 : endfinally_ip - rtm->code); -#endif - if (rtm == NULL || (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) - || (method->iflags & (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL | METHOD_IMPL_ATTRIBUTE_RUNTIME))) { - goto exit_frame; - } - ip_offset = frame->ip - rtm->code; - - if (endfinally_ip != NULL) - finally_ips = g_slist_prepend(finally_ips, (void *)endfinally_ip); - for (i = 0; i < header->num_clauses; ++i) - if (frame->ex_handler == &rtm->clauses [i]) - break; - while (i > 0) { - --i; - clause = &rtm->clauses [i]; - if (MONO_OFFSET_IN_CLAUSE (clause, ip_offset) && (endfinally_ip == NULL || !(MONO_OFFSET_IN_CLAUSE (clause, endfinally_ip - rtm->code)))) { - if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY) { - ip = rtm->code + clause->handler_offset; - finally_ips = g_slist_prepend (finally_ips, (gpointer) ip); -#if DEBUG_INTERP - if (tracing) - g_print ("* Found finally at IL_%04x with exception: %s\n", clause->handler_offset, frame->ex? "yes": "no"); -#endif - } - } - } - - endfinally_ip = NULL; - - if (old_list != finally_ips && finally_ips) { - ip = finally_ips->data; - finally_ips = g_slist_remove (finally_ips, ip); - sp = frame->stack; /* spec says stack should be empty at endfinally so it should be at the start too */ - goto main_loop; - } - - /* - * If an exception is set, we need to execute the fault handler, too, - * otherwise, we continue normally. - */ - if (frame->ex) - goto handle_fault; - ves_abort(); - } - handle_fault: - { - int i; - guint32 ip_offset; - MonoExceptionClause *clause; - MonoMethod *method = frame->runtime_method->method; - MonoMethodHeader *header = mono_method_get_header_checked (method, &error); - mono_error_cleanup (&error); /* FIXME: don't swallow the error */ - -#if DEBUG_INTERP - if (tracing) - g_print ("* Handle fault\n"); -#endif - ip_offset = frame->ip - rtm->code; - for (i = 0; i < header->num_clauses; ++i) { - clause = &rtm->clauses [i]; - if (clause->flags == MONO_EXCEPTION_CLAUSE_FAULT && MONO_OFFSET_IN_CLAUSE (clause, ip_offset)) { - ip = rtm->code + clause->handler_offset; -#if DEBUG_INTERP - if (tracing) - g_print ("* Executing handler at IL_%04x\n", clause->handler_offset); -#endif - goto main_loop; - } - } - /* - * If the handler for the exception was found in this method, we jump - * to it right away, otherwise we return and let the caller run - * the finally, fault and catch blocks. - * This same code should be present in the endfault opcode, but it - * is corrently not assigned in the ECMA specs: LAMESPEC. - */ - if (frame->ex_handler) { -#if DEBUG_INTERP - if (tracing) - g_print ("* Executing handler at IL_%04x\n", frame->ex_handler->handler_offset); -#endif - ip = rtm->code + frame->ex_handler->handler_offset; - sp = frame->stack; - vt_sp = (unsigned char *) sp + rtm->stack_size; - sp->data.p = frame->ex; - ++sp; - goto main_loop; - } - goto exit_frame; - } -exit_frame: - DEBUG_LEAVE (); -} - -void -ves_exec_method (MonoInvocation *frame) -{ - ThreadContext *context = mono_native_tls_get_value (thread_context_id); - ThreadContext context_struct; - MonoError error; - jmp_buf env; - - frame->ex = NULL; - - if (setjmp(env)) { - mono_unhandled_exception ((MonoObject*)frame->ex); - return; - } - if (context == NULL) { - context = &context_struct; - context_struct.domain = mono_domain_get (); - context_struct.base_frame = frame; - context_struct.current_frame = NULL; - context_struct.env_frame = frame; - context_struct.current_env = &env; - context_struct.search_for_handler = 0; - context_struct.managed_code = 0; - mono_native_tls_set_value (thread_context_id, context); - } - frame->ip = NULL; - frame->parent = context->current_frame; - frame->runtime_method = mono_interp_get_runtime_method (context->domain, frame->method, &error); - mono_error_cleanup (&error); /* FIXME: don't swallow the error */ - context->managed_code = 1; - ves_exec_method_with_context (frame, context); - context->managed_code = 0; - if (frame->ex) { - if (context != &context_struct && context->current_env) { - context->env_frame->ex = frame->ex; - longjmp (*context->current_env, 1); - } - else - mono_unhandled_exception ((MonoObject*)frame->ex); - } - if (context->base_frame == frame) - mono_native_tls_set_value (thread_context_id, NULL); - else - context->current_frame = frame->parent; -} - -static int -ves_exec (MonoDomain *domain, MonoAssembly *assembly, int argc, char *argv[]) -{ - MonoImage *image = mono_assembly_get_image (assembly); - MonoMethod *method; - MonoError error; - int rval; - - method = mono_get_method_checked (image, mono_image_get_entry_point (image), NULL, NULL, &error); - mono_error_cleanup (&error); /* FIXME: don't swallow the error */ - - if (!method) - g_error ("No entry point method found in %s", mono_image_get_filename (image)); - - rval = mono_runtime_run_main_checked (method, argc, argv, &error); - mono_error_cleanup (&error); /* FIXME: don't swallow the error */ - return rval; -} - -static void -usage (void) -{ - fprintf (stderr, - "mint %s, the Mono ECMA CLI interpreter, (C) 2001, 2002 Ximian, Inc.\n\n" - "Usage is: mint [options] executable args...\n\n", VERSION); - fprintf (stderr, - "Runtime Debugging:\n" -#ifdef DEBUG_INTERP - " --debug\n" -#endif - " --dieonex\n" - " --noptr\t\t\tdon't print pointer addresses in trace output\n" - " --opcode-count\n" - " --print-vtable\n" - " --traceclassinit\n" - "\n" - "Development:\n" - " --debug method_name\n" - " --profile\n" - " --trace\n" - " --traceops\n" - " --regression\n" - "\n" - "Runtime:\n" - " --config filename load the specified config file instead of the default\n" - " --workers n maximum number of worker threads\n" - ); - exit (1); -} - -static MonoBoolean -interp_ves_icall_get_frame_info (gint32 skip, MonoBoolean need_file_info, - MonoReflectionMethod **method, - gint32 *iloffset, gint32 *native_offset, - MonoString **file, gint32 *line, gint32 *column) -{ - ThreadContext *context = mono_native_tls_get_value (thread_context_id); - MonoInvocation *inv = context->current_frame; - MonoError error; - int i; - - for (i = 0; inv && i < skip; inv = inv->parent) - if (inv->runtime_method != NULL) - ++i; - - if (iloffset) - *iloffset = 0; - if (native_offset) - *native_offset = 0; - if (method) { - if (inv == NULL) { - *method = NULL; - } else { - *method = mono_method_get_object_checked (context->domain, inv->runtime_method->method, NULL, &error); - mono_error_cleanup (&error); /* FIXME: don't swallow the error */ - } - } - if (line) - *line = 0; - if (need_file_info) { - if (column) - *column = 0; - if (file) - *file = mono_string_new (mono_domain_get (), "unknown"); - } - - return TRUE; -} - -static MonoArray * -interp_ves_icall_get_trace (MonoException *exc, gint32 skip, MonoBoolean need_file_info) -{ - MonoDomain *domain = mono_domain_get (); - MonoArray *res; - MonoArray *ta = exc->trace_ips; - MonoError error; - int i, len; - - if (ta == NULL) { - /* Exception is not thrown yet */ - MonoArray *array = mono_array_new_checked (domain, mono_defaults.stack_frame_class, 0, &error); - mono_error_cleanup (&error); /* FIXME: don't swallow the error */ - return array; - } - - len = mono_array_length (ta); - - res = mono_array_new_checked (domain, mono_defaults.stack_frame_class, len > skip ? len - skip : 0, &error); - mono_error_cleanup (&error); /* FIXME: don't swallow the error */ - - for (i = skip; i < len / 2; i++) { - MonoStackFrame *sf = (MonoStackFrame *)mono_object_new_checked (domain, mono_defaults.stack_frame_class, &error); - mono_error_cleanup (&error); /* FIXME: don't swallow the error */ - gushort *ip = mono_array_get (ta, gpointer, 2 * i + 1); - RuntimeMethod *rtm = mono_array_get (ta, gpointer, 2 * i); - - if (rtm != NULL) { - sf->method = mono_method_get_object_checked (domain, rtm->method, NULL, &error); - mono_error_cleanup (&error); /* FIXME: don't swallow the error */ - sf->native_offset = ip - rtm->code; - } - -#if 0 - sf->il_offset = mono_debug_il_offset_from_address (ji->method, sf->native_offset, domain); - - if (need_file_info) { - gchar *filename; - - filename = mono_debug_source_location_from_address (ji->method, sf->native_offset, &sf->line, domain); - - sf->filename = filename? mono_string_new (domain, filename): NULL; - sf->column = 0; - - g_free (filename); - } -#endif - - mono_array_set (res, gpointer, i, sf); - } - - return res; -} - -void -mono_interp_init () -{ - mono_native_tls_alloc (&thread_context_id, NULL); - mono_native_tls_set_value (thread_context_id, NULL); - mono_os_mutex_init_recursive (&runtime_method_lookup_section); - mono_os_mutex_init_recursive (&create_method_pointer_mutex); - - mono_interp_transform_init (); -} - -typedef int (*TestMethod) (void); - -static void -interp_regression_step (MonoImage *image, int verbose, int *total_run, int *total, GTimer *timer, MonoDomain *domain) -{ - int result, expected, failed, cfailed, run; - double elapsed, transform_time; - int i; - MonoObject *result_obj; - static gboolean filter_method_init = FALSE; - static const char *filter_method = NULL; - - g_print ("Test run: image=%s\n", mono_image_get_filename (image)); - cfailed = failed = run = 0; - transform_time = elapsed = 0.0; - -#if 0 - /* fixme: ugly hack - delete all previously compiled methods */ - if (domain_jit_info (domain)) { - g_hash_table_destroy (domain_jit_info (domain)->jit_trampoline_hash); - domain_jit_info (domain)->jit_trampoline_hash = g_hash_table_new (mono_aligned_addr_hash, NULL); - mono_internal_hash_table_destroy (&(domain->jit_code_hash)); - mono_jit_code_hash_init (&(domain->jit_code_hash)); - } -#endif - - g_timer_start (timer); - for (i = 0; i < mono_image_get_table_rows (image, MONO_TABLE_METHOD); ++i) { - MonoObject *exc = NULL; - MonoError error; - MonoMethod *method = mono_get_method_checked (image, MONO_TOKEN_METHOD_DEF | (i + 1), NULL, NULL, &error); - if (!method) { - mono_error_cleanup (&error); /* FIXME don't swallow the error */ - continue; - } - - if (!filter_method_init) { - filter_method = g_getenv ("INTERP_FILTER_METHOD"); - filter_method_init = TRUE; - } - gboolean filter = FALSE; - if (filter_method) { - const char *name = filter_method; - - if ((strchr (name, '.') > name) || strchr (name, ':')) { - MonoMethodDesc *desc = mono_method_desc_new (name, TRUE); - filter = mono_method_desc_full_match (desc, method); - mono_method_desc_free (desc); - } else { - filter = strcmp (method->name, name) == 0; - } - } else { /* no filter, check for `Category' attribute on method */ - filter = TRUE; - MonoCustomAttrInfo* ainfo = mono_custom_attrs_from_method_checked (method, &error); - mono_error_cleanup (&error); - - if (ainfo) { - int j; - for (j = 0; j < ainfo->num_attrs && filter; ++j) { - MonoCustomAttrEntry *centry = &ainfo->attrs [j]; - if (centry->ctor == NULL) - continue; - - MonoClass *klass = centry->ctor->klass; - if (strcmp (klass->name, "CategoryAttribute")) - continue; - - MonoObject *obj = mono_custom_attrs_get_attr_checked (ainfo, klass, &error); - /* FIXME: there is an ordering problem if there're multiple attributes, do this instead: - * MonoObject *obj = create_custom_attr (ainfo->image, centry->ctor, centry->data, centry->data_size, &error); */ - mono_error_cleanup (&error); - MonoMethod *getter = mono_class_get_method_from_name (klass, "get_Category", -1); - MonoObject *str = mono_interp_runtime_invoke (getter, obj, NULL, &exc, &error); - mono_error_cleanup (&error); - char *utf8_str = mono_string_to_utf8_checked ((MonoString *) str, &error); - mono_error_cleanup (&error); - if (!strcmp (utf8_str, "!INTERPRETER")) { - g_print ("skip %s...\n", method->name); - filter = FALSE; - } - } - } - } - if (strncmp (method->name, "test_", 5) == 0 && filter) { - MonoError interp_error; - MonoObject *exc = NULL; - - result_obj = mono_interp_runtime_invoke (method, NULL, NULL, &exc, &interp_error); - if (!mono_error_ok (&interp_error)) { - cfailed++; - g_print ("Test '%s' execution failed.\n", method->name); - } else if (exc != NULL) { - g_print ("Exception in Test '%s' occured:\n", method->name); - mono_object_describe (exc); - run++; - failed++; - } else { - result = *(gint32 *) mono_object_unbox (result_obj); - expected = atoi (method->name + 5); // FIXME: oh no. - run++; - - if (result != expected) { - failed++; - g_print ("Test '%s' failed result (got %d, expected %d).\n", method->name, result, expected); - } - } - } - } - g_timer_stop (timer); - elapsed = g_timer_elapsed (timer, NULL); - if (failed > 0 || cfailed > 0){ - g_print ("Results: total tests: %d, failed: %d, cfailed: %d (pass: %.2f%%)\n", - run, failed, cfailed, 100.0*(run-failed-cfailed)/run); - } else { - g_print ("Results: total tests: %d, all pass \n", run); - } - - g_print ("Elapsed time: %f secs (%f, %f)\n\n", elapsed, - elapsed - transform_time, transform_time); - *total += failed + cfailed; - *total_run += run; -} -static int -interp_regression (MonoImage *image, int verbose, int *total_run) -{ - MonoMethod *method; - GTimer *timer = g_timer_new (); - MonoDomain *domain = mono_domain_get (); - guint32 i; - int total; - - /* load the metadata */ - for (i = 0; i < mono_image_get_table_rows (image, MONO_TABLE_METHOD); ++i) { - MonoError error; - method = mono_get_method_checked (image, MONO_TOKEN_METHOD_DEF | (i + 1), NULL, NULL, &error); - if (!method) { - mono_error_cleanup (&error); - continue; - } - mono_class_init (method->klass); - } - - total = 0; - *total_run = 0; - interp_regression_step (image, verbose, total_run, &total, timer, domain); - - g_timer_destroy (timer); - return total; -} - -int -mono_interp_regression_list (int verbose, int count, char *images []) -{ - int i, total, total_run, run; - - total_run = total = 0; - for (i = 0; i < count; ++i) { - MonoAssembly *ass = mono_assembly_open (images [i], NULL); - if (!ass) { - g_warning ("failed to load assembly: %s", images [i]); - continue; - } - total += interp_regression (mono_assembly_get_image (ass), verbose, &run); - total_run += run; - } - if (total > 0) { - g_print ("Overall results: tests: %d, failed: %d (pass: %.2f%%)\n", total_run, total, 100.0*(total_run-total)/total_run); - } else { - g_print ("Overall results: tests: %d, 100%% pass\n", total_run); - } - - return total; -} - diff --git a/mono/mini/interpreter/interp.h b/mono/mini/interpreter/interp.h deleted file mode 100644 index 59428a882f2..00000000000 --- a/mono/mini/interpreter/interp.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef __MONO_MINI_INTERPRETER_H__ -#define __MONO_MINI_INTERPRETER_H__ -#include - -int -mono_interp_regression_list (int verbose, int count, char *images []); - -void -mono_interp_init (void); - -gpointer -mono_interp_create_method_pointer (MonoMethod *method, MonoError *error); - -MonoObject* -mono_interp_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError *error); - -void -mono_interp_init_delegate (MonoDelegate *del); - -void -interp_walk_stack_with_ctx (MonoInternalStackWalk func, MonoContext *ctx, MonoUnwindOptions options, void *user_data); -#endif /* __MONO_MINI_INTERPRETER_H__ */ diff --git a/mono/mini/interpreter/mintops.c b/mono/mini/interpreter/mintops.c deleted file mode 100644 index 5b4d69269e8..00000000000 --- a/mono/mini/interpreter/mintops.c +++ /dev/null @@ -1,120 +0,0 @@ -/* - * Utilities for handling interpreter VM instructions - * - * Authors: - * Bernie Solomon (bernard@ugsolutions.com) - * - */ -#include -#include -#include "mintops.h" - -#define OPDEF(a,b,c,d) \ - b, -const char *mono_interp_opname[] = { -#include "mintops.def" - "" -}; -#undef OPDEF - -#define OPDEF(a,b,c,d) \ - c, -unsigned char mono_interp_oplen[] = { -#include "mintops.def" - 0 -}; -#undef OPDEF - - -#define OPDEF(a,b,c,d) \ - d, -MintOpArgType mono_interp_opargtype[] = { -#include "mintops.def" - 0 -}; -#undef OPDEF - -const guint16 * -mono_interp_dis_mintop(const guint16 *base, const guint16 *ip) -{ - int len = mono_interp_oplen [*ip]; - guint32 token; - int target; - if (len < 0 || len > 10) { - g_print ("op %d len %d\n", *ip, len); - g_assert_not_reached (); - } else if (len == 0) { /* SWITCH */ - int n = READ32 (ip + 1); - len = 3 + n * 2; - } - - g_print ("IL_%04x: %-10s", ip - base, mono_interp_opname [*ip]); - switch (mono_interp_opargtype [*ip]) { - case MintOpNoArgs: - break; - case MintOpUShortInt: - g_print (" %u", * (guint16 *)(ip + 1)); - break; - case MintOpTwoShorts: - g_print (" %u,%u", * (guint16 *)(ip + 1), * (guint16 *)(ip + 2)); - break; - case MintOpShortAndInt: - g_print (" %u,%u", * (guint16 *)(ip + 1), (guint32)READ32(ip + 2)); - break; - case MintOpShortInt: - g_print (" %d", * (short *)(ip + 1)); - break; - case MintOpClassToken: - case MintOpMethodToken: - case MintOpFieldToken: - token = * (guint16 *)(ip + 1); - g_print (" %u", token); - break; - case MintOpInt: - g_print (" %d", (gint32)READ32 (ip + 1)); - break; - case MintOpLongInt: - g_print (" %lld", (gint64)READ64 (ip + 1)); - break; - case MintOpFloat: { - gint32 tmp = READ32 (ip + 1); - g_print (" %g", * (float *)&tmp); - break; - } - case MintOpDouble: { - gint64 tmp = READ64 (ip + 1); - g_print (" %g", * (double *)&tmp); - break; - } - case MintOpShortBranch: - target = ip + * (short *)(ip + 1) - base; - g_print (" IL_%04x", target); - break; - case MintOpBranch: - target = ip + (gint32)READ32 (ip + 1) - base; - g_print (" IL_%04x", target); - break; - case MintOpSwitch: { - const guint16 *p = ip + 1; - int sval = (gint32)READ32 (p); - int i; - p += 2; - g_print ("("); - for (i = 0; i < sval; ++i) { - int offset; - if (i > 0) - g_print (", "); - offset = (gint32)READ32 (p); - g_print ("IL_%04x", ip - base + 3 + 2 * sval + offset); - p += 2; - } - g_print (")"); - break; - } - default: - g_print("unknown arg type\n"); - } - - return ip + len; -} - diff --git a/mono/mini/interpreter/mintops.def b/mono/mini/interpreter/mintops.def deleted file mode 100644 index 54c5422b27e..00000000000 --- a/mono/mini/interpreter/mintops.def +++ /dev/null @@ -1,506 +0,0 @@ -/* - * Definitions of VM instructions executed by interp.c - * - * Authors: - * Bernie Solomon (bernard@ugsolutions.com) - * - */ - -/* OPDEF (opsymbol, opstring, oplength, optype) */ - -OPDEF(MINT_NOP, "nop", 1, MintOpNoArgs) -OPDEF(MINT_BREAK, "break", 1, MintOpNoArgs) -OPDEF(MINT_LDNULL, "ldnull", 1, MintOpNoArgs) -OPDEF(MINT_DUP, "dup", 1, MintOpNoArgs) -OPDEF(MINT_DUP_VT, "dup.vt", 3, MintOpInt) -OPDEF(MINT_POP, "pop", 2, MintOpShortInt) - -OPDEF(MINT_RET, "ret", 1, MintOpNoArgs) -OPDEF(MINT_RET_VOID, "ret.void", 1, MintOpNoArgs) -OPDEF(MINT_RET_VT, "ret.vt", 3, MintOpInt) - -OPDEF(MINT_VTRESULT, "vtresult", 4, MintOpShortAndInt) /*FIX should be unsigned*/ - -OPDEF(MINT_LDC_I4_M1, "ldc.i4.m1", 1, MintOpNoArgs) -OPDEF(MINT_LDC_I4_0, "ldc.i4.0", 1, MintOpNoArgs) -OPDEF(MINT_LDC_I4_1, "ldc.i4.1", 1, MintOpNoArgs) -OPDEF(MINT_LDC_I4_2, "ldc.i4.2", 1, MintOpNoArgs) -OPDEF(MINT_LDC_I4_3, "ldc.i4.3", 1, MintOpNoArgs) -OPDEF(MINT_LDC_I4_4, "ldc.i4.4", 1, MintOpNoArgs) -OPDEF(MINT_LDC_I4_5, "ldc.i4.5", 1, MintOpNoArgs) -OPDEF(MINT_LDC_I4_6, "ldc.i4.6", 1, MintOpNoArgs) -OPDEF(MINT_LDC_I4_7, "ldc.i4.7", 1, MintOpNoArgs) -OPDEF(MINT_LDC_I4_8, "ldc.i4.8", 1, MintOpNoArgs) - -OPDEF(MINT_LDC_I4_S, "ldc.i4.s", 2, MintOpShortInt) -OPDEF(MINT_LDC_I4, "ldc.i4", 3, MintOpInt) -OPDEF(MINT_LDC_I8, "ldc.i8", 5, MintOpLongInt) - -OPDEF(MINT_LDC_R4, "ldc.r4", 3, MintOpFloat) -OPDEF(MINT_LDC_R8, "ldc.r8", 5, MintOpDouble) - -OPDEF(MINT_LDARG_I1, "ldarg.i1", 2, MintOpUShortInt) -OPDEF(MINT_LDARG_U1, "ldarg.u1", 2, MintOpUShortInt) -OPDEF(MINT_LDARG_I2, "ldarg.i2", 2, MintOpUShortInt) -OPDEF(MINT_LDARG_U2, "ldarg.u2", 2, MintOpUShortInt) -OPDEF(MINT_LDARG_I4, "ldarg.i4", 2, MintOpUShortInt) -OPDEF(MINT_LDARG_I8, "ldarg.i8", 2, MintOpUShortInt) -OPDEF(MINT_LDARG_R4, "ldarg.r4", 2, MintOpUShortInt) -OPDEF(MINT_LDARG_R8, "ldarg.r8", 2, MintOpUShortInt) -OPDEF(MINT_LDARG_O, "ldarg.o", 2, MintOpUShortInt) -OPDEF(MINT_LDARG_P, "ldarg.p", 2, MintOpUShortInt) -OPDEF(MINT_LDARG_VT, "ldarg.vt", 4, MintOpShortAndInt) - -OPDEF(MINT_STARG_I1, "starg.i1", 2, MintOpUShortInt) -OPDEF(MINT_STARG_U1, "starg.u1", 2, MintOpUShortInt) -OPDEF(MINT_STARG_I2, "starg.i2", 2, MintOpUShortInt) -OPDEF(MINT_STARG_U2, "starg.u2", 2, MintOpUShortInt) -OPDEF(MINT_STARG_I4, "starg.i4", 2, MintOpUShortInt) -OPDEF(MINT_STARG_I8, "starg.i8", 2, MintOpUShortInt) -OPDEF(MINT_STARG_R4, "starg.r4", 2, MintOpUShortInt) -OPDEF(MINT_STARG_R8, "starg.r8", 2, MintOpUShortInt) -OPDEF(MINT_STARG_O, "starg.o", 2, MintOpUShortInt) -OPDEF(MINT_STARG_P, "starg.p", 2, MintOpUShortInt) -OPDEF(MINT_STARG_VT, "starg.vt", 4, MintOpShortAndInt) - -OPDEF(MINT_STINARG_I1, "stinarg.i1", 2, MintOpUShortInt) -OPDEF(MINT_STINARG_U1, "stinarg.u1", 2, MintOpUShortInt) -OPDEF(MINT_STINARG_I2, "stinarg.i2", 2, MintOpUShortInt) -OPDEF(MINT_STINARG_U2, "stinarg.u2", 2, MintOpUShortInt) -OPDEF(MINT_STINARG_I4, "stinarg.i4", 2, MintOpUShortInt) -OPDEF(MINT_STINARG_I8, "stinarg.i8", 2, MintOpUShortInt) -OPDEF(MINT_STINARG_R4, "stinarg.r4", 2, MintOpUShortInt) -OPDEF(MINT_STINARG_R8, "stinarg.r8", 2, MintOpUShortInt) -OPDEF(MINT_STINARG_O, "stinarg.o", 2, MintOpUShortInt) -OPDEF(MINT_STINARG_P, "stinarg.p", 2, MintOpUShortInt) -OPDEF(MINT_STINARG_VT, "stinarg.vt", 4, MintOpShortAndInt) - -OPDEF(MINT_LDARGA, "ldarga", 2, MintOpUShortInt) -OPDEF(MINT_LDTHISA, "ldthisa", 1, MintOpNoArgs) - -OPDEF(MINT_LDFLD_I1, "ldfld.i1", 2, MintOpUShortInt) -OPDEF(MINT_LDFLD_U1, "ldfld.u1", 2, MintOpUShortInt) -OPDEF(MINT_LDFLD_I2, "ldfld.i2", 2, MintOpUShortInt) -OPDEF(MINT_LDFLD_U2, "ldfld.u2", 2, MintOpUShortInt) -OPDEF(MINT_LDFLD_I4, "ldfld.i4", 2, MintOpUShortInt) -OPDEF(MINT_LDFLD_I8, "ldfld.i8", 2, MintOpUShortInt) -OPDEF(MINT_LDFLD_R4, "ldfld.r4", 2, MintOpUShortInt) -OPDEF(MINT_LDFLD_R8, "ldfld.r8", 2, MintOpUShortInt) -OPDEF(MINT_LDFLD_O, "ldfld.o", 2, MintOpUShortInt) -OPDEF(MINT_LDFLD_P, "ldfld.p", 2, MintOpUShortInt) -OPDEF(MINT_LDFLD_VT, "ldfld.vt", 4, MintOpShortAndInt) - -OPDEF(MINT_LDRMFLD, "ldrmfld", 2, MintOpFieldToken) -OPDEF(MINT_LDRMFLD_VT, "ldrmfld.vt", 4, MintOpShortAndInt) - -OPDEF(MINT_LDFLDA, "ldflda", 2, MintOpUShortInt) - -OPDEF(MINT_STFLD_I1, "stfld.i1", 2, MintOpUShortInt) -OPDEF(MINT_STFLD_U1, "stfld.u1", 2, MintOpUShortInt) -OPDEF(MINT_STFLD_I2, "stfld.i2", 2, MintOpUShortInt) -OPDEF(MINT_STFLD_U2, "stfld.u2", 2, MintOpUShortInt) -OPDEF(MINT_STFLD_I4, "stfld.i4", 2, MintOpUShortInt) -OPDEF(MINT_STFLD_I8, "stfld.i8", 2, MintOpUShortInt) -OPDEF(MINT_STFLD_R4, "stfld.r4", 2, MintOpUShortInt) -OPDEF(MINT_STFLD_R8, "stfld.r8", 2, MintOpUShortInt) -OPDEF(MINT_STFLD_O, "stfld.o", 2, MintOpUShortInt) -OPDEF(MINT_STFLD_P, "stfld.p", 2, MintOpUShortInt) -OPDEF(MINT_STFLD_VT, "stfld.vt", 4, MintOpShortAndInt) - -OPDEF(MINT_STRMFLD, "strmfld", 2, MintOpFieldToken) -OPDEF(MINT_STRMFLD_VT, "strmfld.vt", 4, MintOpShortAndInt) - -OPDEF(MINT_LDSFLD, "ldsfld", 2, MintOpFieldToken) -OPDEF(MINT_LDSFLD_VT, "ldsfld.vt", 4, MintOpShortAndInt) -OPDEF(MINT_STSFLD, "stsfld", 2, MintOpUShortInt) -OPDEF(MINT_STSFLD_VT, "stsfld.vt", 4, MintOpShortAndInt) -OPDEF(MINT_LDSFLDA, "ldsflda", 2, MintOpUShortInt) - -OPDEF(MINT_LDLOC_I1, "ldloc.i1", 2, MintOpUShortInt) -OPDEF(MINT_LDLOC_U1, "ldloc.u1", 2, MintOpUShortInt) -OPDEF(MINT_LDLOC_I2, "ldloc.i2", 2, MintOpUShortInt) -OPDEF(MINT_LDLOC_U2, "ldloc.u2", 2, MintOpUShortInt) -OPDEF(MINT_LDLOC_I4, "ldloc.i4", 2, MintOpUShortInt) -OPDEF(MINT_LDLOC_I8, "ldloc.i8", 2, MintOpUShortInt) -OPDEF(MINT_LDLOC_R4, "ldloc.r4", 2, MintOpUShortInt) -OPDEF(MINT_LDLOC_R8, "ldloc.r8", 2, MintOpUShortInt) -OPDEF(MINT_LDLOC_O, "ldloc.o", 2, MintOpUShortInt) -OPDEF(MINT_LDLOC_P, "ldloc.p", 2, MintOpUShortInt) -OPDEF(MINT_LDLOC_VT, "ldloc.vt", 4, MintOpShortAndInt) - -OPDEF(MINT_STLOC_I1, "stloc.i1", 2, MintOpUShortInt) -OPDEF(MINT_STLOC_U1, "stloc.u1", 2, MintOpUShortInt) -OPDEF(MINT_STLOC_I2, "stloc.i2", 2, MintOpUShortInt) -OPDEF(MINT_STLOC_U2, "stloc.u2", 2, MintOpUShortInt) -OPDEF(MINT_STLOC_I4, "stloc.i4", 2, MintOpUShortInt) -OPDEF(MINT_STLOC_I8, "stloc.i8", 2, MintOpUShortInt) -OPDEF(MINT_STLOC_R4, "stloc.r4", 2, MintOpUShortInt) -OPDEF(MINT_STLOC_R8, "stloc.r8", 2, MintOpUShortInt) -OPDEF(MINT_STLOC_O, "stloc.o", 2, MintOpUShortInt) -OPDEF(MINT_STLOC_P, "stloc.p", 2, MintOpUShortInt) -OPDEF(MINT_STLOC_VT, "stloc.vt", 4, MintOpShortAndInt) - -OPDEF(MINT_STLOC_NP_I4, "stloc.np.i4", 2, MintOpUShortInt) -OPDEF(MINT_STLOC_NP_O, "stloc.np.o", 2, MintOpUShortInt) - -OPDEF(MINT_LDLOCA_S, "ldloca.s", 2, MintOpUShortInt) - -OPDEF(MINT_LDIND_I1, "ldind.i1", 1, MintOpNoArgs) -OPDEF(MINT_LDIND_U1, "ldind.u1", 1, MintOpNoArgs) -OPDEF(MINT_LDIND_I2, "ldind.i2", 1, MintOpNoArgs) -OPDEF(MINT_LDIND_U2, "ldind.u2", 1, MintOpNoArgs) -OPDEF(MINT_LDIND_I4, "ldind.i4", 1, MintOpNoArgs) -OPDEF(MINT_LDIND_U4, "ldind.u4", 1, MintOpNoArgs) -OPDEF(MINT_LDIND_I8, "ldind.i8", 1, MintOpNoArgs) -OPDEF(MINT_LDIND_I, "ldind.i", 2, MintOpUShortInt) -OPDEF(MINT_LDIND_R4, "ldind.r4", 1, MintOpNoArgs) -OPDEF(MINT_LDIND_R8, "ldind.r8", 1, MintOpNoArgs) -OPDEF(MINT_LDIND_REF, "ldind.ref", 1, MintOpNoArgs) -OPDEF(MINT_STIND_I1, "stind.i1", 1, MintOpNoArgs) -OPDEF(MINT_STIND_I2, "stind.i2", 1, MintOpNoArgs) -OPDEF(MINT_STIND_I4, "stind.i4", 1, MintOpNoArgs) -OPDEF(MINT_STIND_I8, "stind.i8", 1, MintOpNoArgs) -OPDEF(MINT_STIND_I, "stind.i", 1, MintOpNoArgs) -OPDEF(MINT_STIND_R4, "stind.r4", 1, MintOpNoArgs) -OPDEF(MINT_STIND_R8, "stind.r8", 1, MintOpNoArgs) -OPDEF(MINT_STIND_REF, "stind.ref", 1, MintOpNoArgs) - -OPDEF(MINT_BR, "br", 3, MintOpBranch) -OPDEF(MINT_LEAVE, "leave", 3, MintOpBranch) -OPDEF(MINT_BR_S, "br.s", 2, MintOpShortBranch) -OPDEF(MINT_LEAVE_S, "leave.s", 2, MintOpShortBranch) - -OPDEF(MINT_THROW, "throw", 1, MintOpNoArgs) -OPDEF(MINT_RETHROW, "rethrow", 1, MintOpNoArgs) -OPDEF(MINT_ENDFINALLY, "endfinally", 1, MintOpNoArgs) - -OPDEF(MINT_BRFALSE_I4, "brfalse.i4", 3, MintOpBranch) -OPDEF(MINT_BRFALSE_I8, "brfalse.i8", 3, MintOpBranch) -OPDEF(MINT_BRFALSE_R8, "brfalse.r8", 3, MintOpBranch) -OPDEF(MINT_BRTRUE_I4, "brtrue.i4", 3, MintOpBranch) -OPDEF(MINT_BRTRUE_I8, "brtrue.i8", 3, MintOpBranch) -OPDEF(MINT_BRTRUE_R8, "brtrue.r8", 3, MintOpBranch) - -OPDEF(MINT_BRFALSE_I4_S, "brfalse.i4.s", 2, MintOpShortBranch) -OPDEF(MINT_BRFALSE_I8_S, "brfalse.i8.s", 2, MintOpShortBranch) -OPDEF(MINT_BRFALSE_R8_S, "brfalse.r8.s", 2, MintOpShortBranch) -OPDEF(MINT_BRTRUE_I4_S, "brtrue.i4.s", 2, MintOpShortBranch) -OPDEF(MINT_BRTRUE_I8_S, "brtrue.i8.s", 2, MintOpShortBranch) -OPDEF(MINT_BRTRUE_R8_S, "brtrue.r8.s", 2, MintOpShortBranch) - -OPDEF(MINT_BEQ_I4, "beq.i4", 3, MintOpBranch) -OPDEF(MINT_BEQ_I8, "beq.i8", 3, MintOpBranch) -OPDEF(MINT_BEQ_R8, "beq.r8", 3, MintOpBranch) -OPDEF(MINT_BGE_I4, "bge.i4", 3, MintOpBranch) -OPDEF(MINT_BGE_I8, "bge.i8", 3, MintOpBranch) -OPDEF(MINT_BGE_R8, "bge.r8", 3, MintOpBranch) -OPDEF(MINT_BGT_I4, "bgt.i4", 3, MintOpBranch) -OPDEF(MINT_BGT_I8, "bgt.i8", 3, MintOpBranch) -OPDEF(MINT_BGT_R8, "bgt.r8", 3, MintOpBranch) -OPDEF(MINT_BLT_I4, "blt.i4", 3, MintOpBranch) -OPDEF(MINT_BLT_I8, "blt.i8", 3, MintOpBranch) -OPDEF(MINT_BLT_R8, "blt.r8", 3, MintOpBranch) -OPDEF(MINT_BLE_I4, "ble.i4", 3, MintOpBranch) -OPDEF(MINT_BLE_I8, "ble.i8", 3, MintOpBranch) -OPDEF(MINT_BLE_R8, "ble.r8", 3, MintOpBranch) - -OPDEF(MINT_BNE_UN_I4, "bne.un.i4", 3, MintOpBranch) -OPDEF(MINT_BNE_UN_I8, "bne.un.i8", 3, MintOpBranch) -OPDEF(MINT_BNE_UN_R8, "bne.un.r8", 3, MintOpBranch) -OPDEF(MINT_BGE_UN_I4, "bge.un.i4", 3, MintOpBranch) -OPDEF(MINT_BGE_UN_I8, "bge.un.i8", 3, MintOpBranch) -OPDEF(MINT_BGE_UN_R8, "bge.un.r8", 3, MintOpBranch) -OPDEF(MINT_BGT_UN_I4, "bgt.un.i4", 3, MintOpBranch) -OPDEF(MINT_BGT_UN_I8, "bgt.un.i8", 3, MintOpBranch) -OPDEF(MINT_BGT_UN_R8, "bgt.un.r8", 3, MintOpBranch) -OPDEF(MINT_BLE_UN_I4, "ble.un.i4", 3, MintOpBranch) -OPDEF(MINT_BLE_UN_I8, "ble.un.i8", 3, MintOpBranch) -OPDEF(MINT_BLE_UN_R8, "ble.un.r8", 3, MintOpBranch) -OPDEF(MINT_BLT_UN_I4, "blt.un.i4", 3, MintOpBranch) -OPDEF(MINT_BLT_UN_I8, "blt.un.i8", 3, MintOpBranch) -OPDEF(MINT_BLT_UN_R8, "blt.un.r8", 3, MintOpBranch) - -OPDEF(MINT_BEQ_I4_S, "beq.i4.s", 2, MintOpShortBranch) -OPDEF(MINT_BEQ_I8_S, "beq.i8.s", 2, MintOpShortBranch) -OPDEF(MINT_BEQ_R8_S, "beq.r8.s", 2, MintOpShortBranch) -OPDEF(MINT_BGE_I4_S, "bge.i4.s", 2, MintOpShortBranch) -OPDEF(MINT_BGE_I8_S, "bge.i8.s", 2, MintOpShortBranch) -OPDEF(MINT_BGE_R8_S, "bge.r8.s", 2, MintOpShortBranch) -OPDEF(MINT_BGT_I4_S, "bgt.i4.s", 2, MintOpShortBranch) -OPDEF(MINT_BGT_I8_S, "bgt.i8.s", 2, MintOpShortBranch) -OPDEF(MINT_BGT_R8_S, "bgt.r8.s", 2, MintOpShortBranch) -OPDEF(MINT_BLT_I4_S, "blt.i4.s", 2, MintOpShortBranch) -OPDEF(MINT_BLT_I8_S, "blt.i8.s", 2, MintOpShortBranch) -OPDEF(MINT_BLT_R8_S, "blt.r8.s", 2, MintOpShortBranch) -OPDEF(MINT_BLE_I4_S, "ble.i4.s", 2, MintOpShortBranch) -OPDEF(MINT_BLE_I8_S, "ble.i8.s", 2, MintOpShortBranch) -OPDEF(MINT_BLE_R8_S, "ble.r8.s", 2, MintOpShortBranch) - -OPDEF(MINT_BNE_UN_I4_S, "bne.un.i4.s", 2, MintOpShortBranch) -OPDEF(MINT_BNE_UN_I8_S, "bne.un.i8.s", 2, MintOpShortBranch) -OPDEF(MINT_BNE_UN_R8_S, "bne.un.r8.s", 2, MintOpShortBranch) -OPDEF(MINT_BGE_UN_I4_S, "bge.un.i4.s", 2, MintOpShortBranch) -OPDEF(MINT_BGE_UN_I8_S, "bge.un.i8.s", 2, MintOpShortBranch) -OPDEF(MINT_BGE_UN_R8_S, "bge.un.r8.s", 2, MintOpShortBranch) -OPDEF(MINT_BGT_UN_I4_S, "bgt.un.i4.s", 2, MintOpShortBranch) -OPDEF(MINT_BGT_UN_I8_S, "bgt.un.i8.s", 2, MintOpShortBranch) -OPDEF(MINT_BGT_UN_R8_S, "bgt.un.r8.s", 2, MintOpShortBranch) -OPDEF(MINT_BLE_UN_I4_S, "ble.un.i4.s", 2, MintOpShortBranch) -OPDEF(MINT_BLE_UN_I8_S, "ble.un.i8.s", 2, MintOpShortBranch) -OPDEF(MINT_BLE_UN_R8_S, "ble.un.r8.s", 2, MintOpShortBranch) -OPDEF(MINT_BLT_UN_I4_S, "blt.un.i4.s", 2, MintOpShortBranch) -OPDEF(MINT_BLT_UN_I8_S, "blt.un.i8.s", 2, MintOpShortBranch) -OPDEF(MINT_BLT_UN_R8_S, "blt.un.r8.s", 2, MintOpShortBranch) - -OPDEF(MINT_SWITCH, "switch", 0, MintOpSwitch) - -OPDEF(MINT_LDSTR, "ldstr", 2, MintOpMethodToken) /* not really */ - -OPDEF(MINT_CALL, "call", 2, MintOpMethodToken) -OPDEF(MINT_VCALL, "vcall", 2, MintOpMethodToken) -OPDEF(MINT_CALLVIRT, "callvirt", 2, MintOpMethodToken) -OPDEF(MINT_VCALLVIRT, "vcallvirt", 2, MintOpMethodToken) -OPDEF(MINT_CALLI, "calli", 2, MintOpMethodToken) -OPDEF(MINT_CALLI_NAT, "calli.nat", 2, MintOpMethodToken) -OPDEF(MINT_JMP, "jmp", 2, MintOpMethodToken) - -OPDEF(MINT_CALLRUN, "callrun", 1, MintOpNoArgs) - -OPDEF(MINT_NEWOBJ, "newobj", 2, MintOpMethodToken) -OPDEF(MINT_INITOBJ, "initobj", 3, MintOpInt) -OPDEF(MINT_CASTCLASS, "castclass", 2, MintOpClassToken) -OPDEF(MINT_ISINST, "isinst", 2, MintOpClassToken) -OPDEF(MINT_NEWARR, "newarr", 2, MintOpClassToken) -OPDEF(MINT_BOX, "box", 3, MintOpTwoShorts) -OPDEF(MINT_UNBOX, "unbox", 2, MintOpClassToken) -OPDEF(MINT_LDTOKEN, "ldtoken", 2, MintOpClassToken) /* not really */ -OPDEF(MINT_LDFTN, "ldftn", 2, MintOpMethodToken) -OPDEF(MINT_LDVIRTFTN, "ldvirtftn", 2, MintOpMethodToken) -OPDEF(MINT_LDOBJ, "ldobj", 2, MintOpClassToken) -OPDEF(MINT_STOBJ, "stobj", 2, MintOpClassToken) -OPDEF(MINT_STOBJ_VT, "stobj.vt", 2, MintOpClassToken) -OPDEF(MINT_CPBLK, "cpblk", 1, MintOpNoArgs) -OPDEF(MINT_INITBLK, "initblk", 1, MintOpNoArgs) -OPDEF(MINT_LOCALLOC, "localloc", 1, MintOpNoArgs) -OPDEF(MINT_INITLOCALS, "initlocals", 1, MintOpNoArgs) - -OPDEF(MINT_LDELEM_I, "ldelem.i", 1, MintOpNoArgs) -OPDEF(MINT_LDELEM_I1, "ldelem.i1", 1, MintOpNoArgs) -OPDEF(MINT_LDELEM_U1, "ldelem.u1", 1, MintOpNoArgs) -OPDEF(MINT_LDELEM_I2, "ldelem.i2", 1, MintOpNoArgs) -OPDEF(MINT_LDELEM_U2, "ldelem.u2", 1, MintOpNoArgs) -OPDEF(MINT_LDELEM_I4, "ldelem.i4", 1, MintOpNoArgs) -OPDEF(MINT_LDELEM_U4, "ldelem.u4", 1, MintOpNoArgs) -OPDEF(MINT_LDELEM_I8, "ldelem.i8", 1, MintOpNoArgs) -OPDEF(MINT_LDELEM_R4, "ldelem.r4", 1, MintOpNoArgs) -OPDEF(MINT_LDELEM_R8, "ldelem.r8", 1, MintOpNoArgs) -OPDEF(MINT_LDELEM_REF, "ldelem.ref", 1, MintOpNoArgs) -OPDEF(MINT_LDELEM_VT, "ldelem.vt", 4, MintOpShortAndInt) - -OPDEF(MINT_LDELEMA, "ldelema", 2, MintOpClassToken) - -OPDEF(MINT_STELEM_I, "stelem.i", 1, MintOpNoArgs) -OPDEF(MINT_STELEM_I1, "stelem.i1", 1, MintOpNoArgs) -OPDEF(MINT_STELEM_I2, "stelem.i2", 1, MintOpNoArgs) -OPDEF(MINT_STELEM_I4, "stelem.i4", 1, MintOpNoArgs) -OPDEF(MINT_STELEM_I8, "stelem.i8", 1, MintOpNoArgs) -OPDEF(MINT_STELEM_R4, "stelem.r4", 1, MintOpNoArgs) -OPDEF(MINT_STELEM_R8, "stelem.r8", 1, MintOpNoArgs) -OPDEF(MINT_STELEM_REF, "stelem.ref", 1, MintOpNoArgs) -OPDEF(MINT_STELEM_VT, "stelem.vt", 4, MintOpShortAndInt) - -OPDEF(MINT_LDLEN, "ldlen", 1, MintOpNoArgs) - -OPDEF(MINT_ADD_I4, "add.i4", 1, MintOpNoArgs) -OPDEF(MINT_ADD_I8, "add.i8", 1, MintOpNoArgs) -OPDEF(MINT_ADD_R8, "add.r8", 1, MintOpNoArgs) - -OPDEF(MINT_ADD1_I4, "add1.i4", 1, MintOpNoArgs) - -OPDEF(MINT_SUB_I4, "sub.i4", 1, MintOpNoArgs) -OPDEF(MINT_SUB_I8, "sub.i8", 1, MintOpNoArgs) -OPDEF(MINT_SUB_R8, "sub.r8", 1, MintOpNoArgs) - -OPDEF(MINT_SUB1_I4, "sub1.i4", 1, MintOpNoArgs) - -OPDEF(MINT_MUL_I4, "mul.i4", 1, MintOpNoArgs) -OPDEF(MINT_MUL_I8, "mul.i8", 1, MintOpNoArgs) -OPDEF(MINT_MUL_R8, "mul.r8", 1, MintOpNoArgs) - -OPDEF(MINT_DIV_I4, "div.i4", 1, MintOpNoArgs) -OPDEF(MINT_DIV_I8, "div.i8", 1, MintOpNoArgs) -OPDEF(MINT_DIV_R8, "div.r8", 1, MintOpNoArgs) - -OPDEF(MINT_DIV_UN_I4, "div.un.i4", 1, MintOpNoArgs) -OPDEF(MINT_DIV_UN_I8, "div.un.i8", 1, MintOpNoArgs) - -OPDEF(MINT_ADD_OVF_I4, "add.ovf.i4", 1, MintOpNoArgs) -OPDEF(MINT_ADD_OVF_I8, "add.ovf.i8", 1, MintOpNoArgs) - -OPDEF(MINT_ADD_OVF_UN_I4, "add.ovf.un.i4", 1, MintOpNoArgs) -OPDEF(MINT_ADD_OVF_UN_I8, "add.ovf.un.i8", 1, MintOpNoArgs) - -OPDEF(MINT_MUL_OVF_I4, "mul.ovf.i4", 1, MintOpNoArgs) -OPDEF(MINT_MUL_OVF_I8, "mul.ovf.i8", 1, MintOpNoArgs) - -OPDEF(MINT_MUL_OVF_UN_I4, "mul.ovf.un.i4", 1, MintOpNoArgs) -OPDEF(MINT_MUL_OVF_UN_I8, "mul.ovf.un.i8", 1, MintOpNoArgs) - -OPDEF(MINT_SUB_OVF_I4, "sub.ovf.i4", 1, MintOpNoArgs) -OPDEF(MINT_SUB_OVF_I8, "sub.ovf.i8", 1, MintOpNoArgs) - -OPDEF(MINT_SUB_OVF_UN_I4, "sub.ovf.un.i4", 1, MintOpNoArgs) -OPDEF(MINT_SUB_OVF_UN_I8, "sub.ovf.un.i8", 1, MintOpNoArgs) - -OPDEF(MINT_NEG_I4, "neg.i4", 1, MintOpNoArgs) -OPDEF(MINT_NEG_I8, "neg.i8", 1, MintOpNoArgs) -OPDEF(MINT_NEG_R8, "neg.r8", 1, MintOpNoArgs) - -OPDEF(MINT_NOT_I4, "not.i4", 1, MintOpNoArgs) -OPDEF(MINT_NOT_I8, "not.i8", 1, MintOpNoArgs) - -OPDEF(MINT_AND_I4, "and.i4", 1, MintOpNoArgs) -OPDEF(MINT_AND_I8, "and.i8", 1, MintOpNoArgs) - -OPDEF(MINT_OR_I4, "or.i4", 1, MintOpNoArgs) -OPDEF(MINT_OR_I8, "or.i8", 1, MintOpNoArgs) - -OPDEF(MINT_XOR_I4, "xor.i4", 1, MintOpNoArgs) -OPDEF(MINT_XOR_I8, "xor.i8", 1, MintOpNoArgs) - -OPDEF(MINT_REM_I4, "rem.i4", 1, MintOpNoArgs) -OPDEF(MINT_REM_I8, "rem.i8", 1, MintOpNoArgs) -OPDEF(MINT_REM_R8, "rem.r8", 1, MintOpNoArgs) - -OPDEF(MINT_REM_UN_I4, "rem.un.i4", 1, MintOpNoArgs) -OPDEF(MINT_REM_UN_I8, "rem.un.i8", 1, MintOpNoArgs) - -OPDEF(MINT_SHR_UN_I4, "shr.un.i4", 1, MintOpNoArgs) -OPDEF(MINT_SHR_UN_I8, "shr.un.i8", 1, MintOpNoArgs) -OPDEF(MINT_SHL_I4, "shl.i4", 1, MintOpNoArgs) -OPDEF(MINT_SHL_I8, "shl.i8", 1, MintOpNoArgs) -OPDEF(MINT_SHR_I4, "shr.i4", 1, MintOpNoArgs) -OPDEF(MINT_SHR_I8, "shr.i8", 1, MintOpNoArgs) - -OPDEF(MINT_CONV_R_UN_I4, "conv.r.un.i4", 1, MintOpNoArgs) -OPDEF(MINT_CONV_R_UN_I8, "conv.r.un.i8", 1, MintOpNoArgs) - -OPDEF(MINT_CONV_I1_I4, "conv.i1.i4", 1, MintOpNoArgs) -OPDEF(MINT_CONV_I1_I8, "conv.i1.i8", 1, MintOpNoArgs) -OPDEF(MINT_CONV_I1_R8, "conv.i1.r8", 1, MintOpNoArgs) - -OPDEF(MINT_CONV_U1_I4, "conv.u1.i4", 1, MintOpNoArgs) -OPDEF(MINT_CONV_U1_I8, "conv.u1.i8", 1, MintOpNoArgs) -OPDEF(MINT_CONV_U1_R8, "conv.u1.r8", 1, MintOpNoArgs) - -OPDEF(MINT_CONV_I2_I4, "conv.i2.i4", 1, MintOpNoArgs) -OPDEF(MINT_CONV_I2_I8, "conv.i2.i8", 1, MintOpNoArgs) -OPDEF(MINT_CONV_I2_R8, "conv.i2.r8", 1, MintOpNoArgs) - -OPDEF(MINT_CONV_U2_I4, "conv.u2.i4", 1, MintOpNoArgs) -OPDEF(MINT_CONV_U2_I8, "conv.u2.i8", 1, MintOpNoArgs) -OPDEF(MINT_CONV_U2_R8, "conv.u2.r8", 1, MintOpNoArgs) - -OPDEF(MINT_CONV_I4_I8, "conv.i4.i8", 1, MintOpNoArgs) -OPDEF(MINT_CONV_I4_R8, "conv.i4.r8", 1, MintOpNoArgs) - -OPDEF(MINT_CONV_U4_I8, "conv.u4.i8", 1, MintOpNoArgs) -OPDEF(MINT_CONV_U4_R8, "conv.u4.r8", 1, MintOpNoArgs) - -OPDEF(MINT_CONV_I8_I4, "conv.i8.i4", 1, MintOpNoArgs) -OPDEF(MINT_CONV_I8_U4, "conv.i8.u4", 1, MintOpNoArgs) -OPDEF(MINT_CONV_I8_R8, "conv.i8.r8", 1, MintOpNoArgs) - -OPDEF(MINT_CONV_R4_I4, "conv.r4.i4", 1, MintOpNoArgs) -OPDEF(MINT_CONV_R4_I8, "conv.r4.i8", 1, MintOpNoArgs) -OPDEF(MINT_CONV_R4_R8, "conv.r4.r8", 1, MintOpNoArgs) - -OPDEF(MINT_CONV_R8_I4, "conv.r8.i4", 1, MintOpNoArgs) -OPDEF(MINT_CONV_R8_I8, "conv.r8.i8", 1, MintOpNoArgs) - -OPDEF(MINT_CONV_I4_I8_SP, "conv.i4.i8.sp", 1, MintOpNoArgs) /* special for narrowing sp[-2] on 64 bits */ -OPDEF(MINT_CONV_I8_I4_SP, "conv.i8.i4.sp", 1, MintOpNoArgs) /* special for widening sp[-2] on 64 bits */ - -OPDEF(MINT_CONV_U8_I4, "conv.u8.i4", 1, MintOpNoArgs) -OPDEF(MINT_CONV_U8_R8, "conv.u8.r8", 1, MintOpNoArgs) - -OPDEF(MINT_CONV_OVF_I1_I4, "conv.ovf.i1.i4", 1, MintOpNoArgs) -OPDEF(MINT_CONV_OVF_I1_I8, "conv.ovf.i1.i8", 1, MintOpNoArgs) -OPDEF(MINT_CONV_OVF_I1_R8, "conv.ovf.i1.r8", 1, MintOpNoArgs) - -OPDEF(MINT_CONV_OVF_U1_I4, "conv.ovf.u1.i4", 1, MintOpNoArgs) -OPDEF(MINT_CONV_OVF_U1_I8, "conv.ovf.u1.i8", 1, MintOpNoArgs) -OPDEF(MINT_CONV_OVF_U1_R8, "conv.ovf.u1.r8", 1, MintOpNoArgs) - -OPDEF(MINT_CONV_OVF_I2_I4, "conv.ovf.i2.i4", 1, MintOpNoArgs) -OPDEF(MINT_CONV_OVF_I2_I8, "conv.ovf.i2.i8", 1, MintOpNoArgs) -OPDEF(MINT_CONV_OVF_I2_R8, "conv.ovf.i2.r8", 1, MintOpNoArgs) - -OPDEF(MINT_CONV_OVF_U2_I4, "conv.ovf.u2.i4", 1, MintOpNoArgs) -OPDEF(MINT_CONV_OVF_U2_I8, "conv.ovf.u2.i8", 1, MintOpNoArgs) -OPDEF(MINT_CONV_OVF_U2_R8, "conv.ovf.u2.r8", 1, MintOpNoArgs) - -OPDEF(MINT_CONV_OVF_I4_U4, "conv.ovf.i4.u4", 1, MintOpNoArgs) -OPDEF(MINT_CONV_OVF_I4_I8, "conv.ovf.i4.i8", 1, MintOpNoArgs) -OPDEF(MINT_CONV_OVF_I4_R8, "conv.ovf.i4.r8", 1, MintOpNoArgs) - -OPDEF(MINT_CONV_OVF_I4_UN_I8, "conv.ovf.i4.un.i8", 1, MintOpNoArgs) -OPDEF(MINT_CONV_OVF_I4_UN_R8, "conv.ovf.i4.un.r8", 1, MintOpNoArgs) - -OPDEF(MINT_CONV_OVF_U4_I4, "conv.ovf.u4.i4", 1, MintOpNoArgs) -OPDEF(MINT_CONV_OVF_U4_I8, "conv.ovf.u4.i8", 1, MintOpNoArgs) -OPDEF(MINT_CONV_OVF_U4_R8, "conv.ovf.u4.r8", 1, MintOpNoArgs) - -OPDEF(MINT_CONV_OVF_I8_R8, "conv.ovf.i8.r8", 1, MintOpNoArgs) - -OPDEF(MINT_CONV_OVF_I8_UN_R8, "conv.ovf.i8.un.r8", 1, MintOpNoArgs) - -OPDEF(MINT_CONV_OVF_U8_I4, "conv.ovf.u8.i4", 1, MintOpNoArgs) -OPDEF(MINT_CONV_OVF_U8_R8, "conv.ovf.u8.r8", 1, MintOpNoArgs) - -OPDEF(MINT_CEQ_I4, "ceq.i4", 1, MintOpNoArgs) -OPDEF(MINT_CEQ_I8, "ceq.i8", 1, MintOpNoArgs) -OPDEF(MINT_CEQ_R8, "ceq.r8", 1, MintOpNoArgs) - -OPDEF(MINT_CEQ0_I4, "ceq0.i4", 1, MintOpNoArgs) - -OPDEF(MINT_CGT_I4, "cgt.i4", 1, MintOpNoArgs) -OPDEF(MINT_CGT_I8, "cgt.i8", 1, MintOpNoArgs) -OPDEF(MINT_CGT_R8, "cgt.r8", 1, MintOpNoArgs) - -OPDEF(MINT_CGT_UN_I4, "cgt.un.i4", 1, MintOpNoArgs) -OPDEF(MINT_CGT_UN_I8, "cgt.un.i8", 1, MintOpNoArgs) -OPDEF(MINT_CGT_UN_R8, "cgt.un.r8", 1, MintOpNoArgs) - -OPDEF(MINT_CLT_I4, "clt.i4", 1, MintOpNoArgs) -OPDEF(MINT_CLT_I8, "clt.i8", 1, MintOpNoArgs) -OPDEF(MINT_CLT_R8, "clt.r8", 1, MintOpNoArgs) - -OPDEF(MINT_CLT_UN_I4, "clt.un.i4", 1, MintOpNoArgs) -OPDEF(MINT_CLT_UN_I8, "clt.un.i8", 1, MintOpNoArgs) -OPDEF(MINT_CLT_UN_R8, "clt.un.r8", 1, MintOpNoArgs) - -OPDEF(MINT_CKFINITE, "ckfinite", 1, MintOpNoArgs) - -OPDEF(MINT_CKNULL, "cknull", 1, MintOpNoArgs) - -OPDEF(MINT_GETCHR, "getchr", 1, MintOpNoArgs) -OPDEF(MINT_STRLEN, "strlen", 1, MintOpNoArgs) -OPDEF(MINT_ARRAY_RANK, "array_rank", 1, MintOpNoArgs) - -OPDEF(MINT_ICALL_V_V, "mono_icall_v_v", 2, MintOpClassToken) /* not really */ -OPDEF(MINT_ICALL_V_P, "mono_icall_v_p", 2, MintOpClassToken) -OPDEF(MINT_ICALL_P_V, "mono_icall_p_v", 2, MintOpClassToken) -OPDEF(MINT_ICALL_P_P, "mono_icall_p_p", 2, MintOpClassToken) -OPDEF(MINT_ICALL_PP_V, "mono_icall_pp_v", 2, MintOpClassToken) -OPDEF(MINT_ICALL_PI_V, "mono_icall_pi_v", 2, MintOpClassToken) -OPDEF(MINT_ICALL_PP_P, "mono_icall_pp_p", 2, MintOpClassToken) -OPDEF(MINT_ICALL_PI_P, "mono_icall_pi_p", 2, MintOpClassToken) -OPDEF(MINT_ICALL_PPP_V, "mono_icall_ppp_v", 2, MintOpClassToken) -OPDEF(MINT_ICALL_PPI_V, "mono_icall_ppi_v", 2, MintOpClassToken) -OPDEF(MINT_MONO_LDPTR, "mono_ldptr", 2, MintOpClassToken) -OPDEF(MINT_MONO_NEWOBJ, "mono_newobj", 2, MintOpClassToken) -OPDEF(MINT_MONO_RETOBJ, "mono_retobj", 1, MintOpNoArgs) -OPDEF(MINT_MONO_FREE, "mono_free", 1, MintOpNoArgs) - - diff --git a/mono/mini/interpreter/mintops.h b/mono/mini/interpreter/mintops.h deleted file mode 100644 index e787526e2fe..00000000000 --- a/mono/mini/interpreter/mintops.h +++ /dev/null @@ -1,58 +0,0 @@ -#ifndef __INTERPRETER_MINTOPS_H -#define __INTERPRETER_MINTOPS_H - -#include - -typedef enum -{ - MintOpNoArgs, - MintOpShortInt, - MintOpUShortInt, - MintOpInt, - MintOpLongInt, - MintOpFloat, - MintOpDouble, - MintOpBranch, - MintOpShortBranch, - MintOpSwitch, - MintOpMethodToken, - MintOpFieldToken, - MintOpClassToken, - MintOpTwoShorts, - MintOpShortAndInt -} MintOpArgType; - -#define OPDEF(a,b,c,d) \ - a, -enum { -#include "mintops.def" - MINT_LASTOP -}; -#undef OPDEF - -#if NO_UNALIGNED_ACCESS -# if G_BYTE_ORDER == G_LITTLE_ENDIAN -#define READ32(x) (((guint16 *)(x)) [0] | ((guint16 *)(x)) [1] << 16) -#define READ64(x) ((guint64)((guint16 *)(x)) [0] | \ - (guint64)((guint16 *)(x)) [1] << 16 | \ - (guint64)((guint16 *)(x)) [2] << 32 | \ - (guint64)((guint16 *)(x)) [3] << 48) -# else -#define READ32(x) (((guint16 *)(x)) [0] << 16 | ((guint16 *)(x)) [1]) -#define READ64(x) ((guint64)((guint16 *)(x)) [0] << 48 | \ - (guint64)((guint16 *)(x)) [1] << 32 | \ - (guint64)((guint16 *)(x)) [2] << 16 | \ - (guint64)((guint16 *)(x)) [3]) -# endif -#else /* unaligned access OK */ -#define READ32(x) (*(guint32 *)(x)) -#define READ64(x) (*(guint64 *)(x)) -#endif - -extern const char *mono_interp_opname[]; -extern unsigned char mono_interp_oplen[]; -extern MintOpArgType mono_interp_opargtype[]; -extern const guint16 *mono_interp_dis_mintop(const unsigned short *base, const guint16 *ip); - -#endif - diff --git a/mono/mini/interpreter/transform.c b/mono/mini/interpreter/transform.c deleted file mode 100644 index e5e2ec931d3..00000000000 --- a/mono/mini/interpreter/transform.c +++ /dev/null @@ -1,3382 +0,0 @@ -/* - * transform CIL into different opcodes for more - * efficient interpretation - * - * Written by Bernie Solomon (bernard@ugsolutions.com) - * Copyright (c) 2004. - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "mintops.h" -#include "interp-internals.h" -#include "interp.h" - -// TODO: export from marshal.c -MonoDelegate* mono_ftnptr_to_delegate (MonoClass *klass, gpointer ftn); - -#define DEBUG 0 - -typedef struct -{ - MonoClass *klass; - unsigned char type; - unsigned char flags; -} StackInfo; - -typedef struct -{ - MonoMethod *method; - MonoMethodHeader *header; - RuntimeMethod *rtm; - const unsigned char *il_code; - const unsigned char *ip; - const unsigned char *last_ip; - const unsigned char *in_start; - int code_size; - int *in_offsets; - int *forward_refs; - StackInfo **stack_state; - int *stack_height; - int *vt_stack_size; - unsigned char *is_bb_start; - unsigned short *new_code; - unsigned short *new_code_end; - unsigned short *new_ip; - unsigned short *last_new_ip; - unsigned int max_code_size; - StackInfo *stack; - StackInfo *sp; - unsigned int max_stack_height; - unsigned int vt_sp; - unsigned int max_vt_sp; - int n_data_items; - int max_data_items; - void **data_items; - GHashTable *data_hash; -} TransformData; - -#define MINT_TYPE_I1 0 -#define MINT_TYPE_U1 1 -#define MINT_TYPE_I2 2 -#define MINT_TYPE_U2 3 -#define MINT_TYPE_I4 4 -#define MINT_TYPE_I8 5 -#define MINT_TYPE_R4 6 -#define MINT_TYPE_R8 7 -#define MINT_TYPE_O 8 -#define MINT_TYPE_P 9 -#define MINT_TYPE_VT 10 - -#define STACK_TYPE_I4 0 -#define STACK_TYPE_I8 1 -#define STACK_TYPE_R8 2 -#define STACK_TYPE_O 3 -#define STACK_TYPE_VT 4 -#define STACK_TYPE_MP 5 -#define STACK_TYPE_F 6 - -static const char *stack_type_string [] = { "I4", "I8", "R8", "O ", "VT", "MP", "F " }; - -#if SIZEOF_VOID_P == 8 -#define STACK_TYPE_I STACK_TYPE_I8 -#else -#define STACK_TYPE_I STACK_TYPE_I4 -#endif - -static int stack_type [] = { - STACK_TYPE_I4, /*I1*/ - STACK_TYPE_I4, /*U1*/ - STACK_TYPE_I4, /*I2*/ - STACK_TYPE_I4, /*U2*/ - STACK_TYPE_I4, /*I4*/ - STACK_TYPE_I8, /*I8*/ - STACK_TYPE_R8, /*R4*/ - STACK_TYPE_R8, /*R8*/ - STACK_TYPE_O, /*O*/ - STACK_TYPE_MP, /*P*/ - STACK_TYPE_VT -}; - -static void -grow_code (TransformData *td) -{ - unsigned int old_ip_offset = td->new_ip - td->new_code; - unsigned int old_last_ip_offset = td->last_new_ip - td->new_code; - g_assert (old_ip_offset <= td->max_code_size); - td->new_code = g_realloc (td->new_code, (td->max_code_size *= 2) * sizeof (td->new_code [0])); - td->new_code_end = td->new_code + td->max_code_size; - td->new_ip = td->new_code + old_ip_offset; - td->last_new_ip = td->new_code + old_last_ip_offset; -} - -#define ENSURE_CODE(td, n) \ - do { \ - if ((td)->new_ip + (n) > (td)->new_code_end) \ - grow_code (td); \ - } while (0) - -#define ADD_CODE(td, n) \ - do { \ - if ((td)->new_ip == (td)->new_code_end) \ - grow_code (td); \ - *(td)->new_ip++ = (n); \ - } while (0) - -#define CHECK_STACK(td, n) \ - do { \ - int stack_size = (td)->sp - (td)->stack; \ - if (stack_size < (n)) \ - g_warning ("%s.%s: not enough values (%d < %d) on stack at %04x", \ - (td)->method->klass->name, (td)->method->name, \ - stack_size, n, (td)->ip - (td)->il_code); \ - } while (0) - -#define ENSURE_I4(td, sp_off) \ - do { \ - if ((td)->sp [-sp_off].type == STACK_TYPE_I8) \ - ADD_CODE(td, sp_off == 1 ? MINT_CONV_I4_I8 : MINT_CONV_I4_I8_SP); \ - } while (0) - -static void -handle_branch(TransformData *td, int short_op, int long_op, int offset) -{ - int shorten_branch = 0; - int target = td->ip + offset - td->il_code; - if (target < 0 || target >= td->code_size) - g_assert_not_reached (); - if (offset > 0 && td->stack_height [target] < 0) { - td->stack_height [target] = td->sp - td->stack; - if (td->stack_height [target] > 0) - td->stack_state [target] = g_memdup (td->stack, td->stack_height [target] * sizeof (td->stack [0])); - td->vt_stack_size [target] = td->vt_sp; - } - if (offset < 0) { - offset = td->in_offsets [target] - (td->new_ip - td->new_code); - if (offset >= -32768) { - shorten_branch = 1; - } - } else { - int prev = td->forward_refs [target]; - td->forward_refs [td->ip - td->il_code] = prev; - td->forward_refs [target] = td->ip - td->il_code; - offset = 0; - if (td->header->code_size <= 25000) /* FIX to be precise somehow? */ - shorten_branch = 1; - } - if (shorten_branch) { - ADD_CODE(td, short_op); - ADD_CODE(td, offset); - } else { - ADD_CODE(td, long_op); - ADD_CODE(td, * (unsigned short *)(&offset)); - ADD_CODE(td, * ((unsigned short *)&offset + 1)); - } -} - -static void -one_arg_branch(TransformData *td, int mint_op, int offset) -{ - int type = td->sp [-1].type == STACK_TYPE_O || td->sp [-1].type == STACK_TYPE_MP ? STACK_TYPE_I : td->sp [-1].type; - int long_op = mint_op + type - STACK_TYPE_I4; - int short_op = long_op + MINT_BRFALSE_I4_S - MINT_BRFALSE_I4; - CHECK_STACK(td, 1); - --td->sp; - handle_branch (td, short_op, long_op, offset); -} - -static void -two_arg_branch(TransformData *td, int mint_op, int offset) -{ - int type1 = td->sp [-1].type == STACK_TYPE_O || td->sp [-1].type == STACK_TYPE_MP ? STACK_TYPE_I : td->sp [-1].type; - int type2 = td->sp [-2].type == STACK_TYPE_O || td->sp [-2].type == STACK_TYPE_MP ? STACK_TYPE_I : td->sp [-2].type; - int long_op = mint_op + type1 - STACK_TYPE_I4; - int short_op = long_op + MINT_BEQ_I4_S - MINT_BEQ_I4; - CHECK_STACK(td, 2); - if (type1 == STACK_TYPE_I4 && type2 == STACK_TYPE_I8) { - ADD_CODE(td, MINT_CONV_I8_I4); - td->in_offsets [td->ip - td->il_code]++; - } else if (type1 == STACK_TYPE_I8 && type2 == STACK_TYPE_I4) { - ADD_CODE(td, MINT_CONV_I8_I4_SP); - td->in_offsets [td->ip - td->il_code]++; - } else if (type1 != type2) { - g_warning("%s.%s: branch type mismatch %d %d", - td->method->klass->name, td->method->name, - td->sp [-1].type, td->sp [-2].type); - } - td->sp -= 2; - handle_branch (td, short_op, long_op, offset); -} - -static void -unary_arith_op(TransformData *td, int mint_op) -{ - int op = mint_op + td->sp [-1].type - STACK_TYPE_I4; - CHECK_STACK(td, 1); - ADD_CODE(td, op); -} - -static void -binary_arith_op(TransformData *td, int mint_op) -{ - int type1 = td->sp [-2].type; - int type2 = td->sp [-1].type; - int op; -#if SIZEOF_VOID_P == 8 - if ((type1 == STACK_TYPE_MP || type1 == STACK_TYPE_I8) && type2 == STACK_TYPE_I4) { - ADD_CODE(td, MINT_CONV_I8_I4); - type2 = STACK_TYPE_I8; - } - if (type1 == STACK_TYPE_I4 && (type2 == STACK_TYPE_MP || type2 == STACK_TYPE_I8)) { - ADD_CODE(td, MINT_CONV_I8_I4_SP); - type1 = STACK_TYPE_I8; - td->sp [-2].type = STACK_TYPE_I8; - } -#endif - if (type1 == STACK_TYPE_MP) - type1 = STACK_TYPE_I; - if (type2 == STACK_TYPE_MP) - type2 = STACK_TYPE_I; - if (type1 != type2) { - g_warning("%s.%s: %04x arith type mismatch %s %d %d", - td->method->klass->name, td->method->name, - td->ip - td->il_code, mono_interp_opname[mint_op], type1, type2); - } - op = mint_op + type1 - STACK_TYPE_I4; - CHECK_STACK(td, 2); - ADD_CODE(td, op); - --td->sp; -} - -static void -binary_int_op(TransformData *td, int mint_op) -{ - int op = mint_op + td->sp [-1].type - STACK_TYPE_I4; - CHECK_STACK(td, 2); - if (td->sp [-1].type != td->sp [-2].type) - g_warning("%s.%s: int type mismatch", td->method->klass->name, td->method->name); - ADD_CODE(td, op); - --td->sp; -} - -static void -shift_op(TransformData *td, int mint_op) -{ - int op = mint_op + td->sp [-2].type - STACK_TYPE_I4; - CHECK_STACK(td, 2); - if (td->sp [-1].type != STACK_TYPE_I4) { - g_warning("%s.%s: shift type mismatch %d", - td->method->klass->name, td->method->name, - td->sp [-2].type); - } - ADD_CODE(td, op); - --td->sp; -} - -static int -mint_type(MonoType *type) -{ - if (type->byref) - return MINT_TYPE_P; -enum_type: - switch (type->type) { - case MONO_TYPE_I1: - return MINT_TYPE_I1; - case MONO_TYPE_U1: - case MONO_TYPE_BOOLEAN: - return MINT_TYPE_U1; - case MONO_TYPE_I2: - return MINT_TYPE_I2; - case MONO_TYPE_U2: - case MONO_TYPE_CHAR: - return MINT_TYPE_U2; - case MONO_TYPE_I4: - case MONO_TYPE_U4: - return MINT_TYPE_I4; - case MONO_TYPE_I: - case MONO_TYPE_U: -#if SIZEOF_VOID_P == 4 - return MINT_TYPE_I4; -#else - return MINT_TYPE_I8; -#endif - case MONO_TYPE_PTR: - return MINT_TYPE_P; - case MONO_TYPE_R4: - return MINT_TYPE_R4; - case MONO_TYPE_I8: - case MONO_TYPE_U8: - return MINT_TYPE_I8; - case MONO_TYPE_R8: - return MINT_TYPE_R8; - case MONO_TYPE_STRING: - case MONO_TYPE_SZARRAY: - case MONO_TYPE_CLASS: - case MONO_TYPE_OBJECT: - case MONO_TYPE_ARRAY: - return MINT_TYPE_O; - case MONO_TYPE_VALUETYPE: - if (type->data.klass->enumtype) { - type = mono_class_enum_basetype (type->data.klass); - goto enum_type; - } else - return MINT_TYPE_VT; - case MONO_TYPE_GENERICINST: - type = &type->data.generic_class->container_class->byval_arg; - goto enum_type; - default: - g_warning ("got type 0x%02x", type->type); - g_assert_not_reached (); - } - return -1; -} - -static int -can_store (int stack_type, int var_type) -{ - if (stack_type == STACK_TYPE_O || stack_type == STACK_TYPE_MP) - stack_type = STACK_TYPE_I; - if (var_type == STACK_TYPE_O || var_type == STACK_TYPE_MP) - var_type = STACK_TYPE_I; - return stack_type == var_type; -} - -#define SET_SIMPLE_TYPE(s, ty) \ - do { \ - (s)->type = (ty); \ - (s)->flags = 0; \ - (s)->klass = NULL; \ - } while (0) - -#define SET_TYPE(s, ty, k) \ - do { \ - (s)->type = (ty); \ - (s)->flags = 0; \ - (s)->klass = k; \ - } while (0) - -#define PUSH_SIMPLE_TYPE(td, ty) \ - do { \ - int sp_height; \ - (td)->sp++; \ - sp_height = (td)->sp - (td)->stack; \ - if (sp_height > (td)->max_stack_height) \ - (td)->max_stack_height = sp_height; \ - SET_SIMPLE_TYPE((td)->sp - 1, ty); \ - } while (0) - -#define PUSH_TYPE(td, ty, k) \ - do { \ - int sp_height; \ - (td)->sp++; \ - sp_height = (td)->sp - (td)->stack; \ - if (sp_height > (td)->max_stack_height) \ - (td)->max_stack_height = sp_height; \ - SET_TYPE((td)->sp - 1, ty, k); \ - } while (0) - -#define PUSH_VT(td, size) \ - do { \ - (td)->vt_sp += ((size) + 7) & ~7; \ - if ((td)->vt_sp > (td)->max_vt_sp) \ - (td)->max_vt_sp = (td)->vt_sp; \ - } while (0) - -#define POP_VT(td, size) \ - do { \ - (td)->vt_sp -= ((size) + 7) & ~7; \ - } while (0) - -#if NO_UNALIGNED_ACCESS -#define WRITE32(td, v) \ - do { \ - ENSURE_CODE(td, 2); \ - * (guint16 *)((td)->new_ip) = * (guint16 *)(v); \ - * ((guint16 *)((td)->new_ip) + 1) = * ((guint16 *)(v) + 1); \ - (td)->new_ip += 2; \ - } while (0) - -#define WRITE64(td, v) \ - do { \ - ENSURE_CODE(td, 4); \ - * (guint16 *)((td)->new_ip) = * (guint16 *)(v); \ - * ((guint16 *)((td)->new_ip) + 1) = * ((guint16 *)(v) + 1); \ - * ((guint16 *)((td)->new_ip) + 2) = * ((guint16 *)(v) + 2); \ - * ((guint16 *)((td)->new_ip) + 3) = * ((guint16 *)(v) + 3); \ - (td)->new_ip += 4; \ - } while (0) -#else -#define WRITE32(td, v) \ - do { \ - ENSURE_CODE(td, 2); \ - * (guint32 *)((td)->new_ip) = * (guint32 *)(v); \ - (td)->new_ip += 2; \ - } while (0) - -#define WRITE64(td, v) \ - do { \ - ENSURE_CODE(td, 4); \ - * (guint64 *)((td)->new_ip) = * (guint64 *)(v); \ - (td)->new_ip += 4; \ - } while (0) - -#endif - -static void -load_arg(TransformData *td, int n) -{ - int mt; - MonoClass *klass = NULL; - MonoType *type; - - gboolean hasthis = mono_method_signature (td->method)->hasthis; - if (hasthis && n == 0) - type = &td->method->klass->byval_arg; - else - type = mono_method_signature (td->method)->params [hasthis ? n - 1 : n]; - - mt = mint_type (type); - if (mt == MINT_TYPE_VT) { - gint32 size; - klass = mono_class_from_mono_type (type); - if (mono_method_signature (td->method)->pinvoke) - size = mono_class_native_size (klass, NULL); - else - size = mono_class_value_size (klass, NULL); - - if (hasthis && n == 0) { - mt = MINT_TYPE_P; - ADD_CODE (td, MINT_LDARG_P); - ADD_CODE (td, td->rtm->arg_offsets [n]); /* FIX for large offset */ - klass = NULL; - } else { - PUSH_VT (td, size); - ADD_CODE (td, MINT_LDARG_VT); - ADD_CODE (td, td->rtm->arg_offsets [n]); /* FIX for large offset */ - WRITE32 (td, &size); - } - } else { - if (hasthis && n == 0) { - mt = MINT_TYPE_P; - ADD_CODE (td, MINT_LDARG_P); - ADD_CODE (td, td->rtm->arg_offsets [n]); /* FIX for large offset */ - klass = NULL; - } else { - ADD_CODE(td, MINT_LDARG_I1 + (mt - MINT_TYPE_I1)); - ADD_CODE(td, td->rtm->arg_offsets [n]); /* FIX for large offset */ - if (mt == MINT_TYPE_O) - klass = mono_class_from_mono_type (type); - } - } - PUSH_TYPE(td, stack_type[mt], klass); -} - -static void -store_arg(TransformData *td, int n) -{ - int mt; - CHECK_STACK (td, 1); - MonoType *type; - - gboolean hasthis = mono_method_signature (td->method)->hasthis; - if (hasthis && n == 0) - type = &td->method->klass->byval_arg; - else - type = mono_method_signature (td->method)->params [n - !!hasthis]; - - mt = mint_type (type); - if (mt == MINT_TYPE_VT) { - gint32 size; - g_error ("data.klass"); - if (mono_method_signature (td->method)->pinvoke) - size = mono_class_native_size (type->data.klass, NULL); - else - size = mono_class_value_size (type->data.klass, NULL); - ADD_CODE(td, MINT_STARG_VT); - ADD_CODE(td, n); - WRITE32(td, &size); - if (td->sp [-1].type == STACK_TYPE_VT) - POP_VT(td, size); - } else { - ADD_CODE(td, MINT_STARG_I1 + (mt - MINT_TYPE_I1)); - ADD_CODE(td, td->rtm->arg_offsets [n]); - } - --td->sp; -} - -static void -store_inarg(TransformData *td, int n) -{ - MonoType *type; - gboolean hasthis = mono_method_signature (td->method)->hasthis; - if (hasthis && n == 0) - type = &td->method->klass->byval_arg; - else - type = mono_method_signature (td->method)->params [n - !!hasthis]; - - int mt = mint_type (type); - if (hasthis && n == 0) { - ADD_CODE (td, MINT_STINARG_P); - ADD_CODE (td, n); - return; - } - if (mt == MINT_TYPE_VT) { - MonoClass *klass = mono_class_from_mono_type (type); - gint32 size; - if (mono_method_signature (td->method)->pinvoke) - size = mono_class_native_size (klass, NULL); - else - size = mono_class_value_size (klass, NULL); - ADD_CODE(td, MINT_STINARG_VT); - ADD_CODE(td, n); - WRITE32(td, &size); - } else { - ADD_CODE(td, MINT_STINARG_I1 + (mt - MINT_TYPE_I1)); - ADD_CODE(td, n); - } -} - -static void -load_local(TransformData *td, int n) -{ - MonoType *type = td->header->locals [n]; - int mt = mint_type (type); - int offset = td->rtm->local_offsets [n]; - MonoClass *klass = NULL; - if (mt == MINT_TYPE_VT) { - klass = mono_class_from_mono_type (type); - gint32 size = mono_class_value_size (klass, NULL); - PUSH_VT(td, size); - ADD_CODE(td, MINT_LDLOC_VT); - ADD_CODE(td, offset); /*FIX for large offset */ - WRITE32(td, &size); - } else { - g_assert (mt < MINT_TYPE_VT); - if (mt == MINT_TYPE_I4 && !td->is_bb_start [td->in_start - td->il_code] && td->last_new_ip != NULL && - td->last_new_ip [0] == MINT_STLOC_I4 && td->last_new_ip [1] == offset) { - td->last_new_ip [0] = MINT_STLOC_NP_I4; - } else if (mt == MINT_TYPE_O && !td->is_bb_start [td->in_start - td->il_code] && td->last_new_ip != NULL && - td->last_new_ip [0] == MINT_STLOC_O && td->last_new_ip [1] == offset) { - td->last_new_ip [0] = MINT_STLOC_NP_O; - } else { - ADD_CODE(td, MINT_LDLOC_I1 + (mt - MINT_TYPE_I1)); - ADD_CODE(td, offset); /*FIX for large offset */ - } - if (mt == MINT_TYPE_O) - klass = mono_class_from_mono_type (type); - } - PUSH_TYPE(td, stack_type[mt], klass); -} - -static void -store_local(TransformData *td, int n) -{ - MonoType *type = td->header->locals [n]; - int mt = mint_type (type); - int offset = td->rtm->local_offsets [n]; - CHECK_STACK (td, 1); -#if SIZEOF_VOID_P == 8 - if (td->sp [-1].type == STACK_TYPE_I4 && stack_type [mt] == STACK_TYPE_I8) { - ADD_CODE(td, MINT_CONV_I8_I4); - td->sp [-1].type = STACK_TYPE_I8; - } -#endif - if (!can_store(td->sp [-1].type, stack_type [mt])) { - g_warning("%s.%s: Store local stack type mismatch %d %d", - td->method->klass->name, td->method->name, - stack_type [mt], td->sp [-1].type); - } - if (mt == MINT_TYPE_VT) { - MonoClass *klass = mono_class_from_mono_type (type); - gint32 size = mono_class_value_size (klass, NULL); - ADD_CODE(td, MINT_STLOC_VT); - ADD_CODE(td, offset); /*FIX for large offset */ - WRITE32(td, &size); - if (td->sp [-1].type == STACK_TYPE_VT) - POP_VT(td, size); - } else { - g_assert (mt < MINT_TYPE_VT); - ADD_CODE(td, MINT_STLOC_I1 + (mt - MINT_TYPE_I1)); - ADD_CODE(td, offset); /*FIX for large offset */ - } - --td->sp; -} - -#define SIMPLE_OP(td, op) \ - do { \ - ADD_CODE(&td, op); \ - ++td.ip; \ - } while (0) - -static guint16 -get_data_item_index (TransformData *td, void *ptr) -{ - gpointer p = g_hash_table_lookup (td->data_hash, ptr); - guint index; - if (p != NULL) - return GPOINTER_TO_UINT (p) - 1; - if (td->max_data_items == td->n_data_items) { - td->max_data_items = td->n_data_items == 0 ? 16 : 2 * td->max_data_items; - td->data_items = g_realloc (td->data_items, td->max_data_items * sizeof(td->data_items [0])); - } - index = td->n_data_items; - td->data_items [index] = ptr; - ++td->n_data_items; - g_hash_table_insert (td->data_hash, ptr, GUINT_TO_POINTER (index + 1)); - return index; -} - -static void -interp_transform_call (TransformData *td, MonoMethod *method, MonoMethod *target_method, MonoDomain *domain, MonoGenericContext *generic_context, unsigned char *is_bb_start, int body_start_offset, MonoClass *constrained_class) -{ - MonoImage *image = method->klass->image; - MonoMethodSignature *csignature; - MonoError error; - int virtual = *td->ip == CEE_CALLVIRT; - int calli = *td->ip == CEE_CALLI || *td->ip == CEE_MONO_CALLI_EXTRA_ARG; - int i; - guint32 vt_stack_used = 0; - guint32 vt_res_size = 0; - int op = -1; - int native = 0; - int is_void = 0; - - guint32 token = read32 (td->ip + 1); - - if (target_method == NULL) { - if (calli) { - CHECK_STACK(td, 1); - native = (method->wrapper_type != MONO_WRAPPER_DELEGATE_INVOKE && td->sp [-1].type == STACK_TYPE_I); - --td->sp; - if (method->wrapper_type != MONO_WRAPPER_NONE) - csignature = (MonoMethodSignature *)mono_method_get_wrapper_data (method, token); - else - csignature = mono_metadata_parse_signature (image, token); - - if (generic_context) { - csignature = mono_inflate_generic_signature (csignature, generic_context, &error); - mono_error_cleanup (&error); /* FIXME: don't swallow the error */ - } - - target_method = NULL; - } else { - if (method->wrapper_type == MONO_WRAPPER_NONE) - target_method = mono_get_method_full (image, token, NULL, generic_context); - else - target_method = (MonoMethod *)mono_method_get_wrapper_data (method, token); - csignature = mono_method_signature (target_method); - if (target_method->klass == mono_defaults.string_class) { - if (target_method->name [0] == 'g') { - if (strcmp (target_method->name, "get_Chars") == 0) - op = MINT_GETCHR; - else if (strcmp (target_method->name, "get_Length") == 0) - op = MINT_STRLEN; - } - } else if (target_method->klass == mono_defaults.array_class) { - if (strcmp (target_method->name, "get_Rank") == 0) - op = MINT_ARRAY_RANK; - else if (strcmp (target_method->name, "get_Length") == 0) - op = MINT_LDLEN; - } - } - } else { - csignature = mono_method_signature (target_method); - } - - /* TODO: that's oddly specific? */ - if (generic_context && target_method && !strcmp ("Invoke", target_method->name) && target_method->klass->parent == mono_defaults.multicastdelegate_class) { - csignature = mono_inflate_generic_signature (csignature, generic_context, &error); - mono_error_cleanup (&error); /* FIXME: don't swallow the error */ - } - - if (constrained_class) { - if (constrained_class->enumtype && !strcmp (target_method->name, "GetHashCode")) { - /* Use the corresponding method from the base type to avoid boxing */ - MonoType *base_type = mono_class_enum_basetype (constrained_class); - g_assert (base_type); - constrained_class = mono_class_from_mono_type (base_type); - target_method = mono_class_get_method_from_name (constrained_class, target_method->name, 0); - g_assert (target_method); - } - } - - if (constrained_class) { - mono_class_setup_vtable (constrained_class); -#if DEBUG_INTERP - g_print ("CONSTRAINED.CALLVIRT: %s::%s. %s (%p) ->\n", target_method->klass->name, target_method->name, mono_signature_full_name (target_method->signature), target_method); -#endif - target_method = mono_get_method_constrained_with_method (image, target_method, constrained_class, generic_context, &error); -#if DEBUG_INTERP - g_print (" : %s::%s. %s (%p)\n", target_method->klass->name, target_method->name, mono_signature_full_name (target_method->signature), target_method); -#endif - mono_error_cleanup (&error); /* FIXME: don't swallow the error */ - mono_class_setup_vtable (target_method->klass); - - if (constrained_class->valuetype && (target_method->klass == mono_defaults.object_class || target_method->klass == mono_defaults.enum_class->parent || target_method->klass == mono_defaults.enum_class)) { - if (target_method->klass == mono_defaults.enum_class && (td->sp - csignature->param_count - 1)->type == STACK_TYPE_MP) { - /* managed pointer on the stack, we need to deref that puppy */ - ADD_CODE (td, MINT_LDIND_I); - ADD_CODE (td, csignature->param_count); - } - ADD_CODE (td, MINT_BOX); - ADD_CODE (td, get_data_item_index (td, constrained_class)); - ADD_CODE (td, csignature->param_count); - } else if (!constrained_class->valuetype) { - /* managed pointer on the stack, we need to deref that puppy */ - ADD_CODE (td, MINT_LDIND_I); - ADD_CODE (td, csignature->param_count); - } else { - g_assert (target_method->klass->valuetype); - virtual = FALSE; - } - } - - if (target_method) - mono_class_init (target_method->klass); - - CHECK_STACK (td, csignature->param_count + csignature->hasthis); - if (!calli && (!virtual || (target_method->flags & METHOD_ATTRIBUTE_VIRTUAL) == 0) && - (target_method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) == 0 && - (target_method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) == 0) { - int called_inited = mono_class_vtable (domain, target_method->klass)->initialized; - MonoMethodHeader *mheader = mono_method_get_header (target_method); - - if (/*mono_metadata_signature_equal (method->signature, target_method->signature) */ method == target_method && *(td->ip + 5) == CEE_RET) { - int offset; - if (mono_interp_traceopt) - g_print ("Optimize tail call of %s.%s\n", target_method->klass->name, target_method->name); - for (i = csignature->param_count - 1; i >= 0; --i) - store_arg (td, i + csignature->hasthis); - - if (csignature->hasthis) { - g_error ("STTHIS removal"); - // ADD_CODE(td, MINT_STTHIS); - --td->sp; - } - ADD_CODE(td, MINT_BR_S); - offset = body_start_offset - ((td->new_ip - 1) - td->new_code); - ADD_CODE(td, offset); - if (!is_bb_start [td->ip + 5 - td->il_code]) - ++td->ip; /* gobble the CEE_RET if it isn't branched to */ - td->ip += 5; - return; - } else { - /* mheader might not exist if this is a delegate invoc, etc */ - if (mheader && *mheader->code == CEE_RET && called_inited) { - if (mono_interp_traceopt) - g_print ("Inline (empty) call of %s.%s\n", target_method->klass->name, target_method->name); - for (i = 0; i < csignature->param_count; i++) - ADD_CODE (td, MINT_POP); /*FIX: vt */ - ADD_CODE (td, 0); - if (csignature->hasthis) { - if (virtual) - ADD_CODE(td, MINT_CKNULL); - ADD_CODE (td, MINT_POP); - ADD_CODE (td, 0); - } - td->sp -= csignature->param_count + csignature->hasthis; - td->ip += 5; - return; - } - } - } - if (method->wrapper_type == MONO_WRAPPER_NONE && target_method != NULL) { - if (target_method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) - target_method = mono_marshal_get_native_wrapper (target_method, FALSE, FALSE); - if (!virtual && target_method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED) - target_method = mono_marshal_get_synchronized_wrapper (target_method); - } - g_assert (csignature->call_convention == MONO_CALL_DEFAULT || csignature->call_convention == MONO_CALL_C); - td->sp -= csignature->param_count + !!csignature->hasthis; - for (i = 0; i < csignature->param_count; ++i) { - if (td->sp [i + !!csignature->hasthis].type == STACK_TYPE_VT) { - gint32 size; - MonoClass *klass = mono_class_from_mono_type (csignature->params [i]); - if (csignature->pinvoke && method->wrapper_type != MONO_WRAPPER_NONE) - size = mono_class_native_size (klass, NULL); - else - size = mono_class_value_size (klass, NULL); - size = (size + 7) & ~7; - vt_stack_used += size; - } - } - - /* need to handle typedbyref ... */ - if (csignature->ret->type != MONO_TYPE_VOID) { - int mt = mint_type(csignature->ret); - MonoClass *klass = mono_class_from_mono_type (csignature->ret); - if (mt == MINT_TYPE_VT) { - if (csignature->pinvoke && method->wrapper_type != MONO_WRAPPER_NONE) - vt_res_size = mono_class_native_size (klass, NULL); - else - vt_res_size = mono_class_value_size (klass, NULL); - PUSH_VT(td, vt_res_size); - } - PUSH_TYPE(td, stack_type[mt], klass); - } else - is_void = TRUE; - - if (op >= 0) { - ADD_CODE(td, op); -#if SIZEOF_VOID_P == 8 - if (op == MINT_LDLEN) - ADD_CODE(td, MINT_CONV_I4_I8); -#endif - } else { - if (calli) - ADD_CODE(td, native ? MINT_CALLI_NAT : MINT_CALLI); - else if (virtual) - ADD_CODE(td, is_void ? MINT_VCALLVIRT : MINT_CALLVIRT); - else - ADD_CODE(td, is_void ? MINT_VCALL : MINT_CALL); - - if (calli) { - ADD_CODE(td, get_data_item_index (td, (void *)csignature)); - } else { - ADD_CODE(td, get_data_item_index (td, (void *)mono_interp_get_runtime_method (domain, target_method, &error))); - mono_error_cleanup (&error); /* FIXME: don't swallow the error */ - } - } - td->ip += 5; - if (vt_stack_used != 0 || vt_res_size != 0) { - ADD_CODE(td, MINT_VTRESULT); - ADD_CODE(td, vt_res_size); - WRITE32(td, &vt_stack_used); - td->vt_sp -= vt_stack_used; - } -} - -static void -generate (MonoMethod *method, RuntimeMethod *rtm, unsigned char *is_bb_start, MonoGenericContext *generic_context) -{ - MonoMethodHeader *header = mono_method_get_header (method); - MonoMethodSignature *signature = mono_method_signature (method); - MonoImage *image = method->klass->image; - MonoDomain *domain = mono_domain_get (); - MonoClass *constrained_class = NULL; - MonoError error; - int offset, mt; - int i; - int i32; - MonoClass *klass; - MonoClassField *field; - const unsigned char *end; - int new_in_start_offset; - int body_start_offset; - int target; - guint32 token; - TransformData td; - int generating_code = 1; - - memset(&td, 0, sizeof(td)); - td.method = method; - td.rtm = rtm; - td.is_bb_start = is_bb_start; - td.il_code = header->code; - td.code_size = header->code_size; - td.header = header; - td.max_code_size = td.code_size; - td.new_code = (unsigned short *)g_malloc(td.max_code_size * sizeof(gushort)); - td.new_code_end = td.new_code + td.max_code_size; - td.in_offsets = g_malloc0(header->code_size * sizeof(int)); - td.forward_refs = g_malloc(header->code_size * sizeof(int)); - td.stack_state = g_malloc0(header->code_size * sizeof(StackInfo *)); - td.stack_height = g_malloc(header->code_size * sizeof(int)); - td.vt_stack_size = g_malloc(header->code_size * sizeof(int)); - td.n_data_items = 0; - td.max_data_items = 0; - td.data_items = NULL; - td.data_hash = g_hash_table_new (NULL, NULL); - rtm->data_items = td.data_items; - for (i = 0; i < header->code_size; i++) { - td.forward_refs [i] = -1; - td.stack_height [i] = -1; - } - td.new_ip = td.new_code; - td.last_new_ip = NULL; - - td.stack = g_malloc0(header->max_stack * sizeof(td.stack[0])); - td.sp = td.stack; - td.max_stack_height = 0; - - for (i = 0; i < header->num_clauses; i++) { - MonoExceptionClause *c = header->clauses + i; - td.stack_height [c->handler_offset] = 0; - td.vt_stack_size [c->handler_offset] = 0; - td.is_bb_start [c->handler_offset] = 1; - if (c->flags == MONO_EXCEPTION_CLAUSE_NONE) { - td.stack_height [c->handler_offset] = 1; - td.stack_state [c->handler_offset] = g_malloc0(sizeof(StackInfo)); - td.stack_state [c->handler_offset][0].type = STACK_TYPE_O; - td.stack_state [c->handler_offset][0].klass = NULL; /*FIX*/ - } - } - - td.ip = header->code; - end = td.ip + header->code_size; - - if (mono_interp_traceopt) { - char *tmp = mono_disasm_code (NULL, method, td.ip, end); - char *name = mono_method_full_name (method, TRUE); - g_print ("Method %s, original code:\n", name); - g_print ("%s\n", tmp); - g_free (tmp); - g_free (name); - } - - if (signature->hasthis) - store_inarg (&td, 0); - for (i = 0; i < signature->param_count; i++) - store_inarg (&td, i + !!signature->hasthis); - - body_start_offset = td.new_ip - td.new_code; - - for (i = 0; i < header->num_locals; i++) { - int mt = mint_type(header->locals [i]); - if (mt == MINT_TYPE_VT || mt == MINT_TYPE_O) { - ADD_CODE(&td, MINT_INITLOCALS); - break; - } - } - - while (td.ip < end) { - int in_offset; - - g_assert (td.sp >= td.stack); - g_assert (td.vt_sp < 0x10000000); - in_offset = td.ip - header->code; - td.in_offsets [in_offset] = td.new_ip - td.new_code; - new_in_start_offset = td.new_ip - td.new_code; - td.in_start = td.ip; - while (td.forward_refs [in_offset] >= 0) { - int j = td.forward_refs [in_offset]; - int slot; - td.forward_refs [in_offset] = td.forward_refs [j]; - if (td.in_offsets [j] < 0) { - int old_switch_offset = -td.in_offsets [j]; - int new_switch_offset = td.in_offsets [old_switch_offset]; - int switch_case = (j - old_switch_offset - 5) / 4; - int n_cases = read32 (header->code + old_switch_offset + 1); - offset = (td.new_ip - td.new_code) - (new_switch_offset + 2 * n_cases + 3); - slot = new_switch_offset + 3 + 2 * switch_case; - td.new_code [slot] = * (unsigned short *)(&offset); - td.new_code [slot + 1] = * ((unsigned short *)&offset + 1); - } else { - int op = td.new_code [td.in_offsets [j]]; - if (mono_interp_opargtype [op] == MintOpShortBranch) { - offset = (td.new_ip - td.new_code) - td.in_offsets [j]; - g_assert (offset <= 32767); - slot = td.in_offsets [j] + 1; - td.new_code [slot] = offset; - } else { - offset = (td.new_ip - td.new_code) - td.in_offsets [j]; - slot = td.in_offsets [j] + 1; - td.new_code [slot] = * (unsigned short *)(&offset); - td.new_code [slot + 1] = * ((unsigned short *)&offset + 1); - } - } - } - if (td.stack_height [in_offset] >= 0) { - g_assert (is_bb_start [in_offset]); - if (td.stack_height [in_offset] > 0) - memcpy (td.stack, td.stack_state [in_offset], td.stack_height [in_offset] * sizeof(td.stack [0])); - td.sp = td.stack + td.stack_height [in_offset]; - td.vt_sp = td.vt_stack_size [in_offset]; - } - if (is_bb_start [in_offset]) { - generating_code = 1; - } - if (!generating_code) { - while (td.ip < end && !is_bb_start [td.ip - td.il_code]) - ++td.ip; - continue; - } - if (mono_interp_traceopt > 1) { - printf("IL_%04lx %s %-10s -> IL_%04lx, sp %ld, %s %-12s vt_sp %u (max %u)\n", - td.ip - td.il_code, - td.is_bb_start [td.ip - td.il_code] == 3 ? "<>" : - td.is_bb_start [td.ip - td.il_code] == 2 ? "< " : - td.is_bb_start [td.ip - td.il_code] == 1 ? " >" : " ", - mono_opcode_name (*td.ip), td.new_ip - td.new_code, td.sp - td.stack, - td.sp > td.stack ? stack_type_string [td.sp [-1].type] : " ", - (td.sp > td.stack && (td.sp [-1].type == STACK_TYPE_O || td.sp [-1].type == STACK_TYPE_VT)) ? (td.sp [-1].klass == NULL ? "?" : td.sp [-1].klass->name) : "", - td.vt_sp, td.max_vt_sp); - } - switch (*td.ip) { - case CEE_NOP: - /* lose it */ - ++td.ip; - break; - case CEE_BREAK: - SIMPLE_OP(td, MINT_BREAK); - break; - case CEE_LDARG_0: - case CEE_LDARG_1: - case CEE_LDARG_2: - case CEE_LDARG_3: - load_arg (&td, *td.ip - CEE_LDARG_0); - ++td.ip; - break; - case CEE_LDLOC_0: - case CEE_LDLOC_1: - case CEE_LDLOC_2: - case CEE_LDLOC_3: - load_local (&td, *td.ip - CEE_LDLOC_0); - ++td.ip; - break; - case CEE_STLOC_0: - case CEE_STLOC_1: - case CEE_STLOC_2: - case CEE_STLOC_3: - store_local (&td, *td.ip - CEE_STLOC_0); - ++td.ip; - break; - case CEE_LDARG_S: - load_arg (&td, ((guint8 *)td.ip)[1]); - td.ip += 2; - break; - case CEE_LDARGA_S: { - /* NOTE: n includes this */ - int n = ((guint8 *)td.ip)[1]; - if (n == 0 && signature->hasthis) { - g_error ("LDTHISA: NOPE"); - ADD_CODE(&td, MINT_LDTHISA); - } - else { - ADD_CODE(&td, MINT_LDARGA); - ADD_CODE(&td, td.rtm->arg_offsets [n]); - } - PUSH_SIMPLE_TYPE(&td, STACK_TYPE_MP); - td.ip += 2; - break; - } - case CEE_STARG_S: - store_arg (&td, ((guint8 *)td.ip)[1]); - td.ip += 2; - break; - case CEE_LDLOC_S: - load_local (&td, ((guint8 *)td.ip)[1]); - td.ip += 2; - break; - case CEE_LDLOCA_S: - ADD_CODE(&td, MINT_LDLOCA_S); - ADD_CODE(&td, td.rtm->local_offsets [((guint8 *)td.ip)[1]]); - PUSH_SIMPLE_TYPE(&td, STACK_TYPE_MP); - td.ip += 2; - break; - case CEE_STLOC_S: - store_local (&td, ((guint8 *)td.ip)[1]); - td.ip += 2; - break; - case CEE_LDNULL: - SIMPLE_OP(td, MINT_LDNULL); - PUSH_TYPE(&td, STACK_TYPE_O, NULL); - break; - case CEE_LDC_I4_M1: - SIMPLE_OP(td, MINT_LDC_I4_M1); - PUSH_SIMPLE_TYPE(&td, STACK_TYPE_I4); - break; - case CEE_LDC_I4_0: - if (!td.is_bb_start[td.ip + 1 - td.il_code] && td.ip [1] == 0xfe && td.ip [2] == CEE_CEQ && - td.sp > td.stack && td.sp [-1].type == STACK_TYPE_I4) { - SIMPLE_OP(td, MINT_CEQ0_I4); - td.ip += 2; - } else { - SIMPLE_OP(td, MINT_LDC_I4_0); - PUSH_SIMPLE_TYPE(&td, STACK_TYPE_I4); - } - break; - case CEE_LDC_I4_1: - if (!td.is_bb_start[td.ip + 1 - td.il_code] && - (td.ip [1] == CEE_ADD || td.ip [1] == CEE_SUB) && td.sp [-1].type == STACK_TYPE_I4) { - ADD_CODE(&td, td.ip [1] == CEE_ADD ? MINT_ADD1_I4 : MINT_SUB1_I4); - td.ip += 2; - } else { - SIMPLE_OP(td, MINT_LDC_I4_1); - PUSH_SIMPLE_TYPE(&td, STACK_TYPE_I4); - } - break; - case CEE_LDC_I4_2: - case CEE_LDC_I4_3: - case CEE_LDC_I4_4: - case CEE_LDC_I4_5: - case CEE_LDC_I4_6: - case CEE_LDC_I4_7: - case CEE_LDC_I4_8: - SIMPLE_OP(td, (*td.ip - CEE_LDC_I4_0) + MINT_LDC_I4_0); - PUSH_SIMPLE_TYPE(&td, STACK_TYPE_I4); - break; - case CEE_LDC_I4_S: - ADD_CODE(&td, MINT_LDC_I4_S); - ADD_CODE(&td, ((gint8 *) td.ip) [1]); - td.ip += 2; - PUSH_SIMPLE_TYPE(&td, STACK_TYPE_I4); - break; - case CEE_LDC_I4: - i32 = read32 (td.ip + 1); - ADD_CODE(&td, MINT_LDC_I4); - WRITE32(&td, &i32); - td.ip += 5; - PUSH_SIMPLE_TYPE(&td, STACK_TYPE_I4); - break; - case CEE_LDC_I8: { - gint64 val = read64 (td.ip + 1); - ADD_CODE(&td, MINT_LDC_I8); - WRITE64(&td, &val); - td.ip += 9; - PUSH_SIMPLE_TYPE(&td, STACK_TYPE_I8); - break; - } - case CEE_LDC_R4: { - float val; - readr4 (td.ip + 1, &val); - ADD_CODE(&td, MINT_LDC_R4); - WRITE32(&td, &val); - td.ip += 5; - PUSH_SIMPLE_TYPE(&td, STACK_TYPE_R8); - break; - } - case CEE_LDC_R8: { - double val; - readr8 (td.ip + 1, &val); - ADD_CODE(&td, MINT_LDC_R8); - WRITE64(&td, &val); - td.ip += 9; - PUSH_SIMPLE_TYPE(&td, STACK_TYPE_R8); - break; - } - case CEE_DUP: { - int type = td.sp [-1].type; - MonoClass *klass = td.sp [-1].klass; - if (td.sp [-1].type == STACK_TYPE_VT) { - gint32 size = mono_class_value_size (klass, NULL); - PUSH_VT(&td, size); - ADD_CODE(&td, MINT_DUP_VT); - WRITE32(&td, &size); - td.ip ++; - } else - SIMPLE_OP(td, MINT_DUP); - PUSH_TYPE(&td, type, klass); - break; - } - case CEE_POP: - CHECK_STACK(&td, 1); - SIMPLE_OP(td, MINT_POP); - ADD_CODE (&td, 0); - if (td.sp [-1].type == STACK_TYPE_VT) { - int size = mono_class_value_size (td.sp [-1].klass, NULL); - size = (size + 7) & ~7; - ADD_CODE(&td, MINT_VTRESULT); - ADD_CODE(&td, 0); - WRITE32(&td, &size); - td.vt_sp -= size; - } - --td.sp; - break; - case CEE_JMP: { - MonoMethod *m; - if (td.sp > td.stack) - g_warning ("CEE_JMP: stack must be empty"); - token = read32 (td.ip + 1); - m = mono_get_method_full (image, token, NULL, generic_context); - ADD_CODE (&td, MINT_JMP); - ADD_CODE (&td, get_data_item_index (&td, mono_interp_get_runtime_method (domain, m, &error))); - mono_error_cleanup (&error); /* FIXME: don't swallow the error */ - td.ip += 5; - break; - } - case CEE_CALLVIRT: /* Fall through */ - case CEE_CALLI: /* Fall through */ - case CEE_CALL: { - interp_transform_call (&td, method, NULL, domain, generic_context, is_bb_start, body_start_offset, constrained_class); - constrained_class = NULL; - break; - } - case CEE_RET: { - int vt_size = 0; - if (signature->ret->type != MONO_TYPE_VOID) { - --td.sp; - MonoClass *klass = mono_class_from_mono_type (signature->ret); - if (mint_type (&klass->byval_arg) == MINT_TYPE_VT) { - vt_size = mono_class_value_size (klass, NULL); - vt_size = (vt_size + 7) & ~7; - } - } - if (td.sp > td.stack) - g_warning ("%s.%s: CEE_RET: more values on stack: %d", td.method->klass->name, td.method->name, td.sp - td.stack); - if (td.vt_sp != vt_size) - g_error ("%s.%s: CEE_RET: value type stack: %d vs. %d", td.method->klass->name, td.method->name, td.vt_sp, vt_size); - if (vt_size == 0) - SIMPLE_OP(td, signature->ret->type == MONO_TYPE_VOID ? MINT_RET_VOID : MINT_RET); - else { - ADD_CODE(&td, MINT_RET_VT); - WRITE32(&td, &vt_size); - ++td.ip; - } - generating_code = 0; - break; - } - case CEE_BR: - handle_branch (&td, MINT_BR_S, MINT_BR, 5 + read32 (td.ip + 1)); - td.ip += 5; - generating_code = 0; - break; - case CEE_BR_S: - handle_branch (&td, MINT_BR_S, MINT_BR, 2 + (gint8)td.ip [1]); - td.ip += 2; - generating_code = 0; - break; - case CEE_BRFALSE: - one_arg_branch (&td, MINT_BRFALSE_I4, 5 + read32 (td.ip + 1)); - td.ip += 5; - break; - case CEE_BRFALSE_S: - one_arg_branch (&td, MINT_BRFALSE_I4, 2 + (gint8)td.ip [1]); - td.ip += 2; - break; - case CEE_BRTRUE: - one_arg_branch (&td, MINT_BRTRUE_I4, 5 + read32 (td.ip + 1)); - td.ip += 5; - break; - case CEE_BRTRUE_S: - one_arg_branch (&td, MINT_BRTRUE_I4, 2 + (gint8)td.ip [1]); - td.ip += 2; - break; - case CEE_BEQ: - two_arg_branch (&td, MINT_BEQ_I4, 5 + read32 (td.ip + 1)); - td.ip += 5; - break; - case CEE_BEQ_S: - two_arg_branch (&td, MINT_BEQ_I4, 2 + (gint8) td.ip [1]); - td.ip += 2; - break; - case CEE_BGE: - two_arg_branch (&td, MINT_BGE_I4, 5 + read32 (td.ip + 1)); - td.ip += 5; - break; - case CEE_BGE_S: - two_arg_branch (&td, MINT_BGE_I4, 2 + (gint8) td.ip [1]); - td.ip += 2; - break; - case CEE_BGT: - two_arg_branch (&td, MINT_BGT_I4, 5 + read32 (td.ip + 1)); - td.ip += 5; - break; - case CEE_BGT_S: - two_arg_branch (&td, MINT_BGT_I4, 2 + (gint8) td.ip [1]); - td.ip += 2; - break; - case CEE_BLT: - two_arg_branch (&td, MINT_BLT_I4, 5 + read32 (td.ip + 1)); - td.ip += 5; - break; - case CEE_BLT_S: - two_arg_branch (&td, MINT_BLT_I4, 2 + (gint8) td.ip [1]); - td.ip += 2; - break; - case CEE_BLE: - two_arg_branch (&td, MINT_BLE_I4, 5 + read32 (td.ip + 1)); - td.ip += 5; - break; - case CEE_BLE_S: - two_arg_branch (&td, MINT_BLE_I4, 2 + (gint8) td.ip [1]); - td.ip += 2; - break; - case CEE_BNE_UN: - two_arg_branch (&td, MINT_BNE_UN_I4, 5 + read32 (td.ip + 1)); - td.ip += 5; - break; - case CEE_BNE_UN_S: - two_arg_branch (&td, MINT_BNE_UN_I4, 2 + (gint8) td.ip [1]); - td.ip += 2; - break; - case CEE_BGE_UN: - two_arg_branch (&td, MINT_BGE_UN_I4, 5 + read32 (td.ip + 1)); - td.ip += 5; - break; - case CEE_BGE_UN_S: - two_arg_branch (&td, MINT_BGE_UN_I4, 2 + (gint8) td.ip [1]); - td.ip += 2; - break; - case CEE_BGT_UN: - two_arg_branch (&td, MINT_BGT_UN_I4, 5 + read32 (td.ip + 1)); - td.ip += 5; - break; - case CEE_BGT_UN_S: - two_arg_branch (&td, MINT_BGT_UN_I4, 2 + (gint8) td.ip [1]); - td.ip += 2; - break; - case CEE_BLE_UN: - two_arg_branch (&td, MINT_BLE_UN_I4, 5 + read32 (td.ip + 1)); - td.ip += 5; - break; - case CEE_BLE_UN_S: - two_arg_branch (&td, MINT_BLE_UN_I4, 2 + (gint8) td.ip [1]); - td.ip += 2; - break; - case CEE_BLT_UN: - two_arg_branch (&td, MINT_BLT_UN_I4, 5 + read32 (td.ip + 1)); - td.ip += 5; - break; - case CEE_BLT_UN_S: - two_arg_branch (&td, MINT_BLT_UN_I4, 2 + (gint8) td.ip [1]); - td.ip += 2; - break; - case CEE_SWITCH: { - guint32 n; - const unsigned char *next_ip; - const unsigned char *base_ip = td.ip; - unsigned short *next_new_ip; - ++td.ip; - n = read32 (td.ip); - ADD_CODE(&td, MINT_SWITCH); - ADD_CODE(&td, * (unsigned short *)(&n)); - ADD_CODE(&td, * ((unsigned short *)&n + 1)); - td.ip += 4; - next_ip = td.ip + n * 4; - next_new_ip = td.new_ip + n * 2; - for (i = 0; i < n; i++) { - offset = read32 (td.ip); - target = next_ip - td.il_code + offset; - if (offset < 0) - target = td.in_offsets [target] - (next_new_ip - td.new_code); - else { - int prev = td.forward_refs [target]; - td.forward_refs [td.ip - td.il_code] = prev; - td.forward_refs [target] = td.ip - td.il_code; - td.in_offsets [td.ip - td.il_code] = - (base_ip - td.il_code); - } - ADD_CODE(&td, * (unsigned short *)(&target)); - ADD_CODE(&td, * ((unsigned short *)&target + 1)); - td.ip += 4; - } - --td.sp; - break; - } - case CEE_LDIND_I1: - CHECK_STACK (&td, 1); - SIMPLE_OP (td, MINT_LDIND_I1); - SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I4); - break; - case CEE_LDIND_U1: - CHECK_STACK (&td, 1); - SIMPLE_OP (td, MINT_LDIND_U1); - SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I4); - break; - case CEE_LDIND_I2: - CHECK_STACK (&td, 1); - SIMPLE_OP (td, MINT_LDIND_I2); - SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I4); - break; - case CEE_LDIND_U2: - CHECK_STACK (&td, 1); - SIMPLE_OP (td, MINT_LDIND_U2); - SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I4); - break; - case CEE_LDIND_I4: - CHECK_STACK (&td, 1); - SIMPLE_OP (td, MINT_LDIND_I4); - SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I4); - break; - case CEE_LDIND_U4: - CHECK_STACK (&td, 1); - SIMPLE_OP (td, MINT_LDIND_U4); - SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I4); - break; - case CEE_LDIND_I8: - CHECK_STACK (&td, 1); - SIMPLE_OP (td, MINT_LDIND_I8); - SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I8); - break; - case CEE_LDIND_I: - CHECK_STACK (&td, 1); - SIMPLE_OP (td, MINT_LDIND_I); - ADD_CODE (&td, 0); - SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I); - break; - case CEE_LDIND_R4: - CHECK_STACK (&td, 1); - SIMPLE_OP (td, MINT_LDIND_R4); - SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_R8); - break; - case CEE_LDIND_R8: - CHECK_STACK (&td, 1); - SIMPLE_OP (td, MINT_LDIND_R8); - SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_R8); - break; - case CEE_LDIND_REF: - CHECK_STACK (&td, 1); - SIMPLE_OP (td, MINT_LDIND_REF); - SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_O); - break; - case CEE_STIND_REF: - CHECK_STACK (&td, 2); - SIMPLE_OP (td, MINT_STIND_REF); - td.sp -= 2; - break; - case CEE_STIND_I1: - CHECK_STACK (&td, 2); - SIMPLE_OP (td, MINT_STIND_I1); - td.sp -= 2; - break; - case CEE_STIND_I2: - CHECK_STACK (&td, 2); - SIMPLE_OP (td, MINT_STIND_I2); - td.sp -= 2; - break; - case CEE_STIND_I4: - CHECK_STACK (&td, 2); - SIMPLE_OP (td, MINT_STIND_I4); - td.sp -= 2; - break; - case CEE_STIND_I: - CHECK_STACK (&td, 2); - SIMPLE_OP (td, MINT_STIND_I); - td.sp -= 2; - break; - case CEE_STIND_I8: - CHECK_STACK (&td, 2); - SIMPLE_OP (td, MINT_STIND_I8); - td.sp -= 2; - break; - case CEE_STIND_R4: - CHECK_STACK (&td, 2); - SIMPLE_OP (td, MINT_STIND_R4); - td.sp -= 2; - break; - case CEE_STIND_R8: - CHECK_STACK (&td, 2); - SIMPLE_OP (td, MINT_STIND_R8); - td.sp -= 2; - break; - case CEE_ADD: - binary_arith_op(&td, MINT_ADD_I4); - ++td.ip; - break; - case CEE_SUB: - binary_arith_op(&td, MINT_SUB_I4); - ++td.ip; - break; - case CEE_MUL: - binary_arith_op(&td, MINT_MUL_I4); - ++td.ip; - break; - case CEE_DIV: - binary_arith_op(&td, MINT_DIV_I4); - ++td.ip; - break; - case CEE_DIV_UN: - binary_arith_op(&td, MINT_DIV_UN_I4); - ++td.ip; - break; - case CEE_REM: - binary_int_op (&td, MINT_REM_I4); - ++td.ip; - break; - case CEE_REM_UN: - binary_int_op (&td, MINT_REM_UN_I4); - ++td.ip; - break; - case CEE_AND: - binary_int_op (&td, MINT_AND_I4); - ++td.ip; - break; - case CEE_OR: - binary_int_op (&td, MINT_OR_I4); - ++td.ip; - break; - case CEE_XOR: - binary_int_op (&td, MINT_XOR_I4); - ++td.ip; - break; - case CEE_SHL: - shift_op (&td, MINT_SHL_I4); - ++td.ip; - break; - case CEE_SHR: - shift_op (&td, MINT_SHR_I4); - ++td.ip; - break; - case CEE_SHR_UN: - shift_op (&td, MINT_SHR_UN_I4); - ++td.ip; - break; - case CEE_NEG: - unary_arith_op (&td, MINT_NEG_I4); - ++td.ip; - break; - case CEE_NOT: - unary_arith_op (&td, MINT_NOT_I4); - ++td.ip; - break; - case CEE_CONV_U1: - CHECK_STACK (&td, 1); - switch (td.sp [-1].type) { - case STACK_TYPE_R8: - ADD_CODE(&td, MINT_CONV_U1_R8); - break; - case STACK_TYPE_I4: - ADD_CODE(&td, MINT_CONV_U1_I4); - break; - case STACK_TYPE_I8: - ADD_CODE(&td, MINT_CONV_U1_I8); - break; - default: - g_assert_not_reached (); - } - ++td.ip; - SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I4); - break; - case CEE_CONV_I1: - CHECK_STACK (&td, 1); - switch (td.sp [-1].type) { - case STACK_TYPE_R8: - ADD_CODE(&td, MINT_CONV_I1_R8); - break; - case STACK_TYPE_I4: - ADD_CODE(&td, MINT_CONV_I1_I4); - break; - case STACK_TYPE_I8: - ADD_CODE(&td, MINT_CONV_I1_I8); - break; - default: - g_assert_not_reached (); - } - ++td.ip; - SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I4); - break; - case CEE_CONV_U2: - CHECK_STACK (&td, 1); - switch (td.sp [-1].type) { - case STACK_TYPE_R8: - ADD_CODE(&td, MINT_CONV_U2_R8); - break; - case STACK_TYPE_I4: - ADD_CODE(&td, MINT_CONV_U2_I4); - break; - case STACK_TYPE_I8: - ADD_CODE(&td, MINT_CONV_U2_I8); - break; - default: - g_assert_not_reached (); - } - ++td.ip; - SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I4); - break; - case CEE_CONV_I2: - CHECK_STACK (&td, 1); - switch (td.sp [-1].type) { - case STACK_TYPE_R8: - ADD_CODE(&td, MINT_CONV_I2_R8); - break; - case STACK_TYPE_I4: - ADD_CODE(&td, MINT_CONV_I2_I4); - break; - case STACK_TYPE_I8: - ADD_CODE(&td, MINT_CONV_I2_I8); - break; - default: - g_assert_not_reached (); - } - ++td.ip; - SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I4); - break; - case CEE_CONV_U: - CHECK_STACK (&td, 1); - switch (td.sp [-1].type) { - case STACK_TYPE_R8: -#if SIZEOF_VOID_P == 4 - ADD_CODE(&td, MINT_CONV_U4_R8); -#else - ADD_CODE(&td, MINT_CONV_U8_R8); -#endif - break; - case STACK_TYPE_I4: -#if SIZEOF_VOID_P == 8 - ADD_CODE(&td, MINT_CONV_U8_I4); -#endif - break; - case STACK_TYPE_I8: -#if SIZEOF_VOID_P == 4 - ADD_CODE(&td, MINT_CONV_U4_I8); -#endif - break; - case STACK_TYPE_MP: - break; - default: - g_assert_not_reached (); - } - ++td.ip; - SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I); - break; - case CEE_CONV_I: - CHECK_STACK (&td, 1); - switch (td.sp [-1].type) { - case STACK_TYPE_R8: -#if SIZEOF_VOID_P == 8 - ADD_CODE(&td, MINT_CONV_I8_R8); -#else - ADD_CODE(&td, MINT_CONV_I4_R8); -#endif - break; - case STACK_TYPE_I4: -#if SIZEOF_VOID_P == 8 - ADD_CODE(&td, MINT_CONV_I8_I4); -#endif - break; - case STACK_TYPE_O: - break; - case STACK_TYPE_MP: - break; - case STACK_TYPE_I8: -#if SIZEOF_VOID_P == 4 - ADD_CODE(&td, MINT_CONV_I4_I8); -#endif - break; - default: - g_assert_not_reached (); - } - ++td.ip; - SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I); - break; - case CEE_CONV_U4: - CHECK_STACK (&td, 1); - switch (td.sp [-1].type) { - case STACK_TYPE_R8: - ADD_CODE(&td, MINT_CONV_U4_R8); - break; - case STACK_TYPE_I4: - break; - case STACK_TYPE_I8: - ADD_CODE(&td, MINT_CONV_U4_I8); - break; - case STACK_TYPE_MP: -#if SIZEOF_VOID_P == 8 - ADD_CODE(&td, MINT_CONV_U4_I8); -#endif - break; - default: - g_assert_not_reached (); - } - ++td.ip; - SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I4); - break; - case CEE_CONV_I4: - CHECK_STACK (&td, 1); - switch (td.sp [-1].type) { - case STACK_TYPE_R8: - ADD_CODE(&td, MINT_CONV_I4_R8); - break; - case STACK_TYPE_I4: - break; - case STACK_TYPE_I8: - ADD_CODE(&td, MINT_CONV_I4_I8); - break; - case STACK_TYPE_MP: -#if SIZEOF_VOID_P == 8 - ADD_CODE(&td, MINT_CONV_I4_I8); -#endif - break; - default: - g_assert_not_reached (); - } - ++td.ip; - SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I4); - break; - case CEE_CONV_I8: - CHECK_STACK (&td, 1); - switch (td.sp [-1].type) { - case STACK_TYPE_R8: - ADD_CODE(&td, MINT_CONV_I8_R8); - break; - case STACK_TYPE_I4: - ADD_CODE(&td, MINT_CONV_I8_I4); - break; - case STACK_TYPE_I8: - break; - case STACK_TYPE_MP: -#if SIZEOF_VOID_P == 4 - ADD_CODE(&td, MINT_CONV_I8_I4); -#endif - break; - default: - g_assert_not_reached (); - } - ++td.ip; - SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I8); - break; - case CEE_CONV_R4: - CHECK_STACK (&td, 1); - switch (td.sp [-1].type) { - case STACK_TYPE_R8: - ADD_CODE(&td, MINT_CONV_R4_R8); - break; - case STACK_TYPE_I8: - ADD_CODE(&td, MINT_CONV_R4_I8); - break; - case STACK_TYPE_I4: - ADD_CODE(&td, MINT_CONV_R4_I4); - break; - default: - g_assert_not_reached (); - } - ++td.ip; - SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_R8); - break; - case CEE_CONV_R8: - CHECK_STACK (&td, 1); - switch (td.sp [-1].type) { - case STACK_TYPE_I4: - ADD_CODE(&td, MINT_CONV_R8_I4); - break; - case STACK_TYPE_I8: - ADD_CODE(&td, MINT_CONV_R8_I8); - break; - case STACK_TYPE_R8: - break; - default: - g_assert_not_reached (); - } - ++td.ip; - SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_R8); - break; - case CEE_CONV_U8: - CHECK_STACK (&td, 1); - switch (td.sp [-1].type) { - case STACK_TYPE_I4: - ADD_CODE(&td, MINT_CONV_U8_I4); - break; - case STACK_TYPE_I8: - break; - case STACK_TYPE_R8: - ADD_CODE(&td, MINT_CONV_U8_R8); - break; - case STACK_TYPE_MP: -#if SIZEOF_VOID_P == 4 - ADD_CODE(&td, MINT_CONV_U8_I4); -#endif - break; - default: - g_assert_not_reached (); - } - ++td.ip; - SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I8); - break; -#if 0 - case CEE_CPOBJ: { - MonoClass *vtklass; - ++ip; - vtklass = mono_class_get_full (image, read32 (ip), generic_context); - ip += 4; - sp -= 2; - memcpy (sp [0].data.p, sp [1].data.p, mono_class_value_size (vtklass, NULL)); - break; - } -#endif - case CEE_LDOBJ: { - int size; - CHECK_STACK (&td, 1); - - token = read32 (td.ip + 1); - - if (method->wrapper_type != MONO_WRAPPER_NONE) - klass = (MonoClass *)mono_method_get_wrapper_data (method, token); - else - klass = mono_class_get_full (image, token, generic_context); - - ADD_CODE(&td, MINT_LDOBJ); - ADD_CODE(&td, get_data_item_index(&td, klass)); - if (mint_type (&klass->byval_arg) == MINT_TYPE_VT) { - size = mono_class_value_size (klass, NULL); - PUSH_VT(&td, size); - } - td.ip += 5; - SET_TYPE(td.sp - 1, stack_type[mint_type(&klass->byval_arg)], klass); - break; - } - case CEE_LDSTR: { - MonoString *s; - token = mono_metadata_token_index (read32 (td.ip + 1)); - td.ip += 5; - if (method->wrapper_type != MONO_WRAPPER_NONE) { - s = mono_string_new_wrapper( - mono_method_get_wrapper_data (method, token)); - } - else - s = mono_ldstr (domain, image, token); - ADD_CODE(&td, MINT_LDSTR); - ADD_CODE(&td, get_data_item_index (&td, s)); - PUSH_TYPE(&td, STACK_TYPE_O, mono_defaults.string_class); - break; - } - case CEE_NEWOBJ: { - MonoMethod *m; - MonoMethodSignature *csignature; - guint32 vt_stack_used = 0; - guint32 vt_res_size = 0; - - td.ip++; - token = read32 (td.ip); - td.ip += 4; - - if (method->wrapper_type != MONO_WRAPPER_NONE) - m = (MonoMethod *)mono_method_get_wrapper_data (method, token); - else - m = mono_get_method_full (image, token, NULL, generic_context); - - csignature = mono_method_signature (m); - klass = m->klass; - td.sp -= csignature->param_count; - ADD_CODE(&td, MINT_NEWOBJ); - ADD_CODE(&td, get_data_item_index (&td, mono_interp_get_runtime_method (domain, m, &error))); - mono_error_cleanup (&error); /* FIXME: don't swallow the error */ - - if (mint_type (&klass->byval_arg) == MINT_TYPE_VT) { - vt_res_size = mono_class_value_size (klass, NULL); - PUSH_VT (&td, vt_res_size); - } - for (i = 0; i < csignature->param_count; ++i) { - int mt = mint_type(csignature->params [i]); - if (mt == MINT_TYPE_VT) { - MonoClass *k = mono_class_from_mono_type (csignature->params [i]); - gint32 size = mono_class_value_size (k, NULL); - size = (size + 7) & ~7; - vt_stack_used += size; - } - } - if (vt_stack_used != 0 || vt_res_size != 0) { - ADD_CODE(&td, MINT_VTRESULT); - ADD_CODE(&td, vt_res_size); - WRITE32(&td, &vt_stack_used); - td.vt_sp -= vt_stack_used; - } - PUSH_TYPE (&td, stack_type [mint_type (&klass->byval_arg)], klass); - break; - } - case CEE_CASTCLASS: - CHECK_STACK (&td, 1); - token = read32 (td.ip + 1); - klass = mono_class_get_full (image, token, generic_context); - ADD_CODE(&td, MINT_CASTCLASS); - ADD_CODE(&td, get_data_item_index (&td, klass)); - td.sp [-1].klass = klass; - td.ip += 5; - break; - case CEE_ISINST: - CHECK_STACK (&td, 1); - token = read32 (td.ip + 1); - klass = mono_class_get_full (image, token, generic_context); - ADD_CODE(&td, MINT_ISINST); - ADD_CODE(&td, get_data_item_index (&td, klass)); - td.ip += 5; - break; - case CEE_CONV_R_UN: - switch (td.sp [-1].type) { - case STACK_TYPE_R8: - break; - case STACK_TYPE_I8: - ADD_CODE(&td, MINT_CONV_R_UN_I8); - break; - case STACK_TYPE_I4: - ADD_CODE(&td, MINT_CONV_R_UN_I4); - break; - default: - g_assert_not_reached (); - } - SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_R8); - ++td.ip; - break; - case CEE_UNBOX: - CHECK_STACK (&td, 1); - token = read32 (td.ip + 1); - - if (method->wrapper_type != MONO_WRAPPER_NONE) - klass = (MonoClass *)mono_method_get_wrapper_data (method, token); - else - klass = mono_class_get_full (image, token, generic_context); - - if (mono_class_is_nullable (klass)) { - g_error ("cee_unbox: implement Nullable"); - } - - ADD_CODE(&td, MINT_UNBOX); - ADD_CODE(&td, get_data_item_index (&td, klass)); - SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_MP); - td.ip += 5; - break; - case CEE_UNBOX_ANY: - CHECK_STACK (&td, 1); - token = read32 (td.ip + 1); - - g_assert (method->wrapper_type == MONO_WRAPPER_NONE); - klass = mono_class_get_full (image, token, generic_context); - - if (mini_type_is_reference (&klass->byval_arg)) { - g_error ("unbox_any: generic class is reference type"); - } else if (mono_class_is_nullable (klass)) { - MonoMethod *target_method = mono_class_get_method_from_name (klass, "Unbox", 1); - /* td.ip is incremented by interp_transform_call */ - interp_transform_call (&td, method, target_method, domain, generic_context, is_bb_start, body_start_offset, NULL); - } else { - int mt = mint_type (&klass->byval_arg); - ADD_CODE (&td, MINT_UNBOX); - ADD_CODE (&td, get_data_item_index (&td, klass)); - SET_TYPE (td.sp - 1, stack_type [mt], klass); - if (mt == MINT_TYPE_VT) { - int size = mono_class_value_size (klass, NULL); - PUSH_VT (&td, size); - } - td.ip += 5; - } - - break; - case CEE_THROW: - CHECK_STACK (&td, 1); - SIMPLE_OP (td, MINT_THROW); - --td.sp; - generating_code = 0; - break; - case CEE_LDFLDA: - CHECK_STACK (&td, 1); - token = read32 (td.ip + 1); - field = mono_field_from_token (image, token, &klass, generic_context); - mono_class_init (klass); - mt = mint_type(field->type); - ADD_CODE(&td, MINT_LDFLDA); - ADD_CODE(&td, klass->valuetype ? field->offset - sizeof(MonoObject) : field->offset); - td.ip += 5; - SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_MP); - break; - case CEE_LDFLD: { - CHECK_STACK (&td, 1); - token = read32 (td.ip + 1); - field = mono_field_from_token (image, token, &klass, generic_context); - mono_class_init (klass); - - MonoClass *field_klass = mono_class_from_mono_type (field->type); - mt = mint_type (&field_klass->byval_arg); - if (klass->marshalbyref) { - ADD_CODE(&td, mt == MINT_TYPE_VT ? MINT_LDRMFLD_VT : MINT_LDRMFLD); - ADD_CODE(&td, get_data_item_index (&td, field)); - } else { - ADD_CODE(&td, MINT_LDFLD_I1 + mt - MINT_TYPE_I1); - ADD_CODE(&td, klass->valuetype ? field->offset - sizeof(MonoObject) : field->offset); - } - if (mt == MINT_TYPE_VT) { - int size = mono_class_value_size (field_klass, NULL); - PUSH_VT(&td, size); - WRITE32(&td, &size); - } - if (td.sp [-1].type == STACK_TYPE_VT) { - int size = mono_class_value_size (klass, NULL); - size = (size + 7) & ~7; - td.vt_sp -= size; - ADD_CODE (&td, MINT_VTRESULT); - ADD_CODE (&td, 0); - WRITE32 (&td, &size); - } - td.ip += 5; - SET_TYPE(td.sp - 1, stack_type [mt], field_klass); - break; - } - case CEE_STFLD: - CHECK_STACK (&td, 2); - token = read32 (td.ip + 1); - field = mono_field_from_token (image, token, &klass, generic_context); - mono_class_init (klass); - mt = mint_type(field->type); - if (klass->marshalbyref) { - ADD_CODE(&td, mt == MINT_TYPE_VT ? MINT_STRMFLD_VT : MINT_STRMFLD); - ADD_CODE(&td, get_data_item_index (&td, field)); - } else { - ADD_CODE(&td, MINT_STFLD_I1 + mt - MINT_TYPE_I1); - ADD_CODE(&td, klass->valuetype ? field->offset - sizeof(MonoObject) : field->offset); - } - if (mt == MINT_TYPE_VT) { - MonoClass *klass = mono_class_from_mono_type (field->type); - int size = mono_class_value_size (klass, NULL); - POP_VT(&td, size); - WRITE32(&td, &size); - } - td.ip += 5; - td.sp -= 2; - break; - case CEE_LDSFLDA: - token = read32 (td.ip + 1); - field = mono_field_from_token (image, token, &klass, generic_context); - ADD_CODE(&td, MINT_LDSFLDA); - ADD_CODE(&td, get_data_item_index (&td, field)); - td.ip += 5; - PUSH_SIMPLE_TYPE(&td, STACK_TYPE_MP); - break; - case CEE_LDSFLD: - token = read32 (td.ip + 1); - field = mono_field_from_token (image, token, &klass, generic_context); - mt = mint_type(field->type); - ADD_CODE(&td, mt == MINT_TYPE_VT ? MINT_LDSFLD_VT : MINT_LDSFLD); - ADD_CODE(&td, get_data_item_index (&td, field)); - klass = NULL; - if (mt == MINT_TYPE_VT) { - MonoClass *klass = mono_class_from_mono_type (field->type); - int size = mono_class_value_size (klass, NULL); - PUSH_VT(&td, size); - WRITE32(&td, &size); - klass = field->type->data.klass; - } else { - if (mt == MINT_TYPE_O) - klass = mono_class_from_mono_type (field->type); - } - td.ip += 5; - PUSH_TYPE(&td, stack_type [mt], klass); - break; - case CEE_STSFLD: - CHECK_STACK (&td, 1); - token = read32 (td.ip + 1); - field = mono_field_from_token (image, token, &klass, generic_context); - mt = mint_type(field->type); - ADD_CODE(&td, mt == MINT_TYPE_VT ? MINT_STSFLD_VT : MINT_STSFLD); - ADD_CODE(&td, get_data_item_index (&td, field)); - if (mt == MINT_TYPE_VT) { - MonoClass *klass = mono_class_from_mono_type (field->type); - int size = mono_class_value_size (klass, NULL); - POP_VT (&td, size); - WRITE32 (&td, &size); - } - td.ip += 5; - --td.sp; - break; - case CEE_STOBJ: { - int size; - token = read32 (td.ip + 1); - - if (method->wrapper_type != MONO_WRAPPER_NONE) - klass = (MonoClass *)mono_method_get_wrapper_data (method, token); - else - klass = mono_class_get_full (image, token, generic_context); - - ADD_CODE(&td, td.sp [-1].type == STACK_TYPE_VT ? MINT_STOBJ_VT : MINT_STOBJ); - ADD_CODE(&td, get_data_item_index (&td, klass)); - if (td.sp [-1].type == STACK_TYPE_VT) { - size = mono_class_value_size (klass, NULL); - size = (size + 7) & ~7; - td.vt_sp -= size; - } - td.ip += 5; - td.sp -= 2; - break; - } - case CEE_CONV_OVF_I_UN: - CHECK_STACK (&td, 1); - switch (td.sp [-1].type) { - case STACK_TYPE_R8: -#if SIZEOF_VOID_P == 8 - ADD_CODE(&td, MINT_CONV_OVF_I8_UN_R8); -#else - ADD_CODE(&td, MINT_CONV_OVF_I4_UN_R8); -#endif - break; - case STACK_TYPE_I8: - /*FIX*/ - break; - case STACK_TYPE_I4: -#if SIZEOF_VOID_P == 8 - ADD_CODE(&td, MINT_CONV_I8_U4); -#endif - break; - default: - g_assert_not_reached (); - break; - } - SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I8); - ++td.ip; - break; - case CEE_CONV_OVF_I8_UN: - CHECK_STACK (&td, 1); - switch (td.sp [-1].type) { - case STACK_TYPE_R8: - ADD_CODE(&td, MINT_CONV_OVF_I8_UN_R8); - break; - case STACK_TYPE_I8: - break; - case STACK_TYPE_I4: - ADD_CODE(&td, MINT_CONV_I8_U4); - break; - default: - g_assert_not_reached (); - break; - } - SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I8); - ++td.ip; - break; - case CEE_BOX: { - int size; - CHECK_STACK (&td, 1); - token = read32 (td.ip + 1); - if (method->wrapper_type != MONO_WRAPPER_NONE) - klass = (MonoClass *)mono_method_get_wrapper_data (method, token); - else - klass = mono_class_get_full (image, token, generic_context); - - if (mono_class_is_nullable (klass)) { - MonoMethod *target_method = mono_class_get_method_from_name (klass, "Box", 1); - /* td.ip is incremented by interp_transform_call */ - interp_transform_call (&td, method, target_method, domain, generic_context, is_bb_start, body_start_offset, NULL); - } else if (!klass->valuetype) { - /* already boxed, do nothing. */ - td.ip += 5; - } else { - if (mint_type (&klass->byval_arg) == MINT_TYPE_VT && !klass->enumtype) { - size = mono_class_value_size (klass, NULL); - size = (size + 7) & ~7; - td.vt_sp -= size; - } - ADD_CODE(&td, MINT_BOX); - ADD_CODE(&td, get_data_item_index (&td, klass)); - ADD_CODE (&td, 0); - SET_TYPE(td.sp - 1, STACK_TYPE_O, klass); - td.ip += 5; - } - - break; - } - case CEE_NEWARR: - CHECK_STACK (&td, 1); - token = read32 (td.ip + 1); - - if (method->wrapper_type != MONO_WRAPPER_NONE) - klass = (MonoClass *)mono_method_get_wrapper_data (method, token); - else - klass = mono_class_get_full (image, token, generic_context); - - ADD_CODE(&td, MINT_NEWARR); - ADD_CODE(&td, get_data_item_index (&td, klass)); - SET_TYPE(td.sp - 1, STACK_TYPE_O, klass); - td.ip += 5; - break; - case CEE_LDLEN: - CHECK_STACK (&td, 1); - SIMPLE_OP (td, MINT_LDLEN); - SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I); - break; - case CEE_LDELEMA: - CHECK_STACK (&td, 2); - ENSURE_I4 (&td, 1); - token = read32 (td.ip + 1); - - if (method->wrapper_type != MONO_WRAPPER_NONE) - klass = (MonoClass *)mono_method_get_wrapper_data (method, token); - else - klass = mono_class_get_full (image, token, generic_context); - - ADD_CODE(&td, MINT_LDELEMA); - ADD_CODE(&td, get_data_item_index (&td, klass)); - td.ip += 5; - --td.sp; - SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_MP); - break; - case CEE_LDELEM_I1: - CHECK_STACK (&td, 2); - ENSURE_I4 (&td, 1); - SIMPLE_OP (td, MINT_LDELEM_I1); - --td.sp; - SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I4); - break; - case CEE_LDELEM_U1: - CHECK_STACK (&td, 2); - ENSURE_I4 (&td, 1); - SIMPLE_OP (td, MINT_LDELEM_U1); - --td.sp; - SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I4); - break; - case CEE_LDELEM_I2: - CHECK_STACK (&td, 2); - ENSURE_I4 (&td, 1); - SIMPLE_OP (td, MINT_LDELEM_I2); - --td.sp; - SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I4); - break; - case CEE_LDELEM_U2: - CHECK_STACK (&td, 2); - ENSURE_I4 (&td, 1); - SIMPLE_OP (td, MINT_LDELEM_U2); - --td.sp; - SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I4); - break; - case CEE_LDELEM_I4: - CHECK_STACK (&td, 2); - ENSURE_I4 (&td, 1); - SIMPLE_OP (td, MINT_LDELEM_I4); - --td.sp; - SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I4); - break; - case CEE_LDELEM_U4: - CHECK_STACK (&td, 2); - ENSURE_I4 (&td, 1); - SIMPLE_OP (td, MINT_LDELEM_U4); - --td.sp; - SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I4); - break; - case CEE_LDELEM_I8: - CHECK_STACK (&td, 2); - ENSURE_I4 (&td, 1); - SIMPLE_OP (td, MINT_LDELEM_I8); - --td.sp; - SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I8); - break; - case CEE_LDELEM_I: - CHECK_STACK (&td, 2); - ENSURE_I4 (&td, 1); - SIMPLE_OP (td, MINT_LDELEM_I); - --td.sp; - SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I); - break; - case CEE_LDELEM_R4: - CHECK_STACK (&td, 2); - ENSURE_I4 (&td, 1); - SIMPLE_OP (td, MINT_LDELEM_R4); - --td.sp; - SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_R8); - break; - case CEE_LDELEM_R8: - CHECK_STACK (&td, 2); - ENSURE_I4 (&td, 1); - SIMPLE_OP (td, MINT_LDELEM_R8); - --td.sp; - SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_R8); - break; - case CEE_LDELEM_REF: - CHECK_STACK (&td, 2); - ENSURE_I4 (&td, 1); - SIMPLE_OP (td, MINT_LDELEM_REF); - --td.sp; - SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_O); - break; - case CEE_LDELEM: - CHECK_STACK (&td, 2); - token = read32 (td.ip + 1); - klass = mono_class_get_full (image, token, generic_context); - switch (mint_type (&klass->byval_arg)) { - case MINT_TYPE_I1: - ENSURE_I4 (&td, 1); - SIMPLE_OP (td, MINT_LDELEM_I1); - --td.sp; - SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I4); - break; - case MINT_TYPE_U1: - ENSURE_I4 (&td, 1); - SIMPLE_OP (td, MINT_LDELEM_U1); - --td.sp; - SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I4); - break; - case MINT_TYPE_U2: - ENSURE_I4 (&td, 1); - SIMPLE_OP (td, MINT_LDELEM_U2); - --td.sp; - SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I4); - break; - case MINT_TYPE_I2: - ENSURE_I4 (&td, 1); - SIMPLE_OP (td, MINT_LDELEM_I2); - --td.sp; - SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I4); - break; - case MINT_TYPE_I4: - ENSURE_I4 (&td, 1); - SIMPLE_OP (td, MINT_LDELEM_I4); - --td.sp; - SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I4); - break; - case MINT_TYPE_I8: - ENSURE_I4 (&td, 1); - SIMPLE_OP (td, MINT_LDELEM_I8); - --td.sp; - SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I8); - break; - case MINT_TYPE_R4: - ENSURE_I4 (&td, 1); - SIMPLE_OP (td, MINT_LDELEM_R4); - --td.sp; - SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_R8); - break; - case MINT_TYPE_R8: - ENSURE_I4 (&td, 1); - SIMPLE_OP (td, MINT_LDELEM_R8); - --td.sp; - SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_R8); - break; - case MINT_TYPE_O: - ENSURE_I4 (&td, 1); - SIMPLE_OP (td, MINT_LDELEM_REF); - --td.sp; - SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_O); - break; - case MINT_TYPE_VT: { - int size = mono_class_value_size (klass, NULL); - ENSURE_I4 (&td, 1); - SIMPLE_OP (td, MINT_LDELEM_VT); - ADD_CODE (&td, get_data_item_index (&td, klass)); - WRITE32 (&td, &size); - --td.sp; - SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_VT); - PUSH_VT (&td, size); - break; - } - default: { - GString *res = g_string_new (""); - mono_type_get_desc (res, &klass->byval_arg, TRUE); - g_print ("LDELEM: %s -> %d (%s)\n", klass->name, mint_type (&klass->byval_arg), res->str); - g_string_free (res, TRUE); - g_assert (0); - break; - } - } - td.ip += 4; - break; - case CEE_STELEM_I: - CHECK_STACK (&td, 3); - ENSURE_I4 (&td, 2); - SIMPLE_OP (td, MINT_STELEM_I); - td.sp -= 3; - break; - case CEE_STELEM_I1: - CHECK_STACK (&td, 3); - ENSURE_I4 (&td, 2); - SIMPLE_OP (td, MINT_STELEM_I1); - td.sp -= 3; - break; - case CEE_STELEM_I2: - CHECK_STACK (&td, 3); - ENSURE_I4 (&td, 2); - SIMPLE_OP (td, MINT_STELEM_I2); - td.sp -= 3; - break; - case CEE_STELEM_I4: - CHECK_STACK (&td, 3); - ENSURE_I4 (&td, 2); - SIMPLE_OP (td, MINT_STELEM_I4); - td.sp -= 3; - break; - case CEE_STELEM_I8: - CHECK_STACK (&td, 3); - ENSURE_I4 (&td, 2); - SIMPLE_OP (td, MINT_STELEM_I8); - td.sp -= 3; - break; - case CEE_STELEM_R4: - CHECK_STACK (&td, 3); - ENSURE_I4 (&td, 2); - SIMPLE_OP (td, MINT_STELEM_R4); - td.sp -= 3; - break; - case CEE_STELEM_R8: - CHECK_STACK (&td, 3); - ENSURE_I4 (&td, 2); - SIMPLE_OP (td, MINT_STELEM_R8); - td.sp -= 3; - break; - case CEE_STELEM_REF: - CHECK_STACK (&td, 3); - ENSURE_I4 (&td, 2); - SIMPLE_OP (td, MINT_STELEM_REF); - td.sp -= 3; - break; - case CEE_STELEM: - CHECK_STACK (&td, 3); - ENSURE_I4 (&td, 2); - token = read32 (td.ip + 1); - klass = mono_class_get_full (image, token, generic_context); - switch (mint_type (&klass->byval_arg)) { - case MINT_TYPE_I4: - SIMPLE_OP (td, MINT_STELEM_I4); - break; - case MINT_TYPE_O: - SIMPLE_OP (td, MINT_STELEM_REF); - break; - case MINT_TYPE_VT: { - int size = mono_class_value_size (klass, NULL); - SIMPLE_OP (td, MINT_STELEM_VT); - ADD_CODE (&td, get_data_item_index (&td, klass)); - WRITE32 (&td, &size); - POP_VT (&td, size); - break; - } - default: { - GString *res = g_string_new (""); - mono_type_get_desc (res, &klass->byval_arg, TRUE); - g_print ("STELEM: %s -> %d (%s)\n", klass->name, mint_type (&klass->byval_arg), res->str); - g_string_free (res, TRUE); - g_assert (0); - break; - } - } - td.ip += 4; - td.sp -= 3; - break; -#if 0 - case CEE_CONV_OVF_U1: - - case CEE_CONV_OVF_I8: - -#if SIZEOF_VOID_P == 8 - case CEE_CONV_OVF_U: -#endif - case CEE_REFANYVAL: ves_abort(); break; -#endif - case CEE_CKFINITE: - CHECK_STACK (&td, 1); - SIMPLE_OP (td, MINT_CKFINITE); - break; - case CEE_CONV_OVF_I1: - case CEE_CONV_OVF_I1_UN: - CHECK_STACK (&td, 1); - switch (td.sp [-1].type) { - case STACK_TYPE_R8: - ADD_CODE(&td, MINT_CONV_OVF_I1_R8); - break; - case STACK_TYPE_I4: - ADD_CODE(&td, MINT_CONV_OVF_I1_I4); - break; - case STACK_TYPE_I8: - ADD_CODE(&td, MINT_CONV_OVF_I1_I8); - break; - default: - g_assert_not_reached (); - } - ++td.ip; - SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I4); - break; - case CEE_CONV_OVF_U1: - case CEE_CONV_OVF_U1_UN: - CHECK_STACK (&td, 1); - switch (td.sp [-1].type) { - case STACK_TYPE_R8: - ADD_CODE(&td, MINT_CONV_OVF_U1_R8); - break; - case STACK_TYPE_I4: - ADD_CODE(&td, MINT_CONV_OVF_U1_I4); - break; - case STACK_TYPE_I8: - ADD_CODE(&td, MINT_CONV_OVF_U1_I8); - break; - default: - g_assert_not_reached (); - } - ++td.ip; - SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I4); - break; - case CEE_CONV_OVF_I2: - case CEE_CONV_OVF_I2_UN: - CHECK_STACK (&td, 1); - switch (td.sp [-1].type) { - case STACK_TYPE_R8: - ADD_CODE(&td, MINT_CONV_OVF_I2_R8); - break; - case STACK_TYPE_I4: - ADD_CODE(&td, MINT_CONV_OVF_I2_I4); - break; - case STACK_TYPE_I8: - ADD_CODE(&td, MINT_CONV_OVF_I2_I8); - break; - default: - g_assert_not_reached (); - } - ++td.ip; - SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I4); - break; - case CEE_CONV_OVF_U2_UN: - case CEE_CONV_OVF_U2: - CHECK_STACK (&td, 1); - switch (td.sp [-1].type) { - case STACK_TYPE_R8: - ADD_CODE(&td, MINT_CONV_OVF_U2_R8); - break; - case STACK_TYPE_I4: - ADD_CODE(&td, MINT_CONV_OVF_U2_I4); - break; - case STACK_TYPE_I8: - ADD_CODE(&td, MINT_CONV_OVF_U2_I8); - break; - default: - g_assert_not_reached (); - } - ++td.ip; - SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I4); - break; -#if SIZEOF_VOID_P == 4 - case CEE_CONV_OVF_I: -#endif - case CEE_CONV_OVF_I4: - case CEE_CONV_OVF_I4_UN: - CHECK_STACK (&td, 1); - switch (td.sp [-1].type) { - case STACK_TYPE_R8: - ADD_CODE(&td, MINT_CONV_OVF_I4_R8); - break; - case STACK_TYPE_I4: - if (*td.ip == CEE_CONV_OVF_I4_UN) - ADD_CODE(&td, MINT_CONV_OVF_I4_U4); - break; - case STACK_TYPE_I8: - ADD_CODE(&td, MINT_CONV_OVF_I4_I8); - break; - default: - g_assert_not_reached (); - } - ++td.ip; - SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I4); - break; -#if SIZEOF_VOID_P == 4 - case CEE_CONV_OVF_U: -#endif - case CEE_CONV_OVF_U4: - case CEE_CONV_OVF_U4_UN: - CHECK_STACK (&td, 1); - switch (td.sp [-1].type) { - case STACK_TYPE_R8: - ADD_CODE(&td, MINT_CONV_OVF_U4_R8); - break; - case STACK_TYPE_I4: - if (*td.ip != CEE_CONV_OVF_U4_UN) - ADD_CODE(&td, MINT_CONV_OVF_U4_I4); - break; - case STACK_TYPE_I8: - ADD_CODE(&td, MINT_CONV_OVF_U4_I8); - break; - default: - g_assert_not_reached (); - } - ++td.ip; - SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I4); - break; -#if SIZEOF_VOID_P == 8 - case CEE_CONV_OVF_I: -#endif - case CEE_CONV_OVF_I8: - CHECK_STACK (&td, 1); - switch (td.sp [-1].type) { - case STACK_TYPE_R8: - ADD_CODE(&td, MINT_CONV_OVF_I8_R8); - break; - case STACK_TYPE_I4: - ADD_CODE(&td, MINT_CONV_I8_I4); - break; - case STACK_TYPE_I8: - break; - default: - g_assert_not_reached (); - } - ++td.ip; - SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I8); - break; -#if SIZEOF_VOID_P == 8 - case CEE_CONV_OVF_U: -#endif - case CEE_CONV_OVF_U8: - CHECK_STACK (&td, 1); - switch (td.sp [-1].type) { - case STACK_TYPE_R8: - ADD_CODE(&td, MINT_CONV_OVF_U8_R8); - break; - case STACK_TYPE_I4: - ADD_CODE(&td, MINT_CONV_OVF_U8_I4); - break; - case STACK_TYPE_I8: - break; - default: - g_assert_not_reached (); - } - ++td.ip; - SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I8); - break; - case CEE_LDTOKEN: { - int size; - gpointer handle; - token = read32 (td.ip + 1); - if (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD || method->wrapper_type == MONO_WRAPPER_SYNCHRONIZED) { - handle = mono_method_get_wrapper_data (method, token); - klass = (MonoClass *) mono_method_get_wrapper_data (method, token + 1); - if (klass == mono_defaults.typehandle_class) - handle = &((MonoClass *) handle)->byval_arg; - } else { - handle = mono_ldtoken (image, token, &klass, generic_context); - } - mt = mint_type(&klass->byval_arg); - g_assert (mt == MINT_TYPE_VT); - size = mono_class_value_size (klass, NULL); - g_assert (size == sizeof(gpointer)); - PUSH_VT(&td, sizeof(gpointer)); - ADD_CODE(&td, MINT_LDTOKEN); - ADD_CODE(&td, get_data_item_index (&td, handle)); - PUSH_SIMPLE_TYPE(&td, stack_type [mt]); - td.ip += 5; - break; - } - case CEE_ADD_OVF: - binary_arith_op(&td, MINT_ADD_OVF_I4); - ++td.ip; - break; - case CEE_ADD_OVF_UN: - binary_arith_op(&td, MINT_ADD_OVF_UN_I4); - ++td.ip; - break; - case CEE_MUL_OVF: - binary_arith_op(&td, MINT_MUL_OVF_I4); - ++td.ip; - break; - case CEE_MUL_OVF_UN: - binary_arith_op(&td, MINT_MUL_OVF_UN_I4); - ++td.ip; - break; - case CEE_SUB_OVF: - binary_arith_op(&td, MINT_SUB_OVF_I4); - ++td.ip; - break; - case CEE_SUB_OVF_UN: - binary_arith_op(&td, MINT_SUB_OVF_UN_I4); - ++td.ip; - break; - case CEE_ENDFINALLY: - SIMPLE_OP (td, MINT_ENDFINALLY); - generating_code = 0; - break; - case CEE_LEAVE: - td.sp = td.stack; - handle_branch (&td, MINT_LEAVE_S, MINT_LEAVE, 5 + read32 (td.ip + 1)); - td.ip += 5; - generating_code = 0; - break; - case CEE_LEAVE_S: - td.sp = td.stack; - handle_branch (&td, MINT_LEAVE_S, MINT_LEAVE, 2 + (gint8)td.ip [1]); - td.ip += 2; - generating_code = 0; - break; - case CEE_UNUSED41: - ++td.ip; - switch (*td.ip) { - case CEE_MONO_CALLI_EXTRA_ARG: - /* Same as CEE_CALLI, except that we drop the extra arg required for llvm specific behaviour */ - ADD_CODE (&td, MINT_POP); - ADD_CODE (&td, 1); - --td.sp; - interp_transform_call (&td, method, NULL, domain, generic_context, is_bb_start, body_start_offset, NULL); - break; - case CEE_MONO_JIT_ICALL_ADDR: { - guint32 token; - gpointer func; - MonoJitICallInfo *info; - - token = read32 (td.ip + 1); - td.ip += 5; - func = mono_method_get_wrapper_data (method, token); - info = mono_find_jit_icall_by_addr (func); - - ADD_CODE (&td, MINT_LDFTN); - ADD_CODE (&td, get_data_item_index (&td, func)); - PUSH_SIMPLE_TYPE (&td, STACK_TYPE_I); - break; - } - case CEE_MONO_ICALL: { - guint32 token; - gpointer func; - MonoJitICallInfo *info; - - token = read32 (td.ip + 1); - td.ip += 5; - func = mono_method_get_wrapper_data (method, token); - info = mono_find_jit_icall_by_addr (func); - g_assert (info); - - CHECK_STACK (&td, info->sig->param_count); - switch (info->sig->param_count) { - case 0: - if (MONO_TYPE_IS_VOID (info->sig->ret)) - ADD_CODE (&td,MINT_ICALL_V_V); - else - ADD_CODE (&td, MINT_ICALL_V_P); - break; - case 1: - if (MONO_TYPE_IS_VOID (info->sig->ret)) - ADD_CODE (&td,MINT_ICALL_P_V); - else - ADD_CODE (&td,MINT_ICALL_P_P); - break; - case 2: - if (MONO_TYPE_IS_VOID (info->sig->ret)) { - if (info->sig->params [1]->type == MONO_TYPE_I4) - ADD_CODE (&td,MINT_ICALL_PI_V); - else - ADD_CODE (&td,MINT_ICALL_PP_V); - } else { - if (info->sig->params [1]->type == MONO_TYPE_I4) - ADD_CODE (&td,MINT_ICALL_PI_P); - else - ADD_CODE (&td,MINT_ICALL_PP_P); - } - break; - case 3: - g_assert (MONO_TYPE_IS_VOID (info->sig->ret)); - if (info->sig->params [2]->type == MONO_TYPE_I4) - ADD_CODE (&td,MINT_ICALL_PPI_V); - else - ADD_CODE (&td,MINT_ICALL_PPP_V); - break; - default: - g_assert_not_reached (); - } - - if (func == mono_ftnptr_to_delegate) { - g_error ("TODO: ?"); - } - ADD_CODE(&td, get_data_item_index (&td, func)); - td.sp -= info->sig->param_count; - - if (!MONO_TYPE_IS_VOID (info->sig->ret)) { - td.sp ++; - SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I); - } - break; - } - case CEE_MONO_VTADDR: { - int size; - CHECK_STACK (&td, 1); - if (method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) - size = mono_class_native_size(td.sp [-1].klass, NULL); - else - size = mono_class_value_size(td.sp [-1].klass, NULL); - size = (size + 7) & ~7; - ADD_CODE(&td, MINT_VTRESULT); - ADD_CODE(&td, 0); - WRITE32(&td, &size); - td.vt_sp -= size; - ++td.ip; - SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_MP); - break; - } - case CEE_MONO_LDPTR: - case CEE_MONO_CLASSCONST: - token = read32 (td.ip + 1); - td.ip += 5; - ADD_CODE(&td, MINT_MONO_LDPTR); - ADD_CODE(&td, get_data_item_index (&td, mono_method_get_wrapper_data (method, token))); - td.sp [0].type = STACK_TYPE_I; - ++td.sp; - break; - case CEE_MONO_OBJADDR: - CHECK_STACK (&td, 1); - ++td.ip; - td.sp[-1].type = STACK_TYPE_MP; - /* do nothing? */ - break; - case CEE_MONO_NEWOBJ: - token = read32 (td.ip + 1); - td.ip += 5; - ADD_CODE(&td, MINT_MONO_NEWOBJ); - ADD_CODE(&td, get_data_item_index (&td, mono_method_get_wrapper_data (method, token))); - td.sp [0].type = STACK_TYPE_O; - ++td.sp; - break; - case CEE_MONO_RETOBJ: - CHECK_STACK (&td, 1); - token = read32 (td.ip + 1); - td.ip += 5; - ADD_CODE(&td, MINT_MONO_RETOBJ); - td.sp--; - - klass = (MonoClass *)mono_method_get_wrapper_data (method, token); - - /*stackval_from_data (signature->ret, frame->retval, sp->data.vt, signature->pinvoke);*/ - - if (td.sp > td.stack) - g_warning ("CEE_MONO_RETOBJ: more values on stack: %d", td.sp-td.stack); - break; - case CEE_MONO_LDNATIVEOBJ: - token = read32 (td.ip + 1); - td.ip += 5; - klass = (MonoClass *)mono_method_get_wrapper_data (method, token); - g_assert(klass->valuetype); - SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_MP); - break; - case CEE_MONO_SAVE_LMF: - case CEE_MONO_RESTORE_LMF: - case CEE_MONO_NOT_TAKEN: - ++td.ip; - break; - case CEE_MONO_LDPTR_INT_REQ_FLAG: - ADD_CODE (&td, MINT_MONO_LDPTR); - ADD_CODE (&td, get_data_item_index (&td, mono_thread_interruption_request_flag ())); - PUSH_TYPE (&td, STACK_TYPE_MP, NULL); - ++td.ip; - break; - default: - g_error ("transform.c: Unimplemented opcode: 0xF0 %02x at 0x%x\n", *td.ip, td.ip-header->code); - } - break; -#if 0 - case CEE_PREFIX7: - case CEE_PREFIX6: - case CEE_PREFIX5: - case CEE_PREFIX4: - case CEE_PREFIX3: - case CEE_PREFIX2: - case CEE_PREFIXREF: ves_abort(); break; -#endif - /* - * Note: Exceptions thrown when executing a prefixed opcode need - * to take into account the number of prefix bytes (usually the - * throw point is just (ip - n_prefix_bytes). - */ - case CEE_PREFIX1: - ++td.ip; - switch (*td.ip) { -#if 0 - case CEE_ARGLIST: ves_abort(); break; -#endif - case CEE_CEQ: - CHECK_STACK(&td, 2); - if (td.sp [-1].type == STACK_TYPE_O || td.sp [-1].type == STACK_TYPE_MP) - ADD_CODE(&td, MINT_CEQ_I4 + STACK_TYPE_I - STACK_TYPE_I4); - else - ADD_CODE(&td, MINT_CEQ_I4 + td.sp [-1].type - STACK_TYPE_I4); - --td.sp; - SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I4); - ++td.ip; - break; - case CEE_CGT: - CHECK_STACK(&td, 2); - if (td.sp [-1].type == STACK_TYPE_O || td.sp [-1].type == STACK_TYPE_MP) - ADD_CODE(&td, MINT_CGT_I4 + STACK_TYPE_I - STACK_TYPE_I4); - else - ADD_CODE(&td, MINT_CGT_I4 + td.sp [-1].type - STACK_TYPE_I4); - --td.sp; - SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I4); - ++td.ip; - break; - case CEE_CGT_UN: - CHECK_STACK(&td, 2); - if (td.sp [-1].type == STACK_TYPE_O || td.sp [-1].type == STACK_TYPE_MP) - ADD_CODE(&td, MINT_CGT_UN_I4 + STACK_TYPE_I - STACK_TYPE_I4); - else - ADD_CODE(&td, MINT_CGT_UN_I4 + td.sp [-1].type - STACK_TYPE_I4); - --td.sp; - SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I4); - ++td.ip; - break; - case CEE_CLT: - CHECK_STACK(&td, 2); - if (td.sp [-1].type == STACK_TYPE_O || td.sp [-1].type == STACK_TYPE_MP) - ADD_CODE(&td, MINT_CLT_I4 + STACK_TYPE_I - STACK_TYPE_I4); - else - ADD_CODE(&td, MINT_CLT_I4 + td.sp [-1].type - STACK_TYPE_I4); - --td.sp; - SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I4); - ++td.ip; - break; - case CEE_CLT_UN: - CHECK_STACK(&td, 2); - if (td.sp [-1].type == STACK_TYPE_O || td.sp [-1].type == STACK_TYPE_MP) - ADD_CODE(&td, MINT_CLT_UN_I4 + STACK_TYPE_I - STACK_TYPE_I4); - else - ADD_CODE(&td, MINT_CLT_UN_I4 + td.sp [-1].type - STACK_TYPE_I4); - --td.sp; - SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_I4); - ++td.ip; - break; - case CEE_LDVIRTFTN: /* fallthrough */ - case CEE_LDFTN: { - MonoMethod *m; - if (*td.ip == CEE_LDVIRTFTN) { - CHECK_STACK (&td, 1); - --td.sp; - } - token = read32 (td.ip + 1); - if (method->wrapper_type != MONO_WRAPPER_NONE) - m = (MonoMethod *)mono_method_get_wrapper_data (method, token); - else - m = mono_get_method_full (image, token, NULL, generic_context); - - if (method->wrapper_type == MONO_WRAPPER_NONE && m->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED) - m = mono_marshal_get_synchronized_wrapper (m); - - ADD_CODE(&td, *td.ip == CEE_LDFTN ? MINT_LDFTN : MINT_LDVIRTFTN); - ADD_CODE(&td, get_data_item_index (&td, mono_interp_get_runtime_method (domain, m, &error))); - mono_error_cleanup (&error); /* FIXME: don't swallow the error */ - td.ip += 5; - PUSH_SIMPLE_TYPE (&td, STACK_TYPE_F); - break; - } - case CEE_LDARG: - load_arg (&td, read16 (td.ip + 1)); - td.ip += 3; - break; - case CEE_LDARGA: { - int n = read16 (td.ip + 1); - if (n == 0 && signature->hasthis) { - g_error ("LDTHISA: NOPE"); - ADD_CODE(&td, MINT_LDTHISA); - } - else { - ADD_CODE(&td, MINT_LDARGA); - ADD_CODE(&td, td.rtm->arg_offsets [n]); /* FIX for large offsets */ - } - PUSH_SIMPLE_TYPE(&td, STACK_TYPE_MP); - td.ip += 3; - break; - } - case CEE_STARG: - store_arg (&td, read16 (td.ip + 1)); - td.ip += 3; - break; - case CEE_LDLOC: - load_local (&td, read16 (td.ip + 1)); - td.ip += 3; - break; - case CEE_LDLOCA: - ADD_CODE(&td, MINT_LDLOCA_S); - ADD_CODE(&td, td.rtm->local_offsets [read16 (td.ip + 1)]); - PUSH_SIMPLE_TYPE(&td, STACK_TYPE_MP); - td.ip += 3; - break; - case CEE_STLOC: - store_local (&td, read16 (td.ip + 1)); - td.ip += 3; - break; - case CEE_LOCALLOC: - CHECK_STACK (&td, 1); -#if SIZEOF_VOID_P == 8 - if (td.sp [-1].type == STACK_TYPE_I8) - ADD_CODE(&td, MINT_CONV_I4_I8); -#endif - ADD_CODE(&td, MINT_LOCALLOC); - if (td.sp != td.stack + 1) - g_warning("CEE_LOCALLOC: stack not empty"); - ++td.ip; - SET_SIMPLE_TYPE(td.sp - 1, STACK_TYPE_MP); - break; -#if 0 - case CEE_UNUSED57: ves_abort(); break; - case CEE_ENDFILTER: ves_abort(); break; -#endif - case CEE_UNALIGNED_: - ++td.ip; - /* FIX: should do something? */; - break; - case CEE_VOLATILE_: - ++td.ip; - /* FIX: should do something? */; - break; - case CEE_TAIL_: - ++td.ip; - /* FIX: should do something? */; - break; - case CEE_INITOBJ: - CHECK_STACK(&td, 1); - token = read32 (td.ip + 1); - klass = mono_class_get_full (image, token, generic_context); - ADD_CODE(&td, MINT_INITOBJ); - i32 = mono_class_value_size (klass, NULL); - WRITE32(&td, &i32); - td.ip += 5; - --td.sp; - break; - case CEE_CPBLK: - CHECK_STACK(&td, 3); - /* FIX? convert length to I8? */ - ADD_CODE(&td, MINT_CPBLK); - td.sp -= 3; - ++td.ip; - break; - case CEE_CONSTRAINED_: - token = read32 (td.ip + 1); - constrained_class = mono_class_get_full (image, token, generic_context); - mono_class_init (constrained_class); - td.ip += 5; - break; - case CEE_INITBLK: - CHECK_STACK(&td, 3); - ADD_CODE(&td, MINT_INITBLK); - td.sp -= 3; - break; -#if 0 - case CEE_NO_: - /* FIXME: implement */ - ip += 2; - break; -#endif - case CEE_RETHROW: - SIMPLE_OP (td, MINT_RETHROW); - generating_code = 0; - break; - case CEE_SIZEOF: { - gint32 size; - token = read32 (td.ip + 1); - td.ip += 5; - if (mono_metadata_token_table (token) == MONO_TABLE_TYPESPEC) { - int align; - MonoType *type = mono_type_create_from_typespec (image, token); - size = mono_type_size (type, &align); - } else { - guint32 align; - MonoClass *szclass = mono_class_get_full (image, token, generic_context); - mono_class_init (szclass); -#if 0 - if (!szclass->valuetype) - THROW_EX (mono_exception_from_name (mono_defaults.corlib, "System", "InvalidProgramException"), ip - 5); -#endif - size = mono_class_value_size (szclass, &align); - } - ADD_CODE(&td, MINT_LDC_I4); - WRITE32(&td, &size); - PUSH_SIMPLE_TYPE(&td, STACK_TYPE_I4); - break; - } -#if 0 - case CEE_REFANYTYPE: ves_abort(); break; -#endif - default: - g_error ("transform.c: Unimplemented opcode: 0xFE %02x (%s) at 0x%x\n", *td.ip, mono_opcode_name (256 + *td.ip), td.ip-header->code); - } - break; - default: - g_error ("transform.c: Unimplemented opcode: %02x at 0x%x\n", *td.ip, td.ip-header->code); - } - - if (td.new_ip - td.new_code != new_in_start_offset) - td.last_new_ip = td.new_code + new_in_start_offset; - else if (td.is_bb_start [td.in_start - td.il_code]) - td.is_bb_start [td.ip - td.il_code] = 1; - - td.last_ip = td.in_start; - } - - if (mono_interp_traceopt) { - const guint16 *p = td.new_code; - printf("Runtime method: %p, VT stack size: %d\n", rtm, td.max_vt_sp); - printf("Calculated stack size: %d, stated size: %d\n", td.max_stack_height, header->max_stack); - while (p < td.new_ip) { - p = mono_interp_dis_mintop(td.new_code, p); - printf("\n"); - } - } - - rtm->clauses = mono_mempool_alloc (domain->mp, header->num_clauses * sizeof(MonoExceptionClause)); - memcpy (rtm->clauses, header->clauses, header->num_clauses * sizeof(MonoExceptionClause)); - rtm->code = mono_mempool_alloc (domain->mp, (td.new_ip - td.new_code) * sizeof(gushort)); - memcpy (rtm->code, td.new_code, (td.new_ip - td.new_code) * sizeof(gushort)); - g_free (td.new_code); - rtm->new_body_start = rtm->code + body_start_offset; - rtm->num_clauses = header->num_clauses; - for (i = 0; i < header->num_clauses; i++) { - MonoExceptionClause *c = rtm->clauses + i; - int end_off = c->try_offset + c->try_len; - c->try_offset = td.in_offsets [c->try_offset]; - c->try_len = td.in_offsets [end_off] - c->try_offset; - end_off = c->handler_offset + c->handler_len; - c->handler_offset = td.in_offsets [c->handler_offset]; - c->handler_len = td.in_offsets [end_off] - c->handler_offset; - } - rtm->vt_stack_size = td.max_vt_sp; - rtm->alloca_size = rtm->locals_size + rtm->args_size + rtm->vt_stack_size + rtm->stack_size; - rtm->data_items = mono_mempool_alloc (domain->mp, td.n_data_items * sizeof (td.data_items [0])); - memcpy (rtm->data_items, td.data_items, td.n_data_items * sizeof (td.data_items [0])); - g_free (td.in_offsets); - g_free (td.forward_refs); - for (i = 0; i < header->code_size; ++i) - g_free (td.stack_state [i]); - g_free (td.stack_state); - g_free (td.stack_height); - g_free (td.vt_stack_size); - g_free (td.data_items); - g_hash_table_destroy (td.data_hash); -} - -static mono_mutex_t calc_section; - -void -mono_interp_transform_init (void) -{ - mono_os_mutex_init_recursive(&calc_section); -} - -MonoException * -mono_interp_transform_method (RuntimeMethod *runtime_method, ThreadContext *context) -{ - int i, align, size, offset; - MonoMethod *method = runtime_method->method; - MonoImage *image = method->klass->image; - MonoMethodHeader *header = mono_method_get_header (method); - MonoMethodSignature *signature = mono_method_signature (method); - register const unsigned char *ip, *end; - const MonoOpcode *opcode; - MonoMethod *m; - MonoClass *class; - MonoDomain *domain = mono_domain_get (); - unsigned char *is_bb_start; - int in; - MonoVTable *method_class_vt; - int backwards; - MonoGenericContext *generic_context = NULL; - - // g_printerr ("TRANSFORM(0x%016lx): begin %s::%s\n", mono_thread_current (), method->klass->name, method->name); - method_class_vt = mono_class_vtable (domain, runtime_method->method->klass); - if (!method_class_vt->initialized) { - jmp_buf env; - MonoInvocation *last_env_frame = context->env_frame; - jmp_buf *old_env = context->current_env; - - if (setjmp(env)) { - MonoException *failed = context->env_frame->ex; - context->env_frame->ex = NULL; - context->env_frame = last_env_frame; - context->current_env = old_env; - return failed; - } - context->env_frame = context->current_frame; - context->current_env = &env; - mono_runtime_class_init (method_class_vt); - context->env_frame = last_env_frame; - context->current_env = old_env; - } - - mono_profiler_method_jit (method); /* sort of... */ - - if (mono_method_signature (method)->is_inflated) - generic_context = mono_method_get_context (method); - else { - MonoGenericContainer *generic_container = mono_method_get_generic_container (method); - if (generic_container) - generic_context = &generic_container->context; - } - - if (method->iflags & (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL | METHOD_IMPL_ATTRIBUTE_RUNTIME)) { - MonoMethod *nm = NULL; - mono_os_mutex_lock(&calc_section); - if (runtime_method->transformed) { - mono_os_mutex_unlock(&calc_section); - g_error ("FIXME: no jit info?"); - mono_profiler_method_end_jit (method, NULL, MONO_PROFILE_OK); - return NULL; - } - - /* assumes all internal calls with an array this are built in... */ - if (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL && (! mono_method_signature (method)->hasthis || method->klass->rank == 0)) { - nm = mono_marshal_get_native_wrapper (method, TRUE, FALSE); - signature = mono_method_signature (nm); - } else { - const char *name = method->name; - if (method->klass->parent == mono_defaults.multicastdelegate_class) { - if (*name == '.' && (strcmp (name, ".ctor") == 0)) { - MonoJitICallInfo *mi = mono_find_jit_icall_by_name ("ves_icall_mono_delegate_ctor"); - g_assert (mi); - char *wrapper_name = g_strdup_printf ("__icall_wrapper_%s", mi->name); - nm = mono_marshal_get_icall_wrapper (mi->sig, wrapper_name, mi->func, TRUE); - } else if (*name == 'I' && (strcmp (name, "Invoke") == 0)) { - nm = mono_marshal_get_delegate_invoke (method, NULL); - } else if (*name == 'B' && (strcmp (name, "BeginInvoke") == 0)) { - nm = mono_marshal_get_delegate_begin_invoke (method); - } else if (*name == 'E' && (strcmp (name, "EndInvoke") == 0)) { - nm = mono_marshal_get_delegate_end_invoke (method); - } - } - if (nm == NULL) { - runtime_method->code = g_malloc(sizeof(short)); - runtime_method->code[0] = MINT_CALLRUN; - } - } - if (nm == NULL) { - runtime_method->stack_size = sizeof (stackval); /* for tracing */ - runtime_method->alloca_size = runtime_method->stack_size; - runtime_method->transformed = TRUE; - mono_os_mutex_unlock(&calc_section); - mono_profiler_method_end_jit (method, NULL, MONO_PROFILE_OK); - return NULL; - } - method = nm; - header = mono_method_get_header (nm); - mono_os_mutex_unlock(&calc_section); - } - g_assert ((signature->param_count + signature->hasthis) < 1000); - g_assert (header->max_stack < 10000); - /* intern the strings in the method. */ - ip = header->code; - end = ip + header->code_size; - - is_bb_start = g_malloc0(header->code_size); - is_bb_start [0] = 1; - while (ip < end) { - in = *ip; - if (in == 0xfe) { - ip++; - in = *ip + 256; - } - else if (in == 0xf0) { - ip++; - in = *ip + MONO_CEE_MONO_ICALL; - } - opcode = &mono_opcodes [in]; - switch (opcode->argument) { - case MonoInlineNone: - ++ip; - break; - case MonoInlineString: - if (method->wrapper_type == MONO_WRAPPER_NONE) - mono_ldstr (domain, image, mono_metadata_token_index (read32 (ip + 1))); - ip += 5; - break; - case MonoInlineType: - if (method->wrapper_type == MONO_WRAPPER_NONE) { - class = mono_class_get_full (image, read32 (ip + 1), generic_context); - mono_class_init (class); - /* quick fix to not do this for the fake ptr classes - probably should not be getting the vtable at all here */ -#if 0 - g_error ("FIXME: interface method lookup: %s (in method %s)", class->name, method->name); - if (!(class->flags & TYPE_ATTRIBUTE_INTERFACE) && class->interface_offsets != NULL) - mono_class_vtable (domain, class); -#endif - } - ip += 5; - break; - case MonoInlineMethod: - if (method->wrapper_type == MONO_WRAPPER_NONE && *ip != CEE_CALLI) { - m = mono_get_method_full (image, read32 (ip + 1), NULL, generic_context); - if (m == NULL) { - g_free (is_bb_start); - g_error ("FIXME: where to get method and class string?"); - return NULL; - // return mono_get_exception_missing_method (); - } - mono_class_init (m->klass); - if (!mono_class_is_interface (m->klass)) - mono_class_vtable (domain, m->klass); - } - ip += 5; - break; - case MonoInlineField: - case MonoInlineSig: - case MonoInlineI: - case MonoInlineTok: - case MonoShortInlineR: - ip += 5; - break; - case MonoInlineBrTarget: - offset = read32 (ip + 1); - ip += 5; - backwards = offset < 0; - offset += ip - header->code; - g_assert (offset >= 0 && offset < header->code_size); - is_bb_start [offset] |= backwards ? 2 : 1; - break; - case MonoShortInlineBrTarget: - offset = ((gint8 *)ip) [1]; - ip += 2; - backwards = offset < 0; - offset += ip - header->code; - g_assert (offset >= 0 && offset < header->code_size); - is_bb_start [offset] |= backwards ? 2 : 1; - break; - case MonoInlineVar: - ip += 3; - break; - case MonoShortInlineVar: - case MonoShortInlineI: - ip += 2; - break; - case MonoInlineSwitch: { - guint32 n; - const unsigned char *next_ip; - ++ip; - n = read32 (ip); - ip += 4; - next_ip = ip + 4 * n; - for (i = 0; i < n; i++) { - offset = read32 (ip); - backwards = offset < 0; - offset += next_ip - header->code; - g_assert (offset >= 0 && offset < header->code_size); - is_bb_start [offset] |= backwards ? 2 : 1; - ip += 4; - } - break; - } - case MonoInlineR: - case MonoInlineI8: - ip += 9; - break; - default: - g_assert_not_reached (); - } - } - // g_printerr ("TRANSFORM(0x%016lx): end %s::%s\n", mono_thread_current (), method->klass->name, method->name); - - /* the rest needs to be locked so it is only done once */ - mono_os_mutex_lock(&calc_section); - if (runtime_method->transformed) { - mono_os_mutex_unlock(&calc_section); - g_free (is_bb_start); - mono_profiler_method_end_jit (method, NULL, MONO_PROFILE_OK); - return NULL; - } - - runtime_method->local_offsets = g_malloc (header->num_locals * sizeof(guint32)); - runtime_method->stack_size = (sizeof (stackval) + 2) * header->max_stack; /* + 1 for returns of called functions + 1 for 0-ing in trace*/ - runtime_method->stack_size = (runtime_method->stack_size + 7) & ~7; - offset = 0; - for (i = 0; i < header->num_locals; ++i) { - size = mono_type_size (header->locals [i], &align); - offset += align - 1; - offset &= ~(align - 1); - runtime_method->local_offsets [i] = offset; - offset += size; - } - offset = (offset + 7) & ~7; - runtime_method->locals_size = offset; - g_assert (runtime_method->locals_size < 65536); - offset = 0; - runtime_method->arg_offsets = g_malloc ((!!signature->hasthis + signature->param_count) * sizeof(guint32)); - - if (signature->hasthis) { - g_assert (!signature->pinvoke); - size = mono_type_stack_size (&method->klass->byval_arg, &align); - offset += align - 1; - offset &= ~(align - 1); - runtime_method->arg_offsets [0] = offset; - offset += size; - } - - for (i = 0; i < signature->param_count; ++i) { - if (signature->pinvoke) { - guint32 dummy; - size = mono_type_native_stack_size (signature->params [i], &dummy); - align = 8; - } - else - size = mono_type_stack_size (signature->params [i], &align); - offset += align - 1; - offset &= ~(align - 1); - runtime_method->arg_offsets [i + !!signature->hasthis] = offset; - offset += size; - } - offset = (offset + 7) & ~7; - runtime_method->args_size = offset; - g_assert (runtime_method->args_size < 10000); - - generate (method, runtime_method, is_bb_start, generic_context); - - g_free (is_bb_start); - - mono_profiler_method_end_jit (method, NULL, MONO_PROFILE_OK); - runtime_method->transformed = TRUE; - mono_os_mutex_unlock(&calc_section); - - return NULL; -} - diff --git a/mono/mini/mini-exceptions.c b/mono/mini/mini-exceptions.c index de5745a88db..272065388e6 100644 --- a/mono/mini/mini-exceptions.c +++ b/mono/mini/mini-exceptions.c @@ -73,7 +73,7 @@ #include "seq-points.h" #include "llvm-runtime.h" #include "mini-llvm.h" -#include "interpreter/interp.h" +#include "interp/interp.h" #ifdef ENABLE_LLVM #include "mini-llvm-cpp.h" diff --git a/mono/mini/mini-runtime.c b/mono/mini/mini-runtime.c index 2db0d997bee..9336b94f2d2 100644 --- a/mono/mini/mini-runtime.c +++ b/mono/mini/mini-runtime.c @@ -91,7 +91,7 @@ #endif #ifdef ENABLE_INTERPRETER -#include "interpreter/interp.h" +#include "interp/interp.h" #endif static guint32 default_opt = 0; -- cgit v1.2.3