2009-05-14 Zoltan Varga <vargaz@gmail.com>
[mono.git] / mono / mini / aot-compiler.c
index 181b2e045816a532a38707ca7930c50914374a95..d3918ad382477675cdf3dd84a7fcc5c9137a7277 100644 (file)
@@ -62,6 +62,7 @@
 #include <mono/utils/mono-logger.h>
 #include <mono/utils/mono-compiler.h>
 #include <mono/utils/mono-time.h>
+#include <mono/utils/mono-mmap.h>
 
 #include "mini.h"
 #include "image-writer.h"
@@ -132,13 +133,11 @@ typedef struct MonoAotCompile {
        guint32 got_offset, plt_offset, plt_got_offset_base;
        /* Number of GOT entries reserved for trampolines */
        guint32 num_trampoline_got_entries;
-       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;
+
+       guint32 num_trampolines [MONO_AOT_TRAMP_NUM];
+       guint32 trampoline_got_offset_base [MONO_AOT_TRAMP_NUM];
+       guint32 trampoline_size [MONO_AOT_TRAMP_NUM];
+
        MonoAotOptions aot_opts;
        guint32 nmethods;
        guint32 opts;
@@ -451,6 +450,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:
  *
@@ -478,6 +495,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:
  *
@@ -710,6 +729,119 @@ arch_emit_static_rgctx_trampoline (MonoAotCompile *acfg, int offset, int *tramp_
 #endif
 }      
 
+/*
+ * arch_emit_imt_thunk:
+ *
+ *   Emit an IMT thunk usable in full-aot mode. The thunk uses 1 got slot which
+ * points to an array of pointer pairs. The pairs of the form [key, ptr], where
+ * key is the IMT key, and ptr holds the address of a memory location holding
+ * the address to branch to if the IMT arg matches the key. The array is 
+ * terminated by a pair whose key is NULL, and whose ptr is the address of the 
+ * fail_tramp.
+ * TRAMP_SIZE is set to the size of the emitted trampoline.
+ */
+static void
+arch_emit_imt_thunk (MonoAotCompile *acfg, int offset, int *tramp_size)
+{
+#if defined(TARGET_AMD64)
+       guint8 *buf, *code;
+       guint8 *labels [3];
+
+       code = buf = g_malloc (256);
+
+       /* FIXME: Optimize this, i.e. use binary search etc. */
+       /* Maybe move the body into a separate function (slower, but much smaller) */
+
+       /* R10 is a free register */
+
+       labels [0] = code;
+       amd64_alu_membase_imm (code, X86_CMP, AMD64_R10, 0, 0);
+       labels [1] = code;
+       amd64_branch8 (code, X86_CC_Z, FALSE, 0);
+
+       /* Check key */
+       amd64_alu_membase_reg (code, X86_CMP, AMD64_R10, 0, MONO_ARCH_IMT_REG);
+       labels [2] = code;
+       amd64_branch8 (code, X86_CC_Z, FALSE, 0);
+
+       /* Loop footer */
+       amd64_alu_reg_imm (code, X86_ADD, AMD64_R10, 2 * sizeof (gpointer));
+       amd64_jump_code (code, labels [0]);
+
+       /* Match */
+       mono_amd64_patch (labels [2], code);
+       amd64_mov_reg_membase (code, AMD64_R10, AMD64_R10, sizeof (gpointer), 8);
+       amd64_jump_membase (code, AMD64_R10, 0);
+
+       /* No match */
+       /* FIXME: */
+       mono_amd64_patch (labels [1], code);
+       x86_breakpoint (code);
+
+       /* mov <OFFSET>(%rip), %r10 */
+       emit_byte (acfg, '\x4d');
+       emit_byte (acfg, '\x8b');
+       emit_byte (acfg, '\x15');
+       emit_symbol_diff (acfg, "got", ".", (offset * sizeof (gpointer)) - 4);
+
+       emit_bytes (acfg, buf, code - buf);
+       
+       *tramp_size = code - buf + 7;
+#elif defined(TARGET_ARM)
+       guint8 buf [128];
+       guint8 *code, *code2, *labels [16];
+
+       code = buf;
+
+       /* The IMT method is in v5 */
+
+       /* Only IP is available, but we need at least two free registers */
+       ARM_PUSH1 (code, ARMREG_R1);
+       labels [0] = code;
+       /* Load the parameter from the GOT */
+       ARM_LDR_IMM (code, ARMREG_IP, ARMREG_PC, 0);
+       ARM_LDR_REG_REG (code, ARMREG_IP, ARMREG_PC, ARMREG_IP);
+
+       labels [1] = code;
+       ARM_LDR_IMM (code, ARMREG_R1, ARMREG_IP, 0);
+       ARM_CMP_REG_REG (code, ARMREG_R1, ARMREG_V5);
+       labels [2] = code;
+       ARM_B_COND (code, ARMCOND_EQ, 0);
+
+       /* End-of-loop check */
+       ARM_CMP_REG_IMM (code, ARMREG_R1, 0, 0);
+       labels [3] = code;
+       ARM_B_COND (code, ARMCOND_EQ, 0);
+
+       /* Loop footer */
+       ARM_ADD_REG_IMM8 (code, ARMREG_IP, ARMREG_IP, sizeof (gpointer) * 2);
+       labels [4] = code;
+       ARM_B (code, 0);
+       arm_patch (labels [4], labels [1]);
+
+       /* Match */
+       arm_patch (labels [2], code);
+       ARM_POP1 (code, ARMREG_R1);
+       ARM_LDR_IMM (code, ARMREG_IP, ARMREG_IP, 4);
+       ARM_LDR_IMM (code, ARMREG_PC, ARMREG_IP, 0);
+
+       /* No match */
+       arm_patch (labels [3], code);
+       ARM_DBRK (code);
+
+       /* Fixup offset */
+       code2 = labels [0];
+       ARM_LDR_IMM (code2, ARMREG_IP, ARMREG_PC, (code - (labels [0] + 8)));
+
+       emit_bytes (acfg, buf, code - buf);
+       emit_symbol_diff (acfg, "got", ".", (offset * sizeof (gpointer)) + (code - (labels [0] + 8)) - 4);
+
+       *tramp_size = code - buf + 4;
+#else
+       g_assert_not_reached ();
+#endif
+}
+
 /*
  * arch_get_cie_program:
  *
@@ -1162,40 +1294,6 @@ is_plt_patch (MonoJumpInfo *patch_info)
        }
 }
 
-/*
- * is_shared_got_patch:
- *
- *   Return whenever PATCH_INFO refers to a patch which needs a shared GOT
- * entry.
- */
-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;
-       }
-}
-
-gboolean
-mono_aot_is_shared_got_patch (MonoJumpInfo *patch_info)
-{
-       return is_shared_got_patch (patch_info);
-}
-
 static int
 get_plt_offset (MonoAotCompile *acfg, MonoJumpInfo *patch_info)
 {
@@ -1502,8 +1600,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);
@@ -1802,11 +1899,10 @@ 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;
                        }
@@ -1912,14 +2008,29 @@ emit_method_code (MonoAotCompile *acfg, MonoCompile *cfg)
        emit_alignment (acfg, func_alignment);
        emit_label (acfg, symbol);
 
-       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);
+       if (acfg->aot_opts.write_symbols && !acfg->aot_opts.nodebug) {
+               char *name1, *name2;
+               int i, j, len;
+
+               name1 = mono_method_full_name (method, TRUE);
+               len = strlen (name1);
+               name2 = malloc (len + 1);
+               j = 0;
+               for (i = 0; i < len; ++i) {
+                       if (isalnum (name1 [i])) {
+                               name2 [j ++] = name1 [i];
+                       } else if (name1 [i] == ' ' && name1 [i + 1] == '(' && name1 [i + 2] == ')') {
+                               i += 2;
+                       } else if (name1 [i] == '(' || name1 [i] == ')') {
+                       } else
+                               name2 [j ++] = '_';
+               }
+               name2 [j] = '\0';
                sprintf (symbol, ".Lme_%x", method_index);
-               emit_local_symbol (acfg, full_name, symbol, TRUE);
-               emit_label (acfg, full_name);
-               g_free (full_name);
+               emit_local_symbol (acfg, name2, symbol, TRUE);
+               emit_label (acfg, name2);
+               g_free (name1);
+               g_free (name2);
        }
 
        if (cfg->verbose_level > 0)
@@ -2076,7 +2187,7 @@ encode_patch_list (MonoAotCompile *acfg, GPtrArray *patches, int n_patches, int
                        continue;
 
                encode_value (patch_info->type, p, &p);
-               if (is_shared_got_patch (patch_info)) {
+               if (mono_aot_is_shared_got_patch (patch_info)) {
                        guint32 offset = get_got_offset (acfg, patch_info);
                        encode_value (offset, p, &p);
                } else {
@@ -2508,21 +2619,12 @@ emit_trampoline (MonoAotCompile *acfg, const char *name, guint8 *code,
        }
 }
 
-/*
- * When running in aot-only mode, we can't create trampolines at runtime, so we create 
- * a few, and save them in the AOT file. Normal trampolines embed their argument as a 
- * literal inside the trampoline code, we can't do that here, so instead we embed an offset
- * which needs to be added to the trampoline address to get the address of the GOT slot
- * which contains the argument value.
- * The generated trampolines jump to the generic trampolines using another GOT slot, which
- * will be setup by the AOT loader to point to the generic trampoline code of the given 
- * type.
- */
 static void
 emit_trampolines (MonoAotCompile *acfg)
 {
        char symbol [256];
        int i, tramp_got_offset;
+       MonoAotTrampoline ntype;
 #ifdef MONO_ARCH_HAVE_FULL_AOT_TRAMPOLINES
        int tramp_type;
        guint32 code_size;
@@ -2620,57 +2722,90 @@ emit_trampolines (MonoAotCompile *acfg)
 
 #endif /* #ifdef MONO_ARCH_HAVE_FULL_AOT_TRAMPOLINES */
 
+               /* Emit trampolines which are numerous */
+
                /*
-                * FIXME: Maybe we should use more specific trampolines (i.e. one class init for
-                * each class).
+                * These include the following:
+                * - specific trampolines
+                * - static rgctx invoke trampolines
+                * - imt thunks
+                * These trampolines have the same code, they are parameterized by GOT 
+                * slots. 
+                * They are defined in this file, in the arch_... routines instead of
+                * in tramp-<ARCH>.c, since it is easier to do it this way.
                 */
 
-               /* Reserve some entries at the end of the GOT for our use */
-               acfg->num_trampoline_got_entries = (acfg->num_specific_trampolines * 2) + (acfg->num_static_rgctx_trampolines * 2);
+               /*
+                * When running in aot-only mode, we can't create specific trampolines at 
+                * runtime, so we create a few, and save them in the AOT file. 
+                * Normal trampolines embed their argument as a literal inside the 
+                * trampoline code, we can't do that here, so instead we embed an offset
+                * which needs to be added to the trampoline address to get the address of
+                * the GOT slot which contains the argument value.
+                * The generated trampolines jump to the generic trampolines using another
+                * GOT slot, which will be setup by the AOT loader to point to the 
+                * generic trampoline code of the given type.
+                */
 
-               sprintf (symbol, "specific_trampolines");
+               /*
+                * FIXME: Maybe we should use more specific trampolines (i.e. one class init for
+                * each class).
+                */
 
                emit_section_change (acfg, ".text", 0);
-               emit_global (acfg, symbol, TRUE);
-               emit_alignment (acfg, 16);
-               emit_label (acfg, symbol);
 
                tramp_got_offset = acfg->got_offset;
 
-               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, tramp_got_offset, &tramp_size);
-                       if (!acfg->specific_trampoline_size) {
-                               g_assert (tramp_size);
-                               acfg->specific_trampoline_size = tramp_size;
+               for (ntype = 0; ntype < MONO_AOT_TRAMP_NUM; ++ntype) {
+                       switch (ntype) {
+                       case MONO_AOT_TRAMP_SPECIFIC:
+                               sprintf (symbol, "specific_trampolines");
+                               break;
+                       case MONO_AOT_TRAMP_STATIC_RGCTX:
+                               sprintf (symbol, "static_rgctx_trampolines");
+                               break;
+                       case MONO_AOT_TRAMP_IMT_THUNK:
+                               sprintf (symbol, "imt_thunks");
+                               break;
+                       default:
+                               g_assert_not_reached ();
                        }
 
-                       tramp_got_offset += 2;
-               }
+                       emit_global (acfg, symbol, TRUE);
+                       emit_alignment (acfg, 16);
+                       emit_label (acfg, symbol);
 
-               sprintf (symbol, "static_rgctx_trampolines");
+                       acfg->trampoline_got_offset_base [ntype] = tramp_got_offset;
 
-               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_trampolines [ntype]; ++i) {
+                               int tramp_size = 0;
 
-               for (i = 0; i < acfg->num_static_rgctx_trampolines; ++i) {
-                       int tramp_size = 0;
+                               switch (ntype) {
+                               case MONO_AOT_TRAMP_SPECIFIC:
+                                       arch_emit_specific_trampoline (acfg, tramp_got_offset, &tramp_size);
+                                       tramp_got_offset += 2;
+                               break;
+                               case MONO_AOT_TRAMP_STATIC_RGCTX:
+                                       arch_emit_static_rgctx_trampoline (acfg, tramp_got_offset, &tramp_size);                                
+                                       tramp_got_offset += 2;
+                                       break;
+                               case MONO_AOT_TRAMP_IMT_THUNK:
+                                       arch_emit_imt_thunk (acfg, tramp_got_offset, &tramp_size);
+                                       tramp_got_offset += 1;
+                                       break;
+                               default:
+                                       g_assert_not_reached ();
+                               }
 
-                       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;
+                               if (!acfg->trampoline_size [ntype]) {
+                                       g_assert (tramp_size);
+                                       acfg->trampoline_size [ntype] = tramp_size;
+                               }
                        }
-
-                       tramp_got_offset += 2;
                }
+
+               /* Reserve some entries at the end of the GOT for our use */
+               acfg->num_trampoline_got_entries = tramp_got_offset - acfg->got_offset;
        }
 
        /* Unbox trampolines */
@@ -2898,9 +3033,6 @@ compile_method (MonoAotCompile *acfg, MonoMethod *method)
 
        //acfg->aot_opts.print_skipped_methods = TRUE;
 
-       if (acfg->aot_opts.full_aot)
-               mono_use_imt = FALSE;
-
        /*
         * Since these methods are the only ones which are compiled with
         * AOT support, and they are not used by runtime startup/shutdown code,
@@ -3223,7 +3355,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);
                        }
                }
@@ -3344,6 +3476,25 @@ mono_aot_str_hash (gconstpointer v1)
        return hash;
 } 
 
+#define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
+#define mix(a,b,c) { \
+       a -= c;  a ^= rot(c, 4);  c += b; \
+       b -= a;  b ^= rot(a, 6);  a += c; \
+       c -= b;  c ^= rot(b, 8);  b += a; \
+       a -= c;  a ^= rot(c,16);  c += b; \
+       b -= a;  b ^= rot(a,19);  a += c; \
+       c -= b;  c ^= rot(b, 4);  b += a; \
+}
+#define final(a,b,c) { \
+       c ^= b; c -= rot(b,14); \
+       a ^= c; a -= rot(c,11); \
+       b ^= a; b -= rot(a,25); \
+       c ^= b; c -= rot(b,16); \
+       a ^= c; a -= rot(c,4);  \
+       b ^= a; b -= rot(a,14); \
+       c ^= b; c -= rot(b,24); \
+}
+
 /*
  * mono_aot_method_hash:
  *
@@ -3352,19 +3503,78 @@ mono_aot_str_hash (gconstpointer v1)
 guint32
 mono_aot_method_hash (MonoMethod *method)
 {
-       guint32 hash;
+       MonoMethodSignature *sig;
+       MonoClass *klass;
+       int i;
+       int hashes_count;
+       guint32 *hashes_start, *hashes;
+       guint32 a, b, c;
 
-       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);
+       /* Similar to the hash in mono_method_get_imt_slot () */
+
+       sig = mono_method_signature (method);
+
+       hashes_count = sig->param_count + 5;
+       hashes_start = malloc (hashes_count * sizeof (guint32));
+       hashes = hashes_start;
+
+       /* Some wrappers are assigned to random classes */
+       if (!method->wrapper_type || method->wrapper_type == MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK)
+               klass = method->klass;
+       else
+               klass = mono_defaults.object_class;
+
+       if (!method->wrapper_type) {
+               char *full_name = mono_type_full_name (&klass->byval_arg);
+
+               hashes [0] = mono_aot_str_hash (full_name);
+               hashes [1] = 0;
                g_free (full_name);
+       } else {
+               hashes [0] = mono_aot_str_hash (klass->name);
+               hashes [1] = mono_aot_str_hash (klass->name_space);
+       }
+       hashes [2] = mono_aot_str_hash (method->name);
+       hashes [3] = method->wrapper_type;
+       hashes [4] = mono_metadata_type_hash (sig->ret);
+       for (i = 0; i < sig->param_count; i++) {
+               /* This is needed for some reason */
+               if (method->wrapper_type && sig->params [i]->type == MONO_TYPE_GENERICINST)
+                       hashes [5 + i] = MONO_TYPE_GENERICINST;
+               else
+                       hashes [5 + i] = mono_metadata_type_hash (sig->params [i]);
+       }
+       
+       /* Setup internal state */
+       a = b = c = 0xdeadbeef + (((guint32)hashes_count)<<2);
+
+       /* Handle most of the hashes */
+       while (hashes_count > 3) {
+               a += hashes [0];
+               b += hashes [1];
+               c += hashes [2];
+               mix (a,b,c);
+               hashes_count -= 3;
+               hashes += 3;
        }
 
-       return hash;
+       /* Handle the last 3 hashes (all the case statements fall through) */
+       switch (hashes_count) { 
+       case 3 : c += hashes [2];
+       case 2 : b += hashes [1];
+       case 1 : a += hashes [0];
+               final (a,b,c);
+       case 0: /* nothing left to add */
+               break;
+       }
+       
+       free (hashes_start);
+       
+       return c;
 }
+#undef rot
+#undef mix
+#undef final
 
 /*
  * mono_aot_wrapper_name:
@@ -3404,17 +3614,45 @@ mono_aot_wrapper_name (MonoMethod *method)
  *   Create a MonoAotTrampInfo structure from the arguments.
  */
 MonoAotTrampInfo*
-mono_aot_tramp_info_create (char *name, guint8 *code, guint32 code_size)
+mono_aot_tramp_info_create (const char *name, guint8 *code, guint32 code_size)
 {
        MonoAotTrampInfo *info = g_new0 (MonoAotTrampInfo, 1);
 
-       info->name = name;
+       info->name = (char*)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 {
@@ -3948,6 +4186,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
@@ -4058,6 +4303,7 @@ static void
 emit_file_info (MonoAotCompile *acfg)
 {
        char symbol [128];
+       int i;
 
        sprintf (symbol, "mono_aot_file_info");
        emit_section_change (acfg, ".data", 0);
@@ -4069,13 +4315,13 @@ emit_file_info (MonoAotCompile *acfg)
        emit_int32 (acfg, acfg->plt_got_offset_base);
        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_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);
-       emit_pointer (acfg, "got");
+
+       for (i = 0; i < MONO_AOT_TRAMP_NUM; ++i)
+               emit_int32 (acfg, acfg->num_trampolines [i]);
+       for (i = 0; i < MONO_AOT_TRAMP_NUM; ++i)
+               emit_int32 (acfg, acfg->trampoline_got_offset_base [i]);
+       for (i = 0; i < MONO_AOT_TRAMP_NUM; ++i)
+               emit_int32 (acfg, acfg->trampoline_size [i]);
 }
 
 static void
@@ -4434,10 +4680,11 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
        if (!acfg->aot_opts.nodebug)
                acfg->dwarf = mono_dwarf_writer_create (acfg->w, NULL);
 
-       acfg->num_specific_trampolines = acfg->aot_opts.full_aot ? acfg->aot_opts.ntrampolines : 0;
+       acfg->num_trampolines [MONO_AOT_TRAMP_SPECIFIC] = 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;
+       acfg->num_trampolines [MONO_AOT_TRAMP_STATIC_RGCTX] = acfg->aot_opts.full_aot ? 1024 : 0;
 #endif
+       acfg->num_trampolines [MONO_AOT_TRAMP_IMT_THUNK] = acfg->aot_opts.full_aot ? 128 : 0;
 
        acfg->method_index = 1;