2010-02-10 Miguel de Icaza <miguel@novell.com>
[mono.git] / mono / mini / aot-compiler.c
index 0d620dccf296927e7367a0f3839a9cfaae7496d7..9cc38db78f93180a51df1e645d8aa31af3e63434 100644 (file)
@@ -161,10 +161,12 @@ typedef struct MonoAotCompile {
        GHashTable *unwind_info_offsets;
        GPtrArray *unwind_ops;
        guint32 unwind_info_offset;
+       char *got_symbol_base;
        char *got_symbol;
        char *plt_symbol;
        GHashTable *method_label_hash;
        const char *temp_prefix;
+       const char *llvm_label_prefix;
        guint32 label_generator;
        gboolean llvm;
        MonoAotFileFlags flags;
@@ -454,6 +456,23 @@ encode_sleb128 (gint32 value, guint8 *buf, guint8 **endbuf)
 #define PPC_LDX_OP "lwzx"
 #endif
 
+//#define TARGET_ARM
+
+#ifdef TARGET_ARM
+#define LLVM_LABEL_PREFIX "_"
+#else
+#define LLVM_LABEL_PREFIX ""
+#endif
+
+#ifdef TARGET_ARM
+/* iphone */
+#define LLC_TARGET_ARGS "-march=arm -mattr=+v6 -mtriple=arm-apple-darwin"
+/* ELF */
+//#define LLC_TARGET_ARGS "-march=arm -mtriple=arm-linux-gnueabi -soft-float"
+#else
+#define LLC_TARGET_ARGS ""
+#endif
+
 /*
  * arch_emit_direct_call:
  *
@@ -1599,7 +1618,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;
                }
@@ -1607,11 +1626,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:
@@ -1635,7 +1657,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);
@@ -1821,11 +1843,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] ++;
 
@@ -2221,6 +2244,69 @@ add_wrappers (MonoAotCompile *acfg)
                        add_method (acfg, mono_marshal_get_native_wrapper (method, TRUE, TRUE));
                }
        }
+       /* native-to-managed wrappers */
+       for (i = 0; i < acfg->image->tables [MONO_TABLE_METHOD].rows; ++i) {
+               MonoMethod *method;
+               guint32 token = MONO_TOKEN_METHOD_DEF | (i + 1);
+               MonoCustomAttrInfo *cattr;
+               int j;
+
+               method = mono_get_method (acfg->image, token, NULL);
+
+               /* 
+                * Only generate native-to-managed wrappers for methods which have an
+                * attribute named MonoPInvokeCallbackAttribute. We search for the attribute by
+                * name to avoid defining a new assembly to contain it.
+                */
+               cattr = mono_custom_attrs_from_method (method);
+
+               if (cattr) {
+                       for (j = 0; j < cattr->num_attrs; ++j)
+                               if (cattr->attrs [j].ctor && !strcmp (cattr->attrs [j].ctor->klass->name, "MonoPInvokeCallbackAttribute"))
+                                       break;
+                       if (j < cattr->num_attrs) {
+                               MonoCustomAttrEntry *e = &cattr->attrs [j];
+                               MonoMethodSignature *sig = mono_method_signature (e->ctor);
+                               const char *p = (const char*)e->data;
+                               int slen;
+                               char *n;
+                               MonoType *t;
+                               MonoClass *klass;
+
+                               g_assert (method->flags & METHOD_ATTRIBUTE_STATIC);
+
+                               g_assert (sig->param_count == 1);
+                               g_assert (sig->params [0]->type == MONO_TYPE_CLASS && !strcmp (mono_class_from_mono_type (sig->params [0])->name, "Type"));
+
+                               /* 
+                                * Decode the cattr manually since we can't create objects
+                                * during aot compilation.
+                                */
+                                       
+                               /* Skip prolog */
+                               p += 2;
+
+                               /* From load_cattr_value () in reflection.c */
+                               slen = mono_metadata_decode_value (p, &p);
+                               n = g_memdup (p, slen + 1);
+                               n [slen] = 0;
+                               t = mono_reflection_type_from_name (n, acfg->image);
+                               g_assert (t);
+                               g_free (n);
+
+                               klass = mono_class_from_mono_type (t);
+                               g_assert (klass->parent == mono_defaults.multicastdelegate_class);
+
+                               add_method (acfg, mono_marshal_get_managed_wrapper (method, klass, NULL));
+                       }
+               }
+
+               if ((method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) ||
+                       (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL)) {
+                       add_method (acfg, mono_marshal_get_native_wrapper (method, TRUE, TRUE));
+               }
+       }
 
        /* StructureToPtr/PtrToStructure wrappers */
        for (i = 0; i < acfg->image->tables [MONO_TABLE_TYPEDEF].rows; ++i) {
@@ -2627,7 +2713,7 @@ emit_and_reloc_code (MonoAotCompile *acfg, MonoMethod *method, guint8 *code, gui
                                                MonoCompile *callee_cfg = g_hash_table_lookup (acfg->method_to_cfg, patch_info->data.method);
                                                //printf ("DIRECT: %s %s\n", method ? mono_method_full_name (method, TRUE) : "", mono_method_full_name (callee_cfg->method, TRUE));
                                                direct_call = TRUE;
-                                               sprintf (direct_call_target, "%sm_%x", acfg->temp_prefix, get_method_index (acfg, callee_cfg->orig_method));
+                                               sprintf (direct_call_target, callee_cfg->asm_symbol);
                                                patch_info->type = MONO_PATCH_INFO_NONE;
                                                acfg->stats.direct_calls ++;
                                        }
@@ -2640,7 +2726,7 @@ emit_and_reloc_code (MonoAotCompile *acfg, MonoMethod *method, guint8 *code, gui
                                        if (plt_offset != -1) {
                                                /* This patch has a PLT entry, so we must emit a call to the PLT entry */
                                                direct_call = TRUE;
-                                               sprintf (direct_call_target, "%sp_%d", acfg->temp_prefix, plt_offset);
+                                               sprintf (direct_call_target, "%s%sp_%d", acfg->llvm_label_prefix, acfg->temp_prefix, plt_offset);
                
                                                /* Nullify the patch */
                                                patch_info->type = MONO_PATCH_INFO_NONE;
@@ -2757,28 +2843,8 @@ 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, "%sm_%x", acfg->temp_prefix, method_index);
-
-               arch_emit_unbox_trampoline (acfg, cfg->orig_method, cfg->generic_sharing_context, call_target);
-       }
-
        /* Make the labels local */
-       sprintf (symbol, "%sm_%x", acfg->temp_prefix, method_index);
+       sprintf (symbol, "%s", cfg->asm_symbol);
 
        emit_section_change (acfg, ".text", 0);
        emit_alignment (acfg, func_alignment);
@@ -3334,7 +3400,7 @@ emit_plt (MonoAotCompile *acfg)
                char *debug_sym = NULL;
                MonoJumpInfo *ji;
 
-               sprintf (label, "%sp_%d", acfg->temp_prefix, i);
+               sprintf (label, "%s%sp_%d", acfg->llvm_label_prefix, acfg->temp_prefix, i);
 
                if (acfg->llvm) {
                        /*
@@ -3347,7 +3413,7 @@ emit_plt (MonoAotCompile *acfg)
                        ji = g_hash_table_lookup (acfg->plt_offset_to_patch, GUINT_TO_POINTER (i));
                        if (ji && is_direct_callable (acfg, NULL, ji) && !acfg->use_bin_writer) {
                                MonoCompile *callee_cfg = g_hash_table_lookup (acfg->method_to_cfg, ji->data.method);
-                               fprintf (acfg->fp, "\n.set %s, .Lm_%x\n", label, get_method_index (acfg, callee_cfg->orig_method));
+                               fprintf (acfg->fp, "\n.set %s, %s\n", label, callee_cfg->asm_symbol);
                                continue;
                        }
                }
@@ -3504,7 +3570,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
                /*
@@ -3788,6 +3854,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"))
@@ -4215,7 +4282,6 @@ mono_aot_get_method_name (MonoCompile *cfg)
 {
        guint32 method_index = get_method_index (llvm_acfg, cfg->orig_method);
 
-       /* LLVM converts these to .Lm_%x */
        return g_strdup_printf ("m_%x", method_index);
 }
 
@@ -4239,7 +4305,7 @@ mono_aot_get_plt_symbol (MonoJumpInfoType type, gconstpointer data)
 
        offset = get_plt_offset (llvm_acfg, ji);
 
-       return g_strdup_printf (".Lp_%d", offset);
+       return g_strdup_printf ("%sp_%d", llvm_acfg->temp_prefix, offset);
 }
 
 MonoJumpInfo*
@@ -4268,6 +4334,7 @@ emit_llvm_file (MonoAotCompile *acfg)
        char *command, *opts;
        int i;
        MonoJumpInfo *patch_info;
+       char *llc_target_args;
 
        /*
         * When using LLVM, we let llvm emit the got since the LLVM IL needs to refer
@@ -4287,8 +4354,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);
 
        /*
@@ -4296,8 +4381,12 @@ emit_llvm_file (MonoAotCompile *acfg)
         * a lot of time, and doesn't seem to save much space.
         * The following optimizations cannot be enabled:
         * - 'tailcallelim'
+        * The opt list below was produced by taking the output of:
+        * llvm-as < /dev/null | opt -O2 -disable-output -debug-pass=Arguments
+        * then removing tailcallelim + the global opts, and adding a second gvn.
         */
        opts = g_strdup ("-instcombine -simplifycfg");
+       opts = g_strdup ("-simplifycfg -domtree -domfrontier -scalarrepl -instcombine -simplifycfg -basiccg -prune-eh -inline -functionattrs -domtree -domfrontier -scalarrepl -simplify-libcalls -instcombine -jump-threading -simplifycfg -instcombine -simplifycfg -reassociate -domtree -loops -loopsimplify -domfrontier -loopsimplify -lcssa -loop-rotate -licm -lcssa -loop-unswitch -instcombine -scalar-evolution -loopsimplify -lcssa -iv-users -indvars -loop-deletion -loopsimplify -lcssa -loop-unroll -instcombine -memdep -gvn -memdep -memcpyopt -sccp -instcombine -jump-threading -domtree -memdep -dse -adce -gvn -simplifycfg -preverify -domtree -verify");
 #if 1
        command = g_strdup_printf ("opt -f %s -o temp.opt.bc temp.bc", opts);
        printf ("Executing opt: %s\n", command);
@@ -4307,8 +4396,11 @@ emit_llvm_file (MonoAotCompile *acfg)
 #endif
        g_free (opts);
 
-       //command = g_strdup_printf ("llc -march=arm -mtriple=arm-linux-gnueabi -f -relocation-model=pic -unwind-tables temp.bc");
-       command = g_strdup_printf ("llc -f -relocation-model=pic -unwind-tables -o temp.s temp.opt.bc");
+       llc_target_args = g_strdup (LLC_TARGET_ARGS);
+
+       command = g_strdup_printf ("llc %s -f -relocation-model=pic -unwind-tables -o %s temp.opt.bc", llc_target_args, acfg->tmpfname);
+       g_free (llc_target_args);
+
        printf ("Executing llc: %s\n", command);
 
        if (system (command) != 0) {
@@ -4322,6 +4414,7 @@ emit_code (MonoAotCompile *acfg)
 {
        int i;
        char symbol [256];
+       char end_symbol [256];
        GList *l;
 
 #if defined(TARGET_POWERPC64)
@@ -4332,11 +4425,26 @@ emit_code (MonoAotCompile *acfg)
        emit_pointer (acfg, acfg->got_symbol);
 #endif
 
-       if (!acfg->llvm) {
-               sprintf (symbol, "methods");
-               emit_section_change (acfg, ".text", 0);
-               emit_global (acfg, symbol, TRUE);
-               emit_alignment (acfg, 8);
+       /* 
+        * This global symbol is used to compute the address of each method using the
+        * code_offsets array. It is also used to compute the memory ranges occupied by
+        * AOT code, so it must be equal to the address of the first emitted method.
+        */
+       sprintf (symbol, "methods");
+       emit_section_change (acfg, ".text", 0);
+       emit_global (acfg, symbol, TRUE);
+       emit_alignment (acfg, 8);
+       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);
+                               break;
+                       }
+               }
+               if (i == acfg->nmethods)
+                       /* No LLVM compiled methods */
+                       emit_label (acfg, symbol);
+       } else {
                emit_label (acfg, symbol);
        }
 
@@ -4347,14 +4455,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");
@@ -4371,10 +4507,10 @@ emit_code (MonoAotCompile *acfg)
 
        acfg->stats.offsets_size += acfg->nmethods * 4;
 
+       sprintf (end_symbol, "methods");
        for (i = 0; i < acfg->nmethods; ++i) {
                if (acfg->cfgs [i]) {
-                       sprintf (symbol, "%sm_%x", acfg->temp_prefix, i);
-                       emit_symbol_diff (acfg, symbol, "methods", 0);
+                       emit_symbol_diff (acfg, acfg->cfgs [i]->asm_symbol, end_symbol, 0);
                } else {
                        emit_int32 (acfg, 0xffffffff);
                }
@@ -5343,7 +5479,7 @@ emit_dwarf_info (MonoAotCompile *acfg)
                if (cfg->compile_llvm)
                        continue;
 
-               sprintf (symbol, "%sm_%x", acfg->temp_prefix, i);
+               sprintf (symbol, "%s", cfg->asm_symbol);
                sprintf (symbol2, "%sme_%x", acfg->temp_prefix, i);
 
                mono_dwarf_writer_emit_method (acfg->dwarf, cfg, cfg->method, symbol, symbol2, 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 ()));
@@ -5662,7 +5798,7 @@ int
 mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
 {
        MonoImage *image = ass->image;
-       int res;
+       int i, res;
        MonoAotCompile *acfg;
        char *outfile_name, *tmp_outfile_name, *p;
        TV_DECLARE (atv);
@@ -5723,11 +5859,11 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
 #endif
        acfg->num_trampolines [MONO_AOT_TRAMP_IMT_THUNK] = acfg->aot_opts.full_aot ? 128 : 0;
 
-       acfg->got_symbol = g_strdup_printf ("mono_aot_%s_got", acfg->image->assembly->aname.name);
+       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);
 
        /* Get rid of characters which cannot occur in symbols */
-       for (p = acfg->got_symbol; *p; ++p) {
+       for (p = acfg->got_symbol_base; *p; ++p) {
                if (!(isalnum (*p) || *p == '_'))
                        *p = '_';
        }
@@ -5736,6 +5872,8 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
                        *p = '_';
        }
 
+       acfg->temp_prefix = img_writer_get_temp_label_prefix (NULL);
+
        acfg->method_index = 1;
 
        collect_methods (acfg);
@@ -5748,7 +5886,7 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
 
 #ifdef ENABLE_LLVM
        llvm_acfg = acfg;
-       mono_llvm_create_aot_module (acfg->got_symbol);
+       mono_llvm_create_aot_module (acfg->got_symbol_base);
 #endif
 
        /* GOT offset 0 is reserved for the address of the current assembly */
@@ -5778,6 +5916,17 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
        TV_GETTIME (atv);
 
 #ifdef ENABLE_LLVM
+       if (acfg->llvm) {
+               if (acfg->aot_opts.asm_only) {
+                       if (acfg->aot_opts.outfile)
+                               acfg->tmpfname = g_strdup_printf ("%s", acfg->aot_opts.outfile);
+                       else
+                               acfg->tmpfname = g_strdup_printf ("%s.s", acfg->image->name);
+               } else {
+                       acfg->tmpfname = g_strdup ("temp.s");
+               }
+       }
+
        emit_llvm_file (acfg);
 #endif
 
@@ -5805,8 +5954,7 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
                if (acfg->llvm) {
                        /* Append to the .s file created by llvm */
                        /* FIXME: Use multiple files instead */
-                       acfg->tmpfname = g_strdup ("temp.s");
-                       acfg->fp = fopen (acfg->tmpfname, "a");
+                       acfg->fp = fopen (acfg->tmpfname, "a+");
                } else {
                        if (acfg->aot_opts.asm_only) {
                                if (acfg->aot_opts.outfile)
@@ -5826,7 +5974,27 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
                outfile_name = NULL;
        }
 
-       acfg->temp_prefix = img_writer_get_temp_label_prefix (acfg->w);
+       /*
+        * The prefix LLVM likes to put in front of symbol names on darwin.
+        * The mach-os specs require this for globals, but LLVM puts them in front of all
+        * symbols. We need to handle this, since we need to refer to LLVM generated
+        * symbols.
+        */
+       acfg->llvm_label_prefix = "";
+       if (acfg->llvm)
+               acfg->llvm_label_prefix = LLVM_LABEL_PREFIX;
+
+       acfg->got_symbol = g_strdup_printf ("%s%s", acfg->llvm_label_prefix, acfg->got_symbol_base);
+
+       /* Compute symbols for methods */
+       for (i = 0; i < acfg->nmethods; ++i) {
+               if (acfg->cfgs [i]) {
+                       MonoCompile *cfg = acfg->cfgs [i];
+                       int method_index = get_method_index (acfg, cfg->orig_method);
+
+                       cfg->asm_symbol = g_strdup_printf ("%s%sm_%x", acfg->temp_prefix, LLVM_LABEL_PREFIX, method_index);
+               }
+       }
 
        if (!acfg->aot_opts.nodebug)
                acfg->dwarf = mono_dwarf_writer_create (acfg->w, NULL, 0, FALSE);
@@ -5880,7 +6048,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);