X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mono%2Fmini%2Faot.c;h=2850065c92558d0671c69220006923ddd8e58704;hb=517f581ae811a973c6221234e85ba455384c315a;hp=aef8eb3bd445a143be9920ccaa706f0ac427a446;hpb=0cbdf5ddf6ebe75259de9b1e2287aad1c26b05d0;p=mono.git diff --git a/mono/mini/aot.c b/mono/mini/aot.c index aef8eb3bd44..2850065c925 100644 --- a/mono/mini/aot.c +++ b/mono/mini/aot.c @@ -35,10 +35,11 @@ #include #include #include -#include #include "mini.h" +#ifndef DISABLE_AOT + #ifdef PLATFORM_WIN32 #define SHARED_EXT ".dll" #elif defined(__ppc__) && defined(__MACH__) @@ -56,43 +57,45 @@ #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 { char *aot_name; /* Optimization flags used to compile the module */ guint32 opts; - /* Maps MonoMethods to MonoAotMethodInfos */ - MonoGHashTable *methods; /* Pointer to the Global Offset Table */ gpointer *got; + guint32 got_size; char **icall_table; MonoAssemblyName *image_names; char **image_guids; MonoImage **image_table; - guint32* methods_present_table; - gboolean cleanup; + gboolean out_of_date; + guint8 *code; + guint32 *code_offsets; + guint8 *method_infos; + guint32 *method_info_offsets; + guint8 *class_infos; + guint32 *class_info_offsets; } MonoAotModule; +typedef struct MonoAotOptions { + char *outfile; + gboolean save_temps; + gboolean write_symbols; +} MonoAotOptions; + typedef struct MonoAotCompile { + MonoImage *image; FILE *fp; - GHashTable *ref_hash; GHashTable *icall_hash; GPtrArray *icall_table; GHashTable *image_hash; GPtrArray *image_table; guint32 got_offset; + guint32 *method_got_offsets; + MonoAotOptions aot_opts; } MonoAotCompile; -typedef struct MonoAotOptions { - char *outfile; -} MonoAotOptions; - -static MonoGHashTable *aot_modules; +static GHashTable *aot_modules; static CRITICAL_SECTION aot_mutex; @@ -121,6 +124,22 @@ 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 gboolean +is_got_patch (MonoJumpInfoType patch_type) +{ +#ifdef __x86_64__ + return TRUE; +#elif defined(__i386__) + return TRUE; +#else + return FALSE; +#endif +} + +/*****************************************************/ +/* AOT RUNTIME */ +/*****************************************************/ + static MonoImage * load_image (MonoAotModule *module, int index) { @@ -129,18 +148,18 @@ load_image (MonoAotModule *module, int index) if (module->image_table [index]) return module->image_table [index]; - if (module->cleanup) + if (module->out_of_date) return NULL; assembly = mono_assembly_load (&module->image_names [index], NULL, &status); if (!assembly) { - module->cleanup = TRUE; + module->out_of_date = TRUE; return NULL; } if (strcmp (assembly->image->guid, module->image_guids [index])) { mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT module %s is out of date (Older than dependency %s).\n", module->aot_name, module->image_names [index].name); - module->cleanup = TRUE; + module->out_of_date = TRUE; return NULL; } @@ -148,24 +167,55 @@ load_image (MonoAotModule *module, int index) return assembly->image; } + +static inline gint32 +decode_value (char *_ptr, char **rptr) +{ + unsigned char *ptr = (unsigned char *) _ptr; + unsigned char b = *ptr; + gint32 len; + + if ((b & 0x80) == 0){ + len = b; + ++ptr; + } else if ((b & 0x40) == 0){ + len = ((b & 0x3f) << 8 | ptr [1]); + ptr += 2; + } else if (b != 0xff) { + len = ((b & 0x1f) << 24) | + (ptr [1] << 16) | + (ptr [2] << 8) | + ptr [3]; + ptr += 4; + } + else { + len = (ptr [1] << 24) | (ptr [2] << 16) | (ptr [3] << 8) | ptr [4]; + ptr += 5; + } + if (rptr) + *rptr = ptr; + + //printf ("DECODE: %d.\n", len); + return len; +} + static MonoClass* -decode_klass_info (MonoAotModule *module, guint32 *info, guint32 **out_info) +decode_klass_info (MonoAotModule *module, char *buf, char **endbuf) { MonoImage *image; MonoClass *klass; - guint32 token, rank; + guint32 token, rank, image_index; - image = load_image (module, info [0]); + image_index = decode_value (buf, &buf); + image = load_image (module, image_index); if (!image) return NULL; - token = info [1]; - info += 2; - if (token) { - klass = mono_class_get (image, token); + token = decode_value (buf, &buf); + if (mono_metadata_token_code (token) == 0) { + klass = mono_class_get (image, MONO_TOKEN_TYPE_DEF + token); } else { - token = info [0]; - rank = info [1]; - info += 2; + token = MONO_TOKEN_TYPE_DEF + decode_value (buf, &buf); + rank = decode_value (buf, &buf); klass = mono_class_get (image, token); g_assert (klass); klass = mono_array_class_get (klass, rank); @@ -173,26 +223,44 @@ decode_klass_info (MonoAotModule *module, guint32 *info, guint32 **out_info) g_assert (klass); mono_class_init (klass); - *out_info = info; + *endbuf = buf; return klass; } static MonoClassField* -decode_field_info (MonoAotModule *module, guint32 *info, guint32 **out_info) +decode_field_info (MonoAotModule *module, char *buf, char **endbuf) { - MonoClass *klass = decode_klass_info (module, info, &info); + MonoClass *klass = decode_klass_info (module, buf, &buf); guint32 token; if (!klass) return NULL; - token = info [0]; - info ++; - *out_info = info; + token = MONO_TOKEN_FIELD_DEF + decode_value (buf, &buf); + + *endbuf = buf; return mono_class_get_field (klass, token); } +static inline MonoImage* +decode_method_ref (MonoAotModule *module, guint32 *token, char *buf, char **endbuf) +{ + guint32 image_index, value; + MonoImage *image; + + value = decode_value (buf, &buf); + *endbuf = buf; + image_index = value >> 24; + *token = MONO_TOKEN_METHOD_DEF | (value & 0xffffff); + + image = load_image (module, image_index); + if (!image) + return NULL; + else + return image; +} + G_GNUC_UNUSED static void make_writable (guint8* addr, guint32 len) @@ -331,6 +399,7 @@ load_aot_module (MonoAssembly *assembly, gpointer user_data) #ifdef MONO_ARCH_HAVE_PIC_AOT gpointer *got_addr = NULL; gpointer *got = NULL; + guint32 *got_size_ptr = NULL; #endif if (mono_compile_aot) @@ -356,12 +425,6 @@ load_aot_module (MonoAssembly *assembly, gpointer user_data) 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); -#ifdef MONO_ARCH_HAVE_PIC_AOT - g_module_symbol (assembly->aot_module, "got_addr", (gpointer *)&got_addr); - g_assert (got_addr); - got = (gpointer*)*got_addr; - g_assert (got); -#endif if (!aot_version || strcmp (aot_version, MONO_AOT_FILE_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); @@ -381,18 +444,21 @@ load_aot_module (MonoAssembly *assembly, gpointer user_data) return; } - /* - * It seems that MonoGHashTables are in the GC heap, so structures - * containing them must be in the GC heap as well :( - */ -#ifdef HAVE_BOEHM_GC - info = GC_MALLOC (sizeof (MonoAotModule)); -#else - info = g_new0 (MonoAotModule, 1); +#ifdef MONO_ARCH_HAVE_PIC_AOT + g_module_symbol (assembly->aot_module, "got_addr", (gpointer *)&got_addr); + g_assert (got_addr); + got = (gpointer*)*got_addr; + g_assert (got); + g_module_symbol (assembly->aot_module, "got_size", (gpointer *)&got_size_ptr); + g_assert (got_size_ptr); #endif + + info = g_new0 (MonoAotModule, 1); info->aot_name = aot_name; - info->methods = mono_g_hash_table_new (NULL, NULL); +#ifdef MONO_ARCH_HAVE_PIC_AOT info->got = got; + info->got_size = *got_size_ptr; +#endif sscanf (opt_flags, "%d", &info->opts); /* Read image table */ @@ -452,12 +518,16 @@ load_aot_module (MonoAssembly *assembly, gpointer user_data) } } - /* Read methods present table */ - g_module_symbol (assembly->aot_module, "mono_methods_present_table", (gpointer *)&info->methods_present_table); - g_assert (info->methods_present_table); + /* Read method and method_info tables */ + g_module_symbol (assembly->aot_module, "method_offsets", (gpointer*)&info->code_offsets); + g_module_symbol (assembly->aot_module, "methods", (gpointer*)&info->code); + g_module_symbol (assembly->aot_module, "method_info_offsets", (gpointer*)&info->method_info_offsets); + g_module_symbol (assembly->aot_module, "method_infos", (gpointer*)&info->method_infos); + g_module_symbol (assembly->aot_module, "class_infos", (gpointer*)&info->class_infos); + g_module_symbol (assembly->aot_module, "class_info_offsets", (gpointer*)&info->class_info_offsets); EnterCriticalSection (&aot_mutex); - mono_g_hash_table_insert (aot_modules, assembly, info); + g_hash_table_insert (aot_modules, assembly, info); LeaveCriticalSection (&aot_mutex); mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT loaded AOT Module for %s.\n", assembly->image->name); @@ -467,9 +537,7 @@ void mono_aot_init (void) { InitializeCriticalSection (&aot_mutex); - - MONO_GC_REGISTER_ROOT (aot_modules); - aot_modules = mono_g_hash_table_new (NULL, NULL); + aot_modules = g_hash_table_new (NULL, NULL); mono_install_assembly_load_hook (load_aot_module, NULL); @@ -478,6 +546,131 @@ mono_aot_init (void) if (getenv ("MONO_AOT_CACHE")) use_aot_cache = TRUE; } + +static gboolean +decode_cached_class_info (MonoAotModule *module, MonoCachedClassInfo *info, char *buf, char **endbuf) +{ + guint32 flags; + + info->vtable_size = decode_value (buf, &buf); + flags = decode_value (buf, &buf); + info->ghcimpl = (flags >> 0) & 0x1; + info->has_finalize = (flags >> 1) & 0x1; + info->has_cctor = (flags >> 2) & 0x1; + if (info->has_cctor) { + MonoImage *cctor_image = decode_method_ref (module, &info->cctor_token, buf, &buf); + if (!cctor_image) + return FALSE; + } + if (info->has_finalize) { + info->finalize_image = decode_method_ref (module, &info->finalize_token, buf, &buf); + if (!info->finalize_image) + return FALSE; + } + + *endbuf = buf; + + return TRUE; +} + +gboolean +mono_aot_init_vtable (MonoVTable *vtable) +{ + int i; + MonoAotModule *aot_module; + MonoClass *klass = vtable->klass; + guint8 *info; + MonoCachedClassInfo class_info; + char *p; + gboolean err; + + if (MONO_CLASS_IS_INTERFACE (klass) || klass->rank || !klass->image->assembly->aot_module) + return FALSE; + + EnterCriticalSection (&aot_mutex); + + aot_module = (MonoAotModule*) g_hash_table_lookup (aot_modules, klass->image->assembly); + if (!aot_module) { + LeaveCriticalSection (&aot_mutex); + return FALSE; + } + + info = &aot_module->class_infos [aot_module->class_info_offsets [mono_metadata_token_index (klass->type_token) - 1]]; + p = (char*)info; + + err = decode_cached_class_info (aot_module, &class_info, p, &p); + if (!err) { + LeaveCriticalSection (&aot_mutex); + return FALSE; + } + + //printf ("VT0: %s.%s %d\n", klass->name_space, klass->name, vtable_size); + for (i = 0; i < class_info.vtable_size; ++i) { + guint32 image_index, token, value; + MonoImage *image; + MonoMethod *m; + + vtable->vtable [i] = 0; + + value = decode_value (p, &p); + if (!value) + continue; + + image_index = value >> 24; + token = MONO_TOKEN_METHOD_DEF | (value & 0xffffff); + + image = load_image (aot_module, image_index); + if (!image) { + LeaveCriticalSection (&aot_mutex); + return FALSE; + } + +#ifdef MONO_ARCH_HAVE_CREATE_TRAMPOLINE_FROM_TOKEN + vtable->vtable [i] = mono_create_jit_trampoline_from_token (image, token); +#else + m = mono_get_method (image, token, NULL); + g_assert (m); + + //printf ("M: %d %p %s\n", i, &(vtable->vtable [i]), mono_method_full_name (m, TRUE)); + vtable->vtable [i] = mono_create_jit_trampoline (m); +#endif + } + + LeaveCriticalSection (&aot_mutex); + + return TRUE; +} + +gboolean +mono_aot_get_cached_class_info (MonoClass *klass, MonoCachedClassInfo *res) +{ + MonoAotModule *aot_module; + char *p; + gboolean err; + + if (MONO_CLASS_IS_INTERFACE (klass) || klass->rank || !klass->image->assembly->aot_module) + return FALSE; + + EnterCriticalSection (&aot_mutex); + + aot_module = (MonoAotModule*) g_hash_table_lookup (aot_modules, klass->image->assembly); + if (!aot_module) { + LeaveCriticalSection (&aot_mutex); + return FALSE; + } + + p = &aot_module->class_infos [aot_module->class_info_offsets [mono_metadata_token_index (klass->type_token) - 1]]; + + err = decode_cached_class_info (aot_module, res, p, &p); + if (!err) { + LeaveCriticalSection (&aot_mutex); + return FALSE; + } + + LeaveCriticalSection (&aot_mutex); + + return TRUE; +} static MonoJitInfo * mono_aot_get_method_inner (MonoDomain *domain, MonoMethod *method) @@ -485,14 +678,9 @@ mono_aot_get_method_inner (MonoDomain *domain, MonoMethod *method) MonoClass *klass = method->klass; MonoAssembly *ass = klass->image->assembly; GModule *module = ass->aot_module; - char method_label [256]; - char info_label [256]; guint8 *code = NULL; guint8 *info; MonoAotModule *aot_module; - MonoAotMethod *minfo; - MonoJitInfo *jinfo; - MonoMethodHeader *header; if (!module) return NULL; @@ -509,9 +697,7 @@ mono_aot_get_method_inner (MonoDomain *domain, MonoMethod *method) (method->flags & METHOD_ATTRIBUTE_ABSTRACT)) return NULL; - header = mono_method_get_header (method); - - aot_module = (MonoAotModule*)mono_g_hash_table_lookup (aot_modules, ass); + aot_module = (MonoAotModule*) g_hash_table_lookup (aot_modules, ass); g_assert (klass->inited); @@ -519,46 +705,20 @@ mono_aot_get_method_inner (MonoDomain *domain, MonoMethod *method) /* Non shared AOT code can't be used in other appdomains */ return NULL; - minfo = mono_g_hash_table_lookup (aot_module->methods, method); - /* 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)); - if (jinfo->clauses) { - jinfo->clauses = - mono_mempool_alloc0 (domain->mp, sizeof (MonoJitExceptionInfo) * header->num_clauses); - memcpy (jinfo->clauses, minfo->info->clauses, sizeof (MonoJitExceptionInfo) * header->num_clauses); - } - - return jinfo; - } - - /* Do a fast check to see whenever the method exists */ - { - guint32 index = mono_metadata_token_index (method->token) - 1; - guint32 w; - w = aot_module->methods_present_table [index / 32]; - if (! (w & (1 << (index % 32)))) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_AOT, "AOT NOT FOUND: %s.\n", mono_method_full_name (method, TRUE)); - return NULL; - } - } - - if (aot_module->cleanup) + if (aot_module->out_of_date) return NULL; - sprintf (method_label, "m_%x", mono_metadata_token_index (method->token)); - - if (!g_module_symbol (module, method_label, (gpointer *)&code)) + if (aot_module->code_offsets [mono_metadata_token_index (method->token) - 1] == 0xffffffff) { + if (mono_trace_is_traced (G_LOG_LEVEL_DEBUG, MONO_TRACE_AOT)) { + char *full_name = mono_method_full_name (method, TRUE); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_AOT, "AOT NOT FOUND: %s.\n", full_name); + g_free (full_name); + } return NULL; + } - sprintf (info_label, "%s_p", method_label); - - if (!g_module_symbol (module, info_label, (gpointer *)&info)) - return NULL; + code = &aot_module->code [aot_module->code_offsets [mono_metadata_token_index (method->token) - 1]]; + info = &aot_module->method_infos [aot_module->method_info_offsets [mono_metadata_token_index (method->token) - 1]]; if (mono_last_aot_method != -1) { if (mono_jit_stats.methods_aot > mono_last_aot_method) @@ -577,22 +737,17 @@ mono_aot_load_method (MonoDomain *domain, MonoAotModule *aot_module, MonoMethod MonoClass *klass = method->klass; MonoJumpInfo *patch_info = NULL; guint code_len, used_int_regs, used_strings; - MonoAotMethod *minfo; MonoJitInfo *jinfo; - MonoMethodHeader *header = mono_method_get_header (method); MonoMemPool *mp; GPtrArray *patches; int i, pindex, got_index; + gboolean non_got_patches, keep_patches = TRUE; + gboolean has_clauses; + char *p; - minfo = g_new0 (MonoAotMethod, 1); - - minfo->domain = domain; - jinfo = mono_mempool_alloc0 (domain->mp, sizeof (MonoJitInfo)); - - code_len = *(guint32*)info; - info += 4; - used_int_regs = *(guint32*)info; - info += 4; + p = (char*)info; + code_len = decode_value (p, &p); + used_int_regs = decode_value (p, &p); if (!use_loaded_code) { guint8 *code2; @@ -602,90 +757,89 @@ mono_aot_load_method (MonoDomain *domain, MonoAotModule *aot_module, MonoMethod code = code2; } - 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); + if (mono_trace_is_traced (G_LOG_LEVEL_DEBUG, MONO_TRACE_AOT)) { + char *full_name = mono_method_full_name (method, TRUE); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_AOT, "AOT FOUND AOT compiled code for %s %p - %p %p\n", full_name, code, code + code_len, info); + g_free (full_name); + } /* Exception table */ - if (header->num_clauses) { - jinfo->clauses = - mono_mempool_alloc0 (domain->mp, sizeof (MonoJitExceptionInfo) * header->num_clauses); + has_clauses = decode_value (p, &p); + if (has_clauses) { + MonoMethodHeader *header = mono_method_get_header (method); + jinfo = + mono_mempool_alloc0 (domain->mp, sizeof (MonoJitInfo) + (sizeof (MonoJitExceptionInfo) * header->num_clauses)); jinfo->num_clauses = header->num_clauses; - jinfo->exvar_offset = *(guint32*)info; - info += 4; - for (i = 0; i < header->num_clauses; ++i) { MonoExceptionClause *ec = &header->clauses [i]; MonoJitExceptionInfo *ei = &jinfo->clauses [i]; ei->flags = ec->flags; + ei->exvar_offset = decode_value (p, &p); + if (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER) - ei->data.filter = code + *(guint32*)info; + ei->data.filter = code + decode_value (p, &p); else ei->data.catch_class = ec->data.catch_class; - 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; + + ei->try_start = code + decode_value (p, &p); + ei->try_end = code + decode_value (p, &p); + ei->handler_start = code + decode_value (p, &p); } } + else + jinfo = mono_mempool_alloc0 (domain->mp, sizeof (MonoJitInfo)); - if (aot_module->opts & MONO_OPT_SHARED) { - used_strings = *(guint32*)info; - info += 4; - } + if (aot_module->opts & MONO_OPT_SHARED) + used_strings = decode_value (p, &p); else used_strings = 0; for (i = 0; i < used_strings; i++) { - guint token = *(guint32*)info; - info += 4; + guint token = decode_value (p, &p); mono_ldstr (mono_get_root_domain (), klass->image, mono_metadata_token_index (token)); } + if (aot_module->opts & MONO_OPT_SHARED) + keep_patches = FALSE; + #ifdef MONO_ARCH_HAVE_PIC_AOT - got_index = *(guint32*)info; - info += 4; + got_index = decode_value (p, &p); + keep_patches = FALSE; #endif - if (*info) { + if (*p) { MonoImage *image; gpointer *table; int i; guint32 last_offset, buf_len; - guint32 *info32; - if (aot_module->opts & MONO_OPT_SHARED) - mp = mono_mempool_new (); - else + if (keep_patches) mp = domain->mp; + else + mp = mono_mempool_new (); /* First load the type + offset table */ last_offset = 0; patches = g_ptr_array_new (); - while (*info) { + while (*p) { MonoJumpInfo *ji = mono_mempool_alloc0 (mp, sizeof (MonoJumpInfo)); -#ifdef MONO_ARCH_HAVE_PIC_AOT - ji->type = *(guint8*)info; - info ++; +#if defined(MONO_ARCH_HAVE_PIC_AOT) + ji->type = *p; + p ++; #else guint8 b1, b2; - b1 = *(guint8*)info; - b2 = *((guint8*)info + 1); - - info += 2; + b1 = *(guint8*)p; + b2 = *((guint8*)p + 1); + p += 2; ji->type = b1 >> 2; - if (((b1 & (1 + 2)) == 3) && (b2 == 255)) { - info = ALIGN_PTR_TO (info, 4); - ji->ip.i = *(guint32*)info; - info += 4; - } + if (((b1 & (1 + 2)) == 3) && (b2 == 255)) + ji->ip.i = decode_value (p, &p); else ji->ip.i = (((guint32)(b1 & (1 + 2))) << 8) + b2; @@ -699,11 +853,9 @@ mono_aot_load_method (MonoDomain *domain, MonoAotModule *aot_module, MonoMethod g_ptr_array_add (patches, ji); } - info ++; - - info = ALIGN_PTR_TO (info, sizeof (gpointer)); - info32 = (guint32*)info; + /* Null terminated array */ + p ++; /* Then load the other data */ for (pindex = 0; pindex < patches->len; ++pindex) { @@ -714,24 +866,23 @@ mono_aot_load_method (MonoDomain *domain, MonoAotModule *aot_module, MonoMethod case MONO_PATCH_INFO_IID: case MONO_PATCH_INFO_VTABLE: case MONO_PATCH_INFO_CLASS_INIT: - ji->data.klass = decode_klass_info (aot_module, info32, &info32); + ji->data.klass = decode_klass_info (aot_module, p, &p); if (!ji->data.klass) goto cleanup; break; case MONO_PATCH_INFO_IMAGE: - ji->data.image = load_image (aot_module, info32 [0]); + ji->data.image = load_image (aot_module, decode_value (p, &p)); if (!ji->data.image) goto cleanup; - g_assert (ji->data.image); - info32 ++; break; case MONO_PATCH_INFO_METHOD: case MONO_PATCH_INFO_METHODCONST: case MONO_PATCH_INFO_METHOD_JUMP: { - guint32 image_index, token; + guint32 image_index, token, value; - image_index = info32 [0] >> 24; - token = MONO_TOKEN_METHOD_DEF | (info32 [0] & 0xffffff); + value = decode_value (p, &p); + image_index = value >> 24; + token = MONO_TOKEN_METHOD_DEF | (value & 0xffffff); image = load_image (aot_module, image_index); if (!image) @@ -739,22 +890,21 @@ mono_aot_load_method (MonoDomain *domain, MonoAotModule *aot_module, MonoMethod ji->data.method = mono_get_method (image, token, NULL); g_assert (ji->data.method); mono_class_init (ji->data.method->klass); - info32 ++; break; } case MONO_PATCH_INFO_WRAPPER: { guint32 wrapper_type; - wrapper_type = info32 [0]; - info32 ++; + wrapper_type = decode_value (p, &p); switch (wrapper_type) { case MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK: { - guint32 image_index, token; + guint32 image_index, token, value; - image_index = info32 [0] >> 24; - token = MONO_TOKEN_METHOD_DEF | (info32 [0] & 0xffffff); + value = decode_value (p, &p); + image_index = value >> 24; + token = MONO_TOKEN_METHOD_DEF | (value & 0xffffff); image = load_image (aot_module, image_index); if (!image) @@ -765,29 +915,39 @@ mono_aot_load_method (MonoDomain *domain, MonoAotModule *aot_module, MonoMethod ji->type = MONO_PATCH_INFO_METHOD; ji->data.method = mono_marshal_get_remoting_invoke_with_check (ji->data.method); - info32 ++; break; } case MONO_WRAPPER_PROXY_ISINST: { - MonoClass *klass = decode_klass_info (aot_module, info32, &info32); + MonoClass *klass = decode_klass_info (aot_module, p, &p); if (!klass) goto cleanup; - ji->type = MONO_PATCH_INFO_METHODCONST; + ji->type = MONO_PATCH_INFO_METHOD; ji->data.method = mono_marshal_get_proxy_cancast (klass); break; } case MONO_WRAPPER_LDFLD: - case MONO_WRAPPER_STFLD: { - MonoClass *klass = decode_klass_info (aot_module, info32, &info32); + case MONO_WRAPPER_STFLD: + case MONO_WRAPPER_LDFLD_REMOTE: + case MONO_WRAPPER_STFLD_REMOTE: + case MONO_WRAPPER_ISINST: { + MonoClass *klass = decode_klass_info (aot_module, p, &p); if (!klass) goto cleanup; ji->type = MONO_PATCH_INFO_METHOD; if (wrapper_type == MONO_WRAPPER_LDFLD) ji->data.method = mono_marshal_get_ldfld_wrapper (&klass->byval_arg); - else + else if (wrapper_type == MONO_WRAPPER_STFLD) ji->data.method = mono_marshal_get_stfld_wrapper (&klass->byval_arg); + else if (wrapper_type == MONO_WRAPPER_LDFLD_REMOTE) + ji->data.method = mono_marshal_get_ldfld_remote_wrapper (klass); + else + ji->data.method = mono_marshal_get_isinst (klass); break; } + case MONO_WRAPPER_STELEMREF: + ji->type = MONO_PATCH_INFO_METHOD; + ji->data.method = mono_marshal_get_stelemref (); + break; default: g_assert_not_reached (); } @@ -795,52 +955,62 @@ mono_aot_load_method (MonoDomain *domain, MonoAotModule *aot_module, MonoMethod } case MONO_PATCH_INFO_FIELD: case MONO_PATCH_INFO_SFLDA: - ji->data.field = decode_field_info (aot_module, info32, &info32); + ji->data.field = decode_field_info (aot_module, p, &p); if (!ji->data.field) goto cleanup; break; case MONO_PATCH_INFO_INTERNAL_METHOD: - ji->data.name = aot_module->icall_table [info32 [0]]; + ji->data.name = aot_module->icall_table [decode_value (p, &p)]; g_assert (ji->data.name); - info32 ++; - //printf ("A: %s.\n", ji->data.name); break; case MONO_PATCH_INFO_SWITCH: - ji->table_size = info32 [0]; - table = g_new (gpointer, ji->table_size); - ji->data.target = table; - for (i = 0; i < ji->table_size; i++) { - table [i] = (gpointer)(gssize)info32 [i + 1]; - } - info32 += (ji->table_size + 1); + ji->data.table = mono_mempool_alloc0 (mp, sizeof (MonoJumpInfoBBTable)); + ji->data.table->table_size = decode_value (p, &p); + table = g_new (gpointer, ji->data.table->table_size); + ji->data.table->table = (MonoBasicBlock**)table; + for (i = 0; i < ji->data.table->table_size; i++) + table [i] = (gpointer)(gssize)decode_value (p, &p); break; - case MONO_PATCH_INFO_R4: - ji->data.target = info32; - info32 ++; + case MONO_PATCH_INFO_R4: { + guint32 val; + + ji->data.target = mono_mempool_alloc0 (mp, sizeof (float)); + val = decode_value (p, &p); + *(float*)ji->data.target = *(float*)&val; break; - case MONO_PATCH_INFO_R8: - info32 = ALIGN_PTR_TO (info32, 8); - ji->data.target = info32; - info32 += 2; + } + case MONO_PATCH_INFO_R8: { + guint32 val [2]; + + ji->data.target = mono_mempool_alloc0 (mp, sizeof (double)); + + val [0] = decode_value (p, &p); + val [1] = decode_value (p, &p); + *(double*)ji->data.target = *(double*)val; break; + } case MONO_PATCH_INFO_LDSTR: + image = load_image (aot_module, decode_value (p, &p)); + if (!image) + goto cleanup; + ji->data.token = mono_jump_info_token_new (mp, image, MONO_TOKEN_STRING + decode_value (p, &p)); + break; + case MONO_PATCH_INFO_DECLSEC: case MONO_PATCH_INFO_LDTOKEN: case MONO_PATCH_INFO_TYPE_FROM_HANDLE: - image = load_image (aot_module, info32 [0]); + image = load_image (aot_module, decode_value (p, &p)); if (!image) goto cleanup; - ji->data.token = mono_jump_info_token_new (mp, image, info32 [1]); - info32 += 2; + ji->data.token = mono_jump_info_token_new (mp, image, decode_value (p, &p)); break; case MONO_PATCH_INFO_EXC_NAME: - ji->data.klass = decode_klass_info (aot_module, info32, &info32); + ji->data.klass = decode_klass_info (aot_module, p, &p); if (!ji->data.klass) goto cleanup; ji->data.name = ji->data.klass->name; break; case MONO_PATCH_INFO_METHOD_REL: - ji->data.offset = info32 [0]; - info32 ++; + ji->data.offset = decode_value (p, &p); break; default: g_warning ("unhandled type %d", ji->type); @@ -848,21 +1018,32 @@ mono_aot_load_method (MonoDomain *domain, MonoAotModule *aot_module, MonoMethod } } - info = (guint8*)info32; - - buf_len = *(guint32*)info; - info += 4; - mono_debug_add_aot_method (domain, method, code, info, buf_len); + buf_len = decode_value (p, &p); + mono_debug_add_aot_method (domain, method, code, p, buf_len); #if MONO_ARCH_HAVE_PIC_AOT mono_arch_flush_icache (code, code_len); + if (non_got_patches) + make_writable (code, code_len); + /* Do this outside the lock to avoid deadlocks */ LeaveCriticalSection (&aot_mutex); + non_got_patches = FALSE; for (pindex = 0; pindex < patches->len; ++pindex) { MonoJumpInfo *ji = g_ptr_array_index (patches, pindex); - aot_module->got [got_index + pindex] = mono_resolve_patch_target (method, domain, code, ji, TRUE); + if (is_got_patch (ji->type)) { + aot_module->got [got_index] = mono_resolve_patch_target (method, domain, code, ji, TRUE); + got_index ++; + ji->type = MONO_PATCH_INFO_NONE; + } + else + non_got_patches = TRUE; + } + if (non_got_patches) { + make_writable (code, code_len); + mono_arch_patch_code (method, domain, code, patch_info, TRUE); } EnterCriticalSection (&aot_mutex); #else @@ -874,15 +1055,12 @@ mono_aot_load_method (MonoDomain *domain, MonoAotModule *aot_module, MonoMethod LeaveCriticalSection (&aot_mutex); mono_arch_patch_code (method, domain, code, patch_info, TRUE); EnterCriticalSection (&aot_mutex); -#endif +#endif g_ptr_array_free (patches, TRUE); - if (aot_module->opts & MONO_OPT_SHARED) - /* No need to cache patches */ + if (!keep_patches) mono_mempool_destroy (mp); - else - minfo->patch_info = patch_info; } mono_jit_stats.methods_aot++; @@ -893,14 +1071,11 @@ mono_aot_load_method (MonoDomain *domain, MonoAotModule *aot_module, MonoMethod jinfo->method = method; jinfo->code_start = code; #ifdef MONO_ARCH_HAVE_PIC_AOT - jinfo->domain_neutral = 1; + jinfo->domain_neutral = 0; #else jinfo->domain_neutral = (aot_module->opts & MONO_OPT_SHARED) != 0; #endif - minfo->info = jinfo; - mono_g_hash_table_insert (aot_module->methods, method, minfo); - return jinfo; } @@ -933,6 +1108,32 @@ mono_aot_get_method (MonoDomain *domain, MonoMethod *method) return NULL; } +gboolean +mono_aot_is_got_entry (guint8 *code, guint8 *addr) +{ + MonoJitInfo *ji; + MonoAssembly *ass; + MonoAotModule *aot_module; + + ji = mono_jit_info_table_find (mono_domain_get (), code); + if (!ji) + return FALSE; + + ass = ji->method->klass->image->assembly; + + if (!aot_modules) + return FALSE; + aot_module = (MonoAotModule*) g_hash_table_lookup (aot_modules, ass); + if (!aot_module || !aot_module->got) + return FALSE; + + return ((addr >= (guint8*)(aot_module->got)) && (addr < (guint8*)(aot_module->got + aot_module->got_size))); +} + +/*****************************************************/ +/* AOT COMPILER */ +/*****************************************************/ + static void emit_section_change (FILE *fp, const char *section_name, int subsection_index) { @@ -961,7 +1162,7 @@ emit_symbol_type (FILE *fp, const char *name, gboolean func) fprintf (fp, "\t.type %s,#%s\n", name, stype); #elif !(defined(__ppc__) && defined(__MACH__)) fprintf (fp, "\t.type %s,@%s\n", name, stype); -#elif defined(__x86_64__) +#elif defined(__x86_64__) || defined(__i386__) fprintf (fp, "\t.type %s,@%s\n", name, stype); #endif } @@ -971,9 +1172,9 @@ emit_global (FILE *fp, const char *name, gboolean func) { #if defined(__ppc__) && defined(__MACH__) // mach-o always uses a '_' prefix. - fprintf (fp, ".globl _%s\n", name); + fprintf (fp, "\t.globl _%s\n", name); #else - fprintf (fp, ".globl %s\n", name); + fprintf (fp, "\t.globl %s\n", name); #endif emit_symbol_type (fp, name, func); @@ -990,33 +1191,50 @@ emit_label (FILE *fp, const char *name) #endif } -#if 0 static void -write_data_symbol (FILE *fp, const char *name, guint8 *buf, int size, int align) +emit_string_symbol (FILE *fp, const char *name, const char *value) { - int i; - emit_section_change (fp, ".text", 1); + emit_global(fp, name, FALSE); + emit_label(fp, name); + fprintf (fp, "\t%s \"%s\"\n", AS_STRING_DIRECTIVE, value); +} - fprintf (fp, ".globl %s\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++) { - fprintf (fp, ".byte %d\n", buf [i]); - } - +#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 -write_string_symbol (FILE *fp, const char *name, const char *value) +static void +emit_alignment(FILE *fp, int size) { - emit_section_change (fp, ".text", 1); - emit_global(fp, name, FALSE); - emit_label(fp, name); - fprintf (fp, "\t%s \"%s\"\n", AS_STRING_DIRECTIVE, value); +#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 +} + +G_GNUC_UNUSED static void +emit_pointer (FILE *fp, const char *target) +{ + emit_alignment (fp, sizeof (gpointer)); +#if defined(__x86_64__) + fprintf (fp, "\t.quad %s\n", target); +#elif defined(sparc) && SIZEOF_VOID_P == 8 + fprintf (fp, "\t.xword %s\n", target); +#else + fprintf (fp, "\t.long %s\n", target); +#endif } static guint32 @@ -1034,6 +1252,42 @@ mono_get_field_token (MonoClassField *field) return 0; } +static inline void +encode_value (gint32 value, char *buf, char **endbuf) +{ + char *p = buf; + + //printf ("ENCODE: %d 0x%x.\n", value, value); + + /* + * Same encoding as the one used in the metadata, extended to handle values + * greater than 0x1fffffff. + */ + if ((value >= 0) && (value <= 127)) + *p++ = value; + else if ((value >= 0) && (value <= 16383)) { + p [0] = 0x80 | (value >> 8); + p [1] = value & 0xff; + p += 2; + } else if ((value >= 0) && (value <= 0x1fffffff)) { + p [0] = (value >> 24) | 0xc0; + p [1] = (value >> 16) & 0xff; + p [2] = (value >> 8) & 0xff; + p [3] = value & 0xff; + p += 4; + } + else { + p [0] = 0xff; + p [1] = (value >> 24) & 0xff; + p [2] = (value >> 16) & 0xff; + p [3] = (value >> 8) & 0xff; + p [4] = value & 0xff; + p += 5; + } + if (endbuf) + *endbuf = p; +} + static guint32 get_image_index (MonoAotCompile *cfg, MonoImage *image) { @@ -1051,61 +1305,46 @@ get_image_index (MonoAotCompile *cfg, MonoImage *image) } static void -emit_klass_info (MonoAotCompile *cfg, MonoClass *klass) +encode_klass_info (MonoAotCompile *cfg, MonoClass *klass, char *buf, char **endbuf) { - fprintf (cfg->fp, "\t.long 0x%08x\n", get_image_index (cfg, klass->image)); - fprintf (cfg->fp, "\t.long 0x%08x\n", klass->type_token); + encode_value (get_image_index (cfg, klass->image), buf, &buf); if (!klass->type_token) { /* Array class */ g_assert (klass->rank > 0); g_assert (klass->element_class->type_token); - fprintf (cfg->fp, "\t.long 0x%08x\n", klass->element_class->type_token); - fprintf (cfg->fp, "\t.long 0x%08x\n", klass->rank); + encode_value (MONO_TOKEN_TYPE_DEF, buf, &buf); + g_assert (mono_metadata_token_code (klass->element_class->type_token) == MONO_TOKEN_TYPE_DEF); + encode_value (klass->element_class->type_token - MONO_TOKEN_TYPE_DEF, buf, &buf); + encode_value (klass->rank, buf, &buf); + } + else { + g_assert (mono_metadata_token_code (klass->type_token) == MONO_TOKEN_TYPE_DEF); + encode_value (klass->type_token - MONO_TOKEN_TYPE_DEF, buf, &buf); } + *endbuf = buf; } static void -emit_field_info (MonoAotCompile *cfg, MonoClassField *field) +encode_field_info (MonoAotCompile *cfg, MonoClassField *field, char *buf, char **endbuf) { - emit_klass_info (cfg, field->parent); - fprintf (cfg->fp, "\t.long 0x%08x\n", mono_get_field_token (field)); + guint32 token = mono_get_field_token (field); + + encode_klass_info (cfg, field->parent, buf, &buf); + g_assert (mono_metadata_token_code (token) == MONO_TOKEN_FIELD_DEF); + encode_value (token - MONO_TOKEN_FIELD_DEF, buf, &buf); + *endbuf = buf; } -#if defined(__ppc__) && defined(__MACH__) -static int -ilog2(register int value) +static void +encode_method_ref (MonoAotCompile *acfg, MonoMethod *method, char *buf, char **endbuf) { - int count = -1; - while (value & ~0xf) count += 4, value >>= 4; - while (value) count++, value >>= 1; - return count; -} -#endif + guint32 image_index = get_image_index (acfg, method->klass->image); + guint32 token = method->token; + g_assert (image_index < 256); + g_assert (mono_metadata_token_table (token) == MONO_TABLE_METHOD); -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 -} - -G_GNUC_UNUSED static void -emit_pointer (FILE *fp, const char *target) -{ - emit_alignment (fp, sizeof (gpointer)); -#if defined(__x86_64__) - fprintf (fp, "\t.quad %s\n", target); -#elif defined(sparc) && SIZEOF_VOID_P == 8 - fprintf (fp, "\t.xword %s\n", target); -#else - fprintf (fp, "\t.long %s\n", target); -#endif + encode_value ((image_index << 24) + (mono_metadata_token_index (token)), buf, &buf); + *endbuf = buf; } static gint @@ -1126,20 +1365,18 @@ compare_patches (gconstpointer a, gconstpointer b) } static void -emit_method (MonoAotCompile *acfg, MonoCompile *cfg) +emit_method_code (MonoAotCompile *acfg, MonoCompile *cfg) { MonoMethod *method; - GList *l; FILE *tmpfp; - int i, j, k, pindex; + int i, j, pindex, byte_index; guint8 *code, *mname, *mname_p; int func_alignment = 16; GPtrArray *patches; MonoJumpInfo *patch_info; MonoMethodHeader *header; - guint32 last_offset; #ifdef MONO_ARCH_HAVE_PIC_AOT - guint32 first_got_offset; + gboolean skip; #endif tmpfp = acfg->fp; @@ -1147,12 +1384,17 @@ emit_method (MonoAotCompile *acfg, MonoCompile *cfg) code = cfg->native_code; header = mono_method_get_header (method); - emit_section_change (tmpfp, ".text", 0); - mname = g_strdup_printf ("m_%x", mono_metadata_token_index (method->token)); + /* Make the labels local */ + mname = g_strdup_printf (".Lm_%x", mono_metadata_token_index (method->token)); mname_p = g_strdup_printf ("%s_p", mname); + emit_alignment(tmpfp, func_alignment); - emit_global(tmpfp, mname, TRUE); emit_label(tmpfp, mname); + if (acfg->aot_opts.write_symbols) + emit_global (tmpfp, mname, TRUE); + + if (cfg->verbose_level > 0) + g_print ("Method %s emitted as %s\n", mono_method_full_name (method, TRUE), mname); /* Sort relocations */ patches = g_ptr_array_new (); @@ -1161,7 +1403,8 @@ emit_method (MonoAotCompile *acfg, MonoCompile *cfg) g_ptr_array_sort (patches, compare_patches); #ifdef MONO_ARCH_HAVE_PIC_AOT - first_got_offset = acfg->got_offset; + acfg->method_got_offsets [mono_metadata_token_index (method->token)] = acfg->got_offset; + byte_index = 0; for (i = 0; i < cfg->code_len; i++) { patch_info = NULL; for (pindex = 0; pindex < patches->len; ++pindex) { @@ -1170,78 +1413,140 @@ emit_method (MonoAotCompile *acfg, MonoCompile *cfg) break; } + skip = FALSE; if (patch_info && (pindex < patches->len)) { switch (patch_info->type) { case MONO_PATCH_INFO_LABEL: case MONO_PATCH_INFO_BB: - fprintf (tmpfp, ".byte %d\n", (unsigned int) code [i]); + case MONO_PATCH_INFO_NONE: + break; + case MONO_PATCH_INFO_GOT_OFFSET: { + guint32 offset = mono_arch_get_patch_offset (code + i); + fprintf (tmpfp, "\n.byte "); + for (j = 0; j < offset; ++j) + fprintf (tmpfp, "%s0x%x", (j == 0) ? "" : ",", (unsigned int) code [i + j]); + fprintf (tmpfp, "\n.int got - . + %d", offset); + + i += offset + 4 - 1; + skip = TRUE; break; + } default: - /* FIXME: This is arch specific */ - for (j = 0; j < mono_arch_get_aot_patch_offset (); ++j) - fprintf (tmpfp, ".byte %d\n", (unsigned int) code [i + j]); - fprintf (tmpfp, ".int got - . + %d\n", (unsigned int) ((acfg->got_offset * sizeof (gpointer)) - 4)); + if (!is_got_patch (patch_info->type)) + break; + fprintf (tmpfp, "\n.byte "); + for (j = 0; j < mono_arch_get_patch_offset (code + i); ++j) + fprintf (tmpfp, "%s0x%x", (j == 0) ? "" : ",", (unsigned int) code [i + j]); +#ifdef __x86_64__ + fprintf (tmpfp, "\n.int got - . + %d", (unsigned int) ((acfg->got_offset * sizeof (gpointer)) - 4)); +#elif defined(__i386__) + fprintf (tmpfp, "\n.int %d\n", (unsigned int) ((acfg->got_offset * sizeof (gpointer)))); +#endif acfg->got_offset ++; - i += mono_arch_get_aot_patch_offset () + 4 - 1; + i += mono_arch_get_patch_offset (code + i) + 4 - 1; + skip = TRUE; } } - else { - fprintf (tmpfp, ".byte %d\n", (unsigned int) code [i]); + + if (!skip) { + if (byte_index == 0) + fprintf (tmpfp, "\n.byte "); + fprintf (tmpfp, "%s0x%x", (byte_index == 0) ? "" : ",", (unsigned int) code [i]); + byte_index = (byte_index + 1) % 32; } + else + byte_index = 0; } #else for (i = 0; i < cfg->code_len; i++) { - fprintf (tmpfp, ".byte %d\n", (unsigned int) code [i]); + fprintf (tmpfp, ".byte 0x%x\n", (unsigned int) code [i]); } #endif + fprintf (tmpfp, "\n"); +} - emit_section_change (tmpfp, ".text", 1); +static void +emit_method_info (MonoAotCompile *acfg, MonoCompile *cfg) +{ + MonoMethod *method; + GList *l; + FILE *tmpfp; + int i, j, k, pindex, buf_size; + guint32 debug_info_size; + guint8 *code, *mname, *mname_p; + GPtrArray *patches; + MonoJumpInfo *patch_info; + MonoMethodHeader *header; + guint32 last_offset; + char *p, *buf; + guint8 *debug_info; +#ifdef MONO_ARCH_HAVE_PIC_AOT + guint32 first_got_offset; +#endif - emit_global (tmpfp, mname_p, FALSE); - emit_alignment (tmpfp, sizeof (gpointer)); - emit_label (tmpfp, mname_p); + tmpfp = acfg->fp; + method = cfg->method; + code = cfg->native_code; + header = mono_method_get_header (method); + + /* Make the labels local */ + mname = g_strdup_printf (".Lm_%x", mono_metadata_token_index (method->token)); + mname_p = g_strdup_printf ("%s_p", mname); + + /* Sort relocations */ + patches = g_ptr_array_new (); + for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) + g_ptr_array_add (patches, patch_info); + g_ptr_array_sort (patches, compare_patches); + +#ifdef MONO_ARCH_HAVE_PIC_AOT + first_got_offset = acfg->method_got_offsets [mono_metadata_token_index (cfg->method->token)]; +#endif - fprintf (tmpfp, "\t.long %d\n", cfg->code_len); - fprintf (tmpfp, "\t.long %ld\n", (long)cfg->used_int_regs); + /**********************/ + /* Encode method info */ + /**********************/ + + buf_size = (patches->len < 1000) ? 40960 : 40960 + (patches->len * 64); + p = buf = g_malloc (buf_size); + + encode_value (cfg->code_len, p, &p); + encode_value (cfg->used_int_regs, p, &p); /* Exception table */ + encode_value (header->num_clauses ? 1 : 0, p, &p); if (header->num_clauses) { MonoJitInfo *jinfo = cfg->jit_info; - fprintf (tmpfp, "\t.long %d\n", jinfo->exvar_offset); - for (k = 0; k < header->num_clauses; ++k) { MonoJitExceptionInfo *ei = &jinfo->clauses [k]; + encode_value (ei->exvar_offset, p, &p); + if (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER) - fprintf (tmpfp, "\t.long %d\n", (gint)((guint8*)ei->data.filter - code)); - else - /* the class is loaded from the header: optimize away later */ - fprintf (tmpfp, "\t.long %d\n", 0); + encode_value ((gint)((guint8*)ei->data.filter - code), p, &p); - fprintf (tmpfp, "\t.long %d\n", (gint)((guint8*)ei->try_start - code)); - fprintf (tmpfp, "\t.long %d\n", (gint)((guint8*)ei->try_end - code)); - fprintf (tmpfp, "\t.long %d\n", (gint)((guint8*)ei->handler_start - code)); + encode_value ((gint)((guint8*)ei->try_start - code), p, &p); + encode_value ((gint)((guint8*)ei->try_end - code), p, &p); + encode_value ((gint)((guint8*)ei->handler_start - code), p, &p); } } /* String table */ if (cfg->opt & MONO_OPT_SHARED) { - fprintf (tmpfp, "\t.long %d\n", g_list_length (cfg->ldstr_list)); + encode_value (g_list_length (cfg->ldstr_list), p, &p); for (l = cfg->ldstr_list; l; l = l->next) { - fprintf (tmpfp, "\t.long 0x%08lx\n", (long)l->data); + encode_value ((long)l->data, p, &p); } } else /* Used only in shared mode */ g_assert (!cfg->ldstr_list); - //printf ("M: %s (%s).\n", mono_method_full_name (method, TRUE), mname); - #ifdef MONO_ARCH_HAVE_PIC_AOT - fprintf (tmpfp, "\t.long %d\n", first_got_offset); + encode_value (first_got_offset, p, &p); #endif /* First emit the type+position table */ @@ -1252,7 +1557,9 @@ emit_method (MonoAotCompile *acfg, MonoCompile *cfg) patch_info = g_ptr_array_index (patches, pindex); if ((patch_info->type == MONO_PATCH_INFO_LABEL) || - (patch_info->type == MONO_PATCH_INFO_BB)) + (patch_info->type == MONO_PATCH_INFO_BB) || + (patch_info->type == MONO_PATCH_INFO_GOT_OFFSET) || + (patch_info->type == MONO_PATCH_INFO_NONE)) /* Nothing to do */ continue; @@ -1261,180 +1568,245 @@ emit_method (MonoAotCompile *acfg, MonoCompile *cfg) offset = patch_info->ip.i - last_offset; last_offset = patch_info->ip.i; -#ifdef MONO_ARCH_HAVE_PIC_AOT +#if defined(MONO_ARCH_HAVE_PIC_AOT) /* Only the type is needed */ - fprintf (tmpfp, "\t.byte %d\n", patch_info->type); + *p = patch_info->type; + p++; #else /* Encode type+position compactly */ g_assert (patch_info->type < 64); if (offset < 1024 - 1) { - fprintf (tmpfp, "\t.byte %d\n", (patch_info->type << 2) + (offset >> 8)); - fprintf (tmpfp, "\t.byte %d\n", offset & ((1 << 8) - 1)); + *p = (patch_info->type << 2) + (offset >> 8); + p++; + *p = offset & ((1 << 8) - 1); + p ++; } 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); + *p = (patch_info->type << 2) + 3; + p ++; + *p = 255; + p ++; + encode_value (offset, p, &p); } #endif } - if (j) { - /* - * 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); + /* + * 0 is PATCH_INFO_BB, which can't be in the file. + */ + /* NULL terminated array */ + *p = 0; + p ++; - if ((patch_info->type == MONO_PATCH_INFO_LABEL) || - (patch_info->type == MONO_PATCH_INFO_BB)) - /* Nothing to do */ - continue; + /* Then emit the other info */ + for (pindex = 0; pindex < patches->len; ++pindex) { + patch_info = g_ptr_array_index (patches, pindex); - switch (patch_info->type) { - case MONO_PATCH_INFO_LABEL: - case MONO_PATCH_INFO_BB: - break; - case MONO_PATCH_INFO_IMAGE: - fprintf (tmpfp, "\t.long 0x%08x\n", get_image_index (acfg, patch_info->data.image)); - break; - case MONO_PATCH_INFO_METHOD_REL: - fprintf (tmpfp, "\t.long 0x%08x\n", (gint)patch_info->data.offset); - break; - case MONO_PATCH_INFO_SWITCH: { - gpointer *table = (gpointer *)patch_info->data.target; - int k; - - fprintf (tmpfp, "\t.long %d\n", patch_info->table_size); - - for (k = 0; k < patch_info->table_size; k++) { - fprintf (tmpfp, "\t.long %d\n", (int)(gssize)table [k]); - } - break; + switch (patch_info->type) { + case MONO_PATCH_INFO_LABEL: + case MONO_PATCH_INFO_BB: + case MONO_PATCH_INFO_GOT_OFFSET: + case MONO_PATCH_INFO_NONE: + break; + case MONO_PATCH_INFO_IMAGE: + encode_value (get_image_index (acfg, patch_info->data.image), p, &p); + break; + case MONO_PATCH_INFO_METHOD_REL: + encode_value ((gint)patch_info->data.offset, p, &p); + break; + case MONO_PATCH_INFO_SWITCH: { + gpointer *table = (gpointer *)patch_info->data.table->table; + int k; + + encode_value (patch_info->data.table->table_size, p, &p); + for (k = 0; k < patch_info->data.table->table_size; k++) + encode_value ((int)(gssize)table [k], p, &p); + break; + } + case MONO_PATCH_INFO_METHODCONST: + case MONO_PATCH_INFO_METHOD: + case MONO_PATCH_INFO_METHOD_JUMP: + encode_method_ref (acfg, patch_info->data.method, p, &p); + break; + case MONO_PATCH_INFO_INTERNAL_METHOD: { + guint32 icall_index; + + icall_index = GPOINTER_TO_UINT (g_hash_table_lookup (acfg->icall_hash, patch_info->data.name)); + if (!icall_index) { + icall_index = g_hash_table_size (acfg->icall_hash) + 1; + g_hash_table_insert (acfg->icall_hash, (gpointer)patch_info->data.name, + GUINT_TO_POINTER (icall_index)); + g_ptr_array_add (acfg->icall_table, (gpointer)patch_info->data.name); } - case MONO_PATCH_INFO_METHODCONST: - case MONO_PATCH_INFO_METHOD: - case MONO_PATCH_INFO_METHOD_JUMP: { - guint32 image_index = get_image_index (acfg, patch_info->data.method->klass->image); - guint32 token = patch_info->data.method->token; + encode_value (icall_index - 1, p, &p); + break; + } + case MONO_PATCH_INFO_LDSTR: { + guint32 image_index = get_image_index (acfg, patch_info->data.token->image); + guint32 token = patch_info->data.token->token; + g_assert (mono_metadata_token_code (token) == MONO_TOKEN_STRING); + /* + * An optimization would be to emit shared code for ldstr + * statements followed by a throw. + */ + encode_value (image_index, p, &p); + encode_value (patch_info->data.token->token - MONO_TOKEN_STRING, p, &p); + break; + } + case MONO_PATCH_INFO_DECLSEC: + case MONO_PATCH_INFO_LDTOKEN: + case MONO_PATCH_INFO_TYPE_FROM_HANDLE: + encode_value (get_image_index (acfg, patch_info->data.token->image), p, &p); + encode_value (patch_info->data.token->token, p, &p); + break; + case MONO_PATCH_INFO_EXC_NAME: { + MonoClass *ex_class; + + ex_class = + mono_class_from_name (mono_defaults.exception_class->image, + "System", patch_info->data.target); + g_assert (ex_class); + encode_klass_info (acfg, ex_class, p, &p); + break; + } + case MONO_PATCH_INFO_R4: + encode_value (*((guint32 *)patch_info->data.target), p, &p); + break; + case MONO_PATCH_INFO_R8: + encode_value (*((guint32 *)patch_info->data.target), p, &p); + encode_value (*(((guint32 *)patch_info->data.target) + 1), p, &p); + break; + case MONO_PATCH_INFO_VTABLE: + case MONO_PATCH_INFO_CLASS_INIT: + case MONO_PATCH_INFO_CLASS: + case MONO_PATCH_INFO_IID: + encode_klass_info (acfg, patch_info->data.klass, p, &p); + break; + case MONO_PATCH_INFO_FIELD: + case MONO_PATCH_INFO_SFLDA: + encode_field_info (acfg, patch_info->data.field, p, &p); + break; + case MONO_PATCH_INFO_WRAPPER: { + encode_value (patch_info->data.method->wrapper_type, p, &p); + + switch (patch_info->data.method->wrapper_type) { + case MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK: { + 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); - fprintf (tmpfp, "\t.long 0x%08x\n", (image_index << 24) + (mono_metadata_token_index (token))); - break; - } - case MONO_PATCH_INFO_INTERNAL_METHOD: { - guint32 icall_index; - - icall_index = GPOINTER_TO_UINT (g_hash_table_lookup (acfg->icall_hash, patch_info->data.name)); - if (!icall_index) { - icall_index = g_hash_table_size (acfg->icall_hash) + 1; - g_hash_table_insert (acfg->icall_hash, (gpointer)patch_info->data.name, - GUINT_TO_POINTER (icall_index)); - g_ptr_array_add (acfg->icall_table, (gpointer)patch_info->data.name); - } - fprintf (tmpfp, "\t.long 0x%08x\n", icall_index - 1); + encode_value ((image_index << 24) + (mono_metadata_token_index (token)), p, &p); break; } - case MONO_PATCH_INFO_LDSTR: - case MONO_PATCH_INFO_LDTOKEN: - case MONO_PATCH_INFO_TYPE_FROM_HANDLE: - 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); - break; - case MONO_PATCH_INFO_EXC_NAME: { - MonoClass *ex_class; - - ex_class = - mono_class_from_name (mono_defaults.exception_class->image, - "System", patch_info->data.target); - g_assert (ex_class); - emit_klass_info (acfg, ex_class); + case MONO_WRAPPER_PROXY_ISINST: + case MONO_WRAPPER_LDFLD: + case MONO_WRAPPER_STFLD: + case MONO_WRAPPER_LDFLD_REMOTE: + case MONO_WRAPPER_STFLD_REMOTE: + case MONO_WRAPPER_ISINST: { + MonoClass *proxy_class = (MonoClass*)mono_marshal_method_from_wrapper (patch_info->data.method); + encode_klass_info (acfg, proxy_class, p, &p); break; } - case MONO_PATCH_INFO_R4: - fprintf (tmpfp, "\t.long 0x%08x\n", *((guint32 *)patch_info->data.target)); + case MONO_WRAPPER_STELEMREF: break; - case MONO_PATCH_INFO_R8: - emit_alignment (tmpfp, 8); - 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)); - break; - case MONO_PATCH_INFO_VTABLE: - case MONO_PATCH_INFO_CLASS_INIT: - case MONO_PATCH_INFO_CLASS: - case MONO_PATCH_INFO_IID: - emit_klass_info (acfg, patch_info->data.klass); - break; - case MONO_PATCH_INFO_FIELD: - case MONO_PATCH_INFO_SFLDA: - emit_field_info (acfg, patch_info->data.field); - break; - case MONO_PATCH_INFO_WRAPPER: { - fprintf (tmpfp, "\t.long %d\n", patch_info->data.method->wrapper_type); - - switch (patch_info->data.method->wrapper_type) { - case MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK: { - 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); - - fprintf (tmpfp, "\t.long %d\n", (image_index << 24) + (mono_metadata_token_index (token))); - break; - } - case MONO_WRAPPER_PROXY_ISINST: - case MONO_WRAPPER_LDFLD: - case MONO_WRAPPER_STFLD: { - MonoClass *proxy_class = (MonoClass*)mono_marshal_method_from_wrapper (patch_info->data.method); - emit_klass_info (acfg, proxy_class); - break; - } - default: - g_assert_not_reached (); - } - break; - } default: - g_warning ("unable to handle jump info %d", patch_info->type); g_assert_not_reached (); } + break; + } + default: + g_warning ("unable to handle jump info %d", patch_info->type); + g_assert_not_reached (); } } - { - guint8 *buf; - guint32 buf_len; + mono_debug_serialize_debug_info (cfg, &debug_info, &debug_info_size); - mono_debug_serialize_debug_info (cfg, &buf, &buf_len); + encode_value (debug_info_size, p, &p); + if (debug_info_size) { + memcpy (p, debug_info, debug_info_size); + p += debug_info_size; + g_free (debug_info); + } - fprintf (tmpfp, "\t.long %d\n", buf_len); + /* Emit method info */ - for (i = 0; i < buf_len; ++i) - fprintf (tmpfp, ".byte %d\n", (unsigned int) buf [i]); + emit_label (tmpfp, mname_p); - if (buf_len > 0) - g_free (buf); + g_assert (p - buf < buf_size); + for (i = 0; i < p - buf; ++i) { + if ((i % 32) == 0) + fprintf (tmpfp, "\n.byte "); + fprintf (tmpfp, "%s%d", ((i % 32) == 0) ? "" : ",", (unsigned int) buf [i]); } - - /* fixme: save the rest of the required infos */ + fprintf (tmpfp, "\n"); + g_free (buf); g_free (mname); g_free (mname_p); } +static void +emit_klass_info (MonoAotCompile *acfg, guint32 token) +{ + MonoClass *klass = mono_class_get (acfg->image, token); + char *p, *buf; + int i, buf_size; + char *label; + FILE *tmpfp = acfg->fp; + + buf_size = 10240; + p = buf = g_malloc (buf_size); + + g_assert (klass); + + mono_class_init (klass); + + /* + * Emit all the information which is required for creating vtables so + * the runtime does not need to create the MonoMethod structures which + * take up a lot of space. + */ + + if (!MONO_CLASS_IS_INTERFACE (klass)) { + encode_value (klass->vtable_size, p, &p); + encode_value ((klass->has_cctor << 2) | (klass->has_finalize << 1) | klass->ghcimpl, p, &p); + if (klass->has_cctor) + encode_method_ref (acfg, mono_class_get_cctor (klass), p, &p); + if (klass->has_finalize) + encode_method_ref (acfg, mono_class_get_finalizer (klass), p, &p); + + for (i = 0; i < klass->vtable_size; ++i) { + MonoMethod *cm = klass->vtable [i]; + + if (cm) + encode_method_ref (acfg, cm, p, &p); + else + encode_value (0, p, &p); + } + } + + /* Emit the info */ + label = g_strdup_printf (".LK_I_%x", token - MONO_TOKEN_TYPE_DEF - 1); + emit_label (tmpfp, label); + + g_assert (p - buf < buf_size); + for (i = 0; i < p - buf; ++i) { + if ((i % 32) == 0) + fprintf (tmpfp, "\n.byte "); + fprintf (tmpfp, "%s%d", ((i % 32) == 0) ? "" : ",", (unsigned int) buf [i]); + } + fprintf (tmpfp, "\n"); + g_free (buf); +} + static gboolean str_begins_with (const char *str1, const char *str2) { @@ -1455,8 +1827,11 @@ mono_aot_parse_options (const char *aot_options, MonoAotOptions *opts) if (str_begins_with (arg, "outfile=")) { opts->outfile = g_strdup (arg + strlen ("outfile=")); - } - else { + } else if (str_begins_with (arg, "save-temps")) { + opts->save_temps = TRUE; + } else if (str_begins_with (arg, "write-symbols")) { + opts->write_symbols = TRUE; + } else { fprintf (stderr, "AOT : Unknown argument '%s'.\n", arg); exit (1); } @@ -1474,39 +1849,48 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options) int i; guint8 *symbol; int ccount = 0, mcount = 0, lmfcount = 0, abscount = 0, wrappercount = 0, ocount = 0; - GHashTable *ref_hash; MonoAotCompile *acfg; - gboolean *emitted; - MonoAotOptions aot_opts; + MonoCompile **cfgs; char *outfile_name, *tmp_outfile_name; printf ("Mono Ahead of Time compiler - compiling assembly %s\n", image->name); - mono_aot_parse_options (aot_options, &aot_opts); - - i = g_file_open_tmp ("mono_aot_XXXXXX", &tmpfname, NULL); - tmpfp = fdopen (i, "w+"); - g_assert (tmpfp); - - ref_hash = g_hash_table_new (NULL, NULL); - acfg = g_new0 (MonoAotCompile, 1); - acfg->fp = tmpfp; - acfg->ref_hash = ref_hash; acfg->icall_hash = g_hash_table_new (NULL, NULL); acfg->icall_table = g_ptr_array_new (); acfg->image_hash = g_hash_table_new (NULL, NULL); acfg->image_table = g_ptr_array_new (); + acfg->image = image; - write_string_symbol (tmpfp, "mono_assembly_guid" , image->guid); + mono_aot_parse_options (aot_options, &acfg->aot_opts); + + i = g_file_open_tmp ("mono_aot_XXXXXX", &tmpfname, NULL); + tmpfp = fdopen (i, "w+"); + acfg->fp = tmpfp; + g_assert (tmpfp); - write_string_symbol (tmpfp, "mono_aot_version", MONO_AOT_FILE_VERSION); + emit_string_symbol (tmpfp, "mono_assembly_guid" , image->guid); + + emit_string_symbol (tmpfp, "mono_aot_version", MONO_AOT_FILE_VERSION); opts_str = g_strdup_printf ("%d", opts); - write_string_symbol (tmpfp, "mono_aot_opt_flags", opts_str); + emit_string_symbol (tmpfp, "mono_aot_opt_flags", opts_str); g_free (opts_str); - emitted = g_new0 (gboolean, image->tables [MONO_TABLE_METHOD].rows); + symbol = g_strdup_printf ("methods"); + emit_section_change (tmpfp, ".text", 0); + emit_global (tmpfp, symbol, FALSE); + emit_alignment (tmpfp, 8); + emit_label (tmpfp, symbol); + + symbol = g_strdup_printf ("method_infos"); + emit_section_change (tmpfp, ".text", 1); + emit_global (tmpfp, symbol, FALSE); + emit_alignment (tmpfp, 8); + emit_label (tmpfp, symbol); + + cfgs = g_new0 (MonoCompile*, image->tables [MONO_TABLE_METHOD].rows + 32); + acfg->method_got_offsets = g_new0 (guint32, image->tables [MONO_TABLE_METHOD].rows + 32); for (i = 0; i < image->tables [MONO_TABLE_METHOD].rows; ++i) { MonoJumpInfo *patch_info; @@ -1535,11 +1919,17 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options) //printf ("START: %s\n", mono_method_full_name (method, TRUE)); //mono_compile_method (method); - cfg = mini_method_compile (method, opts, mono_get_root_domain (), FALSE, 0); + /* + * Since these methods are the only ones which are compiled with + * AOT support, and they are not used by runtime startup/shutdown code, + * the runtime will not see AOT methods during AOT compilation,so it + * does not need to support them by creating a fake GOT etc. + */ + cfg = mini_method_compile (method, opts, mono_get_root_domain (), FALSE, TRUE, 0); g_assert (cfg); if (cfg->disable_aot) { - printf ("Skip (other): %s\n", mono_method_full_name (method, TRUE)); + //printf ("Skip (other): %s\n", mono_method_full_name (method, TRUE)); ocount++; continue; } @@ -1573,6 +1963,11 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options) case MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK: case MONO_WRAPPER_STFLD: case MONO_WRAPPER_LDFLD: + case MONO_WRAPPER_LDFLD_REMOTE: + case MONO_WRAPPER_STFLD_REMOTE: + case MONO_WRAPPER_STELEMREF: + case MONO_WRAPPER_ISINST: + case MONO_WRAPPER_PROXY_ISINST: patch_info->type = MONO_PATCH_INFO_WRAPPER; break; } @@ -1581,15 +1976,16 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options) skip = FALSE; for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) { - if ((patch_info->type == MONO_PATCH_INFO_METHOD || - patch_info->type == MONO_PATCH_INFO_METHODCONST)) { + switch (patch_info->type) { + case MONO_PATCH_INFO_METHOD: + case MONO_PATCH_INFO_METHODCONST: if (patch_info->data.method->wrapper_type) { /* unable to handle this */ //printf ("Skip (wrapper call): %s %d -> %s\n", mono_method_full_name (method, TRUE), patch_info->type, mono_method_full_name (patch_info->data.method, TRUE)); skip = TRUE; break; } - if (!patch_info->data.method->token) { + if (!patch_info->data.method->token) /* * The method is part of a constructed type like Int[,].Set (). It doesn't * have a token, and we can't make one, since the parent type is part of @@ -1597,30 +1993,81 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options) * referenced this type. */ skip = TRUE; - break; - } + break; + case MONO_PATCH_INFO_VTABLE: + case MONO_PATCH_INFO_CLASS_INIT: + case MONO_PATCH_INFO_CLASS: + case MONO_PATCH_INFO_IID: + if (!patch_info->data.klass->type_token) + if (!patch_info->data.klass->element_class->type_token) + skip = TRUE; + break; + default: + break; } } if (skip) { wrappercount++; + mono_destroy_compile (cfg); continue; } //printf ("Compile: %s\n", mono_method_full_name (method, TRUE)); - emitted [i] = TRUE; - emit_method (acfg, cfg); - - mono_destroy_compile (cfg); + cfgs [i] = cfg; ccount++; } + /* Emit code */ + emit_section_change (tmpfp, ".text", 0); + for (i = 0; i < image->tables [MONO_TABLE_METHOD].rows; ++i) { + if (cfgs [i]) + emit_method_code (acfg, cfgs [i]); + } + + /* Emit method info */ + emit_section_change (tmpfp, ".text", 1); + for (i = 0; i < image->tables [MONO_TABLE_METHOD].rows; ++i) { + if (cfgs [i]) + emit_method_info (acfg, cfgs [i]); + } + + /* Emit class info */ + + symbol = g_strdup_printf ("class_infos"); + emit_section_change (tmpfp, ".text", 1); + emit_global (tmpfp, symbol, FALSE); + emit_alignment (tmpfp, 8); + emit_label (tmpfp, symbol); + + for (i = 0; i < image->tables [MONO_TABLE_TYPEDEF].rows; ++i) + emit_klass_info (acfg, MONO_TOKEN_TYPE_DEF | (i + 1)); + + symbol = g_strdup_printf ("class_info_offsets"); + emit_section_change (tmpfp, ".text", 1); + emit_global (tmpfp, symbol, FALSE); + emit_alignment (tmpfp, 8); + emit_label(tmpfp, symbol); + + for (i = 0; i < image->tables [MONO_TABLE_TYPEDEF].rows; ++i) { + const char *sep; + if ((i % 32) == 0) { + fprintf (tmpfp, "\n.long "); + sep = ""; + } + else + sep = ","; + + symbol = g_strdup_printf (".LK_I_%x", i); + fprintf (tmpfp, "%s%s - class_infos", sep, symbol); + } + fprintf (tmpfp, "\n"); + /* * The icall and image tables are small but referenced in a lot of places. - * So we emit them at once, and reference their elements by an index - * instead of an assembly label to cut back on the number of relocations. + * So we emit them at once, and reference their elements by an index. */ /* Emit icall table */ @@ -1662,42 +2109,20 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options) fprintf (tmpfp, ".long %d\n", aname->revision); } - /* - * g_module_symbol takes a lot of time for failed lookups, so we emit - * a table which contains one bit for each method. This bit specifies - * whenever the method is emitted or not. - */ - - symbol = g_strdup_printf ("mono_methods_present_table"); - emit_section_change (tmpfp, ".text", 1); - emit_global (tmpfp, symbol, FALSE); - emit_alignment (tmpfp, 8); - emit_label (tmpfp, symbol); - { - guint32 k, nrows; - guint32 w; - - nrows = image->tables [MONO_TABLE_METHOD].rows; - for (i = 0; i < nrows / 32 + 1; ++i) { - w = 0; - for (k = 0; k < 32; ++k) { - if (emitted [(i * 32) + k]) - w += (1 << k); - } - //printf ("EMITTED [%d] = %d.\n", i, b); - fprintf (tmpfp, "\t.long %d\n", w); - } - } - #ifdef MONO_ARCH_HAVE_PIC_AOT /* Emit GOT */ /* Don't make GOT global so accesses to it don't need relocations */ symbol = g_strdup_printf ("got"); +#ifdef __x86_64__ emit_section_change (tmpfp, ".bss", 1); +#else + emit_section_change (tmpfp, ".data", 1); +#endif emit_alignment (tmpfp, 8); emit_label(tmpfp, symbol); - fprintf (tmpfp, ".skip %d\n", (int)(acfg->got_offset * sizeof (gpointer))); + if (acfg->got_offset > 0) + fprintf (tmpfp, ".skip %d\n", (int)(acfg->got_offset * sizeof (gpointer))); symbol = g_strdup_printf ("got_addr"); emit_section_change (tmpfp, ".data", 1); @@ -1705,8 +2130,61 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options) emit_alignment (tmpfp, 8); emit_label(tmpfp, symbol); emit_pointer (tmpfp, "got"); + + symbol = g_strdup_printf ("got_size"); + emit_section_change (tmpfp, ".data", 1); + emit_global (tmpfp, symbol, FALSE); + emit_alignment (tmpfp, 8); + emit_label(tmpfp, symbol); + fprintf (tmpfp, ".long %d\n", (int)(acfg->got_offset * sizeof (gpointer))); #endif + symbol = g_strdup_printf ("method_offsets"); + emit_section_change (tmpfp, ".text", 1); + emit_global (tmpfp, symbol, FALSE); + emit_alignment (tmpfp, 8); + emit_label(tmpfp, symbol); + + for (i = 0; i < image->tables [MONO_TABLE_METHOD].rows; ++i) { + const char *sep; + if ((i % 32) == 0) { + fprintf (tmpfp, "\n.long "); + sep = ""; + } + else + sep = ","; + if (cfgs [i]) { + symbol = g_strdup_printf (".Lm_%x", i + 1); + fprintf (tmpfp, "%s%s-methods", sep, symbol); + } + else + fprintf (tmpfp, "%s0xffffffff", sep); + } + fprintf (tmpfp, "\n"); + + symbol = g_strdup_printf ("method_info_offsets"); + emit_section_change (tmpfp, ".text", 1); + emit_global (tmpfp, symbol, FALSE); + emit_alignment (tmpfp, 8); + emit_label(tmpfp, symbol); + + for (i = 0; i < image->tables [MONO_TABLE_METHOD].rows; ++i) { + const char *sep; + if ((i % 32) == 0) { + fprintf (tmpfp, "\n.long "); + sep = ""; + } + else + sep = ","; + if (cfgs [i]) { + symbol = g_strdup_printf (".Lm_%x_p", i + 1); + fprintf (tmpfp, "%s%s - method_infos", sep, symbol); + } + else + fprintf (tmpfp, "%s0", sep); + } + fprintf (tmpfp, "\n"); + fclose (tmpfp); #if defined(__x86_64__) @@ -1724,8 +2202,8 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options) g_free (com); - if (aot_opts.outfile) - outfile_name = g_strdup_printf ("%s", aot_opts.outfile); + if (acfg->aot_opts.outfile) + outfile_name = g_strdup_printf ("%s", acfg->aot_opts.outfile); else outfile_name = g_strdup_printf ("%s%s", image->name, SHARED_EXT); @@ -1765,10 +2243,38 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options) 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); + if (acfg->aot_opts.save_temps) + printf ("Retained input file.\n"); + else + unlink (tmpfname); return 0; } +#else +/* AOT disabled */ + +void +mono_aot_init (void) +{ +} + +MonoJitInfo* +mono_aot_get_method (MonoDomain *domain, MonoMethod *method) +{ + return NULL; +} + +gboolean +mono_aot_is_got_entry (guint8 *code, guint8 *addr) +{ + return FALSE; +} + +int +mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options) +{ + return 0; +} +#endif