Add beginnings of mixed code execution support (#4613)
authorZoltan Varga <vargaz@gmail.com>
Thu, 30 Mar 2017 11:32:44 +0000 (07:32 -0400)
committerGitHub <noreply@github.com>
Thu, 30 Mar 2017 11:32:44 +0000 (07:32 -0400)
* [interp] Fix a few problems exposed by the iltests.exe test suite.

The ENDFINALLY opcode should empty the stack. The INITBLK opcode is two bytes.

* [interp] Store the MonoMethod->RuntimeMethod mapping in a separate hash in MonoJitDomainInfo instead of using MonoDomain.jit_code_hash, the latter contains MonoMethod->MonoJitInfo mappings. Also avoid holding the domain lock while creating the RuntimeMethod structure.

* [interp] Add a mono_jit_compile_method_jit_only () function which always compiles its argument using the JIT/AOT.

* [interp] Print a warning when --interpreter is used with a runtime compiled without ENABLE_INTERPRETER.

* [interp] Fix the size of the icall enter trampoline on amd64. Fix some formatting issues.

* [interp] Add support for calling JITted code from the interpreter. This uses the gsharedvt_out wrappers used by bitcode to reduce the number of possible calling conventions since all arguments and the return value are passed/returned by value. Not enabled yet.

* [interp] Add a --interp= argument which allows passing of options to the interpreter. Add a 'jit=' option which is used to control the set of types whose methods will be called by exiting the interpreter.

* [interp] Add tests for mixed mode execution.

* [interp] Add support for calling interpreter code from JITted code.

* [interp] add mixedmode target to CI

* Revert a debug change.

* [runtime] Fix the locking in the gsharedvt/interp wrapper creation functions.

* [interp] Implement support for interp->jit calls with more than 8 arguments.

17 files changed:
mono/cil/cil-opcodes.xml
mono/cil/opcode.def
mono/metadata/marshal.h
mono/mini/Makefile.am.in
mono/mini/driver.c
mono/mini/interp/interp-internals.h
mono/mini/interp/interp.c
mono/mini/interp/interp.h
mono/mini/interp/mintops.def
mono/mini/interp/transform.c
mono/mini/method-to-ir.c
mono/mini/mini-generic-sharing.c
mono/mini/mini-runtime.c
mono/mini/mini.h
mono/mini/mixed.cs [new file with mode: 0644]
mono/mini/tramp-amd64.c
scripts/ci/run-test-interpreter.sh

index c8ef14eaeed3dd86d814920839c14dc6ddd56398..cafb55618910fee90f6ffbdb45ae51ad053cea12 100644 (file)
 <opcode name="mono_lddomain" input="Pop0" output="PushI" args="InlineNone" o1="0xF0" o2="0x19" flow="next" />
 <opcode name="mono_atomic_store_i4" input="PopI+PopI" output="Push0" args="InlineI" o1="0xF0" o2="0x1A" flow="next" />
 <opcode name="mono_get_last_error" input="Pop0" output="PushI" args="InlineNone" o1="0xF0" o2="0x1B" flow="next" />
+<opcode name="mono_get_rgctx_arg" input="Pop0" output="PushI" args="InlineNone" o1="0xF0" o2="0x1C" flow="next" />
 </opdesc>
index fca2448151a9771b1a91e6fed9d4b130147559b1..91e8924febc18e66763e669964aea5d8352ab2c5 100644 (file)
@@ -320,6 +320,7 @@ OPDEF(CEE_MONO_CALLI_EXTRA_ARG, "mono_calli_extra_arg", VarPop, VarPush, InlineS
 OPDEF(CEE_MONO_LDDOMAIN, "mono_lddomain", Pop0, PushI, InlineNone, X, 2, 0xF0, 0x19, NEXT)
 OPDEF(CEE_MONO_ATOMIC_STORE_I4, "mono_atomic_store_i4", PopI+PopI, Push0, InlineI, X, 2, 0xF0, 0x1A, NEXT)
 OPDEF(CEE_MONO_GET_LAST_ERROR, "mono_get_last_error", Pop0, PushI, InlineNone, X, 2, 0xF0, 0x1B, NEXT)
+OPDEF(CEE_MONO_GET_RGCTX_ARG, "mono_get_rgctx_arg", Pop0, PushI, InlineNone, X, 2, 0xF0, 0x1C, NEXT)
 #ifndef OPALIAS
 #define _MONO_CIL_OPALIAS_DEFINED_
 #define OPALIAS(a,s,r)
index 3f898dba5a0709d6996a54f9c86c0b370659c111..9d24832dbeeae6bda4abd2e6be459e647006c5a6 100644 (file)
@@ -121,6 +121,7 @@ typedef enum {
        /* Subtypes of MONO_WRAPPER_UNKNOWN */
        WRAPPER_SUBTYPE_GSHAREDVT_IN_SIG,
        WRAPPER_SUBTYPE_GSHAREDVT_OUT_SIG,
+       WRAPPER_SUBTYPE_INTERP_IN
 } WrapperSubtype;
 
 typedef struct {
@@ -195,6 +196,10 @@ typedef struct {
        MonoMethod *method;
 } DelegateInvokeWrapperInfo;
 
+typedef struct {
+       MonoMethodSignature *sig;
+} InterpInWrapperInfo;
+
 /*
  * This structure contains additional information to uniquely identify a given wrapper
  * method. It can be retrieved by mono_marshal_get_wrapper_info () for certain types
@@ -237,6 +242,8 @@ typedef struct {
                GsharedvtWrapperInfo gsharedvt;
                /* DELEGATE_INVOKE */
                DelegateInvokeWrapperInfo delegate_invoke;
+               /* INTERP_IN */
+               InterpInWrapperInfo interp_in;
        } d;
 } WrapperInfo;
 
index 482398288f8e40139c6f997f77069ad163d40f5d..79041633ffaf9d50d6cf372b05fdff33a4272f92 100755 (executable)
@@ -506,7 +506,8 @@ test_sources =                      \
        basic-vectors.cs \
        aot-tests.cs \
        gc-test.cs \
-       gshared.cs
+       gshared.cs \
+       mixed.cs
 
 if NACL_CODEGEN
 test_sources += nacl.cs
@@ -751,6 +752,9 @@ rcheck: mono $(regtests)
 richeck: mono $(regtests)
        $(INTERP_RUNTIME) --regression $(regtests)
 
+mixedcheck: mono mixed.exe
+       $(MINI_RUNTIME) --interp=jit=JitClass mixed.exe
+
 if ARM
 check-seq-points:
 else
index 9e09e7a944eb5d7a64fc7f6ef9c1f030ea93ea99..cd896155a121e3cce8d4d235712cfec6a7845638 100644 (file)
@@ -1907,9 +1907,18 @@ mono_main (int argc, char* argv[])
 #endif
                } else if (strcmp (argv [i], "--nollvm") == 0){
                        mono_use_llvm = FALSE;
+               } else if ((strcmp (argv [i], "--interpreter") == 0) || !strcmp (argv [i], "--interp")) {
 #ifdef ENABLE_INTERPRETER
-               } else if (strcmp (argv [i], "--interpreter") == 0) {
                        mono_use_interpreter = TRUE;
+#else
+                       fprintf (stderr, "Mono Warning: --interpreter not enabled in this runtime.\n");
+#endif
+               } else if (strncmp (argv [i], "--interp=", 9) == 0) {
+#ifdef ENABLE_INTERPRETER
+                       mono_use_interpreter = TRUE;
+                       mono_interp_parse_options (argv [i] + 9);
+#else
+                       fprintf (stderr, "Mono Warning: --interp= not enabled in this runtime.\n");
 #endif
 
 #ifdef __native_client__
index f26e4ff57b3badc3c7a3a9d5c9d91e1d9b3be89a..bda0b457e8520bfd76f4702efef447fe904a9fb0 100644 (file)
@@ -82,6 +82,12 @@ typedef struct _RuntimeMethod
        guint32 *local_offsets;
        unsigned int param_count;
        unsigned int hasthis;
+       gpointer jit_wrapper;
+       gpointer jit_addr;
+       MonoMethodSignature *jit_sig;
+       gpointer jit_entry;
+       MonoType *rtype;
+       MonoType **param_types;
 } RuntimeMethod;
 
 struct _MonoInvocation {
@@ -111,6 +117,7 @@ typedef struct {
 } ThreadContext;
 
 extern int mono_interp_traceopt;
+extern GSList *jit_classes;
 
 MonoException *
 mono_interp_transform_method (RuntimeMethod *runtime_method, ThreadContext *context);
index 5f44592287d9a2d157b9e07002017214d988110a..dcea13fe0d09c4ce431dbe5b94b32bf8e1bddb7e 100644 (file)
 #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;       \
+static inline void
+init_frame (MonoInvocation *frame, MonoInvocation *parent_frame, RuntimeMethod *rmethod, stackval *method_args, stackval *method_retval)
+{
+       frame->parent = parent_frame;
+       frame->stack_args = method_args;
+       frame->retval = method_retval;
+       frame->runtime_method = rmethod;
+       frame->ex = NULL;
+       frame->ip = NULL;
+       frame->invoke_trap = 0;
+}
+
+#define INIT_FRAME(frame,parent_frame,method_args,method_retval,domain,mono_method,error) do { \
+       RuntimeMethod *_rmethod = mono_interp_get_runtime_method ((domain), (mono_method), (error));    \
+       init_frame ((frame), (parent_frame), _rmethod, (method_args), (method_retval)); \
        } while (0)
 
+/*
+ * List of classes whose methods will be executed by transitioning to JITted code.
+ * Used for testing.
+ */
+GSList *jit_classes;
+
 void ves_exec_method (MonoInvocation *frame);
 
 static char* dump_stack (stackval *stack, stackval *sp);
@@ -258,18 +270,33 @@ RuntimeMethod*
 mono_interp_get_runtime_method (MonoDomain *domain, MonoMethod *method, MonoError *error)
 {
        RuntimeMethod *rtm;
+       MonoJitDomainInfo *info;
+       MonoMethodSignature *sig;
+       int i;
+
        error_init (error);
 
+       info = domain_jit_info (domain);
        mono_domain_jit_code_hash_lock (domain);
-       if ((rtm = mono_internal_hash_table_lookup (&domain->jit_code_hash, method))) {
-               mono_domain_jit_code_hash_unlock (domain);
+       rtm = mono_internal_hash_table_lookup (&info->interp_code_hash, method);
+       mono_domain_jit_code_hash_unlock (domain);
+       if (rtm)
                return rtm;
-       }
+
+       sig = mono_method_signature (method);
+
        rtm = mono_domain_alloc0 (domain, sizeof (RuntimeMethod));
        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);
+       rtm->param_count = sig->param_count;
+       rtm->hasthis = sig->hasthis;
+       rtm->rtype = mini_get_underlying_type (sig->ret);
+       rtm->param_types = mono_domain_alloc0 (domain, sizeof (MonoType*) * sig->param_count);
+       for (i = 0; i < sig->param_count; ++i)
+               rtm->param_types [i] = mini_get_underlying_type (sig->params [i]);
+
+       mono_domain_jit_code_hash_lock (domain);
+       if (!mono_internal_hash_table_lookup (&info->interp_code_hash, method))
+               mono_internal_hash_table_insert (&info->interp_code_hash, method, rtm);
        mono_domain_jit_code_hash_unlock (domain);
 
        return rtm;
@@ -1415,6 +1442,209 @@ handle_enum:
        return retval;
 }
 
+typedef struct {
+       RuntimeMethod *rmethod;
+       gpointer this_arg;
+       gpointer res;
+       gpointer args [16];
+       gpointer *many_args;
+} InterpEntryData;
+
+/* Main function for entering the interpreter from compiled code */
+static void
+interp_entry (InterpEntryData *data)
+{
+       MonoInvocation frame;
+       RuntimeMethod *rmethod = data->rmethod;
+       ThreadContext *context = mono_native_tls_get_value (thread_context_id);
+       ThreadContext context_struct;
+       MonoInvocation *old_frame;
+       stackval result;
+       stackval *args;
+       MonoMethod *method;
+       MonoMethodSignature *sig;
+       MonoType *type;
+       int i;
+
+       method = rmethod->method;
+       sig = mono_method_signature (method);
+
+       // FIXME: Optimize this
+
+       //printf ("%s\n", mono_method_full_name (method, 1));
+
+       frame.ex = NULL;
+       if (context == NULL) {
+               context = &context_struct;
+               memset (context, 0, sizeof (ThreadContext));
+               context_struct.base_frame = &frame;
+               context_struct.env_frame = &frame;
+               mono_native_tls_set_value (thread_context_id, context);
+       }
+       else
+               old_frame = context->current_frame;
+       context->domain = mono_domain_get ();
+
+       args = alloca (sizeof (stackval) * (sig->param_count + (sig->hasthis ? 1 : 0)));
+       if (sig->hasthis)
+               args [0].data.p = data->this_arg;
+
+       gpointer *params;
+       if (data->many_args)
+               params = data->many_args;
+       else
+               params = data->args;
+       for (i = 0; i < sig->param_count; ++i) {
+               int a_index = i + (sig->hasthis ? 1 : 0);
+               if (sig->params [i]->byref) {
+                       args [a_index].data.p = params [i];
+                       continue;
+               }
+               type = rmethod->param_types [i];
+               switch (type->type) {
+               case MONO_TYPE_U1:
+               case MONO_TYPE_I1:
+                       args [a_index].data.i = *(MonoBoolean*)params [i];
+                       break;
+               case MONO_TYPE_U2:
+               case MONO_TYPE_I2:
+                       args [a_index].data.i = *(gint16*)params [i];
+                       break;
+               case MONO_TYPE_U:
+#if SIZEOF_VOID_P == 4
+                       args [a_index].data.p = GINT_TO_POINTER (*(guint32*)params [i]);
+#else
+                       args [a_index].data.p = GINT_TO_POINTER (*(guint64*)params [i]);
+#endif
+                       break;
+               case MONO_TYPE_I:
+#if SIZEOF_VOID_P == 4
+                       args [a_index].data.p = GINT_TO_POINTER (*(gint32*)params [i]);
+#else
+                       args [a_index].data.p = GINT_TO_POINTER (*(gint64*)params [i]);
+#endif
+                       break;
+               case MONO_TYPE_U4:
+                       args [a_index].data.i = *(guint32*)params [i];
+                       break;
+               case MONO_TYPE_I4:
+                       args [a_index].data.i = *(gint32*)params [i];
+                       break;
+               case MONO_TYPE_U8:
+                       args [a_index].data.l = *(guint64*)params [i];
+                       break;
+               case MONO_TYPE_I8:
+                       args [a_index].data.l = *(gint64*)params [i];
+                       break;
+               case MONO_TYPE_PTR:
+               case MONO_TYPE_OBJECT:
+                       args [a_index].data.p = *(MonoObject**)params [i];
+                       break;
+               case MONO_TYPE_VALUETYPE:
+                       args [a_index].data.p = params [i];
+                       break;
+               case MONO_TYPE_GENERICINST:
+                       if (MONO_TYPE_IS_REFERENCE (type))
+                               args [a_index].data.p = params [i];
+                       else
+                               args [a_index].data.vt = params [i];
+                       break;
+               default:
+                       printf ("%s\n", mono_type_full_name (sig->params [i]));
+                       NOT_IMPLEMENTED;
+                       break;
+               }
+       }
+
+       init_frame (&frame, context->current_frame, data->rmethod, args, &result);
+       context->managed_code = 1;
+
+       type = rmethod->rtype;
+       switch (type->type) {
+       case MONO_TYPE_GENERICINST:
+               if (!MONO_TYPE_IS_REFERENCE (type))
+                       frame.retval->data.vt = data->res;
+               break;
+       case MONO_TYPE_VALUETYPE:
+               frame.retval->data.vt = data->res;
+               break;
+       default:
+               break;
+       }
+
+       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;
+
+       // FIXME:
+       g_assert (frame.ex == NULL);
+
+       type = rmethod->rtype;
+       switch (type->type) {
+       case MONO_TYPE_VOID:
+               break;
+       case MONO_TYPE_I1:
+               *(gint8*)data->res = frame.retval->data.i;
+               break;
+       case MONO_TYPE_U1:
+               *(guint8*)data->res = frame.retval->data.i;
+               break;
+       case MONO_TYPE_I2:
+               *(gint16*)data->res = frame.retval->data.i;
+               break;
+       case MONO_TYPE_U2:
+               *(guint16*)data->res = frame.retval->data.i;
+               break;
+       case MONO_TYPE_I4:
+               *(gint32*)data->res = frame.retval->data.i;
+               break;
+       case MONO_TYPE_U4:
+               *(guint64*)data->res = frame.retval->data.i;
+               break;
+       case MONO_TYPE_I8:
+               *(gint64*)data->res = frame.retval->data.i;
+               break;
+       case MONO_TYPE_U8:
+               *(guint64*)data->res = frame.retval->data.i;
+               break;
+       case MONO_TYPE_I:
+#if SIZEOF_VOID_P == 8
+               *(gint64*)data->res = (gint64)frame.retval->data.p;
+#else
+               *(gint32*)data->res = (gint32)frame.retval->data.p;
+#endif
+               break;
+       case MONO_TYPE_U:
+#if SIZEOF_VOID_P == 8
+               *(guint64*)data->res = (guint64)frame.retval->data.p;
+#else
+               *(guint32*)data->res = (guint32)frame.retval->data.p;
+#endif
+               break;
+       case MONO_TYPE_OBJECT:
+               /* No need for a write barrier */
+               *(MonoObject**)data->res = (MonoObject*)frame.retval->data.p;
+               break;
+       case MONO_TYPE_GENERICINST:
+               if (MONO_TYPE_IS_REFERENCE (type)) {
+                       *(MonoObject**)data->res = *(MonoObject**)frame.retval->data.p;
+               } else {
+                       /* Already set before the call */
+               }
+               break;
+       case MONO_TYPE_VALUETYPE:
+               /* Already set before the call */
+               break;
+       default:
+               printf ("%s\n", mono_type_full_name (sig->ret));
+               NOT_IMPLEMENTED;
+               break;
+       }
+}
+
 static stackval * 
 do_icall (ThreadContext *context, int op, stackval *sp, gpointer ptr)
 {
@@ -1504,84 +1734,220 @@ do_icall (ThreadContext *context, int op, stackval *sp, gpointer ptr)
        return sp;
 }
 
-static mono_mutex_t create_method_pointer_mutex;
-
-static GHashTable *method_pointer_hash = NULL;
-
-#define TRAMPS_USED 8
-
-static MonoMethod *method_pointers [TRAMPS_USED] = {0};
-
-#define GEN_METHOD_PTR_TRAMP(num) \
-               static MonoObject * mp_tramp_ ## num (MonoObject *this_obj, void **params, MonoObject **exc, void *compiled_method) { \
-                       MonoError error; \
-                       void *params_real[] = {this_obj, &params, &exc, &compiled_method}; \
-                       MonoObject *ret = mono_interp_runtime_invoke (method_pointers [num], NULL, params_real, NULL, &error); \
-                       mono_error_cleanup (&error); \
-                       return ret; \
-               }
-
+/*
+ * These functions are the entry points into the interpreter from compiled code.
+ * They are called by the interp_in wrappers. They have the following signature:
+ * void (<optional this_arg>, <optional retval pointer>, <arg1>, ..., <argn>, <method ptr>)
+ * They pack up their arguments into an InterpEntryData structure and call interp_entry ().
+ * It would be possible for the wrappers to pack up the arguments etc, but that would make them bigger, and there are
+ * more wrappers then these functions.
+ * this/static * ret/void * 16 arguments -> 64 functions.
+ */
 
-GEN_METHOD_PTR_TRAMP (0);
-GEN_METHOD_PTR_TRAMP (1);
-GEN_METHOD_PTR_TRAMP (2);
-GEN_METHOD_PTR_TRAMP (3);
-GEN_METHOD_PTR_TRAMP (4);
-GEN_METHOD_PTR_TRAMP (5);
-GEN_METHOD_PTR_TRAMP (6);
-GEN_METHOD_PTR_TRAMP (7);
+#define MAX_INTERP_ENTRY_ARGS 8
 
-#undef GEN_METHOD_PTR_TRAMP
+#define INTERP_ENTRY_BASE(_method, _this_arg, _res) \
+       InterpEntryData data; \
+       (data).rmethod = (_method); \
+       (data).res = (_res); \
+       (data).this_arg = (_this_arg); \
+       (data).many_args = NULL;
 
-gpointer *mp_tramps[TRAMPS_USED] = {
-       (gpointer) mp_tramp_0, (gpointer) mp_tramp_1, (gpointer) mp_tramp_2, (gpointer) mp_tramp_3,
-       (gpointer) mp_tramp_4, (gpointer) mp_tramp_5, (gpointer) mp_tramp_6, (gpointer) mp_tramp_7
-};
+#define INTERP_ENTRY0(_this_arg, _res, _method) {      \
+       INTERP_ENTRY_BASE (_method, _this_arg, _res); \
+       interp_entry (&data); \
+       }
+#define INTERP_ENTRY1(_this_arg, _res, _method) {        \
+       INTERP_ENTRY_BASE (_method, _this_arg, _res); \
+       (data).args [0] = arg1; \
+       interp_entry (&data); \
+       }
+#define INTERP_ENTRY2(_this_arg, _res, _method) {  \
+       INTERP_ENTRY_BASE (_method, _this_arg, _res); \
+       (data).args [0] = arg1; \
+       (data).args [1] = arg2; \
+       interp_entry (&data); \
+       }
+#define INTERP_ENTRY3(_this_arg, _res, _method) { \
+       INTERP_ENTRY_BASE (_method, _this_arg, _res); \
+       (data).args [0] = arg1; \
+       (data).args [1] = arg2; \
+       (data).args [2] = arg3; \
+       interp_entry (&data); \
+       }
+#define INTERP_ENTRY4(_this_arg, _res, _method) {      \
+       INTERP_ENTRY_BASE (_method, _this_arg, _res); \
+       (data).args [0] = arg1; \
+       (data).args [1] = arg2; \
+       (data).args [2] = arg3; \
+       (data).args [3] = arg4; \
+       interp_entry (&data); \
+       }
+#define INTERP_ENTRY5(_this_arg, _res, _method) {      \
+       INTERP_ENTRY_BASE (_method, _this_arg, _res); \
+       (data).args [0] = arg1; \
+       (data).args [1] = arg2; \
+       (data).args [2] = arg3; \
+       (data).args [3] = arg4; \
+       (data).args [4] = arg5; \
+       interp_entry (&data); \
+       }
+#define INTERP_ENTRY6(_this_arg, _res, _method) {      \
+       INTERP_ENTRY_BASE (_method, _this_arg, _res); \
+       (data).args [0] = arg1; \
+       (data).args [1] = arg2; \
+       (data).args [2] = arg3; \
+       (data).args [3] = arg4; \
+       (data).args [4] = arg5; \
+       (data).args [5] = arg6; \
+       interp_entry (&data); \
+       }
+#define INTERP_ENTRY7(_this_arg, _res, _method) {      \
+       INTERP_ENTRY_BASE (_method, _this_arg, _res); \
+       (data).args [0] = arg1; \
+       (data).args [1] = arg2; \
+       (data).args [2] = arg3; \
+       (data).args [3] = arg4; \
+       (data).args [4] = arg5; \
+       (data).args [5] = arg6; \
+       (data).args [6] = arg7; \
+       interp_entry (&data); \
+       }
+#define INTERP_ENTRY8(_this_arg, _res, _method) {      \
+       INTERP_ENTRY_BASE (_method, _this_arg, _res); \
+       (data).args [0] = arg1; \
+       (data).args [1] = arg2; \
+       (data).args [2] = arg3; \
+       (data).args [3] = arg4; \
+       (data).args [4] = arg5; \
+       (data).args [5] = arg6; \
+       (data).args [6] = arg7; \
+       (data).args [7] = arg8; \
+       interp_entry (&data); \
+       }
 
-static int tramps_used = 0;
+#define ARGLIST0 RuntimeMethod *rmethod
+#define ARGLIST1 gpointer arg1, RuntimeMethod *rmethod
+#define ARGLIST2 gpointer arg1, gpointer arg2, RuntimeMethod *rmethod
+#define ARGLIST3 gpointer arg1, gpointer arg2, gpointer arg3, RuntimeMethod *rmethod
+#define ARGLIST4 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, RuntimeMethod *rmethod
+#define ARGLIST5 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, gpointer arg5, RuntimeMethod *rmethod
+#define ARGLIST6 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, gpointer arg5, gpointer arg6, RuntimeMethod *rmethod
+#define ARGLIST7 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, gpointer arg5, gpointer arg6, gpointer arg7, RuntimeMethod *rmethod
+#define ARGLIST8 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, gpointer arg5, gpointer arg6, gpointer arg7, gpointer arg8, RuntimeMethod *rmethod
+
+static void interp_entry_static_0 (ARGLIST0) INTERP_ENTRY0 (NULL, NULL, rmethod)
+static void interp_entry_static_1 (ARGLIST1) INTERP_ENTRY1 (NULL, NULL, rmethod)
+static void interp_entry_static_2 (ARGLIST2) INTERP_ENTRY2 (NULL, NULL, rmethod)
+static void interp_entry_static_3 (ARGLIST3) INTERP_ENTRY3 (NULL, NULL, rmethod)
+static void interp_entry_static_4 (ARGLIST4) INTERP_ENTRY4 (NULL, NULL, rmethod)
+static void interp_entry_static_5 (ARGLIST5) INTERP_ENTRY5 (NULL, NULL, rmethod)
+static void interp_entry_static_6 (ARGLIST6) INTERP_ENTRY6 (NULL, NULL, rmethod)
+static void interp_entry_static_7 (ARGLIST7) INTERP_ENTRY7 (NULL, NULL, rmethod)
+static void interp_entry_static_8 (ARGLIST8) INTERP_ENTRY8 (NULL, NULL, rmethod)
+static void interp_entry_static_ret_0 (gpointer res, ARGLIST0) INTERP_ENTRY0 (NULL, res, rmethod)
+static void interp_entry_static_ret_1 (gpointer res, ARGLIST1) INTERP_ENTRY1 (NULL, res, rmethod)
+static void interp_entry_static_ret_2 (gpointer res, ARGLIST2) INTERP_ENTRY2 (NULL, res, rmethod)
+static void interp_entry_static_ret_3 (gpointer res, ARGLIST3) INTERP_ENTRY3 (NULL, res, rmethod)
+static void interp_entry_static_ret_4 (gpointer res, ARGLIST4) INTERP_ENTRY4 (NULL, res, rmethod)
+static void interp_entry_static_ret_5 (gpointer res, ARGLIST5) INTERP_ENTRY5 (NULL, res, rmethod)
+static void interp_entry_static_ret_6 (gpointer res, ARGLIST6) INTERP_ENTRY6 (NULL, res, rmethod)
+static void interp_entry_static_ret_7 (gpointer res, ARGLIST7) INTERP_ENTRY7 (NULL, res, rmethod)
+static void interp_entry_static_ret_8 (gpointer res, ARGLIST8) INTERP_ENTRY8 (NULL, res, rmethod)
+static void interp_entry_instance_0 (gpointer this_arg, ARGLIST0) INTERP_ENTRY0 (this_arg, NULL, rmethod)
+static void interp_entry_instance_1 (gpointer this_arg, ARGLIST1) INTERP_ENTRY1 (this_arg, NULL, rmethod)
+static void interp_entry_instance_2 (gpointer this_arg, ARGLIST2) INTERP_ENTRY2 (this_arg, NULL, rmethod)
+static void interp_entry_instance_3 (gpointer this_arg, ARGLIST3) INTERP_ENTRY3 (this_arg, NULL, rmethod)
+static void interp_entry_instance_4 (gpointer this_arg, ARGLIST4) INTERP_ENTRY4 (this_arg, NULL, rmethod)
+static void interp_entry_instance_5 (gpointer this_arg, ARGLIST5) INTERP_ENTRY5 (this_arg, NULL, rmethod)
+static void interp_entry_instance_6 (gpointer this_arg, ARGLIST6) INTERP_ENTRY6 (this_arg, NULL, rmethod)
+static void interp_entry_instance_7 (gpointer this_arg, ARGLIST7) INTERP_ENTRY7 (this_arg, NULL, rmethod)
+static void interp_entry_instance_8 (gpointer this_arg, ARGLIST8) INTERP_ENTRY8 (this_arg, NULL, rmethod)
+static void interp_entry_instance_ret_0 (gpointer this_arg, gpointer res, ARGLIST0) INTERP_ENTRY0 (this_arg, res, rmethod)
+static void interp_entry_instance_ret_1 (gpointer this_arg, gpointer res, ARGLIST1) INTERP_ENTRY1 (this_arg, res, rmethod)
+static void interp_entry_instance_ret_2 (gpointer this_arg, gpointer res, ARGLIST2) INTERP_ENTRY2 (this_arg, res, rmethod)
+static void interp_entry_instance_ret_3 (gpointer this_arg, gpointer res, ARGLIST3) INTERP_ENTRY3 (this_arg, res, rmethod)
+static void interp_entry_instance_ret_4 (gpointer this_arg, gpointer res, ARGLIST4) INTERP_ENTRY4 (this_arg, res, rmethod)
+static void interp_entry_instance_ret_5 (gpointer this_arg, gpointer res, ARGLIST5) INTERP_ENTRY5 (this_arg, res, rmethod)
+static void interp_entry_instance_ret_6 (gpointer this_arg, gpointer res, ARGLIST6) INTERP_ENTRY6 (this_arg, res, rmethod)
+static void interp_entry_instance_ret_7 (gpointer this_arg, gpointer res, ARGLIST7) INTERP_ENTRY6 (this_arg, res, rmethod)
+static void interp_entry_instance_ret_8 (gpointer this_arg, gpointer res, ARGLIST8) INTERP_ENTRY6 (this_arg, res, rmethod)
+
+#define INTERP_ENTRY_FUNCLIST(type) interp_entry_ ## type ## _0, interp_entry_ ## type ## _1, interp_entry_ ## type ## _2, interp_entry_ ## type ## _3, interp_entry_ ## type ## _4, interp_entry_ ## type ## _5, interp_entry_ ## type ## _6, interp_entry_ ## type ## _7, interp_entry_ ## type ## _8
+
+gpointer entry_funcs_static [MAX_INTERP_ENTRY_ARGS + 1] = { INTERP_ENTRY_FUNCLIST (static) };
+gpointer entry_funcs_static_ret [MAX_INTERP_ENTRY_ARGS + 1] = { INTERP_ENTRY_FUNCLIST (static_ret) };
+gpointer entry_funcs_instance [MAX_INTERP_ENTRY_ARGS + 1] = { INTERP_ENTRY_FUNCLIST (instance) };
+gpointer entry_funcs_instance_ret [MAX_INTERP_ENTRY_ARGS + 1] = { INTERP_ENTRY_FUNCLIST (instance_ret) };
+
+/* General version for methods with more than MAX_INTERP_ENTRY_ARGS arguments */
+static void
+interp_entry_general (gpointer this_arg, gpointer res, gpointer *args, gpointer rmethod)
+{
+       INTERP_ENTRY_BASE (rmethod, this_arg, res);
+       data.many_args = args;
+       interp_entry (&data);
+}
 
+/*
+ * mono_interp_create_method_pointer:
+ *
+ * Return a function pointer which can be used to call METHOD using the
+ * interpreter. Return NULL for methods which are not supported.
+ */
 gpointer
 mono_interp_create_method_pointer (MonoMethod *method, MonoError *error)
 {
        gpointer addr;
-       MonoJitInfo *ji;
+       MonoMethodSignature *sig = mono_method_signature (method);
+       MonoMethod *wrapper;
+       RuntimeMethod *rmethod;
 
-       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 (method->wrapper_type && method->wrapper_type != MONO_WRAPPER_RUNTIME_INVOKE)
+               return NULL;
+
+       rmethod = mono_interp_get_runtime_method (mono_domain_get (), method, error);
+       if (rmethod->jit_entry)
+               return rmethod->jit_entry;
+       wrapper = mini_get_interp_in_wrapper (sig);
+
+       gpointer jit_wrapper = mono_jit_compile_method_jit_only (wrapper, error);
+       mono_error_assert_ok (error);
+
+       //printf ("%s %s\n", mono_method_full_name (method, 1), mono_method_full_name (wrapper, 1));
+       gpointer entry_func;
+       if (sig->param_count > MAX_INTERP_ENTRY_ARGS) {
+               entry_func = interp_entry_general;
+       } else if (sig->hasthis) {
+               if (sig->ret->type == MONO_TYPE_VOID)
+                       entry_func = entry_funcs_instance [sig->param_count];
+               else
+                       entry_func = entry_funcs_instance_ret [sig->param_count];
+       } else {
+               if (sig->ret->type == MONO_TYPE_VOID)
+                       entry_func = entry_funcs_static [sig->param_count];
+               else
+                       entry_func = entry_funcs_static_ret [sig->param_count];
        }
+       g_assert (entry_func);
+
+       /* This is the argument passed to the interp_in wrapper by the static rgctx trampoline */
+       MonoFtnDesc *ftndesc = g_new0 (MonoFtnDesc, 1);
+       ftndesc->addr = entry_func;
+       ftndesc->arg = rmethod;
+       mono_error_assert_ok (error);
 
        /*
-        * If it is a static P/Invoke method, we can just return the pointer
-        * to the method implementation.
+        * The wrapper is called by compiled code, which doesn't pass the extra argument, so we pass it in the
+        * rgctx register using a trampoline.
         */
-       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 < TRAMPS_USED);
-
-               /* 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);
+       // FIXME: AOT
+       g_assert (!mono_aot_only);
+       addr = mono_arch_get_static_rgctx_trampoline (ftndesc, jit_wrapper);
+
+       mono_memory_barrier ();
+       rmethod->jit_entry = addr;
 
        return addr;
 }
@@ -1970,6 +2336,7 @@ ves_exec_method_with_context (MonoInvocation *frame, ThreadContext *context)
                                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;
@@ -2023,6 +2390,215 @@ ves_exec_method_with_context (MonoInvocation *frame, ThreadContext *context)
                        }
                        MINT_IN_BREAK;
                }
+
+               MINT_IN_CASE(MINT_JIT_CALL) {
+                       MonoMethodSignature *sig;
+                       RuntimeMethod *rmethod = rtm->data_items [* (guint16 *)(ip + 1)];
+                       MonoFtnDesc ftndesc;
+                       guint8 res_buf [256];
+                       MonoType *type;
+
+                       //printf ("%s\n", mono_method_full_name (rmethod->method, 1));
+
+                       /*
+                        * Call JITted code through a gsharedvt_out wrapper. These wrappers receive every argument
+                        * by ref and return a return value using an explicit return value argument.
+                        */
+                       if (!rmethod->jit_wrapper) {
+                               MonoMethod *method = rmethod->method;
+                               MonoError error;
+
+                               sig = mono_method_signature (method);
+                               g_assert (sig);
+
+                               MonoMethod *wrapper = mini_get_gsharedvt_out_sig_wrapper (sig);
+                               //printf ("J: %s %s\n", mono_method_full_name (method, 1), mono_method_full_name (wrapper, 1));
+
+                               gpointer jit_wrapper = mono_jit_compile_method_jit_only (wrapper, &error);
+                               mono_error_assert_ok (&error);
+
+                               gpointer addr = mono_jit_compile_method_jit_only (method, &error);
+                               g_assert (addr);
+                               mono_error_assert_ok (&error);
+
+                               rmethod->jit_addr = addr;
+                               rmethod->jit_sig = sig;
+                               mono_memory_barrier ();
+                               rmethod->jit_wrapper = jit_wrapper;
+
+                       } else {
+                               sig = rmethod->jit_sig;
+                       }
+
+                       frame->ip = ip;
+                       ip += 2;
+                       sp -= sig->param_count;
+                       if (sig->hasthis)
+                               --sp;
+
+                       ftndesc.addr = rmethod->jit_addr;
+                       ftndesc.arg = NULL;
+
+                       // FIXME: Optimize this
+
+                       gpointer args [32];
+                       int pindex = 0;
+                       int stack_index = 0;
+                       if (rmethod->hasthis) {
+                               args [pindex ++] = sp [0].data.p;
+                               stack_index ++;
+                       }
+                       type = rmethod->rtype;
+                       if (type->type != MONO_TYPE_VOID) {
+                               if (MONO_TYPE_ISSTRUCT (type))
+                                       args [pindex ++] = vt_sp;
+                               else
+                                       args [pindex ++] = res_buf;
+                       }
+                       for (int i = 0; i < rmethod->param_count; ++i) {
+                               MonoType *t = rmethod->param_types [i];
+                               stackval *sval = &sp [stack_index + i];
+                               if (sig->params [i]->byref) {
+                                       args [pindex ++] = sval->data.p;
+                               } else if (MONO_TYPE_ISSTRUCT (t)) {
+                                       args [pindex ++] = sval->data.p;
+                               } else if (MONO_TYPE_IS_REFERENCE (t)) {
+                                       args [pindex ++] = &sval->data.p;
+                               } else {
+                                       switch (t->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_VALUETYPE:
+                                               args [pindex ++] = &sval->data.i;
+                                               break;
+                                       case MONO_TYPE_PTR:
+                                       case MONO_TYPE_FNPTR:
+                                       case MONO_TYPE_I:
+                                       case MONO_TYPE_U:
+                                       case MONO_TYPE_OBJECT:
+                                               args [pindex ++] = &sval->data.p;
+                                               break;
+                                       case MONO_TYPE_I8:
+                                       case MONO_TYPE_U8:
+                                               args [pindex ++] = &sval->data.l;
+                                               break;
+                                       default:
+                                               printf ("%s\n", mono_type_full_name (t));
+                                               g_assert_not_reached ();
+                                       }
+                               }
+                       }
+
+                       switch (pindex) {
+                       case 0: {
+                               void (*func)(gpointer) = rmethod->jit_wrapper;
+
+                               func (&ftndesc);
+                               break;
+                       }
+                       case 1: {
+                               void (*func)(gpointer, gpointer) = rmethod->jit_wrapper;
+
+                               func (args [0], &ftndesc);
+                               break;
+                       }
+                       case 2: {
+                               void (*func)(gpointer, gpointer, gpointer) = rmethod->jit_wrapper;
+
+                               func (args [0], args [1], &ftndesc);
+                               break;
+                       }
+                       case 3: {
+                               void (*func)(gpointer, gpointer, gpointer, gpointer) = rmethod->jit_wrapper;
+
+                               func (args [0], args [1], args [2], &ftndesc);
+                               break;
+                       }
+                       case 4: {
+                               void (*func)(gpointer, gpointer, gpointer, gpointer, gpointer) = rmethod->jit_wrapper;
+
+                               func (args [0], args [1], args [2], args [3], &ftndesc);
+                               break;
+                       }
+                       case 5: {
+                               void (*func)(gpointer, gpointer, gpointer, gpointer, gpointer, gpointer) = rmethod->jit_wrapper;
+
+                               func (args [0], args [1], args [2], args [3], args [4], &ftndesc);
+                               break;
+                       }
+                       case 6: {
+                               void (*func)(gpointer, gpointer, gpointer, gpointer, gpointer, gpointer, gpointer) = rmethod->jit_wrapper;
+
+                               func (args [0], args [1], args [2], args [3], args [4], args [5], &ftndesc);
+                               break;
+                       }
+                       case 7: {
+                               void (*func)(gpointer, gpointer, gpointer, gpointer, gpointer, gpointer, gpointer, gpointer) = rmethod->jit_wrapper;
+
+                               func (args [0], args [1], args [2], args [3], args [4], args [5], args [6], &ftndesc);
+                               break;
+                       }
+                       default:
+                               g_assert_not_reached ();
+                               break;
+                       }
+
+                       MonoType *rtype = rmethod->rtype;
+                       switch (rtype->type) {
+                       case MONO_TYPE_VOID:
+                       case MONO_TYPE_OBJECT:
+                       case MONO_TYPE_STRING:
+                       case MONO_TYPE_CLASS:
+                       case MONO_TYPE_ARRAY:
+                       case MONO_TYPE_SZARRAY:
+                       case MONO_TYPE_I:
+                       case MONO_TYPE_U:
+                               sp->data.p = *(gpointer*)res_buf;
+                               break;
+                       case MONO_TYPE_I1:
+                               sp->data.i = *(gint8*)res_buf;
+                               break;
+                       case MONO_TYPE_U1:
+                               sp->data.i = *(guint8*)res_buf;
+                               break;
+                       case MONO_TYPE_I2:
+                               sp->data.i = *(gint16*)res_buf;
+                               break;
+                       case MONO_TYPE_U2:
+                               sp->data.i = *(guint16*)res_buf;
+                               break;
+                       case MONO_TYPE_I4:
+                               sp->data.i = *(gint32*)res_buf;
+                               break;
+                       case MONO_TYPE_U4:
+                               sp->data.i = *(guint32*)res_buf;
+                               break;
+                       case MONO_TYPE_VALUETYPE:
+                               /* The result was written to vt_sp */
+                               sp->data.p = vt_sp;
+                               break;
+                       case MONO_TYPE_GENERICINST:
+                               if (MONO_TYPE_IS_REFERENCE (rtype)) {
+                                       sp->data.p = *(gpointer*)res_buf;
+                               } else {
+                                       /* The result was written to vt_sp */
+                                       sp->data.p = vt_sp;
+                               }
+                               break;
+                       default:
+                               printf ("%s\n", mono_type_full_name (rtype));
+                               g_assert_not_reached ();
+                               break;
+                       }
+                       if (rtype->type != MONO_TYPE_VOID)
+                               sp++;
+                       MINT_IN_BREAK;
+               }
+
                MINT_IN_CASE(MINT_CALLVIRT) {
                        stackval *endsp = sp;
                        MonoObject *this_arg;
@@ -3668,6 +4244,9 @@ array_constructed:
                        BINOP_CAST(l, -, guint64);
                        MINT_IN_BREAK;
                MINT_IN_CASE(MINT_ENDFINALLY)
+                       while (sp > frame->stack) {
+                               --sp;
+                       }
                        if (finally_ips) {
                                ip = finally_ips->data;
                                finally_ips = g_slist_remove (finally_ips, ip);
@@ -4425,12 +5004,25 @@ interp_ves_icall_get_trace (MonoException *exc, gint32 skip, MonoBoolean need_fi
        return res;
 }
 
+void
+mono_interp_parse_options (const char *options)
+{
+       char **args, **ptr;
+
+       args = g_strsplit (options, ",", -1);
+       for (ptr = args; ptr && *ptr; ptr ++) {
+               char *arg = *ptr;
+
+               if (strncmp (arg, "jit=", 4) == 0)
+                       jit_classes = g_slist_prepend (jit_classes, arg + 4);
+       }
+}
+
 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 (&create_method_pointer_mutex);
+       mono_native_tls_set_value (thread_context_id, NULL);
 
        mono_interp_transform_init ();
 }
@@ -4547,6 +5139,7 @@ interp_regression_step (MonoImage *image, int verbose, int *total_run, int *tota
        *total += failed + cfailed;
        *total_run += run;
 }
+
 static int
 interp_regression (MonoImage *image, int verbose, int *total_run)
 {
index 6189b3d1be4e709841609b011a0ec76182cb2b5f..951c47c85e1a416fa8bcbad7e87d0263ccff3228 100644 (file)
@@ -24,6 +24,9 @@ mono_interp_init_delegate (MonoDelegate *del);
 gpointer
 mono_interp_create_trampoline (MonoDomain *domain, MonoMethod *method, MonoError *error);
 
+void
+mono_interp_parse_options (const char *options);
+
 void
 interp_walk_stack_with_ctx (MonoInternalStackWalk func, MonoContext *ctx, MonoUnwindOptions options, void *user_data);
 #endif /* __MONO_MINI_INTERPRETER_H__ */
index a6afa577ebd66786f2dd9b42a27484a140b377c7..43f4e6b124f9fcd6d70a9f9ba82e23b24aae459a 100644 (file)
@@ -509,4 +509,5 @@ OPDEF(MINT_MONO_NEWOBJ, "mono_newobj", 2, MintOpClassToken)
 OPDEF(MINT_MONO_RETOBJ, "mono_retobj", 1, MintOpNoArgs)
 OPDEF(MINT_MONO_FREE, "mono_free", 1, MintOpNoArgs)
 
-
+// FIXME: MintOp
+OPDEF(MINT_JIT_CALL, "mono_jit_call", 2, MintOpNoArgs)
index 1b1776867fcc1bfe1b585db11a1e008a96c4ea3f..ee5f65ac116c34916a3cb621e4d10b90fd262db6 100644 (file)
@@ -636,6 +636,35 @@ get_data_item_index (TransformData *td, void *ptr)
        return index;
 }
 
+static gboolean
+jit_call_supported (MonoMethod *method, MonoMethodSignature *sig)
+{
+       GSList *l;
+
+       if (sig->param_count > 6)
+               return FALSE;
+       if (sig->pinvoke)
+               return FALSE;
+       if (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
+               return FALSE;
+       if (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL)
+               return FALSE;
+       if (method->is_inflated)
+               return FALSE;
+       if (method->string_ctor)
+               return FALSE;
+
+       for (l = jit_classes; l; l = l->next) {
+               char *class_name = l->data;
+               // FIXME: Namespaces
+               if (!strcmp (method->klass->name, class_name))
+                       return TRUE;
+       }
+
+       //return TRUE;
+       return FALSE;
+}
+
 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, gboolean readonly)
 {
@@ -858,6 +887,10 @@ interp_transform_call (TransformData *td, MonoMethod *method, MonoMethod *target
                        ADD_CODE (td, get_data_item_index (td, target_method->klass));
                        ADD_CODE (td, 1 + target_method->klass->rank);
                }
+       } else if (!calli && !virtual && jit_call_supported (target_method, csignature)) {
+               ADD_CODE(td, MINT_JIT_CALL);
+               ADD_CODE(td, get_data_item_index (td, (void *)mono_interp_get_runtime_method (domain, target_method, &error)));
+               mono_error_assert_ok (&error);
        } else {
                if (calli)
                        ADD_CODE(td, native ? MINT_CALLI_NAT : MINT_CALLI);
@@ -865,7 +898,7 @@ interp_transform_call (TransformData *td, MonoMethod *method, MonoMethod *target
                        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 {
@@ -2759,6 +2792,7 @@ generate (MonoMethod *method, RuntimeMethod *rtm, unsigned char *is_bb_start, Mo
                        ++td.ip;
                        break;
                case CEE_ENDFINALLY:
+                       td.sp = td.stack;
                        SIMPLE_OP (td, MINT_ENDFINALLY);
                        generating_code = 0;
                        break;
@@ -3122,6 +3156,7 @@ generate (MonoMethod *method, RuntimeMethod *rtm, unsigned char *is_bb_start, Mo
                                CHECK_STACK(&td, 3);
                                ADD_CODE(&td, MINT_INITBLK);
                                td.sp -= 3;
+                               td.ip += 1;
                                break;
 #if 0
                        case CEE_NO_:
index 29e0b1081fec7fd5c65ff23a4b414b61fb2c713d..2f96bebabc34afb0c6557ceb46ff9595dafdace0 100644 (file)
@@ -1261,16 +1261,22 @@ mono_get_got_var (MonoCompile *cfg)
        return cfg->got_var;
 }
 
-static MonoInst *
-mono_get_vtable_var (MonoCompile *cfg)
+static void
+mono_create_rgctx_var (MonoCompile *cfg)
 {
-       g_assert (cfg->gshared);
-
        if (!cfg->rgctx_var) {
                cfg->rgctx_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
                /* force the var to be stack allocated */
                cfg->rgctx_var->flags |= MONO_INST_VOLATILE;
        }
+}
+
+static MonoInst *
+mono_get_vtable_var (MonoCompile *cfg)
+{
+       g_assert (cfg->gshared);
+
+       mono_create_rgctx_var (cfg);
 
        return cfg->rgctx_var;
 }
@@ -12340,6 +12346,21 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                ins->type = STACK_I4;
                                MONO_ADD_INS (cfg->cbb, ins);
 
+                               ip += 2;
+                               *sp++ = ins;
+                               break;
+                       case CEE_MONO_GET_RGCTX_ARG:
+                               CHECK_OPSIZE (2);
+                               CHECK_STACK_OVF (1);
+
+                               mono_create_rgctx_var (cfg);
+
+                               MONO_INST_NEW (cfg, ins, OP_MOVE);
+                               ins->dreg = alloc_dreg (cfg, STACK_PTR);
+                               ins->sreg1 = cfg->rgctx_var->dreg;
+                               ins->type = STACK_PTR;
+                               MONO_ADD_INS (cfg->cbb, ins);
+
                                ip += 2;
                                *sp++ = ins;
                                break;
index deeee74524e350dc6737772a58167528c70ea6c2..bc7d12aa678ed4dd54f5f111ef17998c28aa1668 100644 (file)
@@ -1200,9 +1200,9 @@ mini_get_gsharedvt_in_sig_wrapper (MonoMethodSignature *sig)
        sig = mini_get_underlying_signature (sig);
 
        // FIXME: Normal cache
+       gshared_lock ();
        if (!cache)
                cache = g_hash_table_new_full ((GHashFunc)mono_signature_hash, (GEqualFunc)mono_metadata_signature_equal, NULL, NULL);
-       gshared_lock ();
        res = g_hash_table_lookup (cache, sig);
        gshared_unlock ();
        if (res) {
@@ -1304,9 +1304,9 @@ mini_get_gsharedvt_out_sig_wrapper (MonoMethodSignature *sig)
        sig = mini_get_underlying_signature (sig);
 
        // FIXME: Normal cache
+       gshared_lock ();
        if (!cache)
                cache = g_hash_table_new_full ((GHashFunc)mono_signature_hash, (GEqualFunc)mono_metadata_signature_equal, NULL, NULL);
-       gshared_lock ();
        res = g_hash_table_lookup (cache, sig);
        gshared_unlock ();
        if (res) {
@@ -1408,6 +1408,170 @@ mini_get_gsharedvt_out_sig_wrapper (MonoMethodSignature *sig)
        return res;
 }
 
+/*
+ * mini_get_interp_in_wrapper:
+ *
+ *   Return a wrapper which can be used to transition from compiled code to the interpreter.
+ * The wrapper has the same signature as SIG. It is very similar to a gsharedvt_in wrapper,
+ * except the 'extra_arg' is passed in the rgctx reg, so this wrapper needs to be
+ * called through a static rgctx trampoline.
+ * FIXME: Move this elsewhere.
+ */
+MonoMethod*
+mini_get_interp_in_wrapper (MonoMethodSignature *sig)
+{
+       MonoMethodBuilder *mb;
+       MonoMethod *res, *cached;
+       WrapperInfo *info;
+       MonoMethodSignature *csig, *entry_sig;
+       int i, pindex, retval_var = 0;
+       static GHashTable *cache;
+       const char *name;
+       gboolean generic = FALSE;
+
+       sig = mini_get_underlying_signature (sig);
+
+       gshared_lock ();
+       if (!cache)
+               cache = g_hash_table_new_full ((GHashFunc)mono_signature_hash, (GEqualFunc)mono_metadata_signature_equal, NULL, NULL);
+       res = g_hash_table_lookup (cache, sig);
+       gshared_unlock ();
+       if (res) {
+               g_free (sig);
+               return res;
+       }
+
+       if (sig->param_count > 8)
+               /* Call the generic interpreter entry point, the specialized ones only handle a limited number of arguments */
+               generic = TRUE;
+
+       /* Create the signature for the wrapper */
+       csig = g_malloc0 (MONO_SIZEOF_METHOD_SIGNATURE + (sig->param_count * sizeof (MonoType*)));
+       memcpy (csig, sig, mono_metadata_signature_size (sig));
+
+       /* Create the signature for the callee callconv */
+       if (generic) {
+               /*
+                * The called function has the following signature:
+                * interp_entry_general (gpointer this_arg, gpointer res, gpointer *args, gpointer rmethod)
+                */
+               entry_sig = g_malloc0 (MONO_SIZEOF_METHOD_SIGNATURE + (4 * sizeof (MonoType*)));
+               entry_sig->ret = &mono_defaults.void_class->byval_arg;
+               entry_sig->param_count = 4;
+               entry_sig->params [0] = &mono_defaults.int_class->byval_arg;
+               entry_sig->params [1] = &mono_defaults.int_class->byval_arg;
+               entry_sig->params [2] = &mono_defaults.int_class->byval_arg;
+               entry_sig->params [3] = &mono_defaults.int_class->byval_arg;
+               name = "interp_in_generic";
+               generic = TRUE;
+       } else  {
+               /*
+                * The called function has the following signature:
+                * void entry(<optional this ptr>, <optional return ptr>, <arguments>, <extra arg>)
+                */
+               entry_sig = g_malloc0 (MONO_SIZEOF_METHOD_SIGNATURE + ((sig->param_count + 2) * sizeof (MonoType*)));
+               memcpy (entry_sig, sig, mono_metadata_signature_size (sig));
+               pindex = 0;
+               /* The return value is returned using an explicit vret argument */
+               if (sig->ret->type != MONO_TYPE_VOID) {
+                       entry_sig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
+                       entry_sig->ret = &mono_defaults.void_class->byval_arg;
+               }
+               for (i = 0; i < sig->param_count; i++) {
+                       entry_sig->params [pindex] = sig->params [i];
+                       if (!sig->params [i]->byref) {
+                               entry_sig->params [pindex] = mono_metadata_type_dup (NULL, entry_sig->params [pindex]);
+                               entry_sig->params [pindex]->byref = 1;
+                       }
+                       pindex ++;
+               }
+               /* Extra arg */
+               entry_sig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
+               entry_sig->param_count = pindex;
+               name = sig->hasthis ? "interp_in" : "interp_in_static";
+       }
+
+       mb = mono_mb_new (mono_defaults.object_class, name, MONO_WRAPPER_UNKNOWN);
+
+       // FIXME: save lmf
+
+#ifndef DISABLE_JIT
+       if (sig->ret->type != MONO_TYPE_VOID)
+               retval_var = mono_mb_add_local (mb, sig->ret);
+
+       /* Make the call */
+       if (generic) {
+               /* Collect arguments */
+               int args_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
+
+               mono_mb_emit_icon (mb, sizeof (gpointer) * sig->param_count);
+               mono_mb_emit_byte (mb, CEE_PREFIX1);
+               mono_mb_emit_byte (mb, CEE_LOCALLOC);
+               mono_mb_emit_stloc (mb, args_var);
+
+               for (i = 0; i < sig->param_count; i++) {
+                       mono_mb_emit_ldloc (mb, args_var);
+                       mono_mb_emit_icon (mb, sizeof (gpointer) * i);
+                       mono_mb_emit_byte (mb, CEE_ADD);
+                       if (sig->params [i]->byref)
+                               mono_mb_emit_ldarg (mb, i + (sig->hasthis == TRUE));
+                       else
+                               mono_mb_emit_ldarg_addr (mb, i + (sig->hasthis == TRUE));
+                       mono_mb_emit_byte (mb, CEE_STIND_I);
+               }
+
+               if (sig->hasthis)
+                       mono_mb_emit_ldarg (mb, 0);
+               else
+                       mono_mb_emit_byte (mb, CEE_LDNULL);
+               if (sig->ret->type != MONO_TYPE_VOID)
+                       mono_mb_emit_ldloc_addr (mb, retval_var);
+               else
+                       mono_mb_emit_byte (mb, CEE_LDNULL);
+               mono_mb_emit_ldloc (mb, args_var);
+       } else {
+               if (sig->hasthis)
+                       mono_mb_emit_ldarg (mb, 0);
+               if (sig->ret->type != MONO_TYPE_VOID)
+                       mono_mb_emit_ldloc_addr (mb, retval_var);
+               for (i = 0; i < sig->param_count; i++) {
+                       if (sig->params [i]->byref)
+                               mono_mb_emit_ldarg (mb, i + (sig->hasthis == TRUE));
+                       else
+                               mono_mb_emit_ldarg_addr (mb, i + (sig->hasthis == TRUE));
+               }
+       }
+       /* Extra arg */
+       mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
+       mono_mb_emit_byte (mb, CEE_MONO_GET_RGCTX_ARG);
+       mono_mb_emit_icon (mb, sizeof (gpointer));
+       mono_mb_emit_byte (mb, CEE_ADD);
+       mono_mb_emit_byte (mb, CEE_LDIND_I);
+       /* Method to call */
+       mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
+       mono_mb_emit_byte (mb, CEE_MONO_GET_RGCTX_ARG);
+       mono_mb_emit_byte (mb, CEE_LDIND_I);
+       mono_mb_emit_calli (mb, entry_sig);
+       if (sig->ret->type != MONO_TYPE_VOID)
+               mono_mb_emit_ldloc (mb, retval_var);
+       mono_mb_emit_byte (mb, CEE_RET);
+#endif
+
+       info = mono_wrapper_info_create (mb, WRAPPER_SUBTYPE_INTERP_IN);
+       info->d.interp_in.sig = sig;
+
+       res = mono_mb_create (mb, csig, sig->param_count + 16, info);
+
+       gshared_lock ();
+       cached = g_hash_table_lookup (cache, sig);
+       if (cached)
+               res = cached;
+       else
+               g_hash_table_insert (cache, sig, res);
+       gshared_unlock ();
+       return res;
+}
+
 MonoMethodSignature*
 mini_get_gsharedvt_out_sig_wrapper_signature (gboolean has_this, gboolean has_ret, int param_count)
 {
index d8f22a99a33a17c5c41ae535a11d63334045cc5c..656499033cf76d28962e81fe5fc2db12515c8e63 100644 (file)
@@ -1751,7 +1751,7 @@ no_gsharedvt_in_wrapper (void)
 }
 
 static gpointer
-mono_jit_compile_method_with_opt (MonoMethod *method, guint32 opt, MonoError *error)
+mono_jit_compile_method_with_opt (MonoMethod *method, guint32 opt, gboolean jit_only, MonoError *error)
 {
        MonoDomain *target_domain, *domain = mono_domain_get ();
        MonoJitInfo *info;
@@ -1763,8 +1763,11 @@ mono_jit_compile_method_with_opt (MonoMethod *method, guint32 opt, MonoError *er
        error_init (error);
 
 #ifdef ENABLE_INTERPRETER
-       if (mono_use_interpreter)
-               return mono_interp_create_method_pointer (method, error);
+       if (mono_use_interpreter && !jit_only) {
+               code = mono_interp_create_method_pointer (method, error);
+               if (code)
+                       return code;
+       }
 #endif
 
        if (mono_llvm_only)
@@ -1921,7 +1924,21 @@ mono_jit_compile_method (MonoMethod *method, MonoError *error)
 {
        gpointer code;
 
-       code = mono_jit_compile_method_with_opt (method, mono_get_optimizations_for_method (method, default_opt), error);
+       code = mono_jit_compile_method_with_opt (method, mono_get_optimizations_for_method (method, default_opt), FALSE, error);
+       return code;
+}
+
+/*
+ * mono_jit_compile_method_jit_only:
+ *
+ *   Compile METHOD using the JIT/AOT, even in interpreted mode.
+ */
+gpointer
+mono_jit_compile_method_jit_only (MonoMethod *method, MonoError *error)
+{
+       gpointer code;
+
+       code = mono_jit_compile_method_with_opt (method, mono_get_optimizations_for_method (method, default_opt), TRUE, error);
        return code;
 }
 
@@ -2408,7 +2425,7 @@ mono_jit_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObjec
                }
 
                if (callee) {
-                       compiled_method = mono_jit_compile_method_with_opt (callee, mono_get_optimizations_for_method (callee, default_opt), error);
+                       compiled_method = mono_jit_compile_method (callee, error);
                        if (!compiled_method) {
                                g_assert (!mono_error_ok (error));
                                return NULL;
@@ -3354,6 +3371,7 @@ mini_create_jit_domain_info (MonoDomain *domain)
        info->seq_points = g_hash_table_new_full (mono_aligned_addr_hash, NULL, NULL, mono_seq_point_info_free);
        info->arch_seq_points = g_hash_table_new (mono_aligned_addr_hash, NULL);
        info->jump_target_hash = g_hash_table_new (NULL, NULL);
+       mono_jit_code_hash_init (&info->interp_code_hash);
 
        domain->runtime_info = info;
 }
index c84e5290d463a693676b0e0f99bd1b5957283732..730c936de3c6a5103683ada79fe930cabdc9cb7c 100644 (file)
@@ -366,6 +366,8 @@ typedef struct
        gpointer llvm_module;
        /* Maps MonoMethod -> GSlist of addresses */
        GHashTable *llvm_jit_callees;
+       /* Maps MonoMethod -> RuntimeMethod */
+       MonoInternalHashTable interp_code_hash;
 } MonoJitDomainInfo;
 
 typedef struct {
@@ -2420,6 +2422,7 @@ gpointer  mono_resolve_patch_target         (MonoMethod *method, MonoDomain *dom
 gpointer  mono_jit_find_compiled_method_with_jit_info (MonoDomain *domain, MonoMethod *method, MonoJitInfo **ji);
 gpointer  mono_jit_find_compiled_method     (MonoDomain *domain, MonoMethod *method);
 gpointer  mono_jit_compile_method           (MonoMethod *method, MonoError *error);
+gpointer  mono_jit_compile_method_jit_only  (MonoMethod *method, MonoError *error);
 gpointer  mono_jit_compile_method_inner     (MonoMethod *method, MonoDomain *target_domain, int opt, MonoError *error);
 MonoLMF * mono_get_lmf                      (void);
 MonoLMF** mono_get_lmf_addr                 (void);
@@ -3098,6 +3101,7 @@ MonoMethod* mini_get_gsharedvt_in_sig_wrapper (MonoMethodSignature *sig);
 MonoMethod* mini_get_gsharedvt_out_sig_wrapper (MonoMethodSignature *sig);
 MonoMethodSignature* mini_get_gsharedvt_out_sig_wrapper_signature (gboolean has_this, gboolean has_ret, int param_count);
 gboolean mini_gsharedvt_runtime_invoke_supported (MonoMethodSignature *sig);
+MonoMethod* mini_get_interp_in_wrapper (MonoMethodSignature *sig);
 
 /* SIMD support */
 
diff --git a/mono/mini/mixed.cs b/mono/mini/mixed.cs
new file mode 100644 (file)
index 0000000..be88673
--- /dev/null
@@ -0,0 +1,182 @@
+using System;
+using System.Collections.Generic;
+using System.Reflection;
+using System.Runtime.InteropServices;
+using System.Runtime.CompilerServices;
+
+/*
+ * Regression tests for the mixed-mode execution.
+ * Run with --interp=jit=JitClass
+ */
+
+struct AStruct {
+       public int i;
+}
+
+struct GStruct<T> {
+       public int i;
+}
+
+class InterpClass
+{
+       [MethodImplAttribute (MethodImplOptions.NoInlining)]
+       public static void entry_void_0 () {
+       }
+
+       [MethodImplAttribute (MethodImplOptions.NoInlining)]
+       public static int entry_int_int (int i) {
+               return i + 1;
+       }
+
+       [MethodImplAttribute (MethodImplOptions.NoInlining)]
+       public int entry_int_this_int (int i) {
+               return i + 1;
+       }
+
+       [MethodImplAttribute (MethodImplOptions.NoInlining)]
+       public static string entry_string_string (string s1, string s2) {
+               return s1 + s2;
+       }
+
+       [MethodImplAttribute (MethodImplOptions.NoInlining)]
+       public static AStruct entry_struct_struct (AStruct l) {
+               return l;
+       }
+
+       [MethodImplAttribute (MethodImplOptions.NoInlining)]
+       public static List<string> entry_ginst_ginst (List<string> l) {
+               return l;
+       }
+
+       [MethodImplAttribute (MethodImplOptions.NoInlining)]
+       public static GStruct<string> entry_ginst_ginst_vtype (GStruct<string> l) {
+               return l;
+       }
+
+       [MethodImplAttribute (MethodImplOptions.NoInlining)]
+       public static void entry_void_byref_int (ref int i) {
+               i = i + 1;
+       }
+
+       [MethodImplAttribute (MethodImplOptions.NoInlining)]
+       public static int entry_8_int_args (int i1, int i2, int i3, int i4, int i5, int i6, int i7, int i8) {
+               return i1 + i2 + i3 + i4 + i5 + i6 + i7 + i8;
+       }
+
+       [MethodImplAttribute (MethodImplOptions.NoInlining)]
+       public static int entry_9_int_args (int i1, int i2, int i3, int i4, int i5, int i6, int i7, int i8, int i9) {
+               return i1 + i2 + i3 + i4 + i5 + i6 + i7 + i8 + i9;
+       }
+
+       [MethodImplAttribute (MethodImplOptions.NoInlining)]
+       public static IntPtr entry_intptr_intptr (IntPtr i) {
+               return i;
+       }
+
+}
+
+/* The methods in this class will always be JITted */
+class JitClass
+{
+       [MethodImplAttribute (MethodImplOptions.NoInlining)]
+       public static int entry () {
+               InterpClass.entry_void_0 ();
+               InterpClass.entry_void_0 ();
+               int res = InterpClass.entry_int_int (1);
+               if (res != 2)
+                       return 1;
+               var c = new InterpClass ();
+               res = c.entry_int_this_int (1);
+               if (res != 2)
+                       return 2;
+               var s = InterpClass.entry_string_string ("A", "B");
+               if (s != "AB")
+                       return 3;
+               var astruct = new AStruct () { i = 1 };
+               var astruct2 = InterpClass.entry_struct_struct (astruct);
+               if (astruct2.i != 1)
+                       return 4;
+               var l = new List<string> ();
+               var l2 = InterpClass.entry_ginst_ginst (l);
+               if (l != l2)
+                       return 5;
+               var gstruct = new GStruct<string> () { i = 1 };
+               var gstruct2 = InterpClass.entry_ginst_ginst_vtype (gstruct);
+               if (gstruct2.i != 1)
+                       return 6;
+               int val = 1;
+               InterpClass.entry_void_byref_int (ref val);
+               if (val != 2)
+                       return 7;
+               res = InterpClass.entry_8_int_args (1, 2, 3, 4, 5, 6, 7, 8);
+               if (res != 36)
+                       return 8;
+               res = InterpClass.entry_9_int_args (1, 2, 3, 4, 5, 6, 7, 8, 9);
+               if (res != 45)
+                       return 9;
+               var ptr = new IntPtr (32);
+               var ptr2 = InterpClass.entry_intptr_intptr (ptr);
+               if (ptr != ptr2)
+                       return 10;
+               return 0;
+       }
+
+       [MethodImplAttribute (MethodImplOptions.NoInlining)]
+       public static AStruct exit_vtype (AStruct s) {
+               return s;
+       }
+
+       [MethodImplAttribute (MethodImplOptions.NoInlining)]
+       public static List<string> exit_ginst (List<string> l) {
+               return l;
+       }
+
+       [MethodImplAttribute (MethodImplOptions.NoInlining)]
+       public static GStruct<string> exit_ginst_vtype (GStruct<string> l) {
+               return l;
+       }
+
+       [MethodImplAttribute (MethodImplOptions.NoInlining)]
+       public static void exit_byref (ref int i) {
+               i += 1;
+       }
+}
+
+#if __MOBILE__
+class MixedTests
+#else
+class Tests
+#endif
+{
+
+#if !__MOBILE__
+       public static int Main (string[] args) {
+               return TestDriver.RunTests (typeof (Tests), args);
+       }
+#endif
+
+       public static int test_0_entry () {
+               // This does an interp->jit transition
+               return JitClass.entry ();
+       }
+
+       public static int test_0_exit () {
+               var astruct = new AStruct () { i = 1};
+               var astruct2 = JitClass.exit_vtype (astruct);
+               if (astruct2.i != 1)
+                       return 1;
+               var ginst = new List<string> ();
+               var ginst2 = JitClass.exit_ginst (ginst);
+               if (ginst != ginst2)
+                       return 2;
+               var gstruct = new GStruct<string> () { i = 1 };
+               var gstruct2 = JitClass.exit_ginst_vtype (gstruct);
+               if (gstruct2.i != 1)
+                       return 3;
+               var anint = 1;
+               JitClass.exit_byref (ref anint);
+               if (anint != 2)
+                       return 4;
+               return 0;
+       }
+}
\ No newline at end of file
index db3c5b960901e0bb4ef9f73fad5f762bd514896c..aa61977cd8f0395c40dedd758282a9acd35e72f1 100644 (file)
@@ -1015,9 +1015,10 @@ mono_arch_get_enter_icall_trampoline (MonoTrampInfo **info)
        MonoJumpInfo *ji = NULL;
        GSList *unwind_ops = NULL;
        static int farg_regs[] = {AMD64_XMM0, AMD64_XMM1, AMD64_XMM2};
-       int i, framesize = 0, off_rbp, off_methodargs, off_targetaddr;
+       int buf_len, i, framesize = 0, off_rbp, off_methodargs, off_targetaddr;
 
-       start = code = (guint8 *) mono_global_codeman_reserve (256 + MONO_TRAMPOLINE_UNWINDINFO_SIZE(0));
+       buf_len = 512 + MONO_TRAMPOLINE_UNWINDINFO_SIZE(0);
+       start = code = (guint8 *) mono_global_codeman_reserve (buf_len);
 
        off_rbp = -framesize;
 
@@ -1056,9 +1057,8 @@ mono_arch_get_enter_icall_trampoline (MonoTrampInfo **info)
                amd64_dec_reg_size (code, AMD64_RAX, 1);
        }
 
-       for (i = 0; i < fregs_num; i++) {
+       for (i = 0; i < fregs_num; i++)
                x86_patch (label_fexits [i], code);
-       }
 
        /* load pointer to MethodArguments* into R11 */
        amd64_mov_reg_reg (code, AMD64_R11, AMD64_ARG_REG2, sizeof (mgreg_t));
@@ -1086,9 +1086,8 @@ mono_arch_get_enter_icall_trampoline (MonoTrampInfo **info)
                amd64_dec_reg_size (code, AMD64_RAX, 1);
        }
 
-       for (i = 0; i < gregs_num; i++) {
+       for (i = 0; i < gregs_num; i++)
                x86_patch (label_gexits [i], code);
-       }
 
        /* load target addr */
        amd64_mov_reg_membase (code, AMD64_R11, AMD64_RBP, off_targetaddr, sizeof (mgreg_t));
@@ -1108,8 +1107,6 @@ mono_arch_get_enter_icall_trampoline (MonoTrampInfo **info)
        label_is_float_ret = code;
        x86_branch8 (code, X86_CC_NZ, 0, FALSE);
 
-
-
        /* greg return */
        /* load MethodArguments */
        amd64_mov_reg_membase (code, AMD64_R11, AMD64_RBP, off_methodargs, sizeof (mgreg_t));
@@ -1125,8 +1122,6 @@ mono_arch_get_enter_icall_trampoline (MonoTrampInfo **info)
        label_leave_tramp [1] = code;
        x86_jump8 (code, 0);
 
-
-
        /* freg return */
        x86_patch (label_is_float_ret, code);
        /* load MethodArguments */
@@ -1147,6 +1142,8 @@ mono_arch_get_enter_icall_trampoline (MonoTrampInfo **info)
        amd64_pop_reg (code, AMD64_RBP);
        amd64_ret (code);
 
+       g_assert (code - start < buf_len);
+
        mono_arch_flush_icache (start, code - start);
        mono_profiler_code_buffer_new (start, code - start, MONO_PROFILER_CODE_BUFFER_EXCEPTION_HANDLING, NULL);
 
index 08a0c5d7da18ddd8d9e3d737e6e3ffc68ead74e2..58fddbc742bb2132b78e3af4468fdbb244b4d396 100755 (executable)
@@ -3,5 +3,6 @@
 export TESTCMD=`dirname "${BASH_SOURCE[0]}"`/run-step.sh
 
 ${TESTCMD} --label=interpreter-regression --timeout=10m make -C mono/mini richeck
+${TESTCMD} --label=mixedmode-regression --timeout=10m make -C mono/mini mixedcheck
 ${TESTCMD} --label=compile-runtime-tests --timeout=40m make -w -C mono/tests -j4 tests
 ${TESTCMD} --label=runtime-interp --timeout=160m make -w -C mono/tests -k testinterp V=1