for TARGET_J2EE only:
[mono.git] / mono / mini / aot-runtime.c
index f3f58ca7d45798af5ff08f4cfad5490478b3b5a2..e3778edf59db7b34928355aa96ec34a5af634da7 100644 (file)
@@ -10,7 +10,9 @@
 
 #include "config.h"
 #include <sys/types.h>
+#ifdef HAVE_UNISTD_H
 #include <unistd.h>
+#endif
 #include <fcntl.h>
 #include <string.h>
 #ifndef PLATFORM_WIN32
 #include <mono/metadata/assembly.h>
 #include <mono/metadata/metadata-internals.h>
 #include <mono/metadata/marshal.h>
+#include <mono/metadata/gc-internal.h>
 #include <mono/utils/mono-logger.h>
 #include "mono/utils/mono-compiler.h"
 
 #include "mini.h"
+#include "version.h"
 
 #ifndef DISABLE_AOT
 
@@ -69,6 +73,7 @@ typedef struct MonoAotModule {
        /* Pointer to the Global Offset Table */
        gpointer *got;
        guint32 got_size;
+       GHashTable *name_cache;
        MonoAssemblyName *image_names;
        char **image_guids;
        MonoImage **image_table;
@@ -145,13 +150,7 @@ init_plt (MonoAotModule *info);
 static inline gboolean 
 is_got_patch (MonoJumpInfoType patch_type)
 {
-#ifdef __x86_64__
-       return TRUE;
-#elif defined(__i386__)
        return TRUE;
-#else
-       return FALSE;
-#endif
 }
 
 /*****************************************************/
@@ -219,40 +218,62 @@ decode_value (guint8 *ptr, guint8 **rptr)
 }
 
 static MonoClass*
-decode_klass_info (MonoAotModule *module, guint8 *buf, guint8 **endbuf)
+decode_klass_ref (MonoAotModule *module, guint8 *buf, guint8 **endbuf)
 {
        MonoImage *image;
-       MonoClass *klass;
-       guint32 token, rank, image_index;
+       MonoClass *klass, *eklass;
+       guint32 token, rank;
 
        token = decode_value (buf, &buf);
        if (token == 0) {
                *endbuf = buf;
                return NULL;
        }
-       image_index = decode_value (buf, &buf);
-       image = load_image (module, image_index);
-       if (!image)
-               return NULL;
-       if (mono_metadata_token_code (token) == 0) {
+       if (mono_metadata_token_table (token) == 0) {
+               image = load_image (module, decode_value (buf, &buf));
+               if (!image)
+                       return NULL;
                klass = mono_class_get (image, MONO_TOKEN_TYPE_DEF + token);
-       } else {
-               token = MONO_TOKEN_TYPE_DEF + decode_value (buf, &buf);
-               rank = decode_value (buf, &buf);
-               if (token == MONO_TOKEN_TYPE_DEF) {
-                       /* <Type>[][] */
-                       token = MONO_TOKEN_TYPE_DEF + decode_value (buf, &buf);
-                       klass = mono_class_get (image, token);
-                       g_assert (klass);
-                       klass = mono_array_class_get (klass, rank);
-
-                       rank = decode_value (buf, &buf);
-                       klass = mono_array_class_get (klass, rank);
+       } else if (mono_metadata_token_table (token) == MONO_TABLE_TYPESPEC) {
+               if (token == MONO_TOKEN_TYPE_SPEC) {
+                       MonoClass *gclass;
+                       int i;
+                       MonoGenericContext ctx;
+                       MonoGenericInst inst;
+
+                       gclass = decode_klass_ref (module, buf, &buf);
+                       g_assert (gclass->generic_container);
+
+                       memset (&ctx, 0, sizeof (ctx));
+                       memset (&inst, 0, sizeof (inst));
+                       ctx.class_inst = &inst;
+                       inst.type_argc = decode_value (buf, &buf);
+                       inst.type_argv = g_new0 (MonoType*, inst.type_argc);
+                       for (i = 0; i < inst.type_argc; ++i) {
+                               MonoClass *pclass = decode_klass_ref (module, buf, &buf);
+                               if (!pclass) {
+                                       g_free (inst.type_argv);
+                                       return NULL;
+                               }
+                               inst.type_argv [i] = &pclass->byval_arg;
+                       }
+                       klass = mono_class_from_mono_type (mono_class_inflate_generic_type (&gclass->byval_arg, &ctx));
                } else {
+                       image = load_image (module, decode_value (buf, &buf));
+                       if (!image)
+                               return NULL;
                        klass = mono_class_get (image, token);
-                       g_assert (klass);
-                       klass = mono_array_class_get (klass, rank);
                }
+       } else if (token == MONO_TOKEN_TYPE_DEF) {
+               /* Array */
+               image = load_image (module, decode_value (buf, &buf));
+               if (!image)
+                       return NULL;
+               rank = decode_value (buf, &buf);
+               eklass = decode_klass_ref (module, buf, &buf);
+               klass = mono_array_class_get (eklass, rank);
+       } else {
+               g_assert_not_reached ();
        }
        g_assert (klass);
        mono_class_init (klass);
@@ -264,7 +285,7 @@ decode_klass_info (MonoAotModule *module, guint8 *buf, guint8 **endbuf)
 static MonoClassField*
 decode_field_info (MonoAotModule *module, guint8 *buf, guint8 **endbuf)
 {
-       MonoClass *klass = decode_klass_info (module, buf, &buf);
+       MonoClass *klass = decode_klass_ref (module, buf, &buf);
        guint32 token;
 
        if (!klass)
@@ -284,10 +305,17 @@ decode_method_ref (MonoAotModule *module, guint32 *token, guint8 *buf, guint8 **
        MonoImage *image;
 
        value = decode_value (buf, &buf);
-       *endbuf = buf;
        image_index = value >> 24;
        *token = MONO_TOKEN_METHOD_DEF | (value & 0xffffff);
 
+       if (image_index == 255) {
+               /* Methodspec */
+               image_index = decode_value (buf, &buf);
+               *token = decode_value (buf, &buf);
+       }
+
+       *endbuf = buf;
+
        image = load_image (module, image_index);
        if (!image)
                return NULL;
@@ -449,12 +477,14 @@ load_aot_module (MonoAssembly *assembly, gpointer user_data)
        gboolean usable = TRUE;
        char *saved_guid = NULL;
        char *aot_version = NULL;
+       char *runtime_version;
        char *opt_flags = NULL;
        gpointer *plt_jump_table_addr = NULL;
        guint32 *plt_jump_table_size = NULL;
        gpointer *got_addr = NULL;
        gpointer *got = NULL;
        guint32 *got_size_ptr = NULL;
+       int i;
 
        if (mono_compile_aot)
                return;
@@ -488,6 +518,7 @@ load_aot_module (MonoAssembly *assembly, gpointer user_data)
        mono_dl_symbol (assembly->aot_module, "mono_assembly_guid", (gpointer *) &saved_guid);
        mono_dl_symbol (assembly->aot_module, "mono_aot_version", (gpointer *) &aot_version);
        mono_dl_symbol (assembly->aot_module, "mono_aot_opt_flags", (gpointer *)&opt_flags);
+       mono_dl_symbol (assembly->aot_module, "mono_runtime_version", (gpointer *)&runtime_version);
 
        if (!aot_version || strcmp (aot_version, MONO_AOT_FILE_VERSION)) {
                mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT module %s has wrong file format version (expected %s got %s)\n", aot_name, MONO_AOT_FILE_VERSION, aot_version);
@@ -500,6 +531,11 @@ load_aot_module (MonoAssembly *assembly, gpointer user_data)
                }
        }
 
+       if (!runtime_version || ((strlen (runtime_version) > 0 && strcmp (runtime_version, FULL_VERSION)))) {
+               mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT module %s is compiled against runtime version %s while this runtime has version %s.\n", aot_name, runtime_version, FULL_VERSION);
+               usable = FALSE;
+       }
+
        if (!usable) {
                g_free (aot_name);
                mono_dl_close (assembly->aot_module);
@@ -622,7 +658,19 @@ load_aot_module (MonoAssembly *assembly, gpointer user_data)
 
        mono_jit_info_add_aot_module (assembly->image, info->code, info->code_end);
 
-       mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT loaded AOT Module for %s.\n", assembly->image->name);
+       /*
+        * Since we store methoddef and classdef tokens when referring to methods/classes in
+        * referenced assemblies, we depend on the exact versions of the referenced assemblies.
+        * MS calls this 'hard binding'. This means we have to load all referenced assemblies
+        * non-lazily, since we can't handle out-of-date errors later.
+        */
+       for (i = 0; i < info->image_table_len; ++i)
+               load_image (info, i);
+
+       if (info->out_of_date)
+               mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT Module %s is unusable because a dependency is out-of-date.\n", assembly->image->name);
+       else
+               mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT loaded AOT Module for %s.\n", assembly->image->name);
 }
 
 void
@@ -645,6 +693,9 @@ decode_cached_class_info (MonoAotModule *module, MonoCachedClassInfo *info, guin
        guint32 flags;
 
        info->vtable_size = decode_value (buf, &buf);
+       if (info->vtable_size == -1)
+               /* Generic type */
+               return FALSE;
        flags = decode_value (buf, &buf);
        info->ghcimpl = (flags >> 0) & 0x1;
        info->has_finalize = (flags >> 1) & 0x1;
@@ -706,43 +757,64 @@ mono_aot_init_vtable (MonoVTable *vtable)
                return FALSE;
        }
 
+       mono_aot_unlock ();
+
+#ifdef MONO_ARCH_COMMON_VTABLE_TRAMPOLINE
        //printf ("VT0: %s.%s %d\n", klass->name_space, klass->name, vtable_size);
        for (i = 0; i < class_info.vtable_size; ++i) {
-               guint32 image_index, token, value;
-               MonoImage *image;
-#ifndef MONO_ARCH_HAVE_CREATE_TRAMPOLINE_FROM_TOKEN
-               MonoMethod *m;
+               vtable->vtable [i] = mini_get_vtable_trampoline ();
+       }
+
+       return TRUE;
+#else
+       return FALSE;
 #endif
+}
 
-               vtable->vtable [i] = 0;
+gpointer
+mono_aot_get_method_from_vt_slot (MonoDomain *domain, MonoVTable *vtable, int slot)
+{
+       int i;
+       MonoAotModule *aot_module;
+       MonoClass *klass = vtable->klass;
+       guint8 *info, *p;
+       MonoCachedClassInfo class_info;
+       gboolean err;
+       guint32 token;
+       MonoImage *image;
 
-               value = decode_value (p, &p);
-               if (!value)
-                       continue;
+       if (MONO_CLASS_IS_INTERFACE (klass) || klass->rank || !klass->image->assembly->aot_module)
+               return NULL;
 
-               image_index = value >> 24;
-               token = MONO_TOKEN_METHOD_DEF | (value & 0xffffff);
+       mono_aot_lock ();
 
-               image = load_image (aot_module, image_index);
-               if (!image) {
-                       mono_aot_unlock ();
-                       return FALSE;
-               }
+       aot_module = (MonoAotModule*) g_hash_table_lookup (aot_modules, klass->image->assembly);
+       if (!aot_module) {
+               mono_aot_unlock ();
+               return NULL;
+       }
 
-#ifdef MONO_ARCH_HAVE_CREATE_TRAMPOLINE_FROM_TOKEN
-               vtable->vtable [i] = mono_create_jit_trampoline_from_token (image, token);
-#else
-               m = mono_get_method (image, token, NULL);
-               g_assert (m);
+       info = &aot_module->class_info [aot_module->class_info_offsets [mono_metadata_token_index (klass->type_token) - 1]];
+       p = info;
 
-               //printf ("M: %d %p %s\n", i, &(vtable->vtable [i]), mono_method_full_name (m, TRUE));
-               vtable->vtable [i] = mono_create_jit_trampoline (m);
-#endif
+       err = decode_cached_class_info (aot_module, &class_info, p, &p);
+       if (!err) {
+               mono_aot_unlock ();
+               return NULL;
+       }
+
+       for (i = 0; i < slot; ++i)
+               decode_method_ref (aot_module, &token, p, &p);
+
+       image = decode_method_ref (aot_module, &token, p, &p);
+       if (!image) {
+               mono_aot_unlock ();
+               return NULL;
        }
 
        mono_aot_unlock ();
 
-       return TRUE;
+       return mono_aot_get_method_from_token (domain, image, token);
 }
 
 gboolean
@@ -798,6 +870,7 @@ mono_aot_get_class_from_name (MonoImage *image, const char *name_space, const ch
        const char *name2, *name_space2;
        MonoTableInfo  *t;
        guint32 cols [MONO_TYPEDEF_SIZE];
+       GHashTable *nspace_table;
 
        if (!aot_modules)
                return FALSE;
@@ -812,6 +885,18 @@ mono_aot_get_class_from_name (MonoImage *image, const char *name_space, const ch
 
        *klass = NULL;
 
+       /* First look in the cache */
+       if (!aot_module->name_cache)
+               aot_module->name_cache = g_hash_table_new (g_str_hash, g_str_equal);
+       nspace_table = g_hash_table_lookup (aot_module->name_cache, name_space);
+       if (nspace_table) {
+               *klass = g_hash_table_lookup (nspace_table, name);
+               if (*klass) {
+                       mono_aot_unlock ();
+                       return TRUE;
+               }
+       }
+
        table_size = aot_module->class_name_table [0];
        table = aot_module->class_name_table + 1;
 
@@ -849,6 +934,18 @@ mono_aot_get_class_from_name (MonoImage *image, const char *name_space, const ch
                        if (!strcmp (name, name2) && !strcmp (name_space, name_space2)) {
                                mono_aot_unlock ();
                                *klass = mono_class_get (image, token);
+
+                               /* Add to cache */
+                               if (*klass) {
+                                       mono_aot_lock ();
+                                       nspace_table = g_hash_table_lookup (aot_module->name_cache, name_space);
+                                       if (!nspace_table) {
+                                               nspace_table = g_hash_table_new (g_str_hash, g_str_equal);
+                                               g_hash_table_insert (aot_module->name_cache, (char*)name_space2, nspace_table);
+                                       }
+                                       g_hash_table_insert (nspace_table, (char*)name2, *klass);
+                                       mono_aot_unlock ();
+                               }
                                return TRUE;
                        }
 
@@ -1057,18 +1154,14 @@ decode_patch_info (MonoAotModule *aot_module, MonoMemPool *mp, MonoJumpInfo *ji,
        case MONO_PATCH_INFO_METHOD:
        case MONO_PATCH_INFO_METHODCONST:
        case MONO_PATCH_INFO_METHOD_JUMP: {
-               guint32 image_index, token, value;
-
-               value = decode_value (p, &p);
-               image_index = value >> 24;
-               token = MONO_TOKEN_METHOD_DEF | (value & 0xffffff);
+               guint32 token;
 
-               image = load_image (aot_module, image_index);
+               image = decode_method_ref (aot_module, &token, p, &p);
                if (!image)
                        goto cleanup;
 
 #ifdef MONO_ARCH_HAVE_CREATE_TRAMPOLINE_FROM_TOKEN
-               if (ji->type == MONO_PATCH_INFO_METHOD) {
+               if ((ji->type == MONO_PATCH_INFO_METHOD) && (mono_metadata_token_table (token) == MONO_TABLE_METHOD)) {
                        ji->data.target = mono_create_jit_trampoline_from_token (image, token);
                        ji->type = MONO_PATCH_INFO_ABS;
                }
@@ -1110,7 +1203,7 @@ decode_patch_info (MonoAotModule *aot_module, MonoMemPool *mp, MonoJumpInfo *ji,
                        break;
                }
                case MONO_WRAPPER_PROXY_ISINST: {
-                       MonoClass *klass = decode_klass_info (aot_module, p, &p);
+                       MonoClass *klass = decode_klass_ref (aot_module, p, &p);
                        if (!klass)
                                goto cleanup;
                        ji->type = MONO_PATCH_INFO_METHOD;
@@ -1123,7 +1216,7 @@ decode_patch_info (MonoAotModule *aot_module, MonoMemPool *mp, MonoJumpInfo *ji,
                case MONO_WRAPPER_LDFLD_REMOTE:
                case MONO_WRAPPER_STFLD_REMOTE:
                case MONO_WRAPPER_ISINST: {
-                       MonoClass *klass = decode_klass_info (aot_module, p, &p);
+                       MonoClass *klass = decode_klass_ref (aot_module, p, &p);
                        if (!klass)
                                goto cleanup;
                        ji->type = MONO_PATCH_INFO_METHOD;
@@ -1143,6 +1236,13 @@ decode_patch_info (MonoAotModule *aot_module, MonoMemPool *mp, MonoJumpInfo *ji,
                                g_assert_not_reached ();
                        break;
                }
+               case MONO_WRAPPER_ALLOC: {
+                       int atype = decode_value (p, &p);
+
+                       ji->type = MONO_PATCH_INFO_METHOD;
+                       ji->data.method = mono_gc_get_managed_allocator_by_type (atype);
+                       break;
+               }
                case MONO_WRAPPER_STELEMREF:
                        ji->type = MONO_PATCH_INFO_METHOD;
                        ji->data.method = mono_marshal_get_stelemref ();
@@ -1170,13 +1270,14 @@ decode_patch_info (MonoAotModule *aot_module, MonoMemPool *mp, MonoJumpInfo *ji,
                        //printf ("HIT!\n");
                } else {
                        guint8 *tmp = aot_module->got_info + aot_module->got_info_offsets [*got_offset];
-                       ji->data.klass = decode_klass_info (aot_module, tmp, &tmp);
+                       ji->data.klass = decode_klass_ref (aot_module, tmp, &tmp);
                        if (!ji->data.klass)
                                goto cleanup;
                }
                break;
        case MONO_PATCH_INFO_CLASS_INIT:
-               ji->data.klass = decode_klass_info (aot_module, p, &p);
+       case MONO_PATCH_INFO_DELEGATE_TRAMPOLINE:
+               ji->data.klass = decode_klass_ref (aot_module, p, &p);
                if (!ji->data.klass)
                        goto cleanup;
                break;
@@ -1248,7 +1349,7 @@ decode_patch_info (MonoAotModule *aot_module, MonoMemPool *mp, MonoJumpInfo *ji,
                }
                break;
        case MONO_PATCH_INFO_EXC_NAME:
-               ji->data.klass = decode_klass_info (aot_module, p, &p);
+               ji->data.klass = decode_klass_ref (aot_module, p, &p);
                if (!ji->data.klass)
                        goto cleanup;
                ji->data.name = ji->data.klass->name;
@@ -1357,6 +1458,12 @@ mono_aot_get_method_inner (MonoDomain *domain, MonoMethod *method)
        if (aot_module->out_of_date)
                return NULL;
 
+       if (method->is_inflated) {
+               if (!mono_method_is_generic_sharable_impl (method))
+                       return NULL;
+               method = mono_method_get_declaring_generic_method (method);
+       }
+
        if (aot_module->code_offsets [method_index] == 0xffffffff) {
                if (mono_trace_is_traced (G_LOG_LEVEL_DEBUG, MONO_TRACE_AOT)) {
                        char *full_name = mono_method_full_name (method, TRUE);
@@ -1399,7 +1506,7 @@ mono_aot_load_method (MonoDomain *domain, MonoAotModule *aot_module, MonoMethod
        MonoJitInfo *jinfo = NULL;
 
        p = info;
-       decode_klass_info (aot_module, p, &p);
+       decode_klass_ref (aot_module, p, &p);
 
        if (!use_loaded_code) {
                guint8 *code2;
@@ -1577,7 +1684,7 @@ mono_aot_get_method_from_token_inner (MonoDomain *domain, MonoImage *image, guin
        }
 
        p = info;
-       *klass = decode_klass_info (aot_module, p, &p);
+       *klass = decode_klass_ref (aot_module, p, &p);
 
        if (mono_trace_is_traced (G_LOG_LEVEL_DEBUG, MONO_TRACE_AOT)) {
                MonoMethod *method = mono_get_method (image, token, NULL);
@@ -1849,7 +1956,7 @@ mono_aot_handle_pagefault (void *ptr)
 }
 
 /*
- * aot_dyn_resolve:
+ * mono_aot_plt_resolve:
  *
  *   This function is called by the entries in the PLT to resolve the actual method that
  * needs to be called. It returns a trampoline to the method and patches the PLT entry.
@@ -1857,7 +1964,7 @@ mono_aot_handle_pagefault (void *ptr)
 gpointer
 mono_aot_plt_resolve (gpointer aot_module, guint32 plt_info_offset, guint8 *code)
 {
-#ifdef MONO_ARCH_HAVE_PIC_AOT
+#ifdef MONO_ARCH_AOT_SUPPORTED
        guint8 *p, *target, *plt_entry;
        MonoJumpInfo ji;
        MonoAotModule *module = (MonoAotModule*)aot_module;
@@ -1897,11 +2004,12 @@ mono_aot_plt_resolve (gpointer aot_module, guint32 plt_info_offset, guint8 *code
 static void
 init_plt (MonoAotModule *info)
 {
-#ifdef MONO_ARCH_HAVE_PIC_AOT
+#ifdef MONO_ARCH_AOT_SUPPORTED
 #ifdef __i386__
        guint8 *buf = info->plt;
-#endif
-#if defined(__x86_64__)
+#elif defined(__x86_64__)
+       int i, n_entries;
+#elif defined(__arm__)
        int i, n_entries;
 #endif
        gpointer tramp;
@@ -1926,6 +2034,21 @@ init_plt (MonoAotModule *info)
         for (i = 1; i < n_entries; ++i)
                 /* Each PLT entry is 16 bytes long, the default entry begins at offset 6 */
                 ((gpointer*)info->plt_jump_table)[i] = info->plt + (i * 16) + 6;
+#elif defined(__arm__)
+        /* Initialize the first PLT entry */
+        make_writable (info->plt, info->plt_end - info->plt);
+        ((guint32*)info->plt)[1] = (guint32)tramp;
+
+        n_entries = ((guint8*)info->plt_end - (guint8*)info->plt) / 8;
+
+        /* 
+         * Initialize the jump targets embedded inside the PLT entries to the default
+         * targets.
+         */
+        for (i = 1; i < n_entries; ++i)
+                /* Each PLT entry is 8 bytes long, the jump target is at offset 4 */
+                /* Each default PLT target is 12 bytes long */
+                ((guint32*)info->plt)[(i * 2) + 1] = (guint8*)info->plt_end + ((i - 1) * 12);
 #else
        g_assert_not_reached ();
 #endif
@@ -1955,6 +2078,19 @@ mono_aot_get_plt_entry (guint8 *code)
                if ((target >= (guint8*)(aot_module->plt)) && (target < (guint8*)(aot_module->plt_end)))
                        return target;
        }
+#elif defined(__arm__)
+       guint32 ins = ((guint32*)code) [-1];
+
+       /* Should be a 'bl' */
+       if ((((ins >> 25) & 0x7) == 0x5) && (((ins >> 24) & 0x1) == 0x1)) {
+               gint32 disp = ((gint32)ins) & 0xffffff;
+               guint8 *target = code - 4 + 8 + (disp * 4);
+
+               if ((target >= (guint8*)(aot_module->plt)) && (target < (guint8*)(aot_module->plt_end)))
+                       return target;
+       }               
+#else
+       g_assert_not_reached ();
 #endif
 
        return NULL;
@@ -1979,7 +2115,7 @@ mono_aot_init (void)
 {
 }
 
-MonoJitInfo*
+gpointer
 mono_aot_get_method (MonoDomain *domain, MonoMethod *method)
 {
        return NULL;
@@ -2049,4 +2185,15 @@ mono_aot_get_plt_entry (guint8 *code)
        return NULL;
 }
 
+gpointer
+mono_aot_plt_resolve (gpointer aot_module, guint32 plt_info_offset, guint8 *code)
+{
+       return NULL;
+}
+
+gpointer
+mono_aot_get_method_from_vt_slot (MonoDomain *domain, MonoVTable *vtable, int slot)
+{
+       return NULL;
+}
 #endif