diff options
Diffstat (limited to 'mono/mini/aot-runtime.c')
-rw-r--r-- | mono/mini/aot-runtime.c | 308 |
1 files changed, 210 insertions, 98 deletions
diff --git a/mono/mini/aot-runtime.c b/mono/mini/aot-runtime.c index 7bf4aa828e..32bbeb79b4 100644 --- a/mono/mini/aot-runtime.c +++ b/mono/mini/aot-runtime.c @@ -70,9 +70,15 @@ #define SHARED_EXT ".so" #endif +#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)) +typedef struct { + int method_index; + MonoJitInfo *jinfo; +} JitInfoMap; + typedef struct MonoAotModule { char *aot_name; /* Pointer to the Global Offset Table */ @@ -98,9 +104,7 @@ typedef struct MonoAotModule { guint8 *plt_end; guint8 *blob; gint32 *code_offsets; -#ifdef MONOTOUCH gpointer *method_addresses; -#endif /* This contains <offset, index> pairs sorted by offset */ /* This is needed because LLVM emitted methods can be in any order */ gint32 *sorted_code_offsets; @@ -132,6 +136,8 @@ typedef struct MonoAotModule { gpointer *globals; MonoDl *sofile; + + JitInfoMap *async_jit_info_table; } MonoAotModule; typedef struct { @@ -180,6 +186,9 @@ static guint32 n_pagefaults = 0; static gsize aot_code_low_addr = (gssize)-1; static gsize aot_code_high_addr = 0; +/* Stats */ +static gint32 async_jit_info_size; + static GHashTable *aot_jit_icall_hash; #ifdef MONOTOUCH @@ -1588,7 +1597,7 @@ load_aot_module (MonoAssembly *assembly, gpointer user_data) sofile = mono_dl_open (aot_name, MONO_DL_LAZY, &err); if (!sofile) { - mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT failed to load AOT module %s: %s\n", aot_name, err); + mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT module '%s' not found: %s\n", aot_name, err); g_free (err); } } @@ -1719,9 +1728,7 @@ load_aot_module (MonoAssembly *assembly, gpointer user_data) } amodule->code_offsets = info->code_offsets; -#ifdef MONOTOUCH amodule->method_addresses = info->method_addresses; -#endif amodule->code = info->methods; #ifdef TARGET_ARM /* Mask out thumb interop bit */ @@ -1755,7 +1762,7 @@ load_aot_module (MonoAssembly *assembly, gpointer user_data) amodule->code_offsets = g_malloc0 (amodule->info.nmethods * sizeof (gint32)); 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 = get_arm_bl_target ((guint32*)(amodule->method_addresses + i)); + void *addr = get_arm_bl_target ((guint32*)amodule->method_addresses + i); if (addr == amodule->method_addresses) amodule->code_offsets [i] = 0xffffffff; @@ -1909,6 +1916,7 @@ mono_aot_init (void) #ifndef __native_client__ mono_install_assembly_load_hook (load_aot_module, NULL); #endif + mono_counters_register ("Async JIT info size", MONO_COUNTER_INT|MONO_COUNTER_JIT, &async_jit_info_size); if (g_getenv ("MONO_LASTAOT")) mono_last_aot_method = atoi (g_getenv ("MONO_LASTAOT")); @@ -2257,11 +2265,11 @@ decode_llvm_mono_eh_frame (MonoAotModule *amodule, MonoDomain *domain, * allocate a new JI. */ jinfo = - mono_domain_alloc0 (domain, MONO_SIZEOF_JIT_INFO + (sizeof (MonoJitExceptionInfo) * (ei_len + nested_len)) + extra_size); + mono_domain_alloc0_lock_free (domain, MONO_SIZEOF_JIT_INFO + (sizeof (MonoJitExceptionInfo) * (ei_len + nested_len)) + extra_size); jinfo->code_size = code_len; jinfo->used_regs = mono_cache_unwind_info (info.unw_info, info.unw_info_len); - jinfo->method = method; + jinfo->d.method = method; jinfo->code_start = code; jinfo->domain_neutral = 0; /* This signals that used_regs points to a normal cached unwind info */ @@ -2321,15 +2329,30 @@ decode_llvm_mono_eh_frame (MonoAotModule *amodule, MonoDomain *domain, return jinfo; } +static gpointer +alloc0_jit_info_data (MonoDomain *domain, int size, gboolean async_context) +{ + gpointer res; + + if (async_context) { + res = mono_domain_alloc0_lock_free (domain, size); + InterlockedExchangeAdd (&async_jit_info_size, size); + } else { + res = mono_domain_alloc0 (domain, size); + } + return res; +} + /* * LOCKING: Acquires the domain lock. + * In async context, this is async safe. */ static MonoJitInfo* decode_exception_debug_info (MonoAotModule *amodule, MonoDomain *domain, MonoMethod *method, guint8* ex_info, guint8 *addr, guint8 *code, guint32 code_len) { - int i, buf_len, num_clauses; + int i, buf_len, num_clauses, len; MonoJitInfo *jinfo; guint used_int_regs, flags; gboolean has_generic_jit_info, has_dwarf_unwind_info, has_clauses, has_seq_points, has_try_block_holes, has_arch_eh_jit_info; @@ -2337,8 +2360,10 @@ decode_exception_debug_info (MonoAotModule *amodule, MonoDomain *domain, guint8 *p; int generic_info_size, try_holes_info_size, num_holes, arch_eh_jit_info_size; int this_reg = 0, this_offset = 0; + gboolean async; /* Load the method info from the AOT file */ + async = mono_thread_info_is_async_context (); p = ex_info; flags = decode_value (p, &p); @@ -2385,6 +2410,9 @@ decode_exception_debug_info (MonoAotModule *amodule, MonoDomain *domain, MonoJitExceptionInfo *clauses; GSList **nesting; + // FIXME: async + g_assert (!async); + /* * Part of the info is encoded by the AOT compiler, the rest is in the .eh_frame * section. @@ -2417,8 +2445,8 @@ decode_exception_debug_info (MonoAotModule *amodule, MonoDomain *domain, g_slist_free (nesting [i]); g_free (nesting); } else { - jinfo = - mono_domain_alloc0 (domain, MONO_SIZEOF_JIT_INFO + (sizeof (MonoJitExceptionInfo) * num_clauses) + generic_info_size + try_holes_info_size + arch_eh_jit_info_size); + len = MONO_SIZEOF_JIT_INFO + (sizeof (MonoJitExceptionInfo) * num_clauses) + generic_info_size + try_holes_info_size + arch_eh_jit_info_size; + jinfo = alloc0_jit_info_data (domain, len, async); jinfo->num_clauses = num_clauses; for (i = 0; i < jinfo->num_clauses; ++i) { @@ -2431,8 +2459,14 @@ decode_exception_debug_info (MonoAotModule *amodule, MonoDomain *domain, if (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER || ei->flags == MONO_EXCEPTION_CLAUSE_FINALLY) ei->data.filter = code + decode_value (p, &p); else { - if (decode_value (p, &p)) - ei->data.catch_class = decode_klass_ref (amodule, p, &p); + int len = decode_value (p, &p); + + if (len > 0) { + if (async) + p += len; + else + ei->data.catch_class = decode_klass_ref (amodule, p, &p); + } } ei->try_start = code + decode_value (p, &p); @@ -2442,14 +2476,49 @@ decode_exception_debug_info (MonoAotModule *amodule, MonoDomain *domain, jinfo->code_size = code_len; jinfo->used_regs = used_int_regs; - jinfo->method = method; + jinfo->d.method = method; jinfo->code_start = code; jinfo->domain_neutral = 0; jinfo->from_aot = 1; } + if (has_try_block_holes) { + MonoTryBlockHoleTableJitInfo *table; + + jinfo->has_try_block_holes = 1; + + table = mono_jit_info_get_try_block_hole_table_info (jinfo); + g_assert (table); + + table->num_holes = (guint16)num_holes; + for (i = 0; i < num_holes; ++i) { + MonoTryBlockHoleJitInfo *hole = &table->holes [i]; + hole->clause = decode_value (p, &p); + hole->length = decode_value (p, &p); + hole->offset = decode_value (p, &p); + } + } + + if (has_arch_eh_jit_info) { + MonoArchEHJitInfo *eh_info; + + jinfo->has_arch_eh_info = 1; + + eh_info = mono_jit_info_get_arch_eh_info (jinfo); + eh_info->stack_size = decode_value (p, &p); + } + + if (async) { + /* The rest is not needed in async mode */ + jinfo->async = TRUE; + jinfo->d.aot_info = amodule; + // FIXME: Cache + return jinfo; + } + if (has_generic_jit_info) { MonoGenericJitInfo *gi; + int len; jinfo->has_generic_jit_info = 1; @@ -2458,7 +2527,7 @@ decode_exception_debug_info (MonoAotModule *amodule, MonoDomain *domain, gi->nlocs = decode_value (p, &p); if (gi->nlocs) { - gi->locations = mono_domain_alloc0 (domain, gi->nlocs * sizeof (MonoDwarfLocListEntry)); + gi->locations = alloc0_jit_info_data (domain, gi->nlocs * sizeof (MonoDwarfLocListEntry), async); for (i = 0; i < gi->nlocs; ++i) { MonoDwarfLocListEntry *entry = &gi->locations [i]; @@ -2482,7 +2551,11 @@ decode_exception_debug_info (MonoAotModule *amodule, MonoDomain *domain, } } - jinfo->method = decode_resolve_method_ref (amodule, p, &p); + len = decode_value (p, &p); + if (async) + p += len; + else + jinfo->d.method = decode_resolve_method_ref (amodule, p, &p); gi->generic_sharing_context = g_new0 (MonoGenericSharingContext, 1); if (decode_value (p, &p)) { @@ -2492,46 +2565,20 @@ decode_exception_debug_info (MonoAotModule *amodule, MonoDomain *domain, n = decode_value (p, &p); if (n) { - gsctx->var_is_vt = g_new0 (gboolean, 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 = g_new0 (gboolean, 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); } } } - if (has_try_block_holes) { - MonoTryBlockHoleTableJitInfo *table; - - jinfo->has_try_block_holes = 1; - - table = mono_jit_info_get_try_block_hole_table_info (jinfo); - g_assert (table); - - table->num_holes = (guint16)num_holes; - for (i = 0; i < num_holes; ++i) { - MonoTryBlockHoleJitInfo *hole = &table->holes [i]; - hole->clause = decode_value (p, &p); - hole->length = decode_value (p, &p); - hole->offset = decode_value (p, &p); - } - } - - if (has_arch_eh_jit_info) { - MonoArchEHJitInfo *eh_info; - - jinfo->has_arch_eh_info = 1; - - eh_info = mono_jit_info_get_arch_eh_info (jinfo); - eh_info->stack_size = decode_value (p, &p); - } - - if (has_seq_points) { + if (method && has_seq_points) { MonoSeqPointInfo *seq_points; int il_offset, native_offset, last_il_offset, last_native_offset, j; @@ -2548,6 +2595,7 @@ decode_exception_debug_info (MonoAotModule *amodule, MonoDomain *domain, sp->il_offset = il_offset; sp->native_offset = native_offset; + sp->flags = decode_value (p, &p); sp->next_len = decode_value (p, &p); sp->next = g_new (int, sp->next_len); for (j = 0; j < sp->next_len; ++j) @@ -2564,7 +2612,8 @@ decode_exception_debug_info (MonoAotModule *amodule, MonoDomain *domain, /* Load debug info */ buf_len = decode_value (p, &p); - mono_debug_add_aot_method (domain, method, code, p, buf_len); + if (!async) + mono_debug_add_aot_method (domain, method, code, p, buf_len); p += buf_len; if (has_gc_map) { @@ -2576,7 +2625,7 @@ decode_exception_debug_info (MonoAotModule *amodule, MonoDomain *domain, p += map_size; } - if (amodule != jinfo->method->klass->image->aot_module) { + if (amodule != jinfo->d.method->klass->image->aot_module) { mono_aot_lock (); if (!ji_to_amodule) ji_to_amodule = g_hash_table_new (NULL, NULL); @@ -2595,10 +2644,14 @@ decode_exception_debug_info (MonoAotModule *amodule, MonoDomain *domain, guint8* mono_aot_get_unwind_info (MonoJitInfo *ji, guint32 *unwind_info_len) { - MonoAotModule *amodule = ji->method->klass->image->aot_module; + MonoAotModule *amodule; guint8 *p; guint8 *code = ji->code_start; + if (ji->async) + amodule = ji->d.aot_info; + else + amodule = jinfo_get_method (ji)->klass->image->aot_module; g_assert (amodule); g_assert (ji->from_aot); @@ -2677,6 +2730,13 @@ msort_code_offsets (gint32 *array, int len) g_free (scratch); } +/* + * mono_aot_find_jit_info: + * + * In async context, the resulting MonoJitInfo will not have its method field set, and it will not be added + * to the jit info tables. + * FIXME: Large sizes in the lock free allocator + */ MonoJitInfo * mono_aot_find_jit_info (MonoDomain *domain, MonoImage *image, gpointer addr) { @@ -2684,13 +2744,14 @@ mono_aot_find_jit_info (MonoDomain *domain, MonoImage *image, gpointer addr) int method_index, table_len; guint32 token; MonoAotModule *amodule = image->aot_module; - MonoMethod *method; + MonoMethod *method = NULL; MonoJitInfo *jinfo; guint8 *code, *ex_info, *p; guint32 *table; int nmethods = amodule->info.nmethods; gint32 *code_offsets; int offsets_len, i; + gboolean async; if (!amodule) return NULL; @@ -2699,10 +2760,13 @@ mono_aot_find_jit_info (MonoDomain *domain, MonoImage *image, gpointer addr) /* FIXME: */ return NULL; + 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) { + // FIXME: async code_offsets = g_new0 (gint32, nmethods * 2); offsets_len = 0; for (i = 0; i < nmethods; ++i) { @@ -2757,6 +2821,20 @@ mono_aot_find_jit_info (MonoDomain *domain, MonoImage *image, gpointer addr) g_assert (offset < code_offsets [((pos + 1) * 2)]); method_index = code_offsets [(pos * 2) + 1]; + /* In async mode, jinfo is not added to the normal jit info table, so have to cache it ourselves */ + if (async) { + JitInfoMap *table = amodule->async_jit_info_table; + int len; + + if (table) { + len = table [0].method_index; + for (i = 1; i < len; ++i) { + if (table [i].method_index == method_index) + return table [i].jinfo; + } + } + } + code = &amodule->code [amodule->code_offsets [method_index]]; ex_info = &amodule->blob [mono_aot_get_offset (amodule->ex_info_offsets, method_index)]; @@ -2768,54 +2846,55 @@ mono_aot_find_jit_info (MonoDomain *domain, MonoImage *image, gpointer addr) g_assert ((guint8*)code <= (guint8*)addr && (guint8*)addr < (guint8*)code + code_len); /* Might be a wrapper/extra method */ - if (amodule->extra_methods) { - mono_aot_lock (); - method = g_hash_table_lookup (amodule->extra_methods, GUINT_TO_POINTER (method_index)); - mono_aot_unlock (); - } else { - method = NULL; - } - - if (!method) { - if (method_index >= image->tables [MONO_TABLE_METHOD].rows) { - /* - * This is hit for extra methods which are called directly, so they are - * not in amodule->extra_methods. - */ - table_len = amodule->extra_method_info_offsets [0]; - table = amodule->extra_method_info_offsets + 1; - left = 0; - right = table_len; - pos = 0; - - /* Binary search */ - while (TRUE) { - pos = ((left + right) / 2); + if (!async) { + if (amodule->extra_methods) { + mono_aot_lock (); + method = g_hash_table_lookup (amodule->extra_methods, GUINT_TO_POINTER (method_index)); + mono_aot_unlock (); + } else { + method = NULL; + } - g_assert (pos < table_len); + if (!method) { + if (method_index >= image->tables [MONO_TABLE_METHOD].rows) { + /* + * This is hit for extra methods which are called directly, so they are + * not in amodule->extra_methods. + */ + table_len = amodule->extra_method_info_offsets [0]; + table = amodule->extra_method_info_offsets + 1; + left = 0; + right = table_len; + pos = 0; + + /* Binary search */ + while (TRUE) { + pos = ((left + right) / 2); + + g_assert (pos < table_len); + + if (table [pos * 2] < method_index) + left = pos + 1; + else if (table [pos * 2] > method_index) + right = pos; + else + break; + } - if (table [pos * 2] < method_index) - left = pos + 1; - else if (table [pos * 2] > method_index) - right = pos; - else - break; + p = amodule->blob + table [(pos * 2) + 1]; + method = decode_resolve_method_ref (amodule, p, &p); + if (!method) + /* Happens when a random address is passed in which matches a not-yey called wrapper encoded using its name */ + return NULL; + } else { + token = mono_metadata_make_token (MONO_TABLE_METHOD, method_index + 1); + method = mono_get_method (image, token, NULL); } - - p = amodule->blob + table [(pos * 2) + 1]; - method = decode_resolve_method_ref (amodule, p, &p); - if (!method) - /* Happens when a random address is passed in which matches a not-yey called wrapper encoded using its name */ - return NULL; - } else { - token = mono_metadata_make_token (MONO_TABLE_METHOD, method_index + 1); - method = mono_get_method (image, token, NULL); } + /* FIXME: */ + g_assert (method); } - /* FIXME: */ - g_assert (method); - //printf ("F: %s\n", mono_method_full_name (method, TRUE)); jinfo = decode_exception_debug_info (amodule, domain, method, ex_info, addr, code, code_len); @@ -2824,7 +2903,35 @@ mono_aot_find_jit_info (MonoDomain *domain, MonoImage *image, gpointer addr) g_assert ((guint8*)addr < (guint8*)jinfo->code_start + jinfo->code_size); /* Add it to the normal JitInfo tables */ - mono_jit_info_table_add (domain, jinfo); + if (async) { + JitInfoMap *old_table, *new_table; + int len; + + /* + * Use a simple inmutable table with linear search to cache async jit info entries. + * This assumes that the number of entries is small. + */ + while (TRUE) { + /* Copy the table, adding a new entry at the end */ + old_table = amodule->async_jit_info_table; + if (old_table) + len = old_table[0].method_index; + else + len = 1; + new_table = alloc0_jit_info_data (domain, (len + 1) * sizeof (JitInfoMap), async); + if (old_table) + memcpy (new_table, old_table, len * sizeof (JitInfoMap)); + new_table [0].method_index = len + 1; + new_table [len].method_index = method_index; + new_table [len].jinfo = jinfo; + /* Publish it */ + mono_memory_barrier (); + if (InterlockedCompareExchangePointer ((gpointer)&amodule->async_jit_info_table, new_table, old_table) == old_table) + break; + } + } else { + mono_jit_info_table_add (domain, jinfo); + } return jinfo; } @@ -2841,7 +2948,8 @@ decode_patch (MonoAotModule *aot_module, MonoMemPool *mp, MonoJumpInfo *ji, guin case MONO_PATCH_INFO_METHOD: case MONO_PATCH_INFO_METHOD_JUMP: case MONO_PATCH_INFO_ICALL_ADDR: - case MONO_PATCH_INFO_METHOD_RGCTX: { + case MONO_PATCH_INFO_METHOD_RGCTX: + case MONO_PATCH_INFO_METHOD_CODE_SLOT: { MethodRef ref; gboolean res; @@ -3635,7 +3743,7 @@ mono_aot_get_method (MonoDomain *domain, MonoMethod *method) char *full_name; full_name = mono_method_full_name (method, TRUE); - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_AOT, "AOT NOT FOUND: %s.\n", full_name); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_AOT, "AOT NOT FOUND: %s.", full_name); g_free (full_name); } return NULL; @@ -4168,14 +4276,16 @@ get_new_trampoline_from_page (int tramp_type) vm_address_t addr, taddr; kern_return_t ret; vm_prot_t prot, max_prot; - int psize; + int psize, specific_trampoline_size; unsigned char *code; + specific_trampoline_size = 2 * sizeof (gpointer); + mono_aot_page_lock (); page = trampoline_pages [tramp_type]; if (page && page->trampolines < page->trampolines_end) { code = page->trampolines; - page->trampolines += 8; + page->trampolines += specific_trampoline_size; mono_aot_page_unlock (); return code; } @@ -4188,6 +4298,8 @@ get_new_trampoline_from_page (int tramp_type) 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) @@ -4231,7 +4343,7 @@ get_new_trampoline_from_page (int tramp_type) /* some other thread already allocated, so use that to avoid wasting memory */ if (page && page->trampolines < page->trampolines_end) { code = page->trampolines; - page->trampolines += 8; + page->trampolines += specific_trampoline_size; mono_aot_page_unlock (); vm_deallocate (mach_task_self (), addr, psize); vm_deallocate (mach_task_self (), taddr, psize); @@ -4343,7 +4455,7 @@ get_numerous_trampoline (MonoAotTrampoline tramp_type, int n_got_slots, MonoAotM *out_amodule = amodule; #ifdef MONOTOUCH -#define MONOTOUCH_TRAMPOLINES_ERROR ". See http://docs.xamarin.com/ios/troubleshooting for instruction on how to fix this condition" +#define MONOTOUCH_TRAMPOLINES_ERROR ". See http://docs.xamarin.com/ios/troubleshooting for instructions on how to fix this condition." #else #define MONOTOUCH_TRAMPOLINES_ERROR "" #endif |