Avoid creating plt entries for empty plt sections.
[mono.git] / mono / mini / aot-runtime.c
index ba9d698d3dbd97e271340832fd2602f7ceba87aa..521ff45b63dbf4808b545fe64b6b8aebb5a684a1 100644 (file)
@@ -68,7 +68,7 @@
 #endif
 
 /* Number of got entries shared between the JIT and LLVM GOT */
-#define N_COMMON_GOT_ENTRIES 4
+#define N_COMMON_GOT_ENTRIES 9
 
 #define ALIGN_TO(val,align) ((((guint64)val) + ((align) - 1)) & ~((align) - 1))
 #define ALIGN_PTR_TO(ptr,align) (gpointer)((((gssize)(ptr)) + (align - 1)) & (~(align - 1)))
@@ -98,6 +98,7 @@ typedef struct MonoAotModule {
        guint32 image_table_len;
        gboolean out_of_date;
        gboolean plt_inited;
+       gboolean got_initializing;
        guint8 *mem_begin;
        guint8 *mem_end;
        guint8 *jit_code_start;
@@ -212,11 +213,7 @@ static void
 compute_llvm_code_range (MonoAotModule *amodule, guint8 **code_start, guint8 **code_end);
 
 static gboolean
-init_method (MonoAotModule *amodule, guint32 method_index, MonoMethod *method, MonoClass **klass);
-
-/*****************************************************/
-/*                 AOT RUNTIME                       */
-/*****************************************************/
+init_method (MonoAotModule *amodule, guint32 method_index, MonoMethod *method, MonoClass *init_class, MonoGenericContext *context);
 
 static inline void
 amodule_lock (MonoAotModule *amodule)
@@ -1673,6 +1670,10 @@ check_usable (MonoAssembly *assembly, MonoAotFileInfo *info, char **out_msg)
                msg = g_strdup_printf ("compiled with --aot=full");
                usable = FALSE;
        }
+       if (mono_llvm_only && !(info->flags & MONO_AOT_FILE_FLAG_LLVM_ONLY)) {
+               msg = g_strdup_printf ("not compiled with --aot=llvmonly");
+               usable = FALSE;
+       }
 #ifdef TARGET_ARM
        /* mono_arch_find_imt_method () requires this */
        if ((info->flags & MONO_AOT_FILE_FLAG_WITH_LLVM) && !mono_use_llvm) {
@@ -1763,6 +1764,28 @@ init_gots (MonoAotModule *amodule)
        }
 }
 
+static void
+init_amodule_got (MonoAotModule *amodule)
+{
+       MonoJumpInfo ji;
+
+       /* These can't be initialized in load_aot_module () */
+       if (!amodule->shared_got [6] && !amodule->got_initializing) {
+               amodule->got_initializing = TRUE;
+
+               memset (&ji, 0, sizeof (ji));
+               ji.type = MONO_PATCH_INFO_INTERNAL_METHOD;
+               ji.data.name = "mono_aot_init_llvm_method";
+               amodule->got_initializing = TRUE;
+               amodule->shared_got [6] = mono_resolve_patch_target (NULL, mono_get_root_domain (), NULL, &ji, FALSE);
+               ji.data.name = "mono_aot_init_gshared_method_this";
+               amodule->shared_got [7] = mono_resolve_patch_target (NULL, mono_get_root_domain (), NULL, &ji, FALSE);
+               ji.data.name = "mono_aot_init_gshared_method_rgctx";
+               amodule->shared_got [8] = mono_resolve_patch_target (NULL, mono_get_root_domain (), NULL, &ji, FALSE);
+               init_gots (amodule);
+       }
+}
+
 static void
 load_aot_module (MonoAssembly *assembly, gpointer user_data)
 {
@@ -1966,6 +1989,12 @@ load_aot_module (MonoAssembly *assembly, gpointer user_data)
        for (i = 0; i < amodule->info.nmethods; ++i) {
                void *addr = NULL;
 
+               if (amodule->info.llvm_get_method) {
+                       gpointer (*get_method) (int) = amodule->info.llvm_get_method;
+
+                       addr = get_method (i);
+               }
+
                /* method_addresses () contains a table of branches, since the ios linker can update those correctly */
                if (!addr && amodule->info.method_addresses) {
                        addr = get_call_table_entry (amodule->info.method_addresses, i);
@@ -2053,6 +2082,9 @@ load_aot_module (MonoAssembly *assembly, gpointer user_data)
                amodule->shared_got [3] = mono_resolve_patch_target (NULL, mono_get_root_domain (), NULL, &ji, FALSE);
        }
 
+       amodule->shared_got [5] = amodule;
+       /* Can't initialize the other shared got slots yet, they are initialized in init_amodule_got () */
+
        init_gots (amodule);
 
        /*
@@ -2393,6 +2425,16 @@ compute_llvm_code_range (MonoAotModule *amodule, guint8 **code_start, guint8 **c
        int version, fde_count;
        gint32 *table;
 
+       if (amodule->info.llvm_get_method) {
+               gpointer (*get_method) (int) = amodule->info.llvm_get_method;
+
+               *code_start = get_method (-1);
+               *code_end = get_method (-2);
+
+               g_assert (*code_end > *code_start);
+               return;
+       }
+
        g_assert (amodule->mono_eh_frame);
 
        p = amodule->mono_eh_frame;
@@ -3356,7 +3398,8 @@ decode_patch (MonoAotModule *aot_module, MonoMemPool *mp, MonoJumpInfo *ji, guin
        case MONO_PATCH_INFO_CASTCLASS_CACHE:
                ji->data.index = decode_value (p, &p);
                break;
-       case MONO_PATCH_INFO_RGCTX_FETCH: {
+       case MONO_PATCH_INFO_RGCTX_FETCH:
+       case MONO_PATCH_INFO_RGCTX_SLOT_INDEX: {
                gboolean res;
                MonoJumpInfoRgctxEntry *entry;
                guint32 offset, val;
@@ -3380,6 +3423,7 @@ decode_patch (MonoAotModule *aot_module, MonoMemPool *mp, MonoJumpInfo *ji, guin
                break;
        }
        case MONO_PATCH_INFO_SEQ_POINT_INFO:
+       case MONO_PATCH_INFO_AOT_MODULE:
                break;
        case MONO_PATCH_INFO_LLVM_IMT_TRAMPOLINE: {
                MonoJumpInfoImtTramp *imt_tramp = mono_mempool_alloc0 (mp, sizeof (MonoJumpInfoImtTramp));
@@ -3567,12 +3611,12 @@ register_jump_target_got_slot (MonoDomain *domain, MonoMethod *method, gpointer
 static gpointer
 load_method (MonoDomain *domain, MonoAotModule *amodule, MonoImage *image, MonoMethod *method, guint32 token, int method_index)
 {
-       MonoClass *klass;
-       gboolean from_plt = method == NULL;
        MonoJitInfo *jinfo = NULL;
        guint8 *code = NULL, *info;
        gboolean res;
 
+       init_amodule_got (amodule);
+
        if (mono_profiler_get_events () & MONO_PROFILE_ENTER_LEAVE) {
                if (mono_aot_only)
                        /* The caller cannot handle this */
@@ -3587,6 +3631,14 @@ load_method (MonoDomain *domain, MonoAotModule *amodule, MonoImage *image, MonoM
        if (amodule->out_of_date)
                return NULL;
 
+       if (amodule->info.llvm_get_method) {
+               /*
+                * Obtain the method address by calling a generated function in the LLVM module.
+                */
+               gpointer (*get_method) (int) = amodule->info.llvm_get_method;
+               code = get_method (method_index);
+       }
+
        if (!code) {
                if (amodule->methods [method_index] == GINT_TO_POINTER (-1)) {
                        if (mono_trace_is_traced (G_LOG_LEVEL_DEBUG, MONO_TRACE_AOT)) {
@@ -3600,10 +3652,9 @@ load_method (MonoDomain *domain, MonoAotModule *amodule, MonoImage *image, MonoM
                        }
                        return NULL;
                }
+               code = amodule->methods [method_index];
        }
 
-       code = amodule->methods [method_index];
-
        info = &amodule->blob [mono_aot_get_offset (amodule->method_info_offsets, method_index)];
 
        if (!amodule->methods_loaded) {
@@ -3637,9 +3688,11 @@ load_method (MonoDomain *domain, MonoAotModule *amodule, MonoImage *image, MonoM
                }
        }
 
-       res = init_method (amodule, method_index, method, &klass);
-       if (!res)
-               goto cleanup;
+       if (!(is_llvm_code (amodule, code) && (amodule->info.flags & MONO_AOT_FILE_FLAG_LLVM_ONLY))) {
+               res = init_method (amodule, method_index, method, NULL, NULL);
+               if (!res)
+                       goto cleanup;
+       }
 
        if (mono_trace_is_traced (G_LOG_LEVEL_DEBUG, MONO_TRACE_AOT)) {
                char *full_name;
@@ -3682,9 +3735,6 @@ load_method (MonoDomain *domain, MonoAotModule *amodule, MonoImage *image, MonoM
                mono_profiler_method_end_jit (method, jinfo, MONO_PROFILE_OK);
        }
 
-       if (from_plt && klass && !klass->generic_container)
-               mono_runtime_class_init (mono_class_vtable (domain, klass));
-
        return code;
 
  cleanup:
@@ -3840,10 +3890,12 @@ mono_aot_find_method_index (MonoMethod *method)
 }
 
 static gboolean
-init_method (MonoAotModule *amodule, guint32 method_index, MonoMethod *method, MonoClass **klass)
+init_method (MonoAotModule *amodule, guint32 method_index, MonoMethod *method, MonoClass *init_class, MonoGenericContext *context)
 {
        MonoDomain *domain = mono_domain_get ();
        MonoMemPool *mp;
+       MonoClass *klass;
+       gboolean from_plt = method == NULL;
        int pindex, n_patches;
        guint8 *p;
        MonoJitInfo *jinfo = NULL;
@@ -3855,10 +3907,10 @@ init_method (MonoAotModule *amodule, guint32 method_index, MonoMethod *method, M
        p = info;
 
        if (method) {
-               *klass = method->klass;
+               klass = method->klass;
                decode_klass_ref (amodule, p, &p);
        } else {
-               *klass = decode_klass_ref (amodule, p, &p);
+               klass = decode_klass_ref (amodule, p, &p);
        }
 
        n_patches = decode_value (p, &p);
@@ -3894,6 +3946,13 @@ init_method (MonoAotModule *amodule, guint32 method_index, MonoMethod *method, M
                         * finished executing (#23242).
                         */
                        if (!got [got_slots [pindex]] || ji->type == MONO_PATCH_INFO_SFLDA) {
+                               /* In llvm-only made, we might encounter shared methods */
+                               if (mono_llvm_only && ji->type == MONO_PATCH_INFO_METHOD && mono_method_check_context_used (ji->data.method)) {
+                                       MonoError error;
+
+                                       g_assert (context);
+                                       ji->data.method = mono_class_inflate_generic_method_checked (ji->data.method, context, &error);
+                               }
                                addr = mono_resolve_patch_target (method, domain, code, ji, TRUE);
                                if (ji->type == MONO_PATCH_INFO_METHOD_JUMP)
                                        addr = mono_create_ftnptr (domain, addr);
@@ -3913,6 +3972,11 @@ init_method (MonoAotModule *amodule, guint32 method_index, MonoMethod *method, M
        if (mini_get_debug_options ()->load_aot_jit_info_eagerly)
                jinfo = mono_aot_find_jit_info (domain, amodule->assembly->image, code);
 
+       if (init_class)
+               mono_runtime_class_init (mono_class_vtable (domain, init_class));
+       else if (from_plt && klass && !klass->generic_container)
+               mono_runtime_class_init (mono_class_vtable (domain, klass));
+
        return TRUE;
 
  cleanup:
@@ -3922,6 +3986,48 @@ init_method (MonoAotModule *amodule, guint32 method_index, MonoMethod *method, M
        return FALSE;
 }
 
+void
+mono_aot_init_llvm_method (gpointer aot_module, guint32 method_index)
+{
+       gboolean res;
+
+       // FIXME: Handle failure
+       res = init_method ((MonoAotModule*)aot_module, method_index, NULL, NULL, NULL);
+       g_assert (res);
+}
+
+void
+mono_aot_init_gshared_method_this (gpointer aot_module, guint32 method_index, MonoObject *this)
+{
+       gboolean res;
+       MonoClass *klass;
+
+       // FIXME:
+       g_assert (this);
+
+       // FIXME: Handle failure
+       klass = this->vtable->klass;
+       res = init_method ((MonoAotModule*)aot_module, method_index, NULL, klass, klass->generic_class ? &klass->generic_class->context : NULL);
+       g_assert (res);
+}
+
+void
+mono_aot_init_gshared_method_rgctx  (gpointer aot_module, guint32 method_index, MonoMethodRuntimeGenericContext *rgctx)
+{
+       gboolean res;
+       MonoGenericContext context = { NULL, NULL };
+       MonoClass *klass = rgctx->class_vtable->klass;
+
+       if (klass->generic_class)
+               context.class_inst = klass->generic_class->context.class_inst;
+       else if (klass->generic_container)
+               context.class_inst = klass->generic_container->context.class_inst;
+       context.method_inst = rgctx->method_inst;
+
+       res = init_method ((MonoAotModule*)aot_module, method_index, NULL, rgctx->class_vtable->klass, &context);
+       g_assert (res);
+}
+
 /*
  * mono_aot_get_method:
  *
@@ -4036,9 +4142,9 @@ mono_aot_get_method (MonoDomain *domain, MonoMethod *method)
                /* Same for CompareExchange<T> and Exchange<T> */
                /* Same for Volatile.Read<T>/Write<T> */
                if (method_index == 0xffffff && method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE && method->klass->image == mono_defaults.corlib && 
-                       ((!strcmp (method->klass->name_space, "System.Threading") && !strcmp (method->klass->name, "Interlocked") && (!strcmp (method->name, "CompareExchange") || !strcmp (method->name, "Exchange")) && MONO_TYPE_IS_REFERENCE (mono_method_signature (method)->params [1])) ||
-                        (!strcmp (method->klass->name_space, "System.Threading") && !strcmp (method->klass->name, "Volatile") && (!strcmp (method->name, "Read") && MONO_TYPE_IS_REFERENCE (mono_method_signature (method)->ret))) ||
-                        (!strcmp (method->klass->name_space, "System.Threading") && !strcmp (method->klass->name, "Volatile") && (!strcmp (method->name, "Write") && MONO_TYPE_IS_REFERENCE (mono_method_signature (method)->params [1]))))) {
+                       ((!strcmp (method->klass->name_space, "System.Threading") && !strcmp (method->klass->name, "Interlocked") && (!strcmp (method->name, "CompareExchange") || !strcmp (method->name, "Exchange")) && MONO_TYPE_IS_REFERENCE (mini_type_get_underlying_type (NULL, mono_method_signature (method)->params [1]))) ||
+                        (!strcmp (method->klass->name_space, "System.Threading") && !strcmp (method->klass->name, "Volatile") && (!strcmp (method->name, "Read") && MONO_TYPE_IS_REFERENCE (mini_type_get_underlying_type (NULL, mono_method_signature (method)->ret)))) ||
+                        (!strcmp (method->klass->name_space, "System.Threading") && !strcmp (method->klass->name, "Volatile") && (!strcmp (method->name, "Write") && MONO_TYPE_IS_REFERENCE (mini_type_get_underlying_type (NULL, mono_method_signature (method)->params [1])))))) {
                        MonoError error;
                        MonoMethod *m;
                        MonoGenericContext ctx;
@@ -4326,6 +4432,11 @@ init_plt (MonoAotModule *amodule)
        if (amodule->plt_inited)
                return;
 
+       if (amodule->info.plt_size <= 1) {
+               amodule->plt_inited = TRUE;
+               return;
+       }
+
        tramp = mono_create_specific_trampoline (amodule, MONO_TRAMPOLINE_AOT_PLT, mono_get_root_domain (), NULL);
 
        /*
@@ -4596,6 +4707,12 @@ get_mscorlib_aot_module (void)
        return amodule;
 }
 
+static void
+no_trampolines (void)
+{
+       g_assert_not_reached ();
+}
+
 /*
  * Return the trampoline identified by NAME from the mscorlib AOT file.
  * On ppc64, this returns a function descriptor.
@@ -4605,6 +4722,11 @@ mono_aot_get_trampoline_full (const char *name, MonoTrampInfo **out_tinfo)
 {
        MonoAotModule *amodule = get_mscorlib_aot_module ();
 
+       /*
+       if (mono_llvm_only)
+               return no_trampolines;
+       */
+
        return mono_create_ftnptr_malloc (load_function_full (amodule, name, out_tinfo));
 }
 
@@ -4994,6 +5116,14 @@ mono_aot_get_unbox_trampoline (MonoMethod *method)
                g_assert (amodule);
        }
 
+       if (amodule->info.llvm_get_unbox_tramp) {
+               gpointer (*get_tramp) (int) = amodule->info.llvm_get_unbox_tramp;
+               code = get_tramp (method_index);
+
+               if (code)
+                       return code;
+       }
+
        ut = amodule->unbox_trampolines;
        ut_end = amodule->unbox_trampolines_end;