Merge pull request #2408 from tastywheattasteslikechicken/MoreInterfaceSupport
[mono.git] / mono / mini / mini-runtime.c
index 27ee9a2858593b7bccd1486372e0eeb66a1054d0..572048ff5ff8b401b415ab6ba0fe9de8e88cc02f 100644 (file)
@@ -1,3 +1,4 @@
+
 /*
  * mini-runtime.c: Runtime code for the JIT
  *
@@ -8,6 +9,7 @@
  * Copyright 2002-2003 Ximian, Inc.
  * Copyright 2003-2010 Novell, Inc.
  * Copyright 2011-2015 Xamarin, Inc (http://www.xamarin.com)
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
  */
 
 #include <config.h>
@@ -47,6 +49,8 @@
 #include <mono/metadata/mempool-internals.h>
 #include <mono/metadata/attach.h>
 #include <mono/metadata/runtime.h>
+#include <mono/metadata/reflection-internals.h>
+#include <mono/metadata/monitor.h>
 #include <mono/utils/mono-math.h>
 #include <mono/utils/mono-compiler.h>
 #include <mono/utils/mono-counters.h>
@@ -59,7 +63,9 @@
 #include <mono/utils/dtrace.h>
 #include <mono/utils/mono-signal-handler.h>
 #include <mono/utils/mono-threads.h>
+#include <mono/utils/mono-threads-coop.h>
 #include <mono/utils/checked-build.h>
+#include <mono/metadata/w32handle.h>
 #include <mono/io-layer/io-layer.h>
 
 #include "mini.h"
@@ -79,6 +85,7 @@
 #ifdef MONO_ARCH_LLVM_SUPPORTED
 #ifdef ENABLE_LLVM
 #include "mini-llvm-cpp.h"
+#include "llvm-jit.h"
 #endif
 #endif
 
@@ -158,7 +165,8 @@ G_GNUC_UNUSED static char*
 get_method_from_ip (void *ip)
 {
        MonoJitInfo *ji;
-       char *method;
+       MonoMethod *method;
+       char *method_name;
        char *res;
        MonoDomain *domain = mono_domain_get ();
        MonoDebugSourceLocation *location;
@@ -187,14 +195,15 @@ get_method_from_ip (void *ip)
                return res;
        }
 
-       method = mono_method_full_name (jinfo_get_method (ji), TRUE);
+       method = jinfo_get_method (ji);
+       method_name = mono_method_full_name (method, TRUE);
        /* FIXME: unused ? */
-       location = mono_debug_lookup_source_location (jinfo_get_method (ji), (guint32)((guint8*)ip - (guint8*)ji->code_start), domain);
+       location = mono_debug_lookup_source_location (method, (guint32)((guint8*)ip - (guint8*)ji->code_start), domain);
 
-       res = g_strdup_printf (" %s + 0x%x (%p %p) [%p - %s]", method, (int)((char*)ip - (char*)ji->code_start), ji->code_start, (char*)ji->code_start + ji->code_size, domain, domain->friendly_name);
+       res = g_strdup_printf (" %s {%p} + 0x%x (%p %p) [%p - %s]", method_name, method, (int)((char*)ip - (char*)ji->code_start), ji->code_start, (char*)ji->code_start + ji->code_size, domain, domain->friendly_name);
 
        mono_debug_free_source_location (location);
-       g_free (method);
+       g_free (method_name);
 
        return res;
 }
@@ -332,7 +341,7 @@ void *mono_global_codeman_reserve (int size)
        void *ptr;
 
        if (mono_aot_only)
-               g_error ("Attempting to allocate from the global code manager while running with --aot-only.\n");
+               g_error ("Attempting to allocate from the global code manager while running in aot-only mode.\n");
 
        if (!global_codeman) {
                /* This can happen during startup */
@@ -355,65 +364,6 @@ mono_nacl_gc()
        __nacl_suspend_thread_if_needed();
 #endif
 }
-
-/* Given the temporary buffer (allocated by mono_global_codeman_reserve) into
- * which we are generating code, return a pointer to the destination in the
- * dynamic code segment into which the code will be copied when
- * mono_global_codeman_commit is called.
- * LOCKING: Acquires the jit lock.
- */
-void*
-nacl_global_codeman_get_dest (void *data)
-{
-       void *dest;
-       mono_jit_lock ();
-       dest = nacl_code_manager_get_code_dest (global_codeman, data);
-       mono_jit_unlock ();
-       return dest;
-}
-
-void
-mono_global_codeman_commit (void *data, int size, int newsize)
-{
-       mono_jit_lock ();
-       mono_code_manager_commit (global_codeman, data, size, newsize);
-       mono_jit_unlock ();
-}
-
-/*
- * Convenience function which calls mono_global_codeman_commit to validate and
- * copy the code. The caller sets *buf_base and *buf_size to the start and size
- * of the buffer (allocated by mono_global_codeman_reserve), and *code_end to
- * the byte after the last instruction byte. On return, *buf_base will point to
- * the start of the copied in the code segment, and *code_end will point after
- * the end of the copied code.
- */
-void
-nacl_global_codeman_validate (guint8 **buf_base, int buf_size, guint8 **code_end)
-{
-       guint8 *tmp = nacl_global_codeman_get_dest (*buf_base);
-       mono_global_codeman_commit (*buf_base, buf_size, *code_end - *buf_base);
-       *code_end = tmp + (*code_end - *buf_base);
-       *buf_base = tmp;
-}
-#else
-/* no-op versions of Native Client functions */
-void*
-nacl_global_codeman_get_dest (void *data)
-{
-       return data;
-}
-
-void
-mono_global_codeman_commit (void *data, int size, int newsize)
-{
-}
-
-void
-nacl_global_codeman_validate (guint8 **buf_base, int buf_size, guint8 **code_end)
-{
-}
-
 #endif /* __native_client__ */
 
 /**
@@ -609,6 +559,7 @@ mono_debug_count (void)
 gconstpointer
 mono_icall_get_wrapper_full (MonoJitICallInfo* callinfo, gboolean do_compile)
 {
+       MonoError error;
        char *name;
        MonoMethod *wrapper;
        gconstpointer trampoline;
@@ -629,10 +580,15 @@ mono_icall_get_wrapper_full (MonoJitICallInfo* callinfo, gboolean do_compile)
        wrapper = mono_marshal_get_icall_wrapper (callinfo->sig, name, callinfo->func, check_exc);
        g_free (name);
 
-       if (do_compile)
-               trampoline = mono_compile_method (wrapper);
-       else
-               trampoline = mono_create_ftnptr (domain, mono_create_jit_trampoline_in_domain (domain, wrapper));
+       if (do_compile) {
+               trampoline = mono_compile_method_checked (wrapper, &error);
+               mono_error_assert_ok (&error);
+       } else {
+
+               trampoline = mono_create_jit_trampoline (domain, wrapper, &error);
+               mono_error_assert_ok (&error);
+               trampoline = mono_create_ftnptr (domain, (gpointer)trampoline);
+       }
 
        mono_loader_lock ();
        if (!callinfo->trampoline) {
@@ -710,6 +666,19 @@ register_icall_no_wrapper (gpointer func, const char *name, const char *sigstr)
        mono_register_jit_icall_full (func, name, sig, TRUE, FALSE, name);
 }
 
+static void
+register_icall_with_wrapper (gpointer func, const char *name, const char *sigstr)
+{
+       MonoMethodSignature *sig;
+
+       if (sigstr)
+               sig = mono_create_icall_signature (sigstr);
+       else
+               sig = NULL;
+
+       mono_register_jit_icall_full (func, name, sig, FALSE, FALSE, NULL);
+}
+
 static void
 register_dyn_icall (gpointer func, const char *name, const char *sigstr, gboolean save)
 {
@@ -810,7 +779,8 @@ mono_get_lmf_addr (void)
         * mono_get_lmf_addr, and mono_get_lmf_addr requires the thread to be attached.
         */
 
-       mono_jit_thread_attach (NULL);
+       mono_thread_attach (mono_get_root_domain ());
+       mono_thread_set_state (mono_thread_internal_current (), ThreadState_Background);
 
        if ((jit_tls = mono_native_tls_get_value (mono_jit_tls_id)))
                return &jit_tls->lmf;
@@ -871,33 +841,39 @@ mono_set_lmf_addr (gpointer lmf_addr)
 /*
  * mono_jit_thread_attach:
  *
- * Called by native->managed wrappers. Returns the original domain which needs to be
- * restored, or NULL.
+ * Called by Xamarin.Mac and other products. Attach thread to runtime if
+ * needed and switch to @domain.
+ *
+ * @return the original domain which needs to be restored, or NULL.
  */
 MonoDomain*
 mono_jit_thread_attach (MonoDomain *domain)
 {
        MonoDomain *orig;
+       gboolean attached;
 
-       if (!domain)
-               /*
-                * Happens when called from AOTed code which is only used in the root
-                * domain.
-                */
+       g_assert (!mono_threads_is_coop_enabled ());
+
+       if (!domain) {
+               /* Happens when called from AOTed code which is only used in the root domain. */
                domain = mono_get_root_domain ();
+       }
+
+       g_assert (domain);
 
 #ifdef MONO_HAVE_FAST_TLS
-       if (!MONO_FAST_TLS_GET (mono_lmf_addr)) {
-               mono_thread_attach (domain);
-               // #678164
-               mono_thread_set_state (mono_thread_internal_current (), ThreadState_Background);
-       }
+       attached = MONO_FAST_TLS_GET (mono_lmf_addr) != NULL;
 #else
-       if (!mono_native_tls_get_value (mono_jit_tls_id)) {
+       attached = mono_native_tls_get_value (mono_jit_tls_id) != NULL;
+#endif
+
+       if (!attached) {
                mono_thread_attach (domain);
+
+               // #678164
                mono_thread_set_state (mono_thread_internal_current (), ThreadState_Background);
        }
-#endif
+
        orig = mono_domain_get ();
        if (orig != domain)
                mono_domain_set (domain, TRUE);
@@ -905,10 +881,16 @@ mono_jit_thread_attach (MonoDomain *domain)
        return orig != domain ? orig : NULL;
 }
 
-/* Called by native->managed wrappers */
+/*
+ * mono_jit_set_domain:
+ *
+ * Set domain to @domain if @domain is not null
+ */
 void
 mono_jit_set_domain (MonoDomain *domain)
 {
+       g_assert (!mono_threads_is_coop_enabled ());
+
        if (domain)
                mono_domain_set (domain, TRUE);
 }
@@ -1017,8 +999,6 @@ mono_thread_attach_cb (intptr_t tid, gpointer stack_start)
        thread = mono_thread_info_current_unchecked ();
        if (thread)
                thread->jit_data = jit_tls;
-       if (mono_profiler_get_events () & MONO_PROFILE_STATISTICAL)
-               mono_runtime_setup_stat_profiler ();
 
        mono_arch_cpu_init ();
 }
@@ -1114,6 +1094,63 @@ mono_patch_info_list_prepend (MonoJumpInfo *list, int ip, MonoJumpInfoType type,
        return ji;
 }
 
+#if !defined(DISABLE_LOGGING) && !defined(DISABLE_JIT)
+
+static const char* const patch_info_str[] = {
+#define PATCH_INFO(a,b) "" #a,
+#include "patch-info.h"
+#undef PATCH_INFO
+};
+
+const char*
+mono_ji_type_to_string (MonoJumpInfoType type)
+{
+       return patch_info_str [type];
+}
+
+void
+mono_print_ji (const MonoJumpInfo *ji)
+{
+       switch (ji->type) {
+       case MONO_PATCH_INFO_RGCTX_FETCH: {
+               MonoJumpInfoRgctxEntry *entry = ji->data.rgctx_entry;
+
+               printf ("[RGCTX_FETCH ");
+               mono_print_ji (entry->data);
+               printf (" - %s]", mono_rgctx_info_type_to_str (entry->info_type));
+               break;
+       }
+       case MONO_PATCH_INFO_METHODCONST: {
+               char *s = mono_method_full_name (ji->data.method, TRUE);
+               printf ("[METHODCONST - %s]", s);
+               g_free (s);
+               break;
+       }
+       case MONO_PATCH_INFO_INTERNAL_METHOD: {
+               printf ("[INTERNAL_METHOD - %s]", ji->data.name);
+               break;
+       }
+       default:
+               printf ("[%s]", patch_info_str [ji->type]);
+               break;
+       }
+}
+
+#else
+
+const char*
+mono_ji_type_to_string (MonoJumpInfoType type)
+{
+       return "";
+}
+
+void
+mono_print_ji (const MonoJumpInfo *ji)
+{
+}
+
+#endif
+
 /**
  * mono_patch_info_dup_mp:
  *
@@ -1215,6 +1252,7 @@ mono_patch_info_hash (gconstpointer data)
        case MONO_PATCH_INFO_METHOD_JUMP:
        case MONO_PATCH_INFO_IMAGE:
        case MONO_PATCH_INFO_ICALL_ADDR:
+       case MONO_PATCH_INFO_ICALL_ADDR_CALL:
        case MONO_PATCH_INFO_FIELD:
        case MONO_PATCH_INFO_SFLDA:
        case MONO_PATCH_INFO_SEQ_POINT_INFO:
@@ -1241,6 +1279,7 @@ mono_patch_info_hash (gconstpointer data)
        case MONO_PATCH_INFO_GOT_OFFSET:
        case MONO_PATCH_INFO_GC_SAFE_POINT_FLAG:
        case MONO_PATCH_INFO_AOT_MODULE:
+       case MONO_PATCH_INFO_GET_TLS_TRAMP:
                return (ji->type << 8);
        case MONO_PATCH_INFO_CASTCLASS_CACHE:
                return (ji->type << 8) | (ji->data.index);
@@ -1262,6 +1301,8 @@ mono_patch_info_hash (gconstpointer data)
        }
        case MONO_PATCH_INFO_JIT_ICALL_ADDR:
                return (ji->type << 8) | g_str_hash (ji->data.target);
+       case MONO_PATCH_INFO_GSHAREDVT_IN_WRAPPER:
+               return (ji->type << 8) | mono_signature_hash (ji->data.sig);
        default:
                printf ("info type: %d\n", ji->type);
                mono_print_ji (ji); printf ("\n");
@@ -1326,6 +1367,8 @@ mono_patch_info_equal (gconstpointer ka, gconstpointer kb)
                if (ji1->data.target == ji2->data.target)
                        return 1;
                return strcmp (ji1->data.target, ji2->data.target) == 0 ? 1 : 0;
+       case MONO_PATCH_INFO_GSHAREDVT_IN_WRAPPER:
+               return mono_metadata_signature_equal (ji1->data.sig, ji2->data.sig) ? 1 : 0;
        default:
                if (ji1->data.target != ji2->data.target)
                        return 0;
@@ -1336,11 +1379,13 @@ mono_patch_info_equal (gconstpointer ka, gconstpointer kb)
 }
 
 gpointer
-mono_resolve_patch_target (MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *patch_info, gboolean run_cctors)
+mono_resolve_patch_target (MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *patch_info, gboolean run_cctors, MonoError *error)
 {
        unsigned char *ip = patch_info->ip.i + code;
        gconstpointer target = NULL;
 
+       mono_error_init (error);
+
        switch (patch_info->type) {
        case MONO_PATCH_INFO_BB:
                /*
@@ -1357,13 +1402,7 @@ mono_resolve_patch_target (MonoMethod *method, MonoDomain *domain, guint8 *code,
                target = patch_info->data.inst->inst_c0 + code;
                break;
        case MONO_PATCH_INFO_IP:
-#if defined(__native_client__) && defined(__native_client_codegen__)
-               /* Need to transform to the destination address, it's */
-               /* emitted as an immediate in the code. */
-               target = nacl_inverse_modify_patch_target(ip);
-#else
                target = ip;
-#endif
                break;
        case MONO_PATCH_INFO_METHOD_REL:
                target = code + patch_info->data.offset;
@@ -1387,31 +1426,19 @@ mono_resolve_patch_target (MonoMethod *method, MonoDomain *domain, guint8 *code,
                break;
        }
        case MONO_PATCH_INFO_METHOD_JUMP:
-               target = mono_create_jump_trampoline (domain, patch_info->data.method, FALSE);
-#if defined(__native_client__) && defined(__native_client_codegen__)
-# if defined(TARGET_AMD64)
-               /* This target is an absolute address, not relative to the */
-               /* current code being emitted on AMD64. */
-               target = nacl_inverse_modify_patch_target(target);
-# endif
-#endif
+               target = mono_create_jump_trampoline (domain, patch_info->data.method, FALSE, error);
+               if (!mono_error_ok (error))
+                       return NULL;
                break;
        case MONO_PATCH_INFO_METHOD:
-#if defined(__native_client_codegen__) && defined(USE_JUMP_TABLES)
-               /*
-                * If we use jumptables, for recursive calls we cannot
-                * avoid trampoline, as we not yet know where we will
-                * be installed.
-                */
-               target = mono_create_jit_trampoline_in_domain (domain, patch_info->data.method);
-#else
                if (patch_info->data.method == method) {
                        target = code;
                } else {
                        /* get the trampoline to the method from the domain */
-                       target = mono_create_jit_trampoline_in_domain (domain, patch_info->data.method);
+                       target = mono_create_jit_trampoline (domain, patch_info->data.method, error);
+                       if (!mono_error_ok (error))
+                               return NULL;
                }
-#endif
                break;
        case MONO_PATCH_INFO_METHOD_CODE_SLOT: {
                gpointer code_slot;
@@ -1456,24 +1483,10 @@ mono_resolve_patch_target (MonoMethod *method, MonoDomain *domain, guint8 *code,
 #endif
 
                for (i = 0; i < patch_info->data.table->table_size; i++) {
-#if defined(__native_client__) && defined(__native_client_codegen__)
-                       /* 'code' is relative to the current code blob, we */
-                       /* need to do this transform on it to make the     */
-                       /* pointers in this table absolute                 */
-                       jump_table [i] = nacl_inverse_modify_patch_target (code) + GPOINTER_TO_INT (patch_info->data.table->table [i]);
-#else
                        jump_table [i] = code + GPOINTER_TO_INT (patch_info->data.table->table [i]);
-#endif
                }
 
-#if defined(__native_client__) && defined(__native_client_codegen__)
-               /* jump_table is in the data section, we need to transform */
-               /* it here so when it gets modified in amd64_patch it will */
-               /* then point back to the absolute data address            */
-               target = nacl_inverse_modify_patch_target (jump_table);
-#else
                target = jump_table;
-#endif
                break;
        }
        case MONO_PATCH_INFO_METHODCONST:
@@ -1520,12 +1533,15 @@ mono_resolve_patch_target (MonoMethod *method, MonoDomain *domain, guint8 *code,
                }
 
                g_assert (vtable);
-               if (!vtable->initialized && !(vtable->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT) && (method && mono_class_needs_cctor_run (vtable->klass, method)))
+               if (!vtable->initialized && !mono_class_is_before_field_init (vtable->klass) && (method && mono_class_needs_cctor_run (vtable->klass, method)))
                        /* Done by the generated code */
                        ;
                else {
-                       if (run_cctors)
-                               mono_runtime_class_init (vtable);
+                       if (run_cctors) {
+                               if (!mono_runtime_class_init_full (vtable, error)) {
+                                       return NULL;
+                               }
+                       }
                }
                target = (char*)mono_vtable_get_static_field_data (vtable) + patch_info->data.field->offset;
                break;
@@ -1547,34 +1563,33 @@ mono_resolve_patch_target (MonoMethod *method, MonoDomain *domain, guint8 *code,
                break;
        case MONO_PATCH_INFO_LDSTR:
                target =
-                       mono_ldstr (domain, patch_info->data.token->image,
-                                               mono_metadata_token_index (patch_info->data.token->token));
+                       mono_ldstr_checked (domain, patch_info->data.token->image,
+                                           mono_metadata_token_index (patch_info->data.token->token), error);
                break;
        case MONO_PATCH_INFO_TYPE_FROM_HANDLE: {
                gpointer handle;
                MonoClass *handle_class;
-               MonoError error;
 
                handle = mono_ldtoken_checked (patch_info->data.token->image,
-                                                          patch_info->data.token->token, &handle_class, patch_info->data.token->has_context ? &patch_info->data.token->context : NULL, &error);
-               if (!mono_error_ok (&error))
-                       g_error ("Could not patch ldtoken due to %s", mono_error_get_message (&error));
+                                                          patch_info->data.token->token, &handle_class, patch_info->data.token->has_context ? &patch_info->data.token->context : NULL, error);
+               if (!mono_error_ok (error))
+                       return NULL;
                mono_class_init (handle_class);
                mono_class_init (mono_class_from_mono_type ((MonoType *)handle));
 
-               target =
-                       mono_type_get_object (domain, (MonoType *)handle);
+               target = mono_type_get_object_checked (domain, (MonoType *)handle, error);
+               if (!mono_error_ok (error))
+                       return NULL;
                break;
        }
        case MONO_PATCH_INFO_LDTOKEN: {
                gpointer handle;
                MonoClass *handle_class;
-               MonoError error;
 
                handle = mono_ldtoken_checked (patch_info->data.token->image,
-                                                          patch_info->data.token->token, &handle_class, patch_info->data.token->has_context ? &patch_info->data.token->context : NULL, &error);
-               if (!mono_error_ok (&error))
-                       g_error ("Could not patch ldtoken due to %s", mono_error_get_message (&error));
+                                                          patch_info->data.token->token, &handle_class, patch_info->data.token->has_context ? &patch_info->data.token->context : NULL, error);
+               if (!mono_error_ok (error))
+                       g_error ("Could not patch ldtoken due to %s", mono_error_get_message (error));
                mono_class_init (handle_class);
 
                target = handle;
@@ -1584,6 +1599,7 @@ mono_resolve_patch_target (MonoMethod *method, MonoDomain *domain, guint8 *code,
                target = (mono_metadata_blob_heap (patch_info->data.token->image, patch_info->data.token->token) + 2);
                break;
        case MONO_PATCH_INFO_ICALL_ADDR:
+       case MONO_PATCH_INFO_ICALL_ADDR_CALL:
                /* run_cctors == 0 -> AOT */
                if (patch_info->data.method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) {
                        const char *exc_class;
@@ -1592,8 +1608,10 @@ mono_resolve_patch_target (MonoMethod *method, MonoDomain *domain, guint8 *code,
                        if (run_cctors) {
                                target = mono_lookup_pinvoke_call (patch_info->data.method, &exc_class, &exc_arg);
                                if (!target) {
-                                       if (mono_aot_only)
-                                               mono_raise_exception (mono_exception_from_name_msg (mono_defaults.corlib, "System", exc_class, exc_arg));
+                                       if (mono_aot_only) {
+                                               mono_error_set_exception_instance (error, mono_exception_from_name_msg (mono_defaults.corlib, "System", exc_class, exc_arg));
+                                               return NULL;
+                                       }
                                        g_error ("Unable to resolve pinvoke method '%s' Re-run with MONO_LOG_LEVEL=debug for more information.\n", mono_method_full_name (patch_info->data.method, TRUE));
                                }
                        } else {
@@ -1698,6 +1716,16 @@ mono_resolve_patch_target (MonoMethod *method, MonoDomain *domain, guint8 *code,
 
                break;
        }
+       case MONO_PATCH_INFO_GSHAREDVT_IN_WRAPPER:
+               target = mini_get_gsharedvt_wrapper (TRUE, NULL, patch_info->data.sig, NULL, -1, FALSE);
+               break;
+       case MONO_PATCH_INFO_GET_TLS_TRAMP:
+#ifdef MONO_ARCH_HAVE_GET_TLS_TRAMP
+               target = mono_arch_get_get_tls_tramp ();
+#else
+               target = NULL;
+#endif
+               break;
        default:
                g_assert_not_reached ();
        }
@@ -1837,7 +1865,7 @@ no_gsharedvt_in_wrapper (void)
 }
 
 static gpointer
-mono_jit_compile_method_with_opt (MonoMethod *method, guint32 opt, MonoException **ex)
+mono_jit_compile_method_with_opt (MonoMethod *method, guint32 opt, MonoError *error)
 {
        MonoDomain *target_domain, *domain = mono_domain_get ();
        MonoJitInfo *info;
@@ -1846,6 +1874,12 @@ mono_jit_compile_method_with_opt (MonoMethod *method, guint32 opt, MonoException
        MonoJitICallInfo *callinfo = NULL;
        WrapperInfo *winfo = NULL;
 
+       mono_error_init (error);
+
+       if (mono_llvm_only)
+               /* Should be handled by the caller */
+               g_assert (!(method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED));
+
        /*
         * ICALL wrappers are handled specially, since there is only one copy of them
         * shared by all appdomains.
@@ -1878,9 +1912,8 @@ mono_jit_compile_method_with_opt (MonoMethod *method, guint32 opt, MonoException
                                ctx = mono_method_get_context (method);
                        method = info->d.synchronized_inner.method;
                        if (ctx) {
-                               MonoError error;
-                               method = mono_class_inflate_generic_method_checked (method, ctx, &error);
-                               g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
+                               method = mono_class_inflate_generic_method_checked (method, ctx, error);
+                               g_assert (mono_error_ok (error)); /* FIXME don't swallow the error */
                        }
                }
        }
@@ -1890,16 +1923,14 @@ mono_jit_compile_method_with_opt (MonoMethod *method, guint32 opt, MonoException
                /* We can't use a domain specific method in another domain */
                if (! ((domain != target_domain) && !info->domain_neutral)) {
                        MonoVTable *vtable;
-                       MonoException *tmpEx;
 
                        mono_jit_stats.methods_lookups++;
-                       vtable = mono_class_vtable (domain, method->klass);
+                       vtable = mono_class_vtable_full (domain, method->klass, error);
+                       if (!is_ok (error))
+                               return NULL;
                        g_assert (vtable);
-                       tmpEx = mono_runtime_class_init_full (vtable, ex == NULL);
-                       if (tmpEx) {
-                               *ex = tmpEx;
+                       if (!mono_runtime_class_init_full (vtable, error))
                                return NULL;
-                       }
                        return mono_create_ftnptr (target_domain, info->code_start);
                }
        }
@@ -1910,9 +1941,18 @@ mono_jit_compile_method_with_opt (MonoMethod *method, guint32 opt, MonoException
 
                mono_class_init (method->klass);
 
-               if ((code = mono_aot_get_method (domain, method))) {
+               if ((code = mono_aot_get_method_checked (domain, method, error))) {
                        MonoVTable *vtable;
 
+                       if (mono_runtime_is_critical_method (method) || mono_gc_is_critical_method (method)) {
+                               /*
+                                * The suspend code needs to be able to lookup these methods by ip in async context,
+                                * so preload their jit info.
+                                */
+                               MonoJitInfo *ji = mono_jit_info_table_find (domain, code);
+                               g_assert (ji);
+                       }
+
                        /*
                         * In llvm-only mode, method might be a shared method, so we can't initialize its class.
                         * This is not a problem, since it will be initialized when the method is first
@@ -1921,15 +1961,15 @@ mono_jit_compile_method_with_opt (MonoMethod *method, guint32 opt, MonoException
                        if (!mono_llvm_only) {
                                vtable = mono_class_vtable (domain, method->klass);
                                g_assert (vtable);
-                               mono_runtime_class_init (vtable);
+                               if (!mono_runtime_class_init_full (vtable, error))
+                                       return NULL;
                        }
                }
+               if (!is_ok (error))
+                       return NULL;
        }
 #endif
 
-       if (!code)
-               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);
@@ -1943,7 +1983,14 @@ mono_jit_compile_method_with_opt (MonoMethod *method, guint32 opt, MonoException
                                return no_gsharedvt_in_wrapper;
                        }
                }
+       }
 
+       if (!code)
+               code = mono_jit_compile_method_inner (method, target_domain, opt, error);
+       if (!mono_error_ok (error))
+               return NULL;
+
+       if (!code && mono_llvm_only) {
                printf ("AOT method not found in llvmonly mode: %s\n", mono_method_full_name (method, 1));
                g_assert_not_reached ();
        }
@@ -1979,17 +2026,11 @@ mono_jit_compile_method_with_opt (MonoMethod *method, guint32 opt, MonoException
 }
 
 gpointer
-mono_jit_compile_method (MonoMethod *method)
+mono_jit_compile_method (MonoMethod *method, MonoError *error)
 {
-       MonoException *ex = NULL;
        gpointer code;
 
-       code = mono_jit_compile_method_with_opt (method, mono_get_optimizations_for_method (method, default_opt), &ex);
-       if (!code) {
-               g_assert (ex);
-               mono_raise_exception (ex);
-       }
-
+       code = mono_jit_compile_method_with_opt (method, mono_get_optimizations_for_method (method, default_opt), error);
        return code;
 }
 
@@ -2054,7 +2095,6 @@ mono_jit_free_method (MonoDomain *domain, MonoMethod *method)
                }
                g_slist_free (remove);
        }
-
        mono_domain_unlock (domain);
 
 #ifdef MONO_ARCH_HAVE_INVALIDATE_METHOD
@@ -2111,6 +2151,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;
@@ -2122,6 +2188,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) {
@@ -2151,42 +2224,31 @@ typedef struct {
        MonoVTable *vtable;
        MonoDynCallInfo *dyn_call_info;
        MonoClass *ret_box_class;
-       gboolean needs_rgctx;
        MonoMethodSignature *sig;
+       gboolean gsharedvt_invoke;
        gpointer *wrapper_arg;
 } RuntimeInvokeInfo;
 
-gboolean
-mini_gsharedvt_runtime_invoke_supported (MonoMethodSignature *sig)
-{
-       gboolean supported = TRUE;
-       int i;
-
-       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;
-       }
-
-       return supported;
-}
-
 static RuntimeInvokeInfo*
-create_runtime_invoke_info (MonoDomain *domain, MonoMethod *method, gpointer compiled_method)
+create_runtime_invoke_info (MonoDomain *domain, MonoMethod *method, gpointer compiled_method, gboolean callee_gsharedvt, MonoError *error)
 {
        MonoMethod *invoke;
        RuntimeInvokeInfo *info;
 
        info = g_new0 (RuntimeInvokeInfo, 1);
-       info->needs_rgctx = mono_llvm_only && mono_method_needs_static_rgctx_invoke (method, TRUE);
        info->compiled_method = compiled_method;
+       if (mono_llvm_only && method->string_ctor)
+               info->sig = mono_marshal_get_string_ctor_signature (method);
+       else
+               info->sig = mono_method_signature (method);
 
-       invoke = mono_marshal_get_runtime_invoke (method, FALSE, info->needs_rgctx);
-       info->vtable = mono_class_vtable_full (domain, method->klass, TRUE);
+       invoke = mono_marshal_get_runtime_invoke (method, FALSE);
+       info->vtable = mono_class_vtable_full (domain, method->klass, error);
+       if (!mono_error_ok (error))
+               return NULL;
        g_assert (info->vtable);
 
-       MonoMethodSignature *sig = mono_method_signature (method);
+       MonoMethodSignature *sig = info->sig;
        MonoType *ret_type;
 
        /*
@@ -2201,7 +2263,6 @@ create_runtime_invoke_info (MonoDomain *domain, MonoMethod *method, gpointer com
 
                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];
@@ -2261,54 +2322,145 @@ create_runtime_invoke_info (MonoDomain *domain, MonoMethod *method, gpointer com
 
        if (!info->dyn_call_info) {
                if (mono_llvm_only) {
-                       gboolean supported;
-
-                       supported = mini_gsharedvt_runtime_invoke_supported (sig);
-
-                       if (mono_class_is_contextbound (method->klass) || !info->compiled_method)
-                               supported = FALSE;
-
-#ifndef ENABLE_GSHAREDVT
-                       supported = FALSE;
+#ifndef MONO_ARCH_GSHAREDVT_SUPPORTED
+                       g_assert_not_reached ();
 #endif
-
-                       if (supported) {
+                       info->gsharedvt_invoke = TRUE;
+                       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->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;
+                               info->wrapper_arg [0] = mini_add_method_wrappers_llvmonly (method, info->compiled_method, FALSE, FALSE, &(info->wrapper_arg [1]));
 
                                /* 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);
+                               info->compiled_method = mono_jit_compile_method (wrapper, error);
+                               if (!mono_error_ok (error)) {
+                                       g_free (info);
+                                       return NULL;
+                               }
+                       } 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->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);
+               info->runtime_invoke = mono_jit_compile_method (invoke, error);
+               if (!mono_error_ok (error)) {
+                       g_free (info);
+                       return NULL;
+               }
        }
 
        return info;
 }
 
+static MonoObject*
+mono_llvmonly_runtime_invoke (MonoMethod *method, RuntimeInvokeInfo *info, void *obj, void **params, MonoObject **exc, MonoError *error)
+{
+       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;
+
+       mono_error_init (error);
+
+       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 (!t->byref && (MONO_TYPE_IS_REFERENCE (t) || t->type == MONO_TYPE_PTR)) {
+                       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 (exc && *exc)
+               return NULL;
+
+       if (sig->ret->type != MONO_TYPE_VOID && info->ret_box_class)
+               return mono_value_box_checked (domain, info->ret_box_class, retval, error);
+       else
+               return *(MonoObject**)retval;
+}
+
 /**
  * mono_jit_runtime_invoke:
  * @method: the method to invoke
  * @obj: this pointer
  * @params: array of parameter values.
- * @exc: used to catch exceptions objects
+ * @exc: Set to the exception raised in the managed method.  If NULL, error is thrown instead.
+ *       If coop is enabled, this argument is ignored - all exceptoins are caught and propagated
+ *       through @error
+ * @error: error or caught exception object
  */
 static MonoObject*
-mono_jit_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
+mono_jit_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError *error)
 {
        MonoMethod *invoke, *callee;
        MonoObject *(*runtime_invoke) (MonoObject *this_obj, void **params, MonoObject **exc, void* compiled_method);
        MonoDomain *domain = mono_domain_get ();
        MonoJitDomainInfo *domain_info;
        RuntimeInvokeInfo *info, *info2;
+       MonoJitInfo *ji = NULL;
+       gboolean callee_gsharedvt = FALSE;
+
+       mono_error_init (error);
 
        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");
@@ -2326,11 +2478,10 @@ mono_jit_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObjec
                         * but keep it just in case for moonlight.
                         */
                        mono_class_setup_vtable (method->klass);
-                       if (method->klass->exception_type != MONO_EXCEPTION_NONE) {
+                       if (mono_class_has_failure (method->klass)) {
+                               mono_error_set_for_class_failure (error, method->klass);
                                if (exc)
                                        *exc = (MonoObject*)mono_class_get_exception_for_failure (method->klass);
-                               else
-                                       mono_raise_exception (mono_class_get_exception_for_failure (method->klass));
                                return NULL;
                        }
                }
@@ -2351,7 +2502,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;
@@ -2359,26 +2510,28 @@ mono_jit_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObjec
                }
 
                if (callee) {
-                       MonoException *jit_ex = NULL;
-
-                       compiled_method = mono_jit_compile_method_with_opt (callee, mono_get_optimizations_for_method (callee, default_opt), &jit_ex);
+                       compiled_method = mono_jit_compile_method_with_opt (callee, mono_get_optimizations_for_method (callee, default_opt), error);
                        if (!compiled_method) {
-                               g_assert (jit_ex);
-                               if (exc) {
-                                       *exc = (MonoObject*)jit_ex;
-                                       return NULL;
-                               } else {
-                                       mono_raise_exception (jit_ex);
-                                       /* coverity[unreachable] */
-                               }
+                               g_assert (!mono_error_ok (error));
+                               return NULL;
                        }
 
-                       compiled_method = mini_add_method_trampoline (callee, compiled_method, mono_method_needs_static_rgctx_invoke (callee, TRUE), 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 (callee_gsharedvt)
+                                       callee_gsharedvt = mini_is_gsharedvt_variable_signature (mono_method_signature (jinfo_get_method (ji)));
+                       }
+
+                       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;
                }
 
-               info = create_runtime_invoke_info (domain, method, compiled_method);
+               info = create_runtime_invoke_info (domain, method, compiled_method, callee_gsharedvt, error);
+               if (!mono_error_ok (error))
+                       return NULL;
 
                mono_domain_lock (domain);
                info2 = (RuntimeInvokeInfo *)mono_conc_hashtable_insert (domain_info->runtime_invoke_hash, method, info);
@@ -2393,14 +2546,20 @@ mono_jit_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObjec
         * We need this here because mono_marshal_get_runtime_invoke can place
         * the helper method in System.Object and not the target class.
         */
-       if (exc) {
-               *exc = (MonoObject*)mono_runtime_class_init_full (info->vtable, FALSE);
-               if (*exc)
-                       return NULL;
-       } else {
-               mono_runtime_class_init (info->vtable);
+       if (!mono_runtime_class_init_full (info->vtable, error)) {
+               if (exc)
+                       *exc = (MonoObject*) mono_error_convert_to_exception (error);
+               return NULL;
        }
 
+       /* If coop is enabled, and the caller didn't ask for the exception to be caught separately,
+          we always catch the exception and propagate it through the MonoError */
+       gboolean catchExcInMonoError =
+               (exc == NULL) && mono_threads_is_coop_enabled ();
+       MonoObject *invoke_exc = NULL;
+       if (catchExcInMonoError)
+               exc = &invoke_exc;
+
        /* The wrappers expect this to be initialized to NULL */
        if (exc)
                *exc = NULL;
@@ -2413,15 +2572,16 @@ 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 = (RuntimeInvokeDynamicFunction)mono_jit_compile_method (invoke);
+                       dyn_runtime_invoke = (RuntimeInvokeDynamicFunction)mono_jit_compile_method (invoke, error);
+                       if (!mono_error_ok (error))
+                               return NULL;
                }
 
                /* Convert the arguments to the format expected by start_dyn_call () */
-               args = (void **)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;
@@ -2436,124 +2596,73 @@ 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));
 
                mono_arch_start_dyn_call (info->dyn_call_info, (gpointer**)args, retval, buf, sizeof (buf));
 
                dyn_runtime_invoke (buf, exc, info->compiled_method);
-
                mono_arch_finish_dyn_call (info->dyn_call_info, buf);
 
-               if (info->ret_box_class)
-                       return mono_value_box (domain, info->ret_box_class, retval);
-               else
-                       return *(MonoObject**)retval;
-       }
-#endif
-
-       runtime_invoke = (MonoObject *(*)(MonoObject *, void **, MonoObject **, void *))info->runtime_invoke;
-
-       if (info->wrapper_arg) {
-               MonoMethodSignature *sig = mono_method_signature (method);
-               gpointer *args;
-               gpointer retval_ptr;
-               guint8 retval [256];
-               gpointer *param_refs;
-               int i, pindex;
-
-               /*
-                * 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.
-                */
-               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 (MONO_TYPE_IS_REFERENCE (t)) {
-                               param_refs [i] = params [i];
-                               params [i] = &(param_refs [i]);
-                       }
-                       args [pindex ++] = &params [i];
+               if (catchExcInMonoError && *exc != NULL) {
+                       mono_error_set_exception_instance (error, (MonoException*) *exc);
+                       return NULL;
                }
-               /* The gsharedvt out wrapper has an extra argument which contains the method to call */
-               args [pindex ++] = &info->wrapper_arg;
-               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);
+               if (info->ret_box_class)
+                       return mono_value_box_checked (domain, info->ret_box_class, retval, error);
                else
                        return *(MonoObject**)retval;
        }
+#endif
 
-       // FIXME: Cache this
-       if (info->needs_rgctx) {
-               MonoMethodSignature *sig = mono_method_signature (method);
-               gpointer rgctx;
-               gpointer *args;
-               int i, pindex;
+       MonoObject *result;
 
-               args = (void **)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 ((MonoObject *)obj, args, exc, info->compiled_method);
+       if (mono_llvm_only) {
+               result = mono_llvmonly_runtime_invoke (method, info, obj, params, exc, error);
+               if (!is_ok (error))
+                       return NULL;
        } else {
-               return runtime_invoke ((MonoObject *)obj, params, exc, info->compiled_method);
+               runtime_invoke = (MonoObject *(*)(MonoObject *, void **, MonoObject **, void *))info->runtime_invoke;
+
+               result = runtime_invoke ((MonoObject *)obj, params, exc, info->compiled_method);
        }
+       if (catchExcInMonoError && *exc != NULL)
+               mono_error_set_exception_instance (error, (MonoException*) *exc);
+       return result;
 }
 
 typedef struct {
        MonoVTable *vtable;
        int slot;
-} IMTThunkInfo;
+} IMTTrampInfo;
 
-typedef gpointer (*IMTThunkFunc) (gpointer *arg, MonoMethod *imt_method);
+typedef gpointer (*IMTTrampFunc) (gpointer *arg, MonoMethod *imt_method);
 
 /*
- * mini_llvmonly_initial_imt_thunk:
+ * mini_llvmonly_initial_imt_tramp:
  *
- *  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.
+ *  This function is called the first time a call is made through an IMT trampoline.
+ * It should have the same signature as the mono_llvmonly_imt_tramp_... functions.
  */
 static gpointer
-mini_llvmonly_initial_imt_thunk (gpointer *arg, MonoMethod *imt_method)
+mini_llvmonly_initial_imt_tramp (gpointer *arg, MonoMethod *imt_method)
 {
-       IMTThunkInfo *info = (IMTThunkInfo*)arg;
+       IMTTrampInfo *info = (IMTTrampInfo*)arg;
        gpointer *imt;
        gpointer *ftndesc;
-       IMTThunkFunc func;
+       IMTTrampFunc 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 */
+       /* Return what the real IMT trampoline returns */
        ftndesc = imt [info->slot];
        func = ftndesc [0];
 
-       if (func == (IMTThunkFunc)mini_llvmonly_initial_imt_thunk)
+       if (func == (IMTTrampFunc)mini_llvmonly_initial_imt_tramp)
                /* Happens when the imt slot contains only a generic virtual method */
                return NULL;
        return func ((gpointer *)ftndesc [1], imt_method);
@@ -2561,11 +2670,11 @@ mini_llvmonly_initial_imt_thunk (gpointer *arg, MonoMethod *imt_method)
 
 /* This is called indirectly through an imt slot. */
 static gpointer
-mono_llvmonly_imt_thunk (gpointer *arg, MonoMethod *imt_method)
+mono_llvmonly_imt_tramp (gpointer *arg, MonoMethod *imt_method)
 {
        int i = 0;
 
-       /* arg points to an array created in mono_llvmonly_get_imt_thunk () */
+       /* arg points to an array created in mono_llvmonly_get_imt_trampoline () */
        while (arg [i] && arg [i] != imt_method)
                i += 2;
        g_assert (arg [i]);
@@ -2573,16 +2682,16 @@ mono_llvmonly_imt_thunk (gpointer *arg, MonoMethod *imt_method)
        return arg [i + 1];
 }
 
-/* Optimized versions of mono_llvmonly_imt_thunk () for different table sizes */
+/* Optimized versions of mono_llvmonly_imt_trampoline () for different table sizes */
 static gpointer
-mono_llvmonly_imt_thunk_1 (gpointer *arg, MonoMethod *imt_method)
+mono_llvmonly_imt_tramp_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)
+mono_llvmonly_imt_tramp_2 (gpointer *arg, MonoMethod *imt_method)
 {
        //g_assert (arg [0] == imt_method || arg [2] == imt_method);
        if (arg [0] == imt_method)
@@ -2592,7 +2701,7 @@ mono_llvmonly_imt_thunk_2 (gpointer *arg, MonoMethod *imt_method)
 }
 
 static gpointer
-mono_llvmonly_imt_thunk_3 (gpointer *arg, MonoMethod *imt_method)
+mono_llvmonly_imt_tramp_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)
@@ -2604,14 +2713,14 @@ mono_llvmonly_imt_thunk_3 (gpointer *arg, MonoMethod *imt_method)
 }
 
 /*
- * A version of the imt thunk used for generic virtual methods.
- * Unlikely a normal imt thunk, its possible that IMT_METHOD is not found
+ * A version of the imt trampoline used for generic virtual/variant iface methods.
+ * Unlikely a normal imt trampoline, 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)
+mono_llvmonly_fallback_imt_tramp (gpointer *arg, MonoMethod *imt_method)
 {
        int i = 0;
 
@@ -2624,7 +2733,7 @@ mono_llvmonly_generic_virtual_imt_thunk (gpointer *arg, MonoMethod *imt_method)
 }
 
 static gpointer
-mono_llvmonly_get_imt_thunk (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckItem **imt_entries, int count, gpointer fail_tramp)
+mono_llvmonly_get_imt_trampoline (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckItem **imt_entries, int count, gpointer fail_tramp)
 {
        gpointer *buf;
        gpointer *res;
@@ -2632,7 +2741,7 @@ mono_llvmonly_get_imt_thunk (MonoVTable *vtable, MonoDomain *domain, MonoIMTChec
        gboolean virtual_generic = FALSE;
 
        /*
-        * Create an array which is passed to the imt thunk functions.
+        * Create an array which is passed to the imt trampoline functions.
         * The array contains MonoMethod-function descriptor pairs, terminated by a NULL entry.
         */
 
@@ -2687,20 +2796,20 @@ mono_llvmonly_get_imt_thunk (MonoVTable *vtable, MonoDomain *domain, MonoIMTChec
        res = (void **)mono_domain_alloc (domain, 2 * sizeof (gpointer));
        switch (real_count) {
        case 1:
-               res [0] = mono_llvmonly_imt_thunk_1;
+               res [0] = mono_llvmonly_imt_tramp_1;
                break;
        case 2:
-               res [0] = mono_llvmonly_imt_thunk_2;
+               res [0] = mono_llvmonly_imt_tramp_2;
                break;
        case 3:
-               res [0] = mono_llvmonly_imt_thunk_3;
+               res [0] = mono_llvmonly_imt_tramp_3;
                break;
        default:
-               res [0] = mono_llvmonly_imt_thunk;
+               res [0] = mono_llvmonly_imt_tramp;
                break;
        }
-       if (virtual_generic)
-               res [0] = mono_llvmonly_generic_virtual_imt_thunk;
+       if (virtual_generic || fail_tramp)
+               res [0] = mono_llvmonly_fallback_imt_tramp;
        res [1] = buf;
 
        return res;
@@ -2747,9 +2856,16 @@ MONO_SIG_HANDLER_FUNC (, mono_sigill_signal_handler)
        MonoException *exc;
        MONO_SIG_HANDLER_GET_CONTEXT;
 
+       if (mono_runtime_get_no_exec ())
+               exit (1);
+
+       MONO_ENTER_GC_UNSAFE_UNBALANCED;
+
        exc = mono_get_exception_execution_engine ("SIGILL");
 
        mono_arch_handle_exception (ctx, exc);
+
+       MONO_EXIT_GC_UNSAFE_UNBALANCED;
 }
 
 #if defined(MONO_ARCH_USE_SIGACTION) || defined(HOST_WIN32)
@@ -2870,35 +2986,36 @@ MONO_SIG_HANDLER_FUNC (, mono_sigint_signal_handler)
  * Returns: a pointer to the newly created code
  */
 static gpointer
-mono_jit_create_remoting_trampoline (MonoDomain *domain, MonoMethod *method, MonoRemotingTarget target)
+mono_jit_create_remoting_trampoline (MonoDomain *domain, MonoMethod *method, MonoRemotingTarget target, MonoError *error)
 {
        MonoMethod *nm;
        guint8 *addr = NULL;
 
+       mono_error_init (error);
+
        if ((method->flags & METHOD_ATTRIBUTE_VIRTUAL) && mono_method_signature (method)->generic_param_count) {
                return mono_create_specific_trampoline (method, MONO_TRAMPOLINE_GENERIC_VIRTUAL_REMOTING,
                        domain, NULL);
        }
 
        if ((method->flags & METHOD_ATTRIBUTE_ABSTRACT) ||
-           (mono_method_signature (method)->hasthis && (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class))) {
+           (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 = (guint8 *)mono_compile_method (nm);
-       } else
-       {
-               addr = (guint8 *)mono_compile_method (method);
-       }
+       else
+               nm = method;
+       addr = (guint8 *)mono_compile_method_checked (nm, error);
+       return_val_if_nok (error, NULL);
        return mono_get_addr_from_ftnptr (addr);
 }
 #endif
 
-static void
+static G_GNUC_UNUSED void
 no_imt_trampoline (void)
 {
        g_assert_not_reached ();
 }
 
-static void
+static G_GNUC_UNUSED void
 no_vcall_trampoline (void)
 {
        g_assert_not_reached ();
@@ -2914,13 +3031,13 @@ mini_get_vtable_trampoline (MonoVTable *vt, int slot_index)
 
        if (mono_llvm_only) {
                if (slot_index < 0) {
-                       /* Initialize the IMT thunks to a 'trampoline' so the generated code doesn't have to initialize it */
+                       /* Initialize the IMT trampoline 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);
+                       IMTTrampInfo *info = g_new0 (IMTTrampInfo, 1);
                        info->vtable = vt;
                        info->slot = index;
-                       ftndesc [0] = mini_llvmonly_initial_imt_thunk;
+                       ftndesc [0] = mini_llvmonly_initial_imt_tramp;
                        ftndesc [1] = info;
                        mono_memory_barrier ();
                        return ftndesc;
@@ -2974,6 +3091,59 @@ mini_imt_entry_inited (MonoVTable *vt, int imt_slot_index)
        return (imt [imt_slot_index] != mini_get_imt_trampoline (vt, imt_slot_index));
 }
 
+static gboolean
+is_callee_gsharedvt_variable (gpointer addr)
+{
+       MonoJitInfo *ji;
+       gboolean callee_gsharedvt;
+
+       ji = mini_jit_info_table_find (mono_domain_get (), (char *)mono_get_addr_from_ftnptr (addr), NULL);
+       g_assert (ji);
+       callee_gsharedvt = mini_jit_info_is_gsharedvt (ji);
+       if (callee_gsharedvt)
+               callee_gsharedvt = mini_is_gsharedvt_variable_signature (mono_method_signature (jinfo_get_method (ji)));
+       return callee_gsharedvt;
+}
+
+gpointer
+mini_get_delegate_arg (MonoMethod *method, gpointer method_ptr)
+{
+       gpointer arg = NULL;
+
+       if (mono_method_needs_static_rgctx_invoke (method, FALSE))
+               arg = mini_method_get_rgctx (method);
+
+       /*
+        * Avoid adding gsharedvt in wrappers since they might not exist if
+        * this delegate is called through a gsharedvt delegate invoke wrapper.
+        * Instead, encode that the method is gsharedvt in del->extra_arg,
+        * the CEE_MONO_CALLI_EXTRA_ARG implementation in the JIT depends on this.
+        */
+       if (method->is_inflated && is_callee_gsharedvt_variable (method_ptr)) {
+               g_assert ((((mgreg_t)arg) & 1) == 0);
+               arg = (gpointer)(((mgreg_t)arg) | 1);
+       }
+       return arg;
+}
+
+void
+mini_init_delegate (MonoDelegate *del)
+{
+       if (mono_llvm_only)
+               del->extra_arg = mini_get_delegate_arg (del->method, del->method_ptr);
+}
+
+char*
+mono_get_delegate_virtual_invoke_impl_name (gboolean load_imt_reg, int offset)
+{
+       int abs_offset;
+
+       abs_offset = offset;
+       if (abs_offset < 0)
+               abs_offset = - abs_offset;
+       return g_strdup_printf ("delegate_virtual_invoke%s_%s%d", load_imt_reg ? "_imt" : "", offset < 0 ? "m_" : "", abs_offset / SIZEOF_VOID_P);
+}
+
 gpointer
 mono_get_delegate_virtual_invoke_impl (MonoMethodSignature *sig, MonoMethod *method)
 {
@@ -2990,10 +3160,10 @@ mono_get_delegate_virtual_invoke_impl (MonoMethodSignature *sig, MonoMethod *met
                return NULL;
 
        is_virtual_generic = method->is_inflated && mono_method_get_declaring_generic_method (method)->is_generic;
-       is_interface = method->klass->flags & TYPE_ATTRIBUTE_INTERFACE ? TRUE : FALSE;
+       is_interface = mono_class_is_interface (method->klass);
        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));
@@ -3025,12 +3195,7 @@ mono_get_delegate_virtual_invoke_impl (MonoMethodSignature *sig, MonoMethod *met
 
        /* FIXME Support more cases */
        if (mono_aot_only) {
-               char tramp_name [256];
-               const char *imt = load_imt_reg ? "_imt" : "";
-               int ind = (load_imt_reg ? (-offset) : offset) / SIZEOF_VOID_P;
-
-               sprintf (tramp_name, "delegate_virtual_invoke%s_%d", imt, ind);
-               cache [idx] = (guint8 *)mono_aot_get_trampoline (tramp_name);
+               cache [idx] = (guint8 *)mono_aot_get_trampoline (mono_get_delegate_virtual_invoke_impl_name (load_imt_reg, offset));
                g_assert (cache [idx]);
        } else {
                cache [idx] = (guint8 *)mono_arch_get_delegate_virtual_invoke_impl (sig, method, offset, load_imt_reg);
@@ -3038,6 +3203,77 @@ mono_get_delegate_virtual_invoke_impl (MonoMethodSignature *sig, MonoMethod *met
        return cache [idx];
 }
 
+/**
+ * mini_parse_debug_option:
+ * @option: The option to parse.
+ *
+ * Parses debug options for the mono runtime. The options are the same as for
+ * the MONO_DEBUG environment variable.
+ *
+ */
+gboolean
+mini_parse_debug_option (const char *option)
+{
+       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"))
+               fprintf (stderr, "Mono Warning: option gen-compact-seq-points is deprecated.\n");
+       else if (!strcmp (option, "no-compact-seq-points"))
+               debug_options.no_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 if (!strcmp (option, "disable_omit_fp"))
+               debug_options.disable_omit_fp = TRUE;
+       else
+               return FALSE;
+
+       return TRUE;
+}
+
 static void
 mini_parse_debug_options (void)
 {
@@ -3052,59 +3288,9 @@ 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");
+                       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', 'no-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);
                }
        }
@@ -3163,6 +3349,44 @@ register_jit_stats (void)
        mono_counters_register ("Methods from AOT", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.methods_aot);
        mono_counters_register ("Methods JITted using mono JIT", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.methods_without_llvm);
        mono_counters_register ("Methods JITted using LLVM", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.methods_with_llvm);
+       mono_counters_register ("JIT/method_to_ir (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_method_to_ir);
+       mono_counters_register ("JIT/liveness_handle_exception_clauses (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_liveness_handle_exception_clauses);
+       mono_counters_register ("JIT/handle_out_of_line_bblock (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_handle_out_of_line_bblock);
+       mono_counters_register ("JIT/decompose_long_opts (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_decompose_long_opts);
+       mono_counters_register ("JIT/decompose_typechecks (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_decompose_typechecks);
+       mono_counters_register ("JIT/local_cprop (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_local_cprop);
+       mono_counters_register ("JIT/local_emulate_ops (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_local_emulate_ops);
+       mono_counters_register ("JIT/optimize_branches (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_optimize_branches);
+       mono_counters_register ("JIT/handle_global_vregs (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_handle_global_vregs);
+       mono_counters_register ("JIT/local_deadce (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_local_deadce);
+       mono_counters_register ("JIT/local_alias_analysis (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_local_alias_analysis);
+       mono_counters_register ("JIT/if_conversion (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_if_conversion);
+       mono_counters_register ("JIT/bb_ordering (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_bb_ordering);
+       mono_counters_register ("JIT/compile_dominator_info (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_compile_dominator_info);
+       mono_counters_register ("JIT/compute_natural_loops (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_compute_natural_loops);
+       mono_counters_register ("JIT/insert_safepoints (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_insert_safepoints);
+       mono_counters_register ("JIT/ssa_compute (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_ssa_compute);
+       mono_counters_register ("JIT/ssa_cprop (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_ssa_cprop);
+       mono_counters_register ("JIT/ssa_deadce(sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_ssa_deadce);
+       mono_counters_register ("JIT/perform_abc_removal (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_perform_abc_removal);
+       mono_counters_register ("JIT/ssa_remove (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_ssa_remove);
+       mono_counters_register ("JIT/local_cprop2 (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_local_cprop2);
+       mono_counters_register ("JIT/handle_global_vregs2 (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_handle_global_vregs2);
+       mono_counters_register ("JIT/local_deadce2 (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_local_deadce2);
+       mono_counters_register ("JIT/optimize_branches2 (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_optimize_branches2);
+       mono_counters_register ("JIT/decompose_vtype_opts (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_decompose_vtype_opts);
+       mono_counters_register ("JIT/decompose_array_access_opts (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_decompose_array_access_opts);
+       mono_counters_register ("JIT/liveness_handle_exception_clauses2 (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_liveness_handle_exception_clauses2);
+       mono_counters_register ("JIT/analyze_liveness (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_analyze_liveness);
+       mono_counters_register ("JIT/linear_scan (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_linear_scan);
+       mono_counters_register ("JIT/arch_allocate_vars (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_arch_allocate_vars);
+       mono_counters_register ("JIT/spill_global_vars (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_spill_global_vars);
+       mono_counters_register ("JIT/local_cprop3 (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_local_cprop3);
+       mono_counters_register ("JIT/local_deadce3 (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_local_deadce3);
+       mono_counters_register ("JIT/codegen (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_codegen);
+       mono_counters_register ("JIT/create_jit_info (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_create_jit_info);
+       mono_counters_register ("JIT/gc_create_gc_map (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_gc_create_gc_map);
+       mono_counters_register ("JIT/save_seq_point_info (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_save_seq_point_info);
        mono_counters_register ("Total time spent JITting (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_time);
        mono_counters_register ("Basic blocks", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.basic_blocks);
        mono_counters_register ("Max basic blocks", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.max_basic_blocks);
@@ -3181,6 +3405,7 @@ register_jit_stats (void)
        mono_counters_register ("Aliases eliminated", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.alias_removed);
        mono_counters_register ("Aliased loads eliminated", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.loads_eliminated);
        mono_counters_register ("Aliased stores eliminated", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.stores_eliminated);
+       mono_counters_register ("Optimized immediate divisions", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.optimized_divisions);
 }
 
 static void runtime_invoke_info_free (gpointer value);
@@ -3253,6 +3478,12 @@ runtime_invoke_info_free (gpointer value)
        g_free (info);
 }
 
+static void
+free_jit_callee_list (gpointer key, gpointer value, gpointer user_data)
+{
+       g_slist_free (value);
+}
+
 static void
 mini_free_jit_domain_info (MonoDomain *domain)
 {
@@ -3283,6 +3514,10 @@ mini_free_jit_domain_info (MonoDomain *domain)
                mono_debugger_agent_free_domain_info (domain);
        if (info->gsharedvt_arg_tramp_hash)
                g_hash_table_destroy (info->gsharedvt_arg_tramp_hash);
+       if (info->llvm_jit_callees) {
+               g_hash_table_foreach (info->llvm_jit_callees, free_jit_callee_list, NULL);
+               g_hash_table_destroy (info->llvm_jit_callees);
+       }
 #ifdef ENABLE_LLVM
        mono_llvm_free_domain_info (domain);
 #endif
@@ -3331,6 +3566,7 @@ mini_llvm_init (void)
 MonoDomain *
 mini_init (const char *filename, const char *runtime_version)
 {
+       MonoError error;
        MonoDomain *domain;
        MonoRuntimeCallbacks callbacks;
        MonoThreadInfoRuntimeCallbacks ticallbacks;
@@ -3385,10 +3621,20 @@ mini_init (const char *filename, const char *runtime_version)
        callbacks.debug_log = mono_debugger_agent_debug_log;
        callbacks.debug_log_is_enabled = mono_debugger_agent_debug_log_is_enabled;
        callbacks.tls_key_supported = mini_tls_key_supported;
-
        callbacks.get_vtable_trampoline = mini_get_vtable_trampoline;
        callbacks.get_imt_trampoline = mini_get_imt_trampoline;
        callbacks.imt_entry_inited = mini_imt_entry_inited;
+       callbacks.init_delegate = mini_init_delegate;
+#define JIT_INVOKE_WORKS
+#ifdef JIT_INVOKE_WORKS
+       callbacks.runtime_invoke = mono_jit_runtime_invoke;
+#endif
+#define JIT_TRAMPOLINES_WORK
+#ifdef JIT_TRAMPOLINES_WORK
+       callbacks.compile_method = mono_jit_compile_method;
+       callbacks.create_jump_trampoline = mono_create_jump_trampoline;
+       callbacks.create_jit_trampoline = mono_create_jit_trampoline;
+#endif
 
        mono_install_callbacks (&callbacks);
 
@@ -3400,6 +3646,10 @@ mini_init (const char *filename, const char *runtime_version)
 
        mono_counters_init ();
 
+#ifndef HOST_WIN32
+       mono_w32handle_init ();
+#endif
+
        mono_threads_runtime_init (&ticallbacks);
 
        if (g_getenv ("MONO_DEBUG") != NULL)
@@ -3458,22 +3708,14 @@ mini_init (const char *filename, const char *runtime_version)
 #endif
        mono_threads_install_cleanup (mini_thread_cleanup);
 
-#define JIT_TRAMPOLINES_WORK
 #ifdef JIT_TRAMPOLINES_WORK
-       mono_install_compile_method (mono_jit_compile_method);
        mono_install_free_method (mono_jit_free_method);
-       mono_install_trampoline (mono_create_jit_trampoline);
-       mono_install_jump_trampoline (mono_create_jump_trampoline);
 #ifndef DISABLE_REMOTING
        mono_install_remoting_trampoline (mono_jit_create_remoting_trampoline);
 #endif
        mono_install_delegate_trampoline (mono_create_delegate_trampoline);
        mono_install_create_domain_hook (mini_create_jit_domain_info);
        mono_install_free_domain_hook (mini_free_jit_domain_info);
-#endif
-#define JIT_INVOKE_WORKS
-#ifdef JIT_INVOKE_WORKS
-       mono_install_runtime_invoke (mono_jit_runtime_invoke);
 #endif
        mono_install_get_cached_class_info (mono_aot_get_cached_class_info);
        mono_install_get_class_from_name (mono_aot_get_class_from_name);
@@ -3494,12 +3736,12 @@ mini_init (const char *filename, const char *runtime_version)
        }
 
        if (mono_llvm_only) {
-               mono_install_imt_thunk_builder (mono_llvmonly_get_imt_thunk);
-               mono_set_always_build_imt_thunks (TRUE);
+               mono_install_imt_trampoline_builder (mono_llvmonly_get_imt_trampoline);
+               mono_set_always_build_imt_trampolines (TRUE);
        } else if (mono_aot_only) {
-               mono_install_imt_thunk_builder (mono_aot_get_imt_thunk);
+               mono_install_imt_trampoline_builder (mono_aot_get_imt_trampoline);
        } else {
-               mono_install_imt_thunk_builder (mono_arch_build_imt_thunk);
+               mono_install_imt_trampoline_builder (mono_arch_build_imt_trampoline);
        }
 
        /*Init arch tls information only after the metadata side is inited to make sure we see dynamic appdomain tls keys*/
@@ -3535,9 +3777,7 @@ mini_init (const char *filename, const char *runtime_version)
        mono_simd_intrinsics_init ();
 #endif
 
-#if MONO_SUPPORT_TASKLETS
        mono_tasklets_init ();
-#endif
 
        register_trampolines (domain);
 
@@ -3548,13 +3788,19 @@ mini_init (const char *filename, const char *runtime_version)
                 */
                mono_runtime_set_no_exec (TRUE);
 
+       mono_mem_account_register_counters ();
+
 #define JIT_RUNTIME_WORKS
 #ifdef JIT_RUNTIME_WORKS
        mono_install_runtime_cleanup ((MonoDomainFunc)mini_cleanup);
-       mono_runtime_init (domain, mono_thread_start_cb, mono_thread_attach_cb);
+       mono_runtime_init_checked (domain, mono_thread_start_cb, mono_thread_attach_cb, &error);
+       mono_error_assert_ok (&error);
        mono_thread_attach (domain);
 #endif
 
+       if (mono_profiler_get_events () & MONO_PROFILE_STATISTICAL)
+               mono_runtime_setup_stat_profiler ();
+
        mono_profiler_runtime_initialized ();
 
        MONO_VES_INIT_END ();
@@ -3571,6 +3817,8 @@ register_icalls (void)
                                ves_icall_get_trace);
        mono_add_internal_call ("Mono.Runtime::mono_runtime_install_handlers",
                                mono_runtime_install_handlers);
+       mono_add_internal_call ("Mono.Runtime::mono_runtime_cleanup_handlers",
+                               mono_runtime_cleanup_handlers);
 
 #if defined(PLATFORM_ANDROID) || defined(TARGET_ANDROID)
        mono_add_internal_call ("System.Diagnostics.Debugger::Mono_UnhandledException_internal",
@@ -3600,7 +3848,7 @@ register_icalls (void)
        register_icall (mono_llvm_match_exception, "mono_llvm_match_exception", "int ptr int int", TRUE);
        register_icall (mono_llvm_clear_exception, "mono_llvm_clear_exception", NULL, TRUE);
        register_icall (mono_llvm_load_exception, "mono_llvm_load_exception", "object", TRUE);
-       register_icall (mono_llvm_throw_corlib_exception, "mono_llvm_throw_corlib_exception", "void int", FALSE);
+       register_icall (mono_llvm_throw_corlib_exception, "mono_llvm_throw_corlib_exception", "void int", TRUE);
 #if defined(ENABLE_LLVM) && !defined(MONO_LLVM_LOADED)
        register_icall (mono_llvm_set_unhandled_exception_handler, "mono_llvm_set_unhandled_exception_handler", NULL, TRUE);
 
@@ -3614,11 +3862,6 @@ register_icalls (void)
        register_icall (mono_thread_get_undeniable_exception, "mono_thread_get_undeniable_exception", "object", FALSE);
        register_icall (mono_thread_interruption_checkpoint, "mono_thread_interruption_checkpoint", "object", FALSE);
        register_icall (mono_thread_force_interruption_checkpoint_noraise, "mono_thread_force_interruption_checkpoint_noraise", "object", FALSE);
-       register_icall (mono_thread_force_interruption_checkpoint, "mono_thread_force_interruption_checkpoint", "void", FALSE);
-#ifndef DISABLE_REMOTING
-       register_icall (mono_load_remote_field_new, "mono_load_remote_field_new", "object object ptr ptr", FALSE);
-       register_icall (mono_store_remote_field_new, "mono_store_remote_field_new", "void object ptr ptr object", FALSE);
-#endif
 
 #if defined(__native_client__) || defined(__native_client_codegen__)
        register_icall (mono_nacl_gc, "mono_nacl_gc", "void", FALSE);
@@ -3692,10 +3935,10 @@ register_icalls (void)
        register_opcode_emulation (OP_LCONV_TO_R_UN, "__emul_lconv_to_r8_un", "double long", mono_lconv_to_r8_un, "mono_lconv_to_r8_un", FALSE);
 #endif
 #ifdef MONO_ARCH_EMULATE_FREM
-#if defined(__default_codegen__)
+#if !defined(__native_client__)
        register_opcode_emulation (OP_FREM, "__emul_frem", "double double double", fmod, "fmod", FALSE);
        register_opcode_emulation (OP_RREM, "__emul_rrem", "float float float", fmodf, "fmodf", FALSE);
-#elif defined(__native_client_codegen__)
+#else
        register_opcode_emulation (OP_FREM, "__emul_frem", "double double double", mono_fmod, "mono_fmod", FALSE);
 #endif
 #endif
@@ -3755,20 +3998,20 @@ register_icalls (void)
 #endif
 
        /* other jit icalls */
-       register_icall (mono_delegate_ctor, "mono_delegate_ctor", "void object object ptr", FALSE);
+       register_icall (ves_icall_mono_delegate_ctor, "ves_icall_mono_delegate_ctor", "void object object ptr", FALSE);
        register_icall (mono_class_static_field_address , "mono_class_static_field_address",
                                 "ptr ptr ptr", FALSE);
        register_icall (mono_ldtoken_wrapper, "mono_ldtoken_wrapper", "ptr ptr ptr ptr", FALSE);
        register_icall (mono_ldtoken_wrapper_generic_shared, "mono_ldtoken_wrapper_generic_shared",
                "ptr ptr ptr ptr", FALSE);
        register_icall (mono_get_special_static_data, "mono_get_special_static_data", "ptr int", FALSE);
-       register_icall (mono_ldstr, "mono_ldstr", "object ptr ptr int32", FALSE);
+       register_icall (ves_icall_mono_ldstr, "ves_icall_mono_ldstr", "object ptr ptr int32", FALSE);
        register_icall (mono_helper_stelem_ref_check, "mono_helper_stelem_ref_check", "void object object", FALSE);
-       register_icall (mono_object_new, "mono_object_new", "object ptr ptr", FALSE);
-       register_icall (mono_object_new_specific, "mono_object_new_specific", "object ptr", FALSE);
-       register_icall (mono_array_new, "mono_array_new", "object ptr ptr int32", FALSE);
-       register_icall (mono_array_new_specific, "mono_array_new_specific", "object ptr int32", FALSE);
-       register_icall (mono_runtime_class_init, "mono_runtime_class_init", "void ptr", FALSE);
+       register_icall (ves_icall_object_new, "ves_icall_object_new", "object ptr ptr", FALSE);
+       register_icall (ves_icall_object_new_specific, "ves_icall_object_new_specific", "object ptr", FALSE);
+       register_icall (ves_icall_array_new, "ves_icall_array_new", "object ptr ptr int32", FALSE);
+       register_icall (ves_icall_array_new_specific, "ves_icall_array_new_specific", "object ptr int32", FALSE);
+       register_icall (ves_icall_runtime_class_init, "ves_icall_runtime_class_init", "void ptr", FALSE);
        register_icall (mono_ldftn, "mono_ldftn", "ptr ptr", FALSE);
        register_icall (mono_ldvirtfn, "mono_ldvirtfn", "ptr object ptr", FALSE);
        register_icall (mono_ldvirtfn_gshared, "mono_ldvirtfn_gshared", "ptr object ptr", FALSE);
@@ -3796,14 +4039,15 @@ register_icalls (void)
        register_icall (mono_object_castclass_with_cache, "mono_object_castclass_with_cache", "object object ptr ptr", FALSE);
        register_icall (mono_object_isinst_with_cache, "mono_object_isinst_with_cache", "object object ptr ptr", FALSE);
        register_icall (mono_generic_class_init, "mono_generic_class_init", "void ptr", FALSE);
-       register_icall (mono_fill_class_rgctx, "mono_class_fill_rgctx", "ptr ptr int", FALSE);
-       register_icall (mono_fill_method_rgctx, "mono_method_fill_rgctx", "ptr ptr int", FALSE);
+       register_icall (mono_fill_class_rgctx, "mono_fill_class_rgctx", "ptr ptr int", FALSE);
+       register_icall (mono_fill_method_rgctx, "mono_fill_method_rgctx", "ptr ptr int", FALSE);
 
        register_icall (mono_debugger_agent_user_break, "mono_debugger_agent_user_break", "void", FALSE);
 
        register_icall (mono_aot_init_llvm_method, "mono_aot_init_llvm_method", "void ptr int", TRUE);
        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 (mono_aot_init_gshared_method_mrgctx, "mono_aot_init_gshared_method_mrgctx", "void ptr int ptr", TRUE);
+       register_icall (mono_aot_init_gshared_method_vtable, "mono_aot_init_gshared_method_vtable", "void ptr int ptr", TRUE);
 
        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");
@@ -3811,9 +4055,17 @@ register_icalls (void)
        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_llvmonly_init_delegate, "mono_llvmonly_init_delegate", "void object", TRUE);
+       register_icall (mono_llvmonly_init_delegate_virtual, "mono_llvmonly_init_delegate_virtual", "void object object ptr", TRUE);
        register_icall (mono_get_assembly_object, "mono_get_assembly_object", "object ptr", TRUE);
+       register_icall (mono_get_method_object, "mono_get_method_object", "object ptr", TRUE);
+       register_icall (mono_throw_method_access, "mono_throw_method_access", "void ptr ptr", FALSE);
+       register_icall_no_wrapper (mono_dummy_jit_icall, "mono_dummy_jit_icall", "void");
+
+       register_icall_with_wrapper (mono_monitor_enter, "mono_monitor_enter", "void obj");
+       register_icall_with_wrapper (mono_monitor_enter_v4, "mono_monitor_enter_v4", "void obj ptr");
+       register_icall_no_wrapper (mono_monitor_enter_fast, "mono_monitor_enter_fast", "int obj");
+       register_icall_no_wrapper (mono_monitor_enter_v4_fast, "mono_monitor_enter_v4_fast", "int obj ptr");
 
 #ifdef TARGET_IOS
        register_icall (pthread_getspecific, "pthread_getspecific", "ptr ptr", TRUE);
@@ -3857,7 +4109,7 @@ print_jit_stats (void)
                g_print ("IMT colliding slots:    %ld\n", mono_stats.imt_slots_with_collisions);
                g_print ("IMT max collisions:     %ld\n", mono_stats.imt_max_collisions_in_slot);
                g_print ("IMT methods at max col: %ld\n", mono_stats.imt_method_count_when_max_collisions);
-               g_print ("IMT thunks size:        %ld\n", mono_stats.imt_thunks_size);
+               g_print ("IMT trampolines size:   %ld\n", mono_stats.imt_trampolines_size);
 
                g_print ("JIT info table inserts: %ld\n", mono_stats.jit_info_table_insert_count);
                g_print ("JIT info table removes: %ld\n", mono_stats.jit_info_table_remove_count);
@@ -3873,7 +4125,8 @@ print_jit_stats (void)
 void
 mini_cleanup (MonoDomain *domain)
 {
-       mono_runtime_shutdown_stat_profiler ();
+       if (mono_profiler_get_events () & MONO_PROFILE_STATISTICAL)
+               mono_runtime_shutdown_stat_profiler ();
 
 #ifndef DISABLE_COM
        cominterop_release_all_rcws ();
@@ -3890,12 +4143,12 @@ mini_cleanup (MonoDomain *domain)
        /* This accesses metadata so needs to be called before runtime shutdown */
        print_jit_stats ();
 
-       mono_profiler_shutdown ();
-
 #ifndef MONO_CROSS_COMPILE
        mono_runtime_cleanup (domain);
 #endif
 
+       mono_profiler_shutdown ();
+
        free_jit_tls_data ((MonoJitTlsData *)mono_native_tls_get_value (mono_jit_tls_id));
 
        mono_icall_cleanup ();
@@ -3943,8 +4196,8 @@ mini_cleanup (MonoDomain *domain)
 
        mono_code_manager_cleanup ();
 
-#ifdef USE_JUMP_TABLES
-       mono_jumptable_cleanup ();
+#ifndef HOST_WIN32
+       mono_w32handle_cleanup ();
 #endif
 }
 
@@ -4013,10 +4266,16 @@ mono_precompile_assembly (MonoAssembly *ass, void *user_data)
                printf ("PRECOMPILE: %s.\n", mono_image_get_filename (image));
 
        for (i = 0; i < mono_image_get_table_rows (image, MONO_TABLE_METHOD); ++i) {
-               method = mono_get_method (image, MONO_TOKEN_METHOD_DEF | (i + 1), NULL);
+               MonoError error;
+
+               method = mono_get_method_checked (image, MONO_TOKEN_METHOD_DEF | (i + 1), NULL, NULL, &error);
+               if (!method) {
+                       mono_error_cleanup (&error); /* FIXME don't swallow the error */
+                       continue;
+               }
                if (method->flags & METHOD_ATTRIBUTE_ABSTRACT)
                        continue;
-               if (method->is_generic || method->klass->generic_container)
+               if (method->is_generic || mono_class_is_gtd (method->klass))
                        continue;
 
                count++;
@@ -4025,15 +4284,21 @@ mono_precompile_assembly (MonoAssembly *ass, void *user_data)
                        g_print ("Compiling %d %s\n", count, desc);
                        g_free (desc);
                }
-               mono_compile_method (method);
+               mono_compile_method_checked (method, &error);
+               if (!is_ok (&error)) {
+                       mono_error_cleanup (&error); /* FIXME don't swallow the error */
+                       continue;
+               }
                if (strcmp (method->name, "Finalize") == 0) {
-                       invoke = mono_marshal_get_runtime_invoke (method, FALSE, FALSE);
-                       mono_compile_method (invoke);
+                       invoke = mono_marshal_get_runtime_invoke (method, FALSE);
+                       mono_compile_method_checked (invoke, &error);
+                       mono_error_assert_ok (&error);
                }
 #ifndef DISABLE_REMOTING
                if (mono_class_is_marshalbyref (method->klass) && mono_method_signature (method)->hasthis) {
                        invoke = mono_marshal_get_remoting_invoke_with_check (method);
-                       mono_compile_method (invoke);
+                       mono_compile_method_checked (invoke, &error);
+                       mono_error_assert_ok (&error);
                }
 #endif
        }
@@ -4066,97 +4331,22 @@ mono_personality (void)
        g_assert_not_reached ();
 }
 
-#ifdef USE_JUMP_TABLES
-#define DEFAULT_JUMPTABLE_CHUNK_ELEMENTS 128
-
-typedef struct MonoJumpTableChunk {
-       guint32 total;
-       guint32 active;
-       struct MonoJumpTableChunk *previous;
-       /* gpointer entries[total]; */
-} MonoJumpTableChunk;
-
-static MonoJumpTableChunk* g_jumptable;
-#define mono_jumptable_lock() mono_os_mutex_lock (&jumptable_mutex)
-#define mono_jumptable_unlock() mono_os_mutex_unlock (&jumptable_mutex)
-static mono_mutex_t jumptable_mutex;
-
-static  MonoJumpTableChunk*
-mono_create_jumptable_chunk (guint32 max_entries)
-{
-       guint32 size = sizeof (MonoJumpTableChunk) + max_entries * sizeof(gpointer);
-       MonoJumpTableChunk *chunk = (MonoJumpTableChunk*) g_new0 (guchar, size);
-       chunk->total = max_entries;
-       return chunk;
-}
-
-void
-mono_jumptable_init (void)
-{
-       if (g_jumptable == NULL) {
-               mono_os_mutex_init_recursive (&jumptable_mutex);
-               g_jumptable = mono_create_jumptable_chunk (DEFAULT_JUMPTABLE_CHUNK_ELEMENTS);
-       }
-}
-
-gpointer*
-mono_jumptable_add_entry (void)
-{
-       return mono_jumptable_add_entries (1);
-}
-
-gpointer*
-mono_jumptable_add_entries (guint32 entries)
+// Custom handlers currently only implemented by Windows.
+#ifndef HOST_WIN32
+gboolean
+mono_runtime_install_custom_handlers (const char *handlers)
 {
-       guint32 index;
-       gpointer *result;
-
-       mono_jumptable_init ();
-       mono_jumptable_lock ();
-       index = g_jumptable->active;
-       if (index + entries >= g_jumptable->total) {
-               /*
-                * Grow jumptable, by adding one more chunk.
-                * We cannot realloc jumptable, as there could be pointers
-                * to existing jump table entries in the code, so instead
-                * we just add one more chunk.
-                */
-               guint32 max_entries = entries;
-               MonoJumpTableChunk *new_chunk;
-
-               if (max_entries < DEFAULT_JUMPTABLE_CHUNK_ELEMENTS)
-                       max_entries = DEFAULT_JUMPTABLE_CHUNK_ELEMENTS;
-               new_chunk = mono_create_jumptable_chunk (max_entries);
-               /* Link old jumptable, so that we could free it up later. */
-               new_chunk->previous = g_jumptable;
-               g_jumptable = new_chunk;
-               index = 0;
-       }
-       g_jumptable->active = index + entries;
-       result = (gpointer*)((guchar*)g_jumptable + sizeof(MonoJumpTableChunk)) + index;
-       mono_jumptable_unlock();
-
-       return result;
+       return FALSE;
 }
 
 void
-mono_jumptable_cleanup (void)
-{
-       if (g_jumptable) {
-               MonoJumpTableChunk *current = g_jumptable, *prev;
-               while (current != NULL) {
-                       prev = current->previous;
-                       g_free (current);
-                       current = prev;
-               }
-               g_jumptable = NULL;
-               mono_os_mutex_destroy (&jumptable_mutex);
-       }
-}
-
-gpointer*
-mono_jumptable_get_entry (guint8 *code_ptr)
+mono_runtime_install_custom_handlers_usage (void)
 {
-       return mono_arch_jumptable_entry_from_code (code_ptr);
+       fprintf (stdout,
+                "Custom Handlers:\n"
+                "   --handlers=HANDLERS            Enable handler support, HANDLERS is a comma\n"
+                "                                  separated list of available handlers to install.\n"
+                "\n"
+                "No handlers supported on current platform.\n");
 }
-#endif
+#endif /* HOST_WIN32 */