X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mono%2Fmini%2Faot-compiler.c;h=2f231bb48780579f7b1b6dfa4b66b69c9efbe87c;hb=f50cce0a651dccb72b7c667d4a8eebf9c622c81f;hp=25de402c1ab7c133fb56755533aa7a235e11d455;hpb=0e5ba7097b8e61a87ed70c534b22e2ffb6238e5a;p=mono.git diff --git a/mono/mini/aot-compiler.c b/mono/mini/aot-compiler.c index 25de402c1ab..2f231bb4878 100644 --- a/mono/mini/aot-compiler.c +++ b/mono/mini/aot-compiler.c @@ -44,10 +44,6 @@ #include #include -#include /* for PAGESIZE */ -#ifndef PAGESIZE -#define PAGESIZE 4096 -#endif #include #include @@ -62,15 +58,17 @@ #include #include #include +#include #include #include #include +#include #include "mini.h" #include "image-writer.h" #include "dwarfwriter.h" -#ifndef DISABLE_AOT +#if !defined(DISABLE_AOT) && !defined(DISABLE_JIT) #define TV_DECLARE(name) gint64 name #define TV_GETTIME(tv) tv = mono_100ns_ticks () @@ -99,13 +97,15 @@ typedef struct MonoAotOptions { gboolean static_link; gboolean asm_only; gboolean asm_writer; + gboolean nodebug; int nthreads; + int ntrampolines; gboolean print_skipped_methods; } MonoAotOptions; typedef struct MonoAotStats { int ccount, mcount, lmfcount, abscount, gcount, ocount, genericcount; - int code_size, info_size, ex_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, got_info_offsets_size; int methods_without_got_slots, direct_calls, all_calls; int got_slots; int got_slot_types [MONO_PATCH_INFO_NONE]; @@ -130,13 +130,16 @@ typedef struct MonoAotCompile { GPtrArray *globals; GList *method_order; guint32 *plt_got_info_offsets; - /* Number of trampolines emitted into the AOT file */ - guint32 num_aot_trampolines; guint32 got_offset, plt_offset, plt_got_offset_base; /* Number of GOT entries reserved for trampolines */ guint32 num_trampoline_got_entries; - guint32 trampoline_got_offset_base; + guint32 num_specific_trampolines; guint32 specific_trampoline_size; + guint32 specific_trampoline_got_offset_base; + /* Same for static rgctx trampolines */ + guint32 num_static_rgctx_trampolines; + guint32 static_rgctx_trampoline_size; + guint32 static_rgctx_trampoline_got_offset_base; MonoAotOptions aot_opts; guint32 nmethods; guint32 opts; @@ -151,6 +154,9 @@ typedef struct MonoAotCompile { FILE *fp; char *tmpfname; GSList *cie_program; + GHashTable *unwind_info_offsets; + GPtrArray *unwind_ops; + guint32 unwind_info_offset; } MonoAotCompile; #define mono_acfg_lock(acfg) EnterCriticalSection (&((acfg)->mutex)) @@ -174,7 +180,7 @@ static const gint16 opidx [] = { #undef PATCH_INFO }; -static const char* +static G_GNUC_UNUSED const char* get_patch_name (int info) { return (const char*)&opstr + opidx [info]; @@ -196,9 +202,6 @@ get_patch_name (int info) #endif -static void -emit_global (MonoAotCompile *acfg, const char *name, gboolean func); - /* Wrappers around the image writer functions */ static inline void @@ -411,7 +414,7 @@ encode_sleb128 (gint32 value, guint8 *buf, guint8 **endbuf) /* ARCHITECTURE SPECIFIC CODE */ -#if defined(__i386__) || defined(__x86_64__) || defined(__arm__) +#if defined(TARGET_X86) || defined(TARGET_AMD64) || defined(TARGET_ARM) #define EMIT_DWARF_INFO 1 #endif @@ -424,12 +427,12 @@ encode_sleb128 (gint32 value, guint8 *buf, guint8 **endbuf) static void arch_emit_direct_call (MonoAotCompile *acfg, const char *target, int *call_size) { -#if defined(__i386__) || defined(__x86_64__) +#if defined(TARGET_X86) || defined(TARGET_AMD64) /* Need to make sure this is exactly 5 bytes long */ emit_byte (acfg, '\xe8'); emit_symbol_diff (acfg, target, ".", -4); *call_size = 5; -#elif defined(__arm__) +#elif defined(TARGET_ARM) if (acfg->use_bin_writer) { guint8 buf [4]; guint8 *code; @@ -449,6 +452,24 @@ arch_emit_direct_call (MonoAotCompile *acfg, const char *target, int *call_size) #endif } +#ifdef MONO_ARCH_AOT_SUPPORTED +/* + * arch_emit_got_offset: + * + * The memory pointed to by CODE should hold native code for computing the GOT + * address. Emit this code while patching it with the offset between code and + * the GOT. CODE_SIZE is set to the number of bytes emitted. + */ +static void +arch_emit_got_offset (MonoAotCompile *acfg, guint8 *code, int *code_size) +{ + guint32 offset = mono_arch_get_patch_offset (code); + emit_bytes (acfg, code, offset); + emit_symbol_diff (acfg, "got", ".", offset); + + *code_size = offset + 4; +} + /* * arch_emit_got_access: * @@ -463,11 +484,11 @@ arch_emit_got_access (MonoAotCompile *acfg, guint8 *code, int got_slot, int *cod emit_bytes (acfg, code, mono_arch_get_patch_offset (code)); /* Emit the offset */ -#ifdef __x86_64__ +#ifdef TARGET_AMD64 emit_symbol_diff (acfg, "got", ".", (unsigned int) ((got_slot * sizeof (gpointer)) - 4)); -#elif defined(__i386__) +#elif defined(TARGET_X86) emit_int32 (acfg, (unsigned int) ((got_slot * sizeof (gpointer)))); -#elif defined(__arm__) +#elif defined(TARGET_ARM) emit_symbol_diff (acfg, "got", ".", (unsigned int) ((got_slot * sizeof (gpointer))) - 12); #else g_assert_not_reached (); @@ -476,6 +497,8 @@ arch_emit_got_access (MonoAotCompile *acfg, guint8 *code, int got_slot, int *cod *code_size = mono_arch_get_patch_offset (code) + 4; } +#endif + /* * arch_emit_plt_entry: * @@ -484,7 +507,7 @@ arch_emit_got_access (MonoAotCompile *acfg, guint8 *code, int got_slot, int *cod static void arch_emit_plt_entry (MonoAotCompile *acfg, int index) { -#if defined(__i386__) +#if defined(TARGET_X86) if (index == 0) { /* It is filled up during loading by the AOT loader. */ emit_zero_bytes (acfg, 16); @@ -494,7 +517,7 @@ arch_emit_plt_entry (MonoAotCompile *acfg, int index) emit_symbol_diff (acfg, "plt", ".", -4); emit_int32 (acfg, acfg->plt_got_info_offsets [index]); } -#elif defined(__x86_64__) +#elif defined(TARGET_AMD64) /* * 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 @@ -507,7 +530,7 @@ arch_emit_plt_entry (MonoAotCompile *acfg, int index) emit_symbol_diff (acfg, "got", ".", ((acfg->plt_got_offset_base + index) * sizeof (gpointer)) -4); /* Used by mono_aot_get_plt_info_offset */ emit_int32 (acfg, acfg->plt_got_info_offsets [index]); -#elif defined(__arm__) +#elif defined(TARGET_ARM) guint8 buf [256]; guint8 *code; @@ -566,7 +589,7 @@ arch_emit_specific_trampoline (MonoAotCompile *acfg, int offset, int *tramp_size * loading the argument from there. * - all the trampolines should be of the same length. */ -#if defined(__x86_64__) +#if defined(TARGET_AMD64) /* This should be exactly 16 bytes long */ *tramp_size = 16; /* call *(%rip) */ @@ -577,7 +600,7 @@ arch_emit_specific_trampoline (MonoAotCompile *acfg, int offset, int *tramp_size /* This should be relative to the start of the trampoline */ emit_symbol_diff (acfg, "got", ".", (offset * sizeof (gpointer)) - 4 + 19); emit_zero_bytes (acfg, 5); -#elif defined(__arm__) +#elif defined(TARGET_ARM) guint8 buf [128]; guint8 *code; @@ -612,7 +635,7 @@ arch_emit_specific_trampoline (MonoAotCompile *acfg, int offset, int *tramp_size static void arch_emit_unbox_trampoline (MonoAotCompile *acfg, MonoMethod *method, MonoGenericSharingContext *gsctx, const char *call_target) { -#if defined(__x86_64__) +#if defined(TARGET_AMD64) guint8 buf [32]; guint8 *code; int this_reg; @@ -625,7 +648,7 @@ arch_emit_unbox_trampoline (MonoAotCompile *acfg, MonoMethod *method, MonoGeneri /* jump */ emit_byte (acfg, '\xe9'); emit_symbol_diff (acfg, call_target, ".", -4); -#elif defined(__arm__) +#elif defined(TARGET_ARM) guint8 buf [128]; guint8 *code; int this_pos = 0; @@ -639,15 +662,75 @@ arch_emit_unbox_trampoline (MonoAotCompile *acfg, MonoMethod *method, MonoGeneri emit_bytes (acfg, buf, code - buf); /* jump to method */ - if (acfg->use_bin_writer) - g_assert_not_reached (); - else + if (acfg->use_bin_writer) { + guint8 buf [4]; + guint8 *code; + + code = buf; + ARM_B (code, 0); + + img_writer_emit_reloc (acfg->w, R_ARM_JUMP24, call_target, -8); + emit_bytes (acfg, buf, 4); + } else { fprintf (acfg->fp, "\n\tb %s\n", call_target); + } #else g_assert_not_reached (); #endif } +/* + * arch_emit_static_rgctx_trampoline: + * + * Emit code for a static rgctx trampoline. OFFSET is the offset of the first of + * two GOT slots which contain the rgctx argument, and the method to jump to. + * TRAMP_SIZE is set to the size of the emitted trampoline. + * These kinds of trampolines cannot be enumerated statically, since there could + * be one trampoline per method instantiation, so we emit the same code for all + * trampolines, and parameterize them using two GOT slots. + */ +static void +arch_emit_static_rgctx_trampoline (MonoAotCompile *acfg, int offset, int *tramp_size) +{ +#if defined(TARGET_AMD64) + /* This should be exactly 13 bytes long */ + *tramp_size = 13; + + /* mov (%rip), %r10 */ + emit_byte (acfg, '\x4d'); + emit_byte (acfg, '\x8b'); + emit_byte (acfg, '\x15'); + emit_symbol_diff (acfg, "got", ".", (offset * sizeof (gpointer)) - 4); + + /* jmp *(%rip) */ + emit_byte (acfg, '\xff'); + emit_byte (acfg, '\x25'); + emit_symbol_diff (acfg, "got", ".", ((offset + 1) * sizeof (gpointer)) - 4); +#elif defined(TARGET_ARM) + guint8 buf [128]; + guint8 *code; + + /* This should be exactly 24 bytes long */ + *tramp_size = 24; + code = buf; + /* Load rgctx value */ + ARM_LDR_IMM (code, ARMREG_R1, ARMREG_PC, 8); + ARM_LDR_REG_REG (code, MONO_ARCH_RGCTX_REG, ARMREG_PC, ARMREG_R1); + /* Load branch addr + branch */ + ARM_LDR_IMM (code, ARMREG_R1, ARMREG_PC, 4); + ARM_LDR_REG_REG (code, ARMREG_PC, ARMREG_PC, ARMREG_R1); + + g_assert (code - buf == 16); + + /* Emit it */ + emit_bytes (acfg, buf, code - buf); + emit_symbol_diff (acfg, "got", ".", (offset * sizeof (gpointer)) - 4 + 8); + emit_symbol_diff (acfg, "got", ".", ((offset + 1) * sizeof (gpointer)) - 4 + 4); +#else + g_assert_not_reached (); +#endif +} + /* * arch_get_cie_program: * @@ -656,7 +739,7 @@ arch_emit_unbox_trampoline (MonoAotCompile *acfg, MonoMethod *method, MonoGeneri static GSList* arch_get_cie_program (void) { -#ifdef __x86_64__ +#ifdef TARGET_AMD64 GSList *l = NULL; mono_add_unwind_op_def_cfa (l, (guint8*)NULL, (guint8*)NULL, AMD64_RSP, 8); @@ -798,20 +881,20 @@ encode_klass_ref (MonoAotCompile *acfg, MonoClass *klass, guint8 *buf, guint8 ** encode_value (klass->type_token - MONO_TOKEN_TYPE_DEF, p, &p); encode_value (get_image_index (acfg, klass->image), p, &p); } else if ((klass->byval_arg.type == MONO_TYPE_VAR) || (klass->byval_arg.type == MONO_TYPE_MVAR)) { - MonoGenericParam *param = klass->byval_arg.data.generic_param; + MonoGenericContainer *container = mono_type_get_generic_param_owner (&klass->byval_arg); + g_assert (container); /* Marker */ encode_value (MONO_TOKEN_TYPE_SPEC, p, &p); encode_value (klass->byval_arg.type, p, &p); - encode_value (param->num, p, &p); + encode_value (mono_type_get_generic_param_num (&klass->byval_arg), p, &p); - g_assert (param->owner); - encode_value (param->owner->is_method, p, &p); - if (param->owner->is_method) - encode_method_ref (acfg, param->owner->owner.method, p, &p); + encode_value (container->is_method, p, &p); + if (container->is_method) + encode_method_ref (acfg, container->owner.method, p, &p); else - encode_klass_ref (acfg, param->owner->owner.klass, p, &p); + encode_klass_ref (acfg, container->owner.klass, p, &p); } else { /* Array class */ g_assert (klass->rank > 0); @@ -965,11 +1048,13 @@ encode_method_ref (MonoAotCompile *acfg, MonoMethod *method, guint8 *buf, guint8 g_assert_not_reached (); break; case MONO_WRAPPER_STATIC_RGCTX_INVOKE: - case MONO_WRAPPER_SYNCHRONIZED: { + case MONO_WRAPPER_SYNCHRONIZED: + case MONO_WRAPPER_MANAGED_TO_NATIVE: { MonoMethod *m; m = mono_marshal_method_from_wrapper (method); g_assert (m); + g_assert (m != method); encode_method_ref (acfg, m, p, &p); break; } @@ -1098,41 +1183,6 @@ is_plt_patch (MonoJumpInfo *patch_info) } } -static gboolean -is_got_patch (MonoJumpInfoType patch_type) -{ - return TRUE; -} - -/* - * is_shared_got_patch: - * - * Return whenever PATCH_INFO refers to a patch which needs a shared GOT - * entry. - * Keep it in sync with the version in aot-runtime.c. - */ -static inline gboolean -is_shared_got_patch (MonoJumpInfo *patch_info) -{ - switch (patch_info->type) { - case MONO_PATCH_INFO_VTABLE: - case MONO_PATCH_INFO_CLASS: - case MONO_PATCH_INFO_IID: - case MONO_PATCH_INFO_ADJUSTED_IID: - case MONO_PATCH_INFO_FIELD: - case MONO_PATCH_INFO_SFLDA: - case MONO_PATCH_INFO_DECLSEC: - case MONO_PATCH_INFO_LDTOKEN: - case MONO_PATCH_INFO_TYPE_FROM_HANDLE: - case MONO_PATCH_INFO_RVA: - case MONO_PATCH_INFO_METHODCONST: - case MONO_PATCH_INFO_IMAGE: - return TRUE; - default: - return FALSE; - } -} - static int get_plt_offset (MonoAotCompile *acfg, MonoJumpInfo *patch_info) { @@ -1285,7 +1335,7 @@ get_runtime_invoke_sig (MonoMethodSignature *sig) mb = mono_mb_new (mono_defaults.object_class, "FOO", MONO_WRAPPER_NONE); m = mono_mb_create_method (mb, sig, 16); - return mono_marshal_get_runtime_invoke (m); + return mono_marshal_get_runtime_invoke (m, FALSE); } static void @@ -1360,6 +1410,9 @@ add_wrappers (MonoAotCompile *acfg) csig->params [1] = &mono_defaults.boolean_class->byval_arg; add_method (acfg, get_runtime_invoke_sig (csig)); + /* runtime-invoke used by finalizers */ + add_method (acfg, mono_marshal_get_runtime_invoke (mono_class_get_method_from_name_flags (mono_defaults.object_class, "Finalize", 0, 0), TRUE)); + for (i = 0; i < acfg->image->tables [MONO_TABLE_METHOD].rows; ++i) { MonoMethod *method; guint32 token = MONO_TOKEN_METHOD_DEF | (i + 1); @@ -1387,7 +1440,7 @@ add_wrappers (MonoAotCompile *acfg) } if (!skip) - add_method (acfg, mono_marshal_get_runtime_invoke (method)); + add_method (acfg, mono_marshal_get_runtime_invoke (method, FALSE)); } if (strcmp (acfg->image->assembly->aname.name, "mscorlib") == 0) { @@ -1436,8 +1489,7 @@ add_wrappers (MonoAotCompile *acfg) sig = mono_method_signature (method); - if (sig->hasthis && (method->klass->marshalbyref || method->klass == mono_defaults.object_class) && - !(method->flags & METHOD_ATTRIBUTE_VIRTUAL)) { + if (sig->hasthis && (method->klass->marshalbyref || method->klass == mono_defaults.object_class)) { m = mono_marshal_get_remoting_invoke_with_check (method); add_method (acfg, m); @@ -1475,23 +1527,6 @@ add_wrappers (MonoAotCompile *acfg) add_method (acfg, mono_marshal_get_synchronized_wrapper (method)); } -#if 0 - /* static rgctx wrappers */ - /* FIXME: Each wrapper belongs to a given instantiation of a generic method */ - for (i = 0; i < acfg->image->tables [MONO_TABLE_METHOD].rows; ++i) { - token = MONO_TOKEN_METHOD_DEF | (i + 1); - method = mono_get_method (acfg->image, token, NULL); - - if (((method->flags & METHOD_ATTRIBUTE_STATIC) || - (method->is_inflated && mono_method_get_context (method)->method_inst)) && - mono_class_generic_sharing_enabled (method->klass) && - mono_method_is_generic_sharable_impl (method, FALSE)) { - m = mono_marshal_get_static_rgctx_invoke (method); - add_method (acfg, m); - } - } -#endif - /* pinvoke wrappers */ for (i = 0; i < acfg->image->tables [MONO_TABLE_METHOD].rows; ++i) { MonoMethod *method; @@ -1573,7 +1608,7 @@ add_generic_class (MonoAotCompile *acfg, MonoClass *klass) * since rgctx wrappers belong to inflated methods. */ method = mono_class_get_cctor (klass); - if (method) + if (method && mono_method_needs_static_rgctx_invoke (method, FALSE)) add_extra_method (acfg, mono_marshal_get_static_rgctx_invoke (method)); iter = NULL; @@ -1592,6 +1627,46 @@ add_generic_class (MonoAotCompile *acfg, MonoClass *klass) */ add_extra_method (acfg, method); } + + /* + * For ICollection, where T is a vtype, add instances of the helper methods + * in Array, since a T[] could be cast to ICollection. + */ + if (klass->image == mono_defaults.corlib && !strcmp (klass->name_space, "System.Collections.Generic") && + (!strcmp(klass->name, "ICollection`1") || !strcmp (klass->name, "IEnumerable`1") || !strcmp (klass->name, "IList`1") || !strcmp (klass->name, "IEnumerator`1")) && + MONO_TYPE_ISSTRUCT (klass->generic_class->context.class_inst->type_argv [0])) { + MonoClass *tclass = mono_class_from_mono_type (klass->generic_class->context.class_inst->type_argv [0]); + MonoClass *array_class = mono_bounded_array_class_get (tclass, 1, FALSE); + gpointer iter; + char *name_prefix; + + if (!strcmp (klass->name, "IEnumerator`1")) + name_prefix = g_strdup_printf ("%s.%s", klass->name_space, "IEnumerable`1"); + else + name_prefix = g_strdup_printf ("%s.%s", klass->name_space, klass->name); + + /* Add the T[]/InternalEnumerator class */ + if (!strcmp (klass->name, "IEnumerable`1") || !strcmp (klass->name, "IEnumerator`1")) { + MonoClass *nclass; + + iter = NULL; + while ((nclass = mono_class_get_nested_types (array_class->parent, &iter))) { + if (!strcmp (nclass->name, "InternalEnumerator`1")) + break; + } + g_assert (nclass); + nclass = mono_class_inflate_generic_class (nclass, mono_generic_class_get_context (klass->generic_class)); + add_generic_class (acfg, nclass); + } + + iter = NULL; + while ((method = mono_class_get_methods (array_class, &iter))) { + if (strstr (method->name, name_prefix)) + add_extra_method (acfg, method); + } + + g_free (name_prefix); + } } /* @@ -1605,6 +1680,8 @@ add_generic_instances (MonoAotCompile *acfg) int i; guint32 token; MonoMethod *method; + MonoMethodHeader *header; + MonoMethodSignature *sig; MonoGenericContext *context; for (i = 0; i < acfg->image->tables [MONO_TABLE_METHODSPEC].rows; ++i) { @@ -1637,6 +1714,29 @@ add_generic_instances (MonoAotCompile *acfg) add_generic_class (acfg, klass); } + + /* Add types of args/locals */ + for (i = 0; i < acfg->methods->len; ++i) { + int j; + + method = g_ptr_array_index (acfg->methods, i); + + sig = mono_method_signature (method); + + if (sig) { + for (j = 0; j < sig->param_count; ++j) + if (sig->params [j]->type == MONO_TYPE_GENERICINST) + add_generic_class (acfg, mono_class_from_mono_type (sig->params [j])); + } + + header = mono_method_get_header (method); + + if (header) { + for (j = 0; j < header->num_locals; ++j) + if (header->locals [j]->type == MONO_TYPE_GENERICINST) + add_generic_class (acfg, mono_class_from_mono_type (header->locals [j])); + } + } } /* @@ -1688,18 +1788,14 @@ emit_and_reloc_code (MonoAotCompile *acfg, MonoMethod *method, guint8 *code, gui case MONO_PATCH_INFO_NONE: break; case MONO_PATCH_INFO_GOT_OFFSET: { - guint32 offset = mono_arch_get_patch_offset (code + i); - emit_bytes (acfg, code + i, offset); - emit_symbol_diff (acfg, "got", ".", offset); - - i += offset + 4 - 1; + int code_size; + + arch_emit_got_offset (acfg, code + i, &code_size); + i += code_size - 1; skip = TRUE; break; } default: { - if (!is_got_patch (patch_info->type)) - break; - /* * If this patch is a call, try emitting a direct call instead of * through a PLT entry. This is possible if the called method is in @@ -1801,7 +1897,7 @@ emit_method_code (MonoAotCompile *acfg, MonoCompile *cfg) emit_alignment (acfg, func_alignment); emit_label (acfg, symbol); - if (acfg->aot_opts.write_symbols && acfg->use_bin_writer) { + if (acfg->aot_opts.write_symbols && !acfg->aot_opts.nodebug && acfg->use_bin_writer) { char *full_name; /* Emit a local symbol into the symbol table */ full_name = mono_method_full_name (method, TRUE); @@ -1949,7 +2045,7 @@ static void encode_patch_list (MonoAotCompile *acfg, GPtrArray *patches, int n_patches, int first_got_offset, guint8 *buf, guint8 **endbuf) { guint8 *p = buf; - guint32 last_offset, j, pindex; + guint32 pindex; MonoJumpInfo *patch_info; encode_value (n_patches, p, &p); @@ -1957,32 +2053,15 @@ encode_patch_list (MonoAotCompile *acfg, GPtrArray *patches, int n_patches, int if (n_patches) encode_value (first_got_offset, p, &p); - /* First encode the type+position table */ - last_offset = 0; - j = 0; for (pindex = 0; pindex < patches->len; ++pindex) { - guint32 offset; patch_info = g_ptr_array_index (patches, pindex); - + if (patch_info->type == MONO_PATCH_INFO_NONE) /* Nothing to do */ continue; - j ++; - //printf ("T: %d O: %d.\n", patch_info->type, patch_info->ip.i); - offset = patch_info->ip.i - last_offset; - last_offset = patch_info->ip.i; - - /* Only the type is needed */ - *p = patch_info->type; - p++; - } - - /* Then encode the other info */ - for (pindex = 0; pindex < patches->len; ++pindex) { - patch_info = g_ptr_array_index (patches, pindex); - - if (is_shared_got_patch (patch_info)) { + encode_value (patch_info->type, p, &p); + if (mono_aot_is_shared_got_patch (patch_info)) { guint32 offset = get_got_offset (acfg, patch_info); encode_value (offset, p, &p); } else { @@ -2091,6 +2170,39 @@ emit_method_info (MonoAotCompile *acfg, MonoCompile *cfg) g_free (buf); } +static guint32 +get_unwind_info_offset (MonoAotCompile *acfg, guint8 *encoded, guint32 encoded_len) +{ + guint32 cache_index; + guint32 offset; + + /* Reuse the unwind module to canonize and store unwind info entries */ + cache_index = mono_cache_unwind_info (encoded, encoded_len); + + /* Use +/- 1 to distinguish 0s from missing entries */ + offset = GPOINTER_TO_UINT (g_hash_table_lookup (acfg->unwind_info_offsets, GUINT_TO_POINTER (cache_index + 1))); + if (offset) + return offset - 1; + else { + guint8 buf [16]; + guint8 *p; + + /* + * It would be easier to use assembler symbols, but the caller needs an + * offset now. + */ + offset = acfg->unwind_info_offset; + g_hash_table_insert (acfg->unwind_info_offsets, GUINT_TO_POINTER (cache_index + 1), GUINT_TO_POINTER (offset + 1)); + g_ptr_array_add (acfg->unwind_ops, GUINT_TO_POINTER (cache_index)); + + p = buf; + encode_value (encoded_len, p, &p); + + acfg->unwind_info_offset += encoded_len + (p - buf); + return offset; + } +} + static void emit_exception_debug_info (MonoAotCompile *acfg, MonoCompile *cfg) { @@ -2114,9 +2226,14 @@ emit_exception_debug_info (MonoAotCompile *acfg, MonoCompile *cfg) /* Make the labels local */ sprintf (symbol, ".Le_%x_p", method_index); - mono_debug_serialize_debug_info (cfg, &debug_info, &debug_info_size); + if (!acfg->aot_opts.nodebug) { + mono_debug_serialize_debug_info (cfg, &debug_info, &debug_info_size); + } else { + debug_info = NULL; + debug_info_size = 0; + } - buf_size = header->num_clauses * 256 + debug_info_size + 256; + buf_size = header->num_clauses * 256 + debug_info_size + 1024; p = buf = g_malloc (buf_size); #ifdef MONO_ARCH_HAVE_XP_UNWIND @@ -2137,9 +2254,7 @@ emit_exception_debug_info (MonoAotCompile *acfg, MonoCompile *cfg) * section cannot be accessed using the dl interface. */ encoded = mono_unwind_ops_encode (cfg->unwind_ops, &encoded_len); - encode_value (encoded_len, p, &p); - memcpy (p, encoded, encoded_len); - p += encoded_len; + encode_value (get_unwind_info_offset (acfg, encoded, encoded_len), p, &p); g_free (encoded); } else { encode_value (jinfo->used_regs, p, &p); @@ -2290,9 +2405,9 @@ emit_plt (MonoAotCompile *acfg) emit_section_change (acfg, ".text", 0); emit_global (acfg, symbol, TRUE); -#ifdef __i386__ +#ifdef TARGET_X86 /* This section will be made read-write by the AOT loader */ - emit_alignment (acfg, PAGESIZE); + emit_alignment (acfg, mono_pagesize ()); #else emit_alignment (acfg, 16); #endif @@ -2316,7 +2431,7 @@ emit_plt (MonoAotCompile *acfg) } static G_GNUC_UNUSED void -emit_named_code (MonoAotCompile *acfg, const char *name, guint8 *code, +emit_trampoline (MonoAotCompile *acfg, const char *name, guint8 *code, guint32 code_size, int got_offset, MonoJumpInfo *ji, GSList *unwind_ops) { char symbol [256]; @@ -2373,7 +2488,8 @@ emit_named_code (MonoAotCompile *acfg, const char *name, guint8 *code, sprintf (symbol, "%s", name); sprintf (symbol2, ".Lnamed_%s", name); - mono_dwarf_writer_emit_trampoline (acfg->dwarf, symbol, symbol2, NULL, NULL, code_size, unwind_ops); + if (acfg->dwarf) + mono_dwarf_writer_emit_trampoline (acfg->dwarf, symbol, symbol2, NULL, NULL, code_size, unwind_ops); } } @@ -2391,7 +2507,7 @@ static void emit_trampolines (MonoAotCompile *acfg) { char symbol [256]; - int i, offset; + int i, tramp_got_offset; #ifdef MONO_ARCH_HAVE_FULL_AOT_TRAMPOLINES int tramp_type; guint32 code_size; @@ -2422,102 +2538,142 @@ emit_trampolines (MonoAotCompile *acfg) sprintf (symbol, "generic_trampoline_%d", tramp_type); - emit_named_code (acfg, symbol, code, code_size, acfg->got_offset, ji, unwind_ops); + emit_trampoline (acfg, symbol, code, code_size, acfg->got_offset, ji, unwind_ops); } code = mono_arch_get_nullified_class_init_trampoline (&code_size); - emit_named_code (acfg, "nullified_class_init_trampoline", code, code_size, acfg->got_offset, NULL, NULL); -#if defined(__x86_64__) && defined(MONO_ARCH_MONITOR_OBJECT_REG) + emit_trampoline (acfg, "nullified_class_init_trampoline", code, code_size, acfg->got_offset, NULL, NULL); +#if defined(TARGET_AMD64) && defined(MONO_ARCH_MONITOR_OBJECT_REG) code = mono_arch_create_monitor_enter_trampoline_full (&code_size, &ji, TRUE); - emit_named_code (acfg, "monitor_enter_trampoline", code, code_size, acfg->got_offset, ji, NULL); + emit_trampoline (acfg, "monitor_enter_trampoline", code, code_size, acfg->got_offset, ji, NULL); code = mono_arch_create_monitor_exit_trampoline_full (&code_size, &ji, TRUE); - emit_named_code (acfg, "monitor_exit_trampoline", code, code_size, acfg->got_offset, ji, NULL); + emit_trampoline (acfg, "monitor_exit_trampoline", code, code_size, acfg->got_offset, ji, NULL); #endif -#if defined(__x86_64__) code = mono_arch_create_generic_class_init_trampoline_full (&code_size, &ji, TRUE); - emit_named_code (acfg, "generic_class_init_trampoline", code, code_size, acfg->got_offset, ji, NULL); -#endif + emit_trampoline (acfg, "generic_class_init_trampoline", code, code_size, acfg->got_offset, ji, NULL); /* Emit the exception related code pieces */ code = mono_arch_get_restore_context_full (&code_size, &ji, TRUE); - emit_named_code (acfg, "restore_context", code, code_size, acfg->got_offset, ji, NULL); + emit_trampoline (acfg, "restore_context", code, code_size, acfg->got_offset, ji, NULL); code = mono_arch_get_call_filter_full (&code_size, &ji, TRUE); - emit_named_code (acfg, "call_filter", code, code_size, acfg->got_offset, ji, NULL); + emit_trampoline (acfg, "call_filter", code, code_size, acfg->got_offset, ji, NULL); code = mono_arch_get_throw_exception_full (&code_size, &ji, TRUE); - emit_named_code (acfg, "throw_exception", code, code_size, acfg->got_offset, ji, NULL); + emit_trampoline (acfg, "throw_exception", code, code_size, acfg->got_offset, ji, NULL); code = mono_arch_get_rethrow_exception_full (&code_size, &ji, TRUE); - emit_named_code (acfg, "rethrow_exception", code, code_size, acfg->got_offset, ji, NULL); + emit_trampoline (acfg, "rethrow_exception", code, code_size, acfg->got_offset, ji, NULL); code = mono_arch_get_throw_exception_by_name_full (&code_size, &ji, TRUE); - emit_named_code (acfg, "throw_exception_by_name", code, code_size, acfg->got_offset, ji, NULL); + emit_trampoline (acfg, "throw_exception_by_name", code, code_size, acfg->got_offset, ji, NULL); code = mono_arch_get_throw_corlib_exception_full (&code_size, &ji, TRUE); - emit_named_code (acfg, "throw_corlib_exception", code, code_size, acfg->got_offset, ji, NULL); + emit_trampoline (acfg, "throw_corlib_exception", code, code_size, acfg->got_offset, ji, NULL); -#if defined(__x86_64__) +#if defined(TARGET_AMD64) code = mono_arch_get_throw_pending_exception_full (&code_size, &ji, TRUE); - emit_named_code (acfg, "throw_pending_exception", code, code_size, acfg->got_offset, ji, NULL); + emit_trampoline (acfg, "throw_pending_exception", code, code_size, acfg->got_offset, ji, NULL); #endif -#if defined(__x86_64__) || defined(__arm__) +#if defined(TARGET_AMD64) || defined(TARGET_ARM) for (i = 0; i < 128; ++i) { int offset; offset = MONO_RGCTX_SLOT_MAKE_RGCTX (i); code = mono_arch_create_rgctx_lazy_fetch_trampoline_full (offset, &code_size, &ji, TRUE); sprintf (symbol, "rgctx_fetch_trampoline_%u", offset); - emit_named_code (acfg, symbol, code, code_size, acfg->got_offset, ji, NULL); + emit_trampoline (acfg, symbol, code, code_size, acfg->got_offset, ji, NULL); offset = MONO_RGCTX_SLOT_MAKE_MRGCTX (i); code = mono_arch_create_rgctx_lazy_fetch_trampoline_full (offset, &code_size, &ji, TRUE); sprintf (symbol, "rgctx_fetch_trampoline_%u", offset); - emit_named_code (acfg, symbol, code, code_size, acfg->got_offset, ji, NULL); + emit_trampoline (acfg, symbol, code, code_size, acfg->got_offset, ji, NULL); } #endif + +#if defined(TARGET_AMD64) || defined(TARGET_ARM) + { + GSList *l; + + /* delegate_invoke_impl trampolines */ + l = mono_arch_get_delegate_invoke_impls (); + while (l) { + MonoAotTrampInfo *info = l->data; + + emit_trampoline (acfg, info->name, info->code, info->code_size, acfg->got_offset, NULL, NULL); + l = l->next; + } + } #endif +#endif /* #ifdef MONO_ARCH_HAVE_FULL_AOT_TRAMPOLINES */ + /* * FIXME: Maybe we should use more specific trampolines (i.e. one class init for * each class). */ /* Reserve some entries at the end of the GOT for our use */ - acfg->num_trampoline_got_entries = acfg->num_aot_trampolines * 2; + acfg->num_trampoline_got_entries = (acfg->num_specific_trampolines * 2) + (acfg->num_static_rgctx_trampolines * 2); - sprintf (symbol, "trampolines"); + sprintf (symbol, "specific_trampolines"); emit_section_change (acfg, ".text", 0); emit_global (acfg, symbol, TRUE); emit_alignment (acfg, 16); emit_label (acfg, symbol); - for (i = 0; i < acfg->num_aot_trampolines; ++i) { - int tramp_size = 0; + tramp_got_offset = acfg->got_offset; - offset = acfg->got_offset + (i * 2); + acfg->specific_trampoline_got_offset_base = tramp_got_offset; + + for (i = 0; i < acfg->num_specific_trampolines; ++i) { + int tramp_size = 0; - arch_emit_specific_trampoline (acfg, offset, &tramp_size); + arch_emit_specific_trampoline (acfg, tramp_got_offset, &tramp_size); if (!acfg->specific_trampoline_size) { g_assert (tramp_size); acfg->specific_trampoline_size = tramp_size; } + + tramp_got_offset += 2; + } + + sprintf (symbol, "static_rgctx_trampolines"); + + emit_section_change (acfg, ".text", 0); + emit_global (acfg, symbol, TRUE); + emit_alignment (acfg, 16); + emit_label (acfg, symbol); + + acfg->static_rgctx_trampoline_got_offset_base = tramp_got_offset; + + for (i = 0; i < acfg->num_static_rgctx_trampolines; ++i) { + int tramp_size = 0; + + arch_emit_static_rgctx_trampoline (acfg, tramp_got_offset, &tramp_size); + if (!acfg->static_rgctx_trampoline_size) { + g_assert (tramp_size); + acfg->static_rgctx_trampoline_size = tramp_size; + } + + tramp_got_offset += 2; } } /* Unbox trampolines */ - - for (i = 0; i < acfg->image->tables [MONO_TABLE_METHOD].rows; ++i) { - MonoMethod *method; - guint32 token = MONO_TOKEN_METHOD_DEF | (i + 1); + for (i = 0; i < acfg->methods->len; ++i) { + MonoMethod *method = g_ptr_array_index (acfg->methods, i); MonoCompile *cfg; char call_target [256]; - method = mono_get_method (acfg->image, token, NULL); - cfg = g_hash_table_lookup (acfg->method_to_cfg, method); if (!cfg || !cfg->orig_method->klass->valuetype || !(method->flags & METHOD_ATTRIBUTE_VIRTUAL)) continue; - sprintf (symbol, "unbox_trampoline_%d", i); + if (!method->wrapper_type && !method->is_inflated) { + g_assert (method->token); + sprintf (symbol, "ut_%d", mono_metadata_token_index (method->token) - 1); + } else { + sprintf (symbol, "ut_e_%d", get_method_index (acfg, method)); + } emit_section_change (acfg, ".text", 0); emit_global (acfg, symbol, TRUE); @@ -2528,8 +2684,6 @@ emit_trampolines (MonoAotCompile *acfg) arch_emit_unbox_trampoline (acfg, cfg->orig_method, cfg->generic_sharing_context, call_target); } - acfg->trampoline_got_offset_base = acfg->got_offset; - acfg->got_offset += acfg->num_trampoline_got_entries; } @@ -2563,15 +2717,6 @@ mono_aot_parse_options (const char *aot_options, MonoAotOptions *opts) opts->bind_to_runtime_version = TRUE; } else if (str_begins_with (arg, "full")) { opts->full_aot = TRUE; - /* - * The no-dlsym option is only useful on the iphone, and even there, - * do to other limitations of the dynamic linker, it doesn't seem to - * work. So disable it for now so we don't have to support it. - */ - /* - } else if (str_begins_with (arg, "no-dlsym")) { - opts->no_dlsym = TRUE; - */ } else if (str_begins_with (arg, "threads=")) { opts->nthreads = atoi (arg + strlen ("threads=")); } else if (str_begins_with (arg, "static")) { @@ -2581,6 +2726,10 @@ mono_aot_parse_options (const char *aot_options, MonoAotOptions *opts) opts->asm_only = TRUE; } else if (str_begins_with (arg, "asmwriter")) { opts->asm_writer = TRUE; + } else if (str_begins_with (arg, "nodebug")) { + opts->nodebug = TRUE; + } else if (str_begins_with (arg, "ntrampolines=")) { + opts->ntrampolines = atoi (arg + strlen ("ntrampolines=")); } else { fprintf (stderr, "AOT : Unknown argument '%s'.\n", arg); exit (1); @@ -2832,10 +2981,12 @@ compile_method (MonoAotCompile *acfg, MonoMethod *method) 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) - add_extra_method (acfg, mono_marshal_get_native_wrapper (m, TRUE, TRUE)); - else + 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); + } } add_generic_class (acfg, m->klass); } @@ -3057,7 +3208,7 @@ alloc_got_slots (MonoAotCompile *acfg) MonoCompile *cfg = acfg->cfgs [i]; for (ji = cfg->patch_info; ji; ji = ji->next) { - if (is_shared_got_patch (ji)) + if (mono_aot_is_shared_got_patch (ji)) get_shared_got_offset (acfg, ji); } } @@ -3154,93 +3305,215 @@ emit_info (MonoAotCompile *acfg) } emit_line (acfg); } - -typedef struct HashEntry { - guint32 key, value, index; - struct HashEntry *next; -} HashEntry; + +#endif /* #if !defined(DISABLE_AOT) && !defined(DISABLE_JIT) */ /* - * emit_extra_methods: + * mono_aot_str_hash: * - * Emit methods which are not in the METHOD table, like wrappers. + * 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. */ -static void -emit_extra_methods (MonoAotCompile *acfg) +guint +mono_aot_str_hash (gconstpointer v1) { - int i, table_size, buf_size; - char symbol [256]; - guint8 *p, *buf; - guint32 *info_offsets; - guint32 hash; - GPtrArray *table; - HashEntry *entry, *new_entry; - int nmethods; + /* Same as g_str_hash () in glib */ + char *p = (char *) v1; + guint hash = *p; - info_offsets = g_new0 (guint32, acfg->extra_methods->len); + while (*p++) { + if (*p) + hash = (hash << 5) - hash + *p; + } - buf_size = acfg->extra_methods->len * 256 + 256; - p = buf = g_malloc (buf_size); + return hash; +} - /* Encode 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); +/* + * mono_aot_method_hash: + * + * Return a hash code for methods which only depends on metadata. + */ +guint32 +mono_aot_method_hash (MonoMethod *method) +{ + guint32 hash; - if (!cfg) - continue; + if (method->wrapper_type) { + hash = mono_aot_str_hash (method->name); + } else { + char *full_name = mono_method_full_name (method, TRUE); + // FIXME: Improve this (changing this requires bumping MONO_AOT_FILE_VERSION) + hash = mono_aot_str_hash (full_name); + g_free (full_name); + } - nmethods ++; - info_offsets [i] = p - buf; + return hash; +} - 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 if (method->wrapper_type == MONO_WRAPPER_DELEGATE_INVOKE) { - char *tmpsig = mono_signature_get_desc (mono_method_signature (method), TRUE); - name = g_strdup_printf ("(wrapper delegate-invoke):%s (%s)", method->name, tmpsig); - g_free (tmpsig); - } else if (method->wrapper_type == MONO_WRAPPER_DELEGATE_BEGIN_INVOKE) { - char *tmpsig = mono_signature_get_desc (mono_method_signature (method), TRUE); - name = g_strdup_printf ("(wrapper delegate-begin-invoke):%s (%s)", method->name, tmpsig); - g_free (tmpsig); - } else if (method->wrapper_type == MONO_WRAPPER_DELEGATE_END_INVOKE) { - char *tmpsig = mono_signature_get_desc (mono_method_signature (method), TRUE); - name = g_strdup_printf ("(wrapper delegate-end-invoke):%s (%s)", method->name, tmpsig); - g_free (tmpsig); - } else { - name = mono_method_full_name (cfg->orig_method, TRUE); - } +/* + * mono_aot_wrapper_name: + * + * Return a string which uniqely identifies the given wrapper method. + */ +char* +mono_aot_wrapper_name (MonoMethod *method) +{ + char *name, *tmpsig, *klass_desc; - 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); - } + tmpsig = mono_signature_get_desc (mono_method_signature (method), TRUE); - g_assert ((p - buf) < buf_size); + switch (method->wrapper_type) { + case MONO_WRAPPER_RUNTIME_INVOKE: + case MONO_WRAPPER_DELEGATE_INVOKE: + case MONO_WRAPPER_DELEGATE_BEGIN_INVOKE: + case MONO_WRAPPER_DELEGATE_END_INVOKE: + /* This is a hack to work around the fact that runtime invoke wrappers get assigned to some random class */ + name = g_strdup_printf ("%s (%s)", method->name, tmpsig); + break; + default: + klass_desc = mono_type_full_name (&method->klass->byval_arg); + + name = g_strdup_printf ("%s:%s (%s)", klass_desc, method->name, tmpsig); + break; } - g_assert ((p - buf) < buf_size); + g_free (tmpsig); - /* 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); + return name; +} + +/* + * mono_aot_tramp_info_create: + * + * Create a MonoAotTrampInfo structure from the arguments. + */ +MonoAotTrampInfo* +mono_aot_tramp_info_create (char *name, guint8 *code, guint32 code_size) +{ + MonoAotTrampInfo *info = g_new0 (MonoAotTrampInfo, 1); + + info->name = name; + info->code = code; + info->code_size = code_size; + + return info; +} + +/* + * mono_is_shared_got_patch: + * + * Return whenever PATCH_INFO refers to a patch which needs a shared GOT + * entry. + */ +gboolean +mono_aot_is_shared_got_patch (MonoJumpInfo *patch_info) +{ + switch (patch_info->type) { + case MONO_PATCH_INFO_VTABLE: + case MONO_PATCH_INFO_CLASS: + case MONO_PATCH_INFO_IID: + case MONO_PATCH_INFO_ADJUSTED_IID: + case MONO_PATCH_INFO_FIELD: + case MONO_PATCH_INFO_SFLDA: + case MONO_PATCH_INFO_DECLSEC: + case MONO_PATCH_INFO_LDTOKEN: + case MONO_PATCH_INFO_TYPE_FROM_HANDLE: + case MONO_PATCH_INFO_RVA: + case MONO_PATCH_INFO_METHODCONST: + case MONO_PATCH_INFO_IMAGE: + return TRUE; + default: + return FALSE; + } +} + +#if !defined(DISABLE_AOT) && !defined(DISABLE_JIT) + +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_extra_methods (MonoAotCompile *acfg) +{ + int i, table_size, buf_size; + char symbol [256]; + guint8 *p, *buf; + guint32 *info_offsets; + guint32 hash; + GPtrArray *table; + HashEntry *entry, *new_entry; + int nmethods, max_chain_length; + int *chain_lengths; + + 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 */ + 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); + char *name; + + if (!cfg) + continue; + + nmethods ++; + info_offsets [i] = p - buf; + + name = NULL; + if (method->wrapper_type) { + /* + * We encode some wrappers using their name, since encoding them + * directly would be difficult. This also avoids creating the wrapper + * methods at runtime, since they are not needed anyway. + */ + switch (method->wrapper_type) { + case MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK: + case MONO_WRAPPER_SYNCHRONIZED: + /* encode_method_ref () can handle these */ + break; + default: + name = mono_aot_wrapper_name (method); + break; + } + } + + if (name) { + encode_value (1, p, &p); + encode_value (method->wrapper_type, 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 */ + 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); @@ -3254,6 +3527,8 @@ emit_extra_methods (MonoAotCompile *acfg) table = g_ptr_array_sized_new (table_size); for (i = 0; i < table_size; ++i) g_ptr_array_add (table, NULL); + chain_lengths = g_new0 (int, table_size); + max_chain_length = 0; 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); @@ -3265,12 +3540,10 @@ emit_extra_methods (MonoAotCompile *acfg) key = info_offsets [i]; value = get_method_index (acfg, method); - if (method->wrapper_type) { - hash = g_str_hash (method->name) % table_size; - } else { - // FIXME: - hash = 0 % table_size; - } + hash = mono_aot_method_hash (method) % table_size; + + chain_lengths [hash] ++; + max_chain_length = MAX (max_chain_length, chain_lengths [hash]); /* FIXME: Allocate from the mempool */ new_entry = g_new0 (HashEntry, 1); @@ -3291,6 +3564,8 @@ emit_extra_methods (MonoAotCompile *acfg) } } + //printf ("MAX: %d\n", max_chain_length); + /* Emit the table */ sprintf (symbol, "extra_method_table"); emit_section_change (acfg, ".text", 0); @@ -3423,6 +3698,42 @@ emit_exception_info (MonoAotCompile *acfg) emit_line (acfg); } +static void +emit_unwind_info (MonoAotCompile *acfg) +{ + int i; + char symbol [128]; + + /* + * The unwind info contains a lot of duplicates so we emit each unique + * entry once, and only store the offset from the start of the table in the + * exception info. + */ + + sprintf (symbol, "unwind_info"); + emit_section_change (acfg, ".text", 1); + emit_alignment (acfg, 8); + emit_label (acfg, symbol); + emit_global (acfg, symbol, FALSE); + + for (i = 0; i < acfg->unwind_ops->len; ++i) { + guint32 index = GPOINTER_TO_UINT (g_ptr_array_index (acfg->unwind_ops, i)); + guint8 *unwind_info; + guint32 unwind_info_len; + guint8 buf [16]; + guint8 *p; + + unwind_info = mono_get_cached_unwind_info (index, &unwind_info_len); + + p = buf; + encode_value (unwind_info_len, p, &p); + emit_bytes (acfg, buf, p - buf); + emit_bytes (acfg, unwind_info, unwind_info_len); + + acfg->stats.unwind_info_size += (p - buf) + unwind_info_len; + } +} + static void emit_class_info (MonoAotCompile *acfg) { @@ -3478,7 +3789,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 = g_str_hash (full_name) % table_size; + hash = mono_aot_str_hash (full_name) % table_size; g_free (full_name); /* FIXME: Allocate from the mempool */ @@ -3650,6 +3961,13 @@ emit_got (MonoAotCompile *acfg) emit_label (acfg, symbol); if (acfg->got_offset > 0) emit_zero_bytes (acfg, (int)(acfg->got_offset * sizeof (gpointer))); + + sprintf (symbol, "mono_aot_got_addr"); + emit_section_change (acfg, ".data", 0); + emit_global (acfg, symbol, FALSE); + emit_alignment (acfg, 8); + emit_label (acfg, symbol); + emit_pointer (acfg, "got"); } static void @@ -3676,20 +3994,16 @@ emit_globals (MonoAotCompile *acfg) emit_string_symbol (acfg, "mono_runtime_version", ""); } - /* - * Some platforms like the iphone have no working dlsym (). To work around this, - * we create an ELF ctor function which will be invoked by dlopen, and which - * will call a function in the AOT loader to register the symbols used by the - * image. + /* * When static linking, we emit a global which will point to the symbol table. */ - if (acfg->aot_opts.no_dlsym) { + if (acfg->aot_opts.static_link) { int i; char symbol [256]; + char *p; - if (acfg->aot_opts.static_link) - /* Emit a string holding the assembly name */ - emit_string_symbol (acfg, "mono_aot_assembly_name", acfg->image->assembly->aname.name); + /* 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) { @@ -3718,101 +4032,45 @@ emit_globals (MonoAotCompile *acfg) emit_pointer (acfg, symbol); } /* Null terminate the table */ - emit_pointer (acfg, NULL); - emit_pointer (acfg, NULL); + emit_int32 (acfg, 0); + emit_int32 (acfg, 0); -#if 0 - if (acfg->aot_opts.static_link) { - char *p; - - /* - * Emit a global symbol which can be passed by an embedding app to - * mono_aot_register_module (). - */ + /* + * Emit a global symbol which can be passed by an embedding app to + * mono_aot_register_module (). + */ #if defined(__MACH__) - sprintf (symbol, "_mono_aot_module_%s_info", acfg->image->assembly->aname.name); + sprintf (symbol, "_mono_aot_module_%s_info", acfg->image->assembly->aname.name); #else - sprintf (symbol, "mono_aot_module_%s_info", acfg->image->assembly->aname.name); + sprintf (symbol, "mono_aot_module_%s_info", acfg->image->assembly->aname.name); #endif - /* Get rid of characters which cannot occur in symbols */ - p = symbol; - for (p = symbol; *p; ++p) { - if (!(isalnum (*p) || *p == '_')) - *p = '_'; - } - acfg->static_linking_symbol = g_strdup (symbol); - emit_global_inner (acfg, symbol, FALSE); - emit_alignment (acfg, 8); - emit_label (acfg, symbol); - emit_pointer (acfg, "globals"); - } else { - sprintf (symbol, "init_%s", acfg->image->assembly->aname.name); - emit_section_change (acfg, ".text", 1); - emit_alignment (acfg, 8); - emit_label (acfg, symbol); - if (acfg->use_bin_writer) - g_assert_not_reached (); -#ifdef __x86_64__ - fprintf (acfg->fp, "leaq globals(%%rip), %%rdi\n"); - fprintf (acfg->fp, "call mono_aot_register_globals@PLT\n"); - fprintf (acfg->fp, "ret\n"); - fprintf (acfg->fp, ".section .ctors,\"aw\",@progbits\n"); - emit_alignment (acfg, 8); - emit_pointer (acfg, symbol); -#elif defined(__arm__) && defined(__MACH__) - - fprintf (acfg->fp, ".text\n"); - fprintf (acfg->fp, ".align 3\n"); - - fprintf (acfg->fp, "ldr r0, .L5\n"); - fprintf (acfg->fp, ".LPIC0:\n"); - fprintf (acfg->fp, "add r0, pc, r0\n"); - fprintf (acfg->fp, "ldr r0, [r0]\n"); - fprintf (acfg->fp, "b _mono_aot_register_globals@PLT\n"); - fprintf (acfg->fp, ".align 2\n"); - - fprintf (acfg->fp, ".L5:\n"); - fprintf (acfg->fp, ".long globals_ptr-(.LPIC0+8)\n"); - - fprintf (acfg->fp, ".data\n"); - fprintf (acfg->fp, ".align 2\n"); - fprintf (acfg->fp, "globals_ptr:\n"); - fprintf (acfg->fp, ".long globals\n"); - - fprintf (acfg->fp, ".mod_init_func\n"); - fprintf (acfg->fp, ".align 2\n"); - fprintf (acfg->fp, ".long %s@target1\n", symbol); - -#elif defined(__arm__) - /* - * Taken from gcc generated code for: - * static int i; - * void foo () { bar (&i); } - * gcc --shared -fPIC -O2 - */ - fprintf (acfg->fp, "ldr r3, .L5\n"); - fprintf (acfg->fp, "ldr r0, .L5+4\n"); - fprintf (acfg->fp, ".LPIC0:\n"); - fprintf (acfg->fp, "add r3, pc, r3\n"); - fprintf (acfg->fp, "add r0, r3, r0\n"); - fprintf (acfg->fp, "b mono_aot_register_globals(PLT)\n"); - - fprintf (acfg->fp, ".L5:\n"); - fprintf (acfg->fp, ".word _GLOBAL_OFFSET_TABLE_-(.LPIC0+8)\n"); - fprintf (acfg->fp, ".word globals(GOTOFF)\n"); - - fprintf (acfg->fp, ".section .init_array,\"aw\",%%init_array\n"); - fprintf (acfg->fp, ".align 2\n"); - fprintf (acfg->fp, ".word %s(target1)\n", symbol); -#else - g_assert_not_reached (); -#endif + /* Get rid of characters which cannot occur in symbols */ + p = symbol; + for (p = symbol; *p; ++p) { + if (!(isalnum (*p) || *p == '_')) + *p = '_'; } -#endif + acfg->static_linking_symbol = g_strdup (symbol); + emit_global_inner (acfg, symbol, FALSE); + emit_alignment (acfg, 8); + emit_label (acfg, symbol); + emit_pointer (acfg, "globals"); } } +static void +emit_mem_end (MonoAotCompile *acfg) +{ + char symbol [128]; + + sprintf (symbol, "mem_end"); + emit_section_change (acfg, ".text", 1); + emit_global (acfg, symbol, FALSE); + emit_alignment (acfg, 8); + emit_label (acfg, symbol); +} + /* * Emit a structure containing all the information not stored elsewhere. */ @@ -3829,18 +4087,16 @@ emit_file_info (MonoAotCompile *acfg) /* The data emitted here must match MonoAotFileInfo in aot-runtime.c. */ emit_int32 (acfg, acfg->plt_got_offset_base); - emit_int32 (acfg, acfg->trampoline_got_offset_base); - emit_int32 (acfg, acfg->num_aot_trampolines); emit_int32 (acfg, (int)(acfg->got_offset * sizeof (gpointer))); emit_int32 (acfg, acfg->plt_offset); + emit_int32 (acfg, acfg->num_specific_trampolines); emit_int32 (acfg, acfg->specific_trampoline_size); - emit_pointer (acfg, "got"); + emit_int32 (acfg, acfg->specific_trampoline_got_offset_base); + emit_int32 (acfg, acfg->num_static_rgctx_trampolines); + emit_int32 (acfg, acfg->static_rgctx_trampoline_size); + emit_int32 (acfg, acfg->static_rgctx_trampoline_got_offset_base); } -/*****************************************/ -/* Emitting DWARF debug information */ -/*****************************************/ - static void emit_dwarf_info (MonoAotCompile *acfg) { @@ -3863,13 +4119,113 @@ emit_dwarf_info (MonoAotCompile *acfg) #endif } +static void +collect_methods (MonoAotCompile *acfg) +{ + int i; + MonoImage *image = acfg->image; + + /* Collect methods */ + for (i = 0; i < image->tables [MONO_TABLE_METHOD].rows; ++i) { + MonoMethod *method; + guint32 token = MONO_TOKEN_METHOD_DEF | (i + 1); + + method = mono_get_method (acfg->image, token, NULL); + + if (!method) { + printf ("Failed to load method 0x%x from '%s'.\n", token, image->name); + exit (1); + } + + /* Load all methods eagerly to skip the slower lazy loading code */ + mono_class_setup_methods (method->klass); + + if (acfg->aot_opts.full_aot && method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) { + /* Compile the wrapper instead */ + /* We do this here instead of add_wrappers () because it is easy to do it here */ + MonoMethod *wrapper = mono_marshal_get_native_wrapper (method, check_for_pending_exc, TRUE); + method = wrapper; + } + + /* Since we add the normal methods first, their index will be equal to their zero based token index */ + add_method_with_index (acfg, method, i); + acfg->method_index ++; + } + + add_generic_instances (acfg); + + if (acfg->aot_opts.full_aot) + add_wrappers (acfg); +} + +static void +compile_methods (MonoAotCompile *acfg) +{ + int i, methods_len; + + if (acfg->aot_opts.nthreads > 0) { + GPtrArray *frag; + int len, j; + GPtrArray *threads; + HANDLE handle; + gpointer *user_data; + MonoMethod **methods; + + methods_len = acfg->methods->len; + + len = acfg->methods->len / acfg->aot_opts.nthreads; + g_assert (len > 0); + /* + * Partition the list of methods into fragments, and hand it to threads to + * process. + */ + threads = g_ptr_array_new (); + /* Make a copy since acfg->methods is modified by compile_method () */ + methods = g_new0 (MonoMethod*, methods_len); + //memcpy (methods, g_ptr_array_index (acfg->methods, 0), sizeof (MonoMethod*) * methods_len); + for (i = 0; i < methods_len; ++i) + methods [i] = g_ptr_array_index (acfg->methods, i); + i = 0; + while (i < methods_len) { + frag = g_ptr_array_new (); + for (j = 0; j < len; ++j) { + if (i < methods_len) { + g_ptr_array_add (frag, methods [i]); + i ++; + } + } + + user_data = g_new0 (gpointer, 3); + user_data [0] = mono_domain_get (); + user_data [1] = acfg; + user_data [2] = frag; + + handle = mono_create_thread (NULL, 0, (gpointer)compile_thread_main, user_data, 0, NULL); + g_ptr_array_add (threads, handle); + } + g_free (methods); + + for (i = 0; i < threads->len; ++i) { + WaitForSingleObjectEx (g_ptr_array_index (threads, i), INFINITE, FALSE); + } + } else { + methods_len = 0; + } + + /* Compile methods added by compile_method () or all methods if nthreads == 0 */ + for (i = methods_len; i < acfg->methods->len; ++i) { + /* This can new methods to acfg->methods */ + compile_method (acfg, g_ptr_array_index (acfg->methods, i)); + } +} + static int compile_asm (MonoAotCompile *acfg) { char *command, *objfile; char *outfile_name, *tmp_outfile_name; -#if defined(__x86_64__) +#if defined(TARGET_AMD64) #define AS_OPTIONS "--64" #elif defined(sparc) && SIZEOF_VOID_P == 8 #define AS_OPTIONS "-xarch=v9" @@ -3917,20 +4273,13 @@ compile_asm (MonoAotCompile *acfg) tmp_outfile_name = g_strdup_printf ("%s.tmp", outfile_name); #if defined(sparc) - command = g_strdup_printf ("ld -shared -G -o %s %s.o", outfile_name, acfg->tmpfname); + command = g_strdup_printf ("ld -shared -G -o %s %s.o", tmp_outfile_name, acfg->tmpfname); #elif defined(__ppc__) && defined(__MACH__) - command = g_strdup_printf ("gcc -dynamiclib -o %s %s.o", outfile_name, acfg->tmpfname); + command = g_strdup_printf ("gcc -dynamiclib -o %s %s.o", tmp_outfile_name, acfg->tmpfname); #elif defined(PLATFORM_WIN32) - command = g_strdup_printf ("gcc -shared --dll -mno-cygwin -o %s %s.o", outfile_name, acfg->tmpfname); + command = g_strdup_printf ("gcc -shared --dll -mno-cygwin -o %s %s.o", tmp_outfile_name, acfg->tmpfname); #else - if (acfg->aot_opts.no_dlsym) { - /* - * Need to link using gcc so our ctor function gets called. - */ - command = g_strdup_printf ("gcc -shared -o %s %s.o", outfile_name, acfg->tmpfname); - } else { - command = g_strdup_printf ("ld -shared -o %s %s.o", outfile_name, acfg->tmpfname); - } + command = g_strdup_printf ("ld -shared -o %s %s.o", tmp_outfile_name, acfg->tmpfname); #endif printf ("Executing the native linker: %s\n", command); if (system (command) != 0) { @@ -3948,6 +4297,22 @@ compile_asm (MonoAotCompile *acfg) system (com); g_free (com);*/ +#if defined(TARGET_ARM) && !defined(__MACH__) + /* + * gas generates 'mapping symbols' each time code and data is mixed, which + * happens a lot in emit_and_reloc_code (), so we need to get rid of them. + */ + command = g_strdup_printf ("strip --strip-symbol=\\$a --strip-symbol=\\$d %s", tmp_outfile_name); + printf ("Stripping the binary: %s\n", command); + if (system (command) != 0) { + g_free (tmp_outfile_name); + g_free (outfile_name); + g_free (command); + g_free (objfile); + return 1; + } +#endif + rename (tmp_outfile_name, outfile_name); g_free (tmp_outfile_name); @@ -3962,6 +4327,35 @@ compile_asm (MonoAotCompile *acfg) return 0; } +static MonoAotCompile* +acfg_create (MonoAssembly *ass, guint32 opts) +{ + MonoImage *image = ass->image; + MonoAotCompile *acfg; + + acfg = g_new0 (MonoAotCompile, 1); + acfg->methods = g_ptr_array_new (); + acfg->method_indexes = 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_shared_got_offset = g_hash_table_new (mono_patch_info_hash, mono_patch_info_equal); + acfg->shared_patches = g_ptr_array_new (); + acfg->method_to_cfg = g_hash_table_new (NULL, NULL); + acfg->token_info_hash = g_hash_table_new_full (NULL, NULL, NULL, g_free); + acfg->image_hash = g_hash_table_new (NULL, NULL); + acfg->image_table = g_ptr_array_new (); + acfg->globals = g_ptr_array_new (); + acfg->image = image; + acfg->opts = opts; + acfg->mempool = mono_mempool_new (); + acfg->extra_methods = g_ptr_array_new (); + acfg->unwind_info_offsets = g_hash_table_new (NULL, NULL); + acfg->unwind_ops = g_ptr_array_new (); + InitializeCriticalSection (&acfg->mutex); + + return acfg; +} + static void acfg_free (MonoAotCompile *acfg) { @@ -3977,6 +4371,7 @@ acfg_free (MonoAotCompile *acfg) g_ptr_array_free (acfg->shared_patches, TRUE); g_ptr_array_free (acfg->image_table, TRUE); 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->plt_offset_to_patch); g_hash_table_destroy (acfg->patch_to_plt_offset); @@ -3984,6 +4379,7 @@ acfg_free (MonoAotCompile *acfg) g_hash_table_destroy (acfg->method_to_cfg); g_hash_table_destroy (acfg->token_info_hash); g_hash_table_destroy (acfg->image_hash); + g_hash_table_destroy (acfg->unwind_info_offsets); mono_mempool_destroy (acfg->mempool); g_free (acfg); } @@ -3992,8 +4388,7 @@ int mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options) { MonoImage *image = ass->image; - char symbol [256]; - int i, res, methods_len; + int res; MonoAotCompile *acfg; char *outfile_name, *tmp_outfile_name; TV_DECLARE (atv); @@ -4001,37 +4396,26 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options) printf ("Mono Ahead of Time compiler - compiling assembly %s\n", image->name); - acfg = g_new0 (MonoAotCompile, 1); - acfg->methods = g_ptr_array_new (); - acfg->method_indexes = 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_shared_got_offset = g_hash_table_new (mono_patch_info_hash, mono_patch_info_equal); - acfg->shared_patches = g_ptr_array_new (); - acfg->method_to_cfg = g_hash_table_new (NULL, NULL); - acfg->token_info_hash = g_hash_table_new_full (NULL, NULL, NULL, g_free); - acfg->image_hash = g_hash_table_new (NULL, NULL); - acfg->image_table = g_ptr_array_new (); - acfg->globals = g_ptr_array_new (); - acfg->image = image; - acfg->opts = opts; - acfg->mempool = mono_mempool_new (); - acfg->extra_methods = g_ptr_array_new (); - InitializeCriticalSection (&acfg->mutex); + acfg = acfg_create (ass, opts); memset (&acfg->aot_opts, 0, sizeof (acfg->aot_opts)); acfg->aot_opts.write_symbols = TRUE; + acfg->aot_opts.ntrampolines = 10240; mono_aot_parse_options (aot_options, &acfg->aot_opts); //acfg->aot_opts.print_skipped_methods = TRUE; -#ifdef __arm__ - if (acfg->aot_opts.full_aot) - /* arch_emit_unbox_trampoline () etc only works with the asm writer */ - acfg->aot_opts.asm_writer = TRUE; +#ifndef MONO_ARCH_HAVE_FULL_AOT_TRAMPOLINES + if (acfg->aot_opts.full_aot) { + printf ("--aot=full is not supported on this platform.\n"); + return 1; + } #endif + if (acfg->aot_opts.static_link) + acfg->aot_opts.asm_writer = TRUE; + if (!acfg->aot_opts.asm_only && !acfg->aot_opts.asm_writer && bin_writer_supported ()) { if (acfg->aot_opts.outfile) outfile_name = g_strdup_printf ("%s", acfg->aot_opts.outfile); @@ -4060,52 +4444,23 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options) acfg->w = img_writer_create (acfg->fp, FALSE); - /* hush compiler warnings about these being possibly uninitialized */ tmp_outfile_name = NULL; outfile_name = NULL; } load_profile_files (acfg); - img_writer_emit_start (acfg->w); - - acfg->dwarf = mono_dwarf_writer_create (acfg->w, NULL); + if (!acfg->aot_opts.nodebug) + acfg->dwarf = mono_dwarf_writer_create (acfg->w, NULL); - acfg->num_aot_trampolines = acfg->aot_opts.full_aot ? 10240 : 0; + acfg->num_specific_trampolines = acfg->aot_opts.full_aot ? acfg->aot_opts.ntrampolines : 0; +#ifdef MONO_ARCH_HAVE_STATIC_RGCTX_TRAMPOLINE + acfg->num_static_rgctx_trampolines = acfg->aot_opts.full_aot ? 1024 : 0; +#endif acfg->method_index = 1; - /* Collect methods */ - for (i = 0; i < image->tables [MONO_TABLE_METHOD].rows; ++i) { - MonoMethod *method; - guint32 token = MONO_TOKEN_METHOD_DEF | (i + 1); - - method = mono_get_method (acfg->image, token, NULL); - - if (!method) { - printf ("Failed to load method 0x%x from '%s'.\n", token, image->name); - exit (1); - } - - /* Load all methods eagerly to skip the slower lazy loading code */ - mono_class_setup_methods (method->klass); - - if (acfg->aot_opts.full_aot && method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) { - /* Compile the wrapper instead */ - /* We do this here instead of add_wrappers () because it is easy to do it here */ - MonoMethod *wrapper = mono_marshal_get_native_wrapper (method, check_for_pending_exc, TRUE); - method = wrapper; - } - - /* Since we add the normal methods first, their index will be equal to their zero based token index */ - add_method_with_index (acfg, method, i); - acfg->method_index ++; - } - - add_generic_instances (acfg); - - if (acfg->aot_opts.full_aot) - add_wrappers (acfg); + collect_methods (acfg); acfg->cfgs_size = acfg->methods->len + 32; acfg->cfgs = g_new0 (MonoCompile*, acfg->cfgs_size); @@ -4113,74 +4468,23 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options) /* PLT offset 0 is reserved for the PLT trampoline */ acfg->plt_offset = 1; - /* Compile methods */ TV_GETTIME (atv); - if (acfg->aot_opts.nthreads > 0) { - GPtrArray *frag; - int len, j; - GPtrArray *threads; - HANDLE handle; - gpointer *user_data; - MonoMethod **methods; - - methods_len = acfg->methods->len; - - len = acfg->methods->len / acfg->aot_opts.nthreads; - g_assert (len > 0); - /* - * Partition the list of methods into fragments, and hand it to threads to - * process. - */ - threads = g_ptr_array_new (); - /* Make a copy since acfg->methods is modified by compile_method () */ - methods = g_new0 (MonoMethod*, methods_len); - //memcpy (methods, g_ptr_array_index (acfg->methods, 0), sizeof (MonoMethod*) * methods_len); - for (i = 0; i < methods_len; ++i) - methods [i] = g_ptr_array_index (acfg->methods, i); - i = 0; - while (i < methods_len) { - frag = g_ptr_array_new (); - for (j = 0; j < len; ++j) { - if (i < methods_len) { - g_ptr_array_add (frag, methods [i]); - i ++; - } - } - - user_data = g_new0 (gpointer, 3); - user_data [0] = mono_domain_get (); - user_data [1] = acfg; - user_data [2] = frag; - - handle = CreateThread (NULL, 0, (gpointer)compile_thread_main, user_data, 0, NULL); - g_ptr_array_add (threads, handle); - } - g_free (methods); - - for (i = 0; i < threads->len; ++i) { - WaitForSingleObjectEx (g_ptr_array_index (threads, i), INFINITE, FALSE); - } - } else { - methods_len = 0; - } - - /* Compile methods added by compile_method () or all methods if nthreads == 0 */ - for (i = methods_len; i < acfg->methods->len; ++i) { - /* This can new methods to acfg->methods */ - compile_method (acfg, g_ptr_array_index (acfg->methods, i)); - } + compile_methods (acfg); TV_GETTIME (btv); - + acfg->stats.jit_time = TV_ELAPSED (atv, btv); TV_GETTIME (atv); - mono_dwarf_writer_emit_base_info (acfg->dwarf, arch_get_cie_program ()); - alloc_got_slots (acfg); + img_writer_emit_start (acfg->w); + + if (acfg->dwarf) + mono_dwarf_writer_emit_base_info (acfg->dwarf, arch_get_cie_program ()); + emit_code (acfg); emit_info (acfg); @@ -4197,6 +4501,8 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options) emit_exception_info (acfg); + emit_unwind_info (acfg); + emit_class_info (acfg); emit_plt (acfg); @@ -4209,19 +4515,16 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options) emit_globals (acfg); - emit_dwarf_info (acfg); + if (acfg->dwarf) + emit_dwarf_info (acfg); - sprintf (symbol, "mem_end"); - emit_section_change (acfg, ".text", 1); - emit_global (acfg, symbol, FALSE); - emit_alignment (acfg, 8); - emit_label (acfg, symbol); + emit_mem_end (acfg); TV_GETTIME (btv); acfg->stats.gen_time = TV_ELAPSED (atv, btv); - printf ("Code: %d Info: %d Ex Info: %d Class Info: %d PLT: %d GOT Info: %d GOT Info Offsets: %d GOT: %d\n", acfg->stats.code_size, acfg->stats.info_size, acfg->stats.ex_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))); + 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\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))); TV_GETTIME (atv); res = img_writer_emit_writeout (acfg->w); @@ -4252,12 +4555,15 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options) printf ("%d methods have other problems (%d%%)\n", acfg->stats.ocount, acfg->stats.mcount ? (acfg->stats.ocount * 100) / acfg->stats.mcount : 100); 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 ("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); + /* 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); acfg_free (acfg); @@ -4290,20 +4596,14 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options) */ static MonoDwarfWriter *xdebug_writer; -static CRITICAL_SECTION xdebug_mutex; static FILE *xdebug_fp; -#define mono_xdebug_lock(acfg) EnterCriticalSection (&xdebug_mutex) -#define mono_xdebug_unlock(acfg) LeaveCriticalSection (&xdebug_mutex) - void mono_xdebug_init (void) { FILE *il_file; MonoImageWriter *w; - InitializeCriticalSection (&xdebug_mutex); - unlink ("xdb.s"); xdebug_fp = fopen ("xdb.s", "w"); @@ -4328,6 +4628,7 @@ mono_xdebug_init (void) * * Emit debugging info for METHOD into an assembly file which can be assembled * and loaded into gdb to provide debugging info for JITted code. + * LOCKING: Acquires the loader lock. */ void mono_save_xdebug_info (MonoCompile *cfg) @@ -4335,16 +4636,17 @@ mono_save_xdebug_info (MonoCompile *cfg) if (!xdebug_writer) return; - mono_xdebug_lock (); + mono_loader_lock (); mono_dwarf_writer_emit_method (xdebug_writer, cfg, cfg->jit_info->method, NULL, NULL, cfg->jit_info->code_start, cfg->jit_info->code_size, cfg->args, cfg->locals, cfg->unwind_ops, mono_debug_find_method (cfg->jit_info->method, mono_domain_get ())); fflush (xdebug_fp); - mono_xdebug_unlock (); + mono_loader_unlock (); } /* * mono_save_trampoline_xdebug_info: * * Same as mono_save_xdebug_info, but for trampolines. + * LOCKING: Acquires the loader lock. */ void mono_save_trampoline_xdebug_info (const char *tramp_name, guint8 *code, guint32 code_size, GSList *unwind_info) @@ -4352,10 +4654,10 @@ mono_save_trampoline_xdebug_info (const char *tramp_name, guint8 *code, guint32 if (!xdebug_writer) return; - mono_xdebug_lock (); + mono_loader_lock (); mono_dwarf_writer_emit_trampoline (xdebug_writer, tramp_name, NULL, NULL, code, code_size, unwind_info); fflush (xdebug_fp); - mono_xdebug_unlock (); + mono_loader_unlock (); } #else