Merge branch 'master' of github.com:mono/mono
[mono.git] / mono / mini / method-to-ir.c
index 428889f755aabe17c4f3111202dd2dbdeddd0170..e46bb852cd014837fe473a984438e1f2c61d6a9f 100644 (file)
@@ -2590,6 +2590,71 @@ create_write_barrier_bitmap (MonoClass *klass, unsigned *wb_bitmap, int offset)
        }
 }
 
+static void
+emit_write_barrier (MonoCompile *cfg, MonoInst *ptr, MonoInst *value, int value_reg)
+{
+#ifdef HAVE_SGEN_GC
+       int card_table_shift_bits;
+       gpointer card_table_mask;
+       guint8 *card_table = mono_gc_get_card_table (&card_table_shift_bits, &card_table_mask);
+       MonoInst *dummy_use;
+
+#ifdef MONO_ARCH_HAVE_CARD_TABLE_WBARRIER
+       int nursery_shift_bits;
+       size_t nursery_size;
+
+       mono_gc_get_nursery (&nursery_shift_bits, &nursery_size);
+
+       if (!cfg->compile_aot && card_table && nursery_shift_bits > 0) {
+               MonoInst *wbarrier;
+
+               MONO_INST_NEW (cfg, wbarrier, OP_CARD_TABLE_WBARRIER);
+               wbarrier->sreg1 = ptr->dreg;
+               if (value)
+                       wbarrier->sreg2 = value->dreg;
+               else
+                       wbarrier->sreg2 = value_reg;
+               MONO_ADD_INS (cfg->cbb, wbarrier);
+       } else
+#endif
+       if (card_table) {
+               int offset_reg = alloc_preg (cfg);
+               int card_reg  = alloc_preg (cfg);
+               MonoInst *ins;
+
+               MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_UN_IMM, offset_reg, ptr->dreg, card_table_shift_bits);
+               if (card_table_mask)
+                       MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PAND_IMM, offset_reg, offset_reg, card_table_mask);
+
+               /*We can't use PADD_IMM since the cardtable might end up in high addresses and amd64 doesn't support
+                * IMM's larger than 32bits.
+                */
+               if (cfg->compile_aot) {
+                       MONO_EMIT_NEW_AOTCONST (cfg, card_reg, NULL, MONO_PATCH_INFO_GC_CARD_TABLE_ADDR);
+               } else {
+                       MONO_INST_NEW (cfg, ins, OP_PCONST);
+                       ins->inst_p0 = card_table;
+                       ins->dreg = card_reg;
+                       MONO_ADD_INS (cfg->cbb, ins);
+               }
+
+               MONO_EMIT_NEW_BIALU (cfg, OP_PADD, offset_reg, offset_reg, card_reg);
+               MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI1_MEMBASE_IMM, offset_reg, 0, 1);
+       } else {
+               MonoMethod *write_barrier = mono_gc_get_write_barrier ();
+               mono_emit_method_call (cfg, write_barrier, &ptr, NULL);
+       }
+
+       if (value) {
+               EMIT_NEW_DUMMY_USE (cfg, dummy_use, value);
+       } else {
+               MONO_INST_NEW (cfg, dummy_use, OP_DUMMY_USE);
+               dummy_use->sreg1 = value_reg;
+               MONO_ADD_INS (cfg->cbb, dummy_use);
+       }
+#endif
+}
+
 static gboolean
 mono_emit_wb_aware_memcpy (MonoCompile *cfg, MonoClass *klass, MonoInst *iargs[4], int size, int align)
 {
@@ -2635,17 +2700,8 @@ mono_emit_wb_aware_memcpy (MonoCompile *cfg, MonoClass *klass, MonoInst *iargs[4
                MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOAD_MEMBASE, tmp_reg, srcreg, offset);
                MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, dest_ptr_reg, 0, tmp_reg);
 
-               if (need_wb & 0x1) {
-                       MonoInst *dummy_use;
-
-                       MonoMethod *write_barrier = mono_gc_get_write_barrier ();
-                       mono_emit_method_call (cfg, write_barrier, &iargs [0], NULL);
-
-                       MONO_INST_NEW (cfg, dummy_use, OP_DUMMY_USE);
-                       dummy_use->sreg1 = dest_ptr_reg;
-                       MONO_ADD_INS (cfg->cbb, dummy_use);
-               }
-
+               if (need_wb & 0x1)
+                       emit_write_barrier (cfg, iargs [0], NULL, tmp_reg);
 
                offset += SIZEOF_VOID_P;
                size -= SIZEOF_VOID_P;
@@ -4434,12 +4490,8 @@ mini_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSign
                                g_assert_not_reached ();
                        }
 
-                       if (cfg->gen_write_barriers && is_ref) {
-                               MonoInst *dummy_use;
-                               MonoMethod *write_barrier = mono_gc_get_write_barrier ();
-                               mono_emit_method_call (cfg, write_barrier, &args [0], NULL);
-                               EMIT_NEW_DUMMY_USE (cfg, dummy_use, args [1]);
-                       }
+                       if (cfg->gen_write_barriers && is_ref)
+                               emit_write_barrier (cfg, args [0], args [1], -1);
                }
 #endif /* MONO_ARCH_HAVE_ATOMIC_EXCHANGE */
  
@@ -4472,12 +4524,8 @@ mini_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSign
                        } else {
                                /* g_assert_not_reached (); */
                        }
-                       if (cfg->gen_write_barriers && is_ref) {
-                               MonoInst *dummy_use;
-                               MonoMethod *write_barrier = mono_gc_get_write_barrier ();
-                               mono_emit_method_call (cfg, write_barrier, &args [0], NULL);
-                               EMIT_NEW_DUMMY_USE (cfg, dummy_use, args [1]);
-                       }
+                       if (cfg->gen_write_barriers && is_ref)
+                               emit_write_barrier (cfg, args [0], args [1], -1);
                }
 #endif /* MONO_ARCH_HAVE_ATOMIC_CAS */
 
@@ -4689,6 +4737,12 @@ inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig,
                return 0;
        }
 
+       /*Must verify before creating locals as it can cause the JIT to assert.*/
+       if (mono_compile_is_broken (cfg, cmethod, FALSE)) {
+               mono_metadata_free_mh (cheader);
+               return 0;
+       }
+
        /* allocate space to store the return value */
        if (!MONO_TYPE_IS_VOID (fsig->ret)) {
                rvar = mono_compile_create_var (cfg, fsig->ret, OP_LOCAL);
@@ -5389,9 +5443,6 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                dont_verify_stloc = TRUE;
        }
 
-       if (!dont_verify && mini_method_verify (cfg, method_definition))
-               goto exception_exit;
-
        if (mono_debug_using_mono_debugger ())
                cfg->keep_cil_nops = TRUE;
 
@@ -6134,7 +6185,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        /* FIXME: check the signature matches */
                        cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
 
-                       if (!cmethod)
+                       if (!cmethod || mono_loader_get_last_error ())
                                goto load_error;
  
                        if (cfg->generic_sharing_context && mono_method_check_context_used (cmethod))
@@ -6248,7 +6299,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                        cil_method = cmethod;
                                }
 
-                               if (!cmethod)
+                               if (!cmethod || mono_loader_get_last_error ())
                                        goto load_error;
                                if (!dont_verify && !cfg->skip_visibility) {
                                        MonoMethod *target_method = cil_method;
@@ -7192,13 +7243,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        ins_flag = 0;
                        MONO_ADD_INS (bblock, ins);
 
-                       if (cfg->gen_write_barriers && *ip == CEE_STIND_REF && method->wrapper_type != MONO_WRAPPER_WRITE_BARRIER && !((sp [1]->opcode == OP_PCONST) && (sp [1]->inst_p0 == 0))) {
-                               MonoInst *dummy_use;
-                               /* insert call to write barrier */
-                               MonoMethod *write_barrier = mono_gc_get_write_barrier ();
-                               mono_emit_method_call (cfg, write_barrier, sp, NULL);
-                               EMIT_NEW_DUMMY_USE (cfg, dummy_use, sp [1]);
-                       }
+                       if (cfg->gen_write_barriers && *ip == CEE_STIND_REF && method->wrapper_type != MONO_WRAPPER_WRITE_BARRIER && !((sp [1]->opcode == OP_PCONST) && (sp [1]->inst_p0 == 0)))
+                               emit_write_barrier (cfg, sp [0], sp [1], -1);
 
                        inline_costs += 1;
                        ++ip;
@@ -7401,12 +7447,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                store->flags |= ins_flag;
                                MONO_ADD_INS (cfg->cbb, store);
 
-                               if (cfg->gen_write_barriers && cfg->method->wrapper_type != MONO_WRAPPER_WRITE_BARRIER) {
-                                       MonoInst *dummy_use;
-                                       MonoMethod *write_barrier = mono_gc_get_write_barrier ();
-                                       mono_emit_method_call (cfg, write_barrier, sp, NULL);
-                                       EMIT_NEW_DUMMY_USE (cfg, dummy_use, sp [1]);
-                               }
+                               if (cfg->gen_write_barriers && cfg->method->wrapper_type != MONO_WRAPPER_WRITE_BARRIER)
+                                       emit_write_barrier (cfg, sp [0], sp [1], -1);
                        } else {
                                mini_emit_stobj (cfg, sp [0], sp [1], klass, FALSE);
                        }
@@ -7547,7 +7589,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        CHECK_OPSIZE (5);
                        token = read32 (ip + 1);
                        cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
-                       if (!cmethod)
+                       if (!cmethod || mono_loader_get_last_error ())
                                goto load_error;
                        fsig = mono_method_get_signature (cmethod, image, token);
                        if (!fsig)
@@ -8161,16 +8203,12 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
 
                                if (cfg->gen_write_barriers && 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 */
-                                       MonoMethod *write_barrier = mono_gc_get_write_barrier ();
-                                       MonoInst *iargs [2], *dummy_use;
+                                       MonoInst *ptr;
                                        int dreg;
 
                                        dreg = alloc_preg (cfg);
-                                       EMIT_NEW_BIALU_IMM (cfg, iargs [0], OP_PADD_IMM, dreg, sp [0]->dreg, foffset);
-                                       iargs [1] = sp [1];
-                                       mono_emit_method_call (cfg, write_barrier, iargs, NULL);
-
-                                       EMIT_NEW_DUMMY_USE (cfg, dummy_use, sp [1]);
+                                       EMIT_NEW_BIALU_IMM (cfg, ptr, OP_PADD_IMM, dreg, sp [0]->dreg, foffset);
+                                       emit_write_barrier (cfg, ptr, sp [1], -1);
                                }
 
                                        store->flags |= ins_flag;
@@ -8553,11 +8591,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0, sp [1]->dreg);
                        if (cfg->gen_write_barriers && cfg->method->wrapper_type != MONO_WRAPPER_WRITE_BARRIER &&
                                        generic_class_is_reference_type (cfg, klass)) {
-                               MonoInst *dummy_use;
                                /* insert call to write barrier */
-                               MonoMethod *write_barrier = mono_gc_get_write_barrier ();
-                               mono_emit_method_call (cfg, write_barrier, sp, NULL);
-                               EMIT_NEW_DUMMY_USE (cfg, dummy_use, sp [1]);
+                               emit_write_barrier (cfg, sp [0], sp [1], -1);
                        }
                        ins_flag = 0;
                        ip += 5;
@@ -9580,7 +9615,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                CHECK_OPSIZE (6);
                                n = read32 (ip + 2);
                                cmethod = mini_get_method (cfg, method, n, NULL, generic_context);
-                               if (!cmethod)
+                               if (!cmethod || mono_loader_get_last_error ())
                                        goto load_error;
                                mono_class_init (cmethod->klass);
 
@@ -9654,7 +9689,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                CHECK_OPSIZE (6);
                                n = read32 (ip + 2);
                                cmethod = mini_get_method (cfg, method, n, NULL, generic_context);
-                               if (!cmethod)
+                               if (!cmethod || mono_loader_get_last_error ())
                                        goto load_error;
                                mono_class_init (cmethod->klass);