2010-02-10 Geoff Norton <gnorton@novell.com>
[mono.git] / mono / mini / method-to-ir.c
index 5ecac9d7b4d03efd527e62de86c8cbfb25312779..75ced4cf5b1f23a91b1435fae6eddf9092c276c4 100644 (file)
@@ -27,9 +27,7 @@
 #include <alloca.h>
 #endif
 
-#ifdef HAVE_VALGRIND_MEMCHECK_H
-#include <valgrind/memcheck.h>
-#endif
+#include <mono/utils/memcheck.h>
 
 #include <mono/metadata/assembly.h>
 #include <mono/metadata/loader.h>
 #include <mono/metadata/threads-types.h>
 #include <mono/metadata/security-core-clr.h>
 #include <mono/metadata/monitor.h>
+#include <mono/metadata/profiler-private.h>
+#include <mono/metadata/profiler.h>
 #include <mono/utils/mono-compiler.h>
+#include <mono/metadata/mono-basic-block.h>
 
 #include "mini.h"
 #include "trace.h"
@@ -57,6 +58,8 @@
 #include "ir-emit.h"
 
 #include "jit-icalls.h"
+#include "jit.h"
+#include "debugger-agent.h"
 
 #define BRANCH_COST 100
 #define INLINE_LENGTH_LIMIT 20
@@ -114,6 +117,7 @@ extern MonoMethodSignature *helper_sig_domain_get;
 extern MonoMethodSignature *helper_sig_generic_class_init_trampoline;
 extern MonoMethodSignature *helper_sig_rgctx_lazy_fetch_trampoline;
 extern MonoMethodSignature *helper_sig_monitor_enter_exit_trampoline;
+extern MonoMethodSignature *helper_sig_monitor_enter_exit_trampoline_llvm;
 
 /*
  * Instruction metadata
@@ -144,16 +148,18 @@ ins_info[] = {
 #undef MINI_OP
 #undef MINI_OP3
 
-#define MINI_OP(a,b,dest,src1,src2) (((src1) != NONE) + ((src2) != NONE)),
-#define MINI_OP3(a,b,dest,src1,src2,src3) (((src1) != NONE) + ((src2) != NONE) + ((src3) != NONE)),
+#define MINI_OP(a,b,dest,src1,src2) ((src2) != NONE ? 2 : ((src1) != NONE ? 1 : 0)),
+#define MINI_OP3(a,b,dest,src1,src2,src3) ((src3) != NONE ? 3 : ((src2) != NONE ? 2 : ((src1) != NONE ? 1 : 0))),
+/* 
+ * This should contain the index of the last sreg + 1. This is not the same
+ * as the number of sregs for opcodes like IA64_CMP_EQ_IMM.
+ */
 const gint8 ins_sreg_counts[] = {
 #include "mini-ops.h"
 };
 #undef MINI_OP
 #undef MINI_OP3
 
-extern GHashTable *jit_icall_name_hash;
-
 #define MONO_INIT_VARINFO(vi,id) do { \
        (vi)->range.first_use.pos.bid = 0xffff; \
        (vi)->reg = -1; \
@@ -291,7 +297,7 @@ mono_print_bb (MonoBasicBlock *bb, const char *msg)
                } \
        } while (0)
 
-#if defined(__i386__) || defined(__x86_64__)
+#if defined(TARGET_X86) || defined(TARGET_AMD64)
 #define EMIT_NEW_X86_LEA(cfg,dest,sr1,sr2,shift,imm) do { \
                MONO_INST_NEW (cfg, dest, OP_X86_LEA); \
                (dest)->dreg = alloc_preg ((cfg)); \
@@ -525,7 +531,7 @@ mono_create_spvar_for_region (MonoCompile *cfg, int region)
        g_hash_table_insert (cfg->spvars, GINT_TO_POINTER (region), var);
 }
 
-static MonoInst *
+MonoInst *
 mono_find_exvar_for_offset (MonoCompile *cfg, int offset)
 {
        return g_hash_table_lookup (cfg->exvars, GINT_TO_POINTER (offset));
@@ -1043,7 +1049,7 @@ mono_get_domainvar (MonoCompile *cfg)
  * The got_var contains the address of the Global Offset Table when AOT 
  * compiling.
  */
-inline static MonoInst *
+MonoInst *
 mono_get_got_var (MonoCompile *cfg)
 {
 #ifdef MONO_ARCH_NEED_GOT_VAR
@@ -1092,7 +1098,8 @@ type_from_stack_type (MonoInst *ins) {
 static G_GNUC_UNUSED int
 type_to_stack_type (MonoType *t)
 {
-       switch (mono_type_get_underlying_type (t)->type) {
+       t = mono_type_get_underlying_type (t);
+       switch (t->type) {
        case MONO_TYPE_I1:
        case MONO_TYPE_U1:
        case MONO_TYPE_BOOLEAN:
@@ -1478,8 +1485,8 @@ mini_emit_max_iid_check_class (MonoCompile *cfg, int klass_reg, MonoClass *klass
        mini_emit_max_iid_check (cfg, max_iid_reg, klass, false_target);
 }
 
-static void 
-mini_emit_isninst_cast (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
+static void
+mini_emit_isninst_cast_inst (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoInst *klass_ins, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
 {
        int idepth_reg = alloc_preg (cfg);
        int stypes_reg = alloc_preg (cfg);
@@ -1492,7 +1499,9 @@ mini_emit_isninst_cast (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoB
        }
        MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stypes_reg, klass_reg, G_STRUCT_OFFSET (MonoClass, supertypes));
        MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stype, stypes_reg, ((klass->idepth - 1) * SIZEOF_VOID_P));
-       if (cfg->compile_aot) {
+       if (klass_ins) {
+               MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, stype, klass_ins->dreg);
+       } else if (cfg->compile_aot) {
                int const_reg = alloc_preg (cfg);
                MONO_EMIT_NEW_CLASSCONST (cfg, const_reg, klass);
                MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, stype, const_reg);
@@ -1502,7 +1511,13 @@ mini_emit_isninst_cast (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoB
        MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, true_target);
 }
 
-static void 
+static void
+mini_emit_isninst_cast (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
+{
+       mini_emit_isninst_cast_inst (cfg, klass_reg, klass, NULL, false_target, true_target);
+}
+
+static void
 mini_emit_iface_cast (MonoCompile *cfg, int vtable_reg, MonoClass *klass, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
 {
        int intf_reg = alloc_preg (cfg);
@@ -1519,7 +1534,7 @@ mini_emit_iface_cast (MonoCompile *cfg, int vtable_reg, MonoClass *klass, MonoBa
 /*
  * Variant of the above that takes a register to the class, not the vtable.
  */
-static void 
+static void
 mini_emit_iface_class_cast (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
 {
        int intf_bit_reg = alloc_preg (cfg);
@@ -1534,9 +1549,11 @@ mini_emit_iface_class_cast (MonoCompile *cfg, int klass_reg, MonoClass *klass, M
 }
 
 static inline void
-mini_emit_class_check (MonoCompile *cfg, int klass_reg, MonoClass *klass)
+mini_emit_class_check_inst (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoInst *klass_inst)
 {
-       if (cfg->compile_aot) {
+       if (klass_inst) {
+               MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, klass_inst->dreg);
+       } else if (cfg->compile_aot) {
                int const_reg = alloc_preg (cfg);
                MONO_EMIT_NEW_CLASSCONST (cfg, const_reg, klass);
                MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, const_reg);
@@ -1546,6 +1563,12 @@ mini_emit_class_check (MonoCompile *cfg, int klass_reg, MonoClass *klass)
        MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
 }
 
+static inline void
+mini_emit_class_check (MonoCompile *cfg, int klass_reg, MonoClass *klass)
+{
+       return mini_emit_class_check_inst (cfg, klass_reg, klass, NULL);
+}
+
 static inline void
 mini_emit_class_check_branch (MonoCompile *cfg, int klass_reg, MonoClass *klass, int branch_op, MonoBasicBlock *target)
 {
@@ -1558,14 +1581,18 @@ mini_emit_class_check_branch (MonoCompile *cfg, int klass_reg, MonoClass *klass,
        }
        MONO_EMIT_NEW_BRANCH_BLOCK (cfg, branch_op, target);
 }
+
+static void
+mini_emit_castclass (MonoCompile *cfg, int obj_reg, int klass_reg, MonoClass *klass, MonoBasicBlock *object_is_null);
        
-static void 
-mini_emit_castclass (MonoCompile *cfg, int obj_reg, int klass_reg, MonoClass *klass, MonoBasicBlock *object_is_null)
+static void
+mini_emit_castclass_inst (MonoCompile *cfg, int obj_reg, int klass_reg, MonoClass *klass, MonoInst *klass_inst, MonoBasicBlock *object_is_null)
 {
        if (klass->rank) {
                int rank_reg = alloc_preg (cfg);
                int eclass_reg = alloc_preg (cfg);
 
+               g_assert (!klass_inst);
                MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, rank_reg, klass_reg, G_STRUCT_OFFSET (MonoClass, rank));
                MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rank_reg, klass->rank);
                MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
@@ -1607,10 +1634,16 @@ mini_emit_castclass (MonoCompile *cfg, int obj_reg, int klass_reg, MonoClass *kl
                }
                MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stypes_reg, klass_reg, G_STRUCT_OFFSET (MonoClass, supertypes));
                MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stype, stypes_reg, ((klass->idepth - 1) * SIZEOF_VOID_P));
-               mini_emit_class_check (cfg, stype, klass);
+               mini_emit_class_check_inst (cfg, stype, klass, klass_inst);
        }
 }
 
+static void
+mini_emit_castclass (MonoCompile *cfg, int obj_reg, int klass_reg, MonoClass *klass, MonoBasicBlock *object_is_null)
+{
+       return mini_emit_castclass_inst (cfg, obj_reg, klass_reg, klass, NULL, object_is_null);
+}
+
 static void 
 mini_emit_memset (MonoCompile *cfg, int destreg, int offset, int size, int val, int align)
 {
@@ -1699,6 +1732,9 @@ mini_emit_memcpy (MonoCompile *cfg, int destreg, int doffset, int srcreg, int so
        if (align == 0)
                align = 4;
 
+       /*FIXME arbitrary hack to avoid unbound code expansion.*/
+       g_assert (size < 10000);
+
        if (align < 4) {
                /* This could be optimized further if neccesary */
                while (size >= 1) {
@@ -2094,26 +2130,31 @@ mono_patch_info_new (MonoMemPool *mp, int ip, MonoJumpInfoType type, gconstpoint
        return ji;
 }
 
-inline static MonoInst*
-mono_emit_jit_icall (MonoCompile *cfg, gconstpointer func, MonoInst **args);
-
 inline static MonoCallInst *
 mono_emit_call_args (MonoCompile *cfg, MonoMethodSignature *sig, 
-                    MonoInst **args, int calli, int virtual)
+                                        MonoInst **args, int calli, int virtual, int tail)
 {
        MonoCallInst *call;
 #ifdef MONO_ARCH_SOFT_FLOAT
        int i;
 #endif
 
-       MONO_INST_NEW_CALL (cfg, call, ret_type_to_call_opcode (sig->ret, calli, virtual, cfg->generic_sharing_context));
+       if (tail)
+               MONO_INST_NEW_CALL (cfg, call, OP_TAILCALL);
+       else
+               MONO_INST_NEW_CALL (cfg, call, ret_type_to_call_opcode (sig->ret, calli, virtual, cfg->generic_sharing_context));
 
        call->args = args;
        call->signature = sig;
 
        type_to_eval_stack_type ((cfg), sig->ret, &call->inst);
 
-       if (MONO_TYPE_ISSTRUCT (sig->ret)) {
+       if (tail) {
+               if (MONO_TYPE_ISSTRUCT (sig->ret)) {
+                       call->vret_var = cfg->vret_addr;
+                       //g_assert_not_reached ();
+               }
+       } else if (MONO_TYPE_ISSTRUCT (sig->ret)) {
                MonoInst *temp = mono_compile_create_var (cfg, sig->ret, OP_LOCAL);
                MonoInst *loada;
 
@@ -2141,35 +2182,44 @@ mono_emit_call_args (MonoCompile *cfg, MonoMethodSignature *sig,
                call->inst.dreg = alloc_dreg (cfg, call->inst.type);
 
 #ifdef MONO_ARCH_SOFT_FLOAT
-       /* 
-        * If the call has a float argument, we would need to do an r8->r4 conversion using 
-        * an icall, but that cannot be done during the call sequence since it would clobber
-        * the call registers + the stack. So we do it before emitting the call.
-        */
-       for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
-               MonoType *t;
-               MonoInst *in = call->args [i];
+       if (COMPILE_SOFT_FLOAT (cfg)) {
+               /* 
+                * If the call has a float argument, we would need to do an r8->r4 conversion using 
+                * an icall, but that cannot be done during the call sequence since it would clobber
+                * the call registers + the stack. So we do it before emitting the call.
+                */
+               for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
+                       MonoType *t;
+                       MonoInst *in = call->args [i];
 
-               if (i >= sig->hasthis)
-                       t = sig->params [i - sig->hasthis];
-               else
-                       t = &mono_defaults.int_class->byval_arg;
-               t = mono_type_get_underlying_type (t);
+                       if (i >= sig->hasthis)
+                               t = sig->params [i - sig->hasthis];
+                       else
+                               t = &mono_defaults.int_class->byval_arg;
+                       t = mono_type_get_underlying_type (t);
 
-               if (!t->byref && t->type == MONO_TYPE_R4) {
-                       MonoInst *iargs [1];
-                       MonoInst *conv;
+                       if (!t->byref && t->type == MONO_TYPE_R4) {
+                               MonoInst *iargs [1];
+                               MonoInst *conv;
 
-                       iargs [0] = in;
-                       conv = mono_emit_jit_icall (cfg, mono_fload_r4_arg, iargs);
+                               iargs [0] = in;
+                               conv = mono_emit_jit_icall (cfg, mono_fload_r4_arg, iargs);
 
-                       /* The result will be in an int vreg */
-                       call->args [i] = conv;
+                               /* The result will be in an int vreg */
+                               call->args [i] = conv;
+                       }
                }
        }
 #endif
 
+#ifdef ENABLE_LLVM
+       if (COMPILE_LLVM (cfg))
+               mono_llvm_emit_call (cfg, call);
+       else
+               mono_arch_emit_call (cfg, call);
+#else
        mono_arch_emit_call (cfg, call);
+#endif
 
        cfg->param_area = MAX (cfg->param_area, call->stack_usage);
        cfg->flags |= MONO_CFG_HAS_CALLS;
@@ -2180,7 +2230,7 @@ mono_emit_call_args (MonoCompile *cfg, MonoMethodSignature *sig,
 inline static MonoInst*
 mono_emit_calli (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **args, MonoInst *addr)
 {
-       MonoCallInst *call = mono_emit_call_args (cfg, sig, args, TRUE, FALSE);
+       MonoCallInst *call = mono_emit_call_args (cfg, sig, args, TRUE, FALSE, FALSE);
 
        call->inst.sreg1 = addr->dreg;
 
@@ -2213,12 +2263,19 @@ mono_emit_rgctx_calli (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **ar
 #endif
 }
 
+static MonoInst*
+emit_get_rgctx_method (MonoCompile *cfg, int context_used, MonoMethod *cmethod, int rgctx_type);
+static MonoInst*
+emit_get_rgctx_klass (MonoCompile *cfg, int context_used, MonoClass *klass, int rgctx_type);
+
 static MonoInst*
 mono_emit_method_call_full (MonoCompile *cfg, MonoMethod *method, MonoMethodSignature *sig,
                                                        MonoInst **args, MonoInst *this, MonoInst *imt_arg)
 {
+       gboolean might_be_remote;
        gboolean virtual = this != NULL;
        gboolean enable_for_aot = TRUE;
+       int context_used;
        MonoCallInst *call;
 
        if (method->string_ctor) {
@@ -2230,15 +2287,27 @@ mono_emit_method_call_full (MonoCompile *cfg, MonoMethod *method, MonoMethodSign
                sig = ctor_sig;
        }
 
-       call = mono_emit_call_args (cfg, sig, args, FALSE, virtual);
+       might_be_remote = this && sig->hasthis &&
+               (method->klass->marshalbyref || method->klass == mono_defaults.object_class) &&
+               !(method->flags & METHOD_ATTRIBUTE_VIRTUAL) && !MONO_CHECK_THIS (this);
+
+       context_used = mono_method_check_context_used (method);
+       if (might_be_remote && context_used) {
+               MonoInst *addr;
+
+               g_assert (cfg->generic_sharing_context);
+
+               addr = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK);
+
+               return mono_emit_calli (cfg, sig, args, addr);
+       }
+
+       call = mono_emit_call_args (cfg, sig, args, FALSE, virtual, FALSE);
 
-       if (this && sig->hasthis && 
-           (method->klass->marshalbyref || method->klass == mono_defaults.object_class) && 
-           !(method->flags & METHOD_ATTRIBUTE_VIRTUAL) && !MONO_CHECK_THIS (this)) {
+       if (might_be_remote)
                call->method = mono_marshal_get_remoting_invoke_with_check (method);
-       } else {
+       else
                call->method = method;
-       }
        call->inst.flags |= MONO_INST_HAS_METHOD;
        call->inst.inst_left = this;
 
@@ -2249,6 +2318,8 @@ mono_emit_method_call_full (MonoCompile *cfg, MonoMethod *method, MonoMethodSign
 
 #ifdef MONO_ARCH_HAVE_CREATE_DELEGATE_TRAMPOLINE
                if ((method->klass->parent == mono_defaults.multicastdelegate_class) && (!strcmp (method->name, "Invoke"))) {
+                       MONO_EMIT_NULL_CHECK (cfg, this_reg);
+
                        /* Make a call to delegate->invoke_impl */
                        call->inst.opcode = callvirt_to_call_membase (call->inst.opcode);
                        call->inst.inst_basereg = this_reg;
@@ -2262,20 +2333,22 @@ mono_emit_method_call_full (MonoCompile *cfg, MonoMethod *method, MonoMethodSign
                if ((!cfg->compile_aot || enable_for_aot) && 
                        (!(method->flags & METHOD_ATTRIBUTE_VIRTUAL) || 
                         (MONO_METHOD_IS_FINAL (method) &&
-                         method->wrapper_type != MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK))) {
+                         method->wrapper_type != MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK)) &&
+                       !(method->klass->marshalbyref && context_used)) {
                        /* 
                         * the method is not virtual, we just need to ensure this is not null
                         * and then we can call the method directly.
                         */
                        if (method->klass->marshalbyref || method->klass == mono_defaults.object_class) {
+                               /* 
+                                * The check above ensures method is not gshared, this is needed since
+                                * gshared methods can't have wrappers.
+                                */
                                method = call->method = mono_marshal_get_remoting_invoke_with_check (method);
                        }
 
-                       if (!method->string_ctor) {
-                               cfg->flags |= MONO_CFG_HAS_CHECK_THIS;
-                               MONO_EMIT_NEW_UNALU (cfg, OP_CHECK_THIS, -1, this_reg);
-                               MONO_EMIT_NEW_UNALU (cfg, OP_NOT_NULL, -1, this_reg);
-                       }
+                       if (!method->string_ctor)
+                               MONO_EMIT_NEW_CHECK_THIS (cfg, this_reg);
 
                        call->inst.opcode = callvirt_to_call (call->inst.opcode);
 
@@ -2290,9 +2363,7 @@ mono_emit_method_call_full (MonoCompile *cfg, MonoMethod *method, MonoMethodSign
                         * it's class or the method itself are sealed.
                         * But first we need to ensure it's not a null reference.
                         */
-                       cfg->flags |= MONO_CFG_HAS_CHECK_THIS;
-                       MONO_EMIT_NEW_UNALU (cfg, OP_CHECK_THIS, -1, this_reg);
-                       MONO_EMIT_NEW_UNALU (cfg, OP_NOT_NULL, -1, this_reg);
+                       MONO_EMIT_NEW_CHECK_THIS (cfg, this_reg);
 
                        call->inst.opcode = callvirt_to_call (call->inst.opcode);
                        MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
@@ -2303,7 +2374,7 @@ mono_emit_method_call_full (MonoCompile *cfg, MonoMethod *method, MonoMethodSign
                call->inst.opcode = callvirt_to_call_membase (call->inst.opcode);
 
                vtable_reg = alloc_preg (cfg);
-               MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, this_reg, G_STRUCT_OFFSET (MonoObject, vtable));
+               MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, this_reg, G_STRUCT_OFFSET (MonoObject, vtable));
                if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
                        slot_reg = -1;
 #ifdef MONO_ARCH_HAVE_IMT
@@ -2322,7 +2393,7 @@ mono_emit_method_call_full (MonoCompile *cfg, MonoMethod *method, MonoMethodSign
                } else {
                        slot_reg = vtable_reg;
                        call->inst.inst_offset = G_STRUCT_OFFSET (MonoVTable, vtable) +
-                               (mono_method_get_vtable_index (method) * SIZEOF_VOID_P);
+                               ((mono_method_get_vtable_index (method)) * (SIZEOF_VOID_P));
 #ifdef MONO_ARCH_HAVE_IMT
                        if (imt_arg) {
                                g_assert (mono_method_signature (method)->generic_param_count);
@@ -2344,7 +2415,9 @@ static MonoInst*
 mono_emit_rgctx_method_call_full (MonoCompile *cfg, MonoMethod *method, MonoMethodSignature *sig,
                MonoInst **args, MonoInst *this, MonoInst *imt_arg, MonoInst *vtable_arg)
 {
-       int rgctx_reg;
+#ifdef MONO_ARCH_RGCTX_REG
+       int rgctx_reg = 0;
+#endif
        MonoInst *ins;
        MonoCallInst *call;
 
@@ -2372,7 +2445,7 @@ mono_emit_rgctx_method_call_full (MonoCompile *cfg, MonoMethod *method, MonoMeth
        return ins;
 }
 
-static inline MonoInst*
+MonoInst*
 mono_emit_method_call (MonoCompile *cfg, MonoMethod *method, MonoInst **args, MonoInst *this)
 {
        return mono_emit_method_call_full (cfg, method, mono_method_signature (method), args, this, NULL);
@@ -2386,7 +2459,7 @@ mono_emit_native_call (MonoCompile *cfg, gconstpointer func, MonoMethodSignature
 
        g_assert (sig);
 
-       call = mono_emit_call_args (cfg, sig, args, FALSE, FALSE);
+       call = mono_emit_call_args (cfg, sig, args, FALSE, FALSE, FALSE);
        call->fptr = func;
 
        MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
@@ -2394,7 +2467,7 @@ mono_emit_native_call (MonoCompile *cfg, gconstpointer func, MonoMethodSignature
        return (MonoInst*)call;
 }
 
-inline static MonoInst*
+MonoInst*
 mono_emit_jit_icall (MonoCompile *cfg, gconstpointer func, MonoInst **args)
 {
        MonoJitICallInfo *info = mono_find_jit_icall_by_addr (func);
@@ -2511,9 +2584,23 @@ mini_emit_stobj (MonoCompile *cfg, MonoInst *dest, MonoInst *src, MonoClass *kla
                /* Avoid barriers when storing to the stack */
                if (!((dest->opcode == OP_ADD_IMM && dest->sreg1 == cfg->frame_reg) ||
                          (dest->opcode == OP_LDADDR))) {
+                       int context_used = 0;
+
                        iargs [0] = dest;
                        iargs [1] = src;
-                       EMIT_NEW_PCONST (cfg, iargs [2], klass);
+
+                       if (cfg->generic_sharing_context)
+                               context_used = mono_class_check_context_used (klass);
+                       if (context_used) {
+                               iargs [2] = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
+                       } else {
+                               if (cfg->compile_aot) {
+                                       EMIT_NEW_CLASSCONST (cfg, iargs [2], klass);
+                               } else {
+                                       EMIT_NEW_PCONST (cfg, iargs [2], klass);
+                                       mono_class_compute_gc_descriptor (klass);
+                               }
+                       }
 
                        mono_emit_jit_icall (cfg, mono_value_copy, iargs);
                }
@@ -2651,14 +2738,35 @@ emit_get_rgctx_klass (MonoCompile *cfg, int context_used,
        return emit_rgctx_fetch (cfg, rgctx, entry);
 }
 
+/*
+ * emit_get_rgctx_method:
+ *
+ *   Emit IR to load the property RGCTX_TYPE of CMETHOD. If context_used is 0, emit
+ * normal constants, else emit a load from the rgctx.
+ */
 static MonoInst*
 emit_get_rgctx_method (MonoCompile *cfg, int context_used,
                                           MonoMethod *cmethod, int rgctx_type)
 {
-       MonoJumpInfoRgctxEntry *entry = mono_patch_info_rgctx_entry_new (cfg->mempool, cfg->current_method, context_used & MONO_GENERIC_CONTEXT_USED_METHOD, MONO_PATCH_INFO_METHODCONST, cmethod, rgctx_type);
-       MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
+       if (!context_used) {
+               MonoInst *ins;
 
-       return emit_rgctx_fetch (cfg, rgctx, entry);
+               switch (rgctx_type) {
+               case MONO_RGCTX_INFO_METHOD:
+                       EMIT_NEW_METHODCONST (cfg, ins, cmethod);
+                       return ins;
+               case MONO_RGCTX_INFO_METHOD_RGCTX:
+                       EMIT_NEW_METHOD_RGCTX_CONST (cfg, ins, cmethod);
+                       return ins;
+               default:
+                       g_assert_not_reached ();
+               }
+       } else {
+               MonoJumpInfoRgctxEntry *entry = mono_patch_info_rgctx_entry_new (cfg->mempool, cfg->current_method, context_used & MONO_GENERIC_CONTEXT_USED_METHOD, MONO_PATCH_INFO_METHODCONST, cmethod, rgctx_type);
+               MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
+
+               return emit_rgctx_fetch (cfg, rgctx, entry);
+       }
 }
 
 static MonoInst*
@@ -2671,6 +2779,42 @@ emit_get_rgctx_field (MonoCompile *cfg, int context_used,
        return emit_rgctx_fetch (cfg, rgctx, entry);
 }
 
+/*
+ * On return the caller must check @klass for load errors.
+ */
+static void
+emit_generic_class_init (MonoCompile *cfg, MonoClass *klass)
+{
+       MonoInst *vtable_arg;
+       MonoCallInst *call;
+       int context_used = 0;
+
+       if (cfg->generic_sharing_context)
+               context_used = mono_class_check_context_used (klass);
+
+       if (context_used) {
+               vtable_arg = emit_get_rgctx_klass (cfg, context_used,
+                                                                                  klass, MONO_RGCTX_INFO_VTABLE);
+       } else {
+               MonoVTable *vtable = mono_class_vtable (cfg->domain, klass);
+
+               if (!vtable)
+                       return;
+               EMIT_NEW_VTABLECONST (cfg, vtable_arg, vtable);
+       }
+
+       call = (MonoCallInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_GENERIC_CLASS_INIT, NULL, helper_sig_generic_class_init_trampoline, &vtable_arg);
+#ifdef MONO_ARCH_VTABLE_REG
+       mono_call_inst_add_outarg_reg (cfg, call, vtable_arg->dreg, MONO_ARCH_VTABLE_REG, FALSE);
+       cfg->uses_vtable_reg = TRUE;
+#else
+       NOT_IMPLEMENTED;
+#endif
+}
+
+/*
+ * On return the caller must check @array_class for load errors
+ */
 static void
 mini_emit_check_array_type (MonoCompile *cfg, MonoInst *obj, MonoClass *array_class)
 {
@@ -2699,11 +2843,19 @@ mini_emit_check_array_type (MonoCompile *cfg, MonoInst *obj, MonoClass *array_cl
                MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, vtable_reg, vtable_ins->dreg);
        } else {
                if (cfg->compile_aot) {
-                       int vt_reg = alloc_preg (cfg);
-                       MONO_EMIT_NEW_VTABLECONST (cfg, vt_reg, mono_class_vtable (cfg->domain, array_class));
+                       int vt_reg;
+                       MonoVTable *vtable;
+
+                       if (!(vtable = mono_class_vtable (cfg->domain, array_class)))
+                               return;
+                       vt_reg = alloc_preg (cfg);
+                       MONO_EMIT_NEW_VTABLECONST (cfg, vt_reg, vtable);
                        MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, vtable_reg, vt_reg);
                } else {
-                       MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, vtable_reg, mono_class_vtable (cfg->domain, array_class));
+                       MonoVTable *vtable;
+                       if (!(vtable = mono_class_vtable (cfg->domain, array_class)))
+                               return;
+                       MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, vtable_reg, vtable);
                }
        }
        
@@ -2784,7 +2936,7 @@ handle_unbox (MonoCompile *cfg, MonoClass *klass, MonoInst **sp, int context_use
        int rank_reg = alloc_dreg (cfg ,STACK_I4);
 
        obj_reg = sp [0]->dreg;
-       MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, G_STRUCT_OFFSET (MonoObject, vtable));
+       MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, obj_reg, G_STRUCT_OFFSET (MonoObject, vtable));
        MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, rank_reg, vtable_reg, G_STRUCT_OFFSET (MonoVTable, rank));
 
        /* FIXME: generics */
@@ -2822,6 +2974,9 @@ handle_unbox (MonoCompile *cfg, MonoClass *klass, MonoInst **sp, int context_use
        return add;
 }
 
+/*
+ * Returns NULL and set the cfg exception on error.
+ */
 static MonoInst*
 handle_alloc (MonoCompile *cfg, MonoClass *klass, gboolean for_box)
 {
@@ -2840,9 +2995,19 @@ handle_alloc (MonoCompile *cfg, MonoClass *klass, gboolean for_box)
                return mono_emit_jit_icall (cfg, mono_helper_newobj_mscorlib, iargs);
        } else {
                MonoVTable *vtable = mono_class_vtable (cfg->domain, klass);
-               MonoMethod *managed_alloc = mono_gc_get_managed_allocator (vtable, for_box);
+               MonoMethod *managed_alloc = NULL;
                gboolean pass_lw;
 
+               if (!vtable) {
+                       cfg->exception_type = MONO_EXCEPTION_TYPE_LOAD;
+                       cfg->exception_ptr = klass;
+                       return NULL;
+               }
+
+#ifndef MONO_CROSS_COMPILE
+               managed_alloc = mono_gc_get_managed_allocator (vtable, for_box);
+#endif
+
                if (managed_alloc) {
                        EMIT_NEW_VTABLECONST (cfg, iargs [0], vtable);
                        return mono_emit_method_call (cfg, managed_alloc, iargs, NULL);
@@ -2895,6 +3060,9 @@ handle_alloc_from_inst (MonoCompile *cfg, MonoClass *klass, MonoInst *data_inst,
        return mono_emit_jit_icall (cfg, alloc_ftn, iargs);
 }
        
+/*
+ * Returns NULL and set the cfg exception on error.
+ */    
 static MonoInst*
 handle_box (MonoCompile *cfg, MonoInst *val, MonoClass *klass)
 {
@@ -2906,6 +3074,8 @@ handle_box (MonoCompile *cfg, MonoInst *val, MonoClass *klass)
        }
 
        alloc = handle_alloc (cfg, klass, TRUE);
+       if (!alloc)
+               return NULL;
 
        EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, alloc->dreg, sizeof (MonoObject), val->dreg);
 
@@ -2935,12 +3105,38 @@ handle_box_from_inst (MonoCompile *cfg, MonoInst *val, MonoClass *klass, int con
        }
 }
 
+/*
+ * Returns NULL and set the cfg exception on error.
+ */
 static MonoInst*
-handle_castclass (MonoCompile *cfg, MonoClass *klass, MonoInst *src)
+handle_castclass (MonoCompile *cfg, MonoClass *klass, MonoInst *src, int context_used)
 {
        MonoBasicBlock *is_null_bb;
        int obj_reg = src->dreg;
        int vtable_reg = alloc_preg (cfg);
+       MonoInst *klass_inst = NULL;
+
+       if (context_used) {
+               MonoInst *args [2];
+
+               klass_inst = emit_get_rgctx_klass (cfg, context_used,
+                                                                                  klass, MONO_RGCTX_INFO_KLASS);
+
+               // FIXME: This doesn't work yet (mcs/tests/gtest-304.cs fails)
+               if (TRUE || (klass->flags & TYPE_ATTRIBUTE_INTERFACE) || klass->rank || mono_class_is_nullable (klass) || klass->marshalbyref || (klass->flags & TYPE_ATTRIBUTE_SEALED) || mono_class_has_variant_generic_params (klass)) {
+                       /* Complex case, handle by an icall */
+
+                       /* obj */
+                       args [0] = src;
+
+                       /* klass */
+                       args [1] = klass_inst;
+
+                       return mono_emit_jit_icall (cfg, mono_object_castclass, args);
+               } else {
+                       /* Simple case, handled by the code below */
+               }
+       }
 
        NEW_BBLOCK (cfg, is_null_bb);
 
@@ -2959,8 +3155,13 @@ handle_castclass (MonoCompile *cfg, MonoClass *klass, MonoInst *src)
 
                if (!klass->rank && !cfg->compile_aot && !(cfg->opt & MONO_OPT_SHARED) && (klass->flags & TYPE_ATTRIBUTE_SEALED)) {
                        /* the remoting code is broken, access the class for now */
-                       if (0) {
+                       if (0) { /*FIXME what exactly is broken? This change refers to r39380 from 2005 and mention some remoting fixes were due.*/
                                MonoVTable *vt = mono_class_vtable (cfg->domain, klass);
+                               if (!vt) {
+                                       cfg->exception_type = MONO_EXCEPTION_TYPE_LOAD;
+                                       cfg->exception_ptr = klass;
+                                       return NULL;
+                               }
                                MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, vtable_reg, vt);
                        } else {
                                MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, G_STRUCT_OFFSET (MonoVTable, klass));
@@ -2969,7 +3170,7 @@ handle_castclass (MonoCompile *cfg, MonoClass *klass, MonoInst *src)
                        MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
                } else {
                        MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, G_STRUCT_OFFSET (MonoVTable, klass));
-                       mini_emit_castclass (cfg, obj_reg, klass_reg, klass, is_null_bb);
+                       mini_emit_castclass_inst (cfg, obj_reg, klass_reg, klass, klass_inst, is_null_bb);
                }
        }
 
@@ -2980,14 +3181,39 @@ handle_castclass (MonoCompile *cfg, MonoClass *klass, MonoInst *src)
        return src;
 }
 
+/*
+ * Returns NULL and set the cfg exception on error.
+ */
 static MonoInst*
-handle_isinst (MonoCompile *cfg, MonoClass *klass, MonoInst *src)
+handle_isinst (MonoCompile *cfg, MonoClass *klass, MonoInst *src, int context_used)
 {
        MonoInst *ins;
        MonoBasicBlock *is_null_bb, *false_bb, *end_bb;
        int obj_reg = src->dreg;
        int vtable_reg = alloc_preg (cfg);
        int res_reg = alloc_preg (cfg);
+       MonoInst *klass_inst = NULL;
+
+       if (context_used) {
+               klass_inst = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
+
+               // FIXME: This doesn't work yet (mcs/tests/gtest-304.cs fails)
+               if (TRUE || (klass->flags & TYPE_ATTRIBUTE_INTERFACE) || klass->rank || mono_class_is_nullable (klass) || klass->marshalbyref || (klass->flags & TYPE_ATTRIBUTE_SEALED) || mono_class_has_variant_generic_params (klass)) {
+                       MonoInst *args [2];
+
+                       /* Complex case, handle by an icall */
+
+                       /* obj */
+                       args [0] = src;
+
+                       /* klass */
+                       args [1] = klass_inst;
+
+                       return mono_emit_jit_icall (cfg, mono_object_isinst, args);
+               } else {
+                       /* Simple case, the code below can handle it */
+               }
+       }
 
        NEW_BBLOCK (cfg, is_null_bb);
        NEW_BBLOCK (cfg, false_bb);
@@ -3001,19 +3227,20 @@ handle_isinst (MonoCompile *cfg, MonoClass *klass, MonoInst *src)
        MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
        MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_null_bb);
 
+       MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, G_STRUCT_OFFSET (MonoObject, vtable));
+
        if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
-               MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, G_STRUCT_OFFSET (MonoObject, vtable));
+               g_assert (!context_used);
                /* the is_null_bb target simply copies the input register to the output */
                mini_emit_iface_cast (cfg, vtable_reg, klass, false_bb, is_null_bb);
        } else {
                int klass_reg = alloc_preg (cfg);
 
-               MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, G_STRUCT_OFFSET (MonoObject, vtable));
-
                if (klass->rank) {
                        int rank_reg = alloc_preg (cfg);
                        int eclass_reg = alloc_preg (cfg);
 
+                       g_assert (!context_used);
                        MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, rank_reg, vtable_reg, G_STRUCT_OFFSET (MonoVTable, rank));
                        MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rank_reg, klass->rank);
                        MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false_bb);
@@ -3047,14 +3274,21 @@ handle_isinst (MonoCompile *cfg, MonoClass *klass, MonoInst *src)
                                mini_emit_isninst_cast (cfg, eclass_reg, klass->cast_class, false_bb, is_null_bb);
                        }
                } else if (mono_class_is_nullable (klass)) {
+                       g_assert (!context_used);
                        MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, G_STRUCT_OFFSET (MonoVTable, klass));
                        /* the is_null_bb target simply copies the input register to the output */
                        mini_emit_isninst_cast (cfg, klass_reg, klass->cast_class, false_bb, is_null_bb);
                } else {
                        if (!cfg->compile_aot && !(cfg->opt & MONO_OPT_SHARED) && (klass->flags & TYPE_ATTRIBUTE_SEALED)) {
+                               g_assert (!context_used);
                                /* the remoting code is broken, access the class for now */
-                               if (0) {
+                               if (0) {/*FIXME what exactly is broken? This change refers to r39380 from 2005 and mention some remoting fixes were due.*/
                                        MonoVTable *vt = mono_class_vtable (cfg->domain, klass);
+                                       if (!vt) {
+                                               cfg->exception_type = MONO_EXCEPTION_TYPE_LOAD;
+                                               cfg->exception_ptr = klass;
+                                               return NULL;
+                                       }
                                        MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, vtable_reg, vt);
                                } else {
                                        MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, G_STRUCT_OFFSET (MonoVTable, klass));
@@ -3065,7 +3299,7 @@ handle_isinst (MonoCompile *cfg, MonoClass *klass, MonoInst *src)
                        } else {
                                MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, G_STRUCT_OFFSET (MonoVTable, klass));
                                /* the is_null_bb target simply copies the input register to the output */
-                               mini_emit_isninst_cast (cfg, klass_reg, klass, false_bb, is_null_bb);
+                               mini_emit_isninst_cast_inst (cfg, klass_reg, klass, klass_inst, false_bb, is_null_bb);
                        }
                }
        }
@@ -3251,8 +3485,11 @@ handle_ccastclass (MonoCompile *cfg, MonoClass *klass, MonoInst *src)
        return ins;
 }
 
+/*
+ * Returns NULL and set the cfg exception on error.
+ */
 static G_GNUC_UNUSED MonoInst*
-handle_delegate_ctor (MonoCompile *cfg, MonoClass *klass, MonoInst *target, MonoMethod *method)
+handle_delegate_ctor (MonoCompile *cfg, MonoClass *klass, MonoInst *target, MonoMethod *method, int context_used)
 {
        gpointer *trampoline;
        MonoInst *obj, *method_ins, *tramp_ins;
@@ -3260,6 +3497,8 @@ handle_delegate_ctor (MonoCompile *cfg, MonoClass *klass, MonoInst *target, Mono
        guint8 **code_slot;
 
        obj = handle_alloc (cfg, klass, FALSE);
+       if (!obj)
+               return NULL;
 
        /* Inline the contents of mono_delegate_ctor */
 
@@ -3269,7 +3508,7 @@ handle_delegate_ctor (MonoCompile *cfg, MonoClass *klass, MonoInst *target, Mono
                MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, G_STRUCT_OFFSET (MonoDelegate, target), target->dreg);
 
        /* Set method field */
-       EMIT_NEW_METHODCONST (cfg, method_ins, method);
+       method_ins = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_METHOD);
        MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, G_STRUCT_OFFSET (MonoDelegate, method), method_ins->dreg);
 
        /* 
@@ -3280,18 +3519,22 @@ handle_delegate_ctor (MonoCompile *cfg, MonoClass *klass, MonoInst *target, Mono
        if (!cfg->compile_aot && !method->dynamic) {
                MonoInst *code_slot_ins;
 
-               domain = mono_domain_get ();
-               mono_domain_lock (domain);
-               if (!domain_jit_info (domain)->method_code_hash)
-                       domain_jit_info (domain)->method_code_hash = g_hash_table_new (NULL, NULL);
-               code_slot = g_hash_table_lookup (domain_jit_info (domain)->method_code_hash, method);
-               if (!code_slot) {
-                       code_slot = mono_domain_alloc0 (domain, sizeof (gpointer));
-                       g_hash_table_insert (domain_jit_info (domain)->method_code_hash, method, code_slot);
+               if (context_used) {
+                       code_slot_ins = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_METHOD_DELEGATE_CODE);
+               } else {
+                       domain = mono_domain_get ();
+                       mono_domain_lock (domain);
+                       if (!domain_jit_info (domain)->method_code_hash)
+                               domain_jit_info (domain)->method_code_hash = g_hash_table_new (NULL, NULL);
+                       code_slot = g_hash_table_lookup (domain_jit_info (domain)->method_code_hash, method);
+                       if (!code_slot) {
+                               code_slot = mono_domain_alloc0 (domain, sizeof (gpointer));
+                               g_hash_table_insert (domain_jit_info (domain)->method_code_hash, method, code_slot);
+                       }
+                       mono_domain_unlock (domain);
+
+                       EMIT_NEW_PCONST (cfg, code_slot_ins, code_slot);
                }
-               mono_domain_unlock (domain);
-
-               EMIT_NEW_PCONST (cfg, code_slot_ins, code_slot);
                MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, G_STRUCT_OFFSET (MonoDelegate, method_code), code_slot_ins->dreg);           
        }
 
@@ -3319,6 +3562,9 @@ handle_array_new (MonoCompile *cfg, int rank, MonoInst **sp, unsigned char *ip)
 
        cfg->flags |= MONO_CFG_HAS_VARARGS;
 
+       /* mono_array_new_va () needs a vararg calling convention */
+       cfg->disable_llvm = TRUE;
+
        /* FIXME: This uses info->sig, but it should use the signature of the wrapper */
        return mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, sp);
 }
@@ -3373,6 +3619,9 @@ mono_method_check_inlining (MonoCompile *cfg, MonoMethod *method)
        if (cfg->generic_sharing_context)
                return FALSE;
 
+       if (cfg->inline_depth > 10)
+               return FALSE;
+
 #ifdef MONO_ARCH_HAVE_LMF_OPS
        if (((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
                 (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) &&
@@ -3416,6 +3665,7 @@ mono_method_check_inlining (MonoCompile *cfg, MonoMethod *method)
        if (!(cfg->opt & MONO_OPT_SHARED)) {
                if (method->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT) {
                        if (cfg->run_cctors && method->klass->has_cctor) {
+                               /*FIXME it would easier and lazier to just use mono_class_try_get_vtable */
                                if (!method->klass->runtime_info)
                                        /* No vtable created yet */
                                        return FALSE;
@@ -3503,8 +3753,13 @@ mini_emit_ldelema_1_ins (MonoCompile *cfg, MonoClass *klass, MonoInst *arr, Mono
 
 #if SIZEOF_REGISTER == 8
        /* The array reg is 64 bits but the index reg is only 32 */
-       index2_reg = alloc_preg (cfg);
-       MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, index2_reg, index_reg);
+       if (COMPILE_LLVM (cfg)) {
+               /* Not needed */
+               index2_reg = index_reg;
+       } else {
+               index2_reg = alloc_preg (cfg);
+               MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, index2_reg, index_reg);
+       }
 #else
        if (index->type == STACK_I8) {
                index2_reg = alloc_preg (cfg);
@@ -3516,7 +3771,7 @@ mini_emit_ldelema_1_ins (MonoCompile *cfg, MonoClass *klass, MonoInst *arr, Mono
 
        MONO_EMIT_BOUNDS_CHECK (cfg, array_reg, MonoArray, max_length, index2_reg);
 
-#if defined(__i386__) || defined(__x86_64__)
+#if defined(TARGET_X86) || defined(TARGET_AMD64)
        if (size == 1 || size == 2 || size == 4 || size == 8) {
                static const int fast_log2 [] = { 1, 0, 1, -1, 2, -1, -1, -1, 3 };
 
@@ -3624,6 +3879,53 @@ mini_emit_ldelema_ins (MonoCompile *cfg, MonoMethod *cmethod, MonoInst **sp, uns
        return addr;
 }
 
+static MonoBreakPolicy
+always_insert_breakpoint (MonoMethod *method)
+{
+       return MONO_BREAK_POLICY_ALWAYS;
+}
+
+static MonoBreakPolicyFunc break_policy_func = always_insert_breakpoint;
+
+/**
+ * mono_set_break_policy:
+ * policy_callback: the new callback function
+ *
+ * Allow embedders to decide wherther to actually obey breakpoint instructions
+ * (both break IL instructions and Debugger.Break () method calls), for example
+ * to not allow an app to be aborted by a perfectly valid IL opcode when executing
+ * untrusted or semi-trusted code.
+ *
+ * @policy_callback will be called every time a break point instruction needs to
+ * be inserted with the method argument being the method that calls Debugger.Break()
+ * or has the IL break instruction. The callback should return #MONO_BREAK_POLICY_NEVER
+ * if it wants the breakpoint to not be effective in the given method.
+ * #MONO_BREAK_POLICY_ALWAYS is the default.
+ */
+void
+mono_set_break_policy (MonoBreakPolicyFunc policy_callback)
+{
+       if (policy_callback)
+               break_policy_func = policy_callback;
+       else
+               break_policy_func = always_insert_breakpoint;
+}
+
+static gboolean
+should_insert_brekpoint (MonoMethod *method) {
+       switch (break_policy_func (method)) {
+       case MONO_BREAK_POLICY_ALWAYS:
+               return TRUE;
+       case MONO_BREAK_POLICY_NEVER:
+               return FALSE;
+       case MONO_BREAK_POLICY_ON_DBG:
+               return mono_debug_using_mono_debugger ();
+       default:
+               g_warning ("Incorrect value returned from break policy callback");
+               return FALSE;
+       }
+}
+
 static MonoInst*
 mini_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
 {
@@ -3649,7 +3951,7 @@ mini_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSign
 #endif 
                        MONO_EMIT_BOUNDS_CHECK (cfg, args [0]->dreg, MonoString, length, index_reg);
 
-#if defined(__i386__) || defined(__x86_64__)
+#if defined(TARGET_X86) || defined(TARGET_AMD64)
                        EMIT_NEW_X86_LEA (cfg, ins, args [0]->dreg, index_reg, 1, G_STRUCT_OFFSET (MonoString, chars));
                        add_reg = ins->dreg;
                        /* Avoid a warning */
@@ -3688,7 +3990,7 @@ mini_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSign
                if (strcmp (cmethod->name, "GetType") == 0) {
                        int dreg = alloc_preg (cfg);
                        int vt_reg = alloc_preg (cfg);
-                       MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vt_reg, args [0]->dreg, G_STRUCT_OFFSET (MonoObject, vtable));
+                       MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vt_reg, args [0]->dreg, G_STRUCT_OFFSET (MonoObject, vtable));
                        EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, vt_reg, G_STRUCT_OFFSET (MonoVTable, type));
                        type_from_op (ins, NULL, NULL);
 
@@ -3717,8 +4019,8 @@ mini_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSign
                if (strcmp (cmethod->name, "get_Rank") == 0) {
                        int dreg = alloc_ireg (cfg);
                        int vtable_reg = alloc_preg (cfg);
-                       MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOAD_MEMBASE, vtable_reg, 
-                                                                                  args [0]->dreg, G_STRUCT_OFFSET (MonoObject, vtable));
+                       MONO_EMIT_NEW_LOAD_MEMBASE_OP_FAULT (cfg, OP_LOAD_MEMBASE, vtable_reg, 
+                                                                                                args [0]->dreg, G_STRUCT_OFFSET (MonoObject, vtable));
                        EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADU1_MEMBASE, dreg,
                                                                   vtable_reg, G_STRUCT_OFFSET (MonoVTable, rank));
                        type_from_op (ins, NULL, NULL);
@@ -3727,8 +4029,8 @@ mini_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSign
                } else if (strcmp (cmethod->name, "get_Length") == 0) {
                        int dreg = alloc_ireg (cfg);
 
-                       EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADI4_MEMBASE, dreg, 
-                                                                  args [0]->dreg, G_STRUCT_OFFSET (MonoArray, max_length));
+                       EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, ins, OP_LOADI4_MEMBASE, dreg, 
+                                                                                args [0]->dreg, G_STRUCT_OFFSET (MonoArray, max_length));
                        type_from_op (ins, NULL, NULL);
 
                        return ins;
@@ -3742,12 +4044,7 @@ mini_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSign
                } else
                        return NULL;
        } else if (cmethod->klass == mono_defaults.thread_class) {
-               if (strcmp (cmethod->name, "get_CurrentThread") == 0 && (ins = mono_arch_get_thread_intrinsic (cfg))) {
-                       ins->dreg = alloc_preg (cfg);
-                       ins->type = STACK_OBJ;
-                       MONO_ADD_INS (cfg->cbb, ins);
-                       return ins;
-               } else if (strcmp (cmethod->name, "SpinWait_nop") == 0) {
+               if (strcmp (cmethod->name, "SpinWait_nop") == 0) {
                        MONO_INST_NEW (cfg, ins, OP_RELAXED_NOP);
                        MONO_ADD_INS (cfg->cbb, ins);
                        return ins;
@@ -3761,19 +4058,31 @@ mini_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSign
                if (strcmp (cmethod->name, "Enter") == 0) {
                        MonoCallInst *call;
 
-                       call = (MonoCallInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_MONITOR_ENTER,
-                                       NULL, helper_sig_monitor_enter_exit_trampoline, NULL);
-                       mono_call_inst_add_outarg_reg (cfg, call, args [0]->dreg,
-                                       MONO_ARCH_MONITOR_OBJECT_REG, FALSE);
+                       if (COMPILE_LLVM (cfg)) {
+                               /* 
+                                * Pass the argument normally, the LLVM backend will handle the
+                                * calling convention problems.
+                                */
+                               call = (MonoCallInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_MONITOR_ENTER, NULL, helper_sig_monitor_enter_exit_trampoline_llvm, args);
+                       } else {
+                               call = (MonoCallInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_MONITOR_ENTER,
+                                           NULL, helper_sig_monitor_enter_exit_trampoline, NULL);
+                               mono_call_inst_add_outarg_reg (cfg, call, args [0]->dreg,
+                                                                                          MONO_ARCH_MONITOR_OBJECT_REG, FALSE);
+                       }
 
                        return (MonoInst*)call;
                } else if (strcmp (cmethod->name, "Exit") == 0) {
                        MonoCallInst *call;
 
-                       call = (MonoCallInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_MONITOR_EXIT,
-                                       NULL, helper_sig_monitor_enter_exit_trampoline, NULL);
-                       mono_call_inst_add_outarg_reg (cfg, call, args [0]->dreg,
-                                       MONO_ARCH_MONITOR_OBJECT_REG, FALSE);
+                       if (COMPILE_LLVM (cfg)) {
+                               call = (MonoCallInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_MONITOR_EXIT, NULL, helper_sig_monitor_enter_exit_trampoline_llvm, args);
+                       } else {
+                               call = (MonoCallInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_MONITOR_EXIT,
+                                           NULL, helper_sig_monitor_enter_exit_trampoline, NULL);
+                               mono_call_inst_add_outarg_reg (cfg, call, args [0]->dreg,
+                                                                                          MONO_ARCH_MONITOR_OBJECT_REG, FALSE);
+                       }
 
                        return (MonoInst*)call;
                }
@@ -3893,17 +4202,16 @@ mini_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSign
 #ifdef MONO_ARCH_HAVE_ATOMIC_EXCHANGE
                if (strcmp (cmethod->name, "Exchange") == 0) {
                        guint32 opcode;
+                       gboolean is_ref = fsig->params [0]->type == MONO_TYPE_OBJECT;
 
                        if (fsig->params [0]->type == MONO_TYPE_I4)
                                opcode = OP_ATOMIC_EXCHANGE_I4;
 #if SIZEOF_REGISTER == 8
-                       else if ((fsig->params [0]->type == MONO_TYPE_I8) ||
-                                        (fsig->params [0]->type == MONO_TYPE_I) ||
-                                        (fsig->params [0]->type == MONO_TYPE_OBJECT))
+                       else if (is_ref || (fsig->params [0]->type == MONO_TYPE_I8) ||
+                                       (fsig->params [0]->type == MONO_TYPE_I))
                                opcode = OP_ATOMIC_EXCHANGE_I8;
 #else
-                       else if ((fsig->params [0]->type == MONO_TYPE_I) ||
-                                        (fsig->params [0]->type == MONO_TYPE_OBJECT))
+                       else if (is_ref || (fsig->params [0]->type == MONO_TYPE_I))
                                opcode = OP_ATOMIC_EXCHANGE_I4;
 #endif
                        else
@@ -3930,15 +4238,23 @@ mini_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSign
                        default:
                                g_assert_not_reached ();
                        }
+
+#if HAVE_WRITE_BARRIERS
+                       if (is_ref) {
+                               MonoMethod *write_barrier = mono_gc_get_write_barrier ();
+                               mono_emit_method_call (cfg, write_barrier, &args [0], NULL);
+                       }
+#endif
                }
 #endif /* MONO_ARCH_HAVE_ATOMIC_EXCHANGE */
  
 #ifdef MONO_ARCH_HAVE_ATOMIC_CAS
                if ((strcmp (cmethod->name, "CompareExchange") == 0)) {
                        int size = 0;
+                       gboolean is_ref = MONO_TYPE_IS_REFERENCE (fsig->params [1]);
                        if (fsig->params [1]->type == MONO_TYPE_I4)
                                size = 4;
-                       else if (fsig->params [1]->type == MONO_TYPE_I || MONO_TYPE_IS_REFERENCE (fsig->params [1]))
+                       else if (is_ref || fsig->params [1]->type == MONO_TYPE_I)
                                size = sizeof (gpointer);
                        else if (sizeof (gpointer) == 8 && fsig->params [1]->type == MONO_TYPE_I4)
                                size = 8;
@@ -3961,6 +4277,12 @@ mini_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSign
                        } else {
                                /* g_assert_not_reached (); */
                        }
+#if HAVE_WRITE_BARRIERS
+                       if (is_ref) {
+                               MonoMethod *write_barrier = mono_gc_get_write_barrier ();
+                               mono_emit_method_call (cfg, write_barrier, &args [0], NULL);
+                       }
+#endif
                }
 #endif /* MONO_ARCH_HAVE_ATOMIC_CAS */
 
@@ -3969,13 +4291,16 @@ mini_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSign
        } else if (cmethod->klass->image == mono_defaults.corlib) {
                if (cmethod->name [0] == 'B' && strcmp (cmethod->name, "Break") == 0
                                && strcmp (cmethod->klass->name, "Debugger") == 0) {
-                       MONO_INST_NEW (cfg, ins, OP_BREAK);
+                       if (should_insert_brekpoint (cfg->method))
+                               MONO_INST_NEW (cfg, ins, OP_BREAK);
+                       else
+                               MONO_INST_NEW (cfg, ins, OP_NOP);
                        MONO_ADD_INS (cfg->cbb, ins);
                        return ins;
                }
                if (cmethod->name [0] == 'g' && strcmp (cmethod->name, "get_IsRunningOnWindows") == 0
                                && strcmp (cmethod->klass->name, "Environment") == 0) {
-#ifdef PLATFORM_WIN32
+#ifdef TARGET_WIN32
                        EMIT_NEW_ICONST (cfg, ins, 1);
 #else
                        EMIT_NEW_ICONST (cfg, ins, 0);
@@ -4011,10 +4336,15 @@ mini_redirect_call (MonoCompile *cfg, MonoMethod *method,
 {
        if (method->klass == mono_defaults.string_class) {
                /* managed string allocation support */
-               if (strcmp (method->name, "InternalAllocateStr") == 0) {
+               if (strcmp (method->name, "InternalAllocateStr") == 0 && !(mono_profiler_events & MONO_PROFILE_STRING_ALLOC)) {
                        MonoInst *iargs [2];
                        MonoVTable *vtable = mono_class_vtable (cfg->domain, method->klass);
-                       MonoMethod *managed_alloc = mono_gc_get_managed_allocator (vtable, FALSE);
+                       MonoMethod *managed_alloc = NULL;
+
+                       g_assert (vtable); /*Should not fail since it System.String*/
+#ifndef MONO_CROSS_COMPILE
+                       managed_alloc = mono_gc_get_managed_allocator (vtable, FALSE);
+#endif
                        if (!managed_alloc)
                                return NULL;
                        EMIT_NEW_VTABLECONST (cfg, iargs [0], vtable);
@@ -4179,6 +4509,7 @@ inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig,
        prev_inlined_method = cfg->inlined_method;
        cfg->inlined_method = cmethod;
        cfg->ret_var_set = FALSE;
+       cfg->inline_depth ++;
        prev_real_offset = cfg->real_offset;
        prev_cbb_hash = cfg->cbb_hash;
        prev_cil_offset_to_bb = cfg->cil_offset_to_bb;
@@ -4205,6 +4536,7 @@ inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig,
        cfg->current_method = prev_current_method;
        cfg->generic_context = prev_generic_context;
        cfg->ret_var_set = prev_ret_var_set;
+       cfg->inline_depth --;
 
        if ((costs >= 0 && costs < 60) || inline_allways) {
                if (cfg->verbose_level > 2)
@@ -4501,54 +4833,25 @@ gboolean check_linkdemand (MonoCompile *cfg, MonoMethod *caller, MonoMethod *cal
 }
 
 static MonoMethod*
-method_access_exception (void)
+throw_exception (void)
 {
        static MonoMethod *method = NULL;
 
        if (!method) {
                MonoSecurityManager *secman = mono_security_manager_get_methods ();
-               method = mono_class_get_method_from_name (secman->securitymanager,
-                                                         "MethodAccessException", 2);
+               method = mono_class_get_method_from_name (secman->securitymanager, "ThrowException", 1);
        }
        g_assert (method);
        return method;
 }
 
 static void
-emit_throw_method_access_exception (MonoCompile *cfg, MonoMethod *caller, MonoMethod *callee,
-                                   MonoBasicBlock *bblock, unsigned char *ip)
+emit_throw_exception (MonoCompile *cfg, MonoException *ex)
 {
-       MonoMethod *thrower = method_access_exception ();
-       MonoInst *args [2];
+       MonoMethod *thrower = throw_exception ();
+       MonoInst *args [1];
 
-       EMIT_NEW_METHODCONST (cfg, args [0], caller);
-       EMIT_NEW_METHODCONST (cfg, args [1], callee);
-       mono_emit_method_call (cfg, thrower, args, NULL);
-}
-
-static MonoMethod*
-field_access_exception (void)
-{
-       static MonoMethod *method = NULL;
-
-       if (!method) {
-               MonoSecurityManager *secman = mono_security_manager_get_methods ();
-               method = mono_class_get_method_from_name (secman->securitymanager,
-                                                         "FieldAccessException", 2);
-       }
-       g_assert (method);
-       return method;
-}
-
-static void
-emit_throw_field_access_exception (MonoCompile *cfg, MonoMethod *caller, MonoClassField *field,
-                                   MonoBasicBlock *bblock, unsigned char *ip)
-{
-       MonoMethod *thrower = field_access_exception ();
-       MonoInst *args [2];
-
-       EMIT_NEW_METHODCONST (cfg, args [0], caller);
-       EMIT_NEW_METHODCONST (cfg, args [1], field);
+       EMIT_NEW_PCONST (cfg, args [0], ex);
        mono_emit_method_call (cfg, thrower, args, NULL);
 }
 
@@ -4585,7 +4888,7 @@ ensure_method_is_allowed_to_access_field (MonoCompile *cfg, MonoMethod *caller,
 
        /* caller is Critical! only SafeCritical and Critical callers can access the field, so we throw if caller is Transparent */
        if (mono_security_core_clr_method_level (caller, TRUE) == MONO_SECURITY_CORE_CLR_TRANSPARENT)
-               emit_throw_field_access_exception (cfg, caller, field, bblock, ip);
+               emit_throw_exception (cfg, mono_get_exception_field_access ());
 }
 
 static void
@@ -4603,7 +4906,7 @@ ensure_method_is_allowed_to_call_method (MonoCompile *cfg, MonoMethod *caller, M
 
        /* caller is Critical! only SafeCritical and Critical callers can call it, so we throw if the caller is Transparent */
        if (mono_security_core_clr_method_level (caller, TRUE) == MONO_SECURITY_CORE_CLR_TRANSPARENT)
-               emit_throw_method_access_exception (cfg, caller, callee, bblock, ip);
+               emit_throw_exception (cfg, mono_get_exception_method_access ());
 }
 
 /*
@@ -4647,7 +4950,7 @@ initialize_array_data (MonoMethod *method, gboolean aot, unsigned char *ip, Mono
                case MONO_TYPE_U1:
                        size = 1; break;
                /* we need to swap on big endian, so punt. Should we handle R4 and R8 as well? */
-#if G_BYTE_ORDER == G_LITTLE_ENDIAN
+#if TARGET_BYTE_ORDER == G_LITTLE_ENDIAN
                case MONO_TYPE_CHAR:
                case MONO_TYPE_I2:
                case MONO_TYPE_U2:
@@ -4692,429 +4995,39 @@ initialize_array_data (MonoMethod *method, gboolean aot, unsigned char *ip, Mono
 
 static void
 set_exception_type_from_invalid_il (MonoCompile *cfg, MonoMethod *method, unsigned char *ip)
-{
-       char *method_fname = mono_method_full_name (method, TRUE);
-       char *method_code;
-
-       if (mono_method_get_header (method)->code_size == 0)
-               method_code = g_strdup ("method body is empty.");
-       else
-               method_code = mono_disasm_code_one (NULL, method, ip, NULL);
-       cfg->exception_type = MONO_EXCEPTION_INVALID_PROGRAM;
-       cfg->exception_message = g_strdup_printf ("Invalid IL code in %s: %s\n", method_fname, method_code);
-       g_free (method_fname);
-       g_free (method_code);
-}
-
-static void
-set_exception_object (MonoCompile *cfg, MonoException *exception)
-{
-       cfg->exception_type = MONO_EXCEPTION_OBJECT_SUPPLIED;
-       MONO_GC_REGISTER_ROOT (cfg->exception_ptr);
-       cfg->exception_ptr = exception;
-}
-
-static gboolean
-generic_class_is_reference_type (MonoCompile *cfg, MonoClass *klass)
-{
-       MonoType *type;
-
-       if (cfg->generic_sharing_context)
-               type = mini_get_basic_type_from_generic (cfg->generic_sharing_context, &klass->byval_arg);
-       else
-               type = &klass->byval_arg;
-       return MONO_TYPE_IS_REFERENCE (type);
-}
-
-/**
- * mono_decompose_array_access_opts:
- *
- *  Decompose array access opcodes.
- * This should be in decompose.c, but it emits calls so it has to stay here until
- * the old JIT is gone.
- */
-void
-mono_decompose_array_access_opts (MonoCompile *cfg)
-{
-       MonoBasicBlock *bb, *first_bb;
-
-       /*
-        * Unlike decompose_long_opts, this pass does not alter the CFG of the method so it 
-        * can be executed anytime. It should be run before decompose_long
-        */
-
-       /**
-        * Create a dummy bblock and emit code into it so we can use the normal 
-        * code generation macros.
-        */
-       cfg->cbb = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
-       first_bb = cfg->cbb;
-
-       for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
-               MonoInst *ins;
-               MonoInst *prev = NULL;
-               MonoInst *dest;
-               MonoInst *iargs [3];
-               gboolean restart;
-
-               if (!bb->has_array_access)
-                       continue;
-
-               if (cfg->verbose_level > 3) mono_print_bb (bb, "BEFORE DECOMPOSE-ARRAY-ACCESS-OPTS ");
-
-               cfg->cbb->code = cfg->cbb->last_ins = NULL;
-               restart = TRUE;
-
-               while (restart) {
-                       restart = FALSE;
-
-                       for (ins = bb->code; ins; ins = ins->next) {
-                               switch (ins->opcode) {
-                               case OP_LDLEN:
-                                       NEW_LOAD_MEMBASE (cfg, dest, OP_LOADI4_MEMBASE, ins->dreg, ins->sreg1,
-                                                                         G_STRUCT_OFFSET (MonoArray, max_length));
-                                       MONO_ADD_INS (cfg->cbb, dest);
-                                       break;
-                               case OP_BOUNDS_CHECK:
-                                       MONO_ARCH_EMIT_BOUNDS_CHECK (cfg, ins->sreg1, ins->inst_imm, ins->sreg2);
-                                       break;
-                               case OP_NEWARR:
-                                       if (cfg->opt & MONO_OPT_SHARED) {
-                                               EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
-                                               EMIT_NEW_CLASSCONST (cfg, iargs [1], ins->inst_newa_class);
-                                               MONO_INST_NEW (cfg, iargs [2], OP_MOVE);
-                                               iargs [2]->dreg = ins->sreg1;
-
-                                               dest = mono_emit_jit_icall (cfg, mono_array_new, iargs);
-                                               dest->dreg = ins->dreg;
-                                       } else {
-                                               MonoVTable *vtable = mono_class_vtable (cfg->domain, mono_array_class_get (ins->inst_newa_class, 1));
-
-                                               g_assert (vtable);
-                                               NEW_VTABLECONST (cfg, iargs [0], vtable);
-                                               MONO_ADD_INS (cfg->cbb, iargs [0]);
-                                               MONO_INST_NEW (cfg, iargs [1], OP_MOVE);
-                                               iargs [1]->dreg = ins->sreg1;
-
-                                               dest = mono_emit_jit_icall (cfg, mono_array_new_specific, iargs);
-                                               dest->dreg = ins->dreg;
-                                       }
-                                       break;
-                               case OP_STRLEN:
-                                       NEW_LOAD_MEMBASE (cfg, dest, OP_LOADI4_MEMBASE, ins->dreg,
-                                                                         ins->sreg1, G_STRUCT_OFFSET (MonoString, length));
-                                       MONO_ADD_INS (cfg->cbb, dest);
-                                       break;
-                               default:
-                                       break;
-                               }
-
-                               g_assert (cfg->cbb == first_bb);
-
-                               if (cfg->cbb->code || (cfg->cbb != first_bb)) {
-                                       /* Replace the original instruction with the new code sequence */
-
-                                       mono_replace_ins (cfg, bb, ins, &prev, first_bb, cfg->cbb);
-                                       first_bb->code = first_bb->last_ins = NULL;
-                                       first_bb->in_count = first_bb->out_count = 0;
-                                       cfg->cbb = first_bb;
-                               }
-                               else
-                                       prev = ins;
-                       }
-               }
-
-               if (cfg->verbose_level > 3) mono_print_bb (bb, "AFTER DECOMPOSE-ARRAY-ACCESS-OPTS ");
-       }
-}
-
-typedef union {
-       guint32 vali [2];
-       gint64 vall;
-       double vald;
-} DVal;
-
-#ifdef MONO_ARCH_SOFT_FLOAT
-
-/**
- * mono_decompose_soft_float:
- *
- *  Soft float support on ARM. We store each double value in a pair of integer vregs,
- * similar to long support on 32 bit platforms. 32 bit float values require special
- * handling when used as locals, arguments, and in calls.
- * One big problem with soft-float is that there are few r4 test cases in our test suite.
- */
-void
-mono_decompose_soft_float (MonoCompile *cfg)
-{
-       MonoBasicBlock *bb, *first_bb;
-
-       /*
-        * This pass creates long opcodes, so it should be run before decompose_long_opts ().
-        */
-
-       /**
-        * Create a dummy bblock and emit code into it so we can use the normal 
-        * code generation macros.
-        */
-       cfg->cbb = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
-       first_bb = cfg->cbb;
-
-       for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
-               MonoInst *ins;
-               MonoInst *prev = NULL;
-               gboolean restart;
-
-               if (cfg->verbose_level > 3) mono_print_bb (bb, "BEFORE HANDLE-SOFT-FLOAT ");
-
-               cfg->cbb->code = cfg->cbb->last_ins = NULL;
-               restart = TRUE;
-
-               while (restart) {
-                       restart = FALSE;
-
-                       for (ins = bb->code; ins; ins = ins->next) {
-                               const char *spec = INS_INFO (ins->opcode);
-
-                               /* Most fp operations are handled automatically by opcode emulation */
-
-                               switch (ins->opcode) {
-                               case OP_R8CONST: {
-                                       DVal d;
-                                       d.vald = *(double*)ins->inst_p0;
-                                       MONO_EMIT_NEW_I8CONST (cfg, ins->dreg, d.vall);
-                                       break;
-                               }
-                               case OP_R4CONST: {
-                                       DVal d;
-                                       /* We load the r8 value */
-                                       d.vald = *(float*)ins->inst_p0;
-                                       MONO_EMIT_NEW_I8CONST (cfg, ins->dreg, d.vall);
-                                       break;
-                               }
-                               case OP_FMOVE:
-                                       ins->opcode = OP_LMOVE;
-                                       break;
-                               case OP_FGETLOW32:
-                                       ins->opcode = OP_MOVE;
-                                       ins->sreg1 = ins->sreg1 + 1;
-                                       break;
-                               case OP_FGETHIGH32:
-                                       ins->opcode = OP_MOVE;
-                                       ins->sreg1 = ins->sreg1 + 2;
-                                       break;
-                               case OP_SETFRET: {
-                                       int reg = ins->sreg1;
-
-                                       ins->opcode = OP_SETLRET;
-                                       ins->dreg = -1;
-                                       ins->sreg1 = reg + 1;
-                                       ins->sreg2 = reg + 2;
-                                       break;
-                               }
-                               case OP_LOADR8_MEMBASE:
-                                       ins->opcode = OP_LOADI8_MEMBASE;
-                                       break;
-                               case OP_STORER8_MEMBASE_REG:
-                                       ins->opcode = OP_STOREI8_MEMBASE_REG;
-                                       break;
-                               case OP_STORER4_MEMBASE_REG: {
-                                       MonoInst *iargs [2];
-                                       int addr_reg;
-
-                                       /* Arg 1 is the double value */
-                                       MONO_INST_NEW (cfg, iargs [0], OP_ARG);
-                                       iargs [0]->dreg = ins->sreg1;
-
-                                       /* Arg 2 is the address to store to */
-                                       addr_reg = mono_alloc_preg (cfg);
-                                       EMIT_NEW_BIALU_IMM (cfg, iargs [1], OP_PADD_IMM, addr_reg, ins->inst_destbasereg, ins->inst_offset);
-                                       mono_emit_jit_icall (cfg, mono_fstore_r4, iargs);
-                                       restart = TRUE;
-                                       break;
-                               }
-                               case OP_LOADR4_MEMBASE: {
-                                       MonoInst *iargs [1];
-                                       MonoInst *conv;
-                                       int addr_reg;
-
-                                       addr_reg = mono_alloc_preg (cfg);
-                                       EMIT_NEW_BIALU_IMM (cfg, iargs [0], OP_PADD_IMM, addr_reg, ins->inst_basereg, ins->inst_offset);
-                                       conv = mono_emit_jit_icall (cfg, mono_fload_r4, iargs);
-                                       conv->dreg = ins->dreg;
-                                       break;
-                               }                                       
-                               case OP_FCALL:
-                               case OP_FCALL_REG:
-                               case OP_FCALL_MEMBASE: {
-                                       MonoCallInst *call = (MonoCallInst*)ins;
-                                       if (call->signature->ret->type == MONO_TYPE_R4) {
-                                               MonoCallInst *call2;
-                                               MonoInst *iargs [1];
-                                               MonoInst *conv;
-
-                                               /* Convert the call into a call returning an int */
-                                               MONO_INST_NEW_CALL (cfg, call2, OP_CALL);
-                                               memcpy (call2, call, sizeof (MonoCallInst));
-                                               switch (ins->opcode) {
-                                               case OP_FCALL:
-                                                       call2->inst.opcode = OP_CALL;
-                                                       break;
-                                               case OP_FCALL_REG:
-                                                       call2->inst.opcode = OP_CALL_REG;
-                                                       break;
-                                               case OP_FCALL_MEMBASE:
-                                                       call2->inst.opcode = OP_CALL_MEMBASE;
-                                                       break;
-                                               default:
-                                                       g_assert_not_reached ();
-                                               }
-                                               call2->inst.dreg = mono_alloc_ireg (cfg);
-                                               MONO_ADD_INS (cfg->cbb, (MonoInst*)call2);
-
-                                               /* FIXME: Optimize this */
-
-                                               /* Emit an r4->r8 conversion */
-                                               EMIT_NEW_VARLOADA_VREG (cfg, iargs [0], call2->inst.dreg, &mono_defaults.int32_class->byval_arg);
-                                               conv = mono_emit_jit_icall (cfg, mono_fload_r4, iargs);
-                                               conv->dreg = ins->dreg;
-                                       } else {
-                                               switch (ins->opcode) {
-                                               case OP_FCALL:
-                                                       ins->opcode = OP_LCALL;
-                                                       break;
-                                               case OP_FCALL_REG:
-                                                       ins->opcode = OP_LCALL_REG;
-                                                       break;
-                                               case OP_FCALL_MEMBASE:
-                                                       ins->opcode = OP_LCALL_MEMBASE;
-                                                       break;
-                                               default:
-                                                       g_assert_not_reached ();
-                                               }
-                                       }
-                                       break;
-                               }
-                               case OP_FCOMPARE: {
-                                       MonoJitICallInfo *info;
-                                       MonoInst *iargs [2];
-                                       MonoInst *call, *cmp, *br;
-
-                                       /* Convert fcompare+fbcc to icall+icompare+beq */
-
-                                       info = mono_find_jit_opcode_emulation (ins->next->opcode);
-                                       g_assert (info);
-
-                                       /* Create dummy MonoInst's for the arguments */
-                                       MONO_INST_NEW (cfg, iargs [0], OP_ARG);
-                                       iargs [0]->dreg = ins->sreg1;
-                                       MONO_INST_NEW (cfg, iargs [1], OP_ARG);
-                                       iargs [1]->dreg = ins->sreg2;
-
-                                       call = mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, iargs);
-
-                                       MONO_INST_NEW (cfg, cmp, OP_ICOMPARE_IMM);
-                                       cmp->sreg1 = call->dreg;
-                                       cmp->inst_imm = 0;
-                                       MONO_ADD_INS (cfg->cbb, cmp);
-                                       
-                                       MONO_INST_NEW (cfg, br, OP_IBNE_UN);
-                                       br->inst_many_bb = mono_mempool_alloc (cfg->mempool, sizeof (gpointer) * 2);
-                                       br->inst_true_bb = ins->next->inst_true_bb;
-                                       br->inst_false_bb = ins->next->inst_false_bb;
-                                       MONO_ADD_INS (cfg->cbb, br);
-
-                                       /* The call sequence might include fp ins */
-                                       restart = TRUE;
-
-                                       /* Skip fbcc or fccc */
-                                       NULLIFY_INS (ins->next);
-                                       break;
-                               }
-                               case OP_FCEQ:
-                               case OP_FCGT:
-                               case OP_FCGT_UN:
-                               case OP_FCLT:
-                               case OP_FCLT_UN: {
-                                       MonoJitICallInfo *info;
-                                       MonoInst *iargs [2];
-                                       MonoInst *call;
-
-                                       /* Convert fccc to icall+icompare+iceq */
-
-                                       info = mono_find_jit_opcode_emulation (ins->opcode);
-                                       g_assert (info);
-
-                                       /* Create dummy MonoInst's for the arguments */
-                                       MONO_INST_NEW (cfg, iargs [0], OP_ARG);
-                                       iargs [0]->dreg = ins->sreg1;
-                                       MONO_INST_NEW (cfg, iargs [1], OP_ARG);
-                                       iargs [1]->dreg = ins->sreg2;
-
-                                       call = mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, iargs);
-
-                                       MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, call->dreg, 1);
-                                       MONO_EMIT_NEW_UNALU (cfg, OP_ICEQ, ins->dreg, -1);
-
-                                       /* The call sequence might include fp ins */
-                                       restart = TRUE;
-                                       break;
-                               }
-                               case OP_CKFINITE: {
-                                       MonoInst *iargs [2];
-                                       MonoInst *call, *cmp;
-
-                                       /* Convert to icall+icompare+cond_exc+move */
-
-                                       /* Create dummy MonoInst's for the arguments */
-                                       MONO_INST_NEW (cfg, iargs [0], OP_ARG);
-                                       iargs [0]->dreg = ins->sreg1;
-
-                                       call = mono_emit_jit_icall (cfg, mono_isfinite, iargs);
-
-                                       MONO_INST_NEW (cfg, cmp, OP_ICOMPARE_IMM);
-                                       cmp->sreg1 = call->dreg;
-                                       cmp->inst_imm = 1;
-                                       MONO_ADD_INS (cfg->cbb, cmp);
-
-                                       MONO_EMIT_NEW_COND_EXC (cfg, INE_UN, "ArithmeticException");
-
-                                       /* Do the assignment if the value is finite */
-                                       MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, ins->dreg, ins->sreg1);
-
-                                       restart = TRUE;
-                                       break;
-                               }
-                               default:
-                                       if (spec [MONO_INST_SRC1] == 'f' || spec [MONO_INST_SRC2] == 'f' || spec [MONO_INST_DEST] == 'f') {
-                                               mono_print_ins (ins);
-                                               g_assert_not_reached ();
-                                       }
-                                       break;
-                               }
-
-                               g_assert (cfg->cbb == first_bb);
-
-                               if (cfg->cbb->code || (cfg->cbb != first_bb)) {
-                                       /* Replace the original instruction with the new code sequence */
-
-                                       mono_replace_ins (cfg, bb, ins, &prev, first_bb, cfg->cbb);
-                                       first_bb->code = first_bb->last_ins = NULL;
-                                       first_bb->in_count = first_bb->out_count = 0;
-                                       cfg->cbb = first_bb;
-                               }
-                               else
-                                       prev = ins;
-                       }
-               }
+{
+       char *method_fname = mono_method_full_name (method, TRUE);
+       char *method_code;
 
-               if (cfg->verbose_level > 3) mono_print_bb (bb, "AFTER HANDLE-SOFT-FLOAT ");
-       }
+       if (mono_method_get_header (method)->code_size == 0)
+               method_code = g_strdup ("method body is empty.");
+       else
+               method_code = mono_disasm_code_one (NULL, method, ip, NULL);
+       cfg->exception_type = MONO_EXCEPTION_INVALID_PROGRAM;
+       cfg->exception_message = g_strdup_printf ("Invalid IL code in %s: %s\n", method_fname, method_code);
+       g_free (method_fname);
+       g_free (method_code);
+}
 
-       mono_decompose_long_opts (cfg);
+static void
+set_exception_object (MonoCompile *cfg, MonoException *exception)
+{
+       cfg->exception_type = MONO_EXCEPTION_OBJECT_SUPPLIED;
+       MONO_GC_REGISTER_ROOT (cfg->exception_ptr);
+       cfg->exception_ptr = exception;
 }
 
-#endif
+static gboolean
+generic_class_is_reference_type (MonoCompile *cfg, MonoClass *klass)
+{
+       MonoType *type;
+
+       if (cfg->generic_sharing_context)
+               type = mini_get_basic_type_from_generic (cfg->generic_sharing_context, &klass->byval_arg);
+       else
+               type = &klass->byval_arg;
+       return MONO_TYPE_IS_REFERENCE (type);
+}
 
 static void
 emit_stloc_ir (MonoCompile *cfg, MonoInst **sp, MonoMethodHeader *header, int n)
@@ -5197,8 +5110,10 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                   MonoInst *return_var, GList *dont_inline, MonoInst **inline_args, 
                   guint inline_offset, gboolean is_virtual_call)
 {
+       MonoError error;
        MonoInst *ins, **sp, **stack_start;
        MonoBasicBlock *bblock, *tblock = NULL, *init_localsbb = NULL;
+       MonoSimpleBasicBlock *bb = NULL;
        MonoMethod *cmethod, *method_definition;
        MonoInst **arg_array;
        MonoMethodHeader *header;
@@ -5222,6 +5137,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
        GSList *class_inits = NULL;
        gboolean dont_verify, dont_verify_stloc, readonly = FALSE;
        int context_used;
+       gboolean init_locals, seq_points, skip_dead_blocks;
 
        /* serialization and xdomain stuff may need access to private fields and methods */
        dont_verify = method->klass->image->assembly->corlib_internal? TRUE: FALSE;
@@ -5247,6 +5163,15 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
        cfg->cil_start = ip;
        end = ip + header->code_size;
        mono_jit_stats.cil_code_size += header->code_size;
+       init_locals = header->init_locals;
+
+       seq_points = cfg->gen_seq_points && cfg->method == method;
+
+       /* 
+        * Methods without init_locals set could cause asserts in various passes
+        * (#497220).
+        */
+       init_locals = TRUE;
 
        method_definition = method;
        while (method_definition->is_inflated) {
@@ -5479,7 +5404,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                }
        }
        
-       if ((header->init_locals || (cfg->method == method && (cfg->opt & MONO_OPT_SHARED))) || cfg->compile_aot || security || pinvoke) {
+       if ((init_locals || (cfg->method == method && (cfg->opt & MONO_OPT_SHARED))) || cfg->compile_aot || security || pinvoke) {
                /* we use a separate basic block for the initialization code */
                NEW_BBLOCK (cfg, init_localsbb);
                cfg->bb_init = init_localsbb;
@@ -5531,12 +5456,20 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
        }
 
        if (mono_security_get_mode () == MONO_SECURITY_MODE_CORE_CLR) {
+               /* check if this is native code, e.g. an icall or a p/invoke */
                if (method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) {
                        MonoMethod *wrapped = mono_marshal_method_from_wrapper (method);
-                       if (wrapped && (wrapped->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
-                               if (!(method->klass && method->klass->image &&
-                                               mono_security_core_clr_is_platform_image (method->klass->image))) {
-                                       emit_throw_method_access_exception (cfg, method, wrapped, bblock, ip);
+                       if (wrapped) {
+                               gboolean pinvk = (wrapped->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL);
+                               gboolean icall = (wrapped->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL);
+
+                               /* if this ia a native call then it can only be JITted from platform code */
+                               if ((icall || pinvk) && method->klass && method->klass->image) {
+                                       if (!mono_security_core_clr_is_platform_image (method->klass->image)) {
+                                               MonoException *ex = icall ? mono_get_exception_security () : 
+                                                       mono_get_exception_method_access ();
+                                               emit_throw_exception (cfg, ex);
+                                       }
                                }
                        }
                }
@@ -5581,9 +5514,17 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
 
                NEW_ARGLOAD (cfg, arg_ins, 0);
                MONO_ADD_INS (cfg->cbb, arg_ins);
-               cfg->flags |= MONO_CFG_HAS_CHECK_THIS;
-               MONO_EMIT_NEW_UNALU (cfg, OP_CHECK_THIS, -1, arg_ins->dreg);
-               MONO_EMIT_NEW_UNALU (cfg, OP_NOT_NULL, -1, arg_ins->dreg);
+               MONO_EMIT_NEW_CHECK_THIS (cfg, arg_ins->dreg);
+       }
+
+       skip_dead_blocks = !dont_verify;
+       if (skip_dead_blocks) {
+               bb = mono_basic_block_split (method, &error);
+               if (!mono_error_ok (&error)) {
+                       mono_error_cleanup (&error);
+                       UNVERIFIED;
+               }
+               g_assert (bb);
        }
 
        /* we use a spare stack slot in SWITCH and NEWOBJ and others */
@@ -5593,7 +5534,6 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
        start_new_bblock = 0;
        cfg->cbb = bblock;
        while (ip < end) {
-
                if (cfg->method == method)
                        cfg->real_offset = ip - header->code;
                else
@@ -5644,6 +5584,38 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        }
                }
 
+               if (skip_dead_blocks) {
+                       int ip_offset = ip - header->code;
+
+                       if (ip_offset == bb->end)
+                               bb = bb->next;
+
+                       if (bb->dead) {
+                               int op_size = mono_opcode_size (ip, end);
+                               g_assert (op_size > 0); /*The BB formation pass must catch all bad ops*/
+
+                               if (cfg->verbose_level > 3) printf ("SKIPPING DEAD OP at %x\n", ip_offset);
+
+                               if (ip_offset + op_size == bb->end) {
+                                       MONO_INST_NEW (cfg, ins, OP_NOP);
+                                       MONO_ADD_INS (bblock, ins);
+                                       start_new_bblock = 1;
+                               }
+
+                               ip += op_size;
+                               continue;
+                       }
+               }
+               /*
+                * Sequence points are points where the debugger can place a breakpoint.
+                * Currently, we generate these automatically at points where the IL
+                * stack is empty.
+                */
+               if (seq_points && sp == stack_start) {
+                       NEW_SEQ_POINT (cfg, ins, ip - header->code, TRUE);
+                       MONO_ADD_INS (cfg->cbb, ins);
+               }
+
                bblock->real_offset = cfg->real_offset;
 
                if ((cfg->method == method) && cfg->coverage_info) {
@@ -5651,7 +5623,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        cfg->coverage_info->data [cil_offset].cil_code = ip;
 
                        /* TODO: Use an increment here */
-#if defined(__i386__)
+#if defined(TARGET_X86)
                        MONO_INST_NEW (cfg, ins, OP_STORE_MEM_IMM);
                        ins->inst_p0 = &(cfg->coverage_info->data [cil_offset].count);
                        ins->inst_imm = 1;
@@ -5675,7 +5647,10 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        MONO_ADD_INS (bblock, ins);
                        break;
                case CEE_BREAK:
-                       MONO_INST_NEW (cfg, ins, OP_BREAK);
+                       if (should_insert_brekpoint (cfg->method))
+                               MONO_INST_NEW (cfg, ins, OP_BREAK);
+                       else
+                               MONO_INST_NEW (cfg, ins, OP_NOP);
                        ip++;
                        MONO_ADD_INS (bblock, ins);
                        break;
@@ -5839,38 +5814,76 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        break;
                case CEE_LDC_R4: {
                        float *f;
+                       gboolean use_aotconst = FALSE;
+
+#ifdef TARGET_POWERPC
+                       /* FIXME: Clean this up */
+                       if (cfg->compile_aot)
+                               use_aotconst = TRUE;
+#endif
+
                        /* FIXME: we should really allocate this only late in the compilation process */
                        f = mono_domain_alloc (cfg->domain, sizeof (float));
                        CHECK_OPSIZE (5);
                        CHECK_STACK_OVF (1);
-                       MONO_INST_NEW (cfg, ins, OP_R4CONST);
-                       ins->type = STACK_R8;
-                       ins->dreg = alloc_dreg (cfg, STACK_R8);
+
+                       if (use_aotconst) {
+                               MonoInst *cons;
+                               int dreg;
+
+                               EMIT_NEW_AOTCONST (cfg, cons, MONO_PATCH_INFO_R4, f);
+
+                               dreg = alloc_freg (cfg);
+                               EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADR4_MEMBASE, dreg, cons->dreg, 0);
+                               ins->type = STACK_R8;
+                       } else {
+                               MONO_INST_NEW (cfg, ins, OP_R4CONST);
+                               ins->type = STACK_R8;
+                               ins->dreg = alloc_dreg (cfg, STACK_R8);
+                               ins->inst_p0 = f;
+                               MONO_ADD_INS (bblock, ins);
+                       }
                        ++ip;
                        readr4 (ip, f);
-                       ins->inst_p0 = f;
-                       MONO_ADD_INS (bblock, ins);
-                       
                        ip += 4;
                        *sp++ = ins;                    
                        break;
                }
                case CEE_LDC_R8: {
                        double *d;
+                       gboolean use_aotconst = FALSE;
+
+#ifdef TARGET_POWERPC
+                       /* FIXME: Clean this up */
+                       if (cfg->compile_aot)
+                               use_aotconst = TRUE;
+#endif
+
                        /* FIXME: we should really allocate this only late in the compilation process */
                        d = mono_domain_alloc (cfg->domain, sizeof (double));
                        CHECK_OPSIZE (9);
                        CHECK_STACK_OVF (1);
-                       MONO_INST_NEW (cfg, ins, OP_R8CONST);
-                       ins->type = STACK_R8;
-                       ins->dreg = alloc_dreg (cfg, STACK_R8);
+
+                       if (use_aotconst) {
+                               MonoInst *cons;
+                               int dreg;
+
+                               EMIT_NEW_AOTCONST (cfg, cons, MONO_PATCH_INFO_R8, d);
+
+                               dreg = alloc_freg (cfg);
+                               EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADR8_MEMBASE, dreg, cons->dreg, 0);
+                               ins->type = STACK_R8;
+                       } else {
+                               MONO_INST_NEW (cfg, ins, OP_R8CONST);
+                               ins->type = STACK_R8;
+                               ins->dreg = alloc_dreg (cfg, STACK_R8);
+                               ins->inst_p0 = d;
+                               MONO_ADD_INS (bblock, ins);
+                       }
                        ++ip;
                        readr8 (ip, d);
-                       ins->inst_p0 = d;
-                       MONO_ADD_INS (bblock, ins);
-
                        ip += 8;
-                       *sp++ = ins;                    
+                       *sp++ = ins;
                        break;
                }
                case CEE_DUP: {
@@ -5898,7 +5911,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        ip++;
                        --sp;
 
-#ifdef __i386__
+#ifdef TARGET_X86
                        if (sp [0]->type == STACK_R8)
                                /* we need to pop the value from the x86 FP stack */
                                MONO_EMIT_NEW_UNALU (cfg, OP_X86_FPOP, -1, sp [0]->dreg);
@@ -5925,7 +5938,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        if (mono_security_get_mode () == MONO_SECURITY_MODE_CAS)
                                CHECK_CFG_EXCEPTION;
 
-#ifdef __x86_64__
+#ifdef MONO_ARCH_USE_OP_TAIL_CALL
                        {
                                MonoMethodSignature *fsig = mono_method_signature (cmethod);
                                int i, n;
@@ -5974,6 +5987,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        gboolean pass_mrgctx = FALSE;
                        MonoInst *vtable_arg = NULL;
                        gboolean check_this = FALSE;
+                       gboolean supported_tail_call = FALSE;
 
                        CHECK_OPSIZE (5);
                        token = read32 (ip + 1);
@@ -5989,6 +6003,21 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                        fsig = mono_metadata_parse_signature (image, token);
 
                                n = fsig->param_count + fsig->hasthis;
+
+                               if (method->dynamic && fsig->pinvoke) {
+                                       MonoInst *args [3];
+
+                                       /*
+                                        * This is a call through a function pointer using a pinvoke
+                                        * signature. Have to create a wrapper and call that instead.
+                                        * FIXME: This is very slow, need to create a wrapper at JIT time
+                                        * instead based on the signature.
+                                        */
+                                       EMIT_NEW_IMAGECONST (cfg, args [0], method->klass->image);
+                                       EMIT_NEW_PCONST (cfg, args [1], fsig);
+                                       args [2] = addr;
+                                       addr = mono_emit_jit_icall (cfg, mono_get_native_calli_wrapper, args);
+                               }
                        } else {
                                MonoMethod *cil_method;
                                
@@ -6084,17 +6113,15 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                 * We have the `constrained.' prefix opcode.
                                 */
                                if (constrained_call->valuetype && !cmethod->klass->valuetype) {
-                                       int dreg;
-
                                        /*
                                         * The type parameter is instantiated as a valuetype,
                                         * but that type doesn't override the method we're
                                         * calling, so we need to box `this'.
                                         */
-                                       dreg = alloc_dreg (cfg, STACK_VTYPE);
-                                       EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADV_MEMBASE, dreg, sp [0]->dreg, 0);
+                                       EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_call->byval_arg, sp [0]->dreg, 0);
                                        ins->klass = constrained_call;
                                        sp [0] = handle_box (cfg, ins, constrained_call);
+                                       CHECK_CFG_EXCEPTION;
                                } else if (!constrained_call->valuetype) {
                                        int dreg = alloc_preg (cfg);
 
@@ -6114,6 +6141,14 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        if (*ip != CEE_CALLI && check_call_signature (cfg, fsig, sp))
                                UNVERIFIED;
 
+                       /* 
+                        * If the callee is a shared method, then its static cctor
+                        * might not get called after the call was patched.
+                        */
+                       if (cfg->generic_sharing_context && cmethod && cmethod->klass != method->klass && cmethod->klass->generic_class && mono_method_is_generic_sharable_impl (cmethod, TRUE) && mono_class_needs_cctor_run (cmethod->klass, method)) {
+                               emit_generic_class_init (cfg, cmethod->klass);
+                               CHECK_TYPELOAD (cmethod->klass);
+                       }
 
                        if (cmethod && ((cmethod->flags & METHOD_ATTRIBUTE_STATIC) || cmethod->klass->valuetype) &&
                                        (cmethod->klass->generic_class || cmethod->klass->generic_container)) {
@@ -6189,12 +6224,17 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        if (pass_mrgctx) {
                                g_assert (!vtable_arg);
 
-                               if (context_used) {
-                                       vtable_arg = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_METHOD_RGCTX);
-                               } else {
-                                       EMIT_NEW_METHOD_RGCTX_CONST (cfg, vtable_arg, cmethod);
+                               if (!cfg->compile_aot) {
+                                       /* 
+                                        * emit_get_rgctx_method () calls mono_class_vtable () so check 
+                                        * for type load errors before.
+                                        */
+                                       mono_class_vtable (cfg->domain, cmethod->klass);
+                                       CHECK_TYPELOAD (cmethod->klass);
                                }
 
+                               vtable_arg = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_METHOD_RGCTX);
+
                                if (!(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) ||
                                                MONO_METHOD_IS_FINAL (cmethod)) {
                                        if (virtual)
@@ -6211,13 +6251,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                        cmethod, MONO_RGCTX_INFO_METHOD);
                        }
 
-                       if (check_this) {
-                               MonoInst *check;
-
-                               MONO_INST_NEW (cfg, check, OP_CHECK_THIS);
-                               check->sreg1 = sp [0]->dreg;
-                               MONO_ADD_INS (cfg->cbb, check);
-                       }
+                       if (check_this)
+                               MONO_EMIT_NEW_CHECK_THIS (cfg, sp [0]->dreg);
 
                        /* Calling virtual generic methods */
                        if (cmethod && virtual && 
@@ -6234,16 +6269,13 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                INLINE_FAILURE;
 
 #if MONO_ARCH_HAVE_GENERALIZED_IMT_THUNK
-                               if (cmethod->wrapper_type == MONO_WRAPPER_NONE && mono_use_imt) {
+                               /* The llvm vcall trampolines doesn't support generic virtual calls yet */
+                               if (cmethod->wrapper_type == MONO_WRAPPER_NONE && mono_use_imt && !mono_use_llvm) {
                                        g_assert (!imt_arg);
-                                       if (context_used) {
-                                               imt_arg = emit_get_rgctx_method (cfg, context_used,
-                                                       cmethod, MONO_RGCTX_INFO_METHOD);
-
-                                       } else {
+                                       if (!context_used)
                                                g_assert (cmethod->is_inflated);
-                                               EMIT_NEW_METHODCONST (cfg, imt_arg, cmethod);
-                                       }
+                                       imt_arg = emit_get_rgctx_method (cfg, context_used,
+                                                                                                        cmethod, MONO_RGCTX_INFO_METHOD);
                                        ins = mono_emit_method_call_full (cfg, cmethod, fsig, sp, sp [0], imt_arg);
                                } else
 #endif
@@ -6256,17 +6288,11 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                        this_arg_temp = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
 
                                        EMIT_NEW_TEMPLOAD (cfg, iargs [0], this_temp->inst_c0);
-                                       if (context_used) {
-                                               iargs [1] = emit_get_rgctx_method (cfg, context_used,
-                                                       cmethod, MONO_RGCTX_INFO_METHOD);
-                                               EMIT_NEW_TEMPLOADA (cfg, iargs [2], this_arg_temp->inst_c0);
-                                               addr = mono_emit_jit_icall (cfg,
-                                                               mono_helper_compile_generic_method, iargs);
-                                       } else {
-                                               EMIT_NEW_METHODCONST (cfg, iargs [1], cmethod);
-                                               EMIT_NEW_TEMPLOADA (cfg, iargs [2], this_arg_temp->inst_c0);
-                                               addr = mono_emit_jit_icall (cfg, mono_helper_compile_generic_method, iargs);
-                                       }
+                                       iargs [1] = emit_get_rgctx_method (cfg, context_used,
+                                                                                                          cmethod, MONO_RGCTX_INFO_METHOD);
+                                       EMIT_NEW_TEMPLOADA (cfg, iargs [2], this_arg_temp->inst_c0);
+                                       addr = mono_emit_jit_icall (cfg,
+                                                                                               mono_helper_compile_generic_method, iargs);
 
                                        EMIT_NEW_TEMPLOAD (cfg, sp [0], this_arg_temp->inst_c0);
 
@@ -6281,27 +6307,30 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                break;
                        }
 
+#ifdef MONO_ARCH_USE_OP_TAIL_CALL
+                       supported_tail_call = cmethod && MONO_ARCH_USE_OP_TAIL_CALL (mono_method_signature (method), mono_method_signature (cmethod));
+#else
+                       supported_tail_call = cmethod && mono_metadata_signature_equal (mono_method_signature (method), mono_method_signature (cmethod)) && !MONO_TYPE_ISSTRUCT (mono_method_signature (cmethod)->ret);
+#endif
+
                        /* Tail prefix */
                        /* FIXME: runtime generic context pointer for jumps? */
                        /* FIXME: handle this for generic sharing eventually */
-                       if ((ins_flag & MONO_INST_TAILCALL) && !cfg->generic_sharing_context && !vtable_arg && cmethod && (*ip == CEE_CALL) &&
-                               (mono_metadata_signature_equal (mono_method_signature (method), mono_method_signature (cmethod))) && !MONO_TYPE_ISSTRUCT (mono_method_signature (cmethod)->ret)) {
+                       if ((ins_flag & MONO_INST_TAILCALL) && !cfg->generic_sharing_context && !vtable_arg && cmethod && (*ip == CEE_CALL) && supported_tail_call) {
                                MonoCallInst *call;
 
                                /* Prevent inlining of methods with tail calls (the call stack would be altered) */
                                INLINE_FAILURE;
 
+#ifdef MONO_ARCH_USE_OP_TAIL_CALL
+                               /* Handle tail calls similarly to calls */
+                               call = mono_emit_call_args (cfg, mono_method_signature (cmethod), sp, FALSE, FALSE, TRUE);
+#else
                                MONO_INST_NEW_CALL (cfg, call, OP_JMP);
                                call->tail_call = TRUE;
                                call->method = cmethod;
                                call->signature = mono_method_signature (cmethod);
 
-#ifdef __x86_64__
-                               /* Handle tail calls similarly to calls */
-                               call->inst.opcode = OP_TAILCALL;
-                               call->args = sp;
-                               mono_arch_emit_call (cfg, call);
-#else
                                /*
                                 * We implement tail calls by storing the actual arguments into the 
                                 * argument variables, then emitting a CEE_JMP.
@@ -6467,6 +6496,9 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                                 */
                                                ins = (MonoInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_ICALL_ADDR, addr->inst_p0, fsig, sp);
                                                NULLIFY_INS (addr);
+                                       } else if (addr->opcode == OP_GOT_ENTRY && addr->inst_right->inst_c1 == MONO_PATCH_INFO_ICALL_ADDR) {
+                                               ins = (MonoInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_ICALL_ADDR, addr->inst_right->inst_left, fsig, sp);
+                                               NULLIFY_INS (addr);
                                        } else {
                                                ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr);
                                        }
@@ -6504,6 +6536,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                } else if (strcmp (cmethod->name, "Address") == 0) { /* array Address */
                                        if (!cmethod->klass->element_class->valuetype && !readonly)
                                                mini_emit_check_array_type (cfg, sp [0], cmethod->klass);
+                                       CHECK_TYPELOAD (cmethod->klass);
                                        
                                        readonly = FALSE;
                                        addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, FALSE);
@@ -6566,6 +6599,18 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                if (cfg->ret) {
                                        MonoType *ret_type = mono_method_signature (method)->ret;
 
+                                       if (seq_points) {
+                                               /* 
+                                                * Place a seq point here too even through the IL stack is not
+                                                * empty, so a step over on
+                                                * call <FOO>
+                                                * ret
+                                                * will work correctly.
+                                                */
+                                               NEW_SEQ_POINT (cfg, ins, ip - header->code, TRUE);
+                                               MONO_ADD_INS (cfg->cbb, ins);
+                                       }
+
                                        g_assert (!return_var);
                                        CHECK_STACK (1);
                                        --sp;
@@ -6584,7 +6629,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                                }
                                        } else {
 #ifdef MONO_ARCH_SOFT_FLOAT
-                                               if (!ret_type->byref && ret_type->type == MONO_TYPE_R4) {
+                                               if (COMPILE_SOFT_FLOAT (cfg) && !ret_type->byref && ret_type->type == MONO_TYPE_R4) {
                                                        MonoInst *iargs [1];
                                                        MonoInst *conv;
 
@@ -6812,7 +6857,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        table->table_size = n;
 
                        use_op_switch = FALSE;
-#ifdef __arm__
+#ifdef TARGET_ARM
                        /* ARM implements SWITCH statements differently */
                        /* FIXME: Make it use the generic implementation */
                        if (!cfg->compile_aot)
@@ -6822,6 +6867,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        if (COMPILE_LLVM (cfg))
                                use_op_switch = TRUE;
 
+                       cfg->cbb->has_jump_table = 1;
+
                        if (use_op_switch) {
                                MONO_INST_NEW (cfg, ins, OP_SWITCH);
                                ins->sreg1 = src1->dreg;
@@ -6904,21 +6951,19 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        CHECK_STACK (2);
                        sp -= 2;
 
+                       NEW_STORE_MEMBASE (cfg, ins, stind_to_store_membase (*ip), sp [0]->dreg, 0, sp [1]->dreg);
+                       ins->flags |= ins_flag;
+                       ins_flag = 0;
+                       MONO_ADD_INS (bblock, ins);
+
 #if HAVE_WRITE_BARRIERS
                        if (*ip == CEE_STIND_REF && method->wrapper_type != MONO_WRAPPER_WRITE_BARRIER && !((sp [1]->opcode == OP_PCONST) && (sp [1]->inst_p0 == 0))) {
                                /* insert call to write barrier */
                                MonoMethod *write_barrier = mono_gc_get_write_barrier ();
                                mono_emit_method_call (cfg, write_barrier, sp, NULL);
-                               ins_flag = 0;
-                               ip++;
-                               break;
                        }
 #endif
 
-                       NEW_STORE_MEMBASE (cfg, ins, stind_to_store_membase (*ip), sp [0]->dreg, 0, sp [1]->dreg);
-                       ins->flags |= ins_flag;
-                       ins_flag = 0;
-                       MONO_ADD_INS (bblock, ins);
                        inline_costs += 1;
                        ++ip;
                        break;
@@ -6992,7 +7037,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
 #endif
                                        }
                                        else
-                                               ins->inst_p1 = (gpointer)(gssize)(sp [1]->inst_c0);
+                                               ins->inst_imm = (gssize)(sp [1]->inst_c0);
                                        ins->sreg2 = -1;
 
                                        /* Might be followed by an instruction added by ADD_WIDEN_OP */
@@ -7164,7 +7209,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
 
                        /* Optimize the ldobj+stobj combination */
                        /* The reference case ends up being a load+store anyway */
-                       if (((ip [5] == CEE_STOBJ) && ip_in_bb (cfg, bblock, ip + 9) && read32 (ip + 6) == token) && !generic_class_is_reference_type (cfg, klass)) {
+                       if (((ip [5] == CEE_STOBJ) && ip_in_bb (cfg, bblock, ip + 5) && read32 (ip + 6) == token) && !generic_class_is_reference_type (cfg, klass)) {
                                CHECK_STACK (1);
 
                                sp --;
@@ -7261,6 +7306,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        if (!cmethod)
                                goto load_error;
                        fsig = mono_method_get_signature (cmethod, image, token);
+                       if (!fsig)
+                               goto load_error;
 
                        mono_save_token_info (cfg, image, token, cmethod);
 
@@ -7281,12 +7328,11 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        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) {
-                                               vtable_arg = emit_get_rgctx_method (cfg, context_used,
-                                                       cmethod, MONO_RGCTX_INFO_METHOD_RGCTX);
-                                       } else {
-                                               EMIT_NEW_METHOD_RGCTX_CONST (cfg, vtable_arg, cmethod);
-                                       }
+                                       mono_class_vtable (cfg->domain, cmethod->klass);
+                                       CHECK_TYPELOAD (cmethod->klass);
+
+                                       vtable_arg = emit_get_rgctx_method (cfg, context_used,
+                                                                                                               cmethod, MONO_RGCTX_INFO_METHOD_RGCTX);
                                } else {
                                        if (context_used) {
                                                vtable_arg = emit_get_rgctx_klass (cfg, context_used,
@@ -7357,18 +7403,16 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        if (mini_class_is_system_array (cmethod->klass)) {
                                g_assert (!vtable_arg);
 
-                               if (context_used) {
-                                       *sp = emit_get_rgctx_method (cfg, context_used,
-                                               cmethod, MONO_RGCTX_INFO_METHOD);
-                               } else {
-                                       EMIT_NEW_METHODCONST (cfg, *sp, cmethod);
-                               }
+                               *sp = emit_get_rgctx_method (cfg, context_used,
+                                                                                        cmethod, MONO_RGCTX_INFO_METHOD);
 
                                /* Avoid varargs in the common case */
                                if (fsig->param_count == 1)
                                        alloc = mono_emit_jit_icall (cfg, mono_array_new_1, sp);
                                else if (fsig->param_count == 2)
                                        alloc = mono_emit_jit_icall (cfg, mono_array_new_2, sp);
+                               else if (fsig->param_count == 3)
+                                       alloc = mono_emit_jit_icall (cfg, mono_array_new_3, sp);
                                else
                                        alloc = handle_array_new (cfg, fsig->param_count, sp, ip);
                        } else if (cmethod->string_ctor) {
@@ -7425,6 +7469,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                        alloc = handle_alloc (cfg, cmethod->klass, FALSE);
                                        *sp = alloc;
                                }
+                               CHECK_CFG_EXCEPTION; /*for handle_alloc*/
 
                                if (alloc)
                                        MONO_EMIT_NEW_UNALU (cfg, OP_NOT_NULL, -1, alloc->dreg);
@@ -7462,8 +7507,6 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                        INLINE_FAILURE;
                                        ins = mono_emit_rgctx_method_call_full (cfg, cmethod, fsig, sp,
                                                                                                                        callvirt_this_arg, NULL, vtable_arg);
-                                       if (mono_method_is_generic_sharable_impl (cmethod, TRUE) && ((MonoCallInst*)ins)->method->wrapper_type == MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK)
-                                               GENERIC_SHARING_FAILURE (*ip);
                                }
                        }
 
@@ -7493,21 +7536,20 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        if (cfg->generic_sharing_context)
                                context_used = mono_class_check_context_used (klass);
 
-                       if (context_used) {
+                       if (!context_used && mono_class_has_variant_generic_params (klass)) {
                                MonoInst *args [2];
 
                                /* obj */
                                args [0] = *sp;
 
                                /* klass */
-                               args [1] = emit_get_rgctx_klass (cfg, context_used,
-                                       klass, MONO_RGCTX_INFO_KLASS);
+                               EMIT_NEW_CLASSCONST (cfg, args [1], klass);
 
                                ins = mono_emit_jit_icall (cfg, mono_object_castclass, args);
                                *sp ++ = ins;
                                ip += 5;
                                inline_costs += 2;
-                       } else if (klass->marshalbyref || klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
+                       } else if (!context_used && (klass->marshalbyref || klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
                                MonoMethod *mono_castclass;
                                MonoInst *iargs [1];
                                int costs;
@@ -7528,7 +7570,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                inline_costs += costs;
                        }
                        else {
-                               ins = handle_castclass (cfg, klass, *sp);
+                               ins = handle_castclass (cfg, klass, *sp, context_used);
+                               CHECK_CFG_EXCEPTION;
                                bblock = cfg->cbb;
                                *sp ++ = ins;
                                ip += 5;
@@ -7547,20 +7590,20 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        if (cfg->generic_sharing_context)
                                context_used = mono_class_check_context_used (klass);
 
-                       if (context_used) {
+                       if (!context_used && mono_class_has_variant_generic_params (klass)) {
                                MonoInst *args [2];
 
                                /* obj */
                                args [0] = *sp;
 
                                /* klass */
-                               args [1] = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
+                               EMIT_NEW_CLASSCONST (cfg, args [1], klass);
 
                                *sp = mono_emit_jit_icall (cfg, mono_object_isinst, args);
                                sp++;
                                ip += 5;
                                inline_costs += 2;
-                       } else if (klass->marshalbyref || klass->flags & TYPE_ATTRIBUTE_INTERFACE) {                    
+                       } else if (!context_used && (klass->marshalbyref || klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
                                MonoMethod *mono_isinst;
                                MonoInst *iargs [1];
                                int costs;
@@ -7581,7 +7624,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                inline_costs += costs;
                        }
                        else {
-                               ins = handle_isinst (cfg, klass, *sp);
+                               ins = handle_isinst (cfg, klass, *sp, context_used);
+                               CHECK_CFG_EXCEPTION;
                                bblock = cfg->cbb;
                                *sp ++ = ins;
                                ip += 5;
@@ -7602,7 +7646,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                context_used = mono_class_check_context_used (klass);
 
                        if (generic_class_is_reference_type (cfg, klass)) {
-                               /* CASTCLASS */
+                               /* CASTCLASS FIXME kill this huge slice of duplicated code*/
                                if (context_used) {
                                        MonoInst *iargs [2];
 
@@ -7634,7 +7678,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                        *sp++ = iargs [0];
                                        inline_costs += costs;
                                } else {
-                                       ins = handle_castclass (cfg, klass, *sp);
+                                       ins = handle_castclass (cfg, klass, *sp, 0);
+                                       CHECK_CFG_EXCEPTION;
                                        bblock = cfg->cbb;
                                        *sp ++ = ins;
                                        ip += 5;
@@ -7741,6 +7786,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                *sp++ = handle_box (cfg, val, klass);
                        }
 
+                       CHECK_CFG_EXCEPTION;
                        ip += 5;
                        inline_costs += 1;
                        break;
@@ -7827,7 +7873,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                                    field->offset);
                                        iargs [4] = sp [1];
 
-                                       if (cfg->opt & MONO_OPT_INLINE) {
+                                       if (cfg->opt & MONO_OPT_INLINE || cfg->compile_aot) {
                                                costs = inline_method (cfg, stfld_wrapper, mono_method_signature (stfld_wrapper), 
                                                                       iargs, ip, cfg->real_offset, dont_inline, TRUE);
                                                g_assert (costs > 0);
@@ -7842,6 +7888,10 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                } else {
                                        MonoInst *store;
 
+                                       MONO_EMIT_NULL_CHECK (cfg, sp [0]->dreg);
+
+                                       EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, field->type, sp [0]->dreg, foffset, sp [1]->dreg);
+
 #if HAVE_WRITE_BARRIERS
                                if (mini_type_to_stind (cfg, field->type) == CEE_STIND_REF && !(sp [1]->opcode == OP_PCONST && sp [1]->inst_c0 == 0)) {
                                        /* insert call to write barrier */
@@ -7856,8 +7906,6 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                }
 #endif
 
-                                       EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, field->type, sp [0]->dreg, foffset, sp [1]->dreg);
-                                               
                                        store->flags |= ins_flag;
                                }
                                ins_flag = 0;
@@ -7904,6 +7952,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                        sp [0] = ins;
                                }
 
+                               MONO_EMIT_NULL_CHECK (cfg, sp [0]->dreg);
+
                                if (*ip == CEE_LDFLDA) {
                                        dreg = alloc_preg (cfg);
 
@@ -7916,6 +7966,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
 
                                        EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, field->type, sp [0]->dreg, foffset);
                                        load->flags |= ins_flag;
+                                       load->flags |= MONO_INST_FAULT;
                                        *sp++ = load;
                                }
                        }
@@ -8227,19 +8278,44 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        if (cfg->generic_sharing_context)
                                context_used = mono_class_check_context_used (klass);
 
+                       if (sp [0]->type == STACK_I8 || (SIZEOF_VOID_P == 8 && sp [0]->type == STACK_PTR)) {
+                               MONO_INST_NEW (cfg, ins, OP_LCONV_TO_I4);
+                               ins->sreg1 = sp [0]->dreg;
+                               ins->type = STACK_I4;
+                               ins->dreg = alloc_ireg (cfg);
+                               MONO_ADD_INS (cfg->cbb, ins);
+                               *sp = mono_decompose_opcode (cfg, ins);
+                       }
+
                        if (context_used) {
-                               MonoInst *args [2];
+                               MonoInst *args [3];
+                               MonoClass *array_class = mono_array_class_get (klass, 1);
+                               /* FIXME: we cannot get a managed
+                                  allocator because we can't get the
+                                  open generic class's vtable.  We
+                                  have the same problem in
+                                  handle_alloc_from_inst().  This
+                                  needs to be solved so that we can
+                                  have managed allocs of shared
+                                  generic classes. */
+                               /*
+                               MonoVTable *array_class_vtable = mono_class_vtable (cfg->domain, array_class);
+                               MonoMethod *managed_alloc = mono_gc_get_managed_array_allocator (array_class_vtable, 1);
+                               */
+                               MonoMethod *managed_alloc = NULL;
 
                                /* FIXME: Decompose later to help abcrem */
 
                                /* vtable */
                                args [0] = emit_get_rgctx_klass (cfg, context_used,
-                                       mono_array_class_get (klass, 1), MONO_RGCTX_INFO_VTABLE);
-
+                                       array_class, MONO_RGCTX_INFO_VTABLE);
                                /* array len */
                                args [1] = sp [0];
 
-                               ins = mono_emit_jit_icall (cfg, mono_array_new_specific, args);
+                               if (managed_alloc)
+                                       ins = mono_emit_method_call (cfg, managed_alloc, args, NULL);
+                               else
+                                       ins = mono_emit_jit_icall (cfg, mono_array_new_specific, args);
                        } else {
                                if (cfg->opt & MONO_OPT_SHARED) {
                                        /* Decompose now to avoid problems with references to the domainvar */
@@ -8252,6 +8328,10 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                        ins = mono_emit_jit_icall (cfg, mono_array_new, iargs);
                                } else {
                                        /* Decompose later since it is needed by abcrem */
+                                       MonoClass *array_type = mono_array_class_get (klass, 1);
+                                       mono_class_vtable (cfg->domain, array_type);
+                                       CHECK_TYPELOAD (array_type);
+
                                        MONO_INST_NEW (cfg, ins, OP_NEWARR);
                                        ins->dreg = alloc_preg (cfg);
                                        ins->sreg1 = sp [0]->dreg;
@@ -8328,15 +8408,18 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                         * to be for correctness. the wrappers are lax with their usage
                         * so we need to ignore them here
                         */
-                       if (!klass->valuetype && method->wrapper_type == MONO_WRAPPER_NONE && !readonly)
-                               mini_emit_check_array_type (cfg, sp [0], mono_array_class_get (klass, 1));
+                       if (!klass->valuetype && method->wrapper_type == MONO_WRAPPER_NONE && !readonly) {
+                               MonoClass *array_class = mono_array_class_get (klass, 1);
+                               mini_emit_check_array_type (cfg, sp [0], array_class);
+                               CHECK_TYPELOAD (array_class);
+                       }
 
                        readonly = FALSE;
                        ins = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1]);
                        *sp++ = ins;
                        ip += 5;
                        break;
-               case CEE_LDELEM_ANY:
+               case CEE_LDELEM:
                case CEE_LDELEM_I1:
                case CEE_LDELEM_U1:
                case CEE_LDELEM_I2:
@@ -8353,7 +8436,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        CHECK_STACK (2);
                        sp -= 2;
 
-                       if (*ip == CEE_LDELEM_ANY) {
+                       if (*ip == CEE_LDELEM) {
                                CHECK_OPSIZE (5);
                                token = read32 (ip + 1);
                                klass = mini_get_class (method, token, generic_context);
@@ -8380,7 +8463,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0);
                        }
                        *sp++ = ins;
-                       if (*ip == CEE_LDELEM_ANY)
+                       if (*ip == CEE_LDELEM)
                                ip += 5;
                        else
                                ++ip;
@@ -8394,7 +8477,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                case CEE_STELEM_R4:
                case CEE_STELEM_R8:
                case CEE_STELEM_REF:
-               case CEE_STELEM_ANY: {
+               case CEE_STELEM: {
                        MonoInst *addr;
 
                        CHECK_STACK (3);
@@ -8402,7 +8485,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
 
                        cfg->flags |= MONO_CFG_HAS_LDELEMA;
 
-                       if (*ip == CEE_STELEM_ANY) {
+                       if (*ip == CEE_STELEM) {
                                CHECK_OPSIZE (5);
                                token = read32 (ip + 1);
                                klass = mini_get_class (method, token, generic_context);
@@ -8445,7 +8528,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                }
                        }
 
-                       if (*ip == CEE_STELEM_ANY)
+                       if (*ip == CEE_STELEM)
                                ip += 5;
                        else
                                ++ip;
@@ -8642,7 +8725,18 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                                ins = emit_get_rgctx_klass (cfg, context_used,
                                                        tclass, MONO_RGCTX_INFO_REFLECTION_TYPE);
                                        } else if (cfg->compile_aot) {
-                                               EMIT_NEW_TYPE_FROM_HANDLE_CONST (cfg, ins, image, n, generic_context);
+                                               if (method->wrapper_type) {
+                                                       if (mono_class_get (tclass->image, tclass->type_token) == tclass && !generic_context) {
+                                                               /* Special case for static synchronized wrappers */
+                                                               EMIT_NEW_TYPE_FROM_HANDLE_CONST (cfg, ins, tclass->image, tclass->type_token, generic_context);
+                                                       } else {
+                                                               /* FIXME: n is not a normal token */
+                                                               cfg->disable_aot = TRUE;
+                                                               EMIT_NEW_PCONST (cfg, ins, NULL);
+                                                       }
+                                               } else {
+                                                       EMIT_NEW_TYPE_FROM_HANDLE_CONST (cfg, ins, image, n, generic_context);
+                                               }
                                        } else {
                                                EMIT_NEW_PCONST (cfg, ins, mono_type_get_object (cfg->domain, handle));
                                        }
@@ -8732,6 +8826,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        /* 
                         * If this leave statement is in a catch block, check for a
                         * pending exception, and rethrow it if necessary.
+                        * We avoid doing this in runtime invoke wrappers, since those are called
+                        * by native code which excepts the wrapper to catch all exceptions.
                         */
                        for (i = 0; i < header->num_clauses; ++i) {
                                MonoExceptionClause *clause = &header->clauses [i];
@@ -8742,7 +8838,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                 * The ordering of the exception clauses guarantees that we find the
                                 * innermost clause.
                                 */
-                               if (MONO_OFFSET_IN_HANDLER (clause, ip - header->code) && (clause->flags == MONO_EXCEPTION_CLAUSE_NONE) && (ip - header->code + ((*ip == CEE_LEAVE) ? 5 : 2)) <= (clause->handler_offset + clause->handler_len)) {
+                               if (MONO_OFFSET_IN_HANDLER (clause, ip - header->code) && (clause->flags == MONO_EXCEPTION_CLAUSE_NONE) && (ip - header->code + ((*ip == CEE_LEAVE) ? 5 : 2)) <= (clause->handler_offset + clause->handler_len) && method->wrapper_type != MONO_WRAPPER_RUNTIME_INVOKE) {
                                        MonoInst *exc_ins;
                                        MonoBasicBlock *dont_throw;
 
@@ -8779,6 +8875,18 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                        MONO_INST_NEW (cfg, ins, OP_CALL_HANDLER);
                                        ins->inst_target_bb = tblock;
                                        MONO_ADD_INS (bblock, ins);
+                                       bblock->has_call_handler = 1;
+                                       if (COMPILE_LLVM (cfg)) {
+                                               MonoBasicBlock *target_bb;
+
+                                               /* 
+                                                * Link the finally bblock with the target, since it will
+                                                * conceptually branch there.
+                                                * FIXME: Have to link the bblock containing the endfinally.
+                                                */
+                                               GET_BBLOCK (cfg, target_bb, target);
+                                               link_bblock (cfg, tblock, target_bb);
+                                       }
                                }
                                g_list_free (handlers);
                        } 
@@ -9044,6 +9152,37 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                *sp++ = ins;
                                ip += 6;
                                break;
+                       case CEE_MONO_DYN_CALL: {
+                               MonoCallInst *call;
+
+                               /* It would be easier to call a trampoline, but that would put an
+                                * extra frame on the stack, confusing exception handling. So
+                                * implement it inline using an opcode for now.
+                                */
+
+                               if (!cfg->dyn_call_var) {
+                                       cfg->dyn_call_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
+                                       /* prevent it from being register allocated */
+                                       cfg->dyn_call_var->flags |= MONO_INST_INDIRECT;
+                               }
+
+                               /* Has to use a call inst since it local regalloc expects it */
+                               MONO_INST_NEW_CALL (cfg, call, OP_DYN_CALL);
+                               ins = (MonoInst*)call;
+                               sp -= 2;
+                               ins->sreg1 = sp [0]->dreg;
+                               ins->sreg2 = sp [1]->dreg;
+                               MONO_ADD_INS (bblock, ins);
+
+#ifdef MONO_ARCH_DYN_CALL_PARAM_AREA
+                               cfg->param_area = MAX (cfg->param_area, MONO_ARCH_DYN_CALL_PARAM_AREA);
+#endif
+
+                               ip += 2;
+                               inline_costs += 10 * num_calls++;
+
+                               break;
+                       }
                        default:
                                g_error ("opcode 0x%02x 0x%02x not handled", MONO_CUSTOM_PREFIX, ip [1]);
                                break;
@@ -9155,41 +9294,37 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                 */
 #if defined(MONO_ARCH_HAVE_CREATE_DELEGATE_TRAMPOLINE) && !defined(HAVE_WRITE_BARRIERS)
                                /* FIXME: SGEN support */
-                               /* FIXME: handle shared static generic methods */
-                               /* FIXME: handle this in shared code */
-                               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)) {
+                               if ((sp > stack_start) && (ip + 6 + 5 < end) && ip_in_bb (cfg, bblock, ip + 6) && (ip [6] == CEE_NEWOBJ)) {
                                        MonoMethod *ctor_method = mini_get_method (cfg, method, read32 (ip + 7), NULL, generic_context);
                                        if (ctor_method && (ctor_method->klass->parent == mono_defaults.multicastdelegate_class)) {
                                                MonoInst *target_ins;
                                                MonoMethod *invoke;
+                                               int invoke_context_used = 0;
 
                                                invoke = mono_get_delegate_invoke (ctor_method->klass);
                                                if (!invoke || !mono_method_signature (invoke))
                                                        goto load_error;
 
-                                               ip += 6;
-                                               if (cfg->verbose_level > 3)
-                                                       g_print ("converting (in B%d: stack: %d) %s", bblock->block_num, (int)(sp - stack_start), mono_disasm_code_one (NULL, method, ip, NULL));
-                                               target_ins = sp [-1];
-                                               sp --;
-                                               *sp = handle_delegate_ctor (cfg, ctor_method->klass, target_ins, cmethod);
-                                               ip += 5;                        
-                                               sp ++;
-                                               break;
+                                               if (cfg->generic_sharing_context)
+                                                       invoke_context_used = mono_method_check_context_used (invoke);
+
+                                               if (invoke_context_used == 0) {
+                                                       ip += 6;
+                                                       if (cfg->verbose_level > 3)
+                                                               g_print ("converting (in B%d: stack: %d) %s", bblock->block_num, (int)(sp - stack_start), mono_disasm_code_one (NULL, method, ip, NULL));
+                                                       target_ins = sp [-1];
+                                                       sp --;
+                                                       *sp = handle_delegate_ctor (cfg, ctor_method->klass, target_ins, cmethod, context_used);
+                                                       CHECK_CFG_EXCEPTION;
+                                                       ip += 5;                        
+                                                       sp ++;
+                                                       break;
+                                               }
                                        }
                                }
 #endif
 
-                               if (context_used) {
-                                       if (needs_static_rgctx_invoke)
-                                               cmethod = mono_marshal_get_static_rgctx_invoke (cmethod);
-
-                                       argconst = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_METHOD);
-                               } else if (needs_static_rgctx_invoke) {
-                                       EMIT_NEW_METHODCONST (cfg, argconst, mono_marshal_get_static_rgctx_invoke (cmethod));
-                               } else {
-                                       EMIT_NEW_METHODCONST (cfg, argconst, cmethod);
-                               }
+                               argconst = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_METHOD);
                                ins = mono_emit_jit_icall (cfg, mono_ldftn, &argconst);
                                *sp++ = ins;
                                
@@ -9222,14 +9357,13 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                --sp;
                                args [0] = *sp;
 
-                               if (context_used) {
-                                       args [1] = emit_get_rgctx_method (cfg, context_used,
-                                               cmethod, MONO_RGCTX_INFO_METHOD);
+                               args [1] = emit_get_rgctx_method (cfg, context_used,
+                                                                                                 cmethod, MONO_RGCTX_INFO_METHOD);
+
+                               if (context_used)
                                        *sp++ = mono_emit_jit_icall (cfg, mono_ldvirtfn_gshared, args);
-                               } else {
-                                       EMIT_NEW_METHODCONST (cfg, args [1], cmethod);
+                               else
                                        *sp++ = mono_emit_jit_icall (cfg, mono_ldvirtfn, args);
-                               }
 
                                ip += 6;
                                inline_costs += 10 * num_calls++;
@@ -9324,7 +9458,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                MONO_ADD_INS (cfg->cbb, ins);
 
                                cfg->flags |= MONO_CFG_HAS_ALLOCA;
-                               if (header->init_locals)
+                               if (init_locals)
                                        ins->flags |= MONO_INST_INIT;
 
                                *sp++ = ins;
@@ -9395,7 +9529,10 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        case CEE_CONSTRAINED_:
                                CHECK_OPSIZE (6);
                                token = read32 (ip + 2);
-                               constrained_call = mono_class_get_full (image, token, generic_context);
+                               if (method->wrapper_type != MONO_WRAPPER_NONE)
+                                       constrained_call =  (MonoClass *)mono_method_get_wrapper_data (method, token);
+                               else
+                                       constrained_call = mono_class_get_full (image, token, generic_context);
                                CHECK_TYPELOAD (constrained_call);
                                ip += 6;
                                break;
@@ -9504,13 +9641,27 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                readonly = TRUE;
                                ip += 2;
                                break;
+
+                       case CEE_UNUSED56:
+                       case CEE_UNUSED57:
+                       case CEE_UNUSED70:
+                       case CEE_UNUSED:
+                       case CEE_UNUSED99:
+                               UNVERIFIED;
+                               
                        default:
-                               g_error ("opcode 0xfe 0x%02x not handled", ip [1]);
+                               g_warning ("opcode 0xfe 0x%02x not handled", ip [1]);
+                               UNVERIFIED;
                        }
                        break;
                }
+               case CEE_UNUSED58:
+               case CEE_UNUSED1:
+                       UNVERIFIED;
+
                default:
-                       g_error ("opcode 0x%02x not handled", *ip);
+                       g_warning ("opcode 0x%02x not handled", *ip);
+                       UNVERIFIED;
                }
        }
        if (start_new_bblock != 1)
@@ -9536,10 +9687,16 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                MONO_ADD_INS (cfg->cbb, store);
        }
 
+#ifdef TARGET_POWERPC
+       if (cfg->compile_aot)
+               /* FIXME: The plt slots require a GOT var even if the method doesn't use it */
+               mono_get_got_var (cfg);
+#endif
+
        if (cfg->method == method && cfg->got_var)
                mono_emit_load_got_addr (cfg);
 
-       if (header->init_locals) {
+       if (init_locals) {
                MonoInst *store;
 
                cfg->cbb = init_localsbb;
@@ -9573,6 +9730,25 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                }
        }
 
+       if (cfg->init_ref_vars && cfg->method == method) {
+               /* Emit initialization for ref vars */
+               // FIXME: Avoid duplication initialization for IL locals.
+               for (i = 0; i < cfg->num_varinfo; ++i) {
+                       MonoInst *ins = cfg->varinfo [i];
+
+                       if (ins->opcode == OP_LOCAL && ins->type == STACK_OBJ)
+                               MONO_EMIT_NEW_PCONST (cfg, ins->dreg, NULL);
+               }
+       }
+
+       /* Add a sequence point for method entry/exit events */
+       if (seq_points) {
+               NEW_SEQ_POINT (cfg, ins, METHOD_ENTRY_IL_OFFSET, FALSE);
+               MONO_ADD_INS (init_localsbb, ins);
+               NEW_SEQ_POINT (cfg, ins, METHOD_EXIT_IL_OFFSET, FALSE);
+               MONO_ADD_INS (cfg->bb_exit, ins);
+       }
+
        cfg->ip = NULL;
 
        if (cfg->method == method) {
@@ -9608,22 +9784,26 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
  exception_exit:
        g_assert (cfg->exception_type != MONO_EXCEPTION_NONE);
        g_slist_free (class_inits);
+       mono_basic_block_free (bb);
        dont_inline = g_list_remove (dont_inline, method);
        return -1;
 
  inline_failure:
        g_slist_free (class_inits);
+       mono_basic_block_free (bb);
        dont_inline = g_list_remove (dont_inline, method);
        return -1;
 
  load_error:
        g_slist_free (class_inits);
+       mono_basic_block_free (bb);
        dont_inline = g_list_remove (dont_inline, method);
        cfg->exception_type = MONO_EXCEPTION_TYPE_LOAD;
        return -1;
 
  unverified:
        g_slist_free (class_inits);
+       mono_basic_block_free (bb);
        dont_inline = g_list_remove (dont_inline, method);
        set_exception_type_from_invalid_il (cfg, method, ip);
        return -1;
@@ -9716,13 +9896,13 @@ mono_op_to_op_imm (int opcode)
        case OP_STOREI4_MEMBASE_REG:
                return OP_STOREI4_MEMBASE_IMM;
 
-#if defined(__i386__) || defined (__x86_64__)
+#if defined(TARGET_X86) || defined (TARGET_AMD64)
        case OP_X86_PUSH:
                return OP_X86_PUSH_IMM;
        case OP_X86_COMPARE_MEMBASE_REG:
                return OP_X86_COMPARE_MEMBASE_IMM;
 #endif
-#if defined(__x86_64__)
+#if defined(TARGET_AMD64)
        case OP_AMD64_ICOMPARE_MEMBASE_REG:
                return OP_AMD64_ICOMPARE_MEMBASE_IMM;
 #endif
@@ -9804,7 +9984,7 @@ int
 mono_load_membase_to_load_mem (int opcode)
 {
        // FIXME: Add a MONO_ARCH_HAVE_LOAD_MEM macro
-#if defined(__i386__) || defined(__x86_64__)
+#if defined(TARGET_X86) || defined(TARGET_AMD64)
        switch (opcode) {
        case OP_LOAD_MEMBASE:
                return OP_LOAD_MEM;
@@ -9829,7 +10009,7 @@ mono_load_membase_to_load_mem (int opcode)
 static inline int
 op_to_op_dest_membase (int store_opcode, int opcode)
 {
-#if defined(__i386__)
+#if defined(TARGET_X86)
        if (!((store_opcode == OP_STORE_MEMBASE_REG) || (store_opcode == OP_STOREI4_MEMBASE_REG)))
                return -1;
 
@@ -9864,7 +10044,7 @@ op_to_op_dest_membase (int store_opcode, int opcode)
        }
 #endif
 
-#if defined(__x86_64__)
+#if defined(TARGET_AMD64)
        if (!((store_opcode == OP_STORE_MEMBASE_REG) || (store_opcode == OP_STOREI4_MEMBASE_REG) || (store_opcode == OP_STOREI8_MEMBASE_REG)))
                return -1;
 
@@ -9925,7 +10105,7 @@ op_to_op_dest_membase (int store_opcode, int opcode)
 static inline int
 op_to_op_store_membase (int store_opcode, int opcode)
 {
-#if defined(__i386__) || defined(__x86_64__)
+#if defined(TARGET_X86) || defined(TARGET_AMD64)
        switch (opcode) {
        case OP_ICEQ:
                if (store_opcode == OP_STOREI1_MEMBASE_REG)
@@ -9942,7 +10122,7 @@ op_to_op_store_membase (int store_opcode, int opcode)
 static inline int
 op_to_op_src1_membase (int load_opcode, int opcode)
 {
-#ifdef __i386__
+#ifdef TARGET_X86
        /* FIXME: This has sign extension issues */
        /*
        if ((opcode == OP_ICOMPARE_IMM) && (load_opcode == OP_LOADU1_MEMBASE))
@@ -9964,7 +10144,7 @@ op_to_op_src1_membase (int load_opcode, int opcode)
        }
 #endif
 
-#ifdef __x86_64__
+#ifdef TARGET_AMD64
        /* FIXME: This has sign extension issues */
        /*
        if ((opcode == OP_ICOMPARE_IMM) && (load_opcode == OP_LOADU1_MEMBASE))
@@ -10004,7 +10184,7 @@ op_to_op_src1_membase (int load_opcode, int opcode)
 static inline int
 op_to_op_src2_membase (int load_opcode, int opcode)
 {
-#ifdef __i386__
+#ifdef TARGET_X86
        if (!((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE)))
                return -1;
        
@@ -10025,7 +10205,7 @@ op_to_op_src2_membase (int load_opcode, int opcode)
        }
 #endif
 
-#ifdef __x86_64__
+#ifdef TARGET_AMD64
        switch (opcode) {
        case OP_ICOMPARE:
                if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE))
@@ -10126,7 +10306,7 @@ mono_handle_global_vregs (MonoCompile *cfg)
                cfg->cbb = bb;
                for (; ins; ins = ins->next) {
                        const char *spec = INS_INFO (ins->opcode);
-                       int regtype, regindex;
+                       int regtype = 0, regindex;
                        gint32 prev_bb;
 
                        if (G_UNLIKELY (cfg->verbose_level > 2))
@@ -10135,7 +10315,7 @@ mono_handle_global_vregs (MonoCompile *cfg)
                        g_assert (ins->opcode >= MONO_CEE_LAST);
 
                        for (regindex = 0; regindex < 4; regindex ++) {
-                               int vreg;
+                               int vreg = 0;
 
                                if (regindex == 0) {
                                        regtype = spec [MONO_INST_DEST];
@@ -10160,7 +10340,8 @@ mono_handle_global_vregs (MonoCompile *cfg)
                                }
 
 #if SIZEOF_REGISTER == 4
-                               if (regtype == 'l') {
+                               /* In the LLVM case, the long opcodes are not decomposed */
+                               if (regtype == 'l' && !COMPILE_LLVM (cfg)) {
                                        /*
                                         * Since some instructions reference the original long vreg,
                                         * and some reference the two component vregs, it is quite hard
@@ -10200,6 +10381,9 @@ mono_handle_global_vregs (MonoCompile *cfg)
                                                case 'i':
                                                        mono_compile_create_var_for_vreg (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL, vreg);
                                                        break;
+                                               case 'l':
+                                                       mono_compile_create_var_for_vreg (cfg, &mono_defaults.int64_class->byval_arg, OP_LOCAL, vreg);
+                                                       break;
                                                case 'f':
                                                        mono_compile_create_var_for_vreg (cfg, &mono_defaults.double_class->byval_arg, OP_LOCAL, vreg);
                                                        break;
@@ -10232,7 +10416,7 @@ mono_handle_global_vregs (MonoCompile *cfg)
 #if SIZEOF_REGISTER == 8
                case STACK_I8:
 #endif
-#if !defined(__i386__) && !defined(MONO_ARCH_SOFT_FLOAT)
+#if !defined(TARGET_X86) && !defined(MONO_ARCH_SOFT_FLOAT)
                /* Enabling this screws up the fp stack on x86 */
                case STACK_R8:
 #endif
@@ -10363,12 +10547,13 @@ mono_spill_global_vars (MonoCompile *cfg, gboolean *need_local_opts)
 
                if ((ins->opcode != OP_REGVAR) && !(ins->flags & MONO_INST_IS_DEAD)) {
                        switch (ins->type) {
-#ifdef MONO_ARCH_SOFT_FLOAT
                        case STACK_R8:
-#endif
                        case STACK_I8: {
                                MonoInst *tree;
 
+                               if (ins->type == STACK_R8 && !COMPILE_SOFT_FLOAT (cfg))
+                                       break;
+
                                g_assert (ins->opcode == OP_REGOFFSET);
 
                                tree = get_vreg_to_inst (cfg, ins->dreg + 1);
@@ -10410,6 +10595,10 @@ mono_spill_global_vars (MonoCompile *cfg, gboolean *need_local_opts)
         * don't split live ranges, these will precisely describe the live range of
         * the variable, i.e. the instruction range where a valid value can be found
         * in the variables location.
+        * The live range is computed using the liveness info computed by the liveness pass.
+        * We can't use vmv->range, since that is an abstract live range, and we need
+        * one which is instruction precise.
+        * FIXME: Variables used in out-of-line bblocks have a hole in their live range.
         */
        /* FIXME: Only do this if debugging info is requested */
        live_range_start = g_new0 (MonoInst*, cfg->next_vreg);
@@ -10554,12 +10743,10 @@ mono_spill_global_vars (MonoCompile *cfg, gboolean *need_local_opts)
 
                                        lvreg = 0;
 
-#ifdef MONO_ARCH_SOFT_FLOAT
-                                       if (store_opcode == OP_STORER8_MEMBASE_REG) {
+                                       if (COMPILE_SOFT_FLOAT (cfg) && store_opcode == OP_STORER8_MEMBASE_REG) {
                                                regtype = 'l';
                                                store_opcode = OP_STOREI8_MEMBASE_REG;
                                        }
-#endif
 
                                        ins->dreg = alloc_dreg (cfg, stacktypes [regtype]);
 
@@ -10763,6 +10950,29 @@ mono_spill_global_vars (MonoCompile *cfg, gboolean *need_local_opts)
                        if (cfg->verbose_level > 2)
                                mono_print_ins_index (1, ins);
                }
+
+               /* Extend the live range based on the liveness info */
+               if (cfg->compute_precise_live_ranges && bb->live_out_set && bb->code) {
+                       for (i = 0; i < cfg->num_varinfo; i ++) {
+                               MonoMethodVar *vi = MONO_VARINFO (cfg, i);
+
+                               if (vreg_is_volatile (cfg, vi->vreg))
+                                       /* The liveness info is incomplete */
+                                       continue;
+
+                               if (mono_bitset_test_fast (bb->live_in_set, i) && !live_range_start [vi->vreg]) {
+                                       /* Live from at least the first ins of this bb */
+                                       live_range_start [vi->vreg] = bb->code;
+                                       live_range_start_bb [vi->vreg] = bb;
+                               }
+
+                               if (mono_bitset_test_fast (bb->live_out_set, i)) {
+                                       /* Live at least until the last ins of this bb */
+                                       live_range_end [vi->vreg] = bb->last_ins;
+                                       live_range_end_bb [vi->vreg] = bb;
+                               }
+                       }
+               }
        }
        
 #ifdef MONO_ARCH_HAVE_LIVERANGE_OPS
@@ -10770,21 +10980,26 @@ mono_spill_global_vars (MonoCompile *cfg, gboolean *need_local_opts)
         * Emit LIVERANGE_START/LIVERANGE_END opcodes, the backend will implement them
         * by storing the current native offset into MonoMethodVar->live_range_start/end.
         */
-       for (i = 0; i < cfg->num_varinfo; ++i) {
-               int vreg = MONO_VARINFO (cfg, i)->vreg;
-               MonoInst *ins;
-
-               if (live_range_start [vreg]) {
-                       MONO_INST_NEW (cfg, ins, OP_LIVERANGE_START);
-                       ins->inst_c0 = i;
-                       ins->inst_c1 = vreg;
-                       mono_bblock_insert_after_ins (live_range_start_bb [vreg], live_range_start [vreg], ins);
-               }
-               if (live_range_end [vreg]) {
-                       MONO_INST_NEW (cfg, ins, OP_LIVERANGE_END);
-                       ins->inst_c0 = i;
-                       ins->inst_c1 = vreg;
-                       mono_bblock_insert_after_ins (live_range_end_bb [vreg], live_range_end [vreg], ins);
+       if (cfg->compute_precise_live_ranges && cfg->comp_done & MONO_COMP_LIVENESS) {
+               for (i = 0; i < cfg->num_varinfo; ++i) {
+                       int vreg = MONO_VARINFO (cfg, i)->vreg;
+                       MonoInst *ins;
+
+                       if (live_range_start [vreg]) {
+                               MONO_INST_NEW (cfg, ins, OP_LIVERANGE_START);
+                               ins->inst_c0 = i;
+                               ins->inst_c1 = vreg;
+                               mono_bblock_insert_after_ins (live_range_start_bb [vreg], live_range_start [vreg], ins);
+                       }
+                       if (live_range_end [vreg]) {
+                               MONO_INST_NEW (cfg, ins, OP_LIVERANGE_END);
+                               ins->inst_c0 = i;
+                               ins->inst_c1 = vreg;
+                               if (live_range_end [vreg] == live_range_end_bb [vreg]->last_ins)
+                                       mono_add_ins_to_end (live_range_end_bb [vreg], ins);
+                               else
+                                       mono_bblock_insert_after_ins (live_range_end_bb [vreg], live_range_end [vreg], ins);
+                       }
                }
        }
 #endif