Test case for bug#325444.
[mono.git] / mono / mini / aot-runtime.c
index 161c1859660bb30f237e2632fe6e3d1ca47e77d2..6da4f6e00f4e1c85c51a40cec484839c6ab2d9a2 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
@@ -44,6 +46,7 @@
 #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"
 
@@ -69,6 +72,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;
@@ -234,14 +238,28 @@ decode_klass_info (MonoAotModule *module, guint8 *buf, guint8 **endbuf)
        image = load_image (module, image_index);
        if (!image)
                return NULL;
-       if (mono_metadata_token_code (token) == 0) {
+       if (mono_metadata_token_table (token) == 0) {
                klass = mono_class_get (image, MONO_TOKEN_TYPE_DEF + token);
+       } else if (mono_metadata_token_table (token) == MONO_TABLE_TYPESPEC) {
+               klass = mono_class_get (image, token);
        } else {
+               g_assert (mono_metadata_token_table (token) == MONO_TABLE_TYPEDEF);
                token = MONO_TOKEN_TYPE_DEF + decode_value (buf, &buf);
                rank = decode_value (buf, &buf);
-               klass = mono_class_get (image, token);
-               g_assert (klass);
-               klass = mono_array_class_get (klass, rank);
+               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 {
+                       klass = mono_class_get (image, token);
+                       g_assert (klass);
+                       klass = mono_array_class_get (klass, rank);
+               }
        }
        g_assert (klass);
        mono_class_init (klass);
@@ -277,6 +295,12 @@ decode_method_ref (MonoAotModule *module, guint32 *token, guint8 *buf, guint8 **
        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);
+       }
+
        image = load_image (module, image_index);
        if (!image)
                return NULL;
@@ -361,12 +385,12 @@ create_cache_structure (void)
  * - invoking a new mono process is a security risk
  * - recompile the AOT module if one of its dependencies changes
  */
-static GModule*
+static MonoDl*
 load_aot_module_from_cache (MonoAssembly *assembly, char **aot_name)
 {
        char *fname, *cmd, *tmp2, *aot_options;
        const char *home;
-       GModule *module;
+       MonoDl *module;
        gboolean res;
        gchar *out, *err;
        gint exit_status;
@@ -386,7 +410,7 @@ load_aot_module_from_cache (MonoAssembly *assembly, char **aot_name)
        g_free (tmp2);
 
        mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT trying to load from cache: '%s'.", fname);
-       module = g_module_open (fname, G_MODULE_BIND_LAZY);     
+       module = mono_dl_open (fname, MONO_DL_LAZY, NULL);
 
        if (!module) {
                mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT not found.");
@@ -422,7 +446,7 @@ load_aot_module_from_cache (MonoAssembly *assembly, char **aot_name)
                        }
                }
 
-               module = g_module_open (fname, G_MODULE_BIND_LAZY);     
+               module = mono_dl_open (fname, MONO_DL_LAZY, NULL);
 
                g_free (aot_options);
        }
@@ -444,6 +468,7 @@ load_aot_module (MonoAssembly *assembly, gpointer user_data)
        gpointer *got_addr = NULL;
        gpointer *got = NULL;
        guint32 *got_size_ptr = NULL;
+       int i;
 
        if (mono_compile_aot)
                return;
@@ -458,12 +483,14 @@ load_aot_module (MonoAssembly *assembly, gpointer user_data)
        if (use_aot_cache)
                assembly->aot_module = load_aot_module_from_cache (assembly, &aot_name);
        else {
+               char *err;
                aot_name = g_strdup_printf ("%s%s", assembly->image->name, SHARED_EXT);
 
-               assembly->aot_module = g_module_open (aot_name, G_MODULE_BIND_LAZY);
+               assembly->aot_module = mono_dl_open (aot_name, MONO_DL_LAZY, &err);
 
                if (!assembly->aot_module) {
-                       mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT failed to load AOT module %s: %s\n", aot_name, g_module_error ());
+                       mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT failed to load AOT module %s: %s\n", aot_name, err);
+                       g_free (err);
                }
        }
 
@@ -472,9 +499,9 @@ load_aot_module (MonoAssembly *assembly, gpointer user_data)
                return;
        }
 
-       g_module_symbol (assembly->aot_module, "mono_assembly_guid", (gpointer *) &saved_guid);
-       g_module_symbol (assembly->aot_module, "mono_aot_version", (gpointer *) &aot_version);
-       g_module_symbol (assembly->aot_module, "mono_aot_opt_flags", (gpointer *)&opt_flags);
+       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);
 
        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);
@@ -489,16 +516,16 @@ load_aot_module (MonoAssembly *assembly, gpointer user_data)
 
        if (!usable) {
                g_free (aot_name);
-               g_module_close (assembly->aot_module);
+               mono_dl_close (assembly->aot_module);
                assembly->aot_module = NULL;
                return;
        }
 
-       g_module_symbol (assembly->aot_module, "got_addr", (gpointer *)&got_addr);
+       mono_dl_symbol (assembly->aot_module, "got_addr", (gpointer *)&got_addr);
        g_assert (got_addr);
        got = (gpointer*)*got_addr;
        g_assert (got);
-       g_module_symbol (assembly->aot_module, "got_size", (gpointer *)&got_size_ptr);
+       mono_dl_symbol (assembly->aot_module, "got_size", (gpointer *)&got_size_ptr);
        g_assert (got_size_ptr);
 
        info = g_new0 (MonoAotModule, 1);
@@ -514,7 +541,7 @@ load_aot_module (MonoAssembly *assembly, gpointer user_data)
                guint32 table_len, i;
                char *table = NULL;
 
-               g_module_symbol (assembly->aot_module, "mono_image_table", (gpointer *)&table);
+               mono_dl_symbol (assembly->aot_module, "mono_image_table", (gpointer *)&table);
                g_assert (table);
 
                table_len = *(guint32*)table;
@@ -551,34 +578,34 @@ load_aot_module (MonoAssembly *assembly, gpointer user_data)
        }
 
        /* Read method and method_info tables */
-       g_module_symbol (assembly->aot_module, "method_offsets", (gpointer*)&info->code_offsets);
-       g_module_symbol (assembly->aot_module, "methods", (gpointer*)&info->code);
-       g_module_symbol (assembly->aot_module, "methods_end", (gpointer*)&info->code_end);
-       g_module_symbol (assembly->aot_module, "method_info_offsets", (gpointer*)&info->method_info_offsets);
-       g_module_symbol (assembly->aot_module, "method_info", (gpointer*)&info->method_info);
-       g_module_symbol (assembly->aot_module, "ex_info_offsets", (gpointer*)&info->ex_info_offsets);
-       g_module_symbol (assembly->aot_module, "ex_info", (gpointer*)&info->ex_info);
-       g_module_symbol (assembly->aot_module, "method_order", (gpointer*)&info->method_order);
-       g_module_symbol (assembly->aot_module, "method_order_end", (gpointer*)&info->method_order_end);
-       g_module_symbol (assembly->aot_module, "class_info", (gpointer*)&info->class_info);
-       g_module_symbol (assembly->aot_module, "class_info_offsets", (gpointer*)&info->class_info_offsets);
-       g_module_symbol (assembly->aot_module, "class_name_table", (gpointer *)&info->class_name_table);
-       g_module_symbol (assembly->aot_module, "got_info", (gpointer*)&info->got_info);
-       g_module_symbol (assembly->aot_module, "got_info_offsets", (gpointer*)&info->got_info_offsets);
-       g_module_symbol (assembly->aot_module, "mem_end", (gpointer*)&info->mem_end);
+       mono_dl_symbol (assembly->aot_module, "method_offsets", (gpointer*)&info->code_offsets);
+       mono_dl_symbol (assembly->aot_module, "methods", (gpointer*)&info->code);
+       mono_dl_symbol (assembly->aot_module, "methods_end", (gpointer*)&info->code_end);
+       mono_dl_symbol (assembly->aot_module, "method_info_offsets", (gpointer*)&info->method_info_offsets);
+       mono_dl_symbol (assembly->aot_module, "method_info", (gpointer*)&info->method_info);
+       mono_dl_symbol (assembly->aot_module, "ex_info_offsets", (gpointer*)&info->ex_info_offsets);
+       mono_dl_symbol (assembly->aot_module, "ex_info", (gpointer*)&info->ex_info);
+       mono_dl_symbol (assembly->aot_module, "method_order", (gpointer*)&info->method_order);
+       mono_dl_symbol (assembly->aot_module, "method_order_end", (gpointer*)&info->method_order_end);
+       mono_dl_symbol (assembly->aot_module, "class_info", (gpointer*)&info->class_info);
+       mono_dl_symbol (assembly->aot_module, "class_info_offsets", (gpointer*)&info->class_info_offsets);
+       mono_dl_symbol (assembly->aot_module, "class_name_table", (gpointer *)&info->class_name_table);
+       mono_dl_symbol (assembly->aot_module, "got_info", (gpointer*)&info->got_info);
+       mono_dl_symbol (assembly->aot_module, "got_info_offsets", (gpointer*)&info->got_info_offsets);
+       mono_dl_symbol (assembly->aot_module, "mem_end", (gpointer*)&info->mem_end);
 
        info->mem_begin = info->code;
 
-       g_module_symbol (assembly->aot_module, "plt", (gpointer*)&info->plt);
-       g_module_symbol (assembly->aot_module, "plt_end", (gpointer*)&info->plt_end);
-       g_module_symbol (assembly->aot_module, "plt_info", (gpointer*)&info->plt_info);
+       mono_dl_symbol (assembly->aot_module, "plt", (gpointer*)&info->plt);
+       mono_dl_symbol (assembly->aot_module, "plt_end", (gpointer*)&info->plt_end);
+       mono_dl_symbol (assembly->aot_module, "plt_info", (gpointer*)&info->plt_info);
 
-       g_module_symbol (assembly->aot_module, "plt_jump_table_addr", (gpointer *)&plt_jump_table_addr);
+       mono_dl_symbol (assembly->aot_module, "plt_jump_table_addr", (gpointer *)&plt_jump_table_addr);
        g_assert (plt_jump_table_addr);
        info->plt_jump_table = (guint8*)*plt_jump_table_addr;
        g_assert (info->plt_jump_table);
 
-       g_module_symbol (assembly->aot_module, "plt_jump_table_size", (gpointer *)&plt_jump_table_size);
+       mono_dl_symbol (assembly->aot_module, "plt_jump_table_size", (gpointer *)&plt_jump_table_size);
        g_assert (plt_jump_table_size);
        info->plt_jump_table_size = *plt_jump_table_size;
 
@@ -609,7 +636,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
@@ -632,6 +671,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;
@@ -785,6 +827,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;
@@ -799,6 +842,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;
 
@@ -836,6 +891,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;
                        }
 
@@ -913,7 +980,7 @@ MonoJitInfo *
 mono_aot_find_jit_info (MonoDomain *domain, MonoImage *image, gpointer addr)
 {
        MonoAssembly *ass = image->assembly;
-       GModule *module = ass->aot_module;
+       MonoDl *module = ass->aot_module;
        int pos, left, right, offset, offset1, offset2, last_offset, new_offset, page_index, method_index, table_len;
        guint32 token;
        MonoAotModule *aot_module;
@@ -1044,18 +1111,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;
                }
@@ -1130,6 +1193,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 ();
@@ -1313,7 +1383,7 @@ mono_aot_get_method_inner (MonoDomain *domain, MonoMethod *method)
 {
        MonoClass *klass = method->klass;
        MonoAssembly *ass = klass->image->assembly;
-       GModule *module = ass->aot_module;
+       MonoDl *module = ass->aot_module;
        guint32 method_index = mono_metadata_token_index (method->token) - 1;
        guint8 *code, *info;
        MonoAotModule *aot_module;
@@ -1518,7 +1588,7 @@ mono_aot_get_method_from_token_inner (MonoDomain *domain, MonoImage *image, guin
        int i, method_index, pindex, got_index, n_patches, used_strings;
        gboolean keep_patches = TRUE;
        guint8 *p;
-       GModule *module = ass->aot_module;
+       MonoDl *module = ass->aot_module;
        guint8 *code = NULL;
        guint8 *info;
        MonoAotModule *aot_module;
@@ -1836,7 +1906,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.
@@ -1966,7 +2036,7 @@ mono_aot_init (void)
 {
 }
 
-MonoJitInfo*
+gpointer
 mono_aot_get_method (MonoDomain *domain, MonoMethod *method)
 {
        return NULL;
@@ -2036,4 +2106,10 @@ 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;
+}
+
 #endif