2009-04-13 Zoltan Varga <vargaz@gmail.com>
authorZoltan Varga <vargaz@gmail.com>
Sun, 12 Apr 2009 22:11:36 +0000 (22:11 -0000)
committerZoltan Varga <vargaz@gmail.com>
Sun, 12 Apr 2009 22:11:36 +0000 (22:11 -0000)
* mini-trampolines.c (mono_create_static_rgctx_trampoline): New trampoline
creation function which returns a trampoline which sets the rgctx
argument.
(mono_magic_trampoline): Use the rgctx trampoline instead of an rgctx
wrapper if possible.
(mono_delegate_trampoline): Ditto.

* mini.c (mono_jit_runtime_invoke): Ditto.

* tramp-amd64.c: Add an implemention of static rgctx trampolines for AMD64.

* aot-compiler.c aot-runtime.c: Add support for static rgctx trampolines.

* mini.h (MONO_AOT_FILE_VERSION): Bump this.

svn path=/trunk/mono/; revision=131555

mono/mini/ChangeLog
mono/mini/aot-compiler.c
mono/mini/aot-runtime.c
mono/mini/jit-icalls.c
mono/mini/mini-amd64.h
mono/mini/mini-trampolines.c
mono/mini/mini.c
mono/mini/mini.h
mono/mini/tramp-amd64.c

index a9fcd6492efa1043a3794075801129164eee6883..cac0923f5c5c3e2b42ae6d05be1cca8abf2f691d 100644 (file)
@@ -1,3 +1,20 @@
+2009-04-13  Zoltan Varga  <vargaz@gmail.com>
+
+       * mini-trampolines.c (mono_create_static_rgctx_trampoline): New trampoline
+       creation function which returns a trampoline which sets the rgctx
+       argument.
+       (mono_magic_trampoline): Use the rgctx trampoline instead of an rgctx
+       wrapper if possible.
+       (mono_delegate_trampoline): Ditto.
+
+       * mini.c (mono_jit_runtime_invoke): Ditto.
+
+       * tramp-amd64.c: Add an implemention of static rgctx trampolines for AMD64.
+       
+       * aot-compiler.c aot-runtime.c: Add support for static rgctx trampolines.
+
+       * mini.h (MONO_AOT_FILE_VERSION): Bump this.
+       
 2009-04-12  Zoltan Varga  <vargaz@gmail.com>
 
        * mini-ia64.c (mono_arch_lowering_pass): Use NULLIFY_INS instead of
index ff80d34c218871a622e9b5e25c11d1b9fb4f8527..1ca4c46af31db8fe3af0046e2774a306d8e9c809 100644 (file)
@@ -132,13 +132,16 @@ typedef struct MonoAotCompile {
        GPtrArray *globals;
        GList *method_order;
        guint32 *plt_got_info_offsets;
-       /* Number of trampolines emitted into the AOT file */
-       guint32 num_aot_trampolines;
        guint32 got_offset, plt_offset, plt_got_offset_base;
        /* Number of GOT entries reserved for trampolines */
        guint32 num_trampoline_got_entries;
-       guint32 trampoline_got_offset_base;
+       guint32 num_specific_trampolines;
        guint32 specific_trampoline_size;
+       guint32 specific_trampoline_got_offset_base;
+       /* Same for static rgctx trampolines */
+       guint32 num_static_rgctx_trampolines;
+       guint32 static_rgctx_trampoline_size;
+       guint32 static_rgctx_trampoline_got_offset_base;
        MonoAotOptions aot_opts;
        guint32 nmethods;
        guint32 opts;
@@ -658,6 +661,38 @@ arch_emit_unbox_trampoline (MonoAotCompile *acfg, MonoMethod *method, MonoGeneri
 #endif
 }
 
+/*
+ * arch_emit_static_rgctx_trampoline:
+ *
+ *   Emit code for a static rgctx trampoline. OFFSET is the offset of the first of
+ * two GOT slots which contain the rgctx argument, and the method to jump to.
+ * TRAMP_SIZE is set to the size of the emitted trampoline.
+ * These kinds of trampolines cannot be enumerated statically, since there could
+ * be one trampoline per method instantiation, so we emit the same code for all
+ * trampolines, and parameterize them using two GOT slots.
+ */
+static void
+arch_emit_static_rgctx_trampoline (MonoAotCompile *acfg, int offset, int *tramp_size)
+{
+#if defined(__x86_64__)
+       /* This should be exactly 13 bytes long */
+       *tramp_size = 13;
+
+       /* mov <OFFSET>(%rip), %r10 */
+       emit_byte (acfg, '\x4d');
+       emit_byte (acfg, '\x8b');
+       emit_byte (acfg, '\x15');
+       emit_symbol_diff (acfg, "got", ".", (offset * sizeof (gpointer)) - 4);
+
+       /* jmp *<offset>(%rip) */
+       emit_byte (acfg, '\xff');
+       emit_byte (acfg, '\x25');
+       emit_symbol_diff (acfg, "got", ".", ((offset + 1) * sizeof (gpointer)) - 4);
+#else
+       g_assert_not_reached ();
+#endif
+}      
+
 /*
  * arch_get_cie_program:
  *
@@ -1490,23 +1525,6 @@ add_wrappers (MonoAotCompile *acfg)
                        add_method (acfg, mono_marshal_get_synchronized_wrapper (method));
        }
 
-#if 0
-       /* static rgctx wrappers */
-       /* FIXME: Each wrapper belongs to a given instantiation of a generic method */
-       for (i = 0; i < acfg->image->tables [MONO_TABLE_METHOD].rows; ++i) {
-               token = MONO_TOKEN_METHOD_DEF | (i + 1);
-               method = mono_get_method (acfg->image, token, NULL);
-
-               if (((method->flags & METHOD_ATTRIBUTE_STATIC) ||
-                        (method->is_inflated && mono_method_get_context (method)->method_inst)) &&
-                       mono_class_generic_sharing_enabled (method->klass) &&
-                       mono_method_is_generic_sharable_impl (method, FALSE)) {
-                       m = mono_marshal_get_static_rgctx_invoke (method);
-                       add_method (acfg, m);
-               }
-       }
-#endif
-
        /* pinvoke wrappers */
        for (i = 0; i < acfg->image->tables [MONO_TABLE_METHOD].rows; ++i) {
                MonoMethod *method;
@@ -2472,9 +2490,9 @@ static void
 emit_trampolines (MonoAotCompile *acfg)
 {
        char symbol [256];
-       int i, offset;
+       int i;
 #ifdef MONO_ARCH_HAVE_FULL_AOT_TRAMPOLINES
-       int tramp_type;
+       int tramp_type, tramp_got_offset;
        guint32 code_size;
        MonoJumpInfo *ji;
        guint8 *code;
@@ -2560,25 +2578,50 @@ emit_trampolines (MonoAotCompile *acfg)
                 */
 
                /* Reserve some entries at the end of the GOT for our use */
-               acfg->num_trampoline_got_entries = acfg->num_aot_trampolines * 2;
+               acfg->num_trampoline_got_entries = (acfg->num_specific_trampolines * 2) + (acfg->num_static_rgctx_trampolines * 2);
 
-               sprintf (symbol, "trampolines");
+               sprintf (symbol, "specific_trampolines");
 
                emit_section_change (acfg, ".text", 0);
                emit_global (acfg, symbol, TRUE);
                emit_alignment (acfg, 16);
                emit_label (acfg, symbol);
 
-               for (i = 0; i < acfg->num_aot_trampolines; ++i) {
-                       int tramp_size = 0;
+               tramp_got_offset = acfg->got_offset;
+
+               acfg->specific_trampoline_got_offset_base = tramp_got_offset;
 
-                       offset = acfg->got_offset + (i * 2);
+               for (i = 0; i < acfg->num_specific_trampolines; ++i) {
+                       int tramp_size = 0;
 
-                       arch_emit_specific_trampoline (acfg, offset, &tramp_size);
+                       arch_emit_specific_trampoline (acfg, tramp_got_offset, &tramp_size);
                        if (!acfg->specific_trampoline_size) {
                                g_assert (tramp_size);
                                acfg->specific_trampoline_size = tramp_size;
                        }
+
+                       tramp_got_offset += 2;
+               }
+
+               sprintf (symbol, "static_rgctx_trampolines");
+
+               emit_section_change (acfg, ".text", 0);
+               emit_global (acfg, symbol, TRUE);
+               emit_alignment (acfg, 16);
+               emit_label (acfg, symbol);
+
+               acfg->static_rgctx_trampoline_got_offset_base = tramp_got_offset;
+
+               for (i = 0; i < acfg->num_static_rgctx_trampolines; ++i) {
+                       int tramp_size = 0;
+
+                       arch_emit_static_rgctx_trampoline (acfg, tramp_got_offset, &tramp_size);
+                       if (!acfg->static_rgctx_trampoline_size) {
+                               g_assert (tramp_size);
+                               acfg->static_rgctx_trampoline_size = tramp_size;
+                       }
+
+                       tramp_got_offset += 2;
                }
        }
 
@@ -2608,8 +2651,6 @@ emit_trampolines (MonoAotCompile *acfg)
                arch_emit_unbox_trampoline (acfg, cfg->orig_method, cfg->generic_sharing_context, call_target);
        }
 
-       acfg->trampoline_got_offset_base = acfg->got_offset;
-
        acfg->got_offset += acfg->num_trampoline_got_entries;
 }
 
@@ -3983,11 +4024,14 @@ emit_file_info (MonoAotCompile *acfg)
 
        /* The data emitted here must match MonoAotFileInfo in aot-runtime.c. */
        emit_int32 (acfg, acfg->plt_got_offset_base);
-       emit_int32 (acfg, acfg->trampoline_got_offset_base);
-       emit_int32 (acfg, acfg->num_aot_trampolines);
        emit_int32 (acfg, (int)(acfg->got_offset * sizeof (gpointer)));
        emit_int32 (acfg, acfg->plt_offset);
+       emit_int32 (acfg, acfg->num_specific_trampolines);
        emit_int32 (acfg, acfg->specific_trampoline_size);
+       emit_int32 (acfg, acfg->specific_trampoline_got_offset_base);
+       emit_int32 (acfg, acfg->num_static_rgctx_trampolines);
+       emit_int32 (acfg, acfg->static_rgctx_trampoline_size);
+       emit_int32 (acfg, acfg->static_rgctx_trampoline_got_offset_base);
        emit_pointer (acfg, "got");
 }
 
@@ -4346,7 +4390,10 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
        if (!acfg->aot_opts.nodebug)
                acfg->dwarf = mono_dwarf_writer_create (acfg->w, NULL);
 
-       acfg->num_aot_trampolines = acfg->aot_opts.full_aot ? 10240 : 0;
+       acfg->num_specific_trampolines = acfg->aot_opts.full_aot ? 10240 : 0;
+#ifdef MONO_ARCH_HAVE_STATIC_RGCTX_TRAMPOLINE
+       acfg->num_static_rgctx_trampolines = acfg->aot_opts.full_aot ? 1024 : 0;
+#endif
 
        acfg->method_index = 1;
 
index ac0e82ce105ad4336affc629280ffde60b73b4ed..84b4d5f3ad0a5950416677619a3971fcca2b2b96 100644 (file)
@@ -113,9 +113,15 @@ typedef struct MonoAotModule {
        guint32 *extra_method_table;
        guint32 *extra_method_info_offsets;
        guint8 *extra_method_info;
-       guint8 *trampolines;
-       guint32 num_trampolines, trampoline_got_offset_base, trampoline_index;
-       guint32 specific_trampoline_size;
+
+       guint8 *specific_trampolines;
+       guint32 num_specific_trampolines, specific_trampoline_got_offset_base;
+       guint32 specific_trampoline_index, specific_trampoline_size;
+
+       guint8 *static_rgctx_trampolines;
+       guint32 num_static_rgctx_trampolines, static_rgctx_trampoline_got_offset_base;
+       guint32 static_rgctx_trampoline_index, static_rgctx_trampoline_size;
+
        gpointer *globals;
        MonoDl *sofile;
 } MonoAotModule;
@@ -124,11 +130,14 @@ typedef struct MonoAotModule {
 typedef struct MonoAotFileInfo
 {
        guint32 plt_got_offset_base;
-       guint32 trampoline_got_offset_base;
-       guint32 num_trampolines;
        guint32 got_size;
        guint32 plt_size;
+       guint32 num_specific_trampolines;
        guint32 specific_trampoline_size;
+       guint32 specific_trampoline_got_offset_base;
+       guint32 num_static_rgctx_trampolines;
+       guint32 static_rgctx_trampoline_size;
+       guint32 static_rgctx_trampoline_got_offset_base;
        gpointer *got;
 } MonoAotFileInfo;
 
@@ -556,6 +565,14 @@ decode_method_ref (MonoAotModule *module, guint32 *token, MonoMethod **method, g
                        *method = mono_marshal_get_static_rgctx_invoke (m);
                        break;
                }
+               case MONO_WRAPPER_SYNCHRONIZED: {
+                       MonoMethod *m = decode_method_ref_2 (module, p, &p);
+
+                       if (!m)
+                               return NULL;
+                       *method = mono_marshal_get_synchronized_wrapper (m);
+                       break;
+               }
                case MONO_WRAPPER_UNKNOWN: {
                        MonoMethodDesc *desc;
                        MonoMethod *orig_method;
@@ -992,11 +1009,14 @@ load_aot_module (MonoAssembly *assembly, gpointer user_data)
        amodule->aot_name = aot_name;
        amodule->assembly = assembly;
        amodule->plt_got_offset_base = file_info->plt_got_offset_base;
-       amodule->num_trampolines = file_info->num_trampolines;
-       amodule->trampoline_got_offset_base = file_info->trampoline_got_offset_base;
+       amodule->num_specific_trampolines = file_info->num_specific_trampolines;
+       amodule->specific_trampoline_got_offset_base = file_info->specific_trampoline_got_offset_base;
+       amodule->specific_trampoline_size = file_info->specific_trampoline_size;
        amodule->got_size = file_info->got_size;
        amodule->plt_size = file_info->plt_size;
-       amodule->specific_trampoline_size = file_info->specific_trampoline_size;
+       amodule->num_static_rgctx_trampolines = file_info->num_static_rgctx_trampolines;
+       amodule->static_rgctx_trampoline_got_offset_base = file_info->static_rgctx_trampoline_got_offset_base;
+       amodule->static_rgctx_trampoline_size = file_info->static_rgctx_trampoline_size;
        amodule->got = file_info->got;
        amodule->got [0] = assembly->image;
        amodule->globals = globals;
@@ -1064,7 +1084,8 @@ load_aot_module (MonoAssembly *assembly, gpointer user_data)
        find_symbol (sofile, globals, "extra_method_info_offsets", (gpointer *)&amodule->extra_method_info_offsets);
        find_symbol (sofile, globals, "got_info", (gpointer*)&amodule->got_info);
        find_symbol (sofile, globals, "got_info_offsets", (gpointer*)&amodule->got_info_offsets);
-       find_symbol (sofile, globals, "trampolines", (gpointer*)&amodule->trampolines);
+       find_symbol (sofile, globals, "specific_trampolines", (gpointer*)&amodule->specific_trampolines);
+       find_symbol (sofile, globals, "static_rgctx_trampolines", (gpointer*)&amodule->static_rgctx_trampolines);
        find_symbol (sofile, globals, "mem_end", (gpointer*)&amodule->mem_end);
 
        amodule->mem_begin = amodule->code;
@@ -2227,6 +2248,18 @@ find_extra_method_in_amodule (MonoAotModule *amodule, MonoMethod *method)
                                index = value;
                                break;
                        }
+
+                       /* Special case: wrappers of shared generic methods */
+                       if (m && method->wrapper_type && m->wrapper_type == m->wrapper_type &&
+                               method->wrapper_type == MONO_WRAPPER_SYNCHRONIZED) {
+                               MonoMethod *w1 = mono_marshal_method_from_wrapper (method);
+                               MonoMethod *w2 = mono_marshal_method_from_wrapper (m);
+
+                               if (w1->is_inflated && ((MonoMethodInflated *)w1)->declaring == w2) {
+                                       index = value;
+                                       break;
+                               }
+                       }
                }
 
                if (next != 0)
@@ -2759,10 +2792,10 @@ mono_aot_create_specific_trampoline (MonoImage *image, gpointer arg1, MonoTrampo
        amodule = image->aot_module;
        g_assert (amodule);
 
-       if (amodule->trampoline_index == amodule->num_trampolines)
-               g_error ("Ran out of trampolines in '%s' (%d)\n", image->name, amodule->num_trampolines);
+       if (amodule->specific_trampoline_index == amodule->num_specific_trampolines)
+               g_error ("Ran out of trampolines in '%s' (%d)\n", image->name, amodule->num_specific_trampolines);
 
-       index = amodule->trampoline_index ++;
+       index = amodule->specific_trampoline_index ++;
 
        mono_aot_unlock ();
 
@@ -2777,18 +2810,52 @@ mono_aot_create_specific_trampoline (MonoImage *image, gpointer arg1, MonoTrampo
        tramp = generic_trampolines [tramp_type];
        g_assert (tramp);
 
-       amodule->got [amodule->trampoline_got_offset_base + (index *2)] = tramp;
-       amodule->got [amodule->trampoline_got_offset_base + (index *2) + 1] = arg1;
+       amodule->got [amodule->specific_trampoline_got_offset_base + (index *2)] = tramp;
+       amodule->got [amodule->specific_trampoline_got_offset_base + (index *2) + 1] = arg1;
 
        tramp_size = amodule->specific_trampoline_size;
 
-       code = amodule->trampolines + (index * tramp_size);
+       code = amodule->specific_trampolines + (index * tramp_size);
        if (code_len)
                *code_len = tramp_size;
 
        return code;
 }
 
+gpointer
+mono_aot_get_static_rgctx_trampoline (gpointer ctx, gpointer addr)
+{
+       MonoAotModule *amodule;
+       int index, tramp_size;
+       guint8 *code;
+       MonoImage *image;
+
+       /* Currently, we keep all trampolines in the mscorlib AOT image */
+       image = mono_defaults.corlib;
+       g_assert (image);
+
+       mono_aot_lock ();
+
+       amodule = image->aot_module;
+       g_assert (amodule);
+
+       if (amodule->static_rgctx_trampoline_index == amodule->num_static_rgctx_trampolines)
+               g_error ("Ran out of trampolines in '%s' (%d)\n", image->name, amodule->num_static_rgctx_trampolines);
+
+       index = amodule->static_rgctx_trampoline_index ++;
+
+       mono_aot_unlock ();
+
+       amodule->got [amodule->static_rgctx_trampoline_got_offset_base + (index *2)] = ctx;
+       amodule->got [amodule->static_rgctx_trampoline_got_offset_base + (index *2) + 1] = addr; 
+
+       tramp_size = amodule->static_rgctx_trampoline_size;
+
+       code = amodule->static_rgctx_trampolines + (index * tramp_size);
+
+       return code;
+}
+
 gpointer
 mono_aot_get_unbox_trampoline (MonoMethod *method)
 {
@@ -2903,6 +2970,13 @@ mono_aot_create_specific_trampoline (MonoImage *image, gpointer arg1, MonoTrampo
        return NULL;
 }
 
+gpointer
+mono_aot_get_static_rgctx_trampoline (gpointer ctx, gpointer addr)
+{
+       g_assert_not_reached ();
+       return NULL;
+}
+
 gpointer
 mono_aot_get_named_code (const char *name)
 {
index 2da0148cb6f52468de56193674b37eabf73257be..9e893edcc5e82241f3afa5f1ff194e9e51d70fa2 100644 (file)
@@ -902,6 +902,7 @@ mono_helper_compile_generic_method (MonoObject *obj, MonoMethod *method, gpointe
        MonoMethod *vmethod;
        gpointer addr;
        MonoGenericContext *context = mono_method_get_context (method);
+       gboolean need_rgctx_tramp = FALSE;
 
        mono_jit_stats.generic_virtual_invocations++;
 
@@ -911,10 +912,21 @@ mono_helper_compile_generic_method (MonoObject *obj, MonoMethod *method, gpointe
        g_assert (!vmethod->klass->generic_container);
        g_assert (!vmethod->klass->generic_class || !vmethod->klass->generic_class->context.class_inst->is_open);
        g_assert (!context->method_inst || !context->method_inst->is_open);
-       if (mono_method_needs_static_rgctx_invoke (vmethod, FALSE))
+
+       if (mono_method_needs_static_rgctx_invoke (vmethod, FALSE)) {
+#ifdef MONO_ARCH_HAVE_STATIC_RGCTX_TRAMPOLINE
+               need_rgctx_tramp = TRUE;
+#else
                vmethod = mono_marshal_get_static_rgctx_invoke (vmethod);
+#endif
+       }
        addr = mono_compile_method (vmethod);
 
+#ifdef MONO_ARCH_HAVE_STATIC_RGCTX_TRAMPOLINE
+       if (need_rgctx_tramp)
+               addr = mono_create_static_rgctx_trampoline (vmethod, addr);
+#endif 
+
        /* Since this is a virtual call, have to unbox vtypes */
        if (obj->vtable->klass->valuetype)
                *this_arg = mono_object_unbox (obj);
index e9d334198ed5db1e3f8325e68b7e70ad8911ec51..f34f2927a4d82d5a540df9b513817212edd87290 100644 (file)
@@ -325,6 +325,7 @@ typedef struct {
 #if !defined(PLATFORM_WIN32) && !defined(HAVE_MOVING_COLLECTOR)
 #define MONO_ARCH_MONITOR_OBJECT_REG AMD64_RDI
 #endif
+#define MONO_ARCH_HAVE_STATIC_RGCTX_TRAMPOLINE 1
 
 #define MONO_ARCH_AOT_SUPPORTED 1
 
index 5fbc536f7b74c7cd3d60aa594bfb0b1bd08835ce..3ef426d26bf163aeb20b6a7dbab17e65a9fd775a 100644 (file)
@@ -39,6 +39,55 @@ get_unbox_trampoline (MonoGenericSharingContext *gsctx, MonoMethod *m, gpointer
                return mono_arch_get_unbox_trampoline (gsctx, m, addr);
 }
 
+#ifdef MONO_ARCH_HAVE_STATIC_RGCTX_TRAMPOLINE
+/*
+ * mono_create_static_rgctx_trampoline:
+ *
+ *   Return a static rgctx trampoline for M which branches to ADDR which should
+ * point to the compiled code of M.
+ *
+ *   Static rgctx trampolines are used when a shared generic method which doesn't
+ * have a this argument is called indirectly, ie. from code which can't pass in
+ * the rgctx argument. The trampoline sets the rgctx argument and jumps to the
+ * methods code. These trampolines are similar to the unbox trampolines, they
+ * perform the same task as the static rgctx wrappers, but they are smaller/faster,
+ * and can be made to work with full AOT.
+ */
+gpointer
+mono_create_static_rgctx_trampoline (MonoMethod *m, gpointer addr)
+{
+       gpointer ctx;
+       gpointer res;
+       MonoDomain *domain;
+
+       if (mini_method_get_context (m)->method_inst)
+               ctx = mono_method_lookup_rgctx (mono_class_vtable (mono_domain_get (), m->klass), mini_method_get_context (m)->method_inst);
+       else
+               ctx = mono_class_vtable (mono_domain_get (), m->klass);
+
+       if (mono_aot_only)
+               return mono_aot_get_static_rgctx_trampoline (ctx, addr);
+
+       domain = mono_domain_get ();
+
+       mono_domain_lock (domain);
+       res = g_hash_table_lookup (domain_jit_info (domain)->static_rgctx_trampoline_hash,
+                                                          m);
+       mono_domain_unlock (domain);
+       if (res)
+               return res;
+
+       res = mono_arch_get_static_rgctx_trampoline (m, ctx, addr);
+
+       mono_domain_lock (domain);
+       /* Duplicates inserted while we didn't hold the lock are OK */
+       g_hash_table_insert (domain_jit_info (domain)->static_rgctx_trampoline_hash, m, res);
+       mono_domain_unlock (domain);
+
+       return res;
+}
+#endif
+
 #ifdef MONO_ARCH_HAVE_IMT
 
 static gpointer*
@@ -129,6 +178,7 @@ mono_magic_trampoline (gssize *regs, guint8 *code, MonoMethod *m, guint8* tramp)
        MonoMethod *generic_virtual = NULL;
        int context_used;
        gboolean proxy = FALSE;
+       gboolean need_rgctx_tramp = FALSE;
 
 #if MONO_ARCH_COMMON_VTABLE_TRAMPOLINE
        if (m == MONO_FAKE_VTABLE_METHOD) {
@@ -203,7 +253,11 @@ mono_magic_trampoline (gssize *regs, guint8 *code, MonoMethod *m, guint8* tramp)
                                /* Generic virtual method */
                                generic_virtual = m;
                                m = impl_method;
+#ifdef MONO_ARCH_HAVE_STATIC_RGCTX_TRAMPOLINE
+                               need_rgctx_tramp = TRUE;
+#else
                                m = mono_marshal_get_static_rgctx_invoke (m);
+#endif
                        } else {
                                m = impl_method;
                        }
@@ -234,8 +288,12 @@ mono_magic_trampoline (gssize *regs, guint8 *code, MonoMethod *m, guint8* tramp)
                }
 
                m = mono_class_inflate_generic_method (declaring, &context);
+#ifdef MONO_ARCH_HAVE_STATIC_RGCTX_TRAMPOLINE
+               need_rgctx_tramp = TRUE;
+#else
                /* FIXME: only do this if the method is sharable */
                m = mono_marshal_get_static_rgctx_invoke (m);
+#endif
        } else if ((context_used = mono_method_check_context_used (m))) {
                MonoClass *klass = NULL;
                MonoMethod *actual_method = NULL;
@@ -346,6 +404,11 @@ mono_magic_trampoline (gssize *regs, guint8 *code, MonoMethod *m, guint8* tramp)
 
        mono_debugger_trampoline_compiled (m, addr);
 
+#ifdef MONO_ARCH_HAVE_STATIC_RGCTX_TRAMPOLINE
+       if (need_rgctx_tramp)
+               addr = mono_create_static_rgctx_trampoline (m, addr);
+#endif
+
        if (generic_virtual) {
                int displacement;
                MonoVTable *vt = mono_arch_get_vcall_slot (code, (gpointer*)regs, &displacement);
@@ -396,7 +459,6 @@ mono_magic_trampoline (gssize *regs, guint8 *code, MonoMethod *m, guint8* tramp)
        if (vtable_slot) {
                if (m->klass->valuetype)
                        addr = get_unbox_trampoline (mono_get_generic_context_from_code (code), m, addr);
-
                g_assert (*vtable_slot);
 
                if (!proxy && (mono_aot_is_got_entry (code, (guint8*)vtable_slot) || mono_domain_owns_vtable_slot (mono_domain_get (), vtable_slot))) {
@@ -638,6 +700,7 @@ mono_delegate_trampoline (gssize *regs, guint8 *code, gpointer *tramp_data, guin
        MonoMethod *m;
        MonoMethod *method = NULL;
        gboolean multicast, callvirt;
+       gboolean need_rgctx_tramp = FALSE;
        MonoMethod *invoke = tramp_data [0];
        guint8 *impl_this = tramp_data [1];
        guint8 *impl_nothis = tramp_data [2];
@@ -674,8 +737,13 @@ mono_delegate_trampoline (gssize *regs, guint8 *code, gpointer *tramp_data, guin
        if (method && method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED)
                method = mono_marshal_get_synchronized_wrapper (method);
 
-       if (method && mono_method_needs_static_rgctx_invoke (method, FALSE))
+       if (method && mono_method_needs_static_rgctx_invoke (method, FALSE)) {
+#ifdef MONO_ARCH_HAVE_STATIC_RGCTX_TRAMPOLINE
+               need_rgctx_tramp = TRUE;
+#else
                method = mono_marshal_get_static_rgctx_invoke (method);
+#endif
+       }
 
        /* 
         * If the called address is a trampoline, replace it with the compiled method so
@@ -693,6 +761,9 @@ mono_delegate_trampoline (gssize *regs, guint8 *code, gpointer *tramp_data, guin
                }
        }
 
+       if (need_rgctx_tramp)
+               delegate->method_ptr = mono_create_static_rgctx_trampoline (method, delegate->method_ptr);
+
        multicast = ((MonoMulticastDelegate*)delegate)->prev != NULL;
        if (!multicast && !callvirt) {
                if (method && (method->flags & METHOD_ATTRIBUTE_STATIC) && mono_method_signature (method)->param_count == mono_method_signature (invoke)->param_count + 1)
index 14dc2e57b88a0267a0e1a6eedd8ae52cff182f79..898c557d3f29498c1712a31eefb1d696402e01e7 100644 (file)
@@ -4335,16 +4335,22 @@ mono_jit_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObjec
        MonoObject *(*runtime_invoke) (MonoObject *this, void **params, MonoObject **exc, void* compiled_method);
        void* compiled_method;
        MonoVTable *vtable;
+       gboolean need_rgctx_tramp = FALSE;
 
        if (obj == NULL && !(method->flags & METHOD_ATTRIBUTE_STATIC) && !method->string_ctor && (method->wrapper_type == 0)) {
                g_warning ("Ignoring invocation of an instance method on a NULL instance.\n");
                return NULL;
        }
 
-       if (mono_method_needs_static_rgctx_invoke (method, FALSE))
+       to_compile = method;
+
+       if (mono_method_needs_static_rgctx_invoke (method, FALSE)) {
+#ifdef MONO_ARCH_HAVE_STATIC_RGCTX_TRAMPOLINE
+               need_rgctx_tramp = TRUE;
+#else
                to_compile = mono_marshal_get_static_rgctx_invoke (method);
-       else
-               to_compile = method;
+#endif
+       }
 
        /* Special case parameterless ctors to speed up Activator.CreateInstance () */
        if (method->flags & (METHOD_ATTRIBUTE_SPECIAL_NAME | METHOD_ATTRIBUTE_RT_SPECIAL_NAME) && !strcmp (method->name, ".ctor") && mono_method_signature (method)->param_count == 0 && !method->klass->valuetype) {
@@ -4361,8 +4367,9 @@ mono_jit_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObjec
                runtime_invoke = mono_jit_compile_method (invoke);
        }
 
-       /* We need this here becuase mono_marshal_get_runtime_invoke can be place 
-        * the helper method in System.Object and not the target class
+       /*
+        * We need this here because mono_marshal_get_runtime_invoke can place 
+        * the helper method in System.Object and not the target class.
         */
        vtable = mono_class_vtable (mono_domain_get (), method->klass);
        g_assert (vtable);
@@ -4378,6 +4385,11 @@ mono_jit_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObjec
        } else {
                compiled_method = mono_jit_compile_method (to_compile);
        }
+#ifdef MONO_ARCH_HAVE_STATIC_RGCTX_TRAMPOLINE
+       if (need_rgctx_tramp)
+               compiled_method = mono_create_static_rgctx_trampoline (to_compile, compiled_method);
+#endif
+
        return runtime_invoke (obj, params, exc, compiled_method);
 }
 
@@ -4596,6 +4608,7 @@ mini_create_jit_domain_info (MonoDomain *domain)
        info->jump_trampoline_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
        info->jit_trampoline_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
        info->delegate_trampoline_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
+       info->static_rgctx_trampoline_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
 
        domain->runtime_info = info;
 }
@@ -4637,6 +4650,7 @@ mini_free_jit_domain_info (MonoDomain *domain)
        g_hash_table_destroy (info->jump_trampoline_hash);
        g_hash_table_destroy (info->jit_trampoline_hash);
        g_hash_table_destroy (info->delegate_trampoline_hash);
+       g_hash_table_destroy (info->static_rgctx_trampoline_hash);
 
        g_free (domain->runtime_info);
        domain->runtime_info = NULL;
index 63c68b1295478667ced516b77a2cd2c9c884191d..8fdb385bc35deb9e6ce99b77ca4ef32810486ca0 100644 (file)
@@ -89,7 +89,7 @@ typedef gint64 mgreg_t;
 #define MONO_FAKE_VTABLE_METHOD ((MonoMethod*)GINT_TO_POINTER(-2))
 
 /* Version number of the AOT file format */
-#define MONO_AOT_FILE_VERSION "49"
+#define MONO_AOT_FILE_VERSION "50"
 
 /* Constants used to encode different types of methods in AOT */
 enum {
@@ -118,6 +118,7 @@ typedef struct
        GHashTable *jump_trampoline_hash;
        GHashTable *jit_trampoline_hash;
        GHashTable *delegate_trampoline_hash;
+       GHashTable *static_rgctx_trampoline_hash;
        /* maps MonoMethod -> MonoJitDynamicMethodInfo */
        GHashTable *dynamic_code_hash;
        GHashTable *method_code_hash;
@@ -1335,6 +1336,7 @@ gpointer mono_aot_create_specific_trampoline   (MonoImage *image, gpointer arg1,
 gpointer mono_aot_get_named_code            (const char *name) MONO_INTERNAL;
 gpointer mono_aot_get_unbox_trampoline      (MonoMethod *method) MONO_INTERNAL;
 gpointer mono_aot_get_lazy_fetch_trampoline (guint32 slot) MONO_INTERNAL;
+gpointer mono_aot_get_static_rgctx_trampoline (gpointer ctx, gpointer addr) MONO_INTERNAL;
 guint8*  mono_aot_get_unwind_info           (MonoJitInfo *ji, guint32 *unwind_info_len) MONO_INTERNAL;
 guint32  mono_aot_method_hash               (MonoMethod *method) MONO_INTERNAL;
 char*    mono_aot_wrapper_name              (MonoMethod *method) MONO_INTERNAL;
@@ -1383,6 +1385,7 @@ gpointer          mono_create_delegate_trampoline (MonoClass *klass) MONO_INTERN
 gpointer          mono_create_rgctx_lazy_fetch_trampoline (guint32 offset) MONO_INTERNAL;
 gpointer          mono_create_monitor_enter_trampoline (void) MONO_INTERNAL;
 gpointer          mono_create_monitor_exit_trampoline (void) MONO_INTERNAL;
+gpointer          mono_create_static_rgctx_trampoline (MonoMethod *m, gpointer addr) MONO_INTERNAL;
 MonoVTable*       mono_find_class_init_trampoline_by_addr (gconstpointer addr) MONO_INTERNAL;
 MonoClass*        mono_find_delegate_trampoline_by_addr (gconstpointer addr) MONO_INTERNAL;
 guint32           mono_find_rgctx_lazy_fetch_trampoline_by_addr (gconstpointer addr) MONO_INTERNAL;
@@ -1532,6 +1535,7 @@ void     mono_arch_create_vars                  (MonoCompile *cfg) MONO_INTERNAL
 void     mono_arch_save_unwind_info             (MonoCompile *cfg) MONO_INTERNAL;
 void     mono_arch_register_lowlevel_calls      (void) MONO_INTERNAL;
 gpointer mono_arch_get_unbox_trampoline         (MonoGenericSharingContext *gsctx, MonoMethod *m, gpointer addr) MONO_INTERNAL;
+gpointer mono_arch_get_static_rgctx_trampoline  (MonoMethod *m, MonoMethodRuntimeGenericContext *mrgctx, gpointer addr) MONO_INTERNAL;
 void     mono_arch_patch_callsite               (guint8 *method_start, guint8 *code, guint8 *addr) MONO_INTERNAL;
 void     mono_arch_patch_plt_entry              (guint8 *code, guint8 *addr) MONO_INTERNAL;
 void     mono_arch_nullify_class_init_trampoline(guint8 *code, gssize *regs) MONO_INTERNAL;
index 58c333761dd9e34456b0b5b4b6202d0f5614bde1..8d773e4cd56550f65a3b8b17f7f511e8c5edd1c7 100644 (file)
@@ -62,6 +62,36 @@ mono_arch_get_unbox_trampoline (MonoGenericSharingContext *gsctx, MonoMethod *m,
        return start;
 }
 
+/*
+ * mono_arch_get_static_rgctx_trampoline:
+ *
+ *   Create a trampoline which sets RGCTX_REG to MRGCTX, then jumps to ADDR.
+ */
+gpointer
+mono_arch_get_static_rgctx_trampoline (MonoMethod *m, MonoMethodRuntimeGenericContext *mrgctx, gpointer addr)
+{
+       guint8 *code, *start;
+       int buf_len;
+
+       MonoDomain *domain = mono_domain_get ();
+
+#ifdef MONO_ARCH_NOMAP32BIT
+       buf_len = 32;
+#else
+       buf_len = 16;
+#endif
+
+       start = code = mono_domain_code_reserve (domain, buf_len);
+
+       amd64_mov_reg_imm (code, MONO_ARCH_RGCTX_REG, mrgctx);
+       amd64_jump_code (code, addr);
+       g_assert ((code - start) < buf_len);
+
+       mono_arch_flush_icache (start, code - start);
+
+       return start;
+}
+
 /*
  * mono_arch_patch_callsite:
  *