#include <mono/metadata/metadata-internals.h>
#include <mono/metadata/marshal.h>
#include <mono/metadata/gc-internal.h>
-#include <mono/metadata/monitor.h>
#include <mono/metadata/threads-types.h>
#include <mono/metadata/mono-endian.h>
#include <mono/utils/mono-logger-internal.h>
#endif
/* Number of got entries shared between the JIT and LLVM GOT */
-#define N_COMMON_GOT_ENTRIES 4
+#define N_COMMON_GOT_ENTRIES 9
#define ALIGN_TO(val,align) ((((guint64)val) + ((align) - 1)) & ~((align) - 1))
#define ALIGN_PTR_TO(ptr,align) (gpointer)((((gssize)(ptr)) + (align - 1)) & (~(align - 1)))
guint32 image_table_len;
gboolean out_of_date;
gboolean plt_inited;
+ gboolean got_initializing;
guint8 *mem_begin;
guint8 *mem_end;
guint8 *jit_code_start;
compute_llvm_code_range (MonoAotModule *amodule, guint8 **code_start, guint8 **code_end);
static gboolean
-init_method (MonoAotModule *amodule, guint32 method_index, MonoMethod *method, MonoClass **klass);
-
-/*****************************************************/
-/* AOT RUNTIME */
-/*****************************************************/
+init_method (MonoAotModule *amodule, guint32 method_index, MonoMethod *method, MonoClass *init_class, MonoGenericContext *context);
static inline void
amodule_lock (MonoAotModule *amodule)
int atype = decode_value (p, &p);
ref->method = mono_gc_get_managed_allocator_by_type (atype, !!(mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS));
- if (!ref->method) {
- fprintf (stderr, "Error: No managed allocator, but we need one for AOT.\nAre you using non-standard GC options?\n");
- exit (1);
- }
+ if (!ref->method)
+ g_error ("Error: No managed allocator, but we need one for AOT.\nAre you using non-standard GC options?\n");
break;
}
case MONO_WRAPPER_WRITE_BARRIER:
msg = g_strdup_printf ("compiled with --aot=full");
usable = FALSE;
}
+ if (mono_llvm_only && !(info->flags & MONO_AOT_FILE_FLAG_LLVM_ONLY)) {
+ msg = g_strdup_printf ("not compiled with --aot=llvmonly");
+ usable = FALSE;
+ }
#ifdef TARGET_ARM
/* mono_arch_find_imt_method () requires this */
if ((info->flags & MONO_AOT_FILE_FLAG_WITH_LLVM) && !mono_use_llvm) {
}
}
+static void
+init_amodule_got (MonoAotModule *amodule)
+{
+ MonoJumpInfo ji;
+
+ /* These can't be initialized in load_aot_module () */
+ if (!amodule->shared_got [6] && !amodule->got_initializing) {
+ amodule->got_initializing = TRUE;
+
+ memset (&ji, 0, sizeof (ji));
+ ji.type = MONO_PATCH_INFO_INTERNAL_METHOD;
+ ji.data.name = "mono_aot_init_llvm_method";
+ amodule->got_initializing = TRUE;
+ amodule->shared_got [6] = mono_resolve_patch_target (NULL, mono_get_root_domain (), NULL, &ji, FALSE);
+ ji.data.name = "mono_aot_init_gshared_method_this";
+ amodule->shared_got [7] = mono_resolve_patch_target (NULL, mono_get_root_domain (), NULL, &ji, FALSE);
+ ji.data.name = "mono_aot_init_gshared_method_rgctx";
+ amodule->shared_got [8] = mono_resolve_patch_target (NULL, mono_get_root_domain (), NULL, &ji, FALSE);
+ init_gots (amodule);
+ }
+}
+
static void
load_aot_module (MonoAssembly *assembly, gpointer user_data)
{
}
if (!sofile && !globals) {
- if (mono_aot_only && assembly->image->tables [MONO_TABLE_METHOD].rows) {
- fprintf (stderr, "Failed to load AOT module '%s' in aot-only mode.\n", aot_name);
- exit (1);
- }
+ if (mono_aot_only && assembly->image->tables [MONO_TABLE_METHOD].rows)
+ g_error ("Failed to load AOT module '%s' in aot-only mode.\n", aot_name);
g_free (aot_name);
return;
}
if (!usable) {
if (mono_aot_only) {
- fprintf (stderr, "Failed to load AOT module '%s' while running in aot-only mode: %s.\n", aot_name, msg);
- exit (1);
+ g_error ("Failed to load AOT module '%s' while running in aot-only mode: %s.\n", aot_name, msg);
} else {
mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT: module %s is unusable: %s.\n", aot_name, msg);
}
return;
}
-#if defined (TARGET_ARM) && defined (TARGET_MACH)
- {
- MonoType t;
- int align = 0;
-
- memset (&t, 0, sizeof (MonoType));
- t.type = MONO_TYPE_R8;
- mono_type_size (&t, &align);
- align_double = align;
-
- memset (&t, 0, sizeof (MonoType));
- t.type = MONO_TYPE_I8;
- align_int64 = align;
- }
-#else
+ /* Sanity check */
align_double = MONO_ABI_ALIGNOF (double);
align_int64 = MONO_ABI_ALIGNOF (gint64);
-#endif
-
- /* Sanity check */
g_assert (info->double_align == align_double);
g_assert (info->long_align == align_int64);
g_assert (info->generic_tramp_num == MONO_TRAMPOLINE_NUM);
for (i = 0; i < amodule->info.nmethods; ++i) {
void *addr = NULL;
+ if (amodule->info.llvm_get_method) {
+ gpointer (*get_method) (int) = amodule->info.llvm_get_method;
+
+ addr = get_method (i);
+ }
+
/* method_addresses () contains a table of branches, since the ios linker can update those correctly */
if (!addr && amodule->info.method_addresses) {
addr = get_call_table_entry (amodule->info.method_addresses, i);
amodule->shared_got [3] = mono_resolve_patch_target (NULL, mono_get_root_domain (), NULL, &ji, FALSE);
}
+ amodule->shared_got [5] = amodule;
+ /* Can't initialize the other shared got slots yet, they are initialized in init_amodule_got () */
+
init_gots (amodule);
+ /*
+ * Register the plt region as a single trampoline so we can unwind from this code
+ */
+ mono_tramp_info_register (
+ mono_tramp_info_create (
+ NULL,
+ amodule->plt,
+ amodule->plt_end - amodule->plt,
+ NULL,
+ mono_unwind_get_cie_program ()
+ ),
+ NULL
+ );
+
/*
* Since we store methoddef and classdef tokens when referring to methods/classes in
* referenced assemblies, we depend on the exact versions of the referenced assemblies.
if (amodule->out_of_date) {
mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT: Module %s is unusable because a dependency is out-of-date.\n", assembly->image->name);
- if (mono_aot_only) {
- fprintf (stderr, "Failed to load AOT module '%s' while running in aot-only mode because a dependency cannot be found or it is out of date.\n", aot_name);
- exit (1);
- }
+ if (mono_aot_only)
+ g_error ("Failed to load AOT module '%s' while running in aot-only mode because a dependency cannot be found or it is out of date.\n", aot_name);
}
else
mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT: loaded AOT Module for %s.\n", assembly->image->name);
int version, fde_count;
gint32 *table;
+ if (amodule->info.llvm_get_method) {
+ gpointer (*get_method) (int) = amodule->info.llvm_get_method;
+
+ *code_start = get_method (-1);
+ *code_end = get_method (-2);
+
+ g_assert (*code_end > *code_start);
+ return;
+ }
+
g_assert (amodule->mono_eh_frame);
p = amodule->mono_eh_frame;
p += 4;
table = (gint32*)p;
- if (fde_count > 1) {
- /* mono_aot_personality () */
- g_assert (table [0] == -1);
- *code_start = amodule->methods [table [2]];
+ if (fde_count > 0) {
+ *code_start = amodule->methods [table [0]];
*code_end = (guint8*)amodule->methods [table [(fde_count - 1) * 2]] + table [fde_count * 2];
} else {
*code_start = NULL;
}
//printf ("F: %s\n", mono_method_full_name (method, TRUE));
-
+
jinfo = decode_exception_debug_info (amodule, domain, method, ex_info, addr, code, code_len);
g_assert ((guint8*)addr >= (guint8*)jinfo->code_start);
- g_assert ((guint8*)addr < (guint8*)jinfo->code_start + jinfo->code_size);
/* Add it to the normal JitInfo tables */
if (async) {
} else {
mono_jit_info_table_add (domain, jinfo);
}
+
+ if ((guint8*)addr >= (guint8*)jinfo->code_start + jinfo->code_size)
+ /* addr is in the padding between methods, see the adjustment of code_size in decode_exception_debug_info () */
+ return NULL;
return jinfo;
}
ji->data.offset = decode_value (p, &p);
break;
case MONO_PATCH_INFO_INTERRUPTION_REQUEST_FLAG:
- case MONO_PATCH_INFO_MONITOR_ENTER:
- case MONO_PATCH_INFO_MONITOR_ENTER_V4:
- case MONO_PATCH_INFO_MONITOR_EXIT:
case MONO_PATCH_INFO_GC_CARD_TABLE_ADDR:
case MONO_PATCH_INFO_GC_NURSERY_START:
case MONO_PATCH_INFO_JIT_TLS_ID:
case MONO_PATCH_INFO_CASTCLASS_CACHE:
ji->data.index = decode_value (p, &p);
break;
- case MONO_PATCH_INFO_RGCTX_FETCH: {
+ case MONO_PATCH_INFO_RGCTX_FETCH:
+ case MONO_PATCH_INFO_RGCTX_SLOT_INDEX: {
gboolean res;
MonoJumpInfoRgctxEntry *entry;
guint32 offset, val;
break;
}
case MONO_PATCH_INFO_SEQ_POINT_INFO:
+ case MONO_PATCH_INFO_AOT_MODULE:
break;
case MONO_PATCH_INFO_LLVM_IMT_TRAMPOLINE: {
MonoJumpInfoImtTramp *imt_tramp = mono_mempool_alloc0 (mp, sizeof (MonoJumpInfoImtTramp));
static gpointer
load_method (MonoDomain *domain, MonoAotModule *amodule, MonoImage *image, MonoMethod *method, guint32 token, int method_index)
{
- MonoClass *klass;
- gboolean from_plt = method == NULL;
MonoJitInfo *jinfo = NULL;
guint8 *code = NULL, *info;
gboolean res;
+ init_amodule_got (amodule);
+
if (mono_profiler_get_events () & MONO_PROFILE_ENTER_LEAVE) {
if (mono_aot_only)
/* The caller cannot handle this */
if (amodule->out_of_date)
return NULL;
+ if (amodule->info.llvm_get_method) {
+ /*
+ * Obtain the method address by calling a generated function in the LLVM module.
+ */
+ gpointer (*get_method) (int) = amodule->info.llvm_get_method;
+ code = get_method (method_index);
+ }
+
if (!code) {
if (amodule->methods [method_index] == GINT_TO_POINTER (-1)) {
if (mono_trace_is_traced (G_LOG_LEVEL_DEBUG, MONO_TRACE_AOT)) {
}
return NULL;
}
+ code = amodule->methods [method_index];
}
- code = amodule->methods [method_index];
-
info = &amodule->blob [mono_aot_get_offset (amodule->method_info_offsets, method_index)];
if (!amodule->methods_loaded) {
}
}
- res = init_method (amodule, method_index, method, &klass);
- if (!res)
- goto cleanup;
+ if (!(is_llvm_code (amodule, code) && (amodule->info.flags & MONO_AOT_FILE_FLAG_LLVM_ONLY))) {
+ res = init_method (amodule, method_index, method, NULL, NULL);
+ if (!res)
+ goto cleanup;
+ }
if (mono_trace_is_traced (G_LOG_LEVEL_DEBUG, MONO_TRACE_AOT)) {
char *full_name;
mono_profiler_method_end_jit (method, jinfo, MONO_PROFILE_OK);
}
- if (from_plt && klass && !klass->generic_container)
- mono_runtime_class_init (mono_class_vtable (domain, klass));
-
return code;
cleanup:
amodule_unlock (amodule);
if (!m) {
m = decode_resolve_method_ref_with_target (amodule, method, p, &p);
- if (m) {
+ /*
+ * Can't catche runtime invoke wrappers since it would break
+ * the check in decode_method_ref_with_target ().
+ */
+ if (m && m->wrapper_type != MONO_WRAPPER_RUNTIME_INVOKE) {
amodule_lock (amodule);
g_hash_table_insert (amodule->method_ref_to_method, orig_p, m);
amodule_unlock (amodule);
}
static gboolean
-init_method (MonoAotModule *amodule, guint32 method_index, MonoMethod *method, MonoClass **klass)
+init_method (MonoAotModule *amodule, guint32 method_index, MonoMethod *method, MonoClass *init_class, MonoGenericContext *context)
{
MonoDomain *domain = mono_domain_get ();
MonoMemPool *mp;
+ MonoClass *klass;
+ gboolean from_plt = method == NULL;
int pindex, n_patches;
guint8 *p;
MonoJitInfo *jinfo = NULL;
p = info;
if (method) {
- *klass = method->klass;
+ klass = method->klass;
decode_klass_ref (amodule, p, &p);
} else {
- *klass = decode_klass_ref (amodule, p, &p);
+ klass = decode_klass_ref (amodule, p, &p);
}
n_patches = decode_value (p, &p);
* finished executing (#23242).
*/
if (!got [got_slots [pindex]] || ji->type == MONO_PATCH_INFO_SFLDA) {
+ /* In llvm-only made, we might encounter shared methods */
+ if (mono_llvm_only && ji->type == MONO_PATCH_INFO_METHOD && mono_method_check_context_used (ji->data.method)) {
+ MonoError error;
+
+ g_assert (context);
+ ji->data.method = mono_class_inflate_generic_method_checked (ji->data.method, context, &error);
+ }
addr = mono_resolve_patch_target (method, domain, code, ji, TRUE);
if (ji->type == MONO_PATCH_INFO_METHOD_JUMP)
addr = mono_create_ftnptr (domain, addr);
if (mini_get_debug_options ()->load_aot_jit_info_eagerly)
jinfo = mono_aot_find_jit_info (domain, amodule->assembly->image, code);
+ if (init_class)
+ mono_runtime_class_init (mono_class_vtable (domain, init_class));
+ else if (from_plt && klass && !klass->generic_container)
+ mono_runtime_class_init (mono_class_vtable (domain, klass));
+
return TRUE;
cleanup:
return FALSE;
}
+void
+mono_aot_init_llvm_method (gpointer aot_module, guint32 method_index)
+{
+ gboolean res;
+
+ // FIXME: Handle failure
+ res = init_method ((MonoAotModule*)aot_module, method_index, NULL, NULL, NULL);
+ g_assert (res);
+}
+
+void
+mono_aot_init_gshared_method_this (gpointer aot_module, guint32 method_index, MonoObject *this)
+{
+ gboolean res;
+ MonoClass *klass;
+
+ // FIXME:
+ g_assert (this);
+
+ // FIXME: Handle failure
+ klass = this->vtable->klass;
+ res = init_method ((MonoAotModule*)aot_module, method_index, NULL, klass, klass->generic_class ? &klass->generic_class->context : NULL);
+ g_assert (res);
+}
+
+void
+mono_aot_init_gshared_method_rgctx (gpointer aot_module, guint32 method_index, MonoMethodRuntimeGenericContext *rgctx)
+{
+ gboolean res;
+ MonoGenericContext context = { NULL, NULL };
+ MonoClass *klass = rgctx->class_vtable->klass;
+
+ if (klass->generic_class)
+ context.class_inst = klass->generic_class->context.class_inst;
+ else if (klass->generic_container)
+ context.class_inst = klass->generic_container->context.class_inst;
+ context.method_inst = rgctx->method_inst;
+
+ res = init_method ((MonoAotModule*)aot_module, method_index, NULL, rgctx->class_vtable->klass, &context);
+ g_assert (res);
+}
+
/*
* mono_aot_get_method:
*
/* Same for CompareExchange<T> and Exchange<T> */
/* Same for Volatile.Read<T>/Write<T> */
if (method_index == 0xffffff && method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE && method->klass->image == mono_defaults.corlib &&
- ((!strcmp (method->klass->name_space, "System.Threading") && !strcmp (method->klass->name, "Interlocked") && (!strcmp (method->name, "CompareExchange") || !strcmp (method->name, "Exchange")) && MONO_TYPE_IS_REFERENCE (mono_method_signature (method)->params [1])) ||
- (!strcmp (method->klass->name_space, "System.Threading") && !strcmp (method->klass->name, "Volatile") && (!strcmp (method->name, "Read") && MONO_TYPE_IS_REFERENCE (mono_method_signature (method)->ret))) ||
- (!strcmp (method->klass->name_space, "System.Threading") && !strcmp (method->klass->name, "Volatile") && (!strcmp (method->name, "Write") && MONO_TYPE_IS_REFERENCE (mono_method_signature (method)->params [1]))))) {
+ ((!strcmp (method->klass->name_space, "System.Threading") && !strcmp (method->klass->name, "Interlocked") && (!strcmp (method->name, "CompareExchange") || !strcmp (method->name, "Exchange")) && MONO_TYPE_IS_REFERENCE (mini_type_get_underlying_type (NULL, mono_method_signature (method)->params [1]))) ||
+ (!strcmp (method->klass->name_space, "System.Threading") && !strcmp (method->klass->name, "Volatile") && (!strcmp (method->name, "Read") && MONO_TYPE_IS_REFERENCE (mini_type_get_underlying_type (NULL, mono_method_signature (method)->ret)))) ||
+ (!strcmp (method->klass->name_space, "System.Threading") && !strcmp (method->klass->name, "Volatile") && (!strcmp (method->name, "Write") && MONO_TYPE_IS_REFERENCE (mini_type_get_underlying_type (NULL, mono_method_signature (method)->params [1])))))) {
MonoError error;
MonoMethod *m;
MonoGenericContext ctx;
if (amodule->plt_inited)
return;
+ if (amodule->info.plt_size <= 1) {
+ amodule->plt_inited = TRUE;
+ return;
+ }
+
tramp = mono_create_specific_trampoline (amodule, MONO_TRAMPOLINE_AOT_PLT, mono_get_root_domain (), NULL);
/*
g_assert (res == 1);
target = mono_create_specific_trampoline (GUINT_TO_POINTER (slot), MONO_TRAMPOLINE_RGCTX_LAZY_FETCH, mono_get_root_domain (), NULL);
target = mono_create_ftnptr_malloc (target);
- } else if (!strcmp (ji->data.name, "specific_trampoline_monitor_enter")) {
- target = mono_create_specific_trampoline (NULL, MONO_TRAMPOLINE_MONITOR_ENTER, mono_get_root_domain (), NULL);
- target = mono_create_ftnptr_malloc (target);
- } else if (!strcmp (ji->data.name, "specific_trampoline_monitor_enter_v4")) {
- target = mono_create_specific_trampoline (NULL, MONO_TRAMPOLINE_MONITOR_ENTER_V4, mono_get_root_domain (), NULL);
- target = mono_create_ftnptr_malloc (target);
- } else if (!strcmp (ji->data.name, "specific_trampoline_monitor_exit")) {
- target = mono_create_specific_trampoline (NULL, MONO_TRAMPOLINE_MONITOR_EXIT, mono_get_root_domain (), NULL);
- target = mono_create_ftnptr_malloc (target);
} else if (!strcmp (ji->data.name, "mono_thread_get_and_clear_pending_exception")) {
target = mono_thread_get_and_clear_pending_exception;
} else if (!strcmp (ji->data.name, "debugger_agent_single_step_from_context")) {
return amodule;
}
+static void
+no_trampolines (void)
+{
+ g_assert_not_reached ();
+}
+
/*
* Return the trampoline identified by NAME from the mscorlib AOT file.
* On ppc64, this returns a function descriptor.
{
MonoAotModule *amodule = get_mscorlib_aot_module ();
+ /*
+ if (mono_llvm_only)
+ return no_trampolines;
+ */
+
return mono_create_ftnptr_malloc (load_function_full (amodule, name, out_tinfo));
}
gpointer
mono_aot_get_trampoline (const char *name)
{
- return mono_aot_get_trampoline_full (name, NULL);
+ MonoTrampInfo *out_tinfo;
+ gpointer code;
+
+ code = mono_aot_get_trampoline_full (name, &out_tinfo);
+ mono_tramp_info_register (out_tinfo, NULL);
+
+ return code;
+}
+
+static gpointer
+read_unwind_info (MonoAotModule *amodule, MonoTrampInfo *info, const char *symbol_name)
+{
+ gpointer symbol_addr;
+ guint32 uw_offset, uw_info_len;
+ guint8 *uw_info;
+
+ find_symbol (amodule->sofile, amodule->globals, symbol_name, &symbol_addr);
+
+ if (!symbol_addr)
+ return NULL;
+
+ uw_offset = *(guint32*)symbol_addr;
+ uw_info = amodule->unwind_info + uw_offset;
+ uw_info_len = decode_value (uw_info, &uw_info);
+
+ info->uw_info = uw_info;
+ info->uw_info_len = uw_info_len;
+
+ /* If successful return the address of the following data */
+ return (guint32*)symbol_addr + 1;
}
#ifdef MONOTOUCH
static TrampolinePage* trampoline_pages [MONO_AOT_TRAMP_NUM];
+static void
+read_page_trampoline_uwinfo (MonoTrampInfo *info, int tramp_type, gboolean is_generic)
+{
+ char symbol_name [128];
+
+ if (tramp_type == MONO_AOT_TRAMP_SPECIFIC)
+ sprintf (symbol_name, "specific_trampolines_page_%s_p", is_generic ? "gen" : "sp");
+ else if (tramp_type == MONO_AOT_TRAMP_STATIC_RGCTX)
+ sprintf (symbol_name, "rgctx_trampolines_page_%s_p", is_generic ? "gen" : "sp");
+ else if (tramp_type == MONO_AOT_TRAMP_IMT_THUNK)
+ sprintf (symbol_name, "imt_trampolines_page_%s_p", is_generic ? "gen" : "sp");
+ else if (tramp_type == MONO_AOT_TRAMP_GSHAREDVT_ARG)
+ sprintf (symbol_name, "gsharedvt_trampolines_page_%s_p", is_generic ? "gen" : "sp");
+ else
+ g_assert_not_reached ();
+
+ read_unwind_info (mono_defaults.corlib->aot_module, info, symbol_name);
+}
+
static unsigned char*
get_new_trampoline_from_page (int tramp_type)
{
count = 40;
page = NULL;
while (page == NULL && count-- > 0) {
+ MonoTrampInfo *gen_info, *sp_info;
+
addr = 0;
/* allocate two contiguous pages of memory: the first page will contain the data (like a local constant pool)
* while the second will contain the trampolines.
code = page->trampolines;
page->trampolines += specific_trampoline_size;
mono_aot_page_unlock ();
+
+ /* Register the generic part at the beggining of the trampoline page */
+ gen_info = mono_tramp_info_create (NULL, (guint8*)taddr, amodule->info.tramp_page_code_offsets [tramp_type], NULL, NULL);
+ read_page_trampoline_uwinfo (gen_info, tramp_type, TRUE);
+ mono_tramp_info_register (gen_info, NULL);
+ /*
+ * FIXME
+ * Registering each specific trampoline produces a lot of
+ * MonoJitInfo structures. Jump trampolines are also registered
+ * separately.
+ */
+ if (tramp_type != MONO_AOT_TRAMP_SPECIFIC) {
+ /* Register the rest of the page as a single trampoline */
+ sp_info = mono_tramp_info_create (NULL, code, page->trampolines_end - code, NULL, NULL);
+ read_page_trampoline_uwinfo (sp_info, tramp_type, FALSE);
+ mono_tramp_info_register (sp_info, NULL);
+ }
return code;
}
g_error ("Cannot allocate more trampoline pages: %d", ret);
}
/* Return a given kind of trampoline */
+/* FIXME set unwind info for these trampolines */
static gpointer
get_numerous_trampoline (MonoAotTrampoline tramp_type, int n_got_slots, MonoAotModule **out_amodule, guint32 *got_offset, guint32 *out_tramp_size)
{
gpointer code;
guint32 *ut, *ut_end, *entry;
int low, high, entry_index = 0;
+ gpointer symbol_addr;
+ MonoTrampInfo *tinfo;
if (method->is_inflated && !mono_method_is_generic_sharable_full (method, FALSE, FALSE, FALSE)) {
method_index = find_aot_method (method, &amodule);
g_assert (amodule);
}
+ if (amodule->info.llvm_get_unbox_tramp) {
+ gpointer (*get_tramp) (int) = amodule->info.llvm_get_unbox_tramp;
+ code = get_tramp (method_index);
+
+ if (code)
+ return code;
+ }
+
ut = amodule->unbox_trampolines;
ut_end = amodule->unbox_trampolines_end;
code = get_call_table_entry (amodule->unbox_trampoline_addresses, entry_index);
g_assert (code);
+ tinfo = mono_tramp_info_create (NULL, code, 0, NULL, NULL);
+
+ symbol_addr = read_unwind_info (amodule, tinfo, "unbox_trampoline_p");
+ if (!symbol_addr) {
+ mono_tramp_info_free (tinfo);
+ return FALSE;
+ }
+
+ tinfo->code_size = *(guint32*)symbol_addr;
+ mono_tramp_info_register (tinfo, NULL);
+
/* The caller expects an ftnptr */
return mono_create_ftnptr (mono_domain_get (), code);
}