Merge pull request #1857 from slluis/fix-assembly-resolver
[mono.git] / mono / mini / aot-compiler.c
index cf80a74070f7288e5974752117cdf0ab12ca7351..933ecfaf395cab7cbbaeced533c87631f4669cc7 100644 (file)
@@ -99,7 +99,7 @@ typedef struct MonoAotOptions {
        gboolean write_symbols;
        gboolean metadata_only;
        gboolean bind_to_runtime_version;
-       gboolean full_aot;
+       MonoAotMode mode;
        gboolean no_dlsym;
        gboolean static_link;
        gboolean asm_only;
@@ -130,6 +130,7 @@ typedef struct MonoAotOptions {
        gboolean autoreg;
        char *mtriple;
        char *llvm_path;
+       char *temp_path;
        char *instances_logfile_path;
        char *logfile;
        gboolean dump_json;
@@ -3066,7 +3067,6 @@ is_plt_patch (MonoJumpInfo *patch_info)
        case MONO_PATCH_INFO_ICALL_ADDR:
        case MONO_PATCH_INFO_CLASS_INIT:
        case MONO_PATCH_INFO_RGCTX_FETCH:
-       case MONO_PATCH_INFO_GENERIC_CLASS_INIT:
        case MONO_PATCH_INFO_MONITOR_ENTER:
        case MONO_PATCH_INFO_MONITOR_ENTER_V4:
        case MONO_PATCH_INFO_MONITOR_EXIT:
@@ -3211,6 +3211,16 @@ add_method_with_index (MonoAotCompile *acfg, MonoMethod *method, int index, gboo
                g_ptr_array_add (acfg->extra_methods, method);
 }
 
+static gboolean
+prefer_gsharedvt_method (MonoAotCompile *acfg, MonoMethod *method)
+{
+       /* One instantiation with valuetypes is generated for each async method */
+       if (method->klass->image == mono_defaults.corlib && (!strcmp (method->klass->name, "AsyncMethodBuilderCore") || !strcmp (method->klass->name, "AsyncVoidMethodBuilder")))
+               return TRUE;
+       else
+               return FALSE;
+}
+
 static guint32
 get_method_index (MonoAotCompile *acfg, MonoMethod *method)
 {
@@ -3253,6 +3263,9 @@ add_extra_method_with_depth (MonoAotCompile *acfg, MonoMethod *method, int depth
 {
        if (mono_method_is_generic_sharable_full (method, FALSE, TRUE, FALSE))
                method = mini_get_shared_method (method);
+       else if ((acfg->opts & MONO_OPT_GSHAREDVT) && prefer_gsharedvt_method (acfg, method) && mono_method_is_generic_sharable_full (method, FALSE, FALSE, TRUE))
+               /* Use the gsharedvt version */
+               return;
 
        if (acfg->aot_opts.log_generics)
                aot_printf (acfg, "%*sAdding method %s.\n", depth, "", mono_method_full_name (method, TRUE));
@@ -3559,7 +3572,12 @@ add_wrappers (MonoAotCompile *acfg)
                        /* Managed Allocators */
                        nallocators = mono_gc_get_managed_allocator_types ();
                        for (i = 0; i < nallocators; ++i) {
-                               m = mono_gc_get_managed_allocator_by_type (i);
+                               m = mono_gc_get_managed_allocator_by_type (i, TRUE);
+                               if (m)
+                                       add_method (acfg, m);
+                       }
+                       for (i = 0; i < nallocators; ++i) {
+                               m = mono_gc_get_managed_allocator_by_type (i, FALSE);
                                if (m)
                                        add_method (acfg, m);
                        }
@@ -3655,8 +3673,18 @@ add_wrappers (MonoAotCompile *acfg)
                                for (j = 0; j < cattr->num_attrs; ++j)
                                        if (cattr->attrs [j].ctor && (!strcmp (cattr->attrs [j].ctor->klass->name, "MonoNativeFunctionWrapperAttribute") || !strcmp (cattr->attrs [j].ctor->klass->name, "UnmanagedFunctionPointerAttribute")))
                                                break;
-                               if (j < cattr->num_attrs)
-                                       add_method (acfg, mono_marshal_get_native_func_wrapper_aot (klass));
+                               if (j < cattr->num_attrs) {
+                                       MonoMethod *invoke;
+                                       MonoMethod *wrapper;
+                                       MonoMethod *del_invoke;
+
+                                       /* Add wrappers needed by mono_ftnptr_to_delegate () */
+                                       invoke = mono_get_delegate_invoke (klass);
+                                       wrapper = mono_marshal_get_native_func_wrapper_aot (klass);
+                                       del_invoke = mono_marshal_get_delegate_invoke_internal (invoke, FALSE, TRUE, wrapper);
+                                       add_method (acfg, wrapper);
+                                       add_method (acfg, del_invoke);
+                               }
                        }
                } else if ((acfg->opts & MONO_OPT_GSHAREDVT) && klass->generic_container) {
                        MonoError error;
@@ -3972,13 +4000,19 @@ method_has_type_vars (MonoMethod *method)
        return FALSE;
 }
 
+static
+gboolean mono_aot_mode_is_full (MonoAotOptions *opts)
+{
+       return opts->mode == MONO_AOT_MODE_FULL;
+}
+
 static void add_generic_class_with_depth (MonoAotCompile *acfg, MonoClass *klass, int depth, const char *ref);
 
 static void
 add_generic_class (MonoAotCompile *acfg, MonoClass *klass, gboolean force, const char *ref)
 {
        /* This might lead to a huge code blowup so only do it if neccesary */
-       if (!acfg->aot_opts.full_aot && !force)
+       if (!mono_aot_mode_is_full (&acfg->aot_opts) && !force)
                return;
 
        add_generic_class_with_depth (acfg, klass, 0, ref);
@@ -4983,7 +5017,9 @@ get_debug_sym (MonoMethod *method, const char *prefix, GHashTable *cache)
        memcpy (name2, prefix, strlen (prefix));
        j = strlen (prefix);
        for (i = 0; i < len; ++i) {
-               if (isalnum (name1 [i])) {
+               if (i == 0 && name1 [0] >= '0' && name1 [0] <= '9') {
+                       name2 [j ++] = '_';
+               } else if (isalnum (name1 [i])) {
                        name2 [j ++] = name1 [i];
                } else if (name1 [i] == ' ' && name1 [i + 1] == '(' && name1 [i + 2] == ')') {
                        i += 2;
@@ -5230,7 +5266,6 @@ encode_patch (MonoAotCompile *acfg, MonoJumpInfo *patch_info, guint8 *buf, guint
                encode_patch (acfg, entry->data, p, &p);
                break;
        }
-       case MONO_PATCH_INFO_GENERIC_CLASS_INIT:
        case MONO_PATCH_INFO_MONITOR_ENTER:
        case MONO_PATCH_INFO_MONITOR_ENTER_V4:
        case MONO_PATCH_INFO_MONITOR_EXIT:
@@ -5846,9 +5881,6 @@ get_plt_entry_debug_sym (MonoAotCompile *acfg, MonoJumpInfo *ji, GHashTable *cac
        case MONO_PATCH_INFO_JIT_ICALL_ADDR:
                debug_sym = g_strdup_printf ("%s_jit_icall_native_%s", prefix, ji->data.name);
                break;
-       case MONO_PATCH_INFO_GENERIC_CLASS_INIT:
-               debug_sym = g_strdup_printf ("%s_generic_class_init", prefix);
-               break;
        default:
                break;
        }
@@ -6112,7 +6144,7 @@ emit_trampolines (MonoAotCompile *acfg)
        int tramp_type;
 #endif
 
-       if (!acfg->aot_opts.full_aot)
+       if (!mono_aot_mode_is_full (&acfg->aot_opts))
                return;
        
        g_assert (acfg->image->assembly);
@@ -6156,9 +6188,6 @@ emit_trampolines (MonoAotCompile *acfg)
                emit_trampoline (acfg, acfg->got_offset, info);
 #endif
 
-               mono_arch_create_generic_class_init_trampoline (&info, TRUE);
-               emit_trampoline (acfg, acfg->got_offset, info);
-
                /* Emit the exception related code pieces */
                mono_arch_get_restore_context (&info, TRUE);
                emit_trampoline (acfg, acfg->got_offset, info);
@@ -6427,6 +6456,21 @@ add_readonly_value (MonoAotOptions *opts, const char *val)
        readonly_values = rdv;
 }
 
+static gchar *
+clean_path (gchar * path)
+{
+       if (!path)
+               return NULL;
+
+       if (g_str_has_suffix (path, G_DIR_SEPARATOR_S))
+               return path;
+
+       gchar *clean = g_strconcat (path, G_DIR_SEPARATOR_S, NULL);
+       g_free (path);
+
+       return clean;
+}
+
 static void
 mono_aot_parse_options (const char *aot_options, MonoAotOptions *opts)
 {
@@ -6440,6 +6484,8 @@ mono_aot_parse_options (const char *aot_options, MonoAotOptions *opts)
                        opts->outfile = g_strdup (arg + strlen ("outfile="));
                } else if (str_begins_with (arg, "llvm-outfile=")) {
                        opts->llvm_outfile = g_strdup (arg + strlen ("llvm-outfile="));
+               } else if (str_begins_with (arg, "temp-path=")) {
+                       opts->temp_path = clean_path (g_strdup (arg + strlen ("temp-path=")));
                } else if (str_begins_with (arg, "save-temps")) {
                        opts->save_temps = TRUE;
                } else if (str_begins_with (arg, "keep-temps")) {
@@ -6453,7 +6499,9 @@ mono_aot_parse_options (const char *aot_options, MonoAotOptions *opts)
                } else if (str_begins_with (arg, "bind-to-runtime-version")) {
                        opts->bind_to_runtime_version = TRUE;
                } else if (str_begins_with (arg, "full")) {
-                       opts->full_aot = TRUE;
+                       opts->mode = MONO_AOT_MODE_FULL;
+               } else if (str_begins_with (arg, "hybrid")) {
+                       opts->mode = MONO_AOT_MODE_HYBRID;                      
                } else if (str_begins_with (arg, "threads=")) {
                        opts->nthreads = atoi (arg + strlen ("threads="));
                } else if (str_begins_with (arg, "static")) {
@@ -6511,12 +6559,7 @@ mono_aot_parse_options (const char *aot_options, MonoAotOptions *opts)
                } else if (str_begins_with (arg, "mtriple=")) {
                        opts->mtriple = g_strdup (arg + strlen ("mtriple="));
                } else if (str_begins_with (arg, "llvm-path=")) {
-                       opts->llvm_path = g_strdup (arg + strlen ("llvm-path="));
-                       if (!g_str_has_suffix (opts->llvm_path, G_DIR_SEPARATOR_S)) {
-                               gchar *old = opts->llvm_path;
-                               opts->llvm_path = g_strconcat (opts->llvm_path, G_DIR_SEPARATOR_S, NULL);
-                               g_free (old);
-                       }
+                       opts->llvm_path = clean_path (g_strdup (arg + strlen ("llvm-path=")));
                } else if (!strcmp (arg, "llvm")) {
                        opts->llvm = TRUE;
                } else if (str_begins_with (arg, "readonly-value=")) {
@@ -6532,6 +6575,8 @@ mono_aot_parse_options (const char *aot_options, MonoAotOptions *opts)
                        printf ("Supported options for --aot:\n");
                        printf ("    outfile=\n");
                        printf ("    llvm-outfile=\n");
+                       printf ("    llvm-path=\n");
+                       printf ("    temp-path=\n");
                        printf ("    save-temps\n");
                        printf ("    keep-temps\n");
                        printf ("    write-symbols\n");
@@ -6758,7 +6803,7 @@ compile_method (MonoAotCompile *acfg, MonoMethod *method)
         * does not need to support them by creating a fake GOT etc.
         */
        flags = JIT_FLAG_AOT;
-       if (acfg->aot_opts.full_aot)
+       if (mono_aot_mode_is_full (&acfg->aot_opts))
                flags |= JIT_FLAG_FULL_AOT;
        if (acfg->llvm)
                flags |= JIT_FLAG_LLVM;
@@ -6875,7 +6920,7 @@ compile_method (MonoAotCompile *acfg, MonoMethod *method)
                                                  mono_method_is_generic_sharable_full (m, FALSE, FALSE, FALSE)) &&
                                                !method_has_type_vars (m)) {
                                                if (m->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) {
-                                                       if (acfg->aot_opts.full_aot)
+                                                       if (mono_aot_mode_is_full (&acfg->aot_opts))
                                                                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);
@@ -7405,7 +7450,7 @@ emit_code (MonoAotCompile *acfg)
                method = cfg->orig_method;
 
                /* Emit unbox trampoline */
-               if (acfg->aot_opts.full_aot && cfg->orig_method->klass->valuetype) {
+               if (mono_aot_mode_is_full (&acfg->aot_opts) && cfg->orig_method->klass->valuetype) {
                        sprintf (symbol, "ut_%d", get_method_index (acfg, method));
 
                        emit_section_change (acfg, ".text", 0);
@@ -7500,7 +7545,7 @@ emit_code (MonoAotCompile *acfg)
 
                method = cfg->orig_method;
 
-               if (acfg->aot_opts.full_aot && cfg->orig_method->klass->valuetype) {
+               if (mono_aot_mode_is_full (&acfg->aot_opts) && cfg->orig_method->klass->valuetype) {
                        index = get_method_index (acfg, method);
 
                        emit_int32 (acfg, index);
@@ -7530,7 +7575,7 @@ emit_code (MonoAotCompile *acfg)
 
                method = cfg->orig_method;
 
-               if (acfg->aot_opts.full_aot && cfg->orig_method->klass->valuetype) {
+               if (mono_aot_mode_is_full (&acfg->aot_opts) && cfg->orig_method->klass->valuetype) {
 #ifdef MONO_ARCH_AOT_SUPPORTED
                        int call_size;
 
@@ -8465,11 +8510,6 @@ emit_file_info (MonoAotCompile *acfg)
                emit_pointer (acfg, NULL);
                emit_pointer (acfg, NULL);
        }
-       if (acfg->thumb_mixed) {
-               emit_pointer (acfg, "thumb_end");
-       } else {
-               emit_pointer (acfg, NULL);
-       }
        if (acfg->aot_opts.static_link) {
                emit_pointer (acfg, "globals");
        } else {
@@ -8651,7 +8691,7 @@ collect_methods (MonoAotCompile *acfg)
                /* 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) {
+               if (mono_aot_mode_is_full (&acfg->aot_opts) && 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);
@@ -8708,7 +8748,7 @@ collect_methods (MonoAotCompile *acfg)
 
        add_generic_instances (acfg);
 
-       if (acfg->aot_opts.full_aot)
+       if (mono_aot_mode_is_full (&acfg->aot_opts))
                add_wrappers (acfg);
        return TRUE;
 }
@@ -8821,7 +8861,7 @@ compile_asm (MonoAotCompile *acfg)
 #define LD_NAME "gcc -shared --dll"
 #elif defined(TARGET_X86) && defined(TARGET_MACH) && !defined(__native_client_codegen__)
 #define LD_NAME "clang -m32 -dynamiclib"
-#elif defined(TARGET_ARM)
+#elif defined(TARGET_ARM) && !defined(TARGET_ANDROID)
 #define LD_NAME "gcc --shared"
 #endif
 
@@ -8918,7 +8958,7 @@ compile_asm (MonoAotCompile *acfg)
         * 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 ("%sstrip --strip-symbol=\\$a --strip-symbol=\\$d %s", tool_prefix, tmp_outfile_name);
+       command = g_strdup_printf ("\"%sstrip\" --strip-symbol=\\$a --strip-symbol=\\$d %s", tool_prefix, tmp_outfile_name);
        aot_printf (acfg, "Stripping the binary: %s\n", command);
        if (execute_system (command) != 0) {
                g_free (tmp_outfile_name);
@@ -9258,7 +9298,7 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
        aot_printf (acfg, "Mono Ahead of Time compiler - compiling assembly %s\n", image->name);
 
 #ifndef MONO_ARCH_HAVE_FULL_AOT_TRAMPOLINES
-       if (acfg->aot_opts.full_aot) {
+       if (mono_aot_mode_is_full (&acfg->aot_opts)) {
                aot_printerrf (acfg, "--aot=full is not supported on this platform.\n");
                return 1;
        }
@@ -9306,11 +9346,17 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
                 * Emit all LLVM code into a separate assembly/object file and link with it
                 * normally.
                 */
-               if (!acfg->aot_opts.asm_only)
+               if (!acfg->aot_opts.asm_only) {
                        acfg->llvm_owriter = TRUE;
+               } else if (acfg->aot_opts.llvm_outfile) {
+                       int len = strlen (acfg->aot_opts.llvm_outfile);
+
+                       if (len >= 2 && acfg->aot_opts.llvm_outfile [len - 2] == '.' && acfg->aot_opts.llvm_outfile [len - 1] == 'o')
+                               acfg->llvm_owriter = TRUE;
+               }
        }
 
-       if (acfg->aot_opts.full_aot)
+       if (mono_aot_mode_is_full (&acfg->aot_opts))
                acfg->flags |= MONO_AOT_FILE_FLAG_FULL_AOT;
 
        if (acfg->aot_opts.instances_logfile_path) {
@@ -9323,20 +9369,23 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
 
        load_profile_files (acfg);
 
-       acfg->num_trampolines [MONO_AOT_TRAMP_SPECIFIC] = acfg->aot_opts.full_aot ? acfg->aot_opts.ntrampolines : 0;
+       acfg->num_trampolines [MONO_AOT_TRAMP_SPECIFIC] = mono_aot_mode_is_full (&acfg->aot_opts) ? acfg->aot_opts.ntrampolines : 0;
 #ifdef MONO_ARCH_GSHARED_SUPPORTED
-       acfg->num_trampolines [MONO_AOT_TRAMP_STATIC_RGCTX] = acfg->aot_opts.full_aot ? acfg->aot_opts.nrgctx_trampolines : 0;
+       acfg->num_trampolines [MONO_AOT_TRAMP_STATIC_RGCTX] = mono_aot_mode_is_full (&acfg->aot_opts) ? acfg->aot_opts.nrgctx_trampolines : 0;
 #endif
-       acfg->num_trampolines [MONO_AOT_TRAMP_IMT_THUNK] = acfg->aot_opts.full_aot ? acfg->aot_opts.nimt_trampolines : 0;
+       acfg->num_trampolines [MONO_AOT_TRAMP_IMT_THUNK] = mono_aot_mode_is_full (&acfg->aot_opts) ? acfg->aot_opts.nimt_trampolines : 0;
 #ifdef MONO_ARCH_GSHAREDVT_SUPPORTED
        if (acfg->opts & MONO_OPT_GSHAREDVT)
-               acfg->num_trampolines [MONO_AOT_TRAMP_GSHAREDVT_ARG] = acfg->aot_opts.full_aot ? acfg->aot_opts.ngsharedvt_arg_trampolines : 0;
+               acfg->num_trampolines [MONO_AOT_TRAMP_GSHAREDVT_ARG] = mono_aot_mode_is_full (&acfg->aot_opts) ? acfg->aot_opts.ngsharedvt_arg_trampolines : 0;
 #endif
 
        acfg->temp_prefix = mono_img_writer_get_temp_label_prefix (NULL);
 
        arch_init (acfg);
 
+       if (acfg->llvm && acfg->thumb_mixed)
+               acfg->flags |= MONO_AOT_FILE_FLAG_LLVM_THUMB;
+
        acfg->assembly_name_sym = g_strdup (acfg->image->assembly->aname.name);
        /* Get rid of characters which cannot occur in symbols */
        for (p = acfg->assembly_name_sym; *p; ++p) {
@@ -9356,7 +9405,7 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
 
        acfg->method_index = 1;
 
-       if (acfg->aot_opts.full_aot)
+       if (mono_aot_mode_is_full (&acfg->aot_opts))
                mono_set_partial_sharing_supported (TRUE);
 
        res = collect_methods (acfg);
@@ -9434,6 +9483,10 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
                        }
                        g_assert (acfg->aot_opts.llvm_outfile);
                        acfg->llvm_sfile = g_strdup (acfg->aot_opts.llvm_outfile);
+                       if (acfg->llvm_owriter)
+                               acfg->llvm_ofile = g_strdup (acfg->aot_opts.llvm_outfile);
+                       else
+                               acfg->llvm_sfile = g_strdup (acfg->aot_opts.llvm_outfile);
                } else {
                        acfg->tmpbasename = g_strdup_printf ("%s", "temp");
                        acfg->tmpfname = g_strdup_printf ("%s.s", acfg->tmpbasename);
@@ -9526,21 +9579,6 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
        if (acfg->dwarf)
                mono_dwarf_writer_emit_base_info (acfg->dwarf, g_path_get_basename (acfg->image->name), mono_unwind_get_cie_program ());
 
-       if (acfg->thumb_mixed) {
-               char symbol [256];
-               /*
-                * This global symbol marks the end of THUMB code, and the beginning of ARM
-                * code generated by our JIT.
-                */
-               sprintf (symbol, "thumb_end");
-               emit_section_change (acfg, ".text", 0);
-               emit_alignment_code (acfg, 8);
-               emit_label (acfg, symbol);
-               emit_zero_bytes (acfg, 16);
-
-               fprintf (acfg->fp, ".arm\n");
-       }
-
        emit_code (acfg);
 
        emit_info (acfg);