[mini] Rename mini_parse_debug_option's argument to match the header file (and match...
[mono.git] / mono / mini / mini-runtime.c
index e7db1b4318e9510d6a1cf88acf700515114defe8..7bd111d26323e164a09d378956f2786c173a76ad 100644 (file)
@@ -167,7 +167,7 @@ get_method_from_ip (void *ip)
        if (!domain)
                domain = mono_get_root_domain ();
 
-       ji = mono_jit_info_table_find_internal (domain, ip, TRUE, TRUE);
+       ji = mono_jit_info_table_find_internal (domain, (char *)ip, TRUE, TRUE);
        if (!ji) {
                user_data.ip = ip;
                user_data.method = NULL;
@@ -244,9 +244,9 @@ mono_print_method_from_ip (void *ip)
        MonoGenericSharingContext*gsctx;
        const char *shared_type;
 
-       ji = mini_jit_info_table_find_ext (domain, ip, TRUE, &target_domain);
+       ji = mini_jit_info_table_find_ext (domain, (char *)ip, TRUE, &target_domain);
        if (ji && ji->is_trampoline) {
-               MonoTrampInfo *tinfo = ji->d.tramp_info;
+               MonoTrampInfo *tinfo = (MonoTrampInfo *)ji->d.tramp_info;
 
                printf ("IP %p is at offset 0x%x of trampoline '%s'.\n", ip, (int)((guint8*)ip - tinfo->code), tinfo->name);
                return;
@@ -437,7 +437,7 @@ mono_create_unwind_op (int when, int tag, int reg, int val)
 MonoJumpInfoToken *
 mono_jump_info_token_new2 (MonoMemPool *mp, MonoImage *image, guint32 token, MonoGenericContext *context)
 {
-       MonoJumpInfoToken *res = mono_mempool_alloc0 (mp, sizeof (MonoJumpInfoToken));
+       MonoJumpInfoToken *res = (MonoJumpInfoToken *)mono_mempool_alloc0 (mp, sizeof (MonoJumpInfoToken));
        res->image = image;
        res->token = token;
        res->has_context = context != NULL;
@@ -488,8 +488,8 @@ register_trampoline_jit_info (MonoDomain *domain, MonoTrampInfo *info)
 {
        MonoJitInfo *ji;
 
-       ji = mono_domain_alloc0 (domain, mono_jit_info_size (0, 0, 0));
-       mono_jit_info_init (ji, NULL, info->code, info->code_size, 0, 0, 0);
+       ji = (MonoJitInfo *)mono_domain_alloc0 (domain, mono_jit_info_size ((MonoJitInfoFlags)0, 0, 0));
+       mono_jit_info_init (ji, NULL, info->code, info->code_size, (MonoJitInfoFlags)0, 0, 0);
        ji->d.tramp_info = info;
        ji->is_trampoline = TRUE;
 
@@ -551,7 +551,7 @@ mono_tramp_info_cleanup (void)
        GSList *l;
 
        for (l = tramp_infos; l; l = l->next) {
-               MonoTrampInfo *info = l->data;
+               MonoTrampInfo *info = (MonoTrampInfo *)l->data;
 
                mono_tramp_info_free (info);
        }
@@ -565,7 +565,7 @@ register_trampolines (MonoDomain *domain)
        GSList *l;
 
        for (l = tramp_infos; l; l = l->next) {
-               MonoTrampInfo *info = l->data;
+               MonoTrampInfo *info = (MonoTrampInfo *)l->data;
 
                register_trampoline_jit_info (domain, info);
        }
@@ -656,7 +656,7 @@ mono_dynamic_code_hash_lookup (MonoDomain *domain, MonoMethod *method)
        MonoJitDynamicMethodInfo *res;
 
        if (domain_jit_info (domain)->dynamic_code_hash)
-               res = g_hash_table_lookup (domain_jit_info (domain)->dynamic_code_hash, method);
+               res = (MonoJitDynamicMethodInfo *)g_hash_table_lookup (domain_jit_info (domain)->dynamic_code_hash, method);
        else
                res = NULL;
        return res;
@@ -775,7 +775,7 @@ MonoLMF *
 mono_get_lmf (void)
 {
 #if defined(MONO_HAVE_FAST_TLS) && defined(MONO_ARCH_ENABLE_MONO_LMF_VAR)
-       return MONO_FAST_TLS_GET (mono_lmf);
+       return (MonoLMF *)MONO_FAST_TLS_GET (mono_lmf);
 #else
        MonoJitTlsData *jit_tls;
 
@@ -794,7 +794,7 @@ MonoLMF **
 mono_get_lmf_addr (void)
 {
 #ifdef MONO_HAVE_FAST_TLS
-       return MONO_FAST_TLS_GET (mono_lmf_addr);
+       return (MonoLMF **)MONO_FAST_TLS_GET (mono_lmf_addr);
 #else
        MonoJitTlsData *jit_tls;
 
@@ -833,7 +833,7 @@ mono_set_lmf (MonoLMF *lmf)
 MonoJitTlsData*
 mono_get_jit_tls (void)
 {
-       return mono_native_tls_get_value (mono_jit_tls_id);
+       return (MonoJitTlsData *)mono_native_tls_get_value (mono_jit_tls_id);
 }
 
 static void
@@ -941,13 +941,13 @@ setup_jit_tls_data (gpointer stack_start, gpointer abort_func)
        MonoJitTlsData *jit_tls;
        MonoLMF *lmf;
 
-       jit_tls = mono_native_tls_get_value (mono_jit_tls_id);
+       jit_tls = (MonoJitTlsData *)mono_native_tls_get_value (mono_jit_tls_id);
        if (jit_tls)
                return jit_tls;
 
        jit_tls = g_new0 (MonoJitTlsData, 1);
 
-       jit_tls->abort_func = abort_func;
+       jit_tls->abort_func = (void (*)(MonoObject *))abort_func;
        jit_tls->end_of_stack = stack_start;
 
        mono_set_jit_tls (jit_tls);
@@ -1038,7 +1038,7 @@ mini_thread_cleanup (MonoNativeThreadId tid)
         * The current offender is mono_thread_manage which cleanup threads from the outside.
         */
        if (info && mono_thread_info_get_tid (info) == tid) {
-               jit_tls = info->jit_data;
+               jit_tls = (MonoJitTlsData *)info->jit_data;
                info->jit_data = NULL;
 
                mono_set_jit_tls (NULL);
@@ -1051,7 +1051,7 @@ mini_thread_cleanup (MonoNativeThreadId tid)
        } else {
                info = mono_thread_info_lookup (tid);
                if (info) {
-                       jit_tls = info->jit_data;
+                       jit_tls = (MonoJitTlsData *)info->jit_data;
                        info->jit_data = NULL;
                }
                mono_hazard_pointer_clear (mono_hazard_pointer_get (), 1);
@@ -1122,7 +1122,7 @@ mono_patch_info_list_prepend (MonoJumpInfo *list, int ip, MonoJumpInfoType type,
 MonoJumpInfo*
 mono_patch_info_dup_mp (MonoMemPool *mp, MonoJumpInfo *patch_info)
 {
-       MonoJumpInfo *res = mono_mempool_alloc (mp, sizeof (MonoJumpInfo));
+       MonoJumpInfo *res = (MonoJumpInfo *)mono_mempool_alloc (mp, sizeof (MonoJumpInfo));
        memcpy (res, patch_info, sizeof (MonoJumpInfo));
 
        switch (patch_info->type) {
@@ -1131,27 +1131,27 @@ mono_patch_info_dup_mp (MonoMemPool *mp, MonoJumpInfo *patch_info)
        case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
        case MONO_PATCH_INFO_LDTOKEN:
        case MONO_PATCH_INFO_DECLSEC:
-               res->data.token = mono_mempool_alloc (mp, sizeof (MonoJumpInfoToken));
+               res->data.token = (MonoJumpInfoToken *)mono_mempool_alloc (mp, sizeof (MonoJumpInfoToken));
                memcpy (res->data.token, patch_info->data.token, sizeof (MonoJumpInfoToken));
                break;
        case MONO_PATCH_INFO_SWITCH:
-               res->data.table = mono_mempool_alloc (mp, sizeof (MonoJumpInfoBBTable));
+               res->data.table = (MonoJumpInfoBBTable *)mono_mempool_alloc (mp, sizeof (MonoJumpInfoBBTable));
                memcpy (res->data.table, patch_info->data.table, sizeof (MonoJumpInfoBBTable));
-               res->data.table->table = mono_mempool_alloc (mp, sizeof (MonoBasicBlock*) * patch_info->data.table->table_size);
+               res->data.table->table = (MonoBasicBlock **)mono_mempool_alloc (mp, sizeof (MonoBasicBlock*) * patch_info->data.table->table_size);
                memcpy (res->data.table->table, patch_info->data.table->table, sizeof (MonoBasicBlock*) * patch_info->data.table->table_size);
                break;
        case MONO_PATCH_INFO_RGCTX_FETCH:
        case MONO_PATCH_INFO_RGCTX_SLOT_INDEX:
-               res->data.rgctx_entry = mono_mempool_alloc (mp, sizeof (MonoJumpInfoRgctxEntry));
+               res->data.rgctx_entry = (MonoJumpInfoRgctxEntry *)mono_mempool_alloc (mp, sizeof (MonoJumpInfoRgctxEntry));
                memcpy (res->data.rgctx_entry, patch_info->data.rgctx_entry, sizeof (MonoJumpInfoRgctxEntry));
                res->data.rgctx_entry->data = mono_patch_info_dup_mp (mp, res->data.rgctx_entry->data);
                break;
        case MONO_PATCH_INFO_DELEGATE_TRAMPOLINE:
-               res->data.del_tramp = mono_mempool_alloc0 (mp, sizeof (MonoDelegateClassMethodPair));
+               res->data.del_tramp = (MonoDelegateClassMethodPair *)mono_mempool_alloc0 (mp, sizeof (MonoDelegateClassMethodPair));
                memcpy (res->data.del_tramp, patch_info->data.del_tramp, sizeof (MonoDelegateClassMethodPair));
                break;
        case MONO_PATCH_INFO_GSHAREDVT_CALL:
-               res->data.gsharedvt = mono_mempool_alloc (mp, sizeof (MonoJumpInfoGSharedVtCall));
+               res->data.gsharedvt = (MonoJumpInfoGSharedVtCall *)mono_mempool_alloc (mp, sizeof (MonoJumpInfoGSharedVtCall));
                memcpy (res->data.gsharedvt, patch_info->data.gsharedvt, sizeof (MonoJumpInfoGSharedVtCall));
                break;
        case MONO_PATCH_INFO_GSHAREDVT_METHOD: {
@@ -1160,15 +1160,15 @@ mono_patch_info_dup_mp (MonoMemPool *mp, MonoJumpInfo *patch_info)
                int i;
 
                oinfo = patch_info->data.gsharedvt_method;
-               info = mono_mempool_alloc (mp, sizeof (MonoGSharedVtMethodInfo));
+               info = (MonoGSharedVtMethodInfo *)mono_mempool_alloc (mp, sizeof (MonoGSharedVtMethodInfo));
                res->data.gsharedvt_method = info;
                memcpy (info, oinfo, sizeof (MonoGSharedVtMethodInfo));
-               info->entries = mono_mempool_alloc (mp, sizeof (MonoRuntimeGenericContextInfoTemplate) * info->count_entries);
+               info->entries = (MonoRuntimeGenericContextInfoTemplate *)mono_mempool_alloc (mp, sizeof (MonoRuntimeGenericContextInfoTemplate) * info->count_entries);
                for (i = 0; i < oinfo->num_entries; ++i) {
                        MonoRuntimeGenericContextInfoTemplate *otemplate = &oinfo->entries [i];
-                       MonoRuntimeGenericContextInfoTemplate *template = &info->entries [i];
+                       MonoRuntimeGenericContextInfoTemplate *template_ = &info->entries [i];
 
-                       memcpy (template, otemplate, sizeof (MonoRuntimeGenericContextInfoTemplate));
+                       memcpy (template_, otemplate, sizeof (MonoRuntimeGenericContextInfoTemplate));
                }
                //info->locals_types = mono_mempool_alloc0 (mp, info->nlocals * sizeof (MonoType*));
                //memcpy (info->locals_types, oinfo->locals_types, info->nlocals * sizeof (MonoType*));
@@ -1179,7 +1179,7 @@ mono_patch_info_dup_mp (MonoMemPool *mp, MonoJumpInfo *patch_info)
                MonoJumpInfoVirtMethod *oinfo;
 
                oinfo = patch_info->data.virt_method;
-               info = mono_mempool_alloc0 (mp, sizeof (MonoJumpInfoVirtMethod));
+               info = (MonoJumpInfoVirtMethod *)mono_mempool_alloc0 (mp, sizeof (MonoJumpInfoVirtMethod));
                res->data.virt_method = info;
                memcpy (info, oinfo, sizeof (MonoJumpInfoVirtMethod));
                break;
@@ -1445,12 +1445,12 @@ mono_resolve_patch_target (MonoMethod *method, MonoDomain *domain, guint8 *code,
                jump_table = g_malloc0 (sizeof(gpointer) * patch_info->data.table->table_size);
 #else
                if (method && method->dynamic) {
-                       jump_table = mono_code_manager_reserve (mono_dynamic_code_hash_lookup (domain, method)->code_mp, sizeof (gpointer) * patch_info->data.table->table_size);
+                       jump_table = (void **)mono_code_manager_reserve (mono_dynamic_code_hash_lookup (domain, method)->code_mp, sizeof (gpointer) * patch_info->data.table->table_size);
                } else {
                        if (mono_aot_only) {
-                               jump_table = mono_domain_alloc (domain, sizeof (gpointer) * patch_info->data.table->table_size);
+                               jump_table = (void **)mono_domain_alloc (domain, sizeof (gpointer) * patch_info->data.table->table_size);
                        } else {
-                               jump_table = mono_domain_code_reserve (domain, sizeof (gpointer) * patch_info->data.table->table_size);
+                               jump_table = (void **)mono_domain_code_reserve (domain, sizeof (gpointer) * patch_info->data.table->table_size);
                        }
                }
 #endif
@@ -1560,10 +1560,10 @@ mono_resolve_patch_target (MonoMethod *method, MonoDomain *domain, guint8 *code,
                if (!mono_error_ok (&error))
                        g_error ("Could not patch ldtoken due to %s", mono_error_get_message (&error));
                mono_class_init (handle_class);
-               mono_class_init (mono_class_from_mono_type (handle));
+               mono_class_init (mono_class_from_mono_type ((MonoType *)handle));
 
                target =
-                       mono_type_get_object (domain, handle);
+                       mono_type_get_object (domain, (MonoType *)handle);
                break;
        }
        case MONO_PATCH_INFO_LDTOKEN: {
@@ -1676,7 +1676,7 @@ mono_resolve_patch_target (MonoMethod *method, MonoDomain *domain, guint8 *code,
        case MONO_PATCH_INFO_TLS_OFFSET: {
                int offset;
 
-               offset = mini_get_tls_offset (GPOINTER_TO_INT (patch_info->data.target));
+               offset = mini_get_tls_offset ((MonoTlsKey)GPOINTER_TO_INT (patch_info->data.target));
 #ifdef MONO_ARCH_HAVE_TRANSLATE_TLS_OFFSET
                offset = mono_arch_translate_tls_offset (offset);
 #endif
@@ -1691,8 +1691,8 @@ mono_resolve_patch_target (MonoMethod *method, MonoDomain *domain, guint8 *code,
                int len;
                char *s;
 
-               len = strlen (patch_info->data.target);
-               s = mono_domain_alloc0 (domain, len + 1);
+               len = strlen ((const char *)patch_info->data.target);
+               s = (char *)mono_domain_alloc0 (domain, len + 1);
                memcpy (s, patch_info->data.target, len);
                target = s;
 
@@ -1746,10 +1746,10 @@ mini_lookup_method (MonoDomain *domain, MonoMethod *method, MonoMethod *shared)
        static int failed_lookups = 0;
 
        mono_domain_jit_code_hash_lock (domain);
-       ji = mono_internal_hash_table_lookup (&domain->jit_code_hash, method);
+       ji = (MonoJitInfo *)mono_internal_hash_table_lookup (&domain->jit_code_hash, method);
        if (!ji && shared) {
                /* Try generic sharing */
-               ji = mono_internal_hash_table_lookup (&domain->jit_code_hash, shared);
+               ji = (MonoJitInfo *)mono_internal_hash_table_lookup (&domain->jit_code_hash, shared);
                if (ji && !ji->has_generic_jit_info)
                        ji = NULL;
                if (!inited) {
@@ -1830,6 +1830,12 @@ mono_jit_map_is_enabled (void)
 
 #endif
 
+static void
+no_gsharedvt_in_wrapper (void)
+{
+       g_assert_not_reached ();
+}
+
 static gpointer
 mono_jit_compile_method_with_opt (MonoMethod *method, guint32 opt, MonoException **ex)
 {
@@ -1852,14 +1858,10 @@ mono_jit_compile_method_with_opt (MonoMethod *method, guint32 opt, MonoException
 
                /* Must be domain neutral since there is only one copy */
                opt |= MONO_OPT_SHARED;
-       }
-
-       if (method->dynamic)
-               opt &= ~MONO_OPT_SHARED;
-
-       /* These methods can become invalid when a domain is unloaded */
-       if (method->klass->image != mono_get_corlib () || method->is_inflated)
+       } else {
+               /* MONO_OPT_SHARED is no longer supported, we only use it for icall wrappers */
                opt &= ~MONO_OPT_SHARED;
+       }
 
        if (opt & MONO_OPT_SHARED)
                target_domain = mono_get_root_domain ();
@@ -1929,6 +1931,19 @@ mono_jit_compile_method_with_opt (MonoMethod *method, guint32 opt, MonoException
                code = mono_jit_compile_method_inner (method, target_domain, opt, ex);
 
        if (!code && mono_llvm_only) {
+               if (method->wrapper_type == MONO_WRAPPER_UNKNOWN) {
+                       WrapperInfo *info = mono_marshal_get_wrapper_info (method);
+
+                       if (info->subtype == WRAPPER_SUBTYPE_GSHAREDVT_IN_SIG) {
+                               /*
+                                * These wrappers are only created for signatures which are in the program, but
+                                * sometimes we load methods too eagerly and have to create them even if they
+                                * will never be called.
+                                */
+                               return no_gsharedvt_in_wrapper;
+                       }
+               }
+
                printf ("AOT method not found in llvmonly mode: %s\n", mono_method_full_name (method, 1));
                g_assert_not_reached ();
        }
@@ -1942,7 +1957,7 @@ mono_jit_compile_method_with_opt (MonoMethod *method, guint32 opt, MonoException
                /*
                 * SGEN requires the JIT info for these methods to be registered, see is_ip_in_managed_allocator ().
                 */
-               ji = mini_jit_info_table_find (mono_domain_get (), code, &d);
+               ji = mini_jit_info_table_find (mono_domain_get (), (char *)code, &d);
                g_assert (ji);
        }
 
@@ -2029,13 +2044,13 @@ mono_jit_free_method (MonoDomain *domain, MonoMethod *method)
 
                remove = NULL;
                for (tmp = jlist->list; tmp; tmp = tmp->next) {
-                       guint8 *ip = tmp->data;
+                       guint8 *ip = (guint8 *)tmp->data;
 
                        if (ip >= (guint8*)ji->ji->code_start && ip < (guint8*)ji->ji->code_start + ji->ji->code_size)
                                remove = g_slist_prepend (remove, tmp);
                }
                for (tmp = remove; tmp; tmp = tmp->next) {
-                       jlist->list = g_slist_delete_link (jlist->list, tmp->data);
+                       jlist->list = g_slist_delete_link ((GSList *)jlist->list, (GSList *)tmp->data);
                }
                g_slist_free (remove);
        }
@@ -2096,6 +2111,32 @@ mono_jit_find_compiled_method_with_jit_info (MonoDomain *domain, MonoMethod *met
        return NULL;
 }
 
+static guint32 bisect_opt = 0;
+static GHashTable *bisect_methods_hash = NULL;
+
+void
+mono_set_bisect_methods (guint32 opt, const char *method_list_filename)
+{
+       FILE *file;
+       char method_name [2048];
+
+       bisect_opt = opt;
+       bisect_methods_hash = g_hash_table_new (g_str_hash, g_str_equal);
+       g_assert (bisect_methods_hash);
+
+       file = fopen (method_list_filename, "r");
+       g_assert (file);
+
+       while (fgets (method_name, sizeof (method_name), file)) {
+               size_t len = strlen (method_name);
+               g_assert (len > 0);
+               g_assert (method_name [len - 1] == '\n');
+               method_name [len - 1] = 0;
+               g_hash_table_insert (bisect_methods_hash, g_strdup (method_name), GINT_TO_POINTER (1));
+       }
+       g_assert (feof (file));
+}
+
 gboolean mono_do_single_method_regression = FALSE;
 guint32 mono_single_method_regression_opt = 0;
 MonoMethod *mono_current_single_method;
@@ -2107,6 +2148,13 @@ mono_get_optimizations_for_method (MonoMethod *method, guint32 default_opt)
 {
        g_assert (method);
 
+       if (bisect_methods_hash) {
+               char *name = mono_method_full_name (method, TRUE);
+               void *res = g_hash_table_lookup (bisect_methods_hash, name);
+               g_free (name);
+               if (res)
+                       return default_opt | bisect_opt;
+       }
        if (!mono_do_single_method_regression)
                return default_opt;
        if (!mono_current_single_method) {
@@ -2136,9 +2184,206 @@ typedef struct {
        MonoVTable *vtable;
        MonoDynCallInfo *dyn_call_info;
        MonoClass *ret_box_class;
-       gboolean needs_rgctx;
+       MonoMethodSignature *sig;
+       gboolean gsharedvt_invoke;
+       gpointer *wrapper_arg;
 } RuntimeInvokeInfo;
 
+static RuntimeInvokeInfo*
+create_runtime_invoke_info (MonoDomain *domain, MonoMethod *method, gpointer compiled_method, gboolean callee_gsharedvt)
+{
+       MonoMethod *invoke;
+       RuntimeInvokeInfo *info;
+
+       info = g_new0 (RuntimeInvokeInfo, 1);
+       info->compiled_method = compiled_method;
+       info->sig = mono_method_signature (method);
+
+       invoke = mono_marshal_get_runtime_invoke (method, FALSE);
+       info->vtable = mono_class_vtable_full (domain, method->klass, TRUE);
+       g_assert (info->vtable);
+
+       MonoMethodSignature *sig = mono_method_signature (method);
+       MonoType *ret_type;
+
+       /*
+        * We want to avoid AOTing 1000s of runtime-invoke wrappers when running
+        * in full-aot mode, so we use a slower, but more generic wrapper if
+        * possible, built on top of the OP_DYN_CALL opcode provided by the JIT.
+        */
+#ifdef MONO_ARCH_DYN_CALL_SUPPORTED
+       if (!mono_llvm_only && (mono_aot_only || debug_options.dyn_runtime_invoke)) {
+               gboolean supported = TRUE;
+               int i;
+
+               if (method->string_ctor)
+                       sig = mono_marshal_get_string_ctor_signature (method);
+
+               for (i = 0; i < sig->param_count; ++i) {
+                       MonoType *t = sig->params [i];
+
+                       if (t->byref && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t)))
+                               supported = FALSE;
+               }
+
+               if (mono_class_is_contextbound (method->klass) || !info->compiled_method)
+                       supported = FALSE;
+
+               if (supported)
+                       info->dyn_call_info = mono_arch_dyn_call_prepare (sig);
+       }
+#endif
+
+       ret_type = sig->ret;
+       switch (ret_type->type) {
+       case MONO_TYPE_VOID:
+               break;
+       case MONO_TYPE_I1:
+       case MONO_TYPE_U1:
+       case MONO_TYPE_I2:
+       case MONO_TYPE_U2:
+       case MONO_TYPE_I4:
+       case MONO_TYPE_U4:
+       case MONO_TYPE_I:
+       case MONO_TYPE_U:
+       case MONO_TYPE_I8:
+       case MONO_TYPE_U8:
+       case MONO_TYPE_BOOLEAN:
+       case MONO_TYPE_CHAR:
+       case MONO_TYPE_R4:
+       case MONO_TYPE_R8:
+               info->ret_box_class = mono_class_from_mono_type (ret_type);
+               break;
+       case MONO_TYPE_PTR:
+               info->ret_box_class = mono_defaults.int_class;
+               break;
+       case MONO_TYPE_STRING:
+       case MONO_TYPE_CLASS:
+       case MONO_TYPE_ARRAY:
+       case MONO_TYPE_SZARRAY:
+       case MONO_TYPE_OBJECT:
+               break;
+       case MONO_TYPE_GENERICINST:
+               if (!MONO_TYPE_IS_REFERENCE (ret_type))
+                       info->ret_box_class = mono_class_from_mono_type (ret_type);
+               break;
+       case MONO_TYPE_VALUETYPE:
+               info->ret_box_class = mono_class_from_mono_type (ret_type);
+               break;
+       default:
+               g_assert_not_reached ();
+               break;
+       }
+
+       if (!info->dyn_call_info) {
+               if (mono_llvm_only) {
+#ifndef ENABLE_GSHAREDVT
+                       g_assert_not_reached ();
+#endif
+                       if (!callee_gsharedvt) {
+                               /* Invoke a gsharedvt out wrapper instead */
+                               MonoMethod *wrapper = mini_get_gsharedvt_out_sig_wrapper (sig);
+                               MonoMethodSignature *wrapper_sig = mini_get_gsharedvt_out_sig_wrapper_signature (sig->hasthis, sig->ret->type != MONO_TYPE_VOID, sig->param_count);
+
+                               info->gsharedvt_invoke = TRUE;
+                               info->wrapper_arg = g_malloc0 (2 * sizeof (gpointer));
+                               info->wrapper_arg [0] = info->compiled_method;
+                               info->wrapper_arg [1] = mono_method_needs_static_rgctx_invoke (method, TRUE) ? mini_method_get_rgctx (method) : NULL;
+
+                               /* Pass has_rgctx == TRUE since the wrapper has an extra arg */
+                               invoke = mono_marshal_get_runtime_invoke_for_sig (wrapper_sig);
+                               g_free (wrapper_sig);
+
+                               info->compiled_method = mono_jit_compile_method (wrapper);
+                       } else {
+                               /* Gsharedvt methods can be invoked the same way */
+                               /* The out wrapper has the same signature as the compiled gsharedvt method */
+                               MonoMethodSignature *wrapper_sig = mini_get_gsharedvt_out_sig_wrapper_signature (sig->hasthis, sig->ret->type != MONO_TYPE_VOID, sig->param_count);
+
+                               info->gsharedvt_invoke = TRUE;
+                               info->wrapper_arg = mono_method_needs_static_rgctx_invoke (method, TRUE) ? mini_method_get_rgctx (method) : NULL;
+
+                               invoke = mono_marshal_get_runtime_invoke_for_sig (wrapper_sig);
+                               g_free (wrapper_sig);
+                       }
+               }
+               info->runtime_invoke = mono_jit_compile_method (invoke);
+       }
+
+       return info;
+}
+
+static MonoObject*
+mono_llvmonly_runtime_invoke (MonoMethod *method, RuntimeInvokeInfo *info, void *obj, void **params, MonoObject **exc)
+{
+       MonoMethodSignature *sig = info->sig;
+       MonoDomain *domain = mono_domain_get ();
+       MonoObject *(*runtime_invoke) (MonoObject *this_obj, void **params, MonoObject **exc, void* compiled_method);
+       gpointer *args;
+       gpointer retval_ptr;
+       guint8 retval [256];
+       gpointer *param_refs;
+       int i, pindex;
+
+       g_assert (info->gsharedvt_invoke);
+
+       /*
+        * Instead of invoking the method directly, we invoke a gsharedvt out wrapper.
+        * The advantage of this is the gsharedvt out wrappers have a reduced set of
+        * signatures, so we only have to generate runtime invoke wrappers for these
+        * signatures.
+        * This code also handles invocation of gsharedvt methods directly, no
+        * out wrappers are used in that case.
+        */
+       args = (void **)g_alloca ((sig->param_count + sig->hasthis + 2) * sizeof (gpointer));
+       param_refs = (gpointer*)g_alloca ((sig->param_count + sig->hasthis + 2) * sizeof (gpointer));
+       pindex = 0;
+       /*
+        * The runtime invoke wrappers expects pointers to primitive types, so have to
+        * use indirections.
+        */
+       if (sig->hasthis)
+               args [pindex ++] = &obj;
+       if (sig->ret->type != MONO_TYPE_VOID) {
+               retval_ptr = (gpointer)&retval;
+               args [pindex ++] = &retval_ptr;
+       }
+       for (i = 0; i < sig->param_count; ++i) {
+               MonoType *t = sig->params [i];
+
+               if (t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t))) {
+                       MonoClass *klass = mono_class_from_mono_type (t);
+                       guint8 *nullable_buf;
+                       int size;
+
+                       size = mono_class_value_size (klass, NULL);
+                       nullable_buf = g_alloca (size);
+                       g_assert (nullable_buf);
+
+                       /* The argument pointed to by params [i] is either a boxed vtype or null */
+                       mono_nullable_init (nullable_buf, (MonoObject*)params [i], klass);
+                       params [i] = nullable_buf;
+               }
+
+               if (MONO_TYPE_IS_REFERENCE (t)) {
+                       param_refs [i] = params [i];
+                       params [i] = &(param_refs [i]);
+               }
+               args [pindex ++] = &params [i];
+       }
+       /* The gsharedvt out wrapper has an extra argument which contains the method to call */
+       args [pindex ++] = &info->wrapper_arg;
+
+       runtime_invoke = (MonoObject *(*)(MonoObject *, void **, MonoObject **, void *))info->runtime_invoke;
+
+       runtime_invoke (NULL, args, exc, info->compiled_method);
+
+       if (sig->ret->type != MONO_TYPE_VOID && info->ret_box_class)
+               return mono_value_box (domain, info->ret_box_class, retval);
+       else
+               return *(MonoObject**)retval;
+}
+
 /**
  * mono_jit_runtime_invoke:
  * @method: the method to invoke
@@ -2154,6 +2399,8 @@ mono_jit_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObjec
        MonoDomain *domain = mono_domain_get ();
        MonoJitDomainInfo *domain_info;
        RuntimeInvokeInfo *info, *info2;
+       MonoJitInfo *ji = NULL;
+       gboolean callee_gsharedvt = FALSE;
 
        if (obj == NULL && !(method->flags & METHOD_ATTRIBUTE_STATIC) && !method->string_ctor && (method->wrapper_type == 0)) {
                g_warning ("Ignoring invocation of an instance method on a NULL instance.\n");
@@ -2162,7 +2409,7 @@ mono_jit_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObjec
 
        domain_info = domain_jit_info (domain);
 
-       info = mono_conc_hashtable_lookup (domain_info->runtime_invoke_hash, method);
+       info = (RuntimeInvokeInfo *)mono_conc_hashtable_lookup (domain_info->runtime_invoke_hash, method);
 
        if (!info) {
                if (mono_security_core_clr_enabled ()) {
@@ -2180,12 +2427,7 @@ mono_jit_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObjec
                        }
                }
 
-               info = g_new0 (RuntimeInvokeInfo, 1);
-               info->needs_rgctx = mono_llvm_only && mono_method_needs_static_rgctx_invoke (method, TRUE);
-
-               invoke = mono_marshal_get_runtime_invoke (method, FALSE, info->needs_rgctx);
-               info->vtable = mono_class_vtable_full (domain, method->klass, TRUE);
-               g_assert (info->vtable);
+               gpointer compiled_method;
 
                callee = method;
                if (method->klass->rank && (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) &&
@@ -2201,7 +2443,7 @@ mono_jit_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObjec
                                MonoMethod *wrapper;
 
                                wrapper = mono_marshal_get_array_accessor_wrapper (method);
-                               invoke = mono_marshal_get_runtime_invoke (wrapper, FALSE, FALSE);
+                               invoke = mono_marshal_get_runtime_invoke (wrapper, FALSE);
                                callee = wrapper;
                        } else {
                                callee = NULL;
@@ -2211,9 +2453,8 @@ mono_jit_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObjec
                if (callee) {
                        MonoException *jit_ex = NULL;
 
-                       info->compiled_method = mono_jit_compile_method_with_opt (callee, mono_get_optimizations_for_method (callee, default_opt), &jit_ex);
-                       if (!info->compiled_method) {
-                               g_free (info);
+                       compiled_method = mono_jit_compile_method_with_opt (callee, mono_get_optimizations_for_method (callee, default_opt), &jit_ex);
+                       if (!compiled_method) {
                                g_assert (jit_ex);
                                if (exc) {
                                        *exc = (MonoObject*)jit_ex;
@@ -2224,90 +2465,21 @@ mono_jit_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObjec
                                }
                        }
 
-                       info->compiled_method = mini_add_method_trampoline (callee, info->compiled_method, mono_method_needs_static_rgctx_invoke (callee, TRUE), FALSE);
-               } else {
-                       info->compiled_method = NULL;
-               }
-
-               /*
-                * We want to avoid AOTing 1000s of runtime-invoke wrappers when running
-                * in full-aot mode, so we use a slower, but more generic wrapper if
-                * possible, built on top of the OP_DYN_CALL opcode provided by the JIT.
-                */
-#ifdef MONO_ARCH_DYN_CALL_SUPPORTED
-               if (!mono_llvm_only && (mono_aot_only || debug_options.dyn_runtime_invoke)) {
-                       MonoType *ret_type;
-                       MonoMethodSignature *sig = mono_method_signature (method);
-                       gboolean supported = TRUE;
-                       int i;
-
-                       if (method->string_ctor)
-                               sig = mono_marshal_get_string_ctor_signature (method);
-                       g_assert (!info->needs_rgctx);
-
-                       for (i = 0; i < sig->param_count; ++i) {
-                               MonoType *t = sig->params [i];
-
-                               if (t->byref && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t)))
-                                       supported = FALSE;
+                       if (mono_llvm_only) {
+                               ji = mini_jit_info_table_find (mono_domain_get (), (char *)mono_get_addr_from_ftnptr (compiled_method), NULL);
+                               callee_gsharedvt = mini_jit_info_is_gsharedvt (ji);
                        }
 
-                       if (mono_class_is_contextbound (method->klass) || !info->compiled_method)
-                               supported = FALSE;
-
-                       if (supported)
-                               info->dyn_call_info = mono_arch_dyn_call_prepare (sig);
-
-                       ret_type = sig->ret;
-                       if (info->dyn_call_info) {
-                               switch (ret_type->type) {
-                               case MONO_TYPE_VOID:
-                                       break;
-                               case MONO_TYPE_I1:
-                               case MONO_TYPE_U1:
-                               case MONO_TYPE_I2:
-                               case MONO_TYPE_U2:
-                               case MONO_TYPE_I4:
-                               case MONO_TYPE_U4:
-                               case MONO_TYPE_I:
-                               case MONO_TYPE_U:
-                               case MONO_TYPE_I8:
-                               case MONO_TYPE_U8:
-                               case MONO_TYPE_BOOLEAN:
-                               case MONO_TYPE_CHAR:
-                               case MONO_TYPE_R4:
-                               case MONO_TYPE_R8:
-                                       info->ret_box_class = mono_class_from_mono_type (ret_type);
-                                       break;
-                               case MONO_TYPE_PTR:
-                                       info->ret_box_class = mono_defaults.int_class;
-                                       break;
-                               case MONO_TYPE_STRING:
-                               case MONO_TYPE_CLASS:
-                               case MONO_TYPE_ARRAY:
-                               case MONO_TYPE_SZARRAY:
-                               case MONO_TYPE_OBJECT:
-                                       break;
-                               case MONO_TYPE_GENERICINST:
-                                       if (!MONO_TYPE_IS_REFERENCE (ret_type))
-                                               info->ret_box_class = mono_class_from_mono_type (ret_type);
-                                       break;
-                               case MONO_TYPE_VALUETYPE:
-                                       info->ret_box_class = mono_class_from_mono_type (ret_type);
-                                       break;
-                               default:
-                                       g_assert_not_reached ();
-                                       break;
-                               }
-                       }
+                       if (!callee_gsharedvt)
+                               compiled_method = mini_add_method_trampoline (callee, compiled_method, mono_method_needs_static_rgctx_invoke (callee, TRUE), FALSE);
+               } else {
+                       compiled_method = NULL;
                }
-#endif
 
-               if (!info->dyn_call_info)
-                       info->runtime_invoke = mono_jit_compile_method (invoke);
+               info = create_runtime_invoke_info (domain, method, compiled_method, callee_gsharedvt);
 
                mono_domain_lock (domain);
-               info2 = mono_conc_hashtable_insert (domain_info->runtime_invoke_hash, method, info);
+               info2 = (RuntimeInvokeInfo *)mono_conc_hashtable_insert (domain_info->runtime_invoke_hash, method, info);
                mono_domain_unlock (domain);
                if (info2) {
                        g_free (info);
@@ -2315,8 +2487,6 @@ mono_jit_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObjec
                }
        }
 
-       runtime_invoke = info->runtime_invoke;
-
        /*
         * We need this here because mono_marshal_get_runtime_invoke can place
         * the helper method in System.Object and not the target class.
@@ -2341,15 +2511,14 @@ mono_jit_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObjec
                int i, pindex;
                guint8 buf [512];
                guint8 retval [256];
-               gpointer rgctx;
 
                if (!dyn_runtime_invoke) {
                        invoke = mono_marshal_get_runtime_invoke_dynamic ();
-                       dyn_runtime_invoke = mono_jit_compile_method (invoke);
+                       dyn_runtime_invoke = (RuntimeInvokeDynamicFunction)mono_jit_compile_method (invoke);
                }
 
                /* Convert the arguments to the format expected by start_dyn_call () */
-               args = g_alloca ((sig->param_count + sig->hasthis + info->needs_rgctx) * sizeof (gpointer));
+               args = (void **)g_alloca ((sig->param_count + sig->hasthis) * sizeof (gpointer));
                pindex = 0;
                if (sig->hasthis)
                        args [pindex ++] = &obj;
@@ -2364,10 +2533,6 @@ mono_jit_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObjec
                                args [pindex ++] = params [i];
                        }
                }
-               if (info->needs_rgctx) {
-                       rgctx = mini_method_get_rgctx (method);
-                       args [pindex ++] = &rgctx;
-               }
 
                //printf ("M: %s\n", mono_method_full_name (method, TRUE));
 
@@ -2384,22 +2549,195 @@ mono_jit_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObjec
        }
 #endif
 
-       if (info->needs_rgctx) {
-               MonoMethodSignature *sig = mono_method_signature (method);
-               gpointer rgctx;
-               gpointer *args;
-               int i, pindex;
+       if (mono_llvm_only)
+               return mono_llvmonly_runtime_invoke (method, info, obj, params, exc);
 
-               args = g_alloca ((sig->param_count + sig->hasthis + info->needs_rgctx) * sizeof (gpointer));
-               pindex = 0;
-               rgctx = mini_method_get_rgctx (method);
-               for (i = 0; i < sig->param_count; ++i)
-                       args [pindex ++] = params [i];
-               args [pindex ++] = &rgctx;
-               return runtime_invoke (obj, args, exc, info->compiled_method);
-       } else {
-               return runtime_invoke (obj, params, exc, info->compiled_method);
+       runtime_invoke = (MonoObject *(*)(MonoObject *, void **, MonoObject **, void *))info->runtime_invoke;
+
+       return runtime_invoke ((MonoObject *)obj, params, exc, info->compiled_method);
+}
+
+typedef struct {
+       MonoVTable *vtable;
+       int slot;
+} IMTThunkInfo;
+
+typedef gpointer (*IMTThunkFunc) (gpointer *arg, MonoMethod *imt_method);
+
+/*
+ * mini_llvmonly_initial_imt_thunk:
+ *
+ *  This function is called the first time a call is made through an IMT thunk.
+ * It should have the same signature as the mono_llvmonly_imt_thunk_... functions.
+ */
+static gpointer
+mini_llvmonly_initial_imt_thunk (gpointer *arg, MonoMethod *imt_method)
+{
+       IMTThunkInfo *info = (IMTThunkInfo*)arg;
+       gpointer *imt;
+       gpointer *ftndesc;
+       IMTThunkFunc func;
+
+       mono_vtable_build_imt_slot (info->vtable, info->slot);
+
+       imt = (gpointer*)info->vtable;
+       imt -= MONO_IMT_SIZE;
+
+       /* Return what the real IMT thunk returns */
+       ftndesc = imt [info->slot];
+       func = ftndesc [0];
+
+       if (func == (IMTThunkFunc)mini_llvmonly_initial_imt_thunk)
+               /* Happens when the imt slot contains only a generic virtual method */
+               return NULL;
+       return func ((gpointer *)ftndesc [1], imt_method);
+}
+
+/* This is called indirectly through an imt slot. */
+static gpointer
+mono_llvmonly_imt_thunk (gpointer *arg, MonoMethod *imt_method)
+{
+       int i = 0;
+
+       /* arg points to an array created in mono_llvmonly_get_imt_thunk () */
+       while (arg [i] && arg [i] != imt_method)
+               i += 2;
+       g_assert (arg [i]);
+
+       return arg [i + 1];
+}
+
+/* Optimized versions of mono_llvmonly_imt_thunk () for different table sizes */
+static gpointer
+mono_llvmonly_imt_thunk_1 (gpointer *arg, MonoMethod *imt_method)
+{
+       //g_assert (arg [0] == imt_method);
+       return arg [1];
+}
+
+static gpointer
+mono_llvmonly_imt_thunk_2 (gpointer *arg, MonoMethod *imt_method)
+{
+       //g_assert (arg [0] == imt_method || arg [2] == imt_method);
+       if (arg [0] == imt_method)
+               return arg [1];
+       else
+               return arg [3];
+}
+
+static gpointer
+mono_llvmonly_imt_thunk_3 (gpointer *arg, MonoMethod *imt_method)
+{
+       //g_assert (arg [0] == imt_method || arg [2] == imt_method || arg [4] == imt_method);
+       if (arg [0] == imt_method)
+               return arg [1];
+       else if (arg [2] == imt_method)
+               return arg [3];
+       else
+               return arg [5];
+}
+
+/*
+ * A version of the imt thunk used for generic virtual methods.
+ * Unlikely a normal imt thunk, its possible that IMT_METHOD is not found
+ * in the search table. The original JIT code had a 'fallback' trampoline it could
+ * call, but we can't do that, so we just return NULL, and the compiled code
+ * will handle it.
+ */
+static gpointer
+mono_llvmonly_generic_virtual_imt_thunk (gpointer *arg, MonoMethod *imt_method)
+{
+       int i = 0;
+
+       while (arg [i] && arg [i] != imt_method)
+               i += 2;
+       if (!arg [i])
+               return NULL;
+
+       return arg [i + 1];
+}
+
+static gpointer
+mono_llvmonly_get_imt_thunk (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckItem **imt_entries, int count, gpointer fail_tramp)
+{
+       gpointer *buf;
+       gpointer *res;
+       int i, index, real_count;
+       gboolean virtual_generic = FALSE;
+
+       /*
+        * Create an array which is passed to the imt thunk functions.
+        * The array contains MonoMethod-function descriptor pairs, terminated by a NULL entry.
+        */
+
+       real_count = 0;
+       for (i = 0; i < count; ++i) {
+               MonoIMTCheckItem *item = imt_entries [i];
+
+               if (item->is_equals)
+                       real_count ++;
+               if (item->has_target_code)
+                       virtual_generic = TRUE;
+       }
+
+       /*
+        * Initialize all vtable entries reachable from this imt slot, so the compiled
+        * code doesn't have to check it.
+        */
+       for (i = 0; i < count; ++i) {
+               MonoIMTCheckItem *item = imt_entries [i];
+               int vt_slot;
+
+               if (!item->is_equals || item->has_target_code)
+                       continue;
+               vt_slot = item->value.vtable_slot;
+               mono_init_vtable_slot (vtable, vt_slot);
        }
+
+       /* Save the entries into an array */
+       buf = (void **)mono_domain_alloc (domain, (real_count + 1) * 2 * sizeof (gpointer));
+       index = 0;
+       for (i = 0; i < count; ++i) {
+               MonoIMTCheckItem *item = imt_entries [i];
+
+               if (!item->is_equals)
+                       continue;
+
+               g_assert (item->key);
+               buf [(index * 2)] = item->key;
+               if (item->has_target_code)
+                       buf [(index * 2) + 1] = item->value.target_code;
+               else
+                       buf [(index * 2) + 1] = vtable->vtable [item->value.vtable_slot];
+               index ++;
+       }
+       buf [(index * 2)] = NULL;
+       buf [(index * 2) + 1] = fail_tramp;
+
+       /*
+        * Return a function descriptor for a C function with 'buf' as its argument.
+        * It will by called by JITted code.
+        */
+       res = (void **)mono_domain_alloc (domain, 2 * sizeof (gpointer));
+       switch (real_count) {
+       case 1:
+               res [0] = mono_llvmonly_imt_thunk_1;
+               break;
+       case 2:
+               res [0] = mono_llvmonly_imt_thunk_2;
+               break;
+       case 3:
+               res [0] = mono_llvmonly_imt_thunk_3;
+               break;
+       default:
+               res [0] = mono_llvmonly_imt_thunk;
+               break;
+       }
+       if (virtual_generic)
+               res [0] = mono_llvmonly_generic_virtual_imt_thunk;
+       res [1] = buf;
+
+       return res;
 }
 
 MONO_SIG_HANDLER_FUNC (, mono_sigfpe_signal_handler)
@@ -2409,7 +2747,7 @@ MONO_SIG_HANDLER_FUNC (, mono_sigfpe_signal_handler)
        MONO_SIG_HANDLER_INFO_TYPE *info = MONO_SIG_HANDLER_GET_INFO ();
        MONO_SIG_HANDLER_GET_CONTEXT;
 
-       ji = mono_jit_info_table_find_internal (mono_domain_get (), mono_arch_ip_from_context (ctx), TRUE, TRUE);
+       ji = mono_jit_info_table_find_internal (mono_domain_get (), (char *)mono_arch_ip_from_context (ctx), TRUE, TRUE);
 
 #if defined(MONO_ARCH_HAVE_IS_INT_OVERFLOW)
        if (mono_arch_is_int_overflow (ctx, info))
@@ -2455,7 +2793,7 @@ MONO_SIG_HANDLER_FUNC (, mono_sigill_signal_handler)
 MONO_SIG_HANDLER_FUNC (, mono_sigsegv_signal_handler)
 {
        MonoJitInfo *ji;
-       MonoJitTlsData *jit_tls = mono_native_tls_get_value (mono_jit_tls_id);
+       MonoJitTlsData *jit_tls = (MonoJitTlsData *)mono_native_tls_get_value (mono_jit_tls_id);
        gpointer fault_addr = NULL;
 #ifdef HAVE_SIG_INFO
        MONO_SIG_HANDLER_INFO_TYPE *info = MONO_SIG_HANDLER_GET_INFO ();
@@ -2495,7 +2833,7 @@ MONO_SIG_HANDLER_FUNC (, mono_sigsegv_signal_handler)
        }
 #endif
 
-       ji = mono_jit_info_table_find_internal (mono_domain_get (), mono_arch_ip_from_context (ctx), TRUE, TRUE);
+       ji = mono_jit_info_table_find_internal (mono_domain_get (), (char *)mono_arch_ip_from_context (ctx), TRUE, TRUE);
 
 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
        if (mono_handle_soft_stack_ovf (jit_tls, ji, ctx, info, (guint8*)info->si_addr))
@@ -2579,10 +2917,10 @@ mono_jit_create_remoting_trampoline (MonoDomain *domain, MonoMethod *method, Mon
        if ((method->flags & METHOD_ATTRIBUTE_ABSTRACT) ||
            (mono_method_signature (method)->hasthis && (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class))) {
                nm = mono_marshal_get_remoting_invoke_for_target (method, target);
-               addr = mono_compile_method (nm);
+               addr = (guint8 *)mono_compile_method (nm);
        } else
        {
-               addr = mono_compile_method (method);
+               addr = (guint8 *)mono_compile_method (method);
        }
        return mono_get_addr_from_ftnptr (addr);
 }
@@ -2604,17 +2942,25 @@ static gpointer *vtable_trampolines;
 static int vtable_trampolines_size;
 
 gpointer
-mini_get_vtable_trampoline (int slot_index)
+mini_get_vtable_trampoline (MonoVTable *vt, int slot_index)
 {
        int index = slot_index + MONO_IMT_SIZE;
 
        if (mono_llvm_only) {
-               /* Not used */
-               if (slot_index < 0)
-                       /* The vtable/imt construction code in object.c depends on this being non-NULL */
-                       return no_imt_trampoline;
-               else
-                       return no_vcall_trampoline;
+               if (slot_index < 0) {
+                       /* Initialize the IMT thunks to a 'trampoline' so the generated code doesn't have to initialize it */
+                       // FIXME: Memory management
+                       gpointer *ftndesc = g_malloc (2 * sizeof (gpointer));
+                       IMTThunkInfo *info = g_new0 (IMTThunkInfo, 1);
+                       info->vtable = vt;
+                       info->slot = index;
+                       ftndesc [0] = mini_llvmonly_initial_imt_thunk;
+                       ftndesc [1] = info;
+                       mono_memory_barrier ();
+                       return ftndesc;
+               } else {
+                       return NULL;
+               }
        }
 
        g_assert (slot_index >= - MONO_IMT_SIZE);
@@ -2633,7 +2979,7 @@ mini_get_vtable_trampoline (int slot_index)
                                memcpy (new_table, vtable_trampolines, vtable_trampolines_size * sizeof (gpointer));
                        g_free (vtable_trampolines);
                        mono_memory_barrier ();
-                       vtable_trampolines = new_table;
+                       vtable_trampolines = (void **)new_table;
                        vtable_trampolines_size = new_size;
                }
                mono_jit_unlock ();
@@ -2644,6 +2990,24 @@ mini_get_vtable_trampoline (int slot_index)
        return vtable_trampolines [index];
 }
 
+static gpointer
+mini_get_imt_trampoline (MonoVTable *vt, int slot_index)
+{
+       return mini_get_vtable_trampoline (vt, slot_index - MONO_IMT_SIZE);
+}
+
+static gboolean
+mini_imt_entry_inited (MonoVTable *vt, int imt_slot_index)
+{
+       if (mono_llvm_only)
+               return FALSE;
+
+       gpointer *imt = (gpointer*)vt;
+       imt -= MONO_IMT_SIZE;
+
+       return (imt [imt_slot_index] != mini_get_imt_trampoline (vt, imt_slot_index));
+}
+
 gpointer
 mono_get_delegate_virtual_invoke_impl (MonoMethodSignature *sig, MonoMethod *method)
 {
@@ -2663,7 +3027,7 @@ mono_get_delegate_virtual_invoke_impl (MonoMethodSignature *sig, MonoMethod *met
        is_interface = method->klass->flags & TYPE_ATTRIBUTE_INTERFACE ? TRUE : FALSE;
        load_imt_reg = is_virtual_generic || is_interface;
 
-       if (is_interface && !is_virtual_generic)
+       if (is_interface)
                offset = ((gint32)mono_method_get_imt_slot (method) - MONO_IMT_SIZE) * SIZEOF_VOID_P;
        else
                offset = G_STRUCT_OFFSET (MonoVTable, vtable) + ((mono_method_get_vtable_index (method)) * (SIZEOF_VOID_P));
@@ -2700,18 +3064,71 @@ mono_get_delegate_virtual_invoke_impl (MonoMethodSignature *sig, MonoMethod *met
                int ind = (load_imt_reg ? (-offset) : offset) / SIZEOF_VOID_P;
 
                sprintf (tramp_name, "delegate_virtual_invoke%s_%d", imt, ind);
-               cache [idx] = mono_aot_get_trampoline (tramp_name);
+               cache [idx] = (guint8 *)mono_aot_get_trampoline (tramp_name);
                g_assert (cache [idx]);
        } else {
-               cache [idx] = mono_arch_get_delegate_virtual_invoke_impl (sig, method, offset, load_imt_reg);
+               cache [idx] = (guint8 *)mono_arch_get_delegate_virtual_invoke_impl (sig, method, offset, load_imt_reg);
        }
        return cache [idx];
 }
 
-static gpointer
-mini_get_imt_trampoline (int slot_index)
+gboolean
+mini_parse_debug_option (const char *option)
 {
-       return mini_get_vtable_trampoline (slot_index - MONO_IMT_SIZE);
+       if (!strcmp (option, "handle-sigint"))
+               debug_options.handle_sigint = TRUE;
+       else if (!strcmp (option, "keep-delegates"))
+               debug_options.keep_delegates = TRUE;
+       else if (!strcmp (option, "reverse-pinvoke-exceptions"))
+               debug_options.reverse_pinvoke_exceptions = TRUE;
+       else if (!strcmp (option, "collect-pagefault-stats"))
+               debug_options.collect_pagefault_stats = TRUE;
+       else if (!strcmp (option, "break-on-unverified"))
+               debug_options.break_on_unverified = TRUE;
+       else if (!strcmp (option, "no-gdb-backtrace"))
+               debug_options.no_gdb_backtrace = TRUE;
+       else if (!strcmp (option, "suspend-on-sigsegv"))
+               debug_options.suspend_on_sigsegv = TRUE;
+       else if (!strcmp (option, "suspend-on-exception"))
+               debug_options.suspend_on_exception = TRUE;
+       else if (!strcmp (option, "suspend-on-unhandled"))
+               debug_options.suspend_on_unhandled = TRUE;
+       else if (!strcmp (option, "dont-free-domains"))
+               mono_dont_free_domains = TRUE;
+       else if (!strcmp (option, "dyn-runtime-invoke"))
+               debug_options.dyn_runtime_invoke = TRUE;
+       else if (!strcmp (option, "gdb"))
+               debug_options.gdb = TRUE;
+       else if (!strcmp (option, "explicit-null-checks"))
+               debug_options.explicit_null_checks = TRUE;
+       else if (!strcmp (option, "gen-seq-points"))
+               debug_options.gen_sdb_seq_points = TRUE;
+       else if (!strcmp (option, "gen-compact-seq-points"))
+               debug_options.gen_seq_points_compact_data = TRUE;
+       else if (!strcmp (option, "single-imm-size"))
+               debug_options.single_imm_size = TRUE;
+       else if (!strcmp (option, "init-stacks"))
+               debug_options.init_stacks = TRUE;
+       else if (!strcmp (option, "casts"))
+               debug_options.better_cast_details = TRUE;
+       else if (!strcmp (option, "soft-breakpoints"))
+               debug_options.soft_breakpoints = TRUE;
+       else if (!strcmp (option, "check-pinvoke-callconv"))
+               debug_options.check_pinvoke_callconv = TRUE;
+       else if (!strcmp (option, "arm-use-fallback-tls"))
+               debug_options.arm_use_fallback_tls = TRUE;
+       else if (!strcmp (option, "debug-domain-unload"))
+               mono_enable_debug_domain_unload (TRUE);
+       else if (!strcmp (option, "partial-sharing"))
+               mono_set_partial_sharing_supported (TRUE);
+       else if (!strcmp (option, "align-small-structs"))
+               mono_align_small_structs = TRUE;
+       else if (!strcmp (option, "native-debugger-break"))
+               debug_options.native_debugger_break = TRUE;
+       else
+               return FALSE;
+
+       return TRUE;
 }
 
 static void
@@ -2728,57 +3145,7 @@ mini_parse_debug_options (void)
        for (ptr = args; ptr && *ptr; ptr++) {
                const char *arg = *ptr;
 
-               if (!strcmp (arg, "handle-sigint"))
-                       debug_options.handle_sigint = TRUE;
-               else if (!strcmp (arg, "keep-delegates"))
-                       debug_options.keep_delegates = TRUE;
-               else if (!strcmp (arg, "reverse-pinvoke-exceptions"))
-                       debug_options.reverse_pinvoke_exceptions = TRUE;
-               else if (!strcmp (arg, "collect-pagefault-stats"))
-                       debug_options.collect_pagefault_stats = TRUE;
-               else if (!strcmp (arg, "break-on-unverified"))
-                       debug_options.break_on_unverified = TRUE;
-               else if (!strcmp (arg, "no-gdb-backtrace"))
-                       debug_options.no_gdb_backtrace = TRUE;
-               else if (!strcmp (arg, "suspend-on-sigsegv"))
-                       debug_options.suspend_on_sigsegv = TRUE;
-               else if (!strcmp (arg, "suspend-on-exception"))
-                       debug_options.suspend_on_exception = TRUE;
-               else if (!strcmp (arg, "suspend-on-unhandled"))
-                       debug_options.suspend_on_unhandled = TRUE;
-               else if (!strcmp (arg, "dont-free-domains"))
-                       mono_dont_free_domains = TRUE;
-               else if (!strcmp (arg, "dyn-runtime-invoke"))
-                       debug_options.dyn_runtime_invoke = TRUE;
-               else if (!strcmp (arg, "gdb"))
-                       debug_options.gdb = TRUE;
-               else if (!strcmp (arg, "explicit-null-checks"))
-                       debug_options.explicit_null_checks = TRUE;
-               else if (!strcmp (arg, "gen-seq-points"))
-                       debug_options.gen_sdb_seq_points = TRUE;
-               else if (!strcmp (arg, "gen-compact-seq-points"))
-                       debug_options.gen_seq_points_compact_data = TRUE;
-               else if (!strcmp (arg, "single-imm-size"))
-                       debug_options.single_imm_size = TRUE;
-               else if (!strcmp (arg, "init-stacks"))
-                       debug_options.init_stacks = TRUE;
-               else if (!strcmp (arg, "casts"))
-                       debug_options.better_cast_details = TRUE;
-               else if (!strcmp (arg, "soft-breakpoints"))
-                       debug_options.soft_breakpoints = TRUE;
-               else if (!strcmp (arg, "check-pinvoke-callconv"))
-                       debug_options.check_pinvoke_callconv = TRUE;
-               else if (!strcmp (arg, "arm-use-fallback-tls"))
-                       debug_options.arm_use_fallback_tls = TRUE;
-               else if (!strcmp (arg, "debug-domain-unload"))
-                       mono_enable_debug_domain_unload (TRUE);
-               else if (!strcmp (arg, "partial-sharing"))
-                       mono_set_partial_sharing_supported (TRUE);
-               else if (!strcmp (arg, "align-small-structs"))
-                       mono_align_small_structs = TRUE;
-               else if (!strcmp (arg, "native-debugger-break"))
-                       debug_options.native_debugger_break = TRUE;
-               else {
+               if (!mini_parse_debug_option (arg)) {
                        fprintf (stderr, "Invalid option for the MONO_DEBUG env variable: %s\n", arg);
                        fprintf (stderr, "Available options: 'handle-sigint', 'keep-delegates', 'reverse-pinvoke-exceptions', 'collect-pagefault-stats', 'break-on-unverified', 'no-gdb-backtrace', 'suspend-on-sigsegv', 'suspend-on-exception', 'suspend-on-unhandled', 'dont-free-domains', 'dyn-runtime-invoke', 'gdb', 'explicit-null-checks', 'gen-seq-points', 'gen-compact-seq-points', 'single-imm-size', 'init-stacks', 'casts', 'soft-breakpoints', 'check-pinvoke-callconv', 'arm-use-fallback-tls', 'debug-domain-unload', 'partial-sharing', 'align-small-structs', 'native-debugger-break'\n");
                        exit (1);
@@ -2864,8 +3231,8 @@ static void runtime_invoke_info_free (gpointer value);
 static gint
 class_method_pair_equal (gconstpointer ka, gconstpointer kb)
 {
-       const MonoClassMethodPair *apair = ka;
-       const MonoClassMethodPair *bpair = kb;
+       const MonoClassMethodPair *apair = (const MonoClassMethodPair *)ka;
+       const MonoClassMethodPair *bpair = (const MonoClassMethodPair *)kb;
 
        return apair->klass == bpair->klass && apair->method == bpair->method ? 1 : 0;
 }
@@ -2873,7 +3240,7 @@ class_method_pair_equal (gconstpointer ka, gconstpointer kb)
 static guint
 class_method_pair_hash (gconstpointer data)
 {
-       const MonoClassMethodPair *pair = data;
+       const MonoClassMethodPair *pair = (const MonoClassMethodPair *)data;
 
        return (gsize)pair->klass ^ (gsize)pair->method;
 }
@@ -2898,21 +3265,21 @@ mini_create_jit_domain_info (MonoDomain *domain)
 static void
 delete_jump_list (gpointer key, gpointer value, gpointer user_data)
 {
-       MonoJumpList *jlist = value;
+       MonoJumpList *jlist = (MonoJumpList *)value;
        g_slist_free (jlist->list);
 }
 
 static void
 delete_got_slot_list (gpointer key, gpointer value, gpointer user_data)
 {
-       GSList *list = value;
+       GSList *list = (GSList *)value;
        g_slist_free (list);
 }
 
 static void
 dynamic_method_info_free (gpointer key, gpointer value, gpointer user_data)
 {
-       MonoJitDynamicMethodInfo *di = value;
+       MonoJitDynamicMethodInfo *di = (MonoJitDynamicMethodInfo *)value;
        mono_code_manager_destroy (di->code_mp);
        g_free (di);
 }
@@ -3035,6 +3402,9 @@ mini_init (const char *filename, const char *runtime_version)
 #ifdef MONO_ARCH_GSHAREDVT_SUPPORTED
        if (mono_aot_only)
                mono_set_generic_sharing_vt_supported (TRUE);
+#else
+       if (mono_llvm_only)
+               mono_set_generic_sharing_vt_supported (TRUE);
 #endif
 
 #ifdef MONO_HAVE_FAST_TLS
@@ -3061,6 +3431,7 @@ mini_init (const char *filename, const char *runtime_version)
 
        callbacks.get_vtable_trampoline = mini_get_vtable_trampoline;
        callbacks.get_imt_trampoline = mini_get_imt_trampoline;
+       callbacks.imt_entry_inited = mini_imt_entry_inited;
 
        mono_install_callbacks (&callbacks);
 
@@ -3165,10 +3536,14 @@ mini_init (const char *filename, const char *runtime_version)
                mono_marshal_use_aot_wrappers (TRUE);
        }
 
-       if (mono_aot_only)
+       if (mono_llvm_only) {
+               mono_install_imt_thunk_builder (mono_llvmonly_get_imt_thunk);
+               mono_set_always_build_imt_thunks (TRUE);
+       } else if (mono_aot_only) {
                mono_install_imt_thunk_builder (mono_aot_get_imt_thunk);
-       else
+       } else {
                mono_install_imt_thunk_builder (mono_arch_build_imt_thunk);
+       }
 
        /*Init arch tls information only after the metadata side is inited to make sure we see dynamic appdomain tls keys*/
        mono_arch_finish_init ();
@@ -3473,8 +3848,12 @@ register_icalls (void)
        register_icall (mono_aot_init_gshared_method_this, "mono_aot_init_gshared_method_this", "void ptr int object", TRUE);
        register_icall (mono_aot_init_gshared_method_rgctx, "mono_aot_init_gshared_method_rgctx", "void ptr int ptr", TRUE);
 
-       register_icall_no_wrapper (mono_resolve_iface_call, "mono_resolve_iface_call", "ptr object int ptr ptr");
-       register_icall_no_wrapper (mono_resolve_vcall, "mono_resolve_vcall", "ptr object int ptr");
+       register_icall_no_wrapper (mono_resolve_iface_call_gsharedvt, "mono_resolve_iface_call_gsharedvt", "ptr object int ptr ptr");
+       register_icall_no_wrapper (mono_resolve_vcall_gsharedvt, "mono_resolve_vcall_gsharedvt", "ptr object int ptr ptr");
+       register_icall_no_wrapper (mono_resolve_generic_virtual_call, "mono_resolve_generic_virtual_call", "ptr ptr int ptr");
+       register_icall_no_wrapper (mono_resolve_generic_virtual_iface_call, "mono_resolve_generic_virtual_iface_call", "ptr ptr int ptr");
+       /* This needs a wrapper so it can have a preserveall cconv */
+       register_icall (mono_init_vtable_slot, "mono_init_vtable_slot", "ptr ptr int", FALSE);
        register_icall (mono_init_delegate, "mono_init_delegate", "void object object ptr", TRUE);
        register_icall (mono_init_delegate_virtual, "mono_init_delegate_virtual", "void object object ptr", TRUE);
        register_icall (mono_get_assembly_object, "mono_get_assembly_object", "object ptr", TRUE);
@@ -3560,7 +3939,7 @@ mini_cleanup (MonoDomain *domain)
        mono_runtime_cleanup (domain);
 #endif
 
-       free_jit_tls_data (mono_native_tls_get_value (mono_jit_tls_id));
+       free_jit_tls_data ((MonoJitTlsData *)mono_native_tls_get_value (mono_jit_tls_id));
 
        mono_icall_cleanup ();
 
@@ -3632,6 +4011,9 @@ mono_set_optimizations (guint32 opts)
        default_opt_set = TRUE;
 #ifdef MONO_ARCH_GSHAREDVT_SUPPORTED
        mono_set_generic_sharing_vt_supported (mono_aot_only || ((default_opt & MONO_OPT_GSHAREDVT) != 0));
+#else
+       if (mono_llvm_only)
+               mono_set_generic_sharing_vt_supported (TRUE);
 #endif
 }
 
@@ -3688,7 +4070,7 @@ mono_precompile_assembly (MonoAssembly *ass, void *user_data)
                }
                mono_compile_method (method);
                if (strcmp (method->name, "Finalize") == 0) {
-                       invoke = mono_marshal_get_runtime_invoke (method, FALSE, FALSE);
+                       invoke = mono_marshal_get_runtime_invoke (method, FALSE);
                        mono_compile_method (invoke);
                }
 #ifndef DISABLE_REMOTING