Merge pull request #4816 from BrzVlad/fix-remoting-exception
[mono.git] / mono / mini / method-to-ir.c
index ac86126e9b725d93da12e5d844092df27a42a4e6..41dbd1a5cb6ed91e279e332a6e4d0656d0c9c3ec 100644 (file)
@@ -1161,10 +1161,24 @@ type_from_op (MonoCompile *cfg, MonoInst *ins, MonoInst *src1, MonoInst *src2)
                ins->klass = mono_defaults.object_class;
 }
 
-static const char 
-ldind_type [] = {
-       STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I8, STACK_PTR, STACK_R8, STACK_R8, STACK_OBJ
-};
+static MonoClass*
+ldind_to_type (int op)
+{
+       switch (op) {
+       case CEE_LDIND_I1: return mono_defaults.sbyte_class;
+       case CEE_LDIND_U1: return mono_defaults.byte_class;
+       case CEE_LDIND_I2: return mono_defaults.int16_class;
+       case CEE_LDIND_U2: return mono_defaults.uint16_class;
+       case CEE_LDIND_I4: return mono_defaults.int32_class;
+       case CEE_LDIND_U4: return mono_defaults.uint32_class;
+       case CEE_LDIND_I8: return mono_defaults.int64_class;
+       case CEE_LDIND_I: return mono_defaults.int_class;
+       case CEE_LDIND_R4: return mono_defaults.single_class;
+       case CEE_LDIND_R8: return mono_defaults.double_class;
+       case CEE_LDIND_REF:return mono_defaults.object_class; //FIXME we should try to return a more specific type
+       default: g_error ("Unknown ldind type %d", op);
+       }
+}
 
 #if 0
 
@@ -1579,142 +1593,6 @@ mini_emit_runtime_constant (MonoCompile *cfg, MonoJumpInfoType patch_type, gpoin
        return ins;
 }
 
-static void 
-mini_emit_memset (MonoCompile *cfg, int destreg, int offset, int size, int val, int align)
-{
-       int val_reg;
-
-       g_assert (val == 0);
-
-       if (align == 0)
-               align = 4;
-
-       if ((size <= SIZEOF_REGISTER) && (size <= align)) {
-               switch (size) {
-               case 1:
-                       MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI1_MEMBASE_IMM, destreg, offset, val);
-                       return;
-               case 2:
-                       MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI2_MEMBASE_IMM, destreg, offset, val);
-                       return;
-               case 4:
-                       MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI4_MEMBASE_IMM, destreg, offset, val);
-                       return;
-#if SIZEOF_REGISTER == 8
-               case 8:
-                       MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI8_MEMBASE_IMM, destreg, offset, val);
-                       return;
-#endif
-               }
-       }
-
-       val_reg = alloc_preg (cfg);
-
-       if (SIZEOF_REGISTER == 8)
-               MONO_EMIT_NEW_I8CONST (cfg, val_reg, val);
-       else
-               MONO_EMIT_NEW_ICONST (cfg, val_reg, val);
-
-       if (align < 4) {
-               /* This could be optimized further if neccesary */
-               while (size >= 1) {
-                       MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, offset, val_reg);
-                       offset += 1;
-                       size -= 1;
-               }
-               return;
-       }       
-
-       if (!cfg->backend->no_unaligned_access && SIZEOF_REGISTER == 8) {
-               if (offset % 8) {
-                       MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, offset, val_reg);
-                       offset += 4;
-                       size -= 4;
-               }
-               while (size >= 8) {
-                       MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, destreg, offset, val_reg);
-                       offset += 8;
-                       size -= 8;
-               }
-       }       
-
-       while (size >= 4) {
-               MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, offset, val_reg);
-               offset += 4;
-               size -= 4;
-       }
-       while (size >= 2) {
-               MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, destreg, offset, val_reg);
-               offset += 2;
-               size -= 2;
-       }
-       while (size >= 1) {
-               MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, offset, val_reg);
-               offset += 1;
-               size -= 1;
-       }
-}
-
-void 
-mini_emit_memcpy (MonoCompile *cfg, int destreg, int doffset, int srcreg, int soffset, int size, int align)
-{
-       int cur_reg;
-
-       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) {
-                       cur_reg = alloc_preg (cfg);
-                       MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, cur_reg, srcreg, soffset);
-                       MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, doffset, cur_reg);
-                       doffset += 1;
-                       soffset += 1;
-                       size -= 1;
-               }
-       }
-
-       if (!cfg->backend->no_unaligned_access && SIZEOF_REGISTER == 8) {
-               while (size >= 8) {
-                       cur_reg = alloc_preg (cfg);
-                       MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI8_MEMBASE, cur_reg, srcreg, soffset);
-                       MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, destreg, doffset, cur_reg);
-                       doffset += 8;
-                       soffset += 8;
-                       size -= 8;
-               }
-       }       
-
-       while (size >= 4) {
-               cur_reg = alloc_preg (cfg);
-               MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, cur_reg, srcreg, soffset);
-               MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, doffset, cur_reg);
-               doffset += 4;
-               soffset += 4;
-               size -= 4;
-       }
-       while (size >= 2) {
-               cur_reg = alloc_preg (cfg);
-               MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI2_MEMBASE, cur_reg, srcreg, soffset);
-               MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, destreg, doffset, cur_reg);
-               doffset += 2;
-               soffset += 2;
-               size -= 2;
-       }
-       while (size >= 1) {
-               cur_reg = alloc_preg (cfg);
-               MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, cur_reg, srcreg, soffset);
-               MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, doffset, cur_reg);
-               doffset += 1;
-               soffset += 1;
-               size -= 1;
-       }
-}
-
 static MonoInst*
 mono_create_fast_tls_getter (MonoCompile *cfg, MonoTlsKey key)
 {
@@ -6768,7 +6646,7 @@ mini_get_method (MonoCompile *cfg, MonoMethod *m, guint32 token, MonoClass *klas
        return method;
 }
 
-static inline MonoClass*
+MonoClass*
 mini_get_class (MonoMethod *method, guint32 token, MonoGenericContext *context)
 {
        MonoError error;
@@ -8722,6 +8600,9 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
 
                        sp -= n;
 
+                       if (cmethod && cmethod->klass->image == mono_defaults.corlib && !strcmp (cmethod->klass->name, "ThrowHelper"))
+                               cfg->cbb->out_of_line = TRUE;
+
                        /*
                         * We have the `constrained.' prefix opcode.
                         */
@@ -9356,7 +9237,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        }
 
                        /* Common call */
-                       if (!(cmethod->iflags & METHOD_IMPL_ATTRIBUTE_AGGRESSIVE_INLINING))
+                       if (!(method->iflags & METHOD_IMPL_ATTRIBUTE_AGGRESSIVE_INLINING) && !(cmethod->iflags & METHOD_IMPL_ATTRIBUTE_AGGRESSIVE_INLINING))
                                INLINE_FAILURE ("call");
                        ins = mono_emit_method_call_full (cfg, cmethod, fsig, tail_call, sp, virtual_ ? sp [0] : NULL,
                                                                                          imt_arg, vtable_arg);
@@ -9754,32 +9635,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        CHECK_STACK (1);
                        --sp;
 
-                       switch (*ip) {
-                       case CEE_LDIND_R4:
-                       case CEE_LDIND_R8:
-                               dreg = alloc_freg (cfg);
-                               break;
-                       case CEE_LDIND_I8:
-                               dreg = alloc_lreg (cfg);
-                               break;
-                       case CEE_LDIND_REF:
-                               dreg = alloc_ireg_ref (cfg);
-                               break;
-                       default:
-                               dreg = alloc_preg (cfg);
-                       }
-
-                       NEW_LOAD_MEMBASE (cfg, ins, ldind_to_load_membase (*ip), dreg, sp [0]->dreg, 0);
-                       ins->type = ldind_type [*ip - CEE_LDIND_I1];
-                       if (*ip == CEE_LDIND_R4)
-                               ins->type = cfg->r4_stack_type;
-                       ins->flags |= ins_flag;
-                       MONO_ADD_INS (cfg->cbb, ins);
+                       ins = mini_emit_memory_load (cfg, &ldind_to_type (*ip)->byval_arg, sp [0], 0, ins_flag);
                        *sp++ = ins;
-                       if (ins_flag & MONO_INST_VOLATILE) {
-                               /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
-                               mini_emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
-                       }
                        ins_flag = 0;
                        ++ip;
                        break;
@@ -10075,15 +9932,9 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                break;
                        }
 
-                       EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0);
-                       ins->flags |= ins_flag;
+                       ins = mini_emit_memory_load (cfg, &klass->byval_arg, sp [0], 0, ins_flag);
                        *sp++ = ins;
 
-                       if (ins_flag & MONO_INST_VOLATILE) {
-                               /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
-                               mini_emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
-                       }
-
                        ip += 5;
                        ins_flag = 0;
                        inline_costs += 1;
@@ -10841,19 +10692,19 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                                }
                                        }
 
+                                       MonoInst *field_add_inst = sp [0];
                                        if (mini_is_gsharedvt_klass (klass)) {
                                                MonoInst *offset_ins;
 
                                                offset_ins = emit_get_gsharedvt_info (cfg, field, MONO_RGCTX_INFO_FIELD_OFFSET);
                                                /* The value is offset by 1 */
                                                EMIT_NEW_BIALU_IMM (cfg, ins, OP_PSUB_IMM, offset_ins->dreg, offset_ins->dreg, 1);
-                                               dreg = alloc_ireg_mp (cfg);
-                                               EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, sp [0]->dreg, offset_ins->dreg);
-                                               EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, field->type, dreg, 0);
-                                       } else {
-                                               EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, field->type, sp [0]->dreg, foffset);
+                                               EMIT_NEW_BIALU (cfg, field_add_inst, OP_PADD, alloc_ireg_mp (cfg), sp [0]->dreg, offset_ins->dreg);
+                                               foffset = 0;
                                        }
-                                       load->flags |= ins_flag;
+
+                                       load = mini_emit_memory_load (cfg, field->type, field_add_inst, foffset, ins_flag);
+
                                        if (sp [0]->opcode != OP_LDADDR)
                                                load->flags |= MONO_INST_FAULT;
                                        *sp++ = load;
@@ -10984,7 +10835,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                        int addr_reg = mono_alloc_preg (cfg);
                                        EMIT_NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, addr_reg, static_data->dreg, field->offset);
                                }
-                               } else if ((cfg->opt & MONO_OPT_SHARED) || (cfg->compile_aot && addr)) {
+                       } else if ((cfg->opt & MONO_OPT_SHARED) || (cfg->compile_aot && addr)) {
                                MonoInst *iargs [2];
 
                                g_assert (field->parent);
@@ -11164,18 +11015,9 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        token = read32 (ip + 1);
                        klass = mini_get_class (method, token, generic_context);
                        CHECK_TYPELOAD (klass);
-                       if (ins_flag & MONO_INST_VOLATILE) {
-                               /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
-                               mini_emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
-                       }
+
                        /* FIXME: should check item at sp [1] is compatible with the type of the store. */
-                       EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0, sp [1]->dreg);
-                       ins->flags |= ins_flag;
-                       if (cfg->gen_write_barriers && cfg->method->wrapper_type != MONO_WRAPPER_WRITE_BARRIER &&
-                               generic_class_is_reference_type (cfg, klass) && !MONO_INS_IS_PCONST_NULL (sp [1])) {
-                               /* insert call to write barrier */
-                               mini_emit_write_barrier (cfg, sp [0], sp [1]);
-                       }
+                       mini_emit_memory_store (cfg, &klass->byval_arg, sp [0], sp [1], ins_flag);
                        ins_flag = 0;
                        ip += 5;
                        inline_costs += 1;
@@ -12785,56 +12627,21 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                ip += 6;
                                break;
                        case CEE_CPBLK:
-                       case CEE_INITBLK: {
-                               MonoInst *iargs [3];
                                CHECK_STACK (3);
                                sp -= 3;
-
-                               /* Skip optimized paths for volatile operations. */
-                               if ((ip [1] == CEE_CPBLK) && !(ins_flag & MONO_INST_VOLATILE) && (cfg->opt & MONO_OPT_INTRINS) && (sp [2]->opcode == OP_ICONST) && ((n = sp [2]->inst_c0) <= sizeof (gpointer) * 5)) {
-                                       mini_emit_memcpy (cfg, sp [0]->dreg, 0, sp [1]->dreg, 0, sp [2]->inst_c0, 0);
-                               } else if ((ip [1] == CEE_INITBLK) && !(ins_flag & MONO_INST_VOLATILE) && (cfg->opt & MONO_OPT_INTRINS) && (sp [2]->opcode == OP_ICONST) && ((n = sp [2]->inst_c0) <= sizeof (gpointer) * 5) && (sp [1]->opcode == OP_ICONST) && (sp [1]->inst_c0 == 0)) {
-                                       /* emit_memset only works when val == 0 */
-                                       mini_emit_memset (cfg, sp [0]->dreg, 0, sp [2]->inst_c0, sp [1]->inst_c0, 0);
-                               } else {
-                                       MonoInst *call;
-                                       iargs [0] = sp [0];
-                                       iargs [1] = sp [1];
-                                       iargs [2] = sp [2];
-                                       if (ip [1] == CEE_CPBLK) {
-                                               /*
-                                                * FIXME: It's unclear whether we should be emitting both the acquire
-                                                * and release barriers for cpblk. It is technically both a load and
-                                                * store operation, so it seems like that's the sensible thing to do.
-                                                *
-                                                * FIXME: We emit full barriers on both sides of the operation for
-                                                * simplicity. We should have a separate atomic memcpy method instead.
-                                                */
-                                               MonoMethod *memcpy_method = mini_get_memcpy_method ();
-
-                                               if (ins_flag & MONO_INST_VOLATILE)
-                                                       mini_emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
-
-                                               call = mono_emit_method_call (cfg, memcpy_method, iargs, NULL);
-                                               call->flags |= ins_flag;
-
-                                               if (ins_flag & MONO_INST_VOLATILE)
-                                                       mini_emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
-                                       } else {
-                                               MonoMethod *memset_method = mini_get_memset_method ();
-                                               if (ins_flag & MONO_INST_VOLATILE) {
-                                                       /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
-                                                       mini_emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
-                                               }
-                                               call = mono_emit_method_call (cfg, memset_method, iargs, NULL);
-                                               call->flags |= ins_flag;
-                                       }
-                               }
+                               mini_emit_memory_copy_bytes (cfg, sp [0], sp [1], sp [2], ins_flag);
+                               ip += 2;
+                               ins_flag = 0;
+                               inline_costs += 1;
+                               break;
+                       case CEE_INITBLK:
+                               CHECK_STACK (3);
+                               sp -= 3;
+                               mini_emit_memory_init_bytes (cfg, sp [0], sp [1], sp [2], ins_flag);
                                ip += 2;
                                ins_flag = 0;
                                inline_costs += 1;
                                break;
-                       }
                        case CEE_NO_:
                                CHECK_OPSIZE (3);
                                if (ip [2] & 0x1)