X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mono%2Fmini%2Faot.c;h=d367904f81e5396341f120338ee8f72dc24053de;hb=311dcbd59f854031a0c719bbc12056431e7108e0;hp=ec0f36d116abc2a04c25bbfc708d51ddae7a0b08;hpb=501a2b6bc63a542d2d4d565767556aa6b56d9aa9;p=mono.git diff --git a/mono/mini/aot.c b/mono/mini/aot.c index ec0f36d116a..d367904f81e 100644 --- a/mono/mini/aot.c +++ b/mono/mini/aot.c @@ -30,19 +30,34 @@ #include #include #include +#include +#include +#include #include #include "mini.h" #ifdef PLATFORM_WIN32 #define SHARED_EXT ".dll" +#elif defined(__ppc__) && defined(__MACH__) +#define SHARED_EXT ".dylib" #else #define SHARED_EXT ".so" #endif +#if defined(sparc) || defined(__ppc__) +#define AS_STRING_DIRECTIVE ".asciz" +#else +/* GNU as */ +#define AS_STRING_DIRECTIVE ".string" +#endif + +#define ALIGN_PTR_TO(ptr,align) (gpointer)((((gssize)(ptr)) + (align - 1)) & (~(align - 1))) + typedef struct MonoAotMethod { MonoJitInfo *info; MonoJumpInfo *patch_info; + MonoDomain *domain; } MonoAotMethod; typedef struct MonoAotModule { @@ -68,22 +83,36 @@ static MonoGHashTable *aot_modules; static CRITICAL_SECTION aot_mutex; -static guint32 mono_aot_verbose = 0; +/* + * Disabling this will make a copy of the loaded code and use the copy instead + * of the original. This will place the caller and the callee close to each + * other in memory, possibly improving cache behavior. Since the original + * code is in copy-on-write memory, this will not increase the memory usage + * of the runtime. + */ +static gboolean use_loaded_code = FALSE; + +/* For debugging */ +static gint32 mono_last_aot_method = -1; + +static MonoJitInfo* +mono_aot_load_method (MonoDomain *domain, MonoAotModule *aot_module, MonoMethod *method, guint8 *code, guint8 *info); static MonoClass * -decode_class_info (MonoAotModule *module, gpointer *data) +decode_class_info (MonoAotModule *module, guint32 *data) { MonoImage *image; MonoClass *klass; - image = module->image_table [(guint32)data [1]]; + image = module->image_table [data [1]]; g_assert (image); if (data [0]) { - return mono_class_get (image, (guint32)data [0]); + return mono_class_get (image, data [0]); } else { - klass = decode_class_info (module, data [3]); - return mono_array_class_get (klass, (guint32)data [2]); + /* the pointer is dword aligned */ + klass = decode_class_info (module, *(guint32**)(ALIGN_PTR_TO (&data[3], sizeof (gpointer)))); + return mono_array_class_get (klass, data [2]); } return NULL; @@ -99,29 +128,27 @@ load_aot_module (MonoAssembly *assembly, gpointer user_data) char *aot_version = NULL; char *opt_flags = NULL; - if (mono_no_aot) - return; - - aot_name = g_strdup_printf ("%s.so", assembly->image->name); + aot_name = g_strdup_printf ("%s%s", assembly->image->name, SHARED_EXT); assembly->aot_module = g_module_open (aot_name, G_MODULE_BIND_LAZY); - if (!assembly->aot_module) + if (!assembly->aot_module) { + mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT Failed to load AOT module %s: %s\n", aot_name, g_module_error ()); + g_free (aot_name); return; + } g_module_symbol (assembly->aot_module, "mono_assembly_guid", (gpointer *) &saved_guid); g_module_symbol (assembly->aot_module, "mono_aot_version", (gpointer *) &aot_version); g_module_symbol (assembly->aot_module, "mono_aot_opt_flags", (gpointer *)&opt_flags); if (!aot_version || strcmp (aot_version, MONO_AOT_FILE_VERSION)) { - if (mono_aot_verbose > 0) - printf ("AOT module %s has wrong file format version (expected %s got %s)\n", aot_name, MONO_AOT_FILE_VERSION, aot_version); + mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT Module %s has wrong file format version (expected %s got %s)\n", aot_name, MONO_AOT_FILE_VERSION, aot_version); usable = FALSE; } else if (!saved_guid || strcmp (assembly->image->guid, saved_guid)) { - if (mono_aot_verbose > 0) - printf ("AOT module %s is out of date.\n", aot_name); + mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT Module %s is out of date.\n", aot_name); usable = FALSE; } @@ -158,11 +185,12 @@ load_aot_module (MonoAssembly *assembly, gpointer user_data) for (i = 0; i < table_len; ++i) { info->image_table [i] = mono_image_loaded_by_guid (table); if (!info->image_table [i]) { - if (mono_aot_verbose > 0) - printf ("AOT module %s is out of date.\n", aot_name); - g_free (info->methods); + mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT module %s is out of date.\n", aot_name); + mono_g_hash_table_destroy (info->methods); g_free (info->image_table); +#ifndef HAVE_BOEHM_GC g_free (info); +#endif g_free (aot_name); g_module_close (assembly->aot_module); assembly->aot_module = NULL; @@ -197,8 +225,7 @@ load_aot_module (MonoAssembly *assembly, gpointer user_data) mono_g_hash_table_insert (aot_modules, assembly, info); LeaveCriticalSection (&aot_mutex); - if (mono_aot_verbose > 0) - printf ("Loaded AOT Module for %s.\n", assembly->image->name); + mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT Loaded AOT Module for %s.\n", assembly->image->name); } void @@ -209,6 +236,9 @@ mono_aot_init (void) aot_modules = mono_g_hash_table_new (NULL, NULL); mono_install_assembly_load_hook (load_aot_module, NULL); + + if (getenv ("MONO_LASTAOT")) + mono_last_aot_method = atoi (getenv ("MONO_LASTAOT")); } static MonoJitInfo * @@ -216,13 +246,11 @@ mono_aot_get_method_inner (MonoDomain *domain, MonoMethod *method) { MonoClass *klass = method->klass; MonoAssembly *ass = klass->image->assembly; - MonoJumpInfo *patch_info = NULL; GModule *module = ass->aot_module; char method_label [256]; char info_label [256]; guint8 *code = NULL; - gpointer *info; - guint code_len, used_int_regs, used_strings; + guint8 *info; MonoAotModule *aot_module; MonoAotMethod *minfo; MonoJitInfo *jinfo; @@ -235,6 +263,9 @@ mono_aot_get_method_inner (MonoDomain *domain, MonoMethod *method) if (!method->token) return NULL; + if (mono_profiler_get_events () & MONO_PROFILE_ENTER_LEAVE) + return NULL; + if ((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) || (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) || (method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) || @@ -246,7 +277,10 @@ mono_aot_get_method_inner (MonoDomain *domain, MonoMethod *method) g_assert (klass->inited); minfo = mono_g_hash_table_lookup (aot_module->methods, method); - if (minfo) { + /* Can't use code from non-root domains since they can be unloaded */ + if (minfo && (minfo->domain == mono_get_root_domain ())) { + /* This method was already loaded in another appdomain */ + /* Duplicate jinfo */ jinfo = mono_mempool_alloc0 (domain->mp, sizeof (MonoJitInfo)); memcpy (jinfo, minfo->info, sizeof (MonoJitInfo)); @@ -256,7 +290,6 @@ mono_aot_get_method_inner (MonoDomain *domain, MonoMethod *method) memcpy (jinfo->clauses, minfo->info->clauses, sizeof (MonoJitExceptionInfo) * header->num_clauses); } - /* This method was already loaded in another appdomain */ if (aot_module->opts & MONO_OPT_SHARED) /* Use the same method in the new appdomain */ ; @@ -266,16 +299,16 @@ mono_aot_get_method_inner (MonoDomain *domain, MonoMethod *method) else { /* Create a copy of the original method and apply relocations */ - code = mono_mempool_alloc (domain->code_mp, minfo->info->code_size); + code = mono_code_manager_reserve (domain->code_mp, minfo->info->code_size); memcpy (code, minfo->info->code_start, minfo->info->code_size); - if (mono_aot_verbose > 1) - printf ("REUSE METHOD: %s %p - %p.\n", mono_method_full_name (method, TRUE), code, (char*)code + code_len); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_AOT, "AOT REUSE METHOD: %s %p - %p.\n", mono_method_full_name (method, TRUE), code, (char*)code + minfo->info->code_size); /* Do this outside the lock to avoid deadlocks */ LeaveCriticalSection (&aot_mutex); - mono_arch_patch_code (method, domain, code, minfo->patch_info); + mono_arch_patch_code (method, domain, code, minfo->patch_info, TRUE); EnterCriticalSection (&aot_mutex); + mono_arch_flush_icache (code, minfo->info->code_size); /* Relocate jinfo */ jinfo->code_start = code; @@ -302,8 +335,7 @@ mono_aot_get_method_inner (MonoDomain *domain, MonoMethod *method) guint32 w; w = aot_module->methods_present_table [index / 32]; if (! (w & (1 << (index % 32)))) { - if (mono_aot_verbose > 1) - printf ("NOT FOUND: %s.\n", mono_method_full_name (method, TRUE)); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_AOT, "AOT NOT FOUND: %s.\n", mono_method_full_name (method, TRUE)); return NULL; } } @@ -318,36 +350,52 @@ mono_aot_get_method_inner (MonoDomain *domain, MonoMethod *method) if (!g_module_symbol (module, info_label, (gpointer *)&info)) return NULL; - { - static int count = 0; - - count ++; - - if (getenv ("MONO_LASTAOT")) { - if (count > atoi(getenv ("MONO_LASTAOT"))) { + if (mono_last_aot_method != -1) { + if (mono_jit_stats.methods_aot > mono_last_aot_method) return NULL; - } - else - if (count == atoi(getenv ("MONO_LASTAOT"))) - printf ("LAST AOT METHOD: %s.%s.%s.\n", klass->name_space, klass->name, method->name); - } + else + if (mono_jit_stats.methods_aot == mono_last_aot_method) + printf ("LAST AOT METHOD: %s.%s.%s.\n", klass->name_space, klass->name, method->name); } + return mono_aot_load_method (domain, aot_module, method, code, info); +} + +static MonoJitInfo* +mono_aot_load_method (MonoDomain *domain, MonoAotModule *aot_module, MonoMethod *method, guint8 *code, guint8 *info) +{ + MonoClass *klass = method->klass; + MonoJumpInfo *patch_info = NULL; + guint code_len, used_int_regs, used_strings; + MonoAotMethod *minfo; + MonoJitInfo *jinfo; + MonoMethodHeader *header = ((MonoMethodNormal*)method)->header; + GPtrArray *patches; + int i, pindex; + #ifdef HAVE_BOEHM_GC minfo = GC_MALLOC (sizeof (MonoAotMethod)); #else minfo = g_new0 (MonoAotMethod, 1); #endif + minfo->domain = domain; jinfo = mono_mempool_alloc0 (domain->mp, sizeof (MonoJitInfo)); - code_len = GPOINTER_TO_UINT (*((gpointer **)info)); - info++; - used_int_regs = GPOINTER_TO_UINT (*((gpointer **)info)); - info++; + code_len = *(guint32*)info; + info += 4; + used_int_regs = *(guint32*)info; + info += 4; + + if (!use_loaded_code) { + guint8 *code2; + code2 = mono_code_manager_reserve (domain->code_mp, code_len); + memcpy (code2, code, code_len); + mono_arch_flush_icache (code2, code_len); + code = code2; + } - if (mono_aot_verbose > 1) - printf ("FOUND AOT compiled code for %s %p - %p %p\n", mono_method_full_name (method, TRUE), code, code + code_len, info); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_AOT, "AOT FOUND AOT compiled code for %s %p - %p %p\n", mono_method_full_name (method, TRUE), code, code + code_len, info); /* Exception table */ if (header->num_clauses) { @@ -355,8 +403,8 @@ mono_aot_get_method_inner (MonoDomain *domain, MonoMethod *method) mono_mempool_alloc0 (domain->mp, sizeof (MonoJitExceptionInfo) * header->num_clauses); jinfo->num_clauses = header->num_clauses; - jinfo->exvar_offset = GPOINTER_TO_UINT (*((gpointer**)info)); - info ++; + jinfo->exvar_offset = *(guint32*)info; + info += 4; for (i = 0; i < header->num_clauses; ++i) { MonoExceptionClause *ec = &header->clauses [i]; @@ -364,30 +412,30 @@ mono_aot_get_method_inner (MonoDomain *domain, MonoMethod *method) ei->flags = ec->flags; if (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER) - ei->data.filter = code + GPOINTER_TO_UINT (*((gpointer**)info)); + ei->data.filter = code + *(guint32*)info; else - ei->data.token = GPOINTER_TO_UINT (*((gpointer**)info)); - info ++; - ei->try_start = code + GPOINTER_TO_UINT (*((gpointer**)info)); - info ++; - ei->try_end = code + GPOINTER_TO_UINT (*((gpointer**)info)); - info ++; - ei->handler_start = code + GPOINTER_TO_UINT (*((gpointer**)info)); - info ++; + ei->data.token = *(guint32*)info; + info += 4; + ei->try_start = code + *(guint32*)info; + info += 4; + ei->try_end = code + *(guint32*)info; + info += 4; + ei->handler_start = code + *(guint32*)info; + info += 4; } } if (aot_module->opts & MONO_OPT_SHARED) { - used_strings = GPOINTER_TO_UINT (*((gpointer **)info)); - info++; + used_strings = *(guint32*)info; + info += 4; } else used_strings = 0; for (i = 0; i < used_strings; i++) { - guint token = GPOINTER_TO_UINT (*((gpointer **)info)); - info++; - mono_ldstr (mono_root_domain, klass->image, mono_metadata_token_index (token)); + guint token = *(guint32*)info; + info += 4; + mono_ldstr (mono_get_root_domain (), klass->image, mono_metadata_token_index (token)); } if (*info) { @@ -397,30 +445,33 @@ mono_aot_get_method_inner (MonoDomain *domain, MonoMethod *method) gpointer *table; int pages; int i, err; - guint32 last_offset; + guint32 last_offset, buf_len; + guint32 *data; if (aot_module->opts & MONO_OPT_SHARED) mp = mono_mempool_new (); else mp = domain->mp; + /* First load the type + offset table */ last_offset = 0; + patches = g_ptr_array_new (); while (*info) { MonoJumpInfo *ji = mono_mempool_alloc0 (mp, sizeof (MonoJumpInfo)); - gpointer *data; guint8 b1, b2; b1 = *(guint8*)info; b2 = *((guint8*)info + 1); - - info = (gpointer*)((guint8*)info + 2); + + info += 2; ji->type = b1 >> 2; if (((b1 & (1 + 2)) == 3) && (b2 == 255)) { - ji->ip.i = GPOINTER_TO_UINT (*info); - info ++; + info = ALIGN_PTR_TO (info, 4); + ji->ip.i = *(guint32*)info; + info += 4; } else ji->ip.i = (((guint32)(b1 & (1 + 2))) << 8) + b2; @@ -429,7 +480,21 @@ mono_aot_get_method_inner (MonoDomain *domain, MonoMethod *method) last_offset = ji->ip.i; //printf ("T: %d O: %d.\n", ji->type, ji->ip.i); - data = *((gpointer **)info); + ji->next = patch_info; + patch_info = ji; + + g_ptr_array_add (patches, ji); + } + info ++; + + info = ALIGN_PTR_TO (info, sizeof (gpointer)); + + /* Then load the other data */ + for (pindex = 0; pindex < patches->len; ++pindex) { + MonoJumpInfo *ji = g_ptr_array_index (patches, pindex); + + data = *((guint32 **)info); + info += sizeof (gpointer); switch (ji->type) { case MONO_PATCH_INFO_CLASS: @@ -439,6 +504,7 @@ mono_aot_get_method_inner (MonoDomain *domain, MonoMethod *method) mono_class_init (ji->data.klass); break; case MONO_PATCH_INFO_VTABLE: + case MONO_PATCH_INFO_CLASS_INIT: ji->data.klass = decode_class_info (aot_module, data); g_assert (ji->data.klass); mono_class_init (ji->data.klass); @@ -448,7 +514,8 @@ mono_aot_get_method_inner (MonoDomain *domain, MonoMethod *method) g_assert (ji->data.image); break; case MONO_PATCH_INFO_METHOD: - case MONO_PATCH_INFO_METHODCONST: { + case MONO_PATCH_INFO_METHODCONST: + case MONO_PATCH_INFO_METHOD_JUMP: { guint32 image_index, token; image_index = (guint32)data >> 24; @@ -461,11 +528,31 @@ mono_aot_get_method_inner (MonoDomain *domain, MonoMethod *method) break; } + case MONO_PATCH_INFO_WRAPPER: { + guint32 image_index, token; + guint32 wrapper_type; + + wrapper_type = (guint32)data[0]; + image_index = (guint32)data[1] >> 24; + token = MONO_TOKEN_METHOD_DEF | ((guint32)data[1] & 0xffffff); + + image = aot_module->image_table [image_index]; + ji->data.method = mono_get_method (image, token, NULL); + g_assert (ji->data.method); + mono_class_init (ji->data.method->klass); + + g_assert (wrapper_type == MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK); + ji->type = MONO_PATCH_INFO_METHOD; + ji->data.method = mono_marshal_get_remoting_invoke_with_check (ji->data.method); + break; + } case MONO_PATCH_INFO_FIELD: case MONO_PATCH_INFO_SFLDA: { - MonoClass *klass = decode_class_info (aot_module, data [1]); + /* The pointer is dword aligned */ + gpointer class_ptr = *(gpointer*)(ALIGN_PTR_TO (&data[1], sizeof (gpointer))); + MonoClass *klass = decode_class_info (aot_module, class_ptr); mono_class_init (klass); - ji->data.field = mono_class_get_field (klass, (guint32)data [0]); + ji->data.field = mono_class_get_field (klass, data [0]); break; } case MONO_PATCH_INFO_INTERNAL_METHOD: @@ -474,7 +561,7 @@ mono_aot_get_method_inner (MonoDomain *domain, MonoMethod *method) //printf ("A: %s.\n", ji->data.name); break; case MONO_PATCH_INFO_SWITCH: - ji->table_size = (int)data [0]; + ji->table_size = data [0]; table = g_new (gpointer, ji->table_size); ji->data.target = table; for (i = 0; i < ji->table_size; i++) { @@ -488,7 +575,8 @@ mono_aot_get_method_inner (MonoDomain *domain, MonoMethod *method) case MONO_PATCH_INFO_LDSTR: case MONO_PATCH_INFO_LDTOKEN: case MONO_PATCH_INFO_TYPE_FROM_HANDLE: - ji->data.target = *data; + image = aot_module->image_table [data [0]]; + ji->data.token = mono_jump_info_token_new (mp, image, data [1]); break; case MONO_PATCH_INFO_EXC_NAME: ji->data.klass = decode_class_info (aot_module, data); @@ -497,34 +585,39 @@ mono_aot_get_method_inner (MonoDomain *domain, MonoMethod *method) ji->data.name = ji->data.klass->name; break; case MONO_PATCH_INFO_METHOD_REL: - ji->data.offset = (int)data [0]; + ji->data.offset = data [0]; break; default: g_warning ("unhandled type %d", ji->type); g_assert_not_reached (); } - - info++; - ji->next = patch_info; - patch_info = ji; } -#ifndef PLATFORM_WIN32 + g_ptr_array_free (patches, TRUE); + + info += 4; + buf_len = *(guint32*)info; + info += 4; + mono_debug_add_aot_method (domain, method, code, info, buf_len); + + if (use_loaded_code) { /* disable write protection */ - page_start = (char *) (((int) (code)) & ~ (PAGESIZE - 1)); - pages = (code + code_len - page_start + PAGESIZE - 1) / PAGESIZE; - err = mprotect (page_start, pages * PAGESIZE, PROT_READ | PROT_WRITE | PROT_EXEC); - g_assert (err == 0); +#ifndef PLATFORM_WIN32 + page_start = (char *) (((int) (code)) & ~ (PAGESIZE - 1)); + pages = (code + code_len - page_start + PAGESIZE - 1) / PAGESIZE; + err = mprotect (page_start, pages * PAGESIZE, PROT_READ | PROT_WRITE | PROT_EXEC); + g_assert (err == 0); #else - { - DWORD oldp; - g_assert (VirtualProtect (code, code_len, PAGE_EXECUTE_READWRITE, &oldp) != 0); - } + { + DWORD oldp; + g_assert (VirtualProtect (code, code_len, PAGE_EXECUTE_READWRITE, &oldp) != 0); + } #endif + } /* Do this outside the lock to avoid deadlocks */ LeaveCriticalSection (&aot_mutex); - mono_arch_patch_code (method, domain, code, patch_info); + mono_arch_patch_code (method, domain, code, patch_info, TRUE); EnterCriticalSection (&aot_mutex); if (aot_module->opts & MONO_OPT_SHARED) @@ -568,15 +661,53 @@ mono_aot_get_method (MonoDomain *domain, MonoMethod *method) return NULL; } +static void +emit_section_change (FILE *fp, const char *section_name, int subsection_index) +{ +#if defined(sparc) + /* For solaris as, GNU as should accept the same */ + fprintf (fp, ".section \"%s\"\n", section_name); +#elif defined(__ppc__) && defined(__MACH__) + /* This needs to be made more precise on mach. */ + fprintf (fp, "%s\n", subsection_index == 0 ? ".text" : ".data"); +#else + fprintf (fp, "%s %d\n", section_name, subsection_index); +#endif +} + +static void +emit_global (FILE *fp, const char *name) +{ +#if defined(__ppc__) && defined(__MACH__) + // mach-o always uses a '_' prefix. + fprintf (fp, ".globl _%s\n", name); +#else + fprintf (fp, ".globl %s\n", name); +#endif +} + +static void +emit_label (FILE *fp, const char *name) +{ +#if defined(__ppc__) && defined(__MACH__) + // mach-o always uses a '_' prefix. + fprintf (fp, "_%s:\n", name); +#else + fprintf (fp, "%s:\n", name); +#endif +} + #if 0 static void write_data_symbol (FILE *fp, const char *name, guint8 *buf, int size, int align) { int i; + emit_section_change (fp, ".text", 1); + fprintf (fp, ".globl %s\n", name); - fprintf (fp, ".text 1 \n\t.align %d\n", align); - fprintf (fp, "\t.type %s,@object\n", name); + fprintf (fp, "\t.align %d\n", align); + fprintf (fp, "\t.type %s,#object\n", name); fprintf (fp, "\t.size %s,%d\n", name, size); fprintf (fp, "%s:\n", name); for (i = 0; i < size; i++) { @@ -589,10 +720,10 @@ write_data_symbol (FILE *fp, const char *name, guint8 *buf, int size, int align) static void write_string_symbol (FILE *fp, const char *name, const char *value) { - fprintf (fp, ".globl %s\n", name); - fprintf (fp, ".text 1\n"); - fprintf (fp, "%s:\n", name); - fprintf (fp, "\t.string \"%s\"\n", value); + emit_section_change (fp, ".text", 1); + emit_global(fp, name); + emit_label(fp, name); + fprintf (fp, "\t%s \"%s\"\n", AS_STRING_DIRECTIVE, value); } static guint32 @@ -636,6 +767,40 @@ emit_image_index (MonoAotCompile *cfg, MonoImage *image) fprintf (cfg->fp, "\t.long %d\n", image_index); } +#if defined(__ppc__) && defined(__MACH__) +static int +ilog2(register int value) +{ + int count = -1; + while (value & ~0xf) count += 4, value >>= 4; + while (value) count++, value >>= 1; + return count; +} +#endif + +static void emit_alignment(FILE *fp, int size) +{ +#if defined(__ppc__) && defined(__MACH__) + // the mach-o assembler specifies alignments as powers of 2. + fprintf (fp, "\t.align %d\t; ilog2\n", ilog2(size)); +#elif defined(__powerpc__) + /* ignore on linux/ppc */ +#else + fprintf (fp, "\t.align %d\n", size); +#endif +} + +static void +emit_pointer (FILE *fp, const char *target) +{ + emit_alignment (fp, sizeof (gpointer)); +#if defined(sparc) && SIZEOF_VOID_P == 8 + fprintf (fp, "\t.xword %s\n", target); +#else + fprintf (fp, "\t.long %s\n", target); +#endif +} + static char * cond_emit_klass_label (MonoAotCompile *cfg, MonoClass *klass) { @@ -649,7 +814,8 @@ cond_emit_klass_label (MonoAotCompile *cfg, MonoClass *klass) el = cond_emit_klass_label (cfg, klass->element_class); } - fprintf (cfg->fp, "\t.align %d\n", sizeof (gpointer)); + emit_alignment(cfg->fp, sizeof (gpointer)); + l1 = g_strdup_printf ("klass_p_%08x_%p", klass->type_token, klass); fprintf (cfg->fp, "%s:\n", l1); fprintf (cfg->fp, "\t.long 0x%08x\n", klass->type_token); @@ -657,7 +823,7 @@ cond_emit_klass_label (MonoAotCompile *cfg, MonoClass *klass) if (el) { fprintf (cfg->fp, "\t.long %d\n", klass->rank); - fprintf (cfg->fp, "\t.long %s\n", el); + emit_pointer (cfg->fp, el); } g_hash_table_insert (cfg->ref_hash, klass, l1); @@ -676,13 +842,13 @@ cond_emit_field_label (MonoAotCompile *cfg, MonoJumpInfo *patch_info) return l1; l2 = cond_emit_klass_label (cfg, field->parent); - fprintf (cfg->fp, "\t.align %d\n", sizeof (gpointer)); + emit_alignment(cfg->fp, sizeof (gpointer)); token = mono_get_field_token (field); g_assert (token); l1 = g_strdup_printf ("klass_p_%08x_%p", token, field); fprintf (cfg->fp, "%s:\n", l1); fprintf (cfg->fp, "\t.long 0x%08x\n", token); - fprintf (cfg->fp, "\t.long %s\n", l2); + emit_pointer (cfg->fp, l2); g_hash_table_insert (cfg->ref_hash, field, l1); @@ -713,7 +879,7 @@ emit_method (MonoAotCompile *acfg, MonoCompile *cfg) GList *l; FILE *tmpfp; int i, j, k, pindex; - guint8 *code, *mname; + guint8 *code, *mname, *mname_p; int func_alignment = 16; GPtrArray *patches; MonoJumpInfo *patch_info; @@ -724,17 +890,22 @@ emit_method (MonoAotCompile *acfg, MonoCompile *cfg) code = cfg->native_code; header = ((MonoMethodNormal*)method)->header; - fprintf (tmpfp, ".text 0\n"); + emit_section_change (tmpfp, ".text", 0); mname = g_strdup_printf ("m_%x", mono_metadata_token_index (method->token)); - fprintf (tmpfp, "\t.align %d\n", func_alignment); - fprintf (tmpfp, ".globl %s\n", mname); + mname_p = g_strdup_printf ("%s_p", mname); + emit_alignment(tmpfp, func_alignment); + emit_global(tmpfp, mname); +#if defined(sparc) + fprintf (tmpfp, "\t.type %s,#function\n", mname); +#elif !(defined(__ppc__) && defined(__MACH__)) fprintf (tmpfp, "\t.type %s,@function\n", mname); - fprintf (tmpfp, "%s:\n", mname); +#endif + emit_label(tmpfp, mname); for (i = 0; i < cfg->code_len; i++) fprintf (tmpfp, ".byte %d\n", (unsigned int) code [i]); - fprintf (tmpfp, ".text 1\n"); + emit_section_change (tmpfp, ".text", 1); /* Sort relocations */ patches = g_ptr_array_new (); @@ -742,6 +913,7 @@ emit_method (MonoAotCompile *acfg, MonoCompile *cfg) g_ptr_array_add (patches, patch_info); g_ptr_array_sort (patches, compare_patches); + /* Emit out of line info for relocations */ j = 0; for (pindex = 0; pindex < patches->len; ++pindex) { patch_info = g_ptr_array_index (patches, pindex); @@ -754,7 +926,7 @@ emit_method (MonoAotCompile *acfg, MonoCompile *cfg) gpointer *table = (gpointer *)patch_info->data.target; int k; - fprintf (tmpfp, "\t.align %d\n", sizeof (gpointer)); + emit_alignment(tmpfp, sizeof (gpointer)); fprintf (tmpfp, "%s_p_%d:\n", mname, j); fprintf (tmpfp, "\t.long %d\n", patch_info->table_size); @@ -779,7 +951,8 @@ emit_method (MonoAotCompile *acfg, MonoCompile *cfg) break; } case MONO_PATCH_INFO_METHODCONST: - case MONO_PATCH_INFO_METHOD: { + case MONO_PATCH_INFO_METHOD: + case MONO_PATCH_INFO_METHOD_JUMP: { /* * The majority of patches are for methods, so we emit * them inline instead of defining a label for them to @@ -795,6 +968,24 @@ emit_method (MonoAotCompile *acfg, MonoCompile *cfg) j++; break; } + case MONO_PATCH_INFO_WRAPPER: { + MonoMethod *m; + guint32 image_index; + guint32 token; + + m = mono_marshal_method_from_wrapper (patch_info->data.method); + image_index = get_image_index (acfg, m->klass->image); + token = m->token; + g_assert (image_index < 256); + g_assert (mono_metadata_token_table (token) == MONO_TABLE_METHOD); + + emit_alignment(tmpfp, sizeof (gpointer)); + fprintf (tmpfp, "%s_p_%d:\n", mname, j); + fprintf (tmpfp, "\t.long %d\n", patch_info->data.method->wrapper_type); + fprintf (tmpfp, "\t.long %d\n", (image_index << 24) + (mono_metadata_token_index (token))); + j++; + break; + } case MONO_PATCH_INFO_FIELD: patch_info->data.name = cond_emit_field_label (acfg, patch_info); j++; @@ -820,25 +1011,26 @@ emit_method (MonoAotCompile *acfg, MonoCompile *cfg) break; } case MONO_PATCH_INFO_R4: - fprintf (tmpfp, "\t.align 8\n"); + emit_alignment(tmpfp, 8); fprintf (tmpfp, "%s_p_%d:\n", mname, j); fprintf (tmpfp, "\t.long 0x%08x\n", *((guint32 *)patch_info->data.target)); j++; break; case MONO_PATCH_INFO_R8: - fprintf (tmpfp, "\t.align 8\n"); + emit_alignment(tmpfp, 8); fprintf (tmpfp, "%s_p_%d:\n", mname, j); fprintf (tmpfp, "\t.long 0x%08x\n", *((guint32 *)patch_info->data.target)); fprintf (tmpfp, "\t.long 0x%08x\n", *((guint32 *)patch_info->data.target + 1)); j++; break; case MONO_PATCH_INFO_METHOD_REL: - fprintf (tmpfp, "\t.align %d\n", sizeof (gpointer)); + emit_alignment(tmpfp, sizeof (gpointer)); fprintf (tmpfp, "%s_p_%d:\n", mname, j); fprintf (tmpfp, "\t.long 0x%08x\n", patch_info->data.offset); j++; break; case MONO_PATCH_INFO_VTABLE: + case MONO_PATCH_INFO_CLASS_INIT: patch_info->data.name = cond_emit_klass_label (acfg, patch_info->data.klass); j++; break; @@ -849,9 +1041,10 @@ emit_method (MonoAotCompile *acfg, MonoCompile *cfg) case MONO_PATCH_INFO_LDSTR: case MONO_PATCH_INFO_LDTOKEN: case MONO_PATCH_INFO_TYPE_FROM_HANDLE: - fprintf (tmpfp, "\t.align 8\n"); + emit_alignment(tmpfp, 8); fprintf (tmpfp, "%s_p_%d:\n", mname, j); - fprintf (tmpfp, "\t.long 0x%08x\n", patch_info->data.token); + fprintf (tmpfp, "\t.long 0x%08x\n", get_image_index (acfg, patch_info->data.token->image)); + fprintf (tmpfp, "\t.long 0x%08x\n", patch_info->data.token->token); j++; break; default: @@ -860,12 +1053,12 @@ emit_method (MonoAotCompile *acfg, MonoCompile *cfg) } } - fprintf (tmpfp, ".globl %s_p\n", mname); - fprintf (tmpfp, "\t.align %d\n", sizeof (gpointer)); - fprintf (tmpfp, "%s_p:\n", mname); + emit_global (tmpfp, mname_p); + emit_alignment (tmpfp, sizeof (gpointer)); + emit_label (tmpfp, mname_p); fprintf (tmpfp, "\t.long %d\n", cfg->code_len); - fprintf (tmpfp, "\t.long %d\n", cfg->used_int_regs); + fprintf (tmpfp, "\t.long %ld\n", (long)cfg->used_int_regs); /* Exception table */ if (header->num_clauses) { @@ -906,6 +1099,8 @@ emit_method (MonoAotCompile *acfg, MonoCompile *cfg) last_offset = 0; j = 0; + + /* First emit the type+position table */ for (pindex = 0; pindex < patches->len; ++pindex) { guint32 offset; patch_info = g_ptr_array_index (patches, pindex); @@ -928,21 +1123,42 @@ emit_method (MonoAotCompile *acfg, MonoCompile *cfg) else { fprintf (tmpfp, "\t.byte %d\n", (patch_info->type << 2) + 3); fprintf (tmpfp, "\t.byte %d\n", 255); + emit_alignment(tmpfp, 4); fprintf (tmpfp, "\t.long %d\n", offset); } + } + + /* + * 0 is PATCH_INFO_BB, which can't be in the file. + */ + /* NULL terminated array */ + fprintf (tmpfp, "\t.byte 0\n"); + + emit_alignment (tmpfp, sizeof (gpointer)); + + /* Then emit the other info */ + for (pindex = 0; pindex < patches->len; ++pindex) { + patch_info = g_ptr_array_index (patches, pindex); + + if ((patch_info->type == MONO_PATCH_INFO_LABEL) || + (patch_info->type == MONO_PATCH_INFO_BB)) + /* Nothing to do */ + continue; switch (patch_info->type) { case MONO_PATCH_INFO_METHODCONST: case MONO_PATCH_INFO_METHOD: + case MONO_PATCH_INFO_METHOD_JUMP: case MONO_PATCH_INFO_CLASS: case MONO_PATCH_INFO_IID: case MONO_PATCH_INFO_FIELD: case MONO_PATCH_INFO_INTERNAL_METHOD: case MONO_PATCH_INFO_IMAGE: case MONO_PATCH_INFO_VTABLE: + case MONO_PATCH_INFO_CLASS_INIT: case MONO_PATCH_INFO_SFLDA: case MONO_PATCH_INFO_EXC_NAME: - fprintf (tmpfp, "\t.long %s\n", patch_info->data.name); + emit_pointer (tmpfp, patch_info->data.name); j++; break; case MONO_PATCH_INFO_SWITCH: @@ -952,9 +1168,13 @@ emit_method (MonoAotCompile *acfg, MonoCompile *cfg) case MONO_PATCH_INFO_LDSTR: case MONO_PATCH_INFO_LDTOKEN: case MONO_PATCH_INFO_TYPE_FROM_HANDLE: - fprintf (tmpfp, "\t.long %s_p_%d\n", mname, j); + case MONO_PATCH_INFO_WRAPPER: { + char buf [256]; + sprintf (buf, "%s_p_%d", mname, j); + emit_pointer (tmpfp, buf); j++; break; + } case MONO_PATCH_INFO_LABEL: case MONO_PATCH_INFO_BB: break; @@ -966,15 +1186,25 @@ emit_method (MonoAotCompile *acfg, MonoCompile *cfg) } } - /* - * 0 is PATCH_INFO_BB, which can't be in the file. - */ - /* NULL terminated array */ - fprintf (tmpfp, "\t.long 0\n"); + { + guint8 *buf; + guint32 buf_len; + + mono_debug_serialize_debug_info (cfg, &buf, &buf_len); + + fprintf (tmpfp, "\t.long %d\n", buf_len); + + for (i = 0; i < buf_len; ++i) + fprintf (tmpfp, ".byte %d\n", (unsigned int) buf [i]); + + if (buf_len > 0) + g_free (buf); + } /* fixme: save the rest of the required infos */ g_free (mname); + g_free (mname_p); } int @@ -992,7 +1222,7 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts) MonoAotCompile *acfg; gboolean *emitted; - printf ("Mono AOT compiler - compiling assembly %s\n", image->name); + printf ("Mono Ahead of Time compiler - compiling assembly %s\n", image->name); i = g_file_open_tmp ("mono_aot_XXXXXX", &tmpfname, NULL); tmpfp = fdopen (i, "w+"); @@ -1045,7 +1275,7 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts) //printf ("START: %s\n", mono_method_full_name (method, TRUE)); //mono_compile_method (method); - cfg = mini_method_compile (method, opts, mono_root_domain, 0); + cfg = mini_method_compile (method, opts, mono_get_root_domain (), FALSE, 0); g_assert (cfg); if (cfg->disable_aot) { @@ -1069,6 +1299,13 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts) continue; } + /* remoting-invoke-with-check wrappers are very common */ + for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) { + if ((patch_info->type == MONO_PATCH_INFO_METHOD) && + ((patch_info->data.method->wrapper_type == MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK))) + patch_info->type = MONO_PATCH_INFO_WRAPPER; + } + skip = FALSE; for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) { if ((patch_info->type == MONO_PATCH_INFO_METHOD || @@ -1105,24 +1342,24 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts) /* Emit icall table */ symbol = g_strdup_printf ("mono_icall_table"); - fprintf (tmpfp, ".globl %s\n", symbol); - fprintf (tmpfp, ".text 1 \n"); - fprintf (tmpfp, "\t.align 8\n"); - fprintf (tmpfp, "%s:\n", symbol); + emit_section_change (tmpfp, ".text", 1); + emit_global(tmpfp, symbol); + emit_alignment(tmpfp, 8); + emit_label(tmpfp, symbol); fprintf (tmpfp, ".long %d\n", acfg->icall_table->len); for (i = 0; i < acfg->icall_table->len; i++) - fprintf (tmpfp, ".string \"%s\"\n", (char*)g_ptr_array_index (acfg->icall_table, i)); + fprintf (tmpfp, "%s \"%s\"\n", AS_STRING_DIRECTIVE, (char*)g_ptr_array_index (acfg->icall_table, i)); /* Emit image table */ symbol = g_strdup_printf ("mono_image_table"); - fprintf (tmpfp, ".globl %s\n", symbol); - fprintf (tmpfp, ".text 1 \n"); - fprintf (tmpfp, "\t.align 8\n"); - fprintf (tmpfp, "%s:\n", symbol); + emit_section_change (tmpfp, ".text", 1); + emit_global(tmpfp, symbol); + emit_alignment(tmpfp, 8); + emit_label(tmpfp, symbol); fprintf (tmpfp, ".long %d\n", acfg->image_table->len); for (i = 0; i < acfg->image_table->len; i++) - fprintf (tmpfp, ".string \"%s\"\n", ((MonoImage*)g_ptr_array_index (acfg->image_table, i))->guid); + fprintf (tmpfp, "%s \"%s\"\n", AS_STRING_DIRECTIVE, ((MonoImage*)g_ptr_array_index (acfg->image_table, i))->guid); /* * g_module_symbol takes a lot of time for failed lookups, so we emit @@ -1131,10 +1368,10 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts) */ symbol = g_strdup_printf ("mono_methods_present_table"); - fprintf (tmpfp, ".globl %s\n", symbol); - fprintf (tmpfp, ".text 1 \n"); - fprintf (tmpfp, "\t.align 8\n"); - fprintf (tmpfp, "%s:\n", symbol); + emit_section_change (tmpfp, ".text", 1); + emit_global(tmpfp, symbol); + emit_alignment(tmpfp, 8); + emit_label(tmpfp, symbol); { guint32 k, nrows; guint32 w; @@ -1153,13 +1390,31 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts) fclose (tmpfp); +#if defined(sparc) && SIZEOF_VOID_P == 8 + com = g_strdup_printf ("as -xarch=v9 %s -o %s.o", tmpfname, tmpfname); +#else com = g_strdup_printf ("as %s -o %s.o", tmpfname, tmpfname); +#endif printf ("Executing the native assembler: %s\n", com); - system (com); + if (system (com) != 0) { + g_free (com); + return 1; + } + g_free (com); +#if defined(sparc) + com = g_strdup_printf ("ld -shared -G -o %s%s %s.o", image->name, SHARED_EXT, tmpfname); +#elif defined(__ppc__) && defined(__MACH__) + com = g_strdup_printf ("gcc -dynamiclib -o %s%s %s.o", image->name, SHARED_EXT, tmpfname); +#else com = g_strdup_printf ("ld -shared -o %s%s %s.o", image->name, SHARED_EXT, tmpfname); +#endif printf ("Executing the native linker: %s\n", com); - system (com); + if (system (com) != 0) { + g_free (com); + return 1; + } + g_free (com); com = g_strdup_printf ("%s.o", tmpfname); unlink (com); @@ -1169,11 +1424,12 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts) system (com); g_free (com);*/ - printf ("Compiled %d out of %d methods (%d%%)\n", ccount, mcount, (ccount*100)/mcount); - printf ("%d methods contain absolute addresses (%d%%)\n", abscount, (abscount*100)/mcount); - printf ("%d methods contain wrapper references (%d%%)\n", wrappercount, (wrappercount*100)/mcount); - printf ("%d methods contain lmf pointers (%d%%)\n", lmfcount, (lmfcount*100)/mcount); - printf ("%d methods have other problems (%d%%)\n", ocount, (ocount*100)/mcount); + printf ("Compiled %d out of %d methods (%d%%)\n", ccount, mcount, mcount ? (ccount*100)/mcount : 100); + printf ("%d methods contain absolute addresses (%d%%)\n", abscount, mcount ? (abscount*100)/mcount : 100); + printf ("%d methods contain wrapper references (%d%%)\n", wrappercount, mcount ? (wrappercount*100)/mcount : 100); + printf ("%d methods contain lmf pointers (%d%%)\n", lmfcount, mcount ? (lmfcount*100)/mcount : 100); + printf ("%d methods have other problems (%d%%)\n", ocount, mcount ? (ocount*100)/mcount : 100); + //printf ("Retained input file.\n"); unlink (tmpfname); return 0;