* mini-codegen.c (mono_local_regalloc): Make free mask
[mono.git] / mono / mini / mini.c
index f0e310b231160c0b23bdf14ce9650461b1108c2c..b074740dc7456833ac2c336b2d7cab922a15acdc 100644 (file)
@@ -59,6 +59,8 @@
 #include <mono/metadata/security-core-clr.h>
 #include <mono/metadata/verify.h>
 #include <mono/metadata/verify-internals.h>
+#include <mono/metadata/mempool-internals.h>
+#include <mono/metadata/attach.h>
 #include <mono/utils/mono-math.h>
 #include <mono/utils/mono-compiler.h>
 #include <mono/utils/mono-counters.h>
                        goto exception_exit;    \
                }                       \
        } while (0)
-#define GENERIC_SHARING_FAILURE_IF_VALUETYPE_METHOD(opcode) do {                       \
-               if (method->klass->valuetype)   \
-                       GENERIC_SHARING_FAILURE ((opcode)); \
-       } while (0)
 #define GET_RGCTX(rgctx, context_used) do {                                            \
                MonoInst *this = NULL;                                  \
                g_assert (context_used);                                \
-               GENERIC_SHARING_FAILURE_IF_VALUETYPE_METHOD(*ip);       \
                if (!(method->flags & METHOD_ATTRIBUTE_STATIC) &&       \
-                               !((context_used) & MONO_GENERIC_CONTEXT_USED_METHOD)) \
+                               !((context_used) & MONO_GENERIC_CONTEXT_USED_METHOD) && \
+                               !method->klass->valuetype)              \
                        NEW_ARGLOAD (cfg, this, 0);                     \
                (rgctx) = get_runtime_generic_context (cfg, method, (context_used), this, ip); \
        } while (0)
@@ -173,9 +171,7 @@ static __thread gpointer mono_jit_tls MONO_TLS_FAST;
 
 MonoTraceSpec *mono_jit_trace_calls = NULL;
 gboolean mono_break_on_exc = FALSE;
-#ifndef DISABLE_AOT
 gboolean mono_compile_aot = FALSE;
-#endif
 /* If this is set, no code is generated dynamically, everything is taken from AOT files */
 gboolean mono_aot_only = FALSE;
 /* Whenever to use IMT */
@@ -220,6 +216,14 @@ gboolean check_for_pending_exc = TRUE;
 /* Whenever to disable passing/returning small valuetypes in registers for managed methods */
 gboolean disable_vtypes_in_regs = FALSE;
 
+gboolean mono_dont_free_global_codeman;
+
+#ifdef DISABLE_JIT
+/* Define this here, since many files reference it */
+const guint8 mono_burg_arity [MBMAX_OPCODES] = {
+};
+#endif
+
 gboolean
 mono_running_on_valgrind (void)
 {
@@ -266,7 +270,7 @@ get_method_from_ip (void *ip)
                user_data.ip = ip;
                user_data.method = NULL;
                mono_domain_lock (domain);
-               g_hash_table_foreach (domain->jit_trampoline_hash, find_tramp, &user_data);
+               g_hash_table_foreach (domain_jit_info (domain)->jit_trampoline_hash, find_tramp, &user_data);
                mono_domain_unlock (domain);
                if (user_data.method) {
                        char *mname = mono_method_full_name (user_data.method, TRUE);
@@ -332,7 +336,7 @@ mono_print_method_from_ip (void *ip)
                user_data.ip = ip;
                user_data.method = NULL;
                mono_domain_lock (domain);
-               g_hash_table_foreach (domain->jit_trampoline_hash, find_tramp, &user_data);
+               g_hash_table_foreach (domain_jit_info (domain)->jit_trampoline_hash, find_tramp, &user_data);
                mono_domain_unlock (domain);
                if (user_data.method) {
                        char *mname = mono_method_full_name (user_data.method, TRUE);
@@ -948,7 +952,7 @@ mono_unlink_bblock (MonoCompile *cfg, MonoBasicBlock *from, MonoBasicBlock* to)
  *
  *   Return whenever BB1 and BB2 are linked in the CFG.
  */
-static gboolean
+gboolean
 mono_bblocks_linked (MonoBasicBlock *bb1, MonoBasicBlock *bb2)
 {
        int i;
@@ -1166,8 +1170,8 @@ split_bblock (MonoCompile *cfg, MonoBasicBlock *first, MonoBasicBlock *second) {
        }
 }
 
-static guint32
-reverse_branch_op (guint32 opcode)
+guint32
+mono_reverse_branch_op (guint32 opcode)
 {
        static const int reverse_map [] = {
                CEE_BNE_UN, CEE_BLT, CEE_BLE, CEE_BGT, CEE_BGE,
@@ -1345,87 +1349,6 @@ condbr_to_fp_br (int opcode)
 }
 #endif
 
-/*
- * Returns the type used in the eval stack when @type is loaded.
- * FIXME: return a MonoType/MonoClass for the byref and VALUETYPE cases.
- */
-static void
-type_to_eval_stack_type (MonoCompile *cfg, MonoType *type, MonoInst *inst)
-{
-       MonoClass *klass;
-
-       inst->klass = klass = mono_class_from_mono_type (type);
-       if (type->byref) {
-               inst->type = STACK_MP;
-               return;
-       }
-
-handle_enum:
-       switch (type->type) {
-       case MONO_TYPE_VOID:
-               inst->type = STACK_INV;
-               return;
-       case MONO_TYPE_I1:
-       case MONO_TYPE_U1:
-       case MONO_TYPE_BOOLEAN:
-       case MONO_TYPE_I2:
-       case MONO_TYPE_U2:
-       case MONO_TYPE_CHAR:
-       case MONO_TYPE_I4:
-       case MONO_TYPE_U4:
-               inst->type = STACK_I4;
-               return;
-       case MONO_TYPE_I:
-       case MONO_TYPE_U:
-       case MONO_TYPE_PTR:
-       case MONO_TYPE_FNPTR:
-               inst->type = STACK_PTR;
-               return;
-       case MONO_TYPE_CLASS:
-       case MONO_TYPE_STRING:
-       case MONO_TYPE_OBJECT:
-       case MONO_TYPE_SZARRAY:
-       case MONO_TYPE_ARRAY:    
-               inst->type = STACK_OBJ;
-               return;
-       case MONO_TYPE_I8:
-       case MONO_TYPE_U8:
-               inst->type = STACK_I8;
-               return;
-       case MONO_TYPE_R4:
-       case MONO_TYPE_R8:
-               inst->type = STACK_R8;
-               return;
-       case MONO_TYPE_VALUETYPE:
-               if (type->data.klass->enumtype) {
-                       type = type->data.klass->enum_basetype;
-                       goto handle_enum;
-               } else {
-                       inst->klass = klass;
-                       inst->type = STACK_VTYPE;
-                       return;
-               }
-       case MONO_TYPE_TYPEDBYREF:
-               inst->klass = mono_defaults.typed_reference_class;
-               inst->type = STACK_VTYPE;
-               return;
-       case MONO_TYPE_GENERICINST:
-               type = &type->data.generic_class->container_class->byval_arg;
-               goto handle_enum;
-       case MONO_TYPE_VAR :
-       case MONO_TYPE_MVAR :
-               /* FIXME: all the arguments must be references for now,
-                * later look inside cfg and see if the arg num is
-                * really a reference
-                */
-               g_assert (cfg->generic_sharing_context);
-               inst->type = STACK_OBJ;
-               return;
-       default:
-               g_error ("unknown type 0x%02x in eval stack type", type->type);
-       }
-}
-
 /*
  * The following tables are used to quickly validate the IL code in type_from_op ().
  */
@@ -2150,6 +2073,13 @@ mono_compile_create_var_for_vreg (MonoCompile *cfg, MonoType *type, int opcode,
                        printf ("  Create LVAR R%d (R%d, R%d)\n", inst->dreg, inst->dreg + 1, inst->dreg + 2);
                }
 
+#ifdef MONO_ARCH_SOFT_FLOAT
+               if (cfg->opt & MONO_OPT_SSA) {
+                       if (mono_type_is_float (type))
+                               inst->flags = MONO_INST_VOLATILE;
+               }
+#endif
+
                /* Allocate a dummy MonoInst for the first vreg */
                MONO_INST_NEW (cfg, tree, OP_LOCAL);
                tree->dreg = inst->dreg + 1;
@@ -4090,6 +4020,10 @@ mini_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSigna
                        MONO_INST_NEW (cfg, ins, OP_MEMORY_BARRIER);
                        return ins;
                }
+               if (strcmp (cmethod->name, "SpinWait_nop") == 0) {
+                       MONO_INST_NEW (cfg, ins, OP_RELAXED_NOP);
+                       return ins;
+               }
        } else if (mini_class_is_system_array (cmethod->klass) &&
                        strcmp (cmethod->name, "GetGenericValueImpl") == 0) {
                MonoInst *sp [2];
@@ -4879,7 +4813,10 @@ set_exception_object (MonoCompile *cfg, MonoException *exception)
 static MonoInst*
 get_runtime_generic_context (MonoCompile *cfg, MonoMethod *method, int context_used, MonoInst *this, unsigned char *ip)
 {
-       g_assert (!method->klass->valuetype);
+       g_assert (cfg->generic_sharing_context);
+
+       if (method->klass->valuetype)
+               g_assert (!this);
 
        if (context_used & MONO_GENERIC_CONTEXT_USED_METHOD) {
                MonoInst *mrgctx_loc, *mrgctx_var;
@@ -4891,7 +4828,7 @@ get_runtime_generic_context (MonoCompile *cfg, MonoMethod *method, int context_u
                NEW_TEMPLOAD (cfg, mrgctx_var, mrgctx_loc->inst_c0);
 
                return mrgctx_var;
-       } else if (method->flags & METHOD_ATTRIBUTE_STATIC) {
+       } else if ((method->flags & METHOD_ATTRIBUTE_STATIC) || method->klass->valuetype) {
                MonoInst *vtable_loc, *vtable_var;
 
                g_assert (!this);
@@ -5007,6 +4944,9 @@ handle_unbox_nullable (MonoCompile* cfg, MonoMethod *caller_method, int context_
        MonoMethodSignature *signature = mono_method_signature (method);
 
        if (rgctx) {
+               /* FIXME: What if the class is shared?  We might not
+                  have to get the address of the method from the
+                  RGCTX. */
                MonoInst *addr = get_runtime_generic_context_method (cfg, caller_method, context_used, bblock, method,
                        generic_context, rgctx, MONO_RGCTX_INFO_GENERIC_METHOD_CODE, ip);
 
@@ -5026,6 +4966,8 @@ handle_box_nullable_from_inst (MonoCompile *cfg, MonoMethod *caller_method, int
 
        g_assert (mono_class_is_nullable (klass));
 
+       /* FIXME: What if the class is shared?  We might not have to
+          get the method address from the RGCTX. */
        method_addr = get_runtime_generic_context_method (cfg, caller_method, context_used, bblock, method,
                        generic_context, rgctx, MONO_RGCTX_INFO_GENERIC_METHOD_CODE, ip);
        temp = mono_emit_rgctx_calli_spilled (cfg, bblock, mono_method_signature (method), &val,
@@ -5123,9 +5065,6 @@ do_return:
        *_inline_costs = inline_costs;
        *_real_offset = real_offset;
        return return_value;
-exception_exit:
-       return_value = -2;
-       goto do_return;
 unverified:
        return_value = -1;
        goto do_return;
@@ -5182,16 +5121,12 @@ emit_unbox (MonoClass *klass, guint32 token, int context_used,
        add->klass = klass;
        *sp = add;
 
-do_return:
        *_bblock = bblock;
        *_ip = ip;
        *_sp = sp;
        *_inline_costs = inline_costs;
        *_real_offset = real_offset;
        return return_value;
-exception_exit:
-       return_value = -2;
-       goto do_return;
 }
 
 gboolean
@@ -5473,7 +5408,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                 * methods) are live.
                                 */
                                if ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
-                                               mini_method_get_context (method)->method_inst) {
+                                               mini_method_get_context (method)->method_inst ||
+                                               method->klass->valuetype) {
                                        mono_get_vtable_var (cfg);
                                } else {
                                        MonoInst *this, *dummy_use;
@@ -5923,7 +5859,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        float *f;
                        /* we should really allocate this only late in the compilation process */
                        mono_domain_lock (cfg->domain);
-                       f = mono_mempool_alloc (cfg->domain->mp, sizeof (float));
+                       f = mono_domain_alloc (cfg->domain, sizeof (float));
                        mono_domain_unlock (cfg->domain);
                        CHECK_OPSIZE (5);
                        CHECK_STACK_OVF (1);
@@ -5940,7 +5876,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                case CEE_LDC_R8: {
                        double *d;
                        mono_domain_lock (cfg->domain);
-                       d = mono_mempool_alloc (cfg->domain->mp, sizeof (double));
+                       d = mono_domain_alloc (cfg->domain, sizeof (double));
                        mono_domain_unlock (cfg->domain);
                        CHECK_OPSIZE (9);
                        CHECK_STACK_OVF (1);
@@ -6172,7 +6108,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        if (*ip != CEE_CALLI && check_call_signature (cfg, fsig, sp))
                                UNVERIFIED;
 
-                       if (cmethod && (cmethod->flags & METHOD_ATTRIBUTE_STATIC) &&
+                       if (cmethod && ((cmethod->flags & METHOD_ATTRIBUTE_STATIC) || cmethod->klass->valuetype) &&
                                        (cmethod->klass->generic_class || cmethod->klass->generic_container)) {
                                gboolean sharing_enabled = mono_class_generic_sharing_enabled (cmethod->klass);
                                MonoGenericContext *context = mini_class_get_context (cmethod->klass);
@@ -6227,7 +6163,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                 * should be a flag in the cfg to
                                 * request a generic sharing context.
                                 */
-                               if (context_used && method->flags & METHOD_ATTRIBUTE_STATIC)
+                               if (context_used && ((method->flags & METHOD_ATTRIBUTE_STATIC) || method->klass->valuetype))
                                        mono_get_vtable_var (cfg);
                        }
 
@@ -6495,16 +6431,11 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        else
                                no_spill = FALSE;
 
-                       /* FIXME: only do this for generic methods if
-                          they are not shared! */
-                       if (context_used &&
-                                       (cmethod->klass->valuetype ||
-                                       (cmethod->is_inflated && mono_method_get_context (cmethod)->method_inst && !pass_mrgctx) ||
-                                       ((cmethod->flags & METHOD_ATTRIBUTE_STATIC) &&
-                                               mono_class_generic_sharing_enabled (cmethod->klass)) ||
-                                       (!imt_arg && !mono_method_is_generic_sharable_impl (cmethod, TRUE) &&
-                                               (!virtual || cmethod->flags & METHOD_ATTRIBUTE_FINAL ||
-                                               !(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL))))) {
+                       if (context_used && !imt_arg &&
+                                       (!mono_method_is_generic_sharable_impl (cmethod, TRUE) ||
+                                               !mono_class_generic_sharing_enabled (cmethod->klass)) &&
+                                       (!virtual || cmethod->flags & METHOD_ATTRIBUTE_FINAL ||
+                                               !(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL))) {
                                MonoInst *rgctx;
 
                                INLINE_FAILURE;
@@ -7307,6 +7238,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        MonoMethodSignature *fsig;
                        MonoInst this_ins;
                        int temp;
+                       MonoInst *vtable_arg = NULL;
 
                        CHECK_OPSIZE (5);
                        token = read32 (ip + 1);
@@ -7331,6 +7263,41 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                ensure_method_is_allowed_to_call_method (cfg, method, cmethod, bblock, ip);
                        }
 
+                       if (cmethod->klass->valuetype && mono_class_generic_sharing_enabled (cmethod->klass) &&
+                                       mono_method_is_generic_sharable_impl (cmethod, TRUE)) {
+                               if (cmethod->is_inflated && mono_method_get_context (cmethod)->method_inst) {
+                                       if (context_used) {
+                                               MonoInst *rgctx;
+
+                                               GET_RGCTX (rgctx, context_used);
+                                               vtable_arg = get_runtime_generic_context_method_rgctx (cfg, method,
+                                                       context_used, bblock, cmethod, generic_context, rgctx, ip);
+                                       } else {
+                                               MonoVTable *vtable = mono_class_vtable (cfg->domain, cmethod->klass);
+                                               MonoMethodRuntimeGenericContext *mrgctx;
+
+                                               mrgctx = mono_method_lookup_rgctx (vtable,
+                                                       mini_method_get_context (cmethod)->method_inst);
+
+                                               NEW_PCONST (cfg, vtable_arg, mrgctx);
+                                       }
+                               } else {
+                                       if (context_used) {
+                                               MonoInst *rgctx;
+
+                                               GET_RGCTX (rgctx, context_used);
+                                               vtable_arg = get_runtime_generic_context_ptr (cfg, method, context_used,
+                                                       bblock, cmethod->klass, generic_context,
+                                                       rgctx, MONO_RGCTX_INFO_VTABLE, ip);
+                                       } else {
+                                               MonoVTable *vtable = mono_class_vtable (cfg->domain, cmethod->klass);
+
+                                               CHECK_TYPELOAD (cmethod->klass);
+                                               NEW_VTABLECONST (cfg, vtable_arg, vtable);
+                                       }
+                               }
+                       }
+
                        n = fsig->param_count;
                        CHECK_STACK (n);
  
@@ -7343,7 +7310,9 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                ((n < 2) || (!fsig->params [1]->byref && fsig->params [1]->type == MONO_TYPE_STRING))) {
                                MonoInst *iargs [3];
                                int temp;
-                               
+
+                               g_assert (!vtable_arg);
+
                                sp -= n;
 
                                NEW_ICONST (cfg, iargs [0], cmethod->klass->type_token);
@@ -7387,6 +7356,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
 
                        if (mini_class_is_system_array (cmethod->klass)) {
                                g_assert (!context_used);
+                               g_assert (!vtable_arg);
 
                                NEW_METHODCONST (cfg, *sp, cmethod);
 
@@ -7397,6 +7367,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                        temp = handle_array_new (cfg, bblock, fsig->param_count, sp, ip);
                        } else if (cmethod->string_ctor) {
                                g_assert (!context_used);
+                               g_assert (!vtable_arg);
 
                                /* we simply pass a null pointer */
                                NEW_PCONST (cfg, *sp, NULL); 
@@ -7455,7 +7426,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                if (cmethod->klass->marshalbyref)
                                        callvirt_this_arg = sp [0];
                                
-                               if ((cfg->opt & MONO_OPT_INLINE) && cmethod && !context_used &&
+                               if ((cfg->opt & MONO_OPT_INLINE) && cmethod && !context_used && !vtable_arg &&
                                    mono_method_check_inlining (cfg, cmethod) &&
                                    !mono_class_is_subclass_of (cmethod->klass, mono_defaults.exception_class, FALSE) &&
                                    !g_list_find (dont_inline, cmethod)) {
@@ -7486,8 +7457,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                                mono_emit_method_call_spilled (cfg, bblock, cmethod, fsig, sp, ip, callvirt_this_arg);
                                        }
                                } else if (context_used &&
-                                               (cmethod->klass->valuetype ||
-                                               !mono_method_is_generic_sharable_impl (cmethod, TRUE))) {
+                                               (!mono_method_is_generic_sharable_impl (cmethod, TRUE) ||
+                                                       !mono_class_generic_sharing_enabled (cmethod->klass))) {
                                        MonoInst *rgctx, *cmethod_addr;
 
                                        g_assert (!callvirt_this_arg);
@@ -7497,12 +7468,13 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                                        bblock, cmethod,
                                                        generic_context, rgctx, MONO_RGCTX_INFO_GENERIC_METHOD_CODE, ip);
 
-                                       mono_emit_calli_spilled (cfg, bblock, fsig, sp, cmethod_addr, ip);
+                                       mono_emit_rgctx_calli_spilled (cfg, bblock, fsig, sp, cmethod_addr, vtable_arg, ip);
                                } else {
                                        /* Prevent inlining of methods which call other methods */
                                        INLINE_FAILURE;
                                        /* now call the actual ctor */
-                                       mono_emit_method_call_spilled (cfg, bblock, cmethod, fsig, sp, ip, callvirt_this_arg);
+                                       mono_emit_rgctx_method_call_spilled (cfg, bblock, cmethod, fsig, sp,
+                                               vtable_arg, NULL, ip, callvirt_this_arg);
                                }
                        }
 
@@ -8008,7 +7980,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
 
                                        call = mono_emit_call_args (cfg, bblock, sig, NULL, FALSE, FALSE, ip, FALSE);
                                        call->inst.opcode = OP_TRAMPCALL_VTABLE;
-                                       call->fptr = mono_get_trampoline_code (MONO_TRAMPOLINE_GENERIC_CLASS_INIT);
+                                       call->fptr = mono_create_generic_class_init_trampoline ();
 
                                        call->inst.inst_left = vtable;
 
@@ -8587,7 +8559,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                if (sp [2]->opcode == OP_PCONST && sp [2]->inst_p0 == NULL) {
                                        MonoInst *load;
                                        NEW_LDELEMA (cfg, load, sp, mono_defaults.object_class);
-                                       MONO_INST_NEW (cfg, ins, stelem_to_stind [*ip - CEE_STELEM_I]);
+                                       MONO_INST_NEW (cfg, ins, CEE_STIND_REF);
                                        ins->inst_left = load;
                                        ins->inst_right = sp [2];
                                        MONO_ADD_INS (bblock, ins);
@@ -9348,7 +9320,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                MonoInst *argconst;
                                MonoMethod *cil_method, *ctor_method;
                                int temp;
-                               gboolean is_shared = FALSE;
+                               gboolean needs_static_rgctx_invoke;
 
                                CHECK_STACK_OVF (1);
                                CHECK_OPSIZE (6);
@@ -9361,15 +9333,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                if (cfg->generic_sharing_context)
                                        context_used = mono_method_check_context_used (cmethod);
 
-                               if (mono_class_generic_sharing_enabled (cmethod->klass)) {
-                                       if ((cmethod->flags & METHOD_ATTRIBUTE_STATIC) &&
-                                                       (cmethod->klass->generic_class ||
-                                                       cmethod->klass->generic_container)) {
-                                               is_shared = TRUE;
-                                       }
-                                       if (cmethod->is_inflated && mono_method_get_context (cmethod)->method_inst)
-                                               is_shared = TRUE;
-                               }
+                               needs_static_rgctx_invoke = mono_method_needs_static_rgctx_invoke (cmethod, TRUE);
 
                                cil_method = cmethod;
                                if (!dont_verify && !cfg->skip_visibility && !mono_method_can_access_method (method, cmethod))
@@ -9389,7 +9353,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                /* FIXME: SGEN support */
                                /* FIXME: handle shared static generic methods */
                                /* FIXME: handle this in shared code */
-                               if (!is_shared && !context_used && (sp > stack_start) && (ip + 6 + 5 < end) && ip_in_bb (cfg, bblock, ip + 6) && (ip [6] == CEE_NEWOBJ) && (ctor_method = mini_get_method (cfg, method, read32 (ip + 7), NULL, generic_context)) && (ctor_method->klass->parent == mono_defaults.multicastdelegate_class)) {
+                               if (!needs_static_rgctx_invoke && !context_used && (sp > stack_start) && (ip + 6 + 5 < end) && ip_in_bb (cfg, bblock, ip + 6) && (ip [6] == CEE_NEWOBJ) && (ctor_method = mini_get_method (cfg, method, read32 (ip + 7), NULL, generic_context)) && (ctor_method->klass->parent == mono_defaults.multicastdelegate_class)) {
                                        MonoInst *target_ins;
 
                                        ip += 6;
@@ -9409,22 +9373,19 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                if (context_used) {
                                        MonoInst *rgctx;
 
-                                       if (is_shared)
+                                       if (needs_static_rgctx_invoke)
                                                cmethod = mono_marshal_get_static_rgctx_invoke (cmethod);
 
                                        GET_RGCTX (rgctx, context_used);
                                        argconst = get_runtime_generic_context_method (cfg, method, context_used,
                                                        bblock, cmethod,
                                                        generic_context, rgctx, MONO_RGCTX_INFO_METHOD, ip);
-                               } else if (is_shared) {
+                               } else if (needs_static_rgctx_invoke) {
                                        NEW_METHODCONST (cfg, argconst, mono_marshal_get_static_rgctx_invoke (cmethod));
                                } else {
                                        NEW_METHODCONST (cfg, argconst, cmethod);
                                }
-                               if (method->wrapper_type != MONO_WRAPPER_SYNCHRONIZED)
-                                       temp = mono_emit_jit_icall (cfg, bblock, mono_ldftn, &argconst, ip);
-                               else
-                                       temp = mono_emit_jit_icall (cfg, bblock, mono_ldftn_nosync, &argconst, ip);
+                               temp = mono_emit_jit_icall (cfg, bblock, mono_ldftn, &argconst, ip);
                                NEW_TEMPLOAD (cfg, *sp, temp);
                                sp ++;
                                
@@ -9701,8 +9662,10 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
 
                                for (i = 0; i < header->num_clauses; ++i) {
                                        MonoExceptionClause *clause = &header->clauses [i];
-                                       if (MONO_OFFSET_IN_HANDLER (clause, ip - header->code) && !(clause->flags & MONO_EXCEPTION_CLAUSE_FINALLY))
+                                       if (MONO_OFFSET_IN_HANDLER (clause, ip - header->code) && !(clause->flags & MONO_EXCEPTION_CLAUSE_FINALLY)) {
                                                handler_offset = clause->handler_offset;
+                                               break;
+                                       }
                                }
 
                                bblock->flags |= BB_EXCEPTION_UNSAFE;
@@ -10048,8 +10011,8 @@ create_helper_signature (void)
        helper_sig_rgctx_lazy_fetch_trampoline = mono_create_icall_signature ("ptr ptr");
 }
 
-gconstpointer
-mono_icall_get_wrapper (MonoJitICallInfo* callinfo)
+static gconstpointer
+mono_icall_get_wrapper_full (MonoJitICallInfo* callinfo, gboolean do_compile)
 {
        char *name;
        MonoMethod *wrapper;
@@ -10078,7 +10041,10 @@ mono_icall_get_wrapper (MonoJitICallInfo* callinfo)
        wrapper = mono_marshal_get_icall_wrapper (callinfo->sig, name, callinfo->func, check_for_pending_exc);
        g_free (name);
 
-       trampoline = mono_create_ftnptr (domain, mono_create_jit_trampoline_in_domain (domain, wrapper, TRUE));
+       if (do_compile)
+               trampoline = mono_compile_method (wrapper);
+       else
+               trampoline = mono_create_ftnptr (domain, mono_create_jit_trampoline_in_domain (domain, wrapper));
        mono_register_jit_icall_wrapper (callinfo, trampoline);
 
        callinfo->trampoline = trampoline;
@@ -10088,12 +10054,18 @@ mono_icall_get_wrapper (MonoJitICallInfo* callinfo)
        return callinfo->trampoline;
 }
 
+gconstpointer
+mono_icall_get_wrapper (MonoJitICallInfo* callinfo)
+{
+       return mono_icall_get_wrapper_full (callinfo, FALSE);
+}
+
 static void
 mono_dynamic_code_hash_insert (MonoDomain *domain, MonoMethod *method, MonoJitDynamicMethodInfo *ji)
 {
-       if (!domain->dynamic_code_hash)
-               domain->dynamic_code_hash = g_hash_table_new (NULL, NULL);
-       g_hash_table_insert (domain->dynamic_code_hash, method, ji);
+       if (!domain_jit_info (domain)->dynamic_code_hash)
+               domain_jit_info (domain)->dynamic_code_hash = g_hash_table_new (NULL, NULL);
+       g_hash_table_insert (domain_jit_info (domain)->dynamic_code_hash, method, ji);
 }
 
 static MonoJitDynamicMethodInfo*
@@ -10101,8 +10073,8 @@ mono_dynamic_code_hash_lookup (MonoDomain *domain, MonoMethod *method)
 {
        MonoJitDynamicMethodInfo *res;
 
-       if (domain->dynamic_code_hash)
-               res = g_hash_table_lookup (domain->dynamic_code_hash, method);
+       if (domain_jit_info (domain)->dynamic_code_hash)
+               res = g_hash_table_lookup (domain_jit_info (domain)->dynamic_code_hash, method);
        else
                res = NULL;
        return res;
@@ -10114,19 +10086,6 @@ typedef struct {
        GSList *slots;
 } StackSlotInfo;
 
-static inline GSList*
-g_slist_prepend_mempool (MonoMemPool *mp, GSList   *list,
-                                                gpointer  data)
-{
-  GSList *new_list;
-
-  new_list = mono_mempool_alloc (mp, sizeof (GSList));
-  new_list->data = data;
-  new_list->next = list;
-
-  return new_list;
-}
-
 static gint 
 compare_by_interval_start_pos_func (gconstpointer a, gconstpointer b)
 {
@@ -10143,6 +10102,8 @@ 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
@@ -10628,6 +10589,17 @@ mono_allocate_stack_slots (MonoCompile *m, guint32 *stack_size, guint32 *stack_a
        return mono_allocate_stack_slots_full (m, TRUE, stack_size, stack_align);
 }
 
+#else
+
+gint32*
+mono_allocate_stack_slots_full (MonoCompile *cfg, gboolean backward, guint32 *stack_size, guint32 *stack_align)
+{
+       g_assert_not_reached ();
+       return NULL;
+}
+
+#endif /* DISABLE_JIT */
+
 void
 mono_register_opcode_emulation (int opcode, const char *name, const char *sigstr, gpointer func, gboolean no_throw)
 {
@@ -10955,8 +10927,8 @@ mono_destroy_compile (MonoCompile *cfg)
        mono_mempool_destroy (cfg->mempool);
        g_list_free (cfg->ldstr_list);
        g_hash_table_destroy (cfg->token_info_hash);
-
-       g_free (cfg->reverse_inst_list);
+       if (cfg->abs_patches)
+               g_hash_table_destroy (cfg->abs_patches);
 
        g_free (cfg->varinfo);
        g_free (cfg->vars);
@@ -11193,7 +11165,7 @@ mono_create_tls_get (MonoCompile *cfg, int offset)
                return NULL;
        
        MONO_INST_NEW (cfg, ins, OP_TLS_GET);
-       ins->dreg = mono_regstate_next_int (cfg->rs);
+       ins->dreg = cfg->new_ir ? mono_alloc_preg (cfg) : mono_regstate_next_int (cfg->rs);
        ins->inst_offset = offset;
        return ins;
 #else
@@ -11270,6 +11242,11 @@ mono_patch_info_dup_mp (MonoMemPool *mp, MonoJumpInfo *patch_info)
                res->data.table = mono_mempool_alloc (mp, sizeof (MonoJumpInfoBBTable));
                memcpy (res->data.table, patch_info->data.table, sizeof (MonoJumpInfoBBTable));
                break;
+       case MONO_PATCH_INFO_RGCTX_FETCH:
+               res->data.rgctx_entry = mono_mempool_alloc (mp, sizeof (MonoJumpInfoRgctxEntry));
+               memcpy (res->data.rgctx_entry, patch_info->data.rgctx_entry, sizeof (MonoJumpInfoRgctxEntry));
+               res->data.rgctx_entry->data = mono_patch_info_dup_mp (mp, res->data.rgctx_entry->data);
+               break;
        default:
                break;
        }
@@ -11300,7 +11277,6 @@ mono_patch_info_hash (gconstpointer data)
        case MONO_PATCH_INFO_IMAGE:
        case MONO_PATCH_INFO_INTERNAL_METHOD:
        case MONO_PATCH_INFO_JIT_ICALL_ADDR:
-       case MONO_PATCH_INFO_WRAPPER:
        case MONO_PATCH_INFO_FIELD:
        case MONO_PATCH_INFO_SFLDA:
                return (ji->type << 8) | (gssize)ji->data.target;
@@ -11377,7 +11353,7 @@ 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, TRUE);
+               target = mono_create_jump_trampoline (domain, patch_info->data.method, FALSE);
                break;
        case MONO_PATCH_INFO_METHOD:
                if (patch_info->data.method == method) {
@@ -11386,7 +11362,7 @@ mono_resolve_patch_target (MonoMethod *method, MonoDomain *domain, guint8 *code,
                        /* get the trampoline to the method from the domain */
                        if (method && method->wrapper_type == MONO_WRAPPER_STATIC_RGCTX_INVOKE) {
                                target = mono_create_jit_trampoline_in_domain (mono_domain_get (),
-                                       patch_info->data.method, FALSE);
+                                       patch_info->data.method);
                        } else {
                                target = mono_create_jit_trampoline (patch_info->data.method);
                        }
@@ -11401,7 +11377,7 @@ mono_resolve_patch_target (MonoMethod *method, MonoDomain *domain, guint8 *code,
                } else {
                        mono_domain_lock (domain);
                        if (mono_aot_only)
-                               jump_table = mono_mempool_alloc (domain->mp, sizeof (gpointer) * patch_info->data.table->table_size);
+                               jump_table = mono_domain_alloc (domain, sizeof (gpointer) * patch_info->data.table->table_size);
                        else
                                jump_table = mono_code_manager_reserve (domain->code_mp, sizeof (gpointer) * patch_info->data.table->table_size);
                        mono_domain_unlock (domain);
@@ -11522,6 +11498,32 @@ mono_resolve_patch_target (MonoMethod *method, MonoDomain *domain, guint8 *code,
        case MONO_PATCH_INFO_GOT_OFFSET:
        case MONO_PATCH_INFO_NONE:
                break;
+       case MONO_PATCH_INFO_RGCTX_FETCH: {
+               MonoJumpInfoRgctxEntry *entry = patch_info->data.rgctx_entry;
+               guint32 slot = -1;
+
+               switch (entry->data->type) {
+               case MONO_PATCH_INFO_CLASS:
+                       slot = mono_method_lookup_or_register_other_info (entry->method, entry->in_mrgctx, &entry->data->data.klass->byval_arg, entry->info_type, mono_method_get_context (entry->method));
+                       break;
+               case MONO_PATCH_INFO_METHOD:
+               case MONO_PATCH_INFO_METHODCONST:
+                       slot = mono_method_lookup_or_register_other_info (entry->method, entry->in_mrgctx, entry->data->data.method, entry->info_type, mono_method_get_context (entry->method));
+                       break;
+               case MONO_PATCH_INFO_FIELD:
+                       slot = mono_method_lookup_or_register_other_info (entry->method, entry->in_mrgctx, entry->data->data.field, entry->info_type, mono_method_get_context (entry->method));
+                       break;
+               default:
+                       g_assert_not_reached ();
+                       break;
+               }
+
+               target = mono_create_rgctx_lazy_fetch_trampoline (slot);
+               break;
+       }
+       case MONO_PATCH_INFO_GENERIC_CLASS_INIT:
+               target = mono_create_generic_class_init_trampoline ();
+               break;
        default:
                g_assert_not_reached ();
        }
@@ -11604,728 +11606,62 @@ decompose_pass (MonoCompile *cfg) {
 }
 
 static void
-nullify_basic_block (MonoBasicBlock *bb) 
-{
-       bb->in_count = 0;
-       bb->out_count = 0;
-       bb->in_bb = NULL;
-       bb->out_bb = NULL;
-       bb->next_bb = NULL;
-       bb->code = bb->last_ins = NULL;
-       bb->cil_code = NULL;
-}
-
-static void 
-replace_out_block (MonoBasicBlock *bb, MonoBasicBlock *orig,  MonoBasicBlock *repl)
+mono_compile_create_vars (MonoCompile *cfg)
 {
+       MonoMethodSignature *sig;
+       MonoMethodHeader *header;
        int i;
 
-       for (i = 0; i < bb->out_count; i++) {
-               MonoBasicBlock *ob = bb->out_bb [i];
-               if (ob == orig) {
-                       if (!repl) {
-                               if (bb->out_count > 1) {
-                                       bb->out_bb [i] = bb->out_bb [bb->out_count - 1];
-                               }
-                               bb->out_count--;
-                       } else {
-                               bb->out_bb [i] = repl;
-                       }
+       header = mono_method_get_header (cfg->method);
+
+       sig = mono_method_signature (cfg->method);
+       
+       if (!MONO_TYPE_IS_VOID (sig->ret)) {
+               if (cfg->new_ir) {
+                       cfg->ret = mono_compile_create_var (cfg, sig->ret, OP_ARG);
+                       /* Inhibit optimizations */
+                       cfg->ret->flags |= MONO_INST_VOLATILE;
+               } else {
+                       cfg->ret = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst));
+                       cfg->ret->opcode = OP_RETARG;
+                       cfg->ret->inst_vtype = sig->ret;
+                       cfg->ret->klass = mono_class_from_mono_type (sig->ret);
                }
        }
-}
+       if (cfg->verbose_level > 2)
+               g_print ("creating vars\n");
 
-static void 
-replace_in_block (MonoBasicBlock *bb, MonoBasicBlock *orig, MonoBasicBlock *repl)
-{
-       int i;
+       cfg->args = mono_mempool_alloc0 (cfg->mempool, (sig->param_count + sig->hasthis) * sizeof (MonoInst*));
 
-       for (i = 0; i < bb->in_count; i++) {
-               MonoBasicBlock *ib = bb->in_bb [i];
-               if (ib == orig) {
-                       if (!repl) {
-                               if (bb->in_count > 1) {
-                                       bb->in_bb [i] = bb->in_bb [bb->in_count - 1];
-                               }
-                               bb->in_count--;
-                       } else {
-                               bb->in_bb [i] = repl;
-                       }
+       if (sig->hasthis)
+               cfg->args [0] = mono_compile_create_var (cfg, &cfg->method->klass->this_arg, OP_ARG);
+
+       for (i = 0; i < sig->param_count; ++i) {
+               cfg->args [i + sig->hasthis] = mono_compile_create_var (cfg, sig->params [i], OP_ARG);
+               if (sig->params [i]->byref) {
+                       if (!cfg->new_ir) cfg->disable_ssa = TRUE;
                }
        }
-}
 
-static void
-replace_out_block_in_code (MonoBasicBlock *bb, MonoBasicBlock *orig, MonoBasicBlock *repl) {
-       MonoInst *ins;
-       
-       for (ins = bb->code; ins != NULL; ins = ins->next) {
-               switch (ins->opcode) {
-               case OP_BR:
-                       if (ins->inst_target_bb == orig)
-                               ins->inst_target_bb = repl;
-                       break;
-               case OP_CALL_HANDLER:
-                       if (ins->inst_target_bb == orig)
-                               ins->inst_target_bb = repl;
-                       break;
-               case OP_SWITCH: {
-                       int i;
-                       int n = GPOINTER_TO_INT (ins->klass);
-                       for (i = 0; i < n; i++ ) {
-                               if (ins->inst_many_bb [i] == orig)
-                                       ins->inst_many_bb [i] = repl;
-                       }
-                       break;
+       if (cfg->new_ir && cfg->verbose_level > 2) {
+               if (cfg->ret) {
+                       printf ("\treturn : ");
+                       mono_print_ins (cfg->ret);
                }
-               default:
-                       if (MONO_IS_COND_BRANCH_OP (ins)) {
-                               if (ins->inst_true_bb == orig)
-                                       ins->inst_true_bb = repl;
-                               if (ins->inst_false_bb == orig)
-                                       ins->inst_false_bb = repl;
-                       } else if (MONO_IS_JUMP_TABLE (ins)) {
-                               int i;
-                               MonoJumpInfoBBTable *table = MONO_JUMP_TABLE_FROM_INS (ins);
-                               for (i = 0; i < table->table_size; i++ ) {
-                                       if (table->table [i] == orig)
-                                               table->table [i] = repl;
-                               }
-                       }
 
-                       break;
+               if (sig->hasthis) {
+                       printf ("\tthis: ");
+                       mono_print_ins (cfg->args [0]);
                }
-       }
-}
-
-/**
-  * Check if a bb is useless (is just made of NOPs and ends with an
-  * unconditional branch, or nothing).
-  * If it is so, unlink it from the CFG and nullify it, and return TRUE.
-  * Otherwise, return FALSE;
-  */
-static gboolean
-remove_block_if_useless (MonoCompile *cfg, MonoBasicBlock *bb, MonoBasicBlock *previous_bb) {
-       MonoBasicBlock *target_bb = NULL;
-       MonoInst *inst;
 
-       /* Do not touch handlers */
-       if (bb->region != -1) {
-               bb->not_useless = TRUE;
-               return FALSE;
-       }
-       
-       MONO_BB_FOR_EACH_INS (bb, inst) {
-               switch (inst->opcode) {
-               case OP_NOP:
-                       break;
-               case OP_BR:
-                       target_bb = inst->inst_target_bb;
-                       break;
-               default:
-                       bb->not_useless = TRUE;
-                       return FALSE;
-               }
-       }
-       
-       if (target_bb == NULL) {
-               if ((bb->out_count == 1) && (bb->out_bb [0] == bb->next_bb)) {
-                       target_bb = bb->next_bb;
-               } else {
-                       /* Do not touch empty BBs that do not "fall through" to their next BB (like the exit BB) */
-                       return FALSE;
+               for (i = 0; i < sig->param_count; ++i) {
+                       printf ("\targ [%d]: ", i);
+                       mono_print_ins (cfg->args [i + sig->hasthis]);
                }
        }
-       
-       /* Do not touch BBs following a switch (they are the "default" branch) */
-       if ((previous_bb->last_ins != NULL) && (previous_bb->last_ins->opcode == OP_SWITCH)) {
-               return FALSE;
-       }
-       
-       /* Do not touch BBs following the entry BB and jumping to something that is not */
-       /* thiry "next" bb (the entry BB cannot contain the branch) */
-       if ((previous_bb == cfg->bb_entry) && (bb->next_bb != target_bb)) {
-               return FALSE;
-       }
 
-       /* 
-        * Do not touch BBs following a try block as the code in 
-        * mini_method_compile needs them to compute the length of the try block.
-        */
-       if (MONO_BBLOCK_IS_IN_REGION (previous_bb, MONO_REGION_TRY))
-               return FALSE;
-       
-       /* Check that there is a target BB, and that bb is not an empty loop (Bug 75061) */
-       if ((target_bb != NULL) && (target_bb != bb)) {
-               int i;
-
-               if (cfg->verbose_level > 1) {
-                       printf ("remove_block_if_useless, removed BB%d\n", bb->block_num);
-               }
-               
-               /* unlink_bblock () modifies the bb->in_bb array so can't use a for loop here */
-               while (bb->in_count) {
-                       MonoBasicBlock *in_bb = bb->in_bb [0];
-                       mono_unlink_bblock (cfg, in_bb, bb);
-                       link_bblock (cfg, in_bb, target_bb);
-                       replace_out_block_in_code (in_bb, bb, target_bb);
-               }
-               
-               mono_unlink_bblock (cfg, bb, target_bb);
-               
-               if ((previous_bb != cfg->bb_entry) &&
-                               (previous_bb->region == bb->region) &&
-                               ((previous_bb->last_ins == NULL) ||
-                               ((previous_bb->last_ins->opcode != OP_BR) &&
-                               (! (MONO_IS_COND_BRANCH_OP (previous_bb->last_ins))) &&
-                               (previous_bb->last_ins->opcode != OP_SWITCH)))) {
-                       for (i = 0; i < previous_bb->out_count; i++) {
-                               if (previous_bb->out_bb [i] == target_bb) {
-                                       MonoInst *jump;
-                                       MONO_INST_NEW (cfg, jump, OP_BR);
-                                       MONO_ADD_INS (previous_bb, jump);
-                                       jump->cil_code = previous_bb->cil_code;
-                                       jump->inst_target_bb = target_bb;
-                                       break;
-                               }
-                       }
-               }
-               
-               previous_bb->next_bb = bb->next_bb;
-               nullify_basic_block (bb);
-               
-               return TRUE;
-       } else {
-               return FALSE;
-       }
-}
-
-void
-mono_merge_basic_blocks (MonoCompile *cfg, MonoBasicBlock *bb, MonoBasicBlock *bbn) 
-{
-       MonoInst *inst;
-       MonoBasicBlock *prev_bb;
-       int i;
-
-       bb->has_array_access |= bbn->has_array_access;
-       bb->extended |= bbn->extended;
-
-       mono_unlink_bblock (cfg, bb, bbn);
-       for (i = 0; i < bbn->out_count; ++i)
-               mono_link_bblock (cfg, bb, bbn->out_bb [i]);
-       while (bbn->out_count)
-               mono_unlink_bblock (cfg, bbn, bbn->out_bb [0]);
-
-       /* Handle the branch at the end of the bb */
-       for (inst = bb->code; inst != NULL; inst = inst->next) {
-               if (inst->opcode == OP_CALL_HANDLER) {
-                       g_assert (inst->inst_target_bb == bbn);
-                       NULLIFY_INS (inst);
-               }
-               if (MONO_IS_JUMP_TABLE (inst)) {
-                       int i;
-                       MonoJumpInfoBBTable *table = MONO_JUMP_TABLE_FROM_INS (inst);
-                       for (i = 0; i < table->table_size; i++ ) {
-                               /* Might be already NULL from a previous merge */
-                               if (table->table [i])
-                                       g_assert (table->table [i] == bbn);
-                               table->table [i] = NULL;
-                       }
-                       /* Can't nullify this as later instructions depend on it */
-               }
-       }
-       if (bb->last_ins && MONO_IS_COND_BRANCH_OP (bb->last_ins)) {
-               g_assert (bb->last_ins->inst_false_bb == bbn);
-               bb->last_ins->inst_false_bb = NULL;
-               bb->extended = TRUE;
-       } else if (bb->last_ins && MONO_IS_BRANCH_OP (bb->last_ins)) {
-               NULLIFY_INS (bb->last_ins);
-       }
-
-       if (bb->last_ins) {
-               if (bbn->code) {
-                       bb->last_ins->next = bbn->code;
-                       bbn->code->prev = bb->last_ins;
-                       bb->last_ins = bbn->last_ins;
-               }
-       } else {
-               bb->code = bbn->code;
-               bb->last_ins = bbn->last_ins;
-       }
-       for (prev_bb = cfg->bb_entry; prev_bb && prev_bb->next_bb != bbn; prev_bb = prev_bb->next_bb)
-               ;
-       if (prev_bb) {
-               prev_bb->next_bb = bbn->next_bb;
-       } else {
-               /* bbn might not be in the bb list yet */
-               if (bb->next_bb == bbn)
-                       bb->next_bb = bbn->next_bb;
-       }
-       nullify_basic_block (bbn);
-}
-
-static void
-move_basic_block_to_end (MonoCompile *cfg, MonoBasicBlock *bb)
-{
-       MonoBasicBlock *bbn, *next;
-
-       next = bb->next_bb;
-
-       /* Find the previous */
-       for (bbn = cfg->bb_entry; bbn->next_bb && bbn->next_bb != bb; bbn = bbn->next_bb)
-               ;
-       if (bbn->next_bb) {
-               bbn->next_bb = bb->next_bb;
-       }
-
-       /* Find the last */
-       for (bbn = cfg->bb_entry; bbn->next_bb; bbn = bbn->next_bb)
-               ;
-       bbn->next_bb = bb;
-       bb->next_bb = NULL;
-
-       /* Add a branch */
-       if (next && (!bb->last_ins || ((bb->last_ins->opcode != OP_NOT_REACHED) && (bb->last_ins->opcode != OP_BR) && (bb->last_ins->opcode != OP_BR_REG) && (!MONO_IS_COND_BRANCH_OP (bb->last_ins))))) {
-               MonoInst *ins;
-
-               MONO_INST_NEW (cfg, ins, OP_BR);
-               MONO_ADD_INS (bb, ins);
-               link_bblock (cfg, bb, next);
-               ins->inst_target_bb = next;
-       }               
-}
-
-/*
- * mono_remove_block:
- *
- *   Remove BB from the control flow graph
- */
-void
-mono_remove_bblock (MonoCompile *cfg, MonoBasicBlock *bb) 
-{
-       MonoBasicBlock *tmp_bb;
-
-       for (tmp_bb = cfg->bb_entry; tmp_bb && tmp_bb->next_bb != bb; tmp_bb = tmp_bb->next_bb)
-               ;
-
-       g_assert (tmp_bb);
-       tmp_bb->next_bb = bb->next_bb;
-}
-
-/* checks that a and b represent the same instructions, conservatively,
- * it can return FALSE also for two trees that are equal.
- * FIXME: also make sure there are no side effects.
- */
-static int
-same_trees (MonoInst *a, MonoInst *b)
-{
-       int arity;
-       if (a->opcode != b->opcode)
-               return FALSE;
-       arity = mono_burg_arity [a->opcode];
-       if (arity == 1) {
-               if (a->ssa_op == b->ssa_op && a->ssa_op == MONO_SSA_LOAD && a->inst_i0 == b->inst_i0)
-                       return TRUE;
-               return same_trees (a->inst_left, b->inst_left);
-       } else if (arity == 2) {
-               return same_trees (a->inst_left, b->inst_left) && same_trees (a->inst_right, b->inst_right);
-       } else if (arity == 0) {
-               switch (a->opcode) {
-               case OP_ICONST:
-                       return a->inst_c0 == b->inst_c0;
-               default:
-                       return FALSE;
-               }
-       }
-       return FALSE;
-}
-
-static int
-get_unsigned_condbranch (int opcode)
-{
-       switch (opcode) {
-       case CEE_BLE: return CEE_BLE_UN;
-       case CEE_BLT: return CEE_BLT_UN;
-       case CEE_BGE: return CEE_BGE_UN;
-       case CEE_BGT: return CEE_BGT_UN;
-       }
-       g_assert_not_reached ();
-       return 0;
-}
-
-static int
-tree_is_unsigned (MonoInst* ins) {
-       switch (ins->opcode) {
-       case OP_ICONST:
-               return (int)ins->inst_c0 >= 0;
-       /* array lengths are positive as are string sizes */
-       case CEE_LDLEN:
-       case OP_STRLEN:
-               return TRUE;
-       case CEE_CONV_U1:
-       case CEE_CONV_U2:
-       case CEE_CONV_U4:
-       case CEE_CONV_OVF_U1:
-       case CEE_CONV_OVF_U2:
-       case CEE_CONV_OVF_U4:
-               return TRUE;
-       case CEE_LDIND_U1:
-       case CEE_LDIND_U2:
-       case CEE_LDIND_U4:
-               return TRUE;
-       default:
-               return FALSE;
-       }
-}
-
-/* check if an unsigned compare can be used instead of two signed compares
- * for (val < 0 || val > limit) conditionals.
- * Returns TRUE if the optimization has been applied.
- * Note that this can't be applied if the second arg is not positive...
- */
-static int
-try_unsigned_compare (MonoCompile *cfg, MonoBasicBlock *bb)
-{
-       MonoBasicBlock *truet, *falset;
-       MonoInst *cmp_inst = bb->last_ins->inst_left;
-       MonoInst *condb;
-       if (!cmp_inst->inst_right->inst_c0 == 0)
-               return FALSE;
-       truet = bb->last_ins->inst_true_bb;
-       falset = bb->last_ins->inst_false_bb;
-       if (falset->in_count != 1)
-               return FALSE;
-       condb = falset->last_ins;
-       /* target bb must have one instruction */
-       if (!condb || (condb != falset->code))
-               return FALSE;
-       if ((((condb->opcode == CEE_BLE || condb->opcode == CEE_BLT) && (condb->inst_false_bb == truet))
-                       || ((condb->opcode == CEE_BGE || condb->opcode == CEE_BGT) && (condb->inst_true_bb == truet)))
-                       && same_trees (cmp_inst->inst_left, condb->inst_left->inst_left)) {
-               if (!tree_is_unsigned (condb->inst_left->inst_right))
-                       return FALSE;
-               condb->opcode = get_unsigned_condbranch (condb->opcode);
-               /* change the original condbranch to just point to the new unsigned check */
-               bb->last_ins->opcode = OP_BR;
-               bb->last_ins->inst_target_bb = falset;
-               replace_out_block (bb, truet, NULL);
-               replace_in_block (truet, bb, NULL);
-               return TRUE;
-       }
-       return FALSE;
-}
-
-/*
- * Optimizes the branches on the Control Flow Graph
- *
- */
-void
-mono_optimize_branches (MonoCompile *cfg)
-{
-       int i, changed = FALSE;
-       MonoBasicBlock *bb, *bbn;
-       guint32 niterations;
-
-       /*
-        * Some crazy loops could cause the code below to go into an infinite
-        * loop, see bug #53003 for an example. To prevent this, we put an upper
-        * bound on the number of iterations.
-        */
-       if (cfg->num_bblocks > 1000)
-               niterations = cfg->num_bblocks * 2;
-       else
-               niterations = 1000;
-       
-       do {
-               MonoBasicBlock *previous_bb;
-               changed = FALSE;
-               niterations --;
-
-               /* we skip the entry block (exit is handled specially instead ) */
-               for (previous_bb = cfg->bb_entry, bb = cfg->bb_entry->next_bb; bb; previous_bb = bb, bb = bb->next_bb) {
-                       /* dont touch code inside exception clauses */
-                       if (bb->region != -1)
-                               continue;
-
-                       if (!bb->not_useless && remove_block_if_useless (cfg, bb, previous_bb)) {
-                               changed = TRUE;
-                               continue;
-                       }
-
-                       if ((bbn = bb->next_bb) && bbn->in_count == 0 && bb->region == bbn->region) {
-                               if (cfg->verbose_level > 2)
-                                       g_print ("nullify block triggered %d\n", bbn->block_num);
-
-                               bb->next_bb = bbn->next_bb;
-
-                               for (i = 0; i < bbn->out_count; i++)
-                                       replace_in_block (bbn->out_bb [i], bbn, NULL);
-
-                               nullify_basic_block (bbn);                      
-                               changed = TRUE;
-                       }
-
-                       if (bb->out_count == 1) {
-                               bbn = bb->out_bb [0];
-
-                               /* conditional branches where true and false targets are the same can be also replaced with OP_BR */
-                               if (bb->last_ins && (bb->last_ins->opcode != OP_BR) && MONO_IS_COND_BRANCH_OP (bb->last_ins)) {
-                                       if (!cfg->new_ir) {
-                                               MonoInst *pop;
-                                               MONO_INST_NEW (cfg, pop, CEE_POP);
-                                               pop->inst_left = bb->last_ins->inst_left->inst_left;
-                                               mono_add_ins_to_end (bb, pop);
-                                               MONO_INST_NEW (cfg, pop, CEE_POP);
-                                               pop->inst_left = bb->last_ins->inst_left->inst_right;
-                                               mono_add_ins_to_end (bb, pop);
-                                       }
-                                       bb->last_ins->opcode = OP_BR;
-                                       bb->last_ins->inst_target_bb = bb->last_ins->inst_true_bb;
-                                       changed = TRUE;
-                                       if (cfg->verbose_level > 2)
-                                               g_print ("cond branch removal triggered in %d %d\n", bb->block_num, bb->out_count);
-                               }
-
-                               if (bb->region == bbn->region && bb->next_bb == bbn) {
-                                       /* the block are in sequence anyway ... */
-
-                                       /* branches to the following block can be removed */
-                                       if (bb->last_ins && bb->last_ins->opcode == OP_BR) {
-                                               bb->last_ins->opcode = OP_NOP;
-                                               changed = TRUE;
-                                               if (cfg->verbose_level > 2)
-                                                       g_print ("br removal triggered %d -> %d\n", bb->block_num, bbn->block_num);
-                                       }
-
-                                       if (bbn->in_count == 1 && !bb->extended) {
-                                               if (bbn != cfg->bb_exit) {
-                                                       if (cfg->verbose_level > 2)
-                                                               g_print ("block merge triggered %d -> %d\n", bb->block_num, bbn->block_num);
-                                                       mono_merge_basic_blocks (cfg, bb, bbn);
-                                                       changed = TRUE;
-                                                       continue;
-                                               }
-
-                                               //mono_print_bb_code (bb);
-                                       }
-                               }
-                       }
-
-                       if ((bbn = bb->next_bb) && bbn->in_count == 0 && bb->region == bbn->region) {
-                               if (cfg->verbose_level > 2) {
-                                       g_print ("nullify block triggered %d\n", bbn->block_num);
-                               }
-                               bb->next_bb = bbn->next_bb;
-
-                               for (i = 0; i < bbn->out_count; i++)
-                                       replace_in_block (bbn->out_bb [i], bbn, NULL);
-
-                               nullify_basic_block (bbn);                      
-                               changed = TRUE;
-                               continue;
-                       }
-
-                       if (bb->out_count == 1) {
-                               bbn = bb->out_bb [0];
-
-                               if (bb->last_ins && bb->last_ins->opcode == OP_BR) {
-                                       bbn = bb->last_ins->inst_target_bb;
-                                       if (bb->region == bbn->region && bbn->code && bbn->code->opcode == OP_BR &&
-                                           bbn->code->inst_target_bb->region == bb->region) {
-                                               
-                                               if (cfg->verbose_level > 2)
-                                                       g_print ("branch to branch triggered %d -> %d -> %d\n", bb->block_num, bbn->block_num, bbn->code->inst_target_bb->block_num);
-
-                                               replace_in_block (bbn, bb, NULL);
-                                               replace_out_block (bb, bbn, bbn->code->inst_target_bb);
-                                               link_bblock (cfg, bb, bbn->code->inst_target_bb);
-                                               bb->last_ins->inst_target_bb = bbn->code->inst_target_bb;
-                                               changed = TRUE;
-                                               continue;
-                                       }
-                               }
-                       } else if (bb->out_count == 2) {
-                               if (bb->last_ins && MONO_IS_COND_BRANCH_NOFP (bb->last_ins)) {
-                                       int branch_result;
-                                       MonoBasicBlock *taken_branch_target = NULL, *untaken_branch_target = NULL;
-
-                                       if (cfg->new_ir) {
-                                               if (bb->last_ins->flags & MONO_INST_CFOLD_TAKEN)
-                                                       branch_result = BRANCH_TAKEN;
-                                               else if (bb->last_ins->flags & MONO_INST_CFOLD_NOT_TAKEN)
-                                                       branch_result = BRANCH_NOT_TAKEN;
-                                               else
-                                                       branch_result = BRANCH_UNDEF;
-                                       }
-                                       else
-                                               branch_result = mono_eval_cond_branch (bb->last_ins);
-
-                                       if (branch_result == BRANCH_TAKEN) {
-                                               taken_branch_target = bb->last_ins->inst_true_bb;
-                                               untaken_branch_target = bb->last_ins->inst_false_bb;
-                                       } else if (branch_result == BRANCH_NOT_TAKEN) {
-                                               taken_branch_target = bb->last_ins->inst_false_bb;
-                                               untaken_branch_target = bb->last_ins->inst_true_bb;
-                                       }
-                                       if (taken_branch_target) {
-                                               /* if mono_eval_cond_branch () is ever taken to handle 
-                                                * non-constant values to compare, issue a pop here.
-                                                */
-                                               bb->last_ins->opcode = OP_BR;
-                                               bb->last_ins->inst_target_bb = taken_branch_target;
-                                               if (!bb->extended)
-                                                       mono_unlink_bblock (cfg, bb, untaken_branch_target);
-                                               changed = TRUE;
-                                               continue;
-                                       }
-                                       bbn = bb->last_ins->inst_true_bb;
-                                       if (bb->region == bbn->region && bbn->code && bbn->code->opcode == OP_BR &&
-                                           bbn->code->inst_target_bb->region == bb->region) {
-                                               if (cfg->verbose_level > 2)             
-                                                       g_print ("cbranch1 to branch triggered %d -> (%d) %d (0x%02x)\n", 
-                                                                bb->block_num, bbn->block_num, bbn->code->inst_target_bb->block_num, 
-                                                                bbn->code->opcode);
-
-                                               /* 
-                                                * Unlink, then relink bblocks to avoid various
-                                                * tricky situations when the two targets of the branch
-                                                * are equal, or will become equal after the change.
-                                                */
-                                               mono_unlink_bblock (cfg, bb, bb->last_ins->inst_true_bb);
-                                               mono_unlink_bblock (cfg, bb, bb->last_ins->inst_false_bb);
-
-                                               bb->last_ins->inst_true_bb = bbn->code->inst_target_bb;
-
-                                               link_bblock (cfg, bb, bb->last_ins->inst_true_bb);
-                                               link_bblock (cfg, bb, bb->last_ins->inst_false_bb);
-
-                                               changed = TRUE;
-                                               continue;
-                                       }
-
-                                       bbn = bb->last_ins->inst_false_bb;
-                                       if (bbn && bb->region == bbn->region && bbn->code && bbn->code->opcode == OP_BR &&
-                                           bbn->code->inst_target_bb->region == bb->region) {
-                                               if (cfg->verbose_level > 2)
-                                                       g_print ("cbranch2 to branch triggered %d -> (%d) %d (0x%02x)\n", 
-                                                                bb->block_num, bbn->block_num, bbn->code->inst_target_bb->block_num, 
-                                                                bbn->code->opcode);
-
-                                               mono_unlink_bblock (cfg, bb, bb->last_ins->inst_true_bb);
-                                               mono_unlink_bblock (cfg, bb, bb->last_ins->inst_false_bb);
-
-                                               bb->last_ins->inst_false_bb = bbn->code->inst_target_bb;
-
-                                               link_bblock (cfg, bb, bb->last_ins->inst_true_bb);
-                                               link_bblock (cfg, bb, bb->last_ins->inst_false_bb);
-
-                                               changed = TRUE;
-                                               continue;
-                                       }
-
-                                       bbn = bb->last_ins->inst_false_bb;
-                                       /*
-                                        * If bb is an extended bb, it could contain an inside branch to bbn.
-                                        * FIXME: Enable the optimization if that is not true.
-                                        * If bblocks_linked () is true, then merging bb and bbn
-                                        * would require addition of an extra branch at the end of bbn 
-                                        * slowing down loops.
-                                        */
-                                       if (cfg->new_ir && bbn && bb->region == bbn->region && bbn->in_count == 1 && cfg->enable_extended_bblocks && bbn != cfg->bb_exit && !bb->extended && !bbn->out_of_line && !mono_bblocks_linked (bbn, bb)) {
-                                               g_assert (bbn->in_bb [0] == bb);
-                                               if (cfg->verbose_level > 2)
-                                                       g_print ("merge false branch target triggered BB%d -> BB%d\n", bb->block_num, bbn->block_num);
-                                               mono_merge_basic_blocks (cfg, bb, bbn);
-                                               changed = TRUE;
-                                               continue;
-                                       }
-                               }
-
-                               /* detect and optimize to unsigned compares checks like: if (v < 0 || v > limit */
-                               if (bb->last_ins && bb->last_ins->opcode == CEE_BLT && !cfg->new_ir && bb->last_ins->inst_left->inst_right->opcode == OP_ICONST) {
-                                       if (try_unsigned_compare (cfg, bb)) {
-                                               /*g_print ("applied in bb %d (->%d) %s\n", bb->block_num, bb->last_ins->inst_target_bb->block_num, mono_method_full_name (cfg->method, TRUE));*/
-                                               changed = TRUE;
-                                               continue;
-                                       }
-                               }
-
-                               if (bb->last_ins && MONO_IS_COND_BRANCH_NOFP (bb->last_ins)) {
-                                       if (bb->last_ins->inst_false_bb && bb->last_ins->inst_false_bb->out_of_line && (bb->region == bb->last_ins->inst_false_bb->region)) {
-                                               /* Reverse the branch */
-                                               bb->last_ins->opcode = reverse_branch_op (bb->last_ins->opcode);
-                                               bbn = bb->last_ins->inst_false_bb;
-                                               bb->last_ins->inst_false_bb = bb->last_ins->inst_true_bb;
-                                               bb->last_ins->inst_true_bb = bbn;
-
-                                               move_basic_block_to_end (cfg, bb->last_ins->inst_true_bb);
-                                               if (cfg->verbose_level > 2)
-                                                       g_print ("cbranch to throw block triggered %d.\n", 
-                                                                        bb->block_num);
-                                       }
-                               }
-                       }
-               }
-       } while (changed && (niterations > 0));
-}
-
-static void
-mono_compile_create_vars (MonoCompile *cfg)
-{
-       MonoMethodSignature *sig;
-       MonoMethodHeader *header;
-       int i;
-
-       header = mono_method_get_header (cfg->method);
-
-       sig = mono_method_signature (cfg->method);
-       
-       if (!MONO_TYPE_IS_VOID (sig->ret)) {
-               if (cfg->new_ir) {
-                       cfg->ret = mono_compile_create_var (cfg, sig->ret, OP_ARG);
-                       /* Inhibit optimizations */
-                       cfg->ret->flags |= MONO_INST_VOLATILE;
-               } else {
-                       cfg->ret = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst));
-                       cfg->ret->opcode = OP_RETARG;
-                       cfg->ret->inst_vtype = sig->ret;
-                       cfg->ret->klass = mono_class_from_mono_type (sig->ret);
-               }
-       }
-       if (cfg->verbose_level > 2)
-               g_print ("creating vars\n");
-
-       cfg->args = mono_mempool_alloc0 (cfg->mempool, (sig->param_count + sig->hasthis) * sizeof (MonoInst*));
-
-       if (sig->hasthis)
-               cfg->args [0] = mono_compile_create_var (cfg, &cfg->method->klass->this_arg, OP_ARG);
-
-       for (i = 0; i < sig->param_count; ++i) {
-               cfg->args [i + sig->hasthis] = mono_compile_create_var (cfg, sig->params [i], OP_ARG);
-               if (sig->params [i]->byref) {
-                       if (!cfg->new_ir) cfg->disable_ssa = TRUE;
-               }
-       }
-
-       if (cfg->new_ir && cfg->verbose_level > 2) {
-               if (cfg->ret) {
-                       printf ("\treturn : ");
-                       mono_print_ins (cfg->ret);
-               }
-
-               if (sig->hasthis) {
-                       printf ("\tthis: ");
-                       mono_print_ins (cfg->args [0]);
-               }
-
-               for (i = 0; i < sig->param_count; ++i) {
-                       printf ("\targ [%d]: ", i);
-                       mono_print_ins (cfg->args [i + sig->hasthis]);
-               }
-       }
-
-       cfg->locals_start = cfg->num_varinfo;
-       cfg->locals = mono_mempool_alloc0 (cfg->mempool, header->num_locals * sizeof (MonoInst*));
+       cfg->locals_start = cfg->num_varinfo;
+       cfg->locals = mono_mempool_alloc0 (cfg->mempool, header->num_locals * sizeof (MonoInst*));
 
        if (cfg->verbose_level > 2)
                g_print ("creating locals\n");
@@ -12363,6 +11699,8 @@ mono_print_code (MonoCompile *cfg, const char* msg)
        }
 }
 
+#ifndef DISABLE_JIT
+
 extern const char * const mono_burg_rule_string [];
 
 static void
@@ -12455,7 +11793,7 @@ mini_select_instructions (MonoCompile *cfg)
                                bb->last_ins->inst_true_bb = bb->last_ins->inst_false_bb;
                                bb->last_ins->inst_false_bb = tmp;
 
-                               bb->last_ins->opcode = reverse_branch_op (bb->last_ins->opcode);
+                               bb->last_ins->opcode = mono_reverse_branch_op (bb->last_ins->opcode);
                        } else {                        
                                MonoInst *ins;
 
@@ -12711,6 +12049,11 @@ mono_codegen (MonoCompile *cfg)
                switch (patch_info->type) {
                case MONO_PATCH_INFO_ABS: {
                        MonoJitICallInfo *info = mono_find_jit_icall_by_addr (patch_info->data.target);
+
+                       /*
+                        * Change patches of type MONO_PATCH_INFO_ABS into patches describing the 
+                        * absolute address.
+                        */
                        if (info) {
                                //printf ("TEST %s %p\n", info->name, patch_info->data.target);
                                // FIXME: CLEAN UP THIS MESS.
@@ -12736,19 +12079,33 @@ mono_codegen (MonoCompile *cfg)
                                        }
                                }
                        }
-                       else {
+                       
+                       if (patch_info->type == MONO_PATCH_INFO_ABS && !cfg->new_ir) {
                                MonoVTable *vtable = mono_find_class_init_trampoline_by_addr (patch_info->data.target);
                                if (vtable) {
                                        patch_info->type = MONO_PATCH_INFO_CLASS_INIT;
                                        patch_info->data.klass = vtable->klass;
-                               } else {
-                                       MonoClass *klass = mono_find_delegate_trampoline_by_addr (patch_info->data.target);
-                                       if (klass) {
-                                               patch_info->type = MONO_PATCH_INFO_DELEGATE_TRAMPOLINE;
-                                               patch_info->data.klass = klass;
+                               }
+                       }
+
+                       if (patch_info->type == MONO_PATCH_INFO_ABS) {
+                               MonoClass *klass = mono_find_delegate_trampoline_by_addr (patch_info->data.target);
+                               if (klass) {
+                                       patch_info->type = MONO_PATCH_INFO_DELEGATE_TRAMPOLINE;
+                                       patch_info->data.klass = klass;
+                               }
+                       }
+
+                       if (patch_info->type == MONO_PATCH_INFO_ABS) {
+                               if (cfg->abs_patches) {
+                                       MonoJumpInfo *abs_ji = g_hash_table_lookup (cfg->abs_patches, patch_info->data.target);
+                                       if (abs_ji) {
+                                               patch_info->type = abs_ji->type;
+                                               patch_info->data.target = abs_ji->data.target;
                                        }
                                }
                        }
+
                        break;
                }
                case MONO_PATCH_INFO_SWITCH: {
@@ -12782,11 +12139,11 @@ mono_codegen (MonoCompile *cfg)
                        unsigned char *ip = cfg->native_code + patch_info->ip.i;
 
                        mono_domain_lock (domain);
-                       if (!domain->jump_target_hash)
-                               domain->jump_target_hash = g_hash_table_new (NULL, NULL);
-                       list = g_hash_table_lookup (domain->jump_target_hash, patch_info->data.method);
+                       if (!domain_jit_info (domain)->jump_target_hash)
+                               domain_jit_info (domain)->jump_target_hash = g_hash_table_new (NULL, NULL);
+                       list = g_hash_table_lookup (domain_jit_info (domain)->jump_target_hash, patch_info->data.method);
                        list = g_slist_prepend (list, ip);
-                       g_hash_table_insert (domain->jump_target_hash, patch_info->data.method, list);
+                       g_hash_table_insert (domain_jit_info (domain)->jump_target_hash, patch_info->data.method, list);
                        mono_domain_unlock (domain);
                        break;
                }
@@ -12846,135 +12203,6 @@ if (valgrind_register){
 #endif
 }
 
-void
-mono_remove_critical_edges (MonoCompile *cfg)
-{
-       MonoBasicBlock *bb;
-       MonoBasicBlock *previous_bb;
-       
-       if (cfg->verbose_level > 3) {
-               for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
-                       int i;
-                       printf ("remove_critical_edges, BEFORE BB%d (in:", bb->block_num);
-                       for (i = 0; i < bb->in_count; i++) {
-                               printf (" %d", bb->in_bb [i]->block_num);
-                       }
-                       printf (") (out:");
-                       for (i = 0; i < bb->out_count; i++) {
-                               printf (" %d", bb->out_bb [i]->block_num);
-                       }
-                       printf (")");
-                       if (bb->last_ins != NULL) {
-                               printf (" ");
-                               mono_print_tree (bb->last_ins);
-                       }
-                       printf ("\n");
-               }
-       }
-       
-       for (previous_bb = cfg->bb_entry, bb = previous_bb->next_bb; bb != NULL; previous_bb = previous_bb->next_bb, bb = bb->next_bb) {
-               if (bb->in_count > 1) {
-                       int in_bb_index;
-                       for (in_bb_index = 0; in_bb_index < bb->in_count; in_bb_index++) {
-                               MonoBasicBlock *in_bb = bb->in_bb [in_bb_index];
-                               if (in_bb->out_count > 1) {
-                                       MonoBasicBlock *new_bb = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
-                                       new_bb->block_num = cfg->num_bblocks++;
-//                                     new_bb->real_offset = bb->real_offset;
-                                       new_bb->region = bb->region;
-                                       
-                                       /* Do not alter the CFG while altering the BB list */
-                                       if (previous_bb->region == bb->region) {
-                                               if (previous_bb != cfg->bb_entry) {
-                                                       /* If previous_bb "followed through" to bb, */
-                                                       /* keep it linked with a OP_BR */
-                                                       if ((previous_bb->last_ins == NULL) ||
-                                                                       ((previous_bb->last_ins->opcode != OP_BR) &&
-                                                                       (! (MONO_IS_COND_BRANCH_OP (previous_bb->last_ins))) &&
-                                                                       (previous_bb->last_ins->opcode != OP_SWITCH))) {
-                                                               int i;
-                                                               /* Make sure previous_bb really falls through bb */
-                                                               for (i = 0; i < previous_bb->out_count; i++) {
-                                                                       if (previous_bb->out_bb [i] == bb) {
-                                                                               MonoInst *jump;
-                                                                               MONO_INST_NEW (cfg, jump, OP_BR);
-                                                                               MONO_ADD_INS (previous_bb, jump);
-                                                                               jump->cil_code = previous_bb->cil_code;
-                                                                               jump->inst_target_bb = bb;
-                                                                               break;
-                                                                       }
-                                                               }
-                                                       }
-                                               } else {
-                                                       /* We cannot add any inst to the entry BB, so we must */
-                                                       /* put a new BB in the middle to hold the OP_BR */
-                                                       MonoInst *jump;
-                                                       MonoBasicBlock *new_bb_after_entry = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
-                                                       new_bb_after_entry->block_num = cfg->num_bblocks++;
-//                                                     new_bb_after_entry->real_offset = bb->real_offset;
-                                                       new_bb_after_entry->region = bb->region;
-                                                       
-                                                       MONO_INST_NEW (cfg, jump, OP_BR);
-                                                       MONO_ADD_INS (new_bb_after_entry, jump);
-                                                       jump->cil_code = bb->cil_code;
-                                                       jump->inst_target_bb = bb;
-                                                       
-                                                       previous_bb->next_bb = new_bb_after_entry;
-                                                       previous_bb = new_bb_after_entry;
-                                                       
-                                                       if (cfg->verbose_level > 2) {
-                                                               printf ("remove_critical_edges, added helper BB%d jumping to BB%d\n", new_bb_after_entry->block_num, bb->block_num);
-                                                       }
-                                               }
-                                       }
-                                       
-                                       /* Insert new_bb in the BB list */
-                                       previous_bb->next_bb = new_bb;
-                                       new_bb->next_bb = bb;
-                                       previous_bb = new_bb;
-                                       
-                                       /* Setup in_bb and out_bb */
-                                       new_bb->in_bb = mono_mempool_alloc ((cfg)->mempool, sizeof (MonoBasicBlock*));
-                                       new_bb->in_bb [0] = in_bb;
-                                       new_bb->in_count = 1;
-                                       new_bb->out_bb = mono_mempool_alloc ((cfg)->mempool, sizeof (MonoBasicBlock*));
-                                       new_bb->out_bb [0] = bb;
-                                       new_bb->out_count = 1;
-                                       
-                                       /* Relink in_bb and bb to (from) new_bb */
-                                       replace_out_block (in_bb, bb, new_bb);
-                                       replace_out_block_in_code (in_bb, bb, new_bb);
-                                       replace_in_block (bb, in_bb, new_bb);
-                                       
-                                       if (cfg->verbose_level > 2) {
-                                               printf ("remove_critical_edges, removed critical edge from BB%d to BB%d (added BB%d)\n", in_bb->block_num, bb->block_num, new_bb->block_num);
-                                       }
-                               }
-                       }
-               }
-       }
-       
-       if (cfg->verbose_level > 3) {
-               for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
-                       int i;
-                       printf ("remove_critical_edges, AFTER BB%d (in:", bb->block_num);
-                       for (i = 0; i < bb->in_count; i++) {
-                               printf (" %d", bb->in_bb [i]->block_num);
-                       }
-                       printf (") (out:");
-                       for (i = 0; i < bb->out_count; i++) {
-                               printf (" %d", bb->out_bb [i]->block_num);
-                       }
-                       printf (")");
-                       if (bb->last_ins != NULL) {
-                               printf (" ");
-                               mono_print_tree (bb->last_ins);
-                       }
-                       printf ("\n");
-               }
-       }
-}
-
 static MonoGenericInst*
 get_object_generic_inst (int type_argc)
 {
@@ -13095,6 +12323,9 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
                 * for this in the debugger. */
                cfg->disable_omit_fp = TRUE;
 
+               /* The debugger needs all locals to be on the stack or in a global register */
+               cfg->disable_vreg_to_lvreg = TRUE;
+
                // cfg->opt |= MONO_OPT_SHARED;
                cfg->opt &= ~MONO_OPT_INLINE;
                cfg->opt &= ~MONO_OPT_COPYPROP;
@@ -13299,13 +12530,14 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
                         * FIXME: Can't use the second case in methods with clauses, since the 
                         * bblocks inside the clauses are not processed during dfn computation.
                         */
-                       if ((header->clauses && (bbn && bbn->region == -1 && bbn->in_count == 0)) ||
-                               (!header->clauses && (bbn && bbn->region == -1 && !bbn->dfn))) {
+                       if (((header->clauses && (bbn && bbn->region == -1 && bbn->in_count == 0)) ||
+                                (!header->clauses && (bbn && bbn->region == -1 && !bbn->dfn))) &&
+                               bbn != cfg->bb_exit) {
                                if (cfg->verbose_level > 1)
                                        g_print ("found unreachable code in BB%d\n", bbn->block_num);
                                /* There may exist unreachable branches to this bb */
                                bb->next_bb = bbn->next_bb;
-                               nullify_basic_block (bbn);                      
+                               mono_nullify_basic_block (bbn);                 
                        } else {
                                bb = bb->next_bb;
                        }
@@ -13576,7 +12808,7 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
                                        bb->last_ins->inst_true_bb = bb->last_ins->inst_false_bb;
                                        bb->last_ins->inst_false_bb = tmp;
 
-                                       bb->last_ins->opcode = reverse_branch_op (bb->last_ins->opcode);
+                                       bb->last_ins->opcode = mono_reverse_branch_op (bb->last_ins->opcode);
                                } else {                        
                                        MonoInst *inst = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst));
                                        inst->opcode = OP_BR;
@@ -13624,7 +12856,7 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
        } else {
                /* we access cfg->domain->mp */
                mono_domain_lock (cfg->domain);
-               jinfo = mono_mempool_alloc0 (cfg->domain->mp, sizeof (MonoJitInfo) +
+               jinfo = mono_domain_alloc0 (cfg->domain, sizeof (MonoJitInfo) +
                                (header->num_clauses * sizeof (MonoJitExceptionInfo)) +
                                generic_info_size);
                mono_domain_unlock (cfg->domain);
@@ -13684,11 +12916,13 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
                 */
                if (cfg->rgctx_var ||
                                (!(method_to_compile->flags & METHOD_ATTRIBUTE_STATIC) &&
-                               !mini_method_get_context (method_to_compile)->method_inst)) {
+                               !mini_method_get_context (method_to_compile)->method_inst &&
+                               !method_to_compile->klass->valuetype)) {
                        gi->has_this = 1;
 
                        if ((method_to_compile->flags & METHOD_ATTRIBUTE_STATIC) ||
-                                       mini_method_get_context (method_to_compile)->method_inst) {
+                                       mini_method_get_context (method_to_compile)->method_inst ||
+                                       method_to_compile->klass->valuetype) {
                                inst = cfg->rgctx_var;
                                g_assert (inst->opcode == OP_REGOFFSET);
                        } else {
@@ -13796,6 +13030,17 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
        return cfg;
 }
 
+#else
+
+MonoCompile*
+mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gboolean run_cctors, gboolean compile_aot, int parts)
+{
+       g_assert_not_reached ();
+       return NULL;
+}
+
+#endif /* DISABLE_JIT */
+
 static MonoJitInfo*
 lookup_generic_method (MonoDomain *domain, MonoMethod *method)
 {
@@ -13892,7 +13137,17 @@ mono_jit_compile_method_inner (MonoMethod *method, MonoDomain *target_domain, in
                        if (*name == '.' && (strcmp (name, ".ctor") == 0)) {
                                MonoJitICallInfo *mi = mono_find_jit_icall_by_name ("mono_delegate_ctor");
                                g_assert (mi);
-                               return mono_get_addr_from_ftnptr ((gpointer)mono_icall_get_wrapper (mi));
+                               /*
+                                * We need to make sure this wrapper
+                                * is compiled because it might end up
+                                * in an (M)RGCTX if generic sharing
+                                * is enabled, and would be called
+                                * indirectly.  If it were a
+                                * trampoline we'd try to patch that
+                                * indirect call, which is not
+                                * possible.
+                                */
+                               return mono_get_addr_from_ftnptr ((gpointer)mono_icall_get_wrapper_full (mi, TRUE));
                        } else if (*name == 'I' && (strcmp (name, "Invoke") == 0)) {
 #ifdef MONO_ARCH_HAVE_CREATE_DELEGATE_TRAMPOLINE
                                return mono_create_delegate_trampoline (method->klass);
@@ -14035,16 +13290,16 @@ mono_jit_compile_method_inner (MonoMethod *method, MonoDomain *target_domain, in
 
        mono_destroy_compile (cfg);
 
-       if (target_domain->jump_target_hash) {
+       if (domain_jit_info (target_domain)->jump_target_hash) {
                MonoJumpInfo patch_info;
                GSList *list, *tmp;
-               list = g_hash_table_lookup (target_domain->jump_target_hash, method);
+               list = g_hash_table_lookup (domain_jit_info (target_domain)->jump_target_hash, method);
                if (list) {
                        patch_info.next = NULL;
                        patch_info.ip.i = 0;
                        patch_info.type = MONO_PATCH_INFO_METHOD_JUMP;
                        patch_info.data.method = method;
-                       g_hash_table_remove (target_domain->jump_target_hash, method);
+                       g_hash_table_remove (domain_jit_info (target_domain)->jump_target_hash, method);
                }
                for (tmp = list; tmp; tmp = tmp->next)
                        mono_arch_patch_code (NULL, target_domain, tmp->data, &patch_info, TRUE);
@@ -14157,9 +13412,9 @@ mono_jit_free_method (MonoDomain *domain, MonoMethod *method)
        if (!ji)
                return;
        mono_domain_lock (domain);
-       g_hash_table_remove (domain->dynamic_code_hash, method);
+       g_hash_table_remove (domain_jit_info (domain)->dynamic_code_hash, method);
        mono_internal_hash_table_remove (&domain->jit_code_hash, method);
-       g_hash_table_remove (domain->jump_trampoline_hash, method);
+       g_hash_table_remove (domain_jit_info (domain)->jump_trampoline_hash, method);
        mono_domain_unlock (domain);
 
 #ifdef MONO_ARCH_HAVE_INVALIDATE_METHOD
@@ -14233,14 +13488,10 @@ mono_jit_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObjec
                return NULL;
        }
 
-       if (((method->flags & METHOD_ATTRIBUTE_STATIC) ||
-                               (method->is_inflated && mono_method_get_context (method)->method_inst)) &&
-                       mono_class_generic_sharing_enabled (method->klass) &&
-                       mono_method_is_generic_sharable_impl (method, FALSE)) {
+       if (mono_method_needs_static_rgctx_invoke (method, FALSE))
                to_compile = mono_marshal_get_static_rgctx_invoke (method);
-       } else {
+       else
                to_compile = method;
-       }
 
        invoke = mono_marshal_get_runtime_invoke (method);
        runtime_invoke = mono_jit_compile_method (invoke);
@@ -14359,30 +13610,9 @@ SIG_HANDLER_SIGNATURE (sigsegv_signal_handler)
        ji = mono_jit_info_table_find (mono_domain_get (), mono_arch_ip_from_context (ctx));
 
 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
-       /* we got a stack overflow in the soft-guard pages
-        * There are two cases:
-        * 1) managed code caused the overflow: we unprotect the soft-guard page
-        * and let the arch-specific code trigger the exception handling mechanism
-        * in the thread stack. The soft-guard pages will be protected again as the stack is unwound.
-        * 2) unmanaged code caused the overflow: we unprotect the soft-guard page
-        * and hope we can continue with those enabled, at least until the hard-guard page
-        * is hit. The alternative to continuing here is to just print a message and abort.
-        * We may add in the future the code to protect the pages again in the codepath
-        * when we return from unmanaged to managed code.
-        */
-       if (jit_tls->stack_ovf_guard_size && (guint8*)info->si_addr >= (guint8*)jit_tls->stack_ovf_guard_base &&
-                       (guint8*)info->si_addr < (guint8*)jit_tls->stack_ovf_guard_base + jit_tls->stack_ovf_guard_size) {
-               mono_mprotect (jit_tls->stack_ovf_guard_base, jit_tls->stack_ovf_guard_size, MONO_MMAP_READ|MONO_MMAP_WRITE|MONO_MMAP_EXEC);
-               if (ji) {
-                       mono_arch_handle_altstack_exception (ctx, info->si_addr, TRUE);
-               } else {
-                       /* We print a message: after this even managed stack overflows
-                        * may crash the runtime
-                        */
-                       fprintf (stderr, "Stack overflow in unmanaged: IP: %p, fault addr: %p\n", mono_arch_ip_from_context (ctx), (gpointer)info->si_addr);
-               }
+       if (mono_handle_soft_stack_ovf (jit_tls, ji, ctx, (guint8*)info->si_addr))
                return;
-       }
+
        /* The hard-guard page has been hit: there is not much we can do anymore
         * Print a hopefully clear message and abort.
         */
@@ -14396,7 +13626,7 @@ SIG_HANDLER_SIGNATURE (sigsegv_signal_handler)
                else
                        method = "Unmanaged";
                fprintf (stderr, "At %s\n", method);
-               abort ();
+               _exit (1);
        } else {
                mono_arch_handle_altstack_exception (ctx, info->si_addr, FALSE);
        }
@@ -14549,8 +13779,15 @@ SIG_HANDLER_SIGNATURE (sigprof_signal_handler)
 static void
 SIG_HANDLER_SIGNATURE (sigquit_signal_handler)
 {
+       gboolean res;
+
        GET_CONTEXT;
 
+       /* We use this signal to start the attach agent too */
+       res = mono_attach_start ();
+       if (res)
+               return;
+
        printf ("Full thread dump:\n");
 
        mono_threads_request_thread_dump ();
@@ -14755,7 +13992,7 @@ mono_runtime_install_handlers (void)
 #else /* !PLATFORM_WIN32 */
 
 
-#ifdef PLATFORM_MACOSX
+#if defined(PLATFORM_MACOSX) && !defined(__arm__)
        macosx_register_exception_handler ();
 #endif
 
@@ -15020,6 +14257,11 @@ mini_create_jit_domain_info (MonoDomain *domain)
 {
        MonoJitDomainInfo *info = g_new0 (MonoJitDomainInfo, 1);
 
+       info->class_init_trampoline_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
+       info->jump_trampoline_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
+       info->jit_trampoline_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
+       info->delegate_trampoline_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
+
        domain->runtime_info = info;
 }
 
@@ -15029,16 +14271,40 @@ delete_jump_list (gpointer key, gpointer value, gpointer user_data)
        g_slist_free (value);
 }
 
+static void
+dynamic_method_info_free (gpointer key, gpointer value, gpointer user_data)
+{
+       MonoJitDynamicMethodInfo *di = value;
+       mono_code_manager_destroy (di->code_mp);
+       g_free (di);
+}
+
 static void
 mini_free_jit_domain_info (MonoDomain *domain)
 {
-       MonoJitDomainInfo *info = jit_domain_info (domain);
+       MonoJitDomainInfo *info = domain_jit_info (domain);
 
+       if (info->jump_target_hash) {
+               g_hash_table_foreach (info->jump_target_hash, delete_jump_list, NULL);
+               g_hash_table_destroy (info->jump_target_hash);
+       }
        if (info->jump_target_got_slot_hash) {
                g_hash_table_foreach (info->jump_target_got_slot_hash, delete_jump_list, NULL);
                g_hash_table_destroy (info->jump_target_got_slot_hash);
        }
+       if (info->dynamic_code_hash) {
+               g_hash_table_foreach (info->dynamic_code_hash, dynamic_method_info_free, NULL);
+               g_hash_table_destroy (info->dynamic_code_hash);
+       }
+       if (info->method_code_hash)
+               g_hash_table_destroy (info->method_code_hash);
+       g_hash_table_destroy (info->class_init_trampoline_hash);
+       g_hash_table_destroy (info->jump_trampoline_hash);
+       g_hash_table_destroy (info->jit_trampoline_hash);
+       g_hash_table_destroy (info->delegate_trampoline_hash);
+
        g_free (domain->runtime_info);
+       domain->runtime_info = NULL;
 }
 
 MonoDomain *
@@ -15082,7 +14348,9 @@ mini_init (const char *filename, const char *runtime_version)
        mono_jit_tls_id = TlsAlloc ();
        setup_jit_tls_data ((gpointer)-1, mono_thread_abort);
 
+#ifndef DISABLE_JIT
        mono_burg_init ();
+#endif
 
        if (default_opt & MONO_OPT_AOT)
                mono_aot_init ();
@@ -15323,7 +14591,6 @@ mini_init (const char *filename, const char *runtime_version)
        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 (mono_ldftn, "mono_ldftn", "ptr ptr", FALSE);
-       register_icall (mono_ldftn_nosync, "mono_ldftn_nosync", "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);
        register_icall (mono_helper_compile_generic_method, "compile_generic_method", "ptr object ptr ptr", FALSE);
@@ -15340,16 +14607,22 @@ mini_init (const char *filename, const char *runtime_version)
        register_icall (mono_array_new_2, "mono_array_new_2", "object ptr int int", FALSE);
 #endif
 
+       mono_generic_sharing_init ();
+
+       if (mono_compile_aot)
+               /* 
+                * Avoid running managed code when AOT compiling, since the platform
+                * might only support aot-only execution.
+                */
+               mono_runtime_set_no_exec (TRUE);
+
 #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_thread_attach (domain);
 #endif
 
-       mono_generic_sharing_init ();
-
-       mono_thread_attach (domain);
-       
        mono_profiler_runtime_initialized ();
        
        MONO_PROBE_VES_INIT_END ();
@@ -15371,7 +14644,6 @@ print_jit_stats (void)
                g_print ("Basic blocks:           %ld\n", mono_jit_stats.basic_blocks);
                g_print ("Max basic blocks:       %ld\n", mono_jit_stats.max_basic_blocks);
                g_print ("Allocated vars:         %ld\n", mono_jit_stats.allocate_var);
-               g_print ("Analyze stack repeat:   %ld\n", mono_jit_stats.analyze_stack_repeat);
                g_print ("Compiled CIL code size: %ld\n", mono_jit_stats.cil_code_size);
                g_print ("Native code size:       %ld\n", mono_jit_stats.native_code_size);
                g_print ("Max code size ratio:    %.2f (%s)\n", mono_jit_stats.max_code_size_ratio/100.0,
@@ -15484,7 +14756,8 @@ mini_cleanup (MonoDomain *domain)
 
        mono_trampolines_cleanup ();
 
-       mono_code_manager_destroy (global_codeman);
+       if (!mono_dont_free_global_codeman)
+               mono_code_manager_destroy (global_codeman);
        g_hash_table_destroy (jit_icall_name_hash);
        g_free (emul_opcode_map);