2010-03-30 Rodrigo Kumpera <rkumpera@novell.com>
[mono.git] / mono / mini / aot-compiler.c
index 6431b0140e1cc01b3630cce929b03b53c340de02..28944ce9843305c2fd6364bf1d4efc01ed15c378 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
@@ -1618,7 +1593,7 @@ encode_method_ref (MonoAotCompile *acfg, MonoMethod *method, guint8 *buf, guint8
                case MONO_WRAPPER_LDFLDA:
                case MONO_WRAPPER_STFLD:
                case MONO_WRAPPER_ISINST: {
-                       MonoClass *proxy_class = mono_marshal_wrapper_info_from_wrapper (method);
+                       MonoClass *proxy_class = mono_marshal_get_wrapper_info (method);
                        encode_klass_ref (acfg, proxy_class, p, &p);
                        break;
                }
@@ -1626,11 +1601,14 @@ encode_method_ref (MonoAotCompile *acfg, MonoMethod *method, guint8 *buf, guint8
                case MONO_WRAPPER_STFLD_REMOTE:
                        break;
                case MONO_WRAPPER_ALLOC: {
-                       int alloc_type = mono_gc_get_managed_allocator_type (method);
-                       g_assert (alloc_type != -1);
-                       encode_value (alloc_type, p, &p);
+                       AllocatorWrapperInfo *info = mono_marshal_get_wrapper_info (method);
+
+                       g_assert (info->alloc_type != -1);
+                       encode_value (info->alloc_type, p, &p);
                        break;
                }
+               case MONO_WRAPPER_WRITE_BARRIER:
+                       break;
                case MONO_WRAPPER_STELEMREF:
                        break;
                case MONO_WRAPPER_UNKNOWN:
@@ -1654,7 +1632,7 @@ encode_method_ref (MonoAotCompile *acfg, MonoMethod *method, guint8 *buf, guint8
                }
                case MONO_WRAPPER_MANAGED_TO_MANAGED:
                        if (!strcmp (method->name, "ElementAddr")) {
-                               ElementAddrWrapperInfo *info = mono_marshal_wrapper_info_from_wrapper (method);
+                               ElementAddrWrapperInfo *info = mono_marshal_get_wrapper_info (method);
 
                                g_assert (info);
                                encode_value (MONO_AOT_WRAPPER_ELEMENT_ADDR, p, &p);
@@ -1840,11 +1818,12 @@ get_got_offset (MonoAotCompile *acfg, MonoJumpInfo *ji)
        if (got_offset)
                return got_offset - 1;
 
-       g_assert (!acfg->final_got_size);
-
        got_offset = acfg->got_offset;
        acfg->got_offset ++;
 
+       if (acfg->final_got_size)
+               g_assert (got_offset < acfg->final_got_size);
+
        acfg->stats.got_slots ++;
        acfg->stats.got_slot_types [ji->type] ++;
 
@@ -2381,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;
 
@@ -2502,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);
        }
 
@@ -2839,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);
 
@@ -3229,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);
+
+               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);
 
-               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 (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER || ei->flags == MONO_EXCEPTION_CLAUSE_FINALLY)
+                               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) {
@@ -3586,7 +3645,7 @@ emit_trampolines (MonoAotCompile *acfg)
        
        g_assert (acfg->image->assembly);
 
-       /* Currently, we only emit most trampolines into the mscorlib AOT image. */
+       /* Currently, we emit most trampolines into the mscorlib AOT image. */
        if (strcmp (acfg->image->assembly->aname.name, "mscorlib") == 0) {
 #ifdef MONO_ARCH_HAVE_FULL_AOT_TRAMPOLINES
                /*
@@ -3802,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=")) {
@@ -3870,6 +3931,7 @@ can_encode_patch (MonoAotCompile *acfg, MonoJumpInfo *patch_info)
                        case MONO_WRAPPER_ALLOC:
                        case MONO_WRAPPER_REMOTING_INVOKE:
                        case MONO_WRAPPER_UNKNOWN:
+                       case MONO_WRAPPER_WRITE_BARRIER:
                                break;
                        case MONO_WRAPPER_MANAGED_TO_MANAGED:
                                if (!strcmp (method->name, "ElementAddr"))
@@ -4237,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);
@@ -4253,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);
        }
@@ -4369,8 +4448,26 @@ emit_llvm_file (MonoAotCompile *acfg)
                        }
                }
        }
+
        acfg->final_got_size = acfg->got_offset + acfg->plt_offset;
 
+       if (acfg->aot_opts.full_aot) {
+               int ntype;
+
+               /* 
+                * Need to add the got entries used by the trampolines.
+                * This is only a conservative approximation.
+                */
+               if (strcmp (acfg->image->assembly->aname.name, "mscorlib") == 0) {
+                       /* For the generic + rgctx trampolines */
+                       acfg->final_got_size += 200;
+                       /* For the specific trampolines */
+                       for (ntype = 0; ntype < MONO_AOT_TRAMP_NUM; ++ntype)
+                               acfg->final_got_size += acfg->num_trampolines [ntype] * 2;
+               }
+       }
+
+
        mono_llvm_emit_aot_module ("temp.bc", acfg->final_got_size);
 
        /*
@@ -4434,7 +4531,7 @@ emit_code (MonoAotCompile *acfg)
        if (acfg->llvm) {
                for (i = 0; i < acfg->nmethods; ++i) {
                        if (acfg->cfgs [i] && acfg->cfgs [i]->compile_llvm) {
-                               fprintf (acfg->fp, "\n.set methods, %s\n", acfg->cfgs [i]->asm_symbol); 
+                               fprintf (acfg->fp, "\n.set methods, %s\n", acfg->cfgs [i]->asm_symbol);
                                break;
                        }
                }
@@ -4452,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");
@@ -4476,7 +4601,7 @@ emit_code (MonoAotCompile *acfg)
 
        acfg->stats.offsets_size += acfg->nmethods * 4;
 
-       sprintf (end_symbol, "%smethods", acfg->llvm_label_prefix);
+       sprintf (end_symbol, "methods");
        for (i = 0; i < acfg->nmethods; ++i) {
                if (acfg->cfgs [i]) {
                        emit_symbol_diff (acfg, acfg->cfgs [i]->asm_symbol, end_symbol, 0);
@@ -4776,6 +4901,8 @@ emit_extra_methods (MonoAotCompile *acfg)
 
                nmethods ++;
 
+               method = cfg->method_to_register;
+
                name = NULL;
                if (method->wrapper_type) {
                        /* 
@@ -5781,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);
 
@@ -5826,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);
@@ -5971,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);
 
@@ -6017,7 +6145,7 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
        acfg->stats.gen_time = TV_ELAPSED (atv, btv);
 
        if (acfg->llvm)
-               g_assert (acfg->got_offset == acfg->final_got_size);
+               g_assert (acfg->got_offset <= acfg->final_got_size);
 
        printf ("Code: %d Info: %d Ex Info: %d Unwind Info: %d Class Info: %d PLT: %d GOT Info: %d GOT: %d Offsets: %d\n", acfg->stats.code_size, acfg->stats.info_size, acfg->stats.ex_info_size, acfg->stats.unwind_info_size, acfg->stats.class_info_size, acfg->plt_offset, acfg->stats.got_info_size, (int)(acfg->got_offset * sizeof (gpointer)), acfg->stats.offsets_size);