Merge pull request #3240 from alexanderkyte/aot_compiler_leaks
[mono.git] / mono / mini / method-to-ir.c
index 231270a865c5bfb07b0e0699c658474a6f7e462a..7f3c4f7e9c803d6ce2bbdae62bd5cee68638ed75 100644 (file)
@@ -64,6 +64,7 @@
 #include <mono/utils/mono-error-internals.h>
 #include <mono/metadata/mono-basic-block.h>
 #include <mono/metadata/reflection-internals.h>
+#include <mono/utils/mono-threads-coop.h>
 
 #include "trace.h"
 
                if (cfg->exception_type != MONO_EXCEPTION_NONE) \
                        goto exception_exit;                                            \
        } while (0)
-#define METHOD_ACCESS_FAILURE(method, cmethod) do {                    \
-               method_access_failure ((cfg), (method), (cmethod));                     \
-               goto exception_exit;                                                                            \
-       } while (0)
 #define FIELD_ACCESS_FAILURE(method, field) do {                                       \
                field_access_failure ((cfg), (method), (field));                        \
                goto exception_exit;    \
@@ -377,17 +374,6 @@ break_on_unverified (void)
                G_BREAKPOINT ();
 }
 
-static MONO_NEVER_INLINE void
-method_access_failure (MonoCompile *cfg, MonoMethod *method, MonoMethod *cil_method)
-{
-       char *method_fname = mono_method_full_name (method, TRUE);
-       char *cil_method_fname = mono_method_full_name (cil_method, TRUE);
-       mono_cfg_set_exception (cfg, MONO_EXCEPTION_MONO_ERROR);
-       mono_error_set_generic_error (&cfg->error, "System", "MethodAccessException", "Method `%s' is inaccessible from method `%s'\n", cil_method_fname, method_fname);
-       g_free (method_fname);
-       g_free (cil_method_fname);
-}
-
 static MONO_NEVER_INLINE void
 field_access_failure (MonoCompile *cfg, MonoMethod *method, MonoClassField *field)
 {
@@ -675,6 +661,24 @@ mono_find_block_region (MonoCompile *cfg, int offset)
        return -1;
 }
 
+static gboolean
+ip_in_finally_clause (MonoCompile *cfg, int offset)
+{
+       MonoMethodHeader *header = cfg->header;
+       MonoExceptionClause *clause;
+       int i;
+
+       for (i = 0; i < header->num_clauses; ++i) {
+               clause = &header->clauses [i];
+               if (clause->flags != MONO_EXCEPTION_CLAUSE_FINALLY && clause->flags != MONO_EXCEPTION_CLAUSE_FAULT)
+                       continue;
+
+               if (MONO_OFFSET_IN_HANDLER (clause, offset))
+                       return TRUE;
+       }
+       return FALSE;
+}
+
 static GList*
 mono_find_final_block (MonoCompile *cfg, unsigned char *ip, unsigned char *target, int type)
 {
@@ -2211,7 +2215,6 @@ target_type_is_incompatible (MonoCompile *cfg, MonoType *target, MonoInst *arg)
        if (target->byref) {
                /* FIXME: check that the pointed to types match */
                if (arg->type == STACK_MP) {
-                       if (cfg->verbose_level) printf ("ok\n");
                        /* This is needed to handle gshared types + ldaddr. We lower the types so we can handle enums and other typedef-like types. */
                        MonoClass *target_class_lowered = mono_class_from_mono_type (mini_get_underlying_type (&mono_class_from_mono_type (target)->byval_arg));
                        MonoClass *source_class_lowered = mono_class_from_mono_type (mini_get_underlying_type (&arg->klass->byval_arg));
@@ -3156,6 +3159,18 @@ mono_emit_widen_call_res (MonoCompile *cfg, MonoInst *ins, MonoMethodSignature *
        return ins;
 }
 
+
+static void
+emit_method_access_failure (MonoCompile *cfg, MonoMethod *method, MonoMethod *cil_method)
+{
+       MonoInst *args [16];
+
+       args [0] = emit_get_rgctx_method (cfg, mono_method_check_context_used (method), method, MONO_RGCTX_INFO_METHOD);
+       args [1] = emit_get_rgctx_method (cfg, mono_method_check_context_used (cil_method), cil_method, MONO_RGCTX_INFO_METHOD);
+
+       mono_emit_jit_icall (cfg, mono_throw_method_access, args);
+}
+
 static MonoMethod*
 get_memcpy_method (void)
 {
@@ -4036,7 +4051,8 @@ handle_unbox_nullable (MonoCompile* cfg, MonoInst* val, MonoClass* klass, int co
                   RGCTX. */
                addr = emit_get_rgctx_method (cfg, context_used, method,
                                                                          MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
-               if (cfg->llvm_only && cfg->gsharedvt) {
+               if (cfg->llvm_only) {
+                       cfg->signatures = g_slist_prepend_mempool (cfg->mempool, cfg->signatures, mono_method_signature (method));
                        return emit_llvmonly_calli (cfg, mono_method_signature (method), &val, addr);
                } else {
                        rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
@@ -4472,14 +4488,19 @@ icall_is_direct_callable (MonoCompile *cfg, MonoMethod *cmethod)
 
 #define is_complex_isinst(klass) ((klass->flags & TYPE_ATTRIBUTE_INTERFACE) || klass->rank || mono_class_is_nullable (klass) || mono_class_is_marshalbyref (klass) || (klass->flags & TYPE_ATTRIBUTE_SEALED) || klass->byval_arg.type == MONO_TYPE_VAR || klass->byval_arg.type == MONO_TYPE_MVAR)
 
+static MonoInst*
+emit_isinst_with_cache (MonoCompile *cfg, MonoClass *klass, MonoInst **args)
+{
+       MonoMethod *mono_isinst = mono_marshal_get_isinst_with_cache ();
+       return mono_emit_method_call (cfg, mono_isinst, args, NULL);
+}
+
 static MonoInst*
 emit_castclass_with_cache (MonoCompile *cfg, MonoClass *klass, MonoInst **args)
 {
-       MonoMethod *mono_castclass;
+       MonoMethod *mono_castclass = mono_marshal_get_castclass_with_cache ();
        MonoInst *res;
 
-       mono_castclass = mono_marshal_get_castclass_with_cache ();
-
        save_cast_details (cfg, klass, args [0]->dreg, TRUE);
        res = mono_emit_method_call (cfg, mono_castclass, args, NULL);
        reset_cast_details (cfg);
@@ -4495,6 +4516,22 @@ get_castclass_cache_idx (MonoCompile *cfg)
        return (cfg->method_index << 16) | cfg->castclass_cache_index;
 }
 
+
+static MonoInst*
+emit_isinst_with_cache_nonshared (MonoCompile *cfg, MonoInst *obj, MonoClass *klass)
+{
+       MonoInst *args [3];
+       int idx;
+
+       args [0] = obj; /* obj */
+       EMIT_NEW_CLASSCONST (cfg, args [1], klass); /* klass */
+
+       idx = get_castclass_cache_idx (cfg); /* inline cache*/
+       args [2] = emit_runtime_constant (cfg, MONO_PATCH_INFO_CASTCLASS_CACHE, GINT_TO_POINTER (idx));
+
+       return emit_isinst_with_cache (cfg, klass, args);
+}
+
 static MonoInst*
 emit_castclass_with_cache_nonshared (MonoCompile *cfg, MonoInst *obj, MonoClass *klass)
 {
@@ -4519,46 +4556,20 @@ emit_castclass_with_cache_nonshared (MonoCompile *cfg, MonoInst *obj, MonoClass
  * Returns NULL and set the cfg exception on error.
  */
 static MonoInst*
-handle_castclass (MonoCompile *cfg, MonoClass *klass, MonoInst *src, guint8 *ip, int *inline_costs)
+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);
-       int context_used;
-       MonoInst *klass_inst = NULL, *res;
-
-       context_used = mini_class_check_context_used (cfg, klass);
-
-       if (!context_used && mini_class_has_reference_variant_generic_argument (cfg, klass, context_used)) {
-               res = emit_castclass_with_cache_nonshared (cfg, src, klass);
-               (*inline_costs) += 2;
-               return res;
-       } else if (!context_used && (mono_class_is_marshalbyref (klass) || klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
-               MonoMethod *mono_castclass;
-               MonoInst *iargs [1];
-               int costs;
-
-               mono_castclass = mono_marshal_get_castclass (klass); 
-               iargs [0] = src;
-                               
-               save_cast_details (cfg, klass, src->dreg, TRUE);
-               costs = inline_method (cfg, mono_castclass, mono_method_signature (mono_castclass), 
-                                                          iargs, ip, cfg->real_offset, TRUE);
-               reset_cast_details (cfg);
-               CHECK_CFG_EXCEPTION;
-               g_assert (costs > 0);
-                               
-               cfg->real_offset += 5;
-
-               (*inline_costs) += costs;
+       MonoInst *klass_inst = NULL;
 
+       if (src->opcode == OP_PCONST && src->inst_p0 == 0)
                return src;
-       }
 
        if (context_used) {
                MonoInst *args [3];
 
-               if(mini_class_has_reference_variant_generic_argument (cfg, klass, context_used) || is_complex_isinst (klass)) {
+               if (mini_class_has_reference_variant_generic_argument (cfg, klass, context_used) || is_complex_isinst (klass)) {
                        MonoInst *cache_ins;
 
                        cache_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_CAST_CACHE);
@@ -4619,9 +4630,6 @@ handle_castclass (MonoCompile *cfg, MonoClass *klass, MonoInst *src, guint8 *ip,
        reset_cast_details (cfg);
 
        return src;
-
-exception_exit:
-       return NULL;
 }
 
 /*
@@ -4641,21 +4649,15 @@ handle_isinst (MonoCompile *cfg, MonoClass *klass, MonoInst *src, int context_us
                MonoInst *args [3];
 
                if(mini_class_has_reference_variant_generic_argument (cfg, klass, context_used) || is_complex_isinst (klass)) {
-                       MonoMethod *mono_isinst = mono_marshal_get_isinst_with_cache ();
-                       MonoInst *cache_ins;
+                       MonoInst *cache_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_CAST_CACHE);
 
-                       cache_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_CAST_CACHE);
-
-                       /* obj */
-                       args [0] = src;
+                       args [0] = src; /* obj */
 
                        /* klass - it's the second element of the cache entry*/
                        EMIT_NEW_LOAD_MEMBASE (cfg, args [1], OP_LOAD_MEMBASE, alloc_preg (cfg), cache_ins->dreg, sizeof (gpointer));
 
-                       /* cache */
-                       args [2] = cache_ins;
-
-                       return mono_emit_method_call (cfg, mono_isinst, args, NULL);
+                       args [2] = cache_ins; /* cache */
+                       return emit_isinst_with_cache (cfg, klass, args);
                }
 
                klass_inst = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
@@ -5902,7 +5904,7 @@ llvm_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSign
                if (opcode && fsig->param_count == 1) {
                        MONO_INST_NEW (cfg, ins, opcode);
                        ins->type = STACK_R8;
-                       ins->dreg = mono_alloc_freg (cfg);
+                       ins->dreg = mono_alloc_dreg (cfg, ins->type);
                        ins->sreg1 = args [0]->dreg;
                        MONO_ADD_INS (cfg->cbb, ins);
                }
@@ -5933,7 +5935,7 @@ llvm_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSign
                if (opcode && fsig->param_count == 2) {
                        MONO_INST_NEW (cfg, ins, opcode);
                        ins->type = fsig->params [0]->type == MONO_TYPE_I4 ? STACK_I4 : STACK_I8;
-                       ins->dreg = mono_alloc_ireg (cfg);
+                       ins->dreg = mono_alloc_dreg (cfg, ins->type);
                        ins->sreg1 = args [0]->dreg;
                        ins->sreg2 = args [1]->dreg;
                        MONO_ADD_INS (cfg->cbb, ins);
@@ -6796,22 +6798,18 @@ mini_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSign
                    !strcmp (cmethod->klass->image->assembly->aname.name, "monotouch")) &&
                                !strcmp (cmethod->klass->name_space, "XamCore.ObjCRuntime") &&
                                !strcmp (cmethod->klass->name, "Selector")) ||
-                          (!strcmp (cmethod->klass->image->assembly->aname.name, "Xamarin.iOS") &&
+                          ((!strcmp (cmethod->klass->image->assembly->aname.name, "Xamarin.iOS") ||
+                                !strcmp (cmethod->klass->image->assembly->aname.name, "Xamarin.Mac")) &&
                                !strcmp (cmethod->klass->name_space, "ObjCRuntime") &&
                                !strcmp (cmethod->klass->name, "Selector"))
                           ) {
-               if (cfg->backend->have_objc_get_selector &&
+               if ((cfg->backend->have_objc_get_selector || cfg->compile_llvm) &&
                        !strcmp (cmethod->name, "GetHandle") && fsig->param_count == 1 &&
                    (args [0]->opcode == OP_GOT_ENTRY || args [0]->opcode == OP_AOTCONST) &&
-                   cfg->compile_aot && !cfg->llvm_only) {
+                   cfg->compile_aot) {
                        MonoInst *pi;
                        MonoJumpInfoToken *ji;
-                       MonoString *s;
-
-                       // FIXME: llvmonly
-
-                       cfg->exception_message = g_strdup ("GetHandle");
-                       cfg->disable_llvm = TRUE;
+                       char *s;
 
                        if (args [0]->opcode == OP_GOT_ENTRY) {
                                pi = (MonoInst *)args [0]->inst_p1;
@@ -6825,13 +6823,13 @@ mini_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSign
 
                        NULLIFY_INS (args [0]);
 
-                       // FIXME: Ugly
-                       s = mono_ldstr_checked (cfg->domain, ji->image, mono_metadata_token_index (ji->token), &cfg->error);
+                       s = mono_ldstr_utf8 (ji->image, mono_metadata_token_index (ji->token), &cfg->error);
                        return_val_if_nok (&cfg->error, NULL);
+
                        MONO_INST_NEW (cfg, ins, OP_OBJC_GET_SELECTOR);
                        ins->dreg = mono_alloc_ireg (cfg);
                        // FIXME: Leaks
-                       ins->inst_p0 = mono_string_to_utf8 (s);
+                       ins->inst_p0 = s;
                        MONO_ADD_INS (cfg->cbb, ins);
                        return ins;
                }
@@ -8193,7 +8191,10 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
        if (!header) {
                mono_cfg_set_exception (cfg, MONO_EXCEPTION_MONO_ERROR);
                goto exception_exit;
+       } else {
+               cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, header);
        }
+
        generic_container = mono_method_get_generic_container (method);
        sig = mono_method_signature (method);
        num_args = sig->hasthis + sig->param_count;
@@ -9052,6 +9053,9 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                for (i = 0; i < n; ++i)
                                        EMIT_NEW_ARGLOAD (cfg, call->args [i], i);
 
+                               if (mini_type_is_vtype (mini_get_underlying_type (call->signature->ret)))
+                                       call->vret_var = cfg->vret_addr;
+
                                mono_arch_emit_call (cfg, call);
                                cfg->param_area = MAX(cfg->param_area, call->stack_usage);
                                MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
@@ -9265,7 +9269,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                }
                                if (!mono_method_can_access_method (method_definition, target_method) &&
                                        !mono_method_can_access_method (method, cil_method))
-                                       METHOD_ACCESS_FAILURE (method, cil_method);
+                                       emit_method_access_failure (cfg, method, cil_method);
                        }
 
                        if (mono_security_core_clr_enabled ())
@@ -9744,6 +9748,20 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
 
                        inline_costs += 10 * num_calls++;
 
+                       /*
+                        * Synchronized wrappers.
+                        * Its hard to determine where to replace a method with its synchronized
+                        * wrapper without causing an infinite recursion. The current solution is
+                        * to add the synchronized wrapper in the trampolines, and to
+                        * change the called method to a dummy wrapper, and resolve that wrapper
+                        * to the real method in mono_jit_compile_method ().
+                        */
+                       if (cfg->method->wrapper_type == MONO_WRAPPER_SYNCHRONIZED) {
+                               MonoMethod *orig = mono_marshal_method_from_wrapper (cfg->method);
+                               if (cmethod == orig || (cmethod->is_inflated && mono_method_get_declaring_generic_method (cmethod) == orig))
+                                       cmethod = mono_marshal_get_synchronized_inner_wrapper (cmethod);
+                       }
+
                        /*
                         * Making generic calls out of gsharedvt methods.
                         * This needs to be used for all generic calls, not just ones with a gsharedvt signature, to avoid
@@ -9963,20 +9981,6 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                }
                        }
 
-                       /* 
-                        * Synchronized wrappers.
-                        * Its hard to determine where to replace a method with its synchronized
-                        * wrapper without causing an infinite recursion. The current solution is
-                        * to add the synchronized wrapper in the trampolines, and to
-                        * change the called method to a dummy wrapper, and resolve that wrapper
-                        * to the real method in mono_jit_compile_method ().
-                        */
-                       if (cfg->method->wrapper_type == MONO_WRAPPER_SYNCHRONIZED) {
-                               MonoMethod *orig = mono_marshal_method_from_wrapper (cfg->method);
-                               if (cmethod == orig || (cmethod->is_inflated && mono_method_get_declaring_generic_method (cmethod) == orig))
-                                       cmethod = mono_marshal_get_synchronized_inner_wrapper (cmethod);
-                       }
-
                        /*
                         * Virtual calls in llvm-only mode.
                         */
@@ -10957,21 +10961,6 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        break;
                }
                case CEE_CASTCLASS:
-                       CHECK_STACK (1);
-                       --sp;
-                       CHECK_OPSIZE (5);
-                       token = read32 (ip + 1);
-                       klass = mini_get_class (method, token, generic_context);
-                       CHECK_TYPELOAD (klass);
-                       if (sp [0]->type != STACK_OBJ)
-                               UNVERIFIED;
-
-                       ins = handle_castclass (cfg, klass, *sp, ip, &inline_costs);
-                       CHECK_CFG_EXCEPTION;
-
-                       *sp ++ = ins;
-                       ip += 5;
-                       break;
                case CEE_ISINST: {
                        CHECK_STACK (1);
                        --sp;
@@ -10981,53 +10970,19 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        CHECK_TYPELOAD (klass);
                        if (sp [0]->type != STACK_OBJ)
                                UNVERIFIED;
-                       context_used = mini_class_check_context_used (cfg, klass);
-
-                       if (!context_used && mini_class_has_reference_variant_generic_argument (cfg, klass, context_used)) {
-                               MonoMethod *mono_isinst = mono_marshal_get_isinst_with_cache ();
-                               MonoInst *args [3];
-                               int idx;
-
-                               /* obj */
-                               args [0] = *sp;
-
-                               /* klass */
-                               EMIT_NEW_CLASSCONST (cfg, args [1], klass);
-
-                               /* inline cache*/
-                               idx = get_castclass_cache_idx (cfg);
-                               args [2] = emit_runtime_constant (cfg, MONO_PATCH_INFO_CASTCLASS_CACHE, GINT_TO_POINTER (idx));
-
-                               *sp++ = mono_emit_method_call (cfg, mono_isinst, args, NULL);
-                               ip += 5;
-                               inline_costs += 2;
-                       } else if (!context_used && (mono_class_is_marshalbyref (klass) || klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
-                               MonoMethod *mono_isinst;
-                               MonoInst *iargs [1];
-                               int costs;
 
-                               mono_isinst = mono_marshal_get_isinst (klass); 
-                               iargs [0] = sp [0];
-
-                               costs = inline_method (cfg, mono_isinst, mono_method_signature (mono_isinst), 
-                                                                          iargs, ip, cfg->real_offset, TRUE);
-                               CHECK_CFG_EXCEPTION;
-                               g_assert (costs > 0);
-                               
-                               ip += 5;
-                               cfg->real_offset += 5;
+                       MONO_INST_NEW (cfg, ins, *ip == CEE_ISINST ? OP_ISINST : OP_CASTCLASS);
+                       ins->dreg = alloc_preg (cfg);
+                       ins->sreg1 = (*sp)->dreg;
+                       ins->klass = klass;
+                       ins->type = STACK_OBJ;
+                       MONO_ADD_INS (cfg->cbb, ins);
 
-                               *sp++= iargs [0];
+                       CHECK_CFG_EXCEPTION;
+                       *sp++ = ins;
+                       ip += 5;
 
-                               inline_costs += costs;
-                       }
-                       else {
-                               ins = handle_isinst (cfg, klass, *sp, context_used);
-                               CHECK_CFG_EXCEPTION;
-                               *sp ++ = ins;
-                               ip += 5;
-                       }
+                       cfg->flags |= MONO_CFG_HAS_TYPE_CHECK;
                        break;
                }
                case CEE_UNBOX_ANY: {
@@ -11048,8 +11003,13 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                res = handle_unbox_gsharedvt (cfg, klass, *sp);
                                inline_costs += 2;
                        } else if (generic_class_is_reference_type (cfg, klass)) {
-                               res = handle_castclass (cfg, klass, *sp, ip, &inline_costs);
-                               CHECK_CFG_EXCEPTION;
+                               MONO_INST_NEW (cfg, res, OP_CASTCLASS);
+                               res->dreg = alloc_preg (cfg);
+                               res->sreg1 = (*sp)->dreg;
+                               res->klass = klass;
+                               res->type = STACK_OBJ;
+                               MONO_ADD_INS (cfg->cbb, res);
+                               cfg->flags |= MONO_CFG_HAS_TYPE_CHECK;
                        } else if (mono_class_is_nullable (klass)) {
                                res = handle_unbox_nullable (cfg, *sp, klass, context_used);
                        } else {
@@ -11373,6 +11333,11 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
 
                                        MONO_EMIT_NULL_CHECK (cfg, sp [0]->dreg);
 
+                                       if (ins_flag & MONO_INST_VOLATILE) {
+                                               /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
+                                               emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
+                                       }
+
                                        if (mini_is_gsharedvt_klass (klass)) {
                                                MonoInst *offset_ins;
 
@@ -12332,6 +12297,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                INLINE_FAILURE ("throw");
                        break;
                case CEE_ENDFINALLY:
+                       if (!ip_in_finally_clause (cfg, ip - header->code))
+                               UNVERIFIED;
                        /* mono_save_seq_point_info () depends on this */
                        if (sp != stack_start)
                                emit_seq_point (cfg, method, ip, FALSE, FALSE);
@@ -12767,59 +12734,68 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                ip += 6;
                                break;
                        }
+                       case CEE_MONO_ATOMIC_STORE_I4: {
+                               g_assert (mono_arch_opcode_supported (OP_ATOMIC_STORE_I4));
+
+                               CHECK_OPSIZE (6);
+                               CHECK_STACK (2);
+                               sp -= 2;
+
+                               MONO_INST_NEW (cfg, ins, OP_ATOMIC_STORE_I4);
+                               ins->dreg = sp [0]->dreg;
+                               ins->sreg1 = sp [1]->dreg;
+                               ins->backend.memory_barrier_kind = (int) read32 (ip + 2);
+                               MONO_ADD_INS (cfg->cbb, ins);
+
+                               ip += 6;
+                               break;
+                       }
                        case CEE_MONO_JIT_ATTACH: {
                                MonoInst *args [16], *domain_ins;
                                MonoInst *ad_ins, *jit_tls_ins;
                                MonoBasicBlock *next_bb = NULL, *call_bb = NULL;
 
-                               cfg->attach_cookie = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
-                               cfg->attach_dummy = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
+                               g_assert (!mono_threads_is_coop_enabled ());
 
-                               if (mono_threads_is_coop_enabled ()) {
-                                       /* AOT code is only used in the root domain */
-                                       EMIT_NEW_PCONST (cfg, args [0], cfg->compile_aot ? NULL : cfg->domain);
-                                       EMIT_NEW_VARLOADA (cfg, args [1], cfg->attach_dummy, cfg->attach_dummy->inst_vtype);
-                                       ins = mono_emit_jit_icall (cfg, mono_jit_thread_attach, args);
-                                       MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->attach_cookie->dreg, ins->dreg);
-                               } else {
-                                       EMIT_NEW_PCONST (cfg, ins, NULL);
-                                       MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->attach_cookie->dreg, ins->dreg);
-
-                                       ad_ins = mono_get_domain_intrinsic (cfg);
-                                       jit_tls_ins = mono_get_jit_tls_intrinsic (cfg);
+                               cfg->orig_domain_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
 
-                                       if (cfg->backend->have_tls_get && ad_ins && jit_tls_ins) {
-                                               NEW_BBLOCK (cfg, next_bb);
-                                               NEW_BBLOCK (cfg, call_bb);
+                               EMIT_NEW_PCONST (cfg, ins, NULL);
+                               MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->orig_domain_var->dreg, ins->dreg);
 
-                                               if (cfg->compile_aot) {
-                                                       /* AOT code is only used in the root domain */
-                                                       EMIT_NEW_PCONST (cfg, domain_ins, NULL);
-                                               } else {
-                                                       EMIT_NEW_PCONST (cfg, domain_ins, cfg->domain);
-                                               }
-                                               MONO_ADD_INS (cfg->cbb, ad_ins);
-                                               MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, ad_ins->dreg, domain_ins->dreg);
-                                               MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, call_bb);
+                               ad_ins = mono_get_domain_intrinsic (cfg);
+                               jit_tls_ins = mono_get_jit_tls_intrinsic (cfg);
 
-                                               MONO_ADD_INS (cfg->cbb, jit_tls_ins);
-                                               MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, jit_tls_ins->dreg, 0);
-                                               MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, call_bb);
+                               if (cfg->backend->have_tls_get && ad_ins && jit_tls_ins) {
+                                       NEW_BBLOCK (cfg, next_bb);
+                                       NEW_BBLOCK (cfg, call_bb);
 
-                                               MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, next_bb);
-                                               MONO_START_BB (cfg, call_bb);
+                                       if (cfg->compile_aot) {
+                                               /* AOT code is only used in the root domain */
+                                               EMIT_NEW_PCONST (cfg, domain_ins, NULL);
+                                       } else {
+                                               EMIT_NEW_PCONST (cfg, domain_ins, cfg->domain);
                                        }
+                                       MONO_ADD_INS (cfg->cbb, ad_ins);
+                                       MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, ad_ins->dreg, domain_ins->dreg);
+                                       MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, call_bb);
 
-                                       /* AOT code is only used in the root domain */
-                                       EMIT_NEW_PCONST (cfg, args [0], cfg->compile_aot ? NULL : cfg->domain);
-                                       EMIT_NEW_PCONST (cfg, args [1], NULL);
-                                       ins = mono_emit_jit_icall (cfg, mono_jit_thread_attach, args);
-                                       MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->attach_cookie->dreg, ins->dreg);
+                                       MONO_ADD_INS (cfg->cbb, jit_tls_ins);
+                                       MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, jit_tls_ins->dreg, 0);
+                                       MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, call_bb);
 
-                                       if (next_bb)
-                                               MONO_START_BB (cfg, next_bb);
+                                       MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, next_bb);
+                                       MONO_START_BB (cfg, call_bb);
                                }
 
+                               /* AOT code is only used in the root domain */
+                               EMIT_NEW_PCONST (cfg, args [0], cfg->compile_aot ? NULL : cfg->domain);
+                               ins = mono_emit_jit_icall (cfg, mono_jit_thread_attach, args);
+                               MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->orig_domain_var->dreg, ins->dreg);
+
+                               if (next_bb)
+                                       MONO_START_BB (cfg, next_bb);
+
+
                                ip += 2;
                                break;
                        }
@@ -12828,9 +12804,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
 
                                /* Restore the original domain */
                                dreg = alloc_ireg (cfg);
-                               EMIT_NEW_UNALU (cfg, args [0], OP_MOVE, dreg, cfg->attach_cookie->dreg);
-                               EMIT_NEW_VARLOADA (cfg, args [1], cfg->attach_dummy, cfg->attach_dummy->inst_vtype);
-                               mono_emit_jit_icall (cfg, mono_jit_thread_detach, args);
+                               EMIT_NEW_UNALU (cfg, args [0], OP_MOVE, dreg, cfg->orig_domain_var->dreg);
+                               mono_emit_jit_icall (cfg, mono_jit_set_domain, args);
                                ip += 2;
                                break;
                        }
@@ -12979,6 +12954,12 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                constrained_class = NULL;
                                break;
                        }
+                       case CEE_MONO_LDDOMAIN:
+                               CHECK_STACK_OVF (1);
+                               EMIT_NEW_PCONST (cfg, ins, cfg->compile_aot ? NULL : cfg->domain);
+                               ip += 2;
+                               *sp++ = ins;
+                               break;
                        default:
                                g_error ("opcode 0x%02x 0x%02x not handled", MONO_CUSTOM_PREFIX, ip [1]);
                                break;
@@ -13078,7 +13059,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
 
                                cil_method = cmethod;
                                if (!dont_verify && !cfg->skip_visibility && !mono_method_can_access_method (method, cmethod))
-                                       METHOD_ACCESS_FAILURE (method, cil_method);
+                                       emit_method_access_failure (cfg, method, cil_method);
 
                                if (mono_security_core_clr_enabled ())
                                        ensure_method_is_allowed_to_call_method (cfg, method, cmethod);
@@ -13278,8 +13259,10 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                ip += 4;
                                inline_costs += 1;
                                break;
-                       case CEE_LOCALLOC:
+                       case CEE_LOCALLOC: {
                                CHECK_STACK (1);
+                               MonoBasicBlock *non_zero_bb, *end_bb;
+                               int alloc_ptr = alloc_preg (cfg);
                                --sp;
                                if (sp != stack_start) 
                                        UNVERIFIED;
@@ -13291,8 +13274,20 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                         */
                                        INLINE_FAILURE("localloc");
 
+                               NEW_BBLOCK (cfg, non_zero_bb);
+                               NEW_BBLOCK (cfg, end_bb);
+
+                               /* if size != zero */
+                               MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, sp [0]->dreg, 0);
+                               MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, non_zero_bb);
+
+                               //size is zero, so result is NULL
+                               MONO_EMIT_NEW_PCONST (cfg, alloc_ptr, NULL);
+                               MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
+
+                               MONO_START_BB (cfg, non_zero_bb);
                                MONO_INST_NEW (cfg, ins, OP_LOCALLOC);
-                               ins->dreg = alloc_preg (cfg);
+                               ins->dreg = alloc_ptr;
                                ins->sreg1 = sp [0]->dreg;
                                ins->type = STACK_PTR;
                                MONO_ADD_INS (cfg->cbb, ins);
@@ -13301,9 +13296,14 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                if (init_locals)
                                        ins->flags |= MONO_INST_INIT;
 
+                               MONO_START_BB (cfg, end_bb);
+                               EMIT_NEW_UNALU (cfg, ins, OP_MOVE, alloc_preg (cfg), alloc_ptr);
+                               ins->type = STACK_PTR;
+
                                *sp++ = ins;
                                ip += 2;
                                break;
+                       }
                        case CEE_ENDFILTER: {
                                MonoExceptionClause *clause, *nearest;
                                int cc;
@@ -13683,7 +13683,6 @@ mono_error_exit:
        g_slist_free (class_inits);
        mono_basic_block_free (original_bb);
        cfg->dont_inline = g_list_remove (cfg->dont_inline, method);
-       cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, header);
        if (cfg->exception_type)
                return -1;
        else
@@ -15037,6 +15036,74 @@ mono_spill_global_vars (MonoCompile *cfg, gboolean *need_local_opts)
        g_free (live_range_end_bb);
 }
 
+static void
+mono_decompose_typecheck (MonoCompile *cfg, MonoBasicBlock *bb, MonoInst *ins)
+{
+       MonoInst *ret, *move, *source;
+       MonoClass *klass = ins->klass;
+       int context_used = mini_class_check_context_used (cfg, klass);
+       int is_isinst = ins->opcode == OP_ISINST;
+       g_assert (is_isinst || ins->opcode == OP_CASTCLASS);
+       source = get_vreg_to_inst (cfg, ins->sreg1);
+       if (!source || source == (MonoInst *) -1)
+               source = mono_compile_create_var_for_vreg (cfg, &mono_defaults.object_class->byval_arg, OP_LOCAL, ins->sreg1);
+       g_assert (source && source != (MonoInst *) -1);
+
+       MonoBasicBlock *first_bb;
+       NEW_BBLOCK (cfg, first_bb);
+       cfg->cbb = first_bb;
+
+       if (!context_used && mini_class_has_reference_variant_generic_argument (cfg, klass, context_used)) {
+               if (is_isinst)
+                       ret = emit_isinst_with_cache_nonshared (cfg, source, klass);
+               else
+                       ret = emit_castclass_with_cache_nonshared (cfg, source, klass);
+       } else if (!context_used && (mono_class_is_marshalbyref (klass) || klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
+               MonoInst *iargs [1];
+               int costs;
+
+               iargs [0] = source;
+               if (is_isinst) {
+                       MonoMethod *wrapper = mono_marshal_get_isinst (klass);
+                       costs = inline_method (cfg, wrapper, mono_method_signature (wrapper), iargs, 0, 0, TRUE);
+               } else {
+                       MonoMethod *wrapper = mono_marshal_get_castclass (klass);
+                       save_cast_details (cfg, klass, source->dreg, TRUE);
+                       costs = inline_method (cfg, wrapper, mono_method_signature (wrapper), iargs, 0, 0, TRUE);
+                       reset_cast_details (cfg);
+               }
+               g_assert (costs > 0);
+               ret = iargs [0];
+       } else {
+               if (is_isinst)
+                       ret = handle_isinst (cfg, klass, source, context_used);
+               else
+                       ret = handle_castclass (cfg, klass, source, context_used);
+       }
+       EMIT_NEW_UNALU (cfg, move, OP_MOVE, ins->dreg, ret->dreg);
+
+       g_assert (cfg->cbb->code || first_bb->code);
+       MonoInst *prev = ins->prev;
+       mono_replace_ins (cfg, bb, ins, &prev, first_bb, cfg->cbb);
+}
+
+void
+mono_decompose_typechecks (MonoCompile *cfg)
+{
+       for (MonoBasicBlock *bb = cfg->bb_entry; bb; bb = bb->next_bb) {
+               MonoInst *ins;
+               MONO_BB_FOR_EACH_INS (bb, ins) {
+                       switch (ins->opcode) {
+                       case OP_ISINST:
+                       case OP_CASTCLASS:
+                               mono_decompose_typecheck (cfg, bb, ins);
+                               break;
+                       }
+               }
+       }
+}
+
+
 /**
  * FIXME:
  * - use 'iadd' instead of 'int_add'