Avoid passing the ex_tag around when throwing exceptions, simply throw a NULL value...
[mono.git] / mono / mini / mini.c
index 67aea21fee19ed726b0a15176cc95aba0d7f5aca..740ce48666b7ac03999a6b4cb7dd59705d82e7b7 100644 (file)
@@ -85,8 +85,7 @@ gboolean mono_using_xdebug;
 #define mono_jit_unlock() mono_mutex_unlock (&jit_mutex)
 static mono_mutex_t jit_mutex;
 
-/* Whenever to check for pending exceptions in managed-to-native wrappers */
-gboolean check_for_pending_exc = TRUE;
+#ifndef DISABLE_JIT
 
 gpointer
 mono_realloc_native_code (MonoCompile *cfg)
@@ -199,6 +198,103 @@ void mono_nacl_fix_patches(const guint8 *code, MonoJumpInfo *ji)
 }
 #endif  /* __native_client_codegen__ */
 
+#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_mutex_lock (&jumptable_mutex)
+#define mono_jumptable_unlock() mono_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_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)
+{
+       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;
+}
+
+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_mutex_destroy (&jumptable_mutex);
+       }
+}
+
+gpointer*
+mono_jumptable_get_entry (guint8 *code_ptr)
+{
+       return mono_arch_jumptable_entry_from_code (code_ptr);
+}
+
+#endif /* USE_JUMP_TABLES */
+
 typedef struct {
        MonoExceptionClause *clause;
        MonoBasicBlock *basic_block;
@@ -423,7 +519,7 @@ mono_reverse_branch_op (guint32 opcode)
 guint
 mono_type_to_store_membase (MonoCompile *cfg, MonoType *type)
 {
-       type = mini_get_underlying_type (cfg, type);
+       type = mini_get_underlying_type (type);
 
 handle_enum:
        switch (type->type) {
@@ -469,7 +565,7 @@ handle_enum:
                goto handle_enum;
        case MONO_TYPE_VAR:
        case MONO_TYPE_MVAR:
-               g_assert (mini_type_var_is_vt (cfg, type));
+               g_assert (mini_type_var_is_vt (type));
                return OP_STOREV_MEMBASE;
        default:
                g_error ("unknown type 0x%02x in type_to_store_membase", type->type);
@@ -480,7 +576,7 @@ handle_enum:
 guint
 mono_type_to_load_membase (MonoCompile *cfg, MonoType *type)
 {
-       type = mini_get_underlying_type (cfg, type);
+       type = mini_get_underlying_type (type);
 
        switch (type->type) {
        case MONO_TYPE_I1:
@@ -526,8 +622,8 @@ mono_type_to_load_membase (MonoCompile *cfg, MonoType *type)
                break;
        case MONO_TYPE_VAR:
        case MONO_TYPE_MVAR:
-               g_assert (cfg->generic_sharing_context);
-               g_assert (mini_type_var_is_vt (cfg, type));
+               g_assert (cfg->gshared);
+               g_assert (mini_type_var_is_vt (type));
                return OP_LOADV_MEMBASE;
        default:
                g_error ("unknown type 0x%02x in type_to_load_membase", type->type);
@@ -535,25 +631,12 @@ mono_type_to_load_membase (MonoCompile *cfg, MonoType *type)
        return -1;
 }
 
-static guint
-mini_type_to_ldind (MonoCompile* cfg, MonoType *type)
-{
-       type = mini_get_underlying_type (cfg, type);
-       if (cfg->generic_sharing_context && !type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR)) {
-               g_assert (mini_type_var_is_vt (cfg, type));
-               return CEE_LDOBJ;
-       }
-       return mono_type_to_ldind (type);
-}
-
-#ifndef DISABLE_JIT
-
 guint
 mini_type_to_stind (MonoCompile* cfg, MonoType *type)
 {
-       type = mini_get_underlying_type (cfg, type);
-       if (cfg->generic_sharing_context && !type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR)) {
-               g_assert (mini_type_var_is_vt (cfg, type));
+       type = mini_get_underlying_type (type);
+       if (cfg->gshared && !type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR)) {
+               g_assert (mini_type_var_is_vt (type));
                return CEE_STOBJ;
        }
        return mono_type_to_stind (type);
@@ -691,8 +774,6 @@ mono_decompose_op_imm (MonoCompile *cfg, MonoBasicBlock *bb, MonoInst *ins)
        bb->max_vreg = MAX (bb->max_vreg, cfg->next_vreg);
 }
 
-#endif
-
 static void
 set_vreg_to_inst (MonoCompile *cfg, int vreg, MonoInst *inst)
 {
@@ -712,16 +793,6 @@ set_vreg_to_inst (MonoCompile *cfg, int vreg, MonoInst *inst)
 #define mono_type_is_long(type) (!(type)->byref && ((mono_type_get_underlying_type (type)->type == MONO_TYPE_I8) || (mono_type_get_underlying_type (type)->type == MONO_TYPE_U8)))
 #define mono_type_is_float(type) (!(type)->byref && (((type)->type == MONO_TYPE_R8) || ((type)->type == MONO_TYPE_R4)))
 
-#ifdef DISABLE_JIT
-
-MonoInst*
-mono_compile_create_var (MonoCompile *cfg, MonoType *type, int opcode)
-{
-       return NULL;
-}
-
-#else
-
 MonoInst*
 mono_compile_create_var_for_vreg (MonoCompile *cfg, MonoType *type, int opcode, int vreg)
 {
@@ -729,7 +800,7 @@ mono_compile_create_var_for_vreg (MonoCompile *cfg, MonoType *type, int opcode,
        int num = cfg->num_varinfo;
        gboolean regpair;
 
-       type = mini_get_underlying_type (cfg, type);
+       type = mini_get_underlying_type (type);
 
        if ((num + 1) >= cfg->varinfo_count) {
                int orig_count = cfg->varinfo_count;
@@ -757,7 +828,7 @@ mono_compile_create_var_for_vreg (MonoCompile *cfg, MonoType *type, int opcode,
                if (type->byref) {
                        mono_mark_vreg_as_mp (cfg, vreg);
                } else {
-                       if ((MONO_TYPE_ISSTRUCT (type) && inst->klass->has_references) || mini_type_is_reference (cfg, type)) {
+                       if ((MONO_TYPE_ISSTRUCT (type) && inst->klass->has_references) || mini_type_is_reference (type)) {
                                inst->flags |= MONO_INST_GC_TRACK;
                                mono_mark_vreg_as_ref (cfg, vreg);
                        }
@@ -838,7 +909,7 @@ MonoInst*
 mono_compile_create_var (MonoCompile *cfg, MonoType *type, int opcode)
 {
        int dreg;
-       type = mini_get_underlying_type (cfg, type);
+       type = mini_get_underlying_type (type);
 
        if (mono_type_is_long (type))
                dreg = mono_alloc_dreg (cfg, STACK_I8);
@@ -851,19 +922,6 @@ mono_compile_create_var (MonoCompile *cfg, MonoType *type, int opcode)
        return mono_compile_create_var_for_vreg (cfg, type, opcode, dreg);
 }
 
-/*
- * Transform a MonoInst into a load from the variable of index var_index.
- */
-void
-mono_compile_make_var_load (MonoCompile *cfg, MonoInst *dest, gssize var_index)
-{
-       memset (dest, 0, sizeof (MonoInst));
-       dest->inst_i0 = cfg->varinfo [var_index];
-       dest->opcode = mini_type_to_ldind (cfg, dest->inst_i0->inst_vtype);
-       type_to_eval_stack_type (cfg, dest->inst_i0->inst_vtype, dest);
-       dest->klass = dest->inst_i0->klass;
-}
-
 MonoInst*
 mini_get_int_to_float_spill_area (MonoCompile *cfg)
 {
@@ -878,8 +936,6 @@ mini_get_int_to_float_spill_area (MonoCompile *cfg)
 #endif
 }
 
-#endif
-
 void
 mono_mark_vreg_as_ref (MonoCompile *cfg, int vreg)
 {
@@ -913,7 +969,8 @@ mono_mark_vreg_as_mp (MonoCompile *cfg, int vreg)
 }      
 
 static MonoType*
-type_from_stack_type (MonoInst *ins) {
+type_from_stack_type (MonoInst *ins)
+{
        switch (ins->type) {
        case STACK_I4: return &mono_defaults.int32_class->byval_arg;
        case STACK_I8: return &mono_defaults.int64_class->byval_arg;
@@ -944,7 +1001,8 @@ type_from_stack_type (MonoInst *ins) {
 }
 
 MonoType*
-mono_type_from_stack_type (MonoInst *ins) {
+mono_type_from_stack_type (MonoInst *ins)
+{
        return type_from_stack_type (ins);
 }
 
@@ -1235,8 +1293,6 @@ compare_by_interval_start_pos_func (gconstpointer a, gconstpointer b)
                return 1;
 }
 
-#ifndef DISABLE_JIT
-
 #if 0
 #define LSCAN_DEBUG(a) do { a; } while (0)
 #else
@@ -1301,7 +1357,7 @@ mono_allocate_stack_slots2 (MonoCompile *cfg, gboolean backward, guint32 *stack_
                inst = cfg->varinfo [vmv->idx];
 
                t = mono_type_get_underlying_type (inst->inst_vtype);
-               if (cfg->gsharedvt && mini_is_gsharedvt_variable_type (cfg, t))
+               if (cfg->gsharedvt && mini_is_gsharedvt_variable_type (t))
                        continue;
 
                /* inst->backend.is_pinvoke indicates native sized value types, this is used by the
@@ -1312,7 +1368,7 @@ mono_allocate_stack_slots2 (MonoCompile *cfg, gboolean backward, guint32 *stack_
                else {
                        int ialign;
 
-                       size = mini_type_stack_size (NULL, t, &ialign);
+                       size = mini_type_stack_size (t, &ialign);
                        align = ialign;
 
                        if (MONO_CLASS_IS_SIMD (cfg, mono_class_from_mono_type (t)))
@@ -1323,7 +1379,7 @@ mono_allocate_stack_slots2 (MonoCompile *cfg, gboolean backward, guint32 *stack_
                if (cfg->disable_reuse_stack_slots)
                        reuse_slot = FALSE;
 
-               t = mini_get_underlying_type (cfg, t);
+               t = mini_get_underlying_type (t);
                switch (t->type) {
                case MONO_TYPE_GENERICINST:
                        if (!mono_type_generic_inst_is_valuetype (t)) {
@@ -1598,7 +1654,7 @@ mono_allocate_stack_slots (MonoCompile *cfg, gboolean backward, guint32 *stack_s
                inst = cfg->varinfo [vmv->idx];
 
                t = mono_type_get_underlying_type (inst->inst_vtype);
-               if (cfg->gsharedvt && mini_is_gsharedvt_variable_type (cfg, t))
+               if (cfg->gsharedvt && mini_is_gsharedvt_variable_type (t))
                        continue;
 
                /* inst->backend.is_pinvoke indicates native sized value types, this is used by the
@@ -1608,7 +1664,7 @@ mono_allocate_stack_slots (MonoCompile *cfg, gboolean backward, guint32 *stack_s
                } else {
                        int ialign;
 
-                       size = mini_type_stack_size (NULL, t, &ialign);
+                       size = mini_type_stack_size (t, &ialign);
                        align = ialign;
 
                        if (mono_class_from_mono_type (t)->exception_type)
@@ -1622,7 +1678,7 @@ mono_allocate_stack_slots (MonoCompile *cfg, gboolean backward, guint32 *stack_s
                if (cfg->disable_reuse_stack_slots)
                        reuse_slot = FALSE;
 
-               t = mini_get_underlying_type (cfg, t);
+               t = mini_get_underlying_type (t);
                switch (t->type) {
                case MONO_TYPE_GENERICINST:
                        if (!mono_type_generic_inst_is_valuetype (t)) {
@@ -1795,17 +1851,6 @@ mono_allocate_stack_slots (MonoCompile *cfg, gboolean backward, guint32 *stack_s
        return offsets;
 }
 
-#else
-
-gint32*
-mono_allocate_stack_slots (MonoCompile *cfg, gboolean backward, guint32 *stack_size, guint32 *stack_align)
-{
-       g_assert_not_reached ();
-       return NULL;
-}
-
-#endif /* DISABLE_JIT */
-
 #define EMUL_HIT_SHIFT 3
 #define EMUL_HIT_MASK ((1 << EMUL_HIT_SHIFT) - 1)
 /* small hit bitmap cache */
@@ -1854,7 +1899,8 @@ mini_register_opcode_emulation (int opcode, const char *name, const char *sigstr
 }
 
 static void
-print_dfn (MonoCompile *cfg) {
+print_dfn (MonoCompile *cfg)
+{
        int i, j;
        char *code;
        MonoBasicBlock *bb;
@@ -2007,7 +2053,6 @@ mono_verify_cfg (MonoCompile *cfg)
 void
 mono_destroy_compile (MonoCompile *cfg)
 {
-#ifndef DISABLE_JIT
        GSList *l;
 
        if (cfg->header)
@@ -2034,11 +2079,8 @@ mono_destroy_compile (MonoCompile *cfg)
        g_free (cfg->vars);
        g_free (cfg->exception_message);
        g_free (cfg);
-#endif
 }
 
-#ifndef DISABLE_JIT
-
 static MonoInst*
 mono_create_tls_get_offset (MonoCompile *cfg, int offset)
 {
@@ -2071,12 +2113,15 @@ mini_tls_get_supported (MonoCompile *cfg, MonoTlsKey key)
 MonoInst*
 mono_create_tls_get (MonoCompile *cfg, MonoTlsKey key)
 {
+       if (!MONO_ARCH_HAVE_TLS_GET)
+               return NULL;
+
        /*
         * TLS offsets might be different at AOT time, so load them from a GOT slot and
         * use a different opcode.
         */
        if (cfg->compile_aot) {
-               if (MONO_ARCH_HAVE_TLS_GET && ARCH_HAVE_TLS_GET_REG) {
+               if (ARCH_HAVE_TLS_GET_REG) {
                        MonoInst *ins, *c;
 
                        EMIT_NEW_TLS_OFFSETCONST (cfg, c, key);
@@ -2122,9 +2167,6 @@ mono_get_lmf_addr_intrinsic (MonoCompile* cfg)
        return mono_create_tls_get (cfg, TLS_KEY_LMF_ADDR);
 }
 
-#endif /* !DISABLE_JIT */
-
-
 void
 mono_add_patch_info (MonoCompile *cfg, int ip, MonoJumpInfoType type, gconstpointer target)
 {
@@ -2196,8 +2238,6 @@ mono_add_var_location (MonoCompile *cfg, MonoInst *var, gboolean is_reg, int reg
                cfg->rgctx_loclist = g_slist_append_mempool (cfg->mempool, cfg->rgctx_loclist, entry);
 }
 
-#ifndef DISABLE_JIT
-
 static void
 mono_compile_create_vars (MonoCompile *cfg)
 {
@@ -2529,7 +2569,7 @@ mono_codegen (MonoCompile *cfg)
                        is_generic = TRUE;
                }
 
-               if (cfg->generic_sharing_context)
+               if (cfg->gshared)
                        g_assert (is_generic);
        }
 
@@ -2627,37 +2667,6 @@ mono_handle_out_of_line_bblock (MonoCompile *cfg)
        }
 }
 
-#endif /* #ifndef DISABLE_JIT */
-
-static MonoJitInfo*
-create_jit_info_for_trampoline (MonoMethod *wrapper, MonoTrampInfo *info)
-{
-       MonoDomain *domain = mono_get_root_domain ();
-       MonoJitInfo *jinfo;
-       guint8 *uw_info;
-       guint32 info_len;
-
-       if (info->uw_info) {
-               uw_info = info->uw_info;
-               info_len = info->uw_info_len;
-       } else {
-               uw_info = mono_unwind_ops_encode (info->unwind_ops, &info_len);
-       }
-
-       jinfo = mono_domain_alloc0 (domain, MONO_SIZEOF_JIT_INFO);
-       jinfo->d.method = wrapper;
-       jinfo->code_start = info->code;
-       jinfo->code_size = info->code_size;
-       jinfo->unwind_info = mono_cache_unwind_info (uw_info, info_len);
-
-       if (!info->uw_info)
-               g_free (uw_info);
-
-       return jinfo;
-}
-
-#ifndef DISABLE_JIT
-
 static MonoJitInfo*
 create_jit_info (MonoCompile *cfg, MonoMethod *method_to_compile)
 {
@@ -2671,7 +2680,7 @@ create_jit_info (MonoCompile *cfg, MonoMethod *method_to_compile)
        g_assert (method_to_compile == cfg->method);
        header = cfg->header;
 
-       if (cfg->generic_sharing_context)
+       if (cfg->gshared)
                flags |= JIT_INFO_HAS_GENERIC_JIT_INFO;
 
        if (cfg->arch_eh_jit_info) {
@@ -2683,7 +2692,7 @@ create_jit_info (MonoCompile *cfg, MonoMethod *method_to_compile)
                 * mono_arch_get_argument_info () is not signal safe.
                 */
                arg_info = g_newa (MonoJitArgumentInfo, sig->param_count + 1);
-               stack_size = mono_arch_get_argument_info (cfg->generic_sharing_context, sig, sig->param_count, arg_info);
+               stack_size = mono_arch_get_argument_info (sig, sig->param_count, arg_info);
 
                if (stack_size)
                        flags |= JIT_INFO_HAS_ARCH_EH_INFO;
@@ -2728,7 +2737,7 @@ create_jit_info (MonoCompile *cfg, MonoMethod *method_to_compile)
        if (COMPILE_LLVM (cfg))
                jinfo->from_llvm = TRUE;
 
-       if (cfg->generic_sharing_context) {
+       if (cfg->gshared) {
                MonoInst *inst;
                MonoGenericJitInfo *gi;
                GSList *loclist = NULL;
@@ -2996,7 +3005,6 @@ create_jit_info (MonoCompile *cfg, MonoMethod *method_to_compile)
 
        return jinfo;
 }
-#endif
 
 /* Return whenever METHOD is a gsharedvt method */
 static gboolean
@@ -3039,8 +3047,6 @@ is_open_method (MonoMethod *method)
        return FALSE;
 }
 
-#ifndef DISABLE_JIT
-
 #if defined(__native_client_codegen__) || USE_COOP_GC
 
 static void
@@ -3098,6 +3104,42 @@ static void
 mono_insert_safepoints (MonoCompile *cfg)
 {
        MonoBasicBlock *bb;
+       if (cfg->method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) {
+               WrapperInfo *info = mono_marshal_get_wrapper_info (cfg->method);
+#if defined(__native_client__) || defined(__native_client_codegen__)
+               gpointer poll_func = &mono_nacl_gc;
+#elif defined(USE_COOP_GC)
+               gpointer poll_func = &mono_threads_state_poll;
+#else
+               gpointer poll_func = NULL;
+#endif
+
+               if (info && info->subtype == WRAPPER_SUBTYPE_ICALL_WRAPPER && info->d.icall.func == poll_func) {
+                       if (cfg->verbose_level > 1)
+                               printf ("SKIPPING SAFEPOINTS for the polling function icall\n");
+                       return;
+               }
+       }
+
+       if (cfg->method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) {
+               if (cfg->verbose_level > 1)
+                       printf ("SKIPPING SAFEPOINTS for native-to-managed wrappers.\n");
+               return;
+       }
+
+       if (cfg->method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) {
+               WrapperInfo *info = mono_marshal_get_wrapper_info (cfg->method);
+
+               if (info && info->subtype == WRAPPER_SUBTYPE_ICALL_WRAPPER &&
+                       (info->d.icall.func == mono_thread_interruption_checkpoint ||
+                       info->d.icall.func == mono_threads_finish_blocking ||
+                       info->d.icall.func == mono_threads_reset_blocking_start)) {
+                       /* These wrappers are called from the wrapper for the polling function, leading to potential stack overflow */
+                       if (cfg->verbose_level > 1)
+                               printf ("SKIPPING SAFEPOINTS for wrapper %s\n", cfg->method->name);
+                       return;
+               }
+       }
 
        if (cfg->verbose_level > 1)
                printf ("INSERTING SAFEPOINTS\n");
@@ -3230,7 +3272,7 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, JitFl
        cfg->orig_method = method;
        cfg->gen_seq_points = debug_options.gen_seq_points_compact_data || debug_options.gen_sdb_seq_points;
        cfg->gen_sdb_seq_points = debug_options.gen_sdb_seq_points;
-       cfg->flags = flags;
+       cfg->llvm_only = (flags & JIT_FLAG_LLVM_ONLY) != 0;
 
 #ifdef PLATFORM_ANDROID
        if (cfg->method->wrapper_type != MONO_WRAPPER_NONE) {
@@ -3243,20 +3285,23 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, JitFl
 #if defined(__native_client_codegen__) || defined(USE_COOP_GC)
        cfg->opt |= MONO_OPT_LOOP;
 #endif
-
-       cfg->explicit_null_checks = debug_options.explicit_null_checks;
+       cfg->explicit_null_checks = debug_options.explicit_null_checks || (flags & JIT_FLAG_EXPLICIT_NULL_CHECKS);
        cfg->soft_breakpoints = debug_options.soft_breakpoints;
        cfg->check_pinvoke_callconv = debug_options.check_pinvoke_callconv;
        cfg->disable_direct_icalls = disable_direct_icalls;
        if (try_generic_shared)
-               cfg->generic_sharing_context = (MonoGenericSharingContext*)&cfg->gsctx;
+               cfg->gshared = TRUE;
        cfg->compile_llvm = try_llvm;
        cfg->token_info_hash = g_hash_table_new (NULL, NULL);
        if (cfg->compile_aot)
                cfg->method_index = aot_method_index;
 
+       /*
        if (!mono_debug_count ())
                cfg->opt &= ~MONO_OPT_FLOAT32;
+       */
+       if (cfg->llvm_only)
+               cfg->opt &= ~MONO_OPT_SIMD;
        cfg->r4fp = (cfg->opt & MONO_OPT_FLOAT32) ? 1 : 0;
        cfg->r4_stack_type = cfg->r4fp ? STACK_R4 : STACK_R8;
 
@@ -3269,7 +3314,7 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, JitFl
                return cfg;
        }
 
-       if (cfg->generic_sharing_context && (gsharedvt_method || mini_is_gsharedvt_sharable_method (method))) {
+       if (cfg->gshared && (gsharedvt_method || mini_is_gsharedvt_sharable_method (method))) {
                MonoMethodInflated *inflated;
                MonoGenericContext *context;
 
@@ -3292,11 +3337,11 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, JitFl
                cfg->gsharedvt = TRUE;
                // FIXME:
                cfg->disable_llvm = TRUE;
+               cfg->exception_message = g_strdup ("gsharedvt");
        }
 
-       if (cfg->generic_sharing_context) {
+       if (cfg->gshared) {
                method_to_register = method_to_compile;
-               cfg->gshared = TRUE;
        } else {
                g_assert (method == method_to_compile);
                method_to_register = method;
@@ -3343,11 +3388,15 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, JitFl
                if (COMPILE_LLVM (cfg)) {
                        mono_llvm_check_method_supported (cfg);
                        if (cfg->disable_llvm) {
-                               if (cfg->verbose_level >= 1) {
+                               if (cfg->verbose_level >= cfg->llvm_only ? 0 : 1) {
                                        //nm = mono_method_full_name (cfg->method, TRUE);
                                        printf ("LLVM failed for '%s': %s\n", method->name, cfg->exception_message);
                                        //g_free (nm);
                                }
+                               if (cfg->llvm_only) {
+                                       cfg->disable_aot = TRUE;
+                                       return cfg;
+                               }
                                mono_destroy_compile (cfg);
                                try_llvm = FALSE;
                                goto restart_compile;
@@ -3437,13 +3486,13 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, JitFl
                char *method_name;
 
                method_name = mono_method_full_name (method, TRUE);
-               g_print ("converting %s%s%smethod %s\n", COMPILE_LLVM (cfg) ? "llvm " : "", cfg->gsharedvt ? "gsharedvt " : "", (cfg->generic_sharing_context && !cfg->gsharedvt) ? "gshared " : "", method_name);
+               g_print ("converting %s%s%smethod %s\n", COMPILE_LLVM (cfg) ? "llvm " : "", cfg->gsharedvt ? "gsharedvt " : "", (cfg->gshared && !cfg->gsharedvt) ? "gshared " : "", method_name);
                /*
                if (COMPILE_LLVM (cfg))
                        g_print ("converting llvm method %s\n", method_name = mono_method_full_name (method, TRUE));
                else if (cfg->gsharedvt)
                        g_print ("converting gsharedvt method %s\n", method_name = mono_method_full_name (method_to_compile, TRUE));
-               else if (cfg->generic_sharing_context)
+               else if (cfg->gshared)
                        g_print ("converting shared method %s\n", method_name = mono_method_full_name (method_to_compile, TRUE));
                else
                        g_print ("converting method %s\n", method_name = mono_method_full_name (method, TRUE));
@@ -3570,6 +3619,8 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, JitFl
        if (!COMPILE_LLVM (cfg))
                mono_if_conversion (cfg);
 
+       MONO_SUSPEND_CHECK ();
+
        /* Depth-first ordering on basic blocks */
        cfg->bblocks = mono_mempool_alloc (cfg->mempool, sizeof (MonoBasicBlock*) * (cfg->num_bblocks + 1));
 
@@ -3856,11 +3907,15 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, JitFl
                if (!cfg->disable_llvm)
                        mono_llvm_emit_method (cfg);
                if (cfg->disable_llvm) {
-                       if (cfg->verbose_level >= 1) {
+                       if (cfg->verbose_level >= cfg->llvm_only ? 0 : 1) {
                                //nm = mono_method_full_name (cfg->method, TRUE);
                                printf ("LLVM failed for '%s': %s\n", method->name, cfg->exception_message);
                                //g_free (nm);
                        }
+                       if (cfg->llvm_only) {
+                               cfg->disable_aot = TRUE;
+                               return cfg;
+                       }
                        mono_destroy_compile (cfg);
                        try_llvm = FALSE;
                        goto restart_compile;
@@ -3946,17 +4001,63 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, JitFl
        return cfg;
 }
 
-#else
+void*
+mono_arch_instrument_epilog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
+{
+       return mono_arch_instrument_epilog_full (cfg, func, p, enable_arguments, FALSE);
+}
 
-MonoCompile*
-mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, JitFlags flags, int parts, int aot_method_index)
+void
+mono_cfg_add_try_hole (MonoCompile *cfg, MonoExceptionClause *clause, guint8 *start, MonoBasicBlock *bb)
 {
-       g_assert_not_reached ();
-       return NULL;
+       TryBlockHole *hole = mono_mempool_alloc (cfg->mempool, sizeof (TryBlockHole));
+       hole->clause = clause;
+       hole->start_offset = start - cfg->native_code;
+       hole->basic_block = bb;
+
+       cfg->try_block_holes = g_slist_append_mempool (cfg->mempool, cfg->try_block_holes, hole);
+}
+
+void
+mono_cfg_set_exception (MonoCompile *cfg, int type)
+{
+       cfg->exception_type = type;
 }
 
 #endif /* DISABLE_JIT */
 
+static MonoJitInfo*
+create_jit_info_for_trampoline (MonoMethod *wrapper, MonoTrampInfo *info)
+{
+       MonoDomain *domain = mono_get_root_domain ();
+       MonoJitInfo *jinfo;
+       guint8 *uw_info;
+       guint32 info_len;
+
+       if (info->uw_info) {
+               uw_info = info->uw_info;
+               info_len = info->uw_info_len;
+       } else {
+               uw_info = mono_unwind_ops_encode (info->unwind_ops, &info_len);
+       }
+
+       jinfo = mono_domain_alloc0 (domain, MONO_SIZEOF_JIT_INFO);
+       jinfo->d.method = wrapper;
+       jinfo->code_start = info->code;
+       jinfo->code_size = info->code_size;
+       jinfo->unwind_info = mono_cache_unwind_info (uw_info, info_len);
+
+       if (!info->uw_info)
+               g_free (uw_info);
+
+       return jinfo;
+}
+
+/*
+ * mono_jit_compile_method_inner:
+ *
+ *   Main entry point for the JIT.
+ */
 gpointer
 mono_jit_compile_method_inner (MonoMethod *method, MonoDomain *target_domain, int opt, MonoException **jit_ex)
 {
@@ -3986,7 +4087,7 @@ mono_jit_compile_method_inner (MonoMethod *method, MonoDomain *target_domain, in
                        else
                                mono_lookup_pinvoke_call (method, NULL, NULL);
                }
-               nm = mono_marshal_get_native_wrapper (method, check_for_pending_exc, mono_aot_only);
+               nm = mono_marshal_get_native_wrapper (method, TRUE, mono_aot_only);
                code = mono_get_addr_from_ftnptr (mono_compile_method (nm));
                jinfo = mono_jit_info_table_find (target_domain, code);
                if (!jinfo)
@@ -4015,6 +4116,10 @@ mono_jit_compile_method_inner (MonoMethod *method, MonoDomain *target_domain, in
                                 */
                                return mono_get_addr_from_ftnptr ((gpointer)mono_icall_get_wrapper_full (mi, TRUE));
                        } else if (*name == 'I' && (strcmp (name, "Invoke") == 0)) {
+                               if (mono_llvm_only) {
+                                       nm = mono_marshal_get_delegate_invoke (method, NULL);
+                                       return mono_get_addr_from_ftnptr (mono_compile_method (nm));
+                               }
                                return mono_create_delegate_trampoline (target_domain, method->klass);
                        } else if (*name == 'B' && (strcmp (name, "BeginInvoke") == 0)) {
                                nm = mono_marshal_get_delegate_begin_invoke (method);
@@ -4185,7 +4290,7 @@ mono_jit_compile_method_inner (MonoMethod *method, MonoDomain *target_domain, in
 
                code = cfg->native_code;
 
-               if (cfg->generic_sharing_context && mono_method_is_generic_sharable (method, FALSE))
+               if (cfg->gshared && mono_method_is_generic_sharable (method, FALSE))
                        mono_stats.generics_shared_methods++;
                if (cfg->gsharedvt)
                        mono_stats.gsharedvt_methods++;
@@ -4277,82 +4382,34 @@ mono_jit_compile_method_inner (MonoMethod *method, MonoDomain *target_domain, in
        return code;
 }
 
-#ifndef DISABLE_JIT
-
-void*
-mono_arch_instrument_epilog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments) {
-       return mono_arch_instrument_epilog_full (cfg, func, p, enable_arguments, FALSE);
-}
-
-void
-mono_cfg_add_try_hole (MonoCompile *cfg, MonoExceptionClause *clause, guint8 *start, MonoBasicBlock *bb)
+/*
+ * mini_get_underlying_type:
+ *
+ *   Return the type the JIT will use during compilation.
+ * Handles: byref, enums, native types, generic sharing.
+ * For gsharedvt types, it will return the original VAR/MVAR.
+ */
+MonoType*
+mini_get_underlying_type (MonoType *type)
 {
-       TryBlockHole *hole = mono_mempool_alloc (cfg->mempool, sizeof (TryBlockHole));
-       hole->clause = clause;
-       hole->start_offset = start - cfg->native_code;
-       hole->basic_block = bb;
-
-       cfg->try_block_holes = g_slist_append_mempool (cfg->mempool, cfg->try_block_holes, hole);
+       return mini_type_get_underlying_type (type);
 }
 
 void
-mono_cfg_set_exception (MonoCompile *cfg, int type)
-{
-       cfg->exception_type = type;
-}
-
-#endif
-
-/* Dummy versions of some arch specific functions to avoid ifdefs at call sites */
-
-#ifndef MONO_ARCH_GSHAREDVT_SUPPORTED
-
-gboolean
-mono_arch_gsharedvt_sig_supported (MonoMethodSignature *sig)
-{
-       return FALSE;
-}
-
-gpointer
-mono_arch_get_gsharedvt_call_info (gpointer addr, MonoMethodSignature *normal_sig, MonoMethodSignature *gsharedvt_sig, MonoGenericSharingContext *gsctx, gboolean gsharedvt_in, gint32 vcall_offset, gboolean calli)
-{
-       g_assert_not_reached ();
-       return NULL;
-}
-
-gpointer
-mono_arch_get_gsharedvt_arg_trampoline (MonoDomain *domain, gpointer arg, gpointer addr)
+mini_jit_init (void)
 {
-       g_assert_not_reached ();
-       return NULL;
+       mono_mutex_init_recursive (&jit_mutex);
 }
 
-gpointer
-mono_arch_get_gsharedvt_trampoline (MonoTrampInfo **info, gboolean aot)
+void
+mini_jit_cleanup (void)
 {
-       g_assert_not_reached ();
-       return NULL;
-}
-
+#ifndef DISABLE_JIT
+       g_free (emul_opcode_map);
+       g_free (emul_opcode_opcodes);
 #endif
-
-#if defined(MONO_ARCH_GSHAREDVT_SUPPORTED) && !defined(ENABLE_GSHAREDVT)
-
-gboolean
-mono_arch_gsharedvt_sig_supported (MonoMethodSignature *sig)
-{
-       return FALSE;
-}
-
-gpointer
-mono_arch_get_gsharedvt_call_info (gpointer addr, MonoMethodSignature *normal_sig, MonoMethodSignature *gsharedvt_sig, MonoGenericSharingContext *gsctx, gboolean gsharedvt_in, gint32 vcall_offset, gboolean calli)
-{
-       NOT_IMPLEMENTED;
-       return NULL;
 }
 
-#endif
-
 #ifndef ENABLE_LLVM
 void
 mono_llvm_emit_aot_file_info (MonoAotFileInfo *info, gboolean has_jitted_code)
@@ -4366,136 +4423,25 @@ void mono_llvm_emit_aot_data (const char *symbol, guint8 *data, int data_len)
 }
 #endif
 
-#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_mutex_lock (&jumptable_mutex)
-#define mono_jumptable_unlock() mono_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_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);
-}
+#ifdef DISABLE_JIT
 
-gpointer*
-mono_jumptable_add_entries (guint32 entries)
+MonoCompile*
+mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, JitFlags flags, int parts, int aot_method_index)
 {
-       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;
+       g_assert_not_reached ();
+       return NULL;
 }
 
 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_mutex_destroy (&jumptable_mutex);
-       }
-}
-
-gpointer*
-mono_jumptable_get_entry (guint8 *code_ptr)
-{
-       return mono_arch_jumptable_entry_from_code (code_ptr);
-}
-#endif
-
-/*
- * mini_replace_type:
- *
- * Replace the type used in the metadata stream with what the JIT will actually use during compilation.
-*/
-MonoType*
-mini_replace_type (MonoType *type)
-{
-       type = mono_type_get_underlying_type (type);
-       return mini_native_type_replace_type (type);
-}
-
-/*
- * mini_get_underlying_type:
- *
- *   Return the type the JIT will use during compilation.
- * Handles: byref, enums, native types, generic sharing.
- * For gsharedvt types, it will return the original VAR/MVAR.
- */
-MonoType*
-mini_get_underlying_type (MonoCompile *cfg, MonoType *type)
+mono_destroy_compile (MonoCompile *cfg)
 {
-       type = mini_type_get_underlying_type (cfg->generic_sharing_context, type);
-       return mini_native_type_replace_type (type);
+       g_assert_not_reached ();
 }
 
 void
-mini_jit_init (void)
+mono_add_patch_info (MonoCompile *cfg, int ip, MonoJumpInfoType type, gconstpointer target)
 {
-       mono_mutex_init_recursive (&jit_mutex);
+       g_assert_not_reached ();
 }
 
-void
-mini_jit_cleanup (void)
-{
-       g_free (emul_opcode_map);
-       g_free (emul_opcode_opcodes);
-}
+#endif /* DISABLE_JIT */