New test.
[mono.git] / mono / mini / aot-compiler.c
index 68ee5a6238aa82bdcf07a037c3a6f2c5a2897f4e..0afd5ba593f32b784d7f93d424757d18e01bd034 100644 (file)
@@ -57,7 +57,7 @@
 #include <mono/metadata/mempool-internals.h>
 #include <mono/metadata/mono-endian.h>
 #include <mono/metadata/threads-types.h>
-#include <mono/utils/mono-logger.h>
+#include <mono/utils/mono-logger-internal.h>
 #include <mono/utils/mono-compiler.h>
 #include <mono/utils/mono-time.h>
 #include <mono/utils/mono-mmap.h>
@@ -100,6 +100,7 @@ typedef struct MonoAotOptions {
        int nthreads;
        int ntrampolines;
        int nrgctx_trampolines;
+       int nimt_trampolines;
        gboolean print_skipped_methods;
        gboolean stats;
        char *tool_prefix;
@@ -1196,32 +1197,6 @@ arch_emit_autoreg (MonoAotCompile *acfg, char *symbol)
 #endif
 }
 
-/*
- * mono_arch_get_cie_program:
- *
- *   Get the unwind bytecode for the DWARF CIE.
- */
-GSList*
-mono_arch_get_cie_program (void)
-{
-#ifdef TARGET_AMD64
-       GSList *l = NULL;
-
-       mono_add_unwind_op_def_cfa (l, (guint8*)NULL, (guint8*)NULL, AMD64_RSP, 8);
-       mono_add_unwind_op_offset (l, (guint8*)NULL, (guint8*)NULL, AMD64_RIP, -8);
-
-       return l;
-#elif defined(TARGET_POWERPC)
-       GSList *l = NULL;
-
-       mono_add_unwind_op_def_cfa (l, (guint8*)NULL, (guint8*)NULL, ppc_r1, 0);
-
-       return l;
-#else
-       return NULL;
-#endif
-}
-
 /* END OF ARCH SPECIFIC CODE */
 
 static guint32
@@ -2385,7 +2360,7 @@ add_generic_class (MonoAotCompile *acfg, MonoClass *klass)
 
        iter = NULL;
        while ((method = mono_class_get_methods (klass, &iter))) {
-               if (mono_method_is_generic_sharable_impl (method, FALSE))
+               if (mono_method_is_generic_sharable_impl_full (method, FALSE, FALSE))
                        /* Already added */
                        continue;
 
@@ -2506,18 +2481,98 @@ add_generic_instances (MonoAotCompile *acfg)
                token = MONO_TOKEN_METHOD_SPEC | (i + 1);
                method = mono_get_method (acfg->image, token, NULL);
 
-               context = mono_method_get_context (method);
-               if (context && ((context->class_inst && context->class_inst->is_open) ||
-                                               (context->method_inst && context->method_inst->is_open)))
+               if (method->klass->image != acfg->image)
                        continue;
 
-               if (method->klass->image != acfg->image)
+               context = mono_method_get_context (method);
+
+               if (context && ((context->class_inst && context->class_inst->is_open)))
                        continue;
 
-               if (mono_method_is_generic_sharable_impl (method, FALSE))
-                       /* Already added */
+               /*
+                * For open methods, create an instantiation which can be passed to the JIT.
+                * FIXME: Handle class_inst as well.
+                */
+               if (context && context->method_inst && context->method_inst->is_open) {
+                       MonoGenericContext shared_context;
+                       MonoGenericInst *inst;
+                       MonoType **type_argv;
+                       int i;
+                       MonoMethod *declaring_method;
+                       gboolean supported = TRUE;
+
+                       /* Check that the context doesn't contain open constructed types */
+                       if (context->class_inst) {
+                               inst = context->class_inst;
+                               for (i = 0; i < inst->type_argc; ++i) {
+                                       if (MONO_TYPE_IS_REFERENCE (inst->type_argv [i]) || inst->type_argv [i]->type == MONO_TYPE_VAR || inst->type_argv [i]->type == MONO_TYPE_MVAR)
+                                               continue;
+                                       if (mono_class_is_open_constructed_type (inst->type_argv [i]))
+                                               supported = FALSE;
+                               }
+                       }
+                       if (context->method_inst) {
+                               inst = context->method_inst;
+                               for (i = 0; i < inst->type_argc; ++i) {
+                                       if (MONO_TYPE_IS_REFERENCE (inst->type_argv [i]) || inst->type_argv [i]->type == MONO_TYPE_VAR || inst->type_argv [i]->type == MONO_TYPE_MVAR)
+                                               continue;
+                                       if (mono_class_is_open_constructed_type (inst->type_argv [i]))
+                                               supported = FALSE;
+                               }
+                       }
+
+                       if (!supported)
+                               continue;
+
+                       memset (&shared_context, 0, sizeof (MonoGenericContext));
+
+                       inst = context->class_inst;
+                       if (inst) {
+                               type_argv = g_new0 (MonoType*, inst->type_argc);
+                               for (i = 0; i < inst->type_argc; ++i) {
+                                       if (MONO_TYPE_IS_REFERENCE (inst->type_argv [i]) || inst->type_argv [i]->type == MONO_TYPE_VAR || inst->type_argv [i]->type == MONO_TYPE_MVAR)
+                                               type_argv [i] = &mono_defaults.object_class->byval_arg;
+                                       else
+                                               type_argv [i] = inst->type_argv [i];
+                               }
+                               
+                               shared_context.class_inst = mono_metadata_get_generic_inst (inst->type_argc, type_argv);
+                               g_free (type_argv);
+                       }
+
+                       inst = context->method_inst;
+                       if (inst) {
+                               type_argv = g_new0 (MonoType*, inst->type_argc);
+                               for (i = 0; i < inst->type_argc; ++i) {
+                                       if (MONO_TYPE_IS_REFERENCE (inst->type_argv [i]) || inst->type_argv [i]->type == MONO_TYPE_VAR || inst->type_argv [i]->type == MONO_TYPE_MVAR)
+                                               type_argv [i] = &mono_defaults.object_class->byval_arg;
+                                       else
+                                               type_argv [i] = inst->type_argv [i];
+                               }
+
+                               shared_context.method_inst = mono_metadata_get_generic_inst (inst->type_argc, type_argv);
+                               g_free (type_argv);
+                       }
+
+                       if (method->is_generic || method->klass->generic_container)
+                               declaring_method = method;
+                       else
+                               declaring_method = mono_method_get_declaring_generic_method (method);
+
+                       method = mono_class_inflate_generic_method (declaring_method, &shared_context);
+               }
+
+               /* 
+                * If the method is fully sharable, it was already added in place of its
+                * generic definition.
+                */
+               if (mono_method_is_generic_sharable_impl_full (method, FALSE, FALSE))
                        continue;
 
+               /*
+                * FIXME: Partially shared methods are not shared here, so we end up with
+                * many identical methods.
+                */
                add_extra_method (acfg, method);
        }
 
@@ -2843,26 +2898,6 @@ emit_method_code (MonoAotCompile *acfg, MonoCompile *cfg)
 
        method_index = get_method_index (acfg, method);
 
-       /* Emit unbox trampoline */
-       if (acfg->aot_opts.full_aot && cfg->orig_method->klass->valuetype && (method->flags & METHOD_ATTRIBUTE_VIRTUAL)) {
-               char call_target [256];
-
-               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);
-               emit_label (acfg, symbol);
-
-               sprintf (call_target, "%s", cfg->asm_symbol);
-
-               arch_emit_unbox_trampoline (acfg, cfg->orig_method, cfg->generic_sharing_context, call_target);
-       }
-
        /* Make the labels local */
        sprintf (symbol, "%s", cfg->asm_symbol);
 
@@ -3233,29 +3268,49 @@ emit_exception_debug_info (MonoAotCompile *acfg, MonoCompile *cfg)
        }
 
        /* Exception table */
-       if (jinfo->num_clauses)
-               encode_value (jinfo->num_clauses, p, &p);
+       if (cfg->compile_llvm) {
+               /* The assembly might be CIL stripped so emit the data ourselves */
+               if (header->num_clauses)
+                       encode_value (header->num_clauses, p, &p);
 
-       for (k = 0; k < jinfo->num_clauses; ++k) {
-               MonoJitExceptionInfo *ei = &jinfo->clauses [k];
+               for (k = 0; k < header->num_clauses; ++k) {
+                       MonoExceptionClause *clause;
 
-               encode_value (ei->flags, p, &p);
-               encode_value (ei->exvar_offset, p, &p);
+                       clause = &header->clauses [k];
 
-               if (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER)
-                       encode_value ((gint)((guint8*)ei->data.filter - code), p, &p);
-               else {
-                       if (ei->data.catch_class) {
+                       encode_value (clause->flags, p, &p);
+                       if (clause->data.catch_class) {
                                encode_value (1, p, &p);
-                               encode_klass_ref (acfg, ei->data.catch_class, p, &p);
+                               encode_klass_ref (acfg, clause->data.catch_class, p, &p);
                        } else {
                                encode_value (0, p, &p);
                        }
                }
+       } else {
+               if (jinfo->num_clauses)
+                       encode_value (jinfo->num_clauses, p, &p);
 
-               encode_value ((gint)((guint8*)ei->try_start - code), p, &p);
-               encode_value ((gint)((guint8*)ei->try_end - code), p, &p);
-               encode_value ((gint)((guint8*)ei->handler_start - code), p, &p);
+               for (k = 0; k < jinfo->num_clauses; ++k) {
+                       MonoJitExceptionInfo *ei = &jinfo->clauses [k];
+
+                       encode_value (ei->flags, p, &p);
+                       encode_value (ei->exvar_offset, p, &p);
+
+                       if (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER)
+                               encode_value ((gint)((guint8*)ei->data.filter - code), p, &p);
+                       else {
+                               if (ei->data.catch_class) {
+                                       encode_value (1, p, &p);
+                                       encode_klass_ref (acfg, ei->data.catch_class, p, &p);
+                               } else {
+                                       encode_value (0, p, &p);
+                               }
+                       }
+
+                       encode_value ((gint)((guint8*)ei->try_start - code), p, &p);
+                       encode_value ((gint)((guint8*)ei->try_end - code), p, &p);
+                       encode_value ((gint)((guint8*)ei->handler_start - code), p, &p);
+               }
        }
 
        if (jinfo->has_generic_jit_info) {
@@ -3806,6 +3861,8 @@ mono_aot_parse_options (const char *aot_options, MonoAotOptions *opts)
                        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, "nimt-trampolines=")) {
+                       opts->nimt_trampolines = atoi (arg + strlen ("nimt-trampolines="));
                } else if (str_begins_with (arg, "autoreg")) {
                        opts->autoreg = TRUE;
                } else if (str_begins_with (arg, "tool-prefix=")) {
@@ -4242,7 +4299,7 @@ load_profile_files (MonoAotCompile *acfg)
 
        file_index = 0;
        while (TRUE) {
-               tmp = g_strdup_printf ("%s/.mono/aot-profile-data/%s-%s-%d", g_get_home_dir (), acfg->image->assembly_name, acfg->image->guid, file_index);
+               tmp = g_strdup_printf ("%s/.mono/aot-profile-data/%s-%d", g_get_home_dir (), acfg->image->assembly_name, file_index);
 
                if (!g_file_test (tmp, G_FILE_TEST_IS_REGULAR)) {
                        g_free (tmp);
@@ -4258,21 +4315,38 @@ load_profile_files (MonoAotCompile *acfg)
                file_index ++;
 
                res = fscanf (infile, "%32s\n", ver);
-               if ((res != 1) || strcmp (ver, "#VER:1") != 0) {
+               if ((res != 1) || strcmp (ver, "#VER:2") != 0) {
                        printf ("Profile file has wrong version or invalid.\n");
                        fclose (infile);
                        continue;
                }
 
                while (TRUE) {
-                       res = fscanf (infile, "%d\n", &token);
-                       if (res < 1)
+                       char name [1024];
+                       MonoMethodDesc *desc;
+                       MonoMethod *method;
+
+                       if (fgets (name, 1023, infile) == NULL)
                                break;
 
-                       method_index = mono_metadata_token_index (token) - 1;
+                       /* Kill the newline */
+                       if (strlen (name) > 0)
+                               name [strlen (name) - 1] = '\0';
+
+                       desc = mono_method_desc_new (name, TRUE);
 
-                       if (!g_list_find (acfg->method_order, GUINT_TO_POINTER (method_index)))
-                               acfg->method_order = g_list_append (acfg->method_order, GUINT_TO_POINTER (method_index));
+                       method = mono_method_desc_search_in_image (desc, acfg->image);
+
+                       if (method && mono_method_get_token (method)) {
+                               token = mono_method_get_token (method);
+                               method_index = mono_metadata_token_index (token) - 1;
+
+                               if (!g_list_find (acfg->method_order, GUINT_TO_POINTER (method_index))) {
+                                       acfg->method_order = g_list_append (acfg->method_order, GUINT_TO_POINTER (method_index));
+                               }
+                       } else {
+                               //printf ("No method found matching '%s'.\n", name);
+                       }
                }
                fclose (infile);
        }
@@ -4475,14 +4549,42 @@ emit_code (MonoAotCompile *acfg)
        emit_zero_bytes (acfg, 16);
 
        for (l = acfg->method_order; l != NULL; l = l->next) {
+               MonoCompile *cfg;
+               MonoMethod *method;
+
                i = GPOINTER_TO_UINT (l->data);
 
-               if (acfg->cfgs [i]) {
-                       if (acfg->cfgs [i]->compile_llvm)
-                               acfg->stats.llvm_count ++;
-                       else
-                               emit_method_code (acfg, acfg->cfgs [i]);
+               cfg = acfg->cfgs [i];
+
+               if (!cfg)
+                       continue;
+
+               method = cfg->orig_method;
+
+               /* Emit unbox trampoline */
+               if (acfg->aot_opts.full_aot && cfg->orig_method->klass->valuetype && (method->flags & METHOD_ATTRIBUTE_VIRTUAL)) {
+                       char call_target [256];
+
+                       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);
+                       emit_label (acfg, symbol);
+
+                       sprintf (call_target, "%s", cfg->asm_symbol);
+
+                       arch_emit_unbox_trampoline (acfg, cfg->orig_method, cfg->generic_sharing_context, call_target);
                }
+
+               if (cfg->compile_llvm)
+                       acfg->stats.llvm_count ++;
+               else
+                       emit_method_code (acfg, cfg);
        }
 
        sprintf (symbol, "methods_end");
@@ -4799,6 +4901,8 @@ emit_extra_methods (MonoAotCompile *acfg)
 
                nmethods ++;
 
+               method = cfg->method_to_register;
+
                name = NULL;
                if (method->wrapper_type) {
                        /* 
@@ -5804,6 +5908,7 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
        acfg->aot_opts.write_symbols = TRUE;
        acfg->aot_opts.ntrampolines = 1024;
        acfg->aot_opts.nrgctx_trampolines = 1024;
+       acfg->aot_opts.nimt_trampolines = 128;
 
        mono_aot_parse_options (aot_options, &acfg->aot_opts);
 
@@ -5849,7 +5954,7 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
 #ifdef MONO_ARCH_HAVE_STATIC_RGCTX_TRAMPOLINE
        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;
+       acfg->num_trampolines [MONO_AOT_TRAMP_IMT_THUNK] = acfg->aot_opts.full_aot ? acfg->aot_opts.nimt_trampolines : 0;
 
        acfg->got_symbol_base = g_strdup_printf ("mono_aot_%s_got", acfg->image->assembly->aname.name);
        acfg->plt_symbol = g_strdup_printf ("mono_aot_%s_plt", acfg->image->assembly->aname.name);
@@ -5994,7 +6099,7 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
        img_writer_emit_start (acfg->w);
 
        if (acfg->dwarf)
-               mono_dwarf_writer_emit_base_info (acfg->dwarf, mono_arch_get_cie_program ());
+               mono_dwarf_writer_emit_base_info (acfg->dwarf, mono_unwind_get_cie_program ());
 
        emit_code (acfg);