X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mono%2Fmini%2Faot-compiler.c;h=cb1fc0e368fe3344632c5ef0d9ddc5fd7c158e25;hb=430ebd1982d79a85e58be0dad04c42249b65cf56;hp=e75ce8918208a08d7b35b728cc42a90512e7a70d;hpb=c52659ae8d9d3801f19e0cc25c2519a860a020cd;p=mono.git diff --git a/mono/mini/aot-compiler.c b/mono/mini/aot-compiler.c index e75ce891820..cb1fc0e368f 100644 --- a/mono/mini/aot-compiler.c +++ b/mono/mini/aot-compiler.c @@ -99,16 +99,18 @@ typedef struct MonoAotOptions { gboolean soft_debug; int nthreads; int ntrampolines; + int nrgctx_trampolines; gboolean print_skipped_methods; + gboolean stats; char *tool_prefix; gboolean autoreg; } MonoAotOptions; typedef struct MonoAotStats { int ccount, mcount, lmfcount, abscount, gcount, ocount, genericcount; - int code_size, info_size, ex_info_size, unwind_info_size, got_size, class_info_size, got_info_size, got_info_offsets_size; + int code_size, info_size, ex_info_size, unwind_info_size, got_size, class_info_size, got_info_size; int methods_without_got_slots, direct_calls, all_calls, llvm_count; - int got_slots; + int got_slots, offsets_size; int got_slot_types [MONO_PATCH_INFO_NONE]; int jit_time, gen_time, link_time; } MonoAotStats; @@ -117,6 +119,7 @@ typedef struct MonoAotCompile { MonoImage *image; GPtrArray *methods; GHashTable *method_indexes; + GHashTable *method_depth; MonoCompile **cfgs; int cfgs_size; GHashTable *patch_to_plt_offset; @@ -165,6 +168,7 @@ typedef struct MonoAotCompile { guint32 label_generator; gboolean llvm; MonoAotFileFlags flags; + MonoDynamicStream blob; } MonoAotCompile; #define mono_acfg_lock(acfg) EnterCriticalSection (&((acfg)->mutex)) @@ -625,7 +629,6 @@ arch_emit_plt_entry (MonoAotCompile *acfg, int index) * We can't emit jumps because they are 32 bits only so they can't be patched. * So we make indirect calls through GOT entries which are patched by the AOT * loader to point to .Lpd entries. - * An x86_64 plt entry is 10 bytes long, init_plt () depends on this. */ /* jmpq *(%rip) */ emit_byte (acfg, '\xff'); @@ -641,7 +644,6 @@ arch_emit_plt_entry (MonoAotCompile *acfg, int index) * - optimize OP_AOTCONST implementation * - optimize the PLT entries * - optimize SWITCH AOT implementation - * - implement IMT support */ code = buf; if (acfg->use_bin_writer && FALSE) { @@ -1108,6 +1110,73 @@ arch_emit_imt_thunk (MonoAotCompile *acfg, int offset, int *tramp_size) #endif } +static void +arch_emit_autoreg (MonoAotCompile *acfg, char *symbol) +{ +#if defined(TARGET_POWERPC) && defined(__mono_ilp32__) + /* Based on code generated by gcc */ + img_writer_emit_unset_mode (acfg->w); + + fprintf (acfg->fp, +#if defined(_MSC_VER) || defined(MONO_CROSS_COMPILE) + ".section .ctors,\"aw\",@progbits\n" + ".align 2\n" + ".globl %s\n" + ".long %s\n" + ".section .opd,\"aw\"\n" + ".align 2\n" + "%s:\n" + ".long .%s,.TOC.@tocbase32\n" + ".size %s,.-%s\n" + ".section .text\n" + ".type .%s,@function\n" + ".align 2\n" + ".%s:\n", symbol, symbol, symbol, symbol, symbol, symbol, symbol, symbol); +#else + ".section .ctors,\"aw\",@progbits\n" + ".align 2\n" + ".globl %1$s\n" + ".long %1$s\n" + ".section .opd,\"aw\"\n" + ".align 2\n" + "%1$s:\n" + ".long .%1$s,.TOC.@tocbase32\n" + ".size %1$s,.-%1$s\n" + ".section .text\n" + ".type .%1$s,@function\n" + ".align 2\n" + ".%1$s:\n", symbol); +#endif + + + fprintf (acfg->fp, + "stdu 1,-128(1)\n" + "mflr 0\n" + "std 31,120(1)\n" + "std 0,144(1)\n" + + ".Lautoreg:\n" + "lis 3, .Lglobals@h\n" + "ori 3, 3, .Lglobals@l\n" + "bl .mono_aot_register_module\n" + "ld 11,0(1)\n" + "ld 0,16(11)\n" + "mtlr 0\n" + "ld 31,-8(11)\n" + "mr 1,11\n" + "blr\n" + ); +#if defined(_MSC_VER) || defined(MONO_CROSS_COMPILE) + fprintf (acfg->fp, + ".size .%s,.-.%s\n", symbol, symbol); +#else + fprintf (acfg->fp, + ".size .%1$s,.-.%1$s\n", symbol); +#endif +#else +#endif +} + /* * arch_get_cie_program: * @@ -1187,6 +1256,123 @@ encode_value (gint32 value, guint8 *buf, guint8 **endbuf) *endbuf = p; } +static void +stream_init (MonoDynamicStream *sh) +{ + sh->index = 0; + sh->alloc_size = 4096; + sh->data = g_malloc (4096); + + /* So offsets are > 0 */ + sh->index ++; +} + +static void +make_room_in_stream (MonoDynamicStream *stream, int size) +{ + if (size <= stream->alloc_size) + return; + + while (stream->alloc_size <= size) { + if (stream->alloc_size < 4096) + stream->alloc_size = 4096; + else + stream->alloc_size *= 2; + } + + stream->data = g_realloc (stream->data, stream->alloc_size); +} + +static guint32 +add_stream_data (MonoDynamicStream *stream, const char *data, guint32 len) +{ + guint32 idx; + + make_room_in_stream (stream, stream->index + len); + memcpy (stream->data + stream->index, data, len); + idx = stream->index; + stream->index += len; + return idx; +} + +/* + * add_to_blob: + * + * Add data to the binary blob inside the aot image. Returns the offset inside the + * blob where the data was stored. + */ +static guint32 +add_to_blob (MonoAotCompile *acfg, guint8 *data, guint32 data_len) +{ + if (acfg->blob.alloc_size == 0) + stream_init (&acfg->blob); + + return add_stream_data (&acfg->blob, (char*)data, data_len); +} + +/* + * emit_offset_table: + * + * Emit a table of increasing offsets in a compact form using differential encoding. + * There is an index entry for each GROUP_SIZE number of entries. The greater the + * group size, the more compact the table becomes, but the slower it becomes to compute + * a given entry. Returns the size of the table. + */ +static guint32 +emit_offset_table (MonoAotCompile *acfg, int noffsets, int group_size, gint32 *offsets) +{ + gint32 current_offset; + int i, buf_size, ngroups, index_entry_size; + guint8 *p, *buf; + guint32 *index_offsets; + + ngroups = (noffsets + (group_size - 1)) / group_size; + + index_offsets = g_new0 (guint32, ngroups); + + buf_size = noffsets * 4; + p = buf = g_malloc0 (buf_size); + + current_offset = 0; + for (i = 0; i < noffsets; ++i) { + //printf ("D: %d -> %d\n", i, offsets [i]); + if ((i % group_size) == 0) { + index_offsets [i / group_size] = p - buf; + /* Emit the full value for these entries */ + encode_value (offsets [i], p, &p); + } else { + /* The offsets are allowed to be non-increasing */ + //g_assert (offsets [i] >= current_offset); + encode_value (offsets [i] - current_offset, p, &p); + } + current_offset = offsets [i]; + } + + if (ngroups && index_offsets [ngroups - 1] < 65000) + index_entry_size = 2; + else + index_entry_size = 4; + + /* Emit the header */ + emit_int32 (acfg, noffsets); + emit_int32 (acfg, group_size); + emit_int32 (acfg, ngroups); + emit_int32 (acfg, index_entry_size); + + /* Emit the index */ + for (i = 0; i < ngroups; ++i) { + if (index_entry_size == 2) + emit_int16 (acfg, index_offsets [i]); + else + emit_int32 (acfg, index_offsets [i]); + } + + /* Emit the data */ + emit_bytes (acfg, buf, p - buf); + + return (int)(p - buf) + (ngroups * 4); +} + static guint32 get_image_index (MonoAotCompile *cfg, MonoImage *image) { @@ -1664,7 +1850,7 @@ get_method_index (MonoAotCompile *acfg, MonoMethod *method) } static int -add_method_full (MonoAotCompile *acfg, MonoMethod *method, gboolean extra) +add_method_full (MonoAotCompile *acfg, MonoMethod *method, gboolean extra, int depth) { int index; @@ -1678,6 +1864,8 @@ add_method_full (MonoAotCompile *acfg, MonoMethod *method, gboolean extra) /* FIXME: Fix quadratic behavior */ acfg->method_order = g_list_append (acfg->method_order, GUINT_TO_POINTER (index)); + g_hash_table_insert (acfg->method_depth, method, GUINT_TO_POINTER (depth)); + acfg->method_index ++; return index; @@ -1686,13 +1874,19 @@ add_method_full (MonoAotCompile *acfg, MonoMethod *method, gboolean extra) static int add_method (MonoAotCompile *acfg, MonoMethod *method) { - return add_method_full (acfg, method, FALSE); + return add_method_full (acfg, method, FALSE, 0); } static void add_extra_method (MonoAotCompile *acfg, MonoMethod *method) { - add_method_full (acfg, method, TRUE); + add_method_full (acfg, method, TRUE, 0); +} + +static void +add_extra_method_with_depth (MonoAotCompile *acfg, MonoMethod *method, int depth) +{ + add_method_full (acfg, method, TRUE, depth); } static void @@ -1823,8 +2017,14 @@ add_wrappers (MonoAotCompile *acfg) #ifdef MONO_ARCH_DYN_CALL_SUPPORTED if (!method->klass->contextbound) { MonoDynCallInfo *info = mono_arch_dyn_call_prepare (sig); + gboolean has_nullable = FALSE; + + for (j = 0; j < sig->param_count; j++) { + if (sig->params [j]->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (sig->params [j]))) + has_nullable = TRUE; + } - if (info) { + if (info && !has_nullable) { /* Supported by the dynamic runtime-invoke wrapper */ skip = TRUE; g_free (info); @@ -1993,7 +2193,7 @@ add_wrappers (MonoAotCompile *acfg) token = MONO_TOKEN_METHOD_DEF | (i + 1); method = mono_get_method (acfg->image, token, NULL); - if (method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED) + if (method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED && !method->is_generic) add_method (acfg, mono_marshal_get_synchronized_wrapper (method)); } @@ -2295,25 +2495,25 @@ add_generic_instances (MonoAotCompile *acfg) klass = mono_class_from_name (acfg->image, "System.Collections.Generic", "IEnumerable`1"); if (klass) add_instances_of (acfg, klass, insts, ninsts); - } - - /* - * Add a managed-to-native wrapper of Array.GetGenericValueImpl, which is - * used for all instances of GetGenericValueImpl by the AOT runtime. - */ - { - MonoGenericContext ctx; - MonoType *args [16]; - MonoMethod *get_method; - MonoClass *array_klass = mono_array_class_get (mono_defaults.object_class, 1)->parent; - - get_method = mono_class_get_method_from_name (array_klass, "GetGenericValueImpl", 2); - if (get_method) { - memset (&ctx, 0, sizeof (ctx)); - args [0] = &mono_defaults.object_class->byval_arg; - ctx.method_inst = mono_metadata_get_generic_inst (1, args); - add_extra_method (acfg, mono_marshal_get_native_wrapper (mono_class_inflate_generic_method (get_method, &ctx), TRUE, TRUE)); + /* + * Add a managed-to-native wrapper of Array.GetGenericValueImpl, which is + * used for all instances of GetGenericValueImpl by the AOT runtime. + */ + { + MonoGenericContext ctx; + MonoType *args [16]; + MonoMethod *get_method; + MonoClass *array_klass = mono_array_class_get (mono_defaults.object_class, 1)->parent; + + get_method = mono_class_get_method_from_name (array_klass, "GetGenericValueImpl", 2); + + if (get_method) { + memset (&ctx, 0, sizeof (ctx)); + args [0] = &mono_defaults.object_class->byval_arg; + ctx.method_inst = mono_metadata_get_generic_inst (1, args); + add_extra_method (acfg, mono_marshal_get_native_wrapper (mono_class_inflate_generic_method (get_method, &ctx), TRUE, TRUE)); + } } } } @@ -2686,8 +2886,8 @@ encode_patch (MonoAotCompile *acfg, MonoJumpInfo *patch_info, guint8 *buf, guint 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); + encode_value (((guint32 *)patch_info->data.target) [MINI_LS_WORD_IDX], p, &p); + encode_value (((guint32 *)patch_info->data.target) [MINI_MS_WORD_IDX], p, &p); break; case MONO_PATCH_INFO_VTABLE: case MONO_PATCH_INFO_CLASS: @@ -2762,7 +2962,6 @@ emit_method_info (MonoAotCompile *acfg, MonoCompile *cfg) GList *l; int pindex, buf_size, n_patches; guint8 *code; - char symbol [128]; GPtrArray *patches; MonoJumpInfo *patch_info; MonoMethodHeader *header; @@ -2776,9 +2975,6 @@ emit_method_info (MonoAotCompile *acfg, MonoCompile *cfg) method_index = get_method_index (acfg, method); - /* Make the labels local */ - sprintf (symbol, "%sm_%x_p", acfg->temp_prefix, method_index); - /* Sort relocations */ patches = g_ptr_array_new (); for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) @@ -2844,12 +3040,9 @@ emit_method_info (MonoAotCompile *acfg, MonoCompile *cfg) acfg->stats.info_size += p - buf; - /* Emit method info */ - - emit_label (acfg, symbol); - g_assert (p - buf < buf_size); - emit_bytes (acfg, buf, p - buf); + + cfg->method_info_offset = add_to_blob (acfg, buf, p - buf); g_free (buf); } @@ -2893,13 +3086,12 @@ emit_exception_debug_info (MonoAotCompile *acfg, MonoCompile *cfg) int i, k, buf_size, method_index; guint32 debug_info_size; guint8 *code; - char symbol [128]; MonoMethodHeader *header; guint8 *p, *buf, *debug_info; MonoJitInfo *jinfo = cfg->jit_info; guint32 flags; gboolean use_unwind_ops = FALSE; - GPtrArray *seq_points; + MonoSeqPointInfo *seq_points; method = cfg->orig_method; code = cfg->native_code; @@ -2907,9 +3099,6 @@ emit_exception_debug_info (MonoAotCompile *acfg, MonoCompile *cfg) method_index = get_method_index (acfg, method); - /* Make the labels local */ - sprintf (symbol, "%se_%x_p", acfg->temp_prefix, method_index); - if (!acfg->aot_opts.nodebug) { mono_debug_serialize_debug_info (cfg, &debug_info, &debug_info_size); } else { @@ -2917,23 +3106,17 @@ emit_exception_debug_info (MonoAotCompile *acfg, MonoCompile *cfg) debug_info_size = 0; } - buf_size = header->num_clauses * 256 + debug_info_size + 1024 + (cfg->seq_points ? (cfg->seq_points->len * 16) : 0); + seq_points = cfg->seq_point_info; + + buf_size = header->num_clauses * 256 + debug_info_size + 1024 + (seq_points ? (seq_points->len * 64) : 0); p = buf = g_malloc (buf_size); #ifdef MONO_ARCH_HAVE_XP_UNWIND use_unwind_ops = cfg->unwind_ops != NULL; #endif - seq_points = cfg->seq_points; - - flags = (jinfo->has_generic_jit_info ? 1 : 0) | (use_unwind_ops ? 2 : 0) | (header->num_clauses ? 4 : 0) | (seq_points ? 8 : 0); + flags = (jinfo->has_generic_jit_info ? 1 : 0) | (use_unwind_ops ? 2 : 0) | (header->num_clauses ? 4 : 0) | (seq_points ? 8 : 0) | (cfg->compile_llvm ? 16 : 0); - if (cfg->compile_llvm) { - /* Emitted by LLVM into the .eh_frame section */ - encode_value (0, p, &p); - } else { - encode_value (jinfo->code_size, p, &p); - } encode_value (flags, p, &p); if (use_unwind_ops) { @@ -2992,17 +3175,22 @@ emit_exception_debug_info (MonoAotCompile *acfg, MonoCompile *cfg) } if (seq_points) { - int il_offset, native_offset, last_il_offset, last_native_offset; + int il_offset, native_offset, last_il_offset, last_native_offset, j; encode_value (seq_points->len, p, &p); last_il_offset = last_native_offset = 0; - for (i = 0; i < seq_points->len; i += 2) { - il_offset = GPOINTER_TO_INT (g_ptr_array_index (seq_points, i)); - native_offset = GPOINTER_TO_INT (g_ptr_array_index (seq_points, i + 1)); + for (i = 0; i < seq_points->len; ++i) { + SeqPoint *sp = &seq_points->seq_points [i]; + il_offset = sp->il_offset; + native_offset = sp->native_offset; encode_value (il_offset - last_il_offset, p, &p); encode_value (native_offset - last_native_offset, p, &p); last_il_offset = il_offset; last_native_offset = native_offset; + + encode_value (sp->next_len, p, &p); + for (j = 0; j < sp->next_len; ++j) + encode_value (sp->next [j], p, &p); } } @@ -3018,22 +3206,19 @@ emit_exception_debug_info (MonoAotCompile *acfg, MonoCompile *cfg) acfg->stats.ex_info_size += p - buf; - /* Emit info */ - - emit_label (acfg, symbol); - g_assert (p - buf < buf_size); - emit_bytes (acfg, buf, p - buf); + + /* Emit info */ + cfg->ex_info_offset = add_to_blob (acfg, buf, p - buf); g_free (buf); } -static void +static guint32 emit_klass_info (MonoAotCompile *acfg, guint32 token) { MonoClass *klass = mono_class_get (acfg->image, token); guint8 *p, *buf; - int i, buf_size; - char symbol [128]; + int i, buf_size, res; gboolean no_special_static, cant_encode; gpointer iter = NULL; @@ -3070,7 +3255,7 @@ emit_klass_info (MonoAotCompile *acfg, guint32 token) encode_value (-1, p, &p); } else { encode_value (klass->vtable_size, p, &p); - encode_value ((no_special_static << 7) | (klass->has_static_refs << 6) | (klass->has_references << 5) | ((klass->blittable << 4) | ((klass->ext && klass->ext->nested_classes) ? 1 : 0) << 3) | (klass->has_cctor << 2) | (klass->has_finalize << 1) | klass->ghcimpl, p, &p); + encode_value ((klass->generic_container ? (1 << 8) : 0) | (no_special_static << 7) | (klass->has_static_refs << 6) | (klass->has_references << 5) | ((klass->blittable << 4) | ((klass->ext && klass->ext->nested_classes) ? 1 : 0) << 3) | (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) @@ -3093,13 +3278,11 @@ emit_klass_info (MonoAotCompile *acfg, guint32 token) acfg->stats.class_info_size += p - buf; - /* Emit the info */ - sprintf (symbol, "%sK_I_%x", acfg->temp_prefix, token - MONO_TOKEN_TYPE_DEF - 1); - emit_label (acfg, symbol); - g_assert (p - buf < buf_size); - emit_bytes (acfg, buf, p - buf); + res = add_to_blob (acfg, buf, p - buf); g_free (buf); + + return res; } /* @@ -3227,7 +3410,7 @@ emit_trampoline (MonoAotCompile *acfg, const char *name, guint8 *code, { char start_symbol [256]; char symbol [256]; - guint32 buf_size; + guint32 buf_size, info_offset; MonoJumpInfo *patch_info; guint8 *buf, *p; GPtrArray *patches; @@ -3270,11 +3453,13 @@ emit_trampoline (MonoAotCompile *acfg, const char *name, guint8 *code, sprintf (symbol, "%s_p", name); + info_offset = add_to_blob (acfg, buf, p - buf); + emit_section_change (acfg, ".text", 0); emit_global (acfg, symbol, FALSE); emit_label (acfg, symbol); - - emit_bytes (acfg, buf, p - buf); + + emit_int32 (acfg, info_offset); /* Emit debug info */ if (unwind_ops) { @@ -3519,16 +3704,18 @@ mono_aot_parse_options (const char *aot_options, MonoAotOptions *opts) opts->nodebug = TRUE; } else if (str_begins_with (arg, "ntrampolines=")) { opts->ntrampolines = atoi (arg + strlen ("ntrampolines=")); + } else if (str_begins_with (arg, "nrgctx-trampolines=")) { + opts->nrgctx_trampolines = atoi (arg + strlen ("nrgctx-trampolines=")); } else if (str_begins_with (arg, "autoreg")) { opts->autoreg = TRUE; } else if (str_begins_with (arg, "tool-prefix=")) { opts->tool_prefix = g_strdup (arg + strlen ("tool-prefix=")); - } else if (str_begins_with (arg, "autoreg")) { - opts->autoreg = TRUE; } else if (str_begins_with (arg, "soft-debug")) { opts->soft_debug = TRUE; } else if (str_begins_with (arg, "print-skipped")) { opts->print_skipped_methods = TRUE; + } else if (str_begins_with (arg, "stats")) { + opts->stats = TRUE; } else { fprintf (stderr, "AOT : Unknown argument '%s'.\n", arg); exit (1); @@ -3644,7 +3831,7 @@ compile_method (MonoAotCompile *acfg, MonoMethod *method) MonoCompile *cfg; MonoJumpInfo *patch_info; gboolean skip; - int index; + int index, depth; MonoMethod *wrapped; if (acfg->aot_opts.metadata_only) @@ -3768,34 +3955,41 @@ compile_method (MonoAotCompile *acfg, MonoMethod *method) } /* Adds generic instances referenced by this method */ - for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) { - switch (patch_info->type) { - case MONO_PATCH_INFO_METHOD: { - MonoMethod *m = patch_info->data.method; - if (m->is_inflated) { - if (!(mono_class_generic_sharing_enabled (m->klass) && - mono_method_is_generic_sharable_impl (m, FALSE)) && - !method_has_type_vars (m)) { - if (m->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) { - if (acfg->aot_opts.full_aot) - add_extra_method (acfg, mono_marshal_get_native_wrapper (m, TRUE, TRUE)); - } else { - add_extra_method (acfg, m); + /* + * The depth is used to avoid infinite loops when generic virtual recursion is + * encountered. + */ + depth = GPOINTER_TO_UINT (g_hash_table_lookup (acfg->method_depth, method)); + if (depth < 32) { + for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) { + switch (patch_info->type) { + case MONO_PATCH_INFO_METHOD: { + MonoMethod *m = patch_info->data.method; + if (m->is_inflated) { + if (!(mono_class_generic_sharing_enabled (m->klass) && + mono_method_is_generic_sharable_impl (m, FALSE)) && + !method_has_type_vars (m)) { + if (m->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) { + if (acfg->aot_opts.full_aot) + add_extra_method_with_depth (acfg, mono_marshal_get_native_wrapper (m, TRUE, TRUE), depth + 1); + } else { + add_extra_method_with_depth (acfg, m, depth + 1); + } } + add_generic_class (acfg, m->klass); } - add_generic_class (acfg, m->klass); + break; } - break; - } - case MONO_PATCH_INFO_VTABLE: { - MonoClass *klass = patch_info->data.klass; + case MONO_PATCH_INFO_VTABLE: { + MonoClass *klass = patch_info->data.klass; - if (klass->generic_class && !mono_generic_context_is_sharable (&klass->generic_class->context, FALSE)) - add_generic_class (acfg, klass); - break; - } - default: - break; + if (klass->generic_class && !mono_generic_context_is_sharable (&klass->generic_class->context, FALSE)) + add_generic_class (acfg, klass); + break; + } + default: + break; + } } } @@ -4050,7 +4244,7 @@ mono_aot_patch_info_dup (MonoJumpInfo* ji) static void emit_llvm_file (MonoAotCompile *acfg) { - char *command; + char *command, *opts; int i; MonoJumpInfo *patch_info; @@ -4076,8 +4270,24 @@ emit_llvm_file (MonoAotCompile *acfg) mono_llvm_emit_aot_module ("temp.bc", acfg->final_got_size); + /* + * FIXME: Experiment with adding optimizations, the -std-compile-opts set takes + * a lot of time, and doesn't seem to save much space. + * The following optimizations cannot be enabled: + * - 'tailcallelim' + */ + opts = g_strdup ("-instcombine -simplifycfg"); +#if 1 + command = g_strdup_printf ("opt -f %s -o temp.opt.bc temp.bc", opts); + printf ("Executing opt: %s\n", command); + if (system (command) != 0) { + exit (1); + } +#endif + g_free (opts); + //command = g_strdup_printf ("llc -march=arm -mtriple=arm-linux-gnueabi -f -relocation-model=pic -unwind-tables temp.bc"); - command = g_strdup_printf ("llc -f -relocation-model=pic -unwind-tables temp.bc"); + command = g_strdup_printf ("llc -f -relocation-model=pic -unwind-tables -o temp.s temp.opt.bc"); printf ("Executing llc: %s\n", command); if (system (command) != 0) { @@ -4132,12 +4342,14 @@ emit_code (MonoAotCompile *acfg) emit_alignment (acfg, 8); emit_label (acfg, symbol); - sprintf (symbol, "method_offsets"); + sprintf (symbol, "code_offsets"); emit_section_change (acfg, ".text", 1); emit_global (acfg, symbol, FALSE); emit_alignment (acfg, 8); emit_label (acfg, symbol); + acfg->stats.offsets_size += acfg->nmethods * 4; + for (i = 0; i < acfg->nmethods; ++i) { if (acfg->cfgs [i]) { sprintf (symbol, "%sm_%x", acfg->temp_prefix, i); @@ -4155,23 +4367,19 @@ emit_info (MonoAotCompile *acfg) int i; char symbol [256]; GList *l; + gint32 *offsets; - /* Emit method info */ - sprintf (symbol, "method_info"); - emit_section_change (acfg, ".text", 1); - emit_global (acfg, symbol, FALSE); - emit_alignment (acfg, 8); - emit_label (acfg, symbol); - - /* To reduce size of generated assembly code */ - sprintf (symbol, "mi"); - emit_label (acfg, symbol); + offsets = g_new0 (gint32, acfg->nmethods); for (l = acfg->method_order; l != NULL; l = l->next) { i = GPOINTER_TO_UINT (l->data); - if (acfg->cfgs [i]) + if (acfg->cfgs [i]) { emit_method_info (acfg, acfg->cfgs [i]); + offsets [i] = acfg->cfgs [i]->method_info_offset; + } else { + offsets [i] = 0; + } } sprintf (symbol, "method_info_offsets"); @@ -4180,40 +4388,13 @@ emit_info (MonoAotCompile *acfg) emit_alignment (acfg, 8); emit_label (acfg, symbol); - for (i = 0; i < acfg->nmethods; ++i) { - if (acfg->cfgs [i]) { - sprintf (symbol, "%sm_%x_p", acfg->temp_prefix, i); - emit_symbol_diff (acfg, symbol, "mi", 0); - } else { - emit_int32 (acfg, 0); - } - } - emit_line (acfg); + acfg->stats.offsets_size += emit_offset_table (acfg, acfg->nmethods, 10, offsets); + + g_free (offsets); } #endif /* #if !defined(DISABLE_AOT) && !defined(DISABLE_JIT) */ -/* - * mono_aot_str_hash: - * - * Hash function for strings which we use to hash strings for things which are - * saved in the AOT image, since g_str_hash () can change. - */ -guint -mono_aot_str_hash (gconstpointer v1) -{ - /* Same as g_str_hash () in glib */ - char *p = (char *) v1; - guint hash = *p; - - while (*p++) { - if (*p) - hash = (hash << 5) - hash + *p; - } - - return hash; -} - #define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k)))) #define mix(a,b,c) { \ a -= c; a ^= rot(c, 4); c += b; \ @@ -4244,11 +4425,11 @@ mono_aot_type_hash (MonoType *t1) case MONO_TYPE_CLASS: case MONO_TYPE_SZARRAY: /* check if the distribution is good enough */ - return ((hash << 5) - hash) ^ mono_aot_str_hash (t1->data.klass->name); + return ((hash << 5) - hash) ^ mono_metadata_str_hash (t1->data.klass->name); case MONO_TYPE_PTR: - return ((hash << 5) - hash) ^ mono_aot_type_hash (t1->data.type); + return ((hash << 5) - hash) ^ mono_metadata_type_hash (t1->data.type); case MONO_TYPE_ARRAY: - return ((hash << 5) - hash) ^ mono_aot_type_hash (&t1->data.array->eklass->byval_arg); + return ((hash << 5) - hash) ^ mono_metadata_type_hash (&t1->data.array->eklass->byval_arg); case MONO_TYPE_GENERICINST: return ((hash << 5) - hash) ^ 0; } @@ -4287,18 +4468,18 @@ mono_aot_method_hash (MonoMethod *method) if (!method->wrapper_type) { char *full_name = mono_type_full_name (&klass->byval_arg); - hashes [0] = mono_aot_str_hash (full_name); + hashes [0] = mono_metadata_str_hash (full_name); hashes [1] = 0; g_free (full_name); } else { - hashes [0] = mono_aot_str_hash (klass->name); - hashes [1] = mono_aot_str_hash (klass->name_space); + hashes [0] = mono_metadata_str_hash (klass->name); + hashes [1] = mono_metadata_str_hash (klass->name_space); } if (method->wrapper_type == MONO_WRAPPER_STFLD || method->wrapper_type == MONO_WRAPPER_LDFLD || method->wrapper_type == MONO_WRAPPER_LDFLDA) /* The method name includes a stringified pointer */ hashes [2] = 0; else - hashes [2] = mono_aot_str_hash (method->name); + hashes [2] = mono_metadata_str_hash (method->name); hashes [3] = method->wrapper_type; hashes [4] = mono_aot_type_hash (sig->ret); for (i = 0; i < sig->param_count; i++) { @@ -4460,14 +4641,8 @@ emit_extra_methods (MonoAotCompile *acfg) info_offsets = g_new0 (guint32, acfg->extra_methods->len); - buf_size = acfg->extra_methods->len * 256 + 256; - p = buf = g_malloc (buf_size); - - /* Encode method info */ + /* Emit method info */ nmethods = 0; - /* So offsets are > 0 */ - *p = 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); @@ -4476,8 +4651,10 @@ emit_extra_methods (MonoAotCompile *acfg) if (!cfg) continue; + buf_size = 512; + p = buf = g_malloc (buf_size); + nmethods ++; - info_offsets [i] = p - buf; name = NULL; if (method->wrapper_type) { @@ -4514,20 +4691,10 @@ emit_extra_methods (MonoAotCompile *acfg) } g_assert ((p - buf) < buf_size); - } - - g_assert ((p - buf) < buf_size); - - /* Emit method info */ - sprintf (symbol, "extra_method_info"); - emit_section_change (acfg, ".text", 1); - emit_global (acfg, symbol, FALSE); - emit_alignment (acfg, 8); - emit_label (acfg, symbol); - emit_bytes (acfg, buf, p - buf); - - emit_line (acfg); + info_offsets [i] = add_to_blob (acfg, buf, p - buf); + g_free (buf); + } /* * Construct a chained hash table for mapping indexes in extra_method_info to @@ -4625,20 +4792,16 @@ emit_exception_info (MonoAotCompile *acfg) { int i; char symbol [256]; + gint32 *offsets; - sprintf (symbol, "ex_info"); - emit_section_change (acfg, ".text", 1); - emit_global (acfg, symbol, FALSE); - emit_alignment (acfg, 8); - emit_label (acfg, symbol); - - /* To reduce size of generated assembly */ - sprintf (symbol, "ex"); - emit_label (acfg, symbol); - + offsets = g_new0 (gint32, acfg->nmethods); for (i = 0; i < acfg->nmethods; ++i) { - if (acfg->cfgs [i]) + if (acfg->cfgs [i]) { emit_exception_debug_info (acfg, acfg->cfgs [i]); + offsets [i] = acfg->cfgs [i]->ex_info_offset; + } else { + offsets [i] = 0; + } } sprintf (symbol, "ex_info_offsets"); @@ -4647,15 +4810,8 @@ emit_exception_info (MonoAotCompile *acfg) emit_alignment (acfg, 8); emit_label (acfg, symbol); - for (i = 0; i < acfg->nmethods; ++i) { - if (acfg->cfgs [i]) { - sprintf (symbol, "%se_%x_p", acfg->temp_prefix, i); - emit_symbol_diff (acfg, symbol, "ex", 0); - } else { - emit_int32 (acfg, 0); - } - } - emit_line (acfg); + acfg->stats.offsets_size += emit_offset_table (acfg, acfg->nmethods, 10, offsets); + g_free (offsets); } static void @@ -4699,15 +4855,11 @@ emit_class_info (MonoAotCompile *acfg) { int i; char symbol [256]; + gint32 *offsets; - sprintf (symbol, "class_info"); - emit_section_change (acfg, ".text", 1); - emit_global (acfg, symbol, FALSE); - emit_alignment (acfg, 8); - emit_label (acfg, symbol); - + offsets = g_new0 (gint32, acfg->image->tables [MONO_TABLE_TYPEDEF].rows); for (i = 0; i < acfg->image->tables [MONO_TABLE_TYPEDEF].rows; ++i) - emit_klass_info (acfg, MONO_TOKEN_TYPE_DEF | (i + 1)); + offsets [i] = emit_klass_info (acfg, MONO_TOKEN_TYPE_DEF | (i + 1)); sprintf (symbol, "class_info_offsets"); emit_section_change (acfg, ".text", 1); @@ -4715,11 +4867,8 @@ emit_class_info (MonoAotCompile *acfg) emit_alignment (acfg, 8); emit_label (acfg, symbol); - for (i = 0; i < acfg->image->tables [MONO_TABLE_TYPEDEF].rows; ++i) { - sprintf (symbol, "%sK_I_%x", acfg->temp_prefix, i); - emit_symbol_diff (acfg, symbol, "class_info", 0); - } - emit_line (acfg); + acfg->stats.offsets_size += emit_offset_table (acfg, acfg->image->tables [MONO_TABLE_TYPEDEF].rows, 10, offsets); + g_free (offsets); } typedef struct ClassNameTableEntry { @@ -4749,7 +4898,7 @@ emit_class_name_table (MonoAotCompile *acfg) token = MONO_TOKEN_TYPE_DEF | (i + 1); klass = mono_class_get (acfg->image, token); full_name = mono_type_get_name_full (mono_class_get_type (klass), MONO_TYPE_NAME_FORMAT_FULL_NAME); - hash = mono_aot_str_hash (full_name) % table_size; + hash = mono_metadata_str_hash (full_name) % table_size; g_free (full_name); /* FIXME: Allocate from the mempool */ @@ -4877,25 +5026,18 @@ emit_got_info (MonoAotCompile *acfg) for (i = 0; i < acfg->got_patches->len; ++i) { MonoJumpInfo *ji = g_ptr_array_index (acfg->got_patches, i); - got_info_offsets [i] = p - buf; - if (i >= first_plt_got_patch) - acfg->plt_got_info_offsets [i - first_plt_got_patch + 1] = got_info_offsets [i]; + p = buf; + encode_value (ji->type, p, &p); encode_patch (acfg, ji, p, &p); - } - - g_assert (p - buf <= buf_size); - acfg->stats.got_info_size = p - buf; - - /* Emit got_info table */ - sprintf (symbol, "got_info"); - emit_section_change (acfg, ".text", 1); - emit_global (acfg, symbol, FALSE); - emit_alignment (acfg, 8); - emit_label (acfg, symbol); + g_assert (p - buf <= buf_size); + got_info_offsets [i] = add_to_blob (acfg, buf, p - buf); - emit_bytes (acfg, buf, p - buf); + if (i >= first_plt_got_patch) + acfg->plt_got_info_offsets [i - first_plt_got_patch + 1] = got_info_offsets [i]; + acfg->stats.got_info_size += p - buf; + } /* Emit got_info_offsets table */ sprintf (symbol, "got_info_offsets"); @@ -4905,10 +5047,7 @@ emit_got_info (MonoAotCompile *acfg) emit_label (acfg, symbol); /* No need to emit offsets for the got plt entries, the plt embeds them directly */ - for (i = 0; i < first_plt_got_patch; ++i) - emit_int32 (acfg, got_info_offsets [i]); - - acfg->stats.got_info_offsets_size = acfg->got_patches->len * 4; + acfg->stats.offsets_size += emit_offset_table (acfg, first_plt_got_patch, 10, (gint32*)got_info_offsets); } static void @@ -4938,22 +5077,118 @@ emit_got (MonoAotCompile *acfg) emit_pointer (acfg, acfg->got_symbol); } +typedef struct GlobalsTableEntry { + guint32 value, index; + struct GlobalsTableEntry *next; +} GlobalsTableEntry; + +static void +emit_globals_table (MonoAotCompile *acfg) +{ + int i, table_size; + guint32 hash; + GPtrArray *table; + char symbol [256]; + GlobalsTableEntry *entry, *new_entry; + + /* + * Construct a chained hash table for mapping global names to their index in + * the globals table. + */ + table_size = g_spaced_primes_closest ((int)(acfg->globals->len * 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->globals->len; ++i) { + char *name = g_ptr_array_index (acfg->globals, i); + + hash = mono_metadata_str_hash (name) % table_size; + + /* FIXME: Allocate from the mempool */ + new_entry = g_new0 (GlobalsTableEntry, 1); + new_entry->value = i; + + entry = g_ptr_array_index (table, hash); + if (entry == NULL) { + new_entry->index = hash; + g_ptr_array_index (table, hash) = new_entry; + } else { + while (entry->next) + entry = entry->next; + + entry->next = new_entry; + new_entry->index = table->len; + g_ptr_array_add (table, new_entry); + } + } + + /* Emit the table */ + sprintf (symbol, ".Lglobals_hash"); + emit_section_change (acfg, ".text", 0); + emit_alignment (acfg, 8); + emit_label (acfg, symbol); + + /* FIXME: Optimize memory usage */ + g_assert (table_size < 65000); + emit_int16 (acfg, table_size); + for (i = 0; i < table->len; ++i) { + GlobalsTableEntry *entry = g_ptr_array_index (table, i); + + if (entry == NULL) { + emit_int16 (acfg, 0); + emit_int16 (acfg, 0); + } else { + emit_int16 (acfg, entry->value + 1); + if (entry->next) + emit_int16 (acfg, entry->next->index); + else + emit_int16 (acfg, 0); + } + } + + /* Emit the names */ + for (i = 0; i < acfg->globals->len; ++i) { + char *name = g_ptr_array_index (acfg->globals, i); + + sprintf (symbol, "name_%d", i); + emit_section_change (acfg, ".text", 1); + emit_label (acfg, symbol); + emit_string (acfg, name); + } + + /* Emit the globals table */ + sprintf (symbol, ".Lglobals"); + emit_section_change (acfg, ".data", 0); + /* This is not a global, since it is accessed by the init function */ + emit_alignment (acfg, 8); + emit_label (acfg, symbol); + + sprintf (symbol, "%sglobals_hash", acfg->temp_prefix); + emit_pointer (acfg, symbol); + + for (i = 0; i < acfg->globals->len; ++i) { + char *name = g_ptr_array_index (acfg->globals, i); + + sprintf (symbol, "name_%d", i); + emit_pointer (acfg, symbol); + + sprintf (symbol, "%s", name); + emit_pointer (acfg, symbol); + } + /* Null terminate the table */ + emit_int32 (acfg, 0); + emit_int32 (acfg, 0); +} + static void emit_globals (MonoAotCompile *acfg) { - char *opts_str; char *build_info; emit_string_symbol (acfg, "mono_assembly_guid" , acfg->image->guid); emit_string_symbol (acfg, "mono_aot_version", MONO_AOT_FILE_VERSION); - opts_str = g_strdup_printf ("%d", acfg->opts); - emit_string_symbol (acfg, "mono_aot_opt_flags", opts_str); - g_free (opts_str); - - emit_string_symbol (acfg, "mono_aot_full_aot", acfg->aot_opts.full_aot ? "TRUE" : "FALSE"); - if (acfg->aot_opts.bind_to_runtime_version) { build_info = mono_get_runtime_build_info (); emit_string_symbol (acfg, "mono_runtime_version", build_info); @@ -4966,42 +5201,13 @@ emit_globals (MonoAotCompile *acfg) * When static linking, we emit a global which will point to the symbol table. */ if (acfg->aot_opts.static_link) { - int i; char symbol [256]; char *p; /* Emit a string holding the assembly name */ emit_string_symbol (acfg, "mono_aot_assembly_name", acfg->image->assembly->aname.name); - /* Emit the names */ - for (i = 0; i < acfg->globals->len; ++i) { - char *name = g_ptr_array_index (acfg->globals, i); - - sprintf (symbol, "name_%d", i); - emit_section_change (acfg, ".text", 1); - emit_label (acfg, symbol); - emit_string (acfg, name); - } - - /* Emit the globals table */ - sprintf (symbol, ".Lglobals"); - emit_section_change (acfg, ".data", 0); - /* This is not a global, since it is accessed by the init function */ - emit_alignment (acfg, 8); - emit_label (acfg, symbol); - - for (i = 0; i < acfg->globals->len; ++i) { - char *name = g_ptr_array_index (acfg->globals, i); - - sprintf (symbol, "name_%d", i); - emit_pointer (acfg, symbol); - - sprintf (symbol, "%s", name); - emit_pointer (acfg, symbol); - } - /* Null terminate the table */ - emit_int32 (acfg, 0); - emit_int32 (acfg, 0); + emit_globals_table (acfg); /* * Emit a global symbol which can be passed by an embedding app to @@ -5023,7 +5229,8 @@ emit_globals (MonoAotCompile *acfg) emit_global_inner (acfg, symbol, FALSE); emit_alignment (acfg, 8); emit_label (acfg, symbol); - emit_pointer (acfg, ".Lglobals"); + sprintf (symbol, "%sglobals", acfg->temp_prefix); + emit_pointer (acfg, symbol); } } @@ -5041,67 +5248,7 @@ emit_autoreg (MonoAotCompile *acfg) symbol = g_strdup_printf ("_%s_autoreg", acfg->static_linking_symbol); -#if defined(TARGET_POWERPC) && defined(__mono_ilp32__) - /* Based on code generated by gcc */ - img_writer_emit_unset_mode (acfg->w); - - fprintf (acfg->fp, -#ifdef _MSC_VER - ".section .ctors,\"aw\",@progbits\n" - ".align 2\n" - ".globl %s\n" - ".long %s\n" - ".section .opd,\"aw\"\n" - ".align 2\n" - "%s:\n" - ".long .%s,.TOC.@tocbase32\n" - ".size %s,.-%s\n" - ".section .text\n" - ".type .%s,@function\n" - ".%s:\n", symbol, symbol, symbol, symbol, symbol, symbol, symbol, symbol); -#else - ".section .ctors,\"aw\",@progbits\n" - ".align 2\n" - ".globl %1$s\n" - ".long %1$s\n" - ".section .opd,\"aw\"\n" - ".align 2\n" - "%1$s:\n" - ".long .%1$s,.TOC.@tocbase32\n" - ".size %1$s,.-%1$s\n" - ".section .text\n" - ".type .%1$s,@function\n" - ".%1$s:\n", symbol); -#endif - - - fprintf (acfg->fp, - "stdu 1,-128(1)\n" - "mflr 0\n" - "std 31,120(1)\n" - "std 0,144(1)\n" - - ".Lautoreg:\n" - "lis 3, .Lglobals@h\n" - "ori 3, 3, .Lglobals@l\n" - "bl .mono_aot_register_module\n" - "ld 11,0(1)\n" - "ld 0,16(11)\n" - "mtlr 0\n" - "ld 31,-8(11)\n" - "mr 1,11\n" - "blr\n" - ); -#ifdef _MSC_VER - fprintf (acfg->fp, - ".size .%s,.-.%s\n", symbol, symbol); -#else - fprintf (acfg->fp, - ".size .%1$s,.-.%1$s\n", symbol); -#endif -#else - g_assert_not_reached (); -#endif + arch_emit_autoreg (acfg, symbol); g_free (symbol); } @@ -5139,6 +5286,7 @@ emit_file_info (MonoAotCompile *acfg) emit_int32 (acfg, acfg->plt_offset); emit_int32 (acfg, acfg->nmethods); emit_int32 (acfg, acfg->flags); + emit_int32 (acfg, acfg->opts); for (i = 0; i < MONO_AOT_TRAMP_NUM; ++i) emit_int32 (acfg, acfg->num_trampolines [i]); @@ -5148,6 +5296,20 @@ emit_file_info (MonoAotCompile *acfg) emit_int32 (acfg, acfg->trampoline_size [i]); } +static void +emit_blob (MonoAotCompile *acfg) +{ + char symbol [128]; + + sprintf (symbol, "blob"); + emit_section_change (acfg, ".text", 1); + emit_global (acfg, symbol, FALSE); + emit_alignment (acfg, 8); + emit_label (acfg, symbol); + + emit_bytes (acfg, (guint8*)acfg->blob.data, acfg->blob.index); +} + static void emit_dwarf_info (MonoAotCompile *acfg) { @@ -5421,6 +5583,7 @@ acfg_create (MonoAssembly *ass, guint32 opts) acfg = g_new0 (MonoAotCompile, 1); acfg->methods = g_ptr_array_new (); acfg->method_indexes = g_hash_table_new (NULL, NULL); + acfg->method_depth = g_hash_table_new (NULL, NULL); acfg->plt_offset_to_patch = g_hash_table_new (NULL, NULL); acfg->patch_to_plt_offset = g_hash_table_new (mono_patch_info_hash, mono_patch_info_equal); acfg->patch_to_got_offset = g_hash_table_new (mono_patch_info_hash, mono_patch_info_equal); @@ -5464,6 +5627,7 @@ acfg_free (MonoAotCompile *acfg) g_ptr_array_free (acfg->globals, TRUE); g_ptr_array_free (acfg->unwind_ops, TRUE); g_hash_table_destroy (acfg->method_indexes); + g_hash_table_destroy (acfg->method_depth); g_hash_table_destroy (acfg->plt_offset_to_patch); g_hash_table_destroy (acfg->patch_to_plt_offset); g_hash_table_destroy (acfg->patch_to_got_offset); @@ -5496,6 +5660,7 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options) memset (&acfg->aot_opts, 0, sizeof (acfg->aot_opts)); acfg->aot_opts.write_symbols = TRUE; acfg->aot_opts.ntrampolines = 1024; + acfg->aot_opts.nrgctx_trampolines = 1024; mono_aot_parse_options (aot_options, &acfg->aot_opts); @@ -5532,11 +5697,14 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options) acfg->flags |= MONO_AOT_FILE_FLAG_WITH_LLVM; #endif + if (acfg->aot_opts.full_aot) + acfg->flags |= MONO_AOT_FILE_FLAG_FULL_AOT; + load_profile_files (acfg); acfg->num_trampolines [MONO_AOT_TRAMP_SPECIFIC] = acfg->aot_opts.full_aot ? acfg->aot_opts.ntrampolines : 0; #ifdef MONO_ARCH_HAVE_STATIC_RGCTX_TRAMPOLINE - acfg->num_trampolines [MONO_AOT_TRAMP_STATIC_RGCTX] = acfg->aot_opts.full_aot ? 1024 : 0; + acfg->num_trampolines [MONO_AOT_TRAMP_STATIC_RGCTX] = acfg->aot_opts.full_aot ? acfg->aot_opts.nrgctx_trampolines : 0; #endif acfg->num_trampolines [MONO_AOT_TRAMP_IMT_THUNK] = acfg->aot_opts.full_aot ? 128 : 0; @@ -5679,6 +5847,8 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options) emit_file_info (acfg); + emit_blob (acfg); + emit_globals (acfg); emit_autoreg (acfg); @@ -5697,7 +5867,7 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options) if (acfg->llvm) g_assert (acfg->got_offset == acfg->final_got_size); - printf ("Code: %d Info: %d Ex Info: %d Unwind Info: %d Class Info: %d PLT: %d GOT Info: %d GOT Info Offsets: %d GOT: %d Offsets: %d\n", acfg->stats.code_size, acfg->stats.info_size, acfg->stats.ex_info_size, acfg->stats.unwind_info_size, acfg->stats.class_info_size, acfg->plt_offset, acfg->stats.got_info_size, acfg->stats.got_info_offsets_size, (int)(acfg->got_offset * sizeof (gpointer)), (int)(acfg->nmethods * 3 * sizeof (gpointer))); + printf ("Code: %d Info: %d Ex Info: %d Unwind Info: %d Class Info: %d PLT: %d GOT Info: %d GOT: %d Offsets: %d\n", acfg->stats.code_size, acfg->stats.info_size, acfg->stats.ex_info_size, acfg->stats.unwind_info_size, acfg->stats.class_info_size, acfg->plt_offset, acfg->stats.got_info_size, (int)(acfg->got_offset * sizeof (gpointer)), acfg->stats.offsets_size); TV_GETTIME (atv); res = img_writer_emit_writeout (acfg->w); @@ -5736,12 +5906,14 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options) printf ("Methods without GOT slots: %d (%d%%)\n", acfg->stats.methods_without_got_slots, acfg->stats.mcount ? (acfg->stats.methods_without_got_slots * 100) / acfg->stats.mcount : 100); printf ("Direct calls: %d (%d%%)\n", acfg->stats.direct_calls, acfg->stats.all_calls ? (acfg->stats.direct_calls * 100) / acfg->stats.all_calls : 100); - /* - printf ("GOT slot distribution:\n"); - for (i = 0; i < MONO_PATCH_INFO_NONE; ++i) - if (acfg->stats.got_slot_types [i]) - printf ("\t%s: %d\n", get_patch_name (i), acfg->stats.got_slot_types [i]); - */ + if (acfg->aot_opts.stats) { + int i; + + printf ("GOT slot distribution:\n"); + for (i = 0; i < MONO_PATCH_INFO_NONE; ++i) + if (acfg->stats.got_slot_types [i]) + printf ("\t%s: %d\n", get_patch_name (i), acfg->stats.got_slot_types [i]); + } printf ("JIT time: %d ms, Generation time: %d ms, Assembly+Link time: %d ms.\n", acfg->stats.jit_time / 1000, acfg->stats.gen_time / 1000, acfg->stats.link_time / 1000); @@ -5953,7 +6125,7 @@ xdebug_end_emit (MonoImageWriter *w, MonoDwarfWriter *dw, MonoMethod *method) * This could be called from inside gdb to flush the debugging information not yet * registered with gdb. */ -static void +void mono_xdebug_flush (void) { if (xdebug_w)