From: Zoltan Varga Date: Sat, 18 Oct 2008 19:17:35 +0000 (-0000) Subject: 2008-10-18 Zoltan Varga X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=commitdiff_plain;h=0cbc013a7dbd0f32647dd3a01a32dbfb94b43bf2;p=mono.git 2008-10-18 Zoltan Varga * method-to-ir.c (mono_method_to_ir2): Change a !compile_aot assert to disable_aot. * mini.c (mono_patch_info_equal): Compare the generic context as well. * mini.h: Bump aot file format version. * aot-compiler.c aot-runtime.c: Generalize the wrapper handling code so the AOT file can contain native code for methods which are not in the METHOD table. Generate code for non-sharable generic instances of generic methods found in the METHODSPEC table. svn path=/trunk/mono/; revision=116384 --- diff --git a/mono/mini/ChangeLog b/mono/mini/ChangeLog index d581e76b932..be61796e0b7 100644 --- a/mono/mini/ChangeLog +++ b/mono/mini/ChangeLog @@ -1,5 +1,17 @@ 2008-10-18 Zoltan Varga + * method-to-ir.c (mono_method_to_ir2): Change a !compile_aot assert to + disable_aot. + + * mini.c (mono_patch_info_equal): Compare the generic context as well. + + * mini.h: Bump aot file format version. + + * aot-compiler.c aot-runtime.c: Generalize the wrapper handling code so the + AOT file can contain native code for methods which are not in the METHOD + table. Generate code for non-sharable generic instances of generic methods + found in the METHODSPEC table. + * method-to-ir.c (mono_method_to_ir2): Remove the aot restriction when encoding generic type handles. diff --git a/mono/mini/aot-compiler.c b/mono/mini/aot-compiler.c index 157e1374a05..8d9324192ae 100644 --- a/mono/mini/aot-compiler.c +++ b/mono/mini/aot-compiler.c @@ -146,6 +146,8 @@ typedef struct MonoAotCompile { GHashTable *image_hash; GHashTable *method_to_cfg; GHashTable *token_info_hash; + GPtrArray *extra_methods; + GHashTable *extra_methods_hash; GPtrArray *image_table; GPtrArray *globals; GList *method_order; @@ -2320,6 +2322,43 @@ add_wrappers (MonoAotCompile *acfg) #endif } +/* + * add_methodspecs: + * + * Add methods referenced by the METHODSPEC table. + */ +static void +add_methodspecs (MonoAotCompile *acfg) +{ + int i; + guint32 token; + MonoMethod *method; + MonoGenericContext *context; + + /* FIXME: Only add instantiations with vtype arguments */ + for (i = 0; i < acfg->image->tables [MONO_TABLE_METHODSPEC].rows; ++i) { + token = MONO_TOKEN_METHOD_SPEC | (i + 1); + method = mono_get_method (acfg->image, token, NULL); + + context = mono_method_get_context (method); + if (context && ((context->class_inst && context->class_inst->is_open) || + (context->method_inst && context->method_inst->is_open))) + continue; + + if (method->klass->image != acfg->image) + continue; + + if (mono_method_is_generic_sharable_impl (method, FALSE)) + /* Already added */ + continue; + + add_method (acfg, method); + + g_ptr_array_add (acfg->extra_methods, method); + g_hash_table_insert (acfg->extra_methods_hash, method, method); + } +} + static void emit_and_reloc_code (MonoAotCompile *acfg, MonoMethod *method, guint8 *code, guint32 code_len, MonoJumpInfo *relocs, gboolean got_only) { @@ -2383,8 +2422,20 @@ emit_and_reloc_code (MonoAotCompile *acfg, MonoMethod *method, guint8 *code, gui if (!got_only && (patch_info->type == MONO_PATCH_INFO_METHOD) && (patch_info->data.method->klass->image == method->klass->image)) { MonoCompile *callee_cfg = g_hash_table_lookup (acfg->method_to_cfg, patch_info->data.method); if (callee_cfg) { - if (!callee_cfg->has_got_slots && (callee_cfg->method->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT)) { - //printf ("DIRECT: %s %s\n", mono_method_full_name (cfg->method, TRUE), mono_method_full_name (callee_cfg->method, TRUE)); + gboolean direct_callable = TRUE; + + if (direct_callable && !(!callee_cfg->has_got_slots && (callee_cfg->method->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT))) + direct_callable = FALSE; + /* + * FIXME: mono_aot_find_jit_info () needs to construct the + * MonoMethod belonging to a piece of code, and it can't + * do it for generic instances. + */ + if (direct_callable && callee_cfg->method->is_inflated && g_hash_table_lookup (acfg->extra_methods_hash, callee_cfg->method)) + direct_callable = FALSE; + + if (direct_callable) { + printf ("DIRECT: %s %s\n", method ? mono_method_full_name (method, TRUE) : "", mono_method_full_name (callee_cfg->method, TRUE)); direct_call_target = g_strdup_printf (".Lm_%x", get_method_index (acfg, callee_cfg->orig_method)); patch_info->type = MONO_PATCH_INFO_NONE; acfg->stats.direct_calls ++; @@ -3662,6 +3713,11 @@ compile_method (MonoAotCompile *acfg, MonoMethod *method) g_hash_table_insert (acfg->method_to_cfg, cfg->orig_method, cfg); + if (cfg->orig_method->wrapper_type) { + g_ptr_array_add (acfg->extra_methods, cfg->orig_method); + g_hash_table_insert (acfg->extra_methods_hash, cfg->orig_method, cfg->orig_method); + } + acfg->stats.ccount++; } @@ -3851,51 +3907,154 @@ emit_info (MonoAotCompile *acfg) } emit_line (acfg); } + +typedef struct HashEntry { + guint32 key, value, index; + struct HashEntry *next; +} HashEntry; +/* + * emit_extra_methods: + * + * Emit methods which are not in the METHOD table, like wrappers. + */ static void -emit_wrapper_info (MonoAotCompile *acfg) +emit_extra_methods (MonoAotCompile *acfg) { - int i, index; + int i, table_size, buf_size; char *symbol; - char *name; + guint8 *p, *buf; + guint32 *info_offsets; + guint32 hash; + GPtrArray *table; + HashEntry *entry, *new_entry; + int nmethods; + + info_offsets = g_new0 (guint32, acfg->nmethods); + + buf_size = acfg->extra_methods->len * 256 + 256; + p = buf = g_malloc (buf_size); + + /* Encode method info */ + nmethods = 0; + /* So offsets are > 0 */ + p++; + for (i = 0; i < acfg->extra_methods->len; ++i) { + MonoMethod *method = g_ptr_array_index (acfg->extra_methods, i); + MonoCompile *cfg = g_hash_table_lookup (acfg->method_to_cfg, method); + + if (!cfg) + continue; + + nmethods ++; + info_offsets [i] = p - buf; + + if (method->wrapper_type) { + char *name; + + // FIXME: Optimize disk usage + if (method->wrapper_type == MONO_WRAPPER_RUNTIME_INVOKE) { + char *tmpsig = mono_signature_get_desc (mono_method_signature (method), TRUE); + name = g_strdup_printf ("(wrapper runtime-invoke):%s (%s)", method->name, tmpsig); + g_free (tmpsig); + } else { + name = mono_method_full_name (cfg->orig_method, TRUE); + } + + encode_value (1, p, &p); + strcpy ((char*)p, name); + p += strlen (name ) + 1; + g_free (name); + } else { + encode_value (0, p, &p); + encode_method_ref (acfg, method, p, &p); + } + + g_assert ((p - buf) < buf_size); + } + + g_assert ((p - buf) < buf_size); /* Emit method info */ - symbol = g_strdup_printf ("wrapper_info"); + symbol = g_strdup_printf ("extra_method_info"); emit_section_change (acfg, ".text", 1); emit_global (acfg, symbol, FALSE); emit_alignment (acfg, 8); emit_label (acfg, symbol); g_free (symbol); - if (!acfg->aot_opts.full_aot) - return; + emit_bytes (acfg, buf, p - buf); - for (i = 0; i < acfg->nmethods; ++i) { - MonoCompile *cfg = acfg->cfgs [i]; - MonoMethod *method; + emit_line (acfg); + + /* + * Construct a chained hash table for mapping indexes in extra_method_info to + * method indexes. + */ + table_size = g_spaced_primes_closest ((int)(nmethods * 1.5)); + table = g_ptr_array_sized_new (table_size); + for (i = 0; i < table_size; ++i) + g_ptr_array_add (table, NULL); + for (i = 0; i < acfg->extra_methods->len; ++i) { + MonoMethod *method = g_ptr_array_index (acfg->extra_methods, i); + MonoCompile *cfg = g_hash_table_lookup (acfg->method_to_cfg, method); + guint32 key, value; - if (!cfg || !cfg->orig_method->wrapper_type) + if (!cfg) continue; - method = cfg->orig_method; - index = get_method_index (acfg, method); + key = info_offsets [i]; + value = get_method_index (acfg, method); + // FIXME: + hash = 0 % table_size; + + /* FIXME: Allocate from the mempool */ + new_entry = g_new0 (HashEntry, 1); + new_entry->key = key; + new_entry->value = value; - // FIXME: Optimize disk usage and lookup speed - if (method->wrapper_type == MONO_WRAPPER_RUNTIME_INVOKE) { - char *tmpsig = mono_signature_get_desc (mono_method_signature (method), TRUE); - name = g_strdup_printf ("(wrapper runtime-invoke):%s (%s)", method->name, tmpsig); - g_free (tmpsig); + entry = g_ptr_array_index (table, hash); + if (entry == NULL) { + new_entry->index = hash; + g_ptr_array_index (table, hash) = new_entry; } else { - name = mono_method_full_name (cfg->orig_method, TRUE); + while (entry->next) + entry = entry->next; + + entry->next = new_entry; + new_entry->index = table->len; + g_ptr_array_add (table, new_entry); } - emit_string (acfg, name); - emit_alignment (acfg, 4); - emit_int32 (acfg, index); } - emit_byte (acfg, 0); + /* Emit the table */ + symbol = g_strdup_printf ("extra_method_table"); + emit_section_change (acfg, ".text", 0); + emit_global (acfg, symbol, FALSE); + emit_alignment (acfg, 8); + emit_label (acfg, symbol); + g_free (symbol); - emit_line (acfg); + g_assert (table_size < 65000); + emit_int32 (acfg, table_size); + g_assert (table->len < 65000); + for (i = 0; i < table->len; ++i) { + HashEntry *entry = g_ptr_array_index (table, i); + + if (entry == NULL) { + emit_int32 (acfg, 0); + emit_int32 (acfg, 0); + emit_int32 (acfg, 0); + } else { + g_assert (entry->key > 0); + emit_int32 (acfg, entry->key); + emit_int32 (acfg, entry->value); + if (entry->next) + emit_int32 (acfg, entry->next->index); + else + emit_int32 (acfg, 0); + } + } } static void @@ -4438,6 +4597,8 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options) acfg->image = image; acfg->opts = opts; acfg->mempool = mono_mempool_new (); + acfg->extra_methods = g_ptr_array_new (); + acfg->extra_methods_hash = g_hash_table_new (NULL, NULL); mono_aot_parse_options (aot_options, &acfg->aot_opts); @@ -4468,6 +4629,8 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options) acfg->method_index ++; } + add_methodspecs (acfg); + if (acfg->aot_opts.full_aot) add_wrappers (acfg); @@ -4489,7 +4652,7 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options) emit_info (acfg); - emit_wrapper_info (acfg); + emit_extra_methods (acfg); emit_method_order (acfg); diff --git a/mono/mini/aot-runtime.c b/mono/mini/aot-runtime.c index 2452e1e0e76..7ad4d35051d 100644 --- a/mono/mini/aot-runtime.c +++ b/mono/mini/aot-runtime.c @@ -74,11 +74,9 @@ typedef struct MonoAotModule { gpointer *got; guint32 got_size; GHashTable *name_cache; - GHashTable *wrappers; - /* Maps wrapper names to their method index */ - GHashTable *wrappers_by_name; - /* Maps wrapper methods to their code */ - GHashTable *wrappers_to_code; + GHashTable *extra_methods; + /* Maps methods to their code */ + GHashTable *method_to_code; MonoAssemblyName *image_names; char **image_guids; MonoAssembly *assembly; @@ -108,7 +106,8 @@ typedef struct MonoAotModule { guint32 *class_info_offsets; guint32 *methods_loaded; guint16 *class_name_table; - guint8 *wrapper_info; + guint32 *extra_method_table; + guint8 *extra_method_info; guint8 *trampolines; guint32 num_trampolines, first_trampoline_got_offset, trampoline_index; gpointer *globals; @@ -917,6 +916,7 @@ load_aot_module (MonoAssembly *assembly, gpointer user_data) amodule->got [0] = assembly->image; amodule->globals = globals; amodule->sofile = sofile; + amodule->method_to_code = g_hash_table_new (mono_aligned_addr_hash, NULL); sscanf (opt_flags, "%d", &amodule->opts); @@ -974,9 +974,10 @@ load_aot_module (MonoAssembly *assembly, gpointer user_data) find_symbol (sofile, globals, "class_info", (gpointer*)&amodule->class_info); find_symbol (sofile, globals, "class_info_offsets", (gpointer*)&amodule->class_info_offsets); find_symbol (sofile, globals, "class_name_table", (gpointer *)&amodule->class_name_table); + find_symbol (sofile, globals, "extra_method_table", (gpointer *)&amodule->extra_method_table); + find_symbol (sofile, globals, "extra_method_info", (gpointer *)&amodule->extra_method_info); find_symbol (sofile, globals, "got_info", (gpointer*)&amodule->got_info); find_symbol (sofile, globals, "got_info_offsets", (gpointer*)&amodule->got_info_offsets); - find_symbol (sofile, globals, "wrapper_info", (gpointer*)&amodule->wrapper_info); find_symbol (sofile, globals, "trampolines", (gpointer*)&amodule->trampolines); find_symbol (sofile, globals, "mem_end", (gpointer*)&amodule->mem_end); @@ -1494,16 +1495,23 @@ mono_aot_find_jit_info (MonoDomain *domain, MonoImage *image, gpointer addr) method_index = table [pos]; - /* Might be a wrapper */ - if (aot_module->wrappers) { + /* Might be a wrapper/extra method */ + if (aot_module->extra_methods) { mono_aot_lock (); - method = g_hash_table_lookup (aot_module->wrappers, GUINT_TO_POINTER (method_index)); + method = g_hash_table_lookup (aot_module->extra_methods, GUINT_TO_POINTER (method_index)); mono_aot_unlock (); } else { method = NULL; } if (!method) { + /* + * This only works for methods which are in the METHOD table, it can't + * handle generic instances/wrappers. This is only a problem for direct + * calls, since those bypass mono_get_aot_method (), so we can't add the + * method to aot_module->extra_methods. + */ + g_assert (method_index < image->tables [MONO_TABLE_METHOD].rows); token = mono_metadata_make_token (MONO_TABLE_METHOD, method_index + 1); method = mono_get_method (image, token, NULL); } @@ -1826,11 +1834,81 @@ register_jump_target_got_slot (MonoDomain *domain, MonoMethod *method, gpointer mono_domain_unlock (domain); } +/* + * find_extra_method: + * + * Try finding METHOD in the extra_method table in the AOT image. + * Return its method index, or 0xffffff if not found. + */ +static guint32 +find_extra_method (MonoDomain *domain, MonoMethod *method) +{ + MonoClass *klass = method->klass; + MonoAotModule *aot_module = klass->image->aot_module; + guint32 table_size, entry_size, hash; + guint32 *table, *entry; + char *full_name = NULL; + + if (!aot_module) + return 0xffffff; + + table_size = aot_module->extra_method_table [0]; + table = aot_module->extra_method_table + 1; + entry_size = 3; + + if (method->wrapper_type) { + /* FIXME: This is a hack to work around the fact that runtime invoke wrappers get assigned to some random class */ + if (method->wrapper_type == MONO_WRAPPER_RUNTIME_INVOKE) { + char *tmpsig = mono_signature_get_desc (mono_method_signature (method), TRUE); + full_name = g_strdup_printf ("(wrapper runtime-invoke):%s (%s)", method->name, tmpsig); + g_free (tmpsig); + } else { + full_name = mono_method_full_name (method, TRUE); + } + } + + // FIXME: + hash = 0 % table_size; + + entry = &table [hash * entry_size]; + + if (entry [0] != 0) { + while (TRUE) { + guint32 key = entry [0]; + guint32 value = entry [1]; + guint32 next = entry [entry_size - 1]; + MonoMethod *m; + guint8 *p; + int is_wrapper; + + // FIXME: Avoid fully decoding the method ref + p = aot_module->extra_method_info + key; + is_wrapper = decode_value (p, &p); + if (method->wrapper_type && is_wrapper) { + if (!strcmp (full_name, (char*)p)) + return value; + } else { + m = decode_method_ref_2 (aot_module, p, &p); + if (m == method) + return value; + } + + if (next != 0) { + entry = &table [next * entry_size]; + } else { + break; + } + } + } + + return 0xffffff; +} + gpointer mono_aot_get_method (MonoDomain *domain, MonoMethod *method) { MonoClass *klass = method->klass; - guint32 method_index = mono_metadata_token_index (method->token) - 1; + guint32 method_index; guint8 *code, *info; MonoAotModule *aot_module = klass->image->aot_module; @@ -1855,71 +1933,31 @@ mono_aot_get_method (MonoDomain *domain, MonoMethod *method) if (aot_module->out_of_date) return NULL; - if (method->is_inflated) { - if (!mono_method_is_generic_sharable_impl (method, FALSE)) - return NULL; + /* Find method index */ + if (method->is_inflated && mono_method_is_generic_sharable_impl (method, FALSE)) { method = mono_method_get_declaring_generic_method (method); - } - - if (!method->token) { - char *full_name; - char *p; - - if (!method->wrapper_type || !aot_module->wrapper_info) - return NULL; - + method_index = mono_metadata_token_index (method->token) - 1; + } else if (method->is_inflated || !method->token) { + /* This hash table is used to avoid the slower search in the extra_method_table in the AOT image */ mono_aot_lock (); - - /* Avoid doing a hash table lookup using strings if possible */ - if (!aot_module->wrappers_to_code) - aot_module->wrappers_to_code = g_hash_table_new (mono_aligned_addr_hash, NULL); - code = g_hash_table_lookup (aot_module->wrappers_to_code, method); - if (code) { - mono_aot_unlock (); - return code; - } - - /* Try to find the wrapper among the wrapper info */ - /* FIXME: This is a hack to work around the fact that runtime invoke wrappers get assigned to some random class */ - if (method->wrapper_type == MONO_WRAPPER_RUNTIME_INVOKE) { - char *tmpsig = mono_signature_get_desc (mono_method_signature (method), TRUE); - full_name = g_strdup_printf ("(wrapper runtime-invoke):%s (%s)", method->name, tmpsig); - g_free (tmpsig); - } else { - full_name = mono_method_full_name (method, TRUE); - } - - /* Create a hash table to avoid repeated linear searches */ - if (!aot_module->wrappers_by_name) { - aot_module->wrappers_by_name = g_hash_table_new (g_str_hash, g_str_equal); - p = (char*)aot_module->wrapper_info; - while (*p) { - char *end; - - end = p + strlen (p) + 1; - end = ALIGN_PTR_TO (end, 4); - method_index = *(guint32*)end; - end += 4; - /* The + 1 is used to distinguish a 0 index from a not-found one */ - g_hash_table_insert (aot_module->wrappers_by_name, p, GUINT_TO_POINTER (method_index + 1)); - p = end; - } - } - method_index = GPOINTER_TO_UINT (g_hash_table_lookup (aot_module->wrappers_by_name, full_name)); + code = g_hash_table_lookup (aot_module->method_to_code, method); mono_aot_unlock (); + if (code) + return code; - g_free (full_name); - if (!method_index) + method_index = find_extra_method (domain, method); + if (method_index == 0xffffff) return NULL; - method_index --; - /* Needed by find_jit_info */ mono_aot_lock (); - if (!aot_module->wrappers) - aot_module->wrappers = g_hash_table_new (NULL, NULL); - g_hash_table_insert (aot_module->wrappers, GUINT_TO_POINTER (method_index), method); + if (!aot_module->extra_methods) + aot_module->extra_methods = g_hash_table_new (NULL, NULL); + g_hash_table_insert (aot_module->extra_methods, GUINT_TO_POINTER (method_index), method); mono_aot_unlock (); + } else { + /* Common case */ + method_index = mono_metadata_token_index (method->token) - 1; } if (aot_module->code_offsets [method_index] == 0xffffffff) { @@ -2068,7 +2106,7 @@ mono_aot_load_method (MonoDomain *domain, MonoAotModule *aot_module, MonoMethod init_plt (aot_module); if (method->wrapper_type) - g_hash_table_insert (aot_module->wrappers_to_code, method, code); + g_hash_table_insert (aot_module->method_to_code, method, code); mono_aot_unlock (); diff --git a/mono/mini/method-to-ir.c b/mono/mini/method-to-ir.c index b10d0cb2834..29202c69d78 100644 --- a/mono/mini/method-to-ir.c +++ b/mono/mini/method-to-ir.c @@ -6029,7 +6029,8 @@ mono_method_to_ir2 (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_ cmethod, MONO_RGCTX_INFO_METHOD_CONTEXT); } else { - g_assert (!cfg->compile_aot); + // FIXME: + cfg->disable_aot = TRUE; g_assert (cmethod->is_inflated); EMIT_NEW_PCONST (cfg, imt_arg, ((MonoMethodInflated*)cmethod)->context.method_inst); diff --git a/mono/mini/mini.c b/mono/mini/mini.c index 3439ae4fef4..307a3d8c6d5 100644 --- a/mono/mini/mini.c +++ b/mono/mini/mini.c @@ -11326,7 +11326,10 @@ mono_patch_info_equal (gconstpointer ka, gconstpointer kb) case MONO_PATCH_INFO_LDTOKEN: case MONO_PATCH_INFO_DECLSEC: if ((ji1->data.token->image != ji2->data.token->image) || - (ji1->data.token->token != ji2->data.token->token)) + (ji1->data.token->token != ji2->data.token->token) || + (ji1->data.token->has_context != ji2->data.token->has_context) || + (ji1->data.token->context.class_inst != ji2->data.token->context.class_inst) || + (ji1->data.token->context.method_inst != ji2->data.token->context.method_inst)) return 0; break; default: diff --git a/mono/mini/mini.h b/mono/mini/mini.h index f54bbfecdcc..c2700d8af30 100644 --- a/mono/mini/mini.h +++ b/mono/mini/mini.h @@ -66,7 +66,7 @@ #define MONO_FAKE_VTABLE_METHOD ((MonoMethod*)GINT_TO_POINTER(-2)) /* Version number of the AOT file format */ -#define MONO_AOT_FILE_VERSION "40" +#define MONO_AOT_FILE_VERSION "41" /* Per-domain information maintained by the JIT */ typedef struct