#define ENABLE_AOT_CACHE
#endif
+/* Number of got entries shared between the JIT and LLVM GOT */
+#define N_COMMON_GOT_ENTRIES 4
+
#define ALIGN_TO(val,align) ((((guint64)val) + ((align) - 1)) & ~((align) - 1))
#define ALIGN_PTR_TO(ptr,align) (gpointer)((((gssize)(ptr)) + (align - 1)) & (~(align - 1)))
#define ROUND_DOWN(VALUE,SIZE) ((VALUE) & ~((SIZE) - 1))
/* Pointer to the Global Offset Table */
gpointer *got;
gpointer *llvm_got;
+ gpointer shared_got [N_COMMON_GOT_ENTRIES];
GHashTable *name_cache;
GHashTable *extra_methods;
/* Maps methods to their code */
gboolean plt_inited;
guint8 *mem_begin;
guint8 *mem_end;
- /* Points to either the start of JIT compiler or LLVM compiled code */
- guint8 *code;
guint8 *jit_code_start;
guint8 *jit_code_end;
guint8 *llvm_code_start;
guint8 *plt;
guint8 *plt_end;
guint8 *blob;
- gint32 *code_offsets;
- gpointer *method_addresses;
- /* This contains <offset, index> pairs sorted by offset */
- /* This is needed because LLVM emitted methods can be in any order */
- gint32 *sorted_code_offsets;
- gint32 sorted_code_offsets_len;
+ /* Maps method indexes to their code */
+ gpointer *methods;
+ /* Sorted array of method addresses */
+ gpointer *sorted_methods;
+ /* Method indexes for each method in sorted_methods */
+ int *sorted_method_indexes;
+ /* The length of the two tables above */
+ int sorted_methods_len;
guint32 *method_info_offsets;
guint32 *ex_info_offsets;
guint32 *class_info_offsets;
guint32 *unbox_trampolines_end;
guint32 *unbox_trampoline_addresses;
guint8 *unwind_info;
- guint8 *thumb_end;
/* Points to the mono EH data created by LLVM */
guint8 *mono_eh_frame;
#define mono_aot_page_unlock() mono_mutex_unlock (&aot_page_mutex)
static mono_mutex_t aot_page_mutex;
+static MonoAotModule *mscorlib_aot_module;
+
static void
init_plt (MonoAotModule *info);
static void
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 */
/*****************************************************/
int type = decode_value (p, &p);
int num = decode_value (p, &p);
gboolean has_container = decode_value (p, &p);
- MonoTypeEnum gshared_constraint = 0;
+ MonoType *gshared_constraint = NULL;
char *par_name = NULL;
if (has_container) {
container = class_def->generic_container;
}
} else {
- gshared_constraint = decode_value (p, &p);
- if (gshared_constraint) {
- int len = decode_value (p, &p);
+ gboolean has_gshared_constraint = decode_value (p, &p);
+ if (has_gshared_constraint) {
+ int len;
+
+ gshared_constraint = decode_type (module, p, &p);
+ if (!gshared_constraint)
+ return NULL;
+
+ len = decode_value (p, &p);
if (len) {
par_name = mono_image_alloc (module->assembly->image, len + 1);
memcpy (par_name, p, len);
t->type = type;
if (container) {
t->data.generic_param = mono_generic_container_get_param (container, num);
- g_assert (gshared_constraint == 0);
+ g_assert (gshared_constraint == NULL);
} else {
/* Anonymous */
MonoGenericParam *par = (MonoGenericParam*)mono_image_alloc0 (module->assembly->image, sizeof (MonoGenericParamFull));
if (!m)
return FALSE;
mono_class_init (m->klass);
- ref->method = mono_marshal_get_remoting_invoke_with_check (m);
+ if (mono_aot_only)
+ ref->method = m;
+ else
+ ref->method = mono_marshal_get_remoting_invoke_with_check (m);
break;
}
case MONO_WRAPPER_PROXY_ISINST: {
case MONO_WRAPPER_ALLOC: {
int atype = decode_value (p, &p);
- ref->method = mono_gc_get_managed_allocator_by_type (atype);
+ 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);
#endif
}
+static void
+init_gots (MonoAotModule *amodule)
+{
+ int i;
+
+ if (amodule->got) {
+ for (i = 0; i < N_COMMON_GOT_ENTRIES; ++i)
+ amodule->got [i] = amodule->shared_got [i];
+ }
+ if (amodule->llvm_got) {
+ for (i = 0; i < N_COMMON_GOT_ENTRIES; ++i)
+ amodule->llvm_got [i] = amodule->shared_got [i];
+ }
+}
+
static void
load_aot_module (MonoAssembly *assembly, gpointer user_data)
{
if (image_is_dynamic (assembly->image) || assembly->ref_only)
return;
- if (mono_security_cas_enabled ())
- return;
-
mono_aot_lock ();
if (static_aot_modules)
info = g_hash_table_lookup (static_aot_modules, assembly->aname.name);
memcpy (&amodule->info, info, sizeof (*info));
- amodule->got = amodule->info.got;
+ amodule->got = amodule->info.jit_got;
amodule->llvm_got = amodule->info.llvm_got;
amodule->globals = globals;
amodule->sofile = sofile;
}
}
- amodule->method_addresses = info->method_addresses;
- amodule->code = info->methods;
-#ifdef TARGET_ARM
- /* Mask out thumb interop bit */
- amodule->code = (void*)((mgreg_t)amodule->code & ~1);
-#endif
amodule->jit_code_start = info->jit_code_start;
amodule->jit_code_end = info->jit_code_end;
amodule->method_info_offsets = info->method_info_offsets;
amodule->unbox_trampolines_end = info->unbox_trampolines_end;
amodule->unbox_trampoline_addresses = info->unbox_trampoline_addresses;
amodule->unwind_info = info->unwind_info;
+ amodule->mem_begin = amodule->jit_code_start;
amodule->mem_end = info->mem_end;
- amodule->mem_begin = amodule->code;
amodule->plt = info->plt;
amodule->plt_end = info->plt_end;
amodule->mono_eh_frame = info->mono_eh_frame;
amodule->trampolines [MONO_AOT_TRAMP_STATIC_RGCTX] = info->static_rgctx_trampolines;
amodule->trampolines [MONO_AOT_TRAMP_IMT_THUNK] = info->imt_thunks;
amodule->trampolines [MONO_AOT_TRAMP_GSHAREDVT_ARG] = info->gsharedvt_arg_trampolines;
- amodule->thumb_end = info->thumb_end;
- /* Compute code_offsets from the method addresses */
- amodule->code_offsets = g_malloc0 (amodule->info.nmethods * sizeof (gint32));
+ if (!strcmp (assembly->aname.name, "mscorlib"))
+ mscorlib_aot_module = amodule;
+
+ /* Compute method addresses */
+ amodule->methods = g_malloc0 (amodule->info.nmethods * sizeof (gpointer));
for (i = 0; i < amodule->info.nmethods; ++i) {
- /* method_addresses () contains a table of branches, since the ios linker can update those correctly */
- void *addr;
+ void *addr = NULL;
- addr = get_call_table_entry (amodule->method_addresses, i);
- g_assert (addr);
- if (addr == amodule->method_addresses)
- amodule->code_offsets [i] = 0xffffffff;
+ /* 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);
+ g_assert (addr);
+ if (addr == amodule->info.method_addresses)
+ addr = NULL;
+ }
+ if (addr == NULL)
+ amodule->methods [i] = GINT_TO_POINTER (-1);
else
- amodule->code_offsets [i] = (char*)addr - (char*)amodule->code;
+ amodule->methods [i] = addr;
}
if (make_unreadable) {
int err, len;
addr = amodule->mem_begin;
+ g_assert (addr);
len = amodule->mem_end - amodule->mem_begin;
/* Round down in both directions to avoid modifying data which is not ours */
mono_aot_lock ();
- aot_code_low_addr = MIN (aot_code_low_addr, (gsize)amodule->jit_code_start);
- aot_code_high_addr = MAX (aot_code_high_addr, (gsize)amodule->jit_code_end);
+ if (amodule->jit_code_start) {
+ aot_code_low_addr = MIN (aot_code_low_addr, (gsize)amodule->jit_code_start);
+ aot_code_high_addr = MAX (aot_code_high_addr, (gsize)amodule->jit_code_end);
+ }
if (amodule->llvm_code_start) {
aot_code_low_addr = MIN (aot_code_low_addr, (gsize)amodule->llvm_code_start);
aot_code_high_addr = MAX (aot_code_high_addr, (gsize)amodule->llvm_code_end);
g_hash_table_insert (aot_modules, assembly, amodule);
mono_aot_unlock ();
- mono_jit_info_add_aot_module (assembly->image, amodule->jit_code_start, amodule->jit_code_end);
+ if (amodule->jit_code_start)
+ mono_jit_info_add_aot_module (assembly->image, amodule->jit_code_start, amodule->jit_code_end);
if (amodule->llvm_code_start)
mono_jit_info_add_aot_module (assembly->image, amodule->llvm_code_start, amodule->llvm_code_end);
assembly->image->aot_module = amodule;
- amodule->got [0] = assembly->image;
+ amodule->shared_got [0] = assembly->image;
if (mono_aot_only) {
char *code;
/* The second got slot contains the mscorlib got addr */
MonoAotModule *mscorlib_amodule = mono_defaults.corlib->aot_module;
- amodule->got [1] = mscorlib_amodule->got;
+ amodule->shared_got [1] = mscorlib_amodule->got;
} else {
- amodule->got [1] = amodule->got;
+ amodule->shared_got [1] = amodule->got;
}
}
memset (&ji, 0, sizeof (ji));
ji.type = MONO_PATCH_INFO_GC_CARD_TABLE_ADDR;
- amodule->got [2] = mono_resolve_patch_target (NULL, mono_get_root_domain (), NULL, &ji, FALSE);
+ amodule->shared_got [2] = mono_resolve_patch_target (NULL, mono_get_root_domain (), NULL, &ji, FALSE);
memset (&ji, 0, sizeof (ji));
ji.type = MONO_PATCH_INFO_GC_NURSERY_START;
- amodule->got [3] = mono_resolve_patch_target (NULL, mono_get_root_domain (), NULL, &ji, FALSE);
+ amodule->shared_got [3] = mono_resolve_patch_target (NULL, mono_get_root_domain (), NULL, &ji, FALSE);
}
- if (amodule->llvm_got) {
- amodule->llvm_got [0] = amodule->got [0];
- amodule->llvm_got [1] = amodule->got [1];
- amodule->llvm_got [2] = amodule->got [2];
- amodule->llvm_got [3] = amodule->got [3];
- }
+ init_gots (amodule);
/*
* Since we store methoddef and classdef tokens when referring to methods/classes in
if (fde_count > 1) {
/* mono_aot_personality () */
g_assert (table [0] == -1);
- *code_start = amodule->code + amodule->code_offsets [table [2]];
- *code_end = amodule->code + amodule->code_offsets [table [(fde_count - 1) * 2]] + table [fde_count * 2];
+ *code_start = amodule->methods [table [2]];
+ *code_end = (guint8*)amodule->methods [table [(fde_count - 1) * 2]] + table [fde_count * 2];
} else {
*code_start = NULL;
*code_end = NULL;
}
}
+static gboolean
+is_llvm_code (MonoAotModule *amodule, guint8 *code)
+{
+ if ((guint8*)code >= amodule->llvm_code_start && (guint8*)code < amodule->llvm_code_end)
+ return TRUE;
+ else
+ return FALSE;
+}
+
+static gboolean
+is_thumb_code (MonoAotModule *amodule, guint8 *code)
+{
+ if (is_llvm_code (amodule, code) && (amodule->info.flags & MONO_AOT_FILE_FLAG_LLVM_THUMB))
+ return TRUE;
+ else
+ return FALSE;
+}
+
/*
- * decode_mono_eh_frame:
+ * decode_llvm_mono_eh_frame:
*
* Decode the EH information emitted by our modified LLVM compiler and construct a
* MonoJitInfo structure from it.
GSList **nesting,
int *this_reg, int *this_offset)
{
- guint8 *p;
+ guint8 *p, *code1, *code2;
guint8 *fde, *cie, *code_start, *code_end;
int version, fde_count;
gint32 *table;
- int i, j, pos, left, right, offset, offset1, offset2, code_len;
+ int i, pos, left, right, code_len;
MonoJitExceptionInfo *ei;
guint32 fde_len, ei_len, nested_len, nindex;
gpointer *type_info;
cie = p + ((fde_count + 1) * 8);
/* Binary search in the table to find the entry for code */
- offset = code - amodule->code;
left = 0;
right = fde_count;
while (TRUE) {
/* The table contains method index/fde offset pairs */
g_assert (table [(pos * 2)] != -1);
- offset1 = amodule->code_offsets [table [(pos * 2)]];
+ code1 = amodule->methods [table [(pos * 2)]];
if (pos + 1 == fde_count) {
- offset2 = amodule->llvm_code_end - amodule->llvm_code_start;
+ code2 = amodule->llvm_code_end;
} else {
g_assert (table [(pos + 1) * 2] != -1);
- offset2 = amodule->code_offsets [table [(pos + 1) * 2]];
+ code2 = amodule->methods [table [(pos + 1) * 2]];
}
- if (offset < offset1)
+ if (code < code1)
right = pos;
- else if (offset >= offset2)
+ else if (code >= code2)
left = pos + 1;
else
break;
}
- code_start = amodule->code + amodule->code_offsets [table [(pos * 2)]];
+ code_start = amodule->methods [table [(pos * 2)]];
if (pos + 1 == fde_count) {
/* The +1 entry in the table contains the length of the last method */
int len = table [(pos + 1) * 2];
code_end = code_start + len;
} else {
- code_end = amodule->code + amodule->code_offsets [table [(pos + 1) * 2]];
+ code_end = amodule->methods [table [(pos + 1) * 2]];
}
code_len = code_end - code_start;
g_assert (code >= code_start && code < code_end);
- if (amodule->thumb_end && (guint8*)code_start < amodule->thumb_end)
+ if (is_thumb_code (amodule, code_start))
/* Clear thumb flag */
code_start = (guint8*)(((mgreg_t)code_start) & ~1);
gint32 cindex1 = read32 (type_info [i]);
GSList *l;
- for (l = nesting [cindex1]; l; l = l->next) {
- gint32 nesting_cindex = GPOINTER_TO_INT (l->data);
-
- for (j = 0; j < ei_len; ++j) {
- gint32 cindex2 = read32 (type_info [j]);
-
- if (cindex2 == nesting_cindex)
- nested_len ++;
- }
- }
+ for (l = nesting [cindex1]; l; l = l->next)
+ nested_len ++;
}
/*
jei->handler_start = ei [i].handler_start;
jei->clause_index = clause_index;
- /* Make sure we transition to thumb when a handler starts */
- if (amodule->thumb_end && (guint8*)jei->handler_start < amodule->thumb_end)
+ if (is_thumb_code (amodule, jei->try_start)) {
+ jei->try_start = (void*)((mgreg_t)jei->try_start & ~1);
+ jei->try_end = (void*)((mgreg_t)jei->try_end & ~1);
+ /* Make sure we transition to thumb when a handler starts */
jei->handler_start = (void*)((mgreg_t)jei->handler_start + 1);
+ }
}
/* See exception_cb () in mini-llvm.c as to why this is needed */
for (l = nesting [cindex1]; l; l = l->next) {
gint32 nesting_cindex = GPOINTER_TO_INT (l->data);
+ MonoJitExceptionInfo *nesting_ei;
+ MonoJitExceptionInfo *nesting_clause = &clauses [nesting_cindex];
- for (j = 0; j < ei_len; ++j) {
- gint32 cindex2 = read32 (type_info [j]);
+ nesting_ei = &jinfo->clauses [nindex];
+ nindex ++;
- if (cindex2 == nesting_cindex) {
- memcpy (&jinfo->clauses [nindex], &jinfo->clauses [j], sizeof (MonoJitExceptionInfo));
- jinfo->clauses [nindex].try_start = jinfo->clauses [i].try_start;
- jinfo->clauses [nindex].try_end = jinfo->clauses [i].try_end;
- jinfo->clauses [nindex].handler_start = jinfo->clauses [i].handler_start;
- jinfo->clauses [nindex].exvar_offset = jinfo->clauses [i].exvar_offset;
- nindex ++;
- }
- }
+ memcpy (nesting_ei, &jinfo->clauses [i], sizeof (MonoJitExceptionInfo));
+ nesting_ei->flags = nesting_clause->flags;
+ nesting_ei->data.catch_class = nesting_clause->data.catch_class;
+ nesting_ei->clause_index = nesting_cindex;
}
}
g_assert (nindex == ei_len + nested_len);
ei->flags = decode_value (p, &p);
+#ifdef MONO_CONTEXT_SET_LLVM_EXC_REG
+ /* Not used for catch clauses */
+ if (ei->flags != MONO_EXCEPTION_CLAUSE_NONE)
+ ei->exvar_offset = decode_value (p, &p);
+#else
ei->exvar_offset = decode_value (p, &p);
+#endif
if (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER || ei->flags == MONO_EXCEPTION_CLAUSE_FINALLY)
ei->data.filter = code + decode_value (p, &p);
gi->generic_sharing_context = g_new0 (MonoGenericSharingContext, 1);
if (decode_value (p, &p)) {
/* gsharedvt */
- int i, n;
MonoGenericSharingContext *gsctx = gi->generic_sharing_context;
- n = decode_value (p, &p);
- if (n) {
- gsctx->var_is_vt = alloc0_jit_info_data (domain, sizeof (gboolean) * n, async);
- for (i = 0; i < n; ++i)
- gsctx->var_is_vt [i] = decode_value (p, &p);
- }
- n = decode_value (p, &p);
- if (n) {
- gsctx->mvar_is_vt = alloc0_jit_info_data (domain, sizeof (gboolean) * n, async);
- for (i = 0; i < n; ++i)
- gsctx->mvar_is_vt [i] = decode_value (p, &p);
- }
+ gsctx->is_gsharedvt = TRUE;
}
}
if (method && has_seq_points) {
MonoSeqPointInfo *seq_points;
- p += seq_point_info_read (&seq_points, p, FALSE);
+ p += mono_seq_point_info_read (&seq_points, p, FALSE);
mono_domain_lock (domain);
g_hash_table_insert (domain_jit_info (domain)->seq_points, method, seq_points);
return p;
}
-static G_GNUC_UNUSED int
-compare_ints (const void *a, const void *b)
-{
- return *(gint32*)a - *(gint32*)b;
-}
-
static void
-msort_code_offsets_internal (gint32 *array, int lo, int hi, gint32 *scratch)
+msort_method_addresses_internal (gpointer *array, int *indexes, int lo, int hi, gpointer *scratch, int *scratch_indexes)
{
int mid = (lo + hi) / 2;
int i, t_lo, t_hi;
if (hi - lo < 32) {
for (i = lo; i < hi; ++i)
- if (array [(i * 2)] > array [(i * 2) + 2])
+ if (array [i] > array [i + 1])
break;
if (i == hi)
/* Already sorted */
return;
}
- msort_code_offsets_internal (array, lo, mid, scratch);
- msort_code_offsets_internal (array, mid + 1, hi, scratch);
+ msort_method_addresses_internal (array, indexes, lo, mid, scratch, scratch_indexes);
+ msort_method_addresses_internal (array, indexes, mid + 1, hi, scratch, scratch_indexes);
- if (array [mid * 2] < array [(mid + 1) * 2])
+ if (array [mid] < array [mid + 1])
return;
/* Merge */
t_lo = lo;
t_hi = mid + 1;
for (i = lo; i <= hi; i ++) {
- if (t_lo <= mid && ((t_hi > hi) || array [t_lo * 2] < array [t_hi * 2])) {
- scratch [(i * 2)] = array [t_lo * 2];
- scratch [(i * 2) + 1] = array [(t_lo *2) + 1];
+ if (t_lo <= mid && ((t_hi > hi) || array [t_lo] < array [t_hi])) {
+ scratch [i] = array [t_lo];
+ scratch_indexes [i] = indexes [t_lo];
t_lo ++;
} else {
- scratch [(i * 2)] = array [t_hi * 2];
- scratch [(i * 2) + 1] = array [(t_hi *2) + 1];
+ scratch [i] = array [t_hi];
+ scratch_indexes [i] = indexes [t_hi];
t_hi ++;
}
}
for (i = lo; i <= hi; ++i) {
- array [(i * 2)] = scratch [i * 2];
- array [(i * 2) + 1] = scratch [(i * 2) + 1];
+ array [i] = scratch [i];
+ indexes [i] = scratch_indexes [i];
}
}
static void
-msort_code_offsets (gint32 *array, int len)
+msort_method_addresses (gpointer *array, int *indexes, int len)
{
- gint32 *scratch;
+ gpointer *scratch;
+ int *scratch_indexes;
- scratch = g_new (gint32, len * 2);
- msort_code_offsets_internal (array, 0, len - 1, scratch);
+ scratch = g_new (gpointer, len);
+ scratch_indexes = g_new (int, len);
+ msort_method_addresses_internal (array, indexes, 0, len - 1, scratch, scratch_indexes);
g_free (scratch);
+ g_free (scratch_indexes);
}
/*
MonoJitInfo *
mono_aot_find_jit_info (MonoDomain *domain, MonoImage *image, gpointer addr)
{
- int pos, left, right, offset, offset1, offset2, code_len;
+ int pos, left, right, code_len;
int method_index, table_len;
guint32 token;
MonoAotModule *amodule = image->aot_module;
guint8 *code, *ex_info, *p;
guint32 *table;
int nmethods;
- gint32 *code_offsets;
- int offsets_len, i;
+ gpointer *methods;
+ guint8 *code1, *code2;
+ int methods_len, i;
gboolean async;
if (!amodule)
async = mono_thread_info_is_async_context ();
- offset = (guint8*)addr - amodule->code;
-
- /* Compute a sorted table mapping code offsets to method indexes. */
- if (!amodule->sorted_code_offsets) {
+ /* Compute a sorted table mapping code to method indexes. */
+ if (!amodule->sorted_methods) {
// FIXME: async
- code_offsets = g_new0 (gint32, nmethods * 2);
- offsets_len = 0;
+ gpointer *methods = g_new0 (gpointer, nmethods);
+ int *method_indexes = g_new0 (int, nmethods);
+ int methods_len = 0;
+
for (i = 0; i < nmethods; ++i) {
/* Skip the -1 entries to speed up sorting */
- if (amodule->code_offsets [i] == 0xffffffff)
+ if (amodule->methods [i] == GINT_TO_POINTER (-1))
continue;
- code_offsets [(offsets_len * 2)] = amodule->code_offsets [i];
- code_offsets [(offsets_len *2) + 1] = i;
- offsets_len ++;
+ methods [methods_len] = amodule->methods [i];
+ method_indexes [methods_len] = i;
+ methods_len ++;
}
/* Use a merge sort as this is mostly sorted */
- msort_code_offsets (code_offsets, offsets_len);
- //qsort (code_offsets, offsets_len, sizeof (gint32) * 2, compare_ints);
- for (i = 0; i < offsets_len -1; ++i)
- g_assert (code_offsets [(i * 2)] <= code_offsets [(i + 1) * 2]);
-
- amodule->sorted_code_offsets_len = offsets_len;
- mono_memory_barrier ();
- if (InterlockedCompareExchangePointer ((gpointer*)&amodule->sorted_code_offsets, code_offsets, NULL) != NULL)
+ msort_method_addresses (methods, method_indexes, methods_len);
+ for (i = 0; i < methods_len -1; ++i)
+ g_assert (methods [i] <= methods [i + 1]);
+ amodule->sorted_methods_len = methods_len;
+ if (InterlockedCompareExchangePointer ((gpointer*)&amodule->sorted_methods, methods, NULL) != NULL)
+ /* Somebody got in before us */
+ g_free (methods);
+ if (InterlockedCompareExchangePointer ((gpointer*)&amodule->sorted_method_indexes, method_indexes, NULL) != NULL)
/* Somebody got in before us */
- g_free (code_offsets);
+ g_free (method_indexes);
}
- code_offsets = amodule->sorted_code_offsets;
- offsets_len = amodule->sorted_code_offsets_len;
-
- /* Binary search in the sorted_code_offsets table */
+ /* Binary search in the sorted_methods table */
+ methods = amodule->sorted_methods;
+ methods_len = amodule->sorted_methods_len;
+ code = addr;
left = 0;
- right = offsets_len;
+ right = methods_len;
while (TRUE) {
pos = (left + right) / 2;
- offset1 = code_offsets [(pos * 2)];
- if (pos + 1 == offsets_len) {
- if (amodule->code + offset1 >= amodule->jit_code_start && amodule->code + offset1 < amodule->jit_code_end)
- offset2 = amodule->jit_code_end - amodule->code;
+ code1 = methods [pos];
+ if (pos + 1 == methods_len) {
+ if (code1 >= amodule->jit_code_start && code1 < amodule->jit_code_end)
+ code2 = amodule->jit_code_end;
else
- offset2 = amodule->llvm_code_end - amodule->code;
+ code2 = amodule->llvm_code_end;
} else {
- offset2 = code_offsets [(pos + 1) * 2];
+ code2 = methods [pos + 1];
}
- if (offset < offset1)
+ if (code < code1)
right = pos;
- else if (offset >= offset2)
+ else if (code >= code2)
left = pos + 1;
else
break;
}
- g_assert (offset >= code_offsets [(pos * 2)]);
- if (pos + 1 < offsets_len)
- g_assert (offset < code_offsets [((pos + 1) * 2)]);
- method_index = code_offsets [(pos * 2) + 1];
+ g_assert (addr >= methods [pos]);
+ if (pos + 1 < methods_len)
+ g_assert (addr < methods [pos + 1]);
+ method_index = amodule->sorted_method_indexes [pos];
/* In async mode, jinfo is not added to the normal jit info table, so have to cache it ourselves */
if (async) {
}
}
- code = &amodule->code [amodule->code_offsets [method_index]];
+ code = amodule->methods [method_index];
ex_info = &amodule->blob [mono_aot_get_offset (amodule->ex_info_offsets, method_index)];
- if (pos == offsets_len - 1) {
+ if (pos == methods_len - 1) {
if (code >= amodule->jit_code_start && code < amodule->jit_code_end)
code_len = amodule->jit_code_end - code;
else
code_len = amodule->llvm_code_end - code;
} else {
- code_len = code_offsets [(pos + 1) * 2] - code_offsets [pos * 2];
+ code_len = (guint8*)methods [pos + 1] - (guint8*)methods [pos];
}
g_assert ((guint8*)code <= (guint8*)addr && (guint8*)addr < (guint8*)code + code_len);
case MONO_PATCH_INFO_CLASS:
case MONO_PATCH_INFO_IID:
case MONO_PATCH_INFO_ADJUSTED_IID:
- case MONO_PATCH_INFO_CLASS_INIT:
/* Shared */
ji->data.klass = decode_klass_ref (aot_module, p, &p);
if (!ji->data.klass)
ji->data.offset = decode_value (p, &p);
break;
case MONO_PATCH_INFO_INTERRUPTION_REQUEST_FLAG:
- case MONO_PATCH_INFO_GENERIC_CLASS_INIT:
case MONO_PATCH_INFO_MONITOR_ENTER:
case MONO_PATCH_INFO_MONITOR_ENTER_V4:
case MONO_PATCH_INFO_MONITOR_EXIT:
ji->data.target = info;
break;
}
+ case MONO_PATCH_INFO_GC_SAFE_POINT_FLAG:
+ break;
default:
g_warning ("unhandled type %d", ji->type);
g_assert_not_reached ();
{
MonoClass *klass;
gboolean from_plt = method == NULL;
- MonoMemPool *mp;
- int i, pindex, n_patches, used_strings;
- gboolean keep_patches = TRUE;
- guint8 *p;
MonoJitInfo *jinfo = NULL;
- guint8 *code, *info;
+ guint8 *code = NULL, *info;
+ gboolean res;
if (mono_profiler_get_events () & MONO_PROFILE_ENTER_LEAVE) {
if (mono_aot_only)
return NULL;
}
- if ((domain != mono_get_root_domain ()) && (!(amodule->info.opts & MONO_OPT_SHARED)))
+ if (domain != mono_get_root_domain ())
/* Non shared AOT code can't be used in other appdomains */
return NULL;
if (amodule->out_of_date)
return NULL;
- if (amodule->code_offsets [method_index] == 0xffffffff) {
- if (mono_trace_is_traced (G_LOG_LEVEL_DEBUG, MONO_TRACE_AOT)) {
- char *full_name;
+ if (!code) {
+ if (amodule->methods [method_index] == GINT_TO_POINTER (-1)) {
+ if (mono_trace_is_traced (G_LOG_LEVEL_DEBUG, MONO_TRACE_AOT)) {
+ char *full_name;
- if (!method)
- method = mono_get_method (image, token, NULL);
- full_name = mono_method_full_name (method, TRUE);
- mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_AOT, "AOT: NOT FOUND: %s.", full_name);
- g_free (full_name);
+ if (!method)
+ method = mono_get_method (image, token, NULL);
+ full_name = mono_method_full_name (method, TRUE);
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_AOT, "AOT: NOT FOUND: %s.", full_name);
+ g_free (full_name);
+ }
+ return NULL;
}
- return NULL;
}
- code = &amodule->code [amodule->code_offsets [method_index]];
+ code = amodule->methods [method_index];
info = &amodule->blob [mono_aot_get_offset (amodule->method_info_offsets, method_index)];
}
}
- p = info;
-
- if (method) {
- klass = method->klass;
- decode_klass_ref (amodule, p, &p);
- } else {
- klass = decode_klass_ref (amodule, p, &p);
- }
-
- if (amodule->info.opts & MONO_OPT_SHARED)
- used_strings = decode_value (p, &p);
- else
- used_strings = 0;
-
- for (i = 0; i < used_strings; i++) {
- guint token = decode_value (p, &p);
- mono_ldstr (mono_get_root_domain (), image, mono_metadata_token_index (token));
- }
-
- if (amodule->info.opts & MONO_OPT_SHARED)
- keep_patches = FALSE;
-
- n_patches = decode_value (p, &p);
-
- keep_patches = FALSE;
-
- if (n_patches) {
- MonoJumpInfo *patches;
- guint32 *got_slots;
- gboolean llvm;
- gpointer *got;
-
- if (keep_patches)
- mp = domain->mp;
- else
- mp = mono_mempool_new ();
-
- if ((gpointer)code >= amodule->info.jit_code_start && (gpointer)code <= amodule->info.jit_code_end) {
- llvm = FALSE;
- got = amodule->got;
- } else {
- llvm = TRUE;
- got = amodule->llvm_got;
- g_assert (got);
- }
-
- patches = load_patch_info (amodule, mp, n_patches, llvm, &got_slots, p, &p);
- if (patches == NULL)
- goto cleanup;
-
- for (pindex = 0; pindex < n_patches; ++pindex) {
- MonoJumpInfo *ji = &patches [pindex];
- gpointer addr;
-
- /*
- * For SFLDA, we need to call resolve_patch_target () since the GOT slot could have
- * been initialized by load_method () for a static cctor before the cctor has
- * finished executing (#23242).
- */
- if (!got [got_slots [pindex]] || ji->type == MONO_PATCH_INFO_SFLDA) {
- addr = mono_resolve_patch_target (method, domain, code, ji, TRUE);
- if (ji->type == MONO_PATCH_INFO_METHOD_JUMP)
- addr = mono_create_ftnptr (domain, addr);
- mono_memory_barrier ();
- got [got_slots [pindex]] = addr;
- if (ji->type == MONO_PATCH_INFO_METHOD_JUMP)
- register_jump_target_got_slot (domain, ji->data.method, &(got [got_slots [pindex]]));
- }
- ji->type = MONO_PATCH_INFO_NONE;
- }
-
- g_free (got_slots);
-
- if (!keep_patches)
- mono_mempool_destroy (mp);
- }
-
- if (mini_get_debug_options ()->load_aot_jit_info_eagerly)
- jinfo = mono_aot_find_jit_info (domain, amodule->assembly->image, code);
+ res = init_method (amodule, method_index, method, &klass);
+ if (!res)
+ goto cleanup;
if (mono_trace_is_traced (G_LOG_LEVEL_DEBUG, MONO_TRACE_AOT)) {
char *full_name;
MonoJitInfo *jinfo;
if (!method) {
- method = mono_get_method (image, token, NULL);
+ method = mono_get_method (amodule->assembly->image, token, NULL);
g_assert (method);
}
mono_profiler_method_jit (method);
return code;
cleanup:
- /* FIXME: The space in domain->mp is wasted */
- if (amodule->info.opts & MONO_OPT_SHARED)
- /* No need to cache patches */
- mono_mempool_destroy (mp);
-
if (jinfo)
g_free (jinfo);
}
static guint32
-find_aot_method_in_amodule (MonoAotModule *amodule, MonoMethod *method)
+find_aot_method_in_amodule (MonoAotModule *amodule, MonoMethod *method, guint32 hash_full)
{
guint32 table_size, entry_size, hash;
guint32 *table, *entry;
return 0xffffff;
table_size = amodule->extra_method_table [0];
+ hash = hash_full % table_size;
table = amodule->extra_method_table + 1;
entry_size = 3;
- hash = mono_aot_method_hash (method) % table_size;
-
entry = &table [hash * entry_size];
if (entry [0] == 0)
guint32 index;
GPtrArray *modules;
int i;
+ guint32 hash = mono_aot_method_hash (method);
/* Try the method's module first */
*out_amodule = method->klass->image->aot_module;
- index = find_aot_method_in_amodule (method->klass->image->aot_module, method);
+ index = find_aot_method_in_amodule (method->klass->image->aot_module, method, hash);
if (index != 0xffffff)
return index;
MonoAotModule *amodule = g_ptr_array_index (modules, i);
if (amodule != method->klass->image->aot_module)
- index = find_aot_method_in_amodule (amodule, method);
+ index = find_aot_method_in_amodule (amodule, method, hash);
if (index != 0xffffff) {
*out_amodule = amodule;
break;
return find_aot_method (method, &out_amodule);
}
+static gboolean
+init_method (MonoAotModule *amodule, guint32 method_index, MonoMethod *method, MonoClass **klass)
+{
+ MonoDomain *domain = mono_domain_get ();
+ MonoMemPool *mp;
+ int pindex, n_patches;
+ guint8 *p;
+ MonoJitInfo *jinfo = NULL;
+ guint8 *code, *info;
+
+ code = amodule->methods [method_index];
+ info = &amodule->blob [mono_aot_get_offset (amodule->method_info_offsets, method_index)];
+
+ p = info;
+
+ if (method) {
+ *klass = method->klass;
+ decode_klass_ref (amodule, p, &p);
+ } else {
+ *klass = decode_klass_ref (amodule, p, &p);
+ }
+
+ n_patches = decode_value (p, &p);
+
+ if (n_patches) {
+ MonoJumpInfo *patches;
+ guint32 *got_slots;
+ gboolean llvm;
+ gpointer *got;
+
+ mp = mono_mempool_new ();
+
+ if ((gpointer)code >= amodule->info.jit_code_start && (gpointer)code <= amodule->info.jit_code_end) {
+ llvm = FALSE;
+ got = amodule->got;
+ } else {
+ llvm = TRUE;
+ got = amodule->llvm_got;
+ g_assert (got);
+ }
+
+ patches = load_patch_info (amodule, mp, n_patches, llvm, &got_slots, p, &p);
+ if (patches == NULL)
+ goto cleanup;
+
+ for (pindex = 0; pindex < n_patches; ++pindex) {
+ MonoJumpInfo *ji = &patches [pindex];
+ gpointer addr;
+
+ /*
+ * For SFLDA, we need to call resolve_patch_target () since the GOT slot could have
+ * been initialized by load_method () for a static cctor before the cctor has
+ * finished executing (#23242).
+ */
+ if (!got [got_slots [pindex]] || ji->type == MONO_PATCH_INFO_SFLDA) {
+ addr = mono_resolve_patch_target (method, domain, code, ji, TRUE);
+ if (ji->type == MONO_PATCH_INFO_METHOD_JUMP)
+ addr = mono_create_ftnptr (domain, addr);
+ mono_memory_barrier ();
+ got [got_slots [pindex]] = addr;
+ if (ji->type == MONO_PATCH_INFO_METHOD_JUMP)
+ register_jump_target_got_slot (domain, ji->data.method, &(got [got_slots [pindex]]));
+ }
+ ji->type = MONO_PATCH_INFO_NONE;
+ }
+
+ g_free (got_slots);
+
+ mono_mempool_destroy (mp);
+ }
+
+ if (mini_get_debug_options ()->load_aot_jit_info_eagerly)
+ jinfo = mono_aot_find_jit_info (domain, amodule->assembly->image, code);
+
+ return TRUE;
+
+ cleanup:
+ if (jinfo)
+ g_free (jinfo);
+
+ return FALSE;
+}
+
/*
* mono_aot_get_method:
*
/* Find method index */
method_index = 0xffffff;
- if (method->is_inflated && !method->wrapper_type && mono_method_is_generic_sharable_full (method, FALSE, FALSE, FALSE)) {
+ if (method->is_inflated && !method->wrapper_type && mono_method_is_generic_sharable_full (method, TRUE, FALSE, FALSE)) {
/*
* For generic methods, we store the fully shared instance in place of the
* original method.
* patches, so have to translate between the two.
* FIXME: Clean this up, but how ?
*/
- if (ji.type == MONO_PATCH_INFO_ABS || ji.type == MONO_PATCH_INFO_INTERNAL_METHOD || ji.type == MONO_PATCH_INFO_CLASS_INIT || ji.type == MONO_PATCH_INFO_ICALL_ADDR || ji.type == MONO_PATCH_INFO_JIT_ICALL_ADDR || ji.type == MONO_PATCH_INFO_RGCTX_FETCH) {
+ if (ji.type == MONO_PATCH_INFO_ABS || ji.type == MONO_PATCH_INFO_INTERNAL_METHOD || ji.type == MONO_PATCH_INFO_ICALL_ADDR || ji.type == MONO_PATCH_INFO_JIT_ICALL_ADDR || ji.type == MONO_PATCH_INFO_RGCTX_FETCH) {
/* These should already have a function descriptor */
#ifdef PPC_USES_FUNCTION_DESCRIPTOR
/* Our function descriptors have a 0 environment, gcc created ones don't */
return NULL;
#ifdef TARGET_ARM
- if (amodule->thumb_end) {
- if (code >= amodule->llvm_code_start && code < amodule->llvm_code_end)
- return mono_arm_get_thumb_plt_entry (code);
- }
+ if (is_thumb_code (amodule, code))
+ return mono_arm_get_thumb_plt_entry (code);
#endif
#ifdef MONO_ARCH_AOT_SUPPORTED
} 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, "specific_trampoline_generic_class_init")) {
- target = mono_create_specific_trampoline (NULL, MONO_TRAMPOLINE_GENERIC_CLASS_INIT, 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 load_function_full (amodule, name, NULL);
}
+static MonoAotModule*
+get_mscorlib_aot_module (void)
+{
+ MonoImage *image;
+ MonoAotModule *amodule;
+
+ image = mono_defaults.corlib;
+ if (image)
+ amodule = image->aot_module;
+ else
+ amodule = mscorlib_aot_module;
+ g_assert (amodule);
+ return amodule;
+}
+
/*
* Return the trampoline identified by NAME from the mscorlib AOT file.
* On ppc64, this returns a function descriptor.
gpointer
mono_aot_get_trampoline_full (const char *name, MonoTrampInfo **out_tinfo)
{
- MonoImage *image;
- MonoAotModule *amodule;
-
- image = mono_defaults.corlib;
- g_assert (image);
-
- amodule = image->aot_module;
- g_assert (amodule);
+ MonoAotModule *amodule = get_mscorlib_aot_module ();
return mono_create_ftnptr_malloc (load_function_full (amodule, name, out_tinfo));
}
return code;
}
mono_aot_page_unlock ();
- psize = mono_pagesize ();
/* the trampoline template page is in the mscorlib module */
image = mono_defaults.corlib;
g_assert (image);
+ psize = MONO_AOT_TRAMP_PAGE_SIZE;
+
amodule = image->aot_module;
g_assert (amodule);
- g_assert (amodule->info.tramp_page_size == psize);
-
if (tramp_type == MONO_AOT_TRAMP_SPECIFIC)
tpage = load_function (amodule, "specific_trampolines_page");
else if (tramp_type == MONO_AOT_TRAMP_STATIC_RGCTX)
code = get_new_trampoline_from_page (MONO_AOT_TRAMP_SPECIFIC);
- data = (gpointer*)((char*)code - mono_pagesize ());
+ data = (gpointer*)((char*)code - MONO_AOT_TRAMP_PAGE_SIZE);
data [0] = arg;
data [1] = tramp;
/*g_warning ("new trampoline at %p for data %p, tramp %p (stored at %p)", code, arg, tramp, data);*/
code = get_new_trampoline_from_page (MONO_AOT_TRAMP_STATIC_RGCTX);
- data = (gpointer*)((char*)code - mono_pagesize ());
+ data = (gpointer*)((char*)code - MONO_AOT_TRAMP_PAGE_SIZE);
data [0] = arg;
data [1] = tramp;
/*g_warning ("new rgctx trampoline at %p for data %p, tramp %p (stored at %p)", code, arg, tramp, data);*/
code = get_new_trampoline_from_page (MONO_AOT_TRAMP_IMT_THUNK);
- data = (gpointer*)((char*)code - mono_pagesize ());
+ data = (gpointer*)((char*)code - MONO_AOT_TRAMP_PAGE_SIZE);
data [0] = arg;
/*g_warning ("new imt trampoline at %p for data %p, (stored at %p)", code, arg, data);*/
return code;
code = get_new_trampoline_from_page (MONO_AOT_TRAMP_GSHAREDVT_ARG);
- data = (gpointer*)((char*)code - mono_pagesize ());
+ data = (gpointer*)((char*)code - MONO_AOT_TRAMP_PAGE_SIZE);
data [0] = arg;
data [1] = tramp;
/*g_warning ("new rgctx trampoline at %p for data %p, tramp %p (stored at %p)", code, arg, tramp, data);*/
static gpointer
get_numerous_trampoline (MonoAotTrampoline tramp_type, int n_got_slots, MonoAotModule **out_amodule, guint32 *got_offset, guint32 *out_tramp_size)
{
- MonoAotModule *amodule;
- int index, tramp_size;
MonoImage *image;
+ MonoAotModule *amodule = get_mscorlib_aot_module ();
+ int index, tramp_size;
/* 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);
*out_amodule = amodule;
+ mono_aot_lock ();
+
#ifdef MONOTOUCH
#define MONOTOUCH_TRAMPOLINES_ERROR ". See http://docs.xamarin.com/ios/troubleshooting for instructions on how to fix this condition."
#else
#endif
if (amodule->trampoline_index [tramp_type] == amodule->info.num_trampolines [tramp_type]) {
g_error ("Ran out of trampolines of type %d in '%s' (%d)%s\n",
- tramp_type, image->name, amodule->info.num_trampolines [tramp_type], MONOTOUCH_TRAMPOLINES_ERROR);
+ tramp_type, image ? image->name : "mscorlib", amodule->info.num_trampolines [tramp_type], MONOTOUCH_TRAMPOLINES_ERROR);
}
index = amodule->trampoline_index [tramp_type] ++;
if (method->is_inflated && !mono_method_is_generic_sharable_full (method, FALSE, FALSE, FALSE)) {
method_index = find_aot_method (method, &amodule);
- if (method_index == 0xffffff && mono_method_is_generic_sharable_full (method, FALSE, FALSE, TRUE)) {
+ if (method_index == 0xffffff && mono_method_is_generic_sharable_full (method, FALSE, TRUE, FALSE)) {
+ MonoMethod *shared = mini_get_shared_method_full (method, FALSE, FALSE);
+ method_index = find_aot_method (shared, &amodule);
+ }
+ if (method_index == 0xffffff && mono_method_is_generic_sharable_full (method, FALSE, TRUE, TRUE)) {
MonoMethod *shared = mini_get_shared_method_full (method, TRUE, TRUE);
method_index = find_aot_method (shared, &amodule);
}