+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
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;
#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:
*
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;
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;
*/
/* 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;
}
}
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;
}
/* 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");
}
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;
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;
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;
*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;
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;
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;
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)
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 ();
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)
{
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)
{
MonoMethod *vmethod;
gpointer addr;
MonoGenericContext *context = mono_method_get_context (method);
+ gboolean need_rgctx_tramp = FALSE;
mono_jit_stats.generic_virtual_invocations++;
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);
#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
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*
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) {
/* 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;
}
}
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;
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);
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))) {
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];
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
}
}
+ 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)
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) {
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);
} 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);
}
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;
}
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;
#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 {
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;
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;
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;
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;
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:
*