Merge pull request #3716 from vargaz/unbox-stobj-null
authorRodrigo Kumpera <kumpera@users.noreply.github.com>
Thu, 13 Oct 2016 18:00:58 +0000 (14:00 -0400)
committerGitHub <noreply@github.com>
Thu, 13 Oct 2016 18:00:58 +0000 (14:00 -0400)
[jit] Add a small optimization for unbox.any+stobj called with a null…

1  2 
mono/mini/method-to-ir.c
mono/mini/mini.h

diff --combined mono/mini/method-to-ir.c
index 0929e7dc70050bcb549e1fd4fd4cb898d2fdbca2,be20f3e03397d9063e27406e77085ef5a05c8ea7..ad00295b8d291f8c9d4a7d1f60cd8e34fa15b088
@@@ -4572,7 -4572,7 +4572,7 @@@ handle_castclass (MonoCompile *cfg, Mon
        int vtable_reg = alloc_preg (cfg);
        MonoInst *klass_inst = NULL;
  
-       if (src->opcode == OP_PCONST && src->inst_p0 == 0)
+       if (MONO_INS_IS_PCONST_NULL (src))
                return src;
  
        if (context_used) {
@@@ -5056,7 -5056,7 +5056,7 @@@ handle_delegate_ctor (MonoCompile *cfg
  
        /* Set target field */
        /* Optimize away setting of NULL target */
-       if (!(target->opcode == OP_PCONST && target->inst_p0 == 0)) {
+       if (!MONO_INS_IS_PCONST_NULL (target)) {
                MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, target), target->dreg);
                if (cfg->gen_write_barriers) {
                        dreg = alloc_preg (cfg);
@@@ -5698,7 -5698,7 +5698,7 @@@ static MonoInst
  emit_array_store (MonoCompile *cfg, MonoClass *klass, MonoInst **sp, gboolean safety_checks)
  {
        if (safety_checks && generic_class_is_reference_type (cfg, klass) &&
-               !(sp [2]->opcode == OP_PCONST && sp [2]->inst_p0 == NULL)) {
+               !(MONO_INS_IS_PCONST_NULL (sp [2]))) {
                MonoClass *obj_array = mono_array_class_get_cached (mono_defaults.object_class, 1);
                MonoMethod *helper = mono_marshal_get_virtual_stelemref (obj_array);
                MonoInst *iargs [3];
@@@ -8479,8 -8479,7 +8479,8 @@@ mono_method_to_ir (MonoCompile *cfg, Mo
  
        /* we use a separate basic block for the initialization code */
        NEW_BBLOCK (cfg, init_localsbb);
 -      cfg->bb_init = init_localsbb;
 +      if (cfg->method == method)
 +              cfg->bb_init = init_localsbb;
        init_localsbb->real_offset = cfg->real_offset;
        start_bblock->next_bb = init_localsbb;
        init_localsbb->next_bb = cfg->cbb;
                                        
                                        addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, TRUE);
                                        EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, fsig->params [fsig->param_count - 1], addr->dreg, 0, val->dreg);
-                                       if (cfg->gen_write_barriers && val->type == STACK_OBJ && !(val->opcode == OP_PCONST && val->inst_c0 == 0))
+                                       if (cfg->gen_write_barriers && val->type == STACK_OBJ && !MONO_INS_IS_PCONST_NULL (val))
                                                emit_write_barrier (cfg, addr, val);
                                        if (cfg->gen_write_barriers && mini_is_gsharedvt_klass (cmethod->klass))
                                                GSHAREDVT_FAILURE (*ip);
  
                        MONO_ADD_INS (cfg->cbb, 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)))
+                       if (cfg->gen_write_barriers && *ip == CEE_STIND_REF && method->wrapper_type != MONO_WRAPPER_WRITE_BARRIER && !MONO_INS_IS_PCONST_NULL (sp [1]))
                                emit_write_barrier (cfg, sp [0], sp [1]);
  
                        inline_costs += 1;
                                res = handle_unbox_gsharedvt (cfg, klass, *sp);
                                inline_costs += 2;
                        } else if (generic_class_is_reference_type (cfg, klass)) {
-                               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;
+                               if (MONO_INS_IS_PCONST_NULL (*sp)) {
+                                       EMIT_NEW_PCONST (cfg, res, NULL);
+                                       res->type = STACK_OBJ;
+                               } else {
+                                       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 {
                                        if (sp [0]->opcode != OP_LDADDR)
                                                store->flags |= MONO_INST_FAULT;
  
-                                       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)) {
+                                       if (cfg->gen_write_barriers && mini_type_to_stind (cfg, field->type) == CEE_STIND_REF && !MONO_INS_IS_PCONST_NULL (sp [1])) {
                                                if (mini_is_gsharedvt_klass (klass)) {
                                                        g_assert (wbarrier_ptr_ins);
                                                        emit_write_barrier (cfg, wbarrier_ptr_ins, sp [1]);
                        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)) {
+                               generic_class_is_reference_type (cfg, klass) && !MONO_INS_IS_PCONST_NULL (sp [1])) {
                                /* insert call to write barrier */
                                emit_write_barrier (cfg, sp [0], sp [1]);
                        }
        if (cfg->method == method) {
                MonoBasicBlock *bb;
                for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
 -                      bb->region = mono_find_block_region (cfg, bb->real_offset);
 +                      if (bb == cfg->bb_init)
 +                              bb->region = -1;
 +                      else
 +                              bb->region = mono_find_block_region (cfg, bb->real_offset);
                        if (cfg->spvars)
                                mono_create_spvar_for_region (cfg, bb->region);
                        if (cfg->verbose_level > 2)
diff --combined mono/mini/mini.h
index a7bba5a62e4660dafca5a516e2cd9fe762e50cf2,ab2ba4e9dcdf58c7e41b8d3ff7e52a53873a5ccf..dd24cd540b12b9ff16146e1192d68942ef79c60e
@@@ -507,6 -507,8 +507,8 @@@ enum 
  /* INEG sets the condition codes, and the OP_LNEG decomposition depends on this on x86 */
  #define MONO_INS_HAS_NO_SIDE_EFFECT(ins) (MONO_IS_MOVE (ins) || (ins->opcode == OP_ICONST) || (ins->opcode == OP_I8CONST) || MONO_IS_ZERO (ins) || (ins->opcode == OP_ADD_IMM) || (ins->opcode == OP_R8CONST) || (ins->opcode == OP_LADD_IMM) || (ins->opcode == OP_ISUB_IMM) || (ins->opcode == OP_IADD_IMM) || (ins->opcode == OP_LNEG) || (ins->opcode == OP_ISUB) || (ins->opcode == OP_CMOV_IGE) || (ins->opcode == OP_ISHL_IMM) || (ins->opcode == OP_ISHR_IMM) || (ins->opcode == OP_ISHR_UN_IMM) || (ins->opcode == OP_IAND_IMM) || (ins->opcode == OP_ICONV_TO_U1) || (ins->opcode == OP_ICONV_TO_I1) || (ins->opcode == OP_SEXT_I4) || (ins->opcode == OP_LCONV_TO_U1) || (ins->opcode == OP_ICONV_TO_U2) || (ins->opcode == OP_ICONV_TO_I2) || (ins->opcode == OP_LCONV_TO_I2) || (ins->opcode == OP_LDADDR) || (ins->opcode == OP_PHI) || (ins->opcode == OP_NOP) || (ins->opcode == OP_ZEXT_I4) || (ins->opcode == OP_NOT_NULL) || (ins->opcode == OP_IL_SEQ_POINT))
  
+ #define MONO_INS_IS_PCONST_NULL(ins) ((ins)->opcode == OP_PCONST && (ins)->inst_p0 == 0)
  #define MONO_METHOD_IS_FINAL(m) (((m)->flags & METHOD_ATTRIBUTE_FINAL) || ((m)->klass && ((m)->klass->flags & TYPE_ATTRIBUTE_SEALED)))
  
  
@@@ -1496,7 -1498,6 +1498,7 @@@ typedef struct 
        guint            need_got_var : 1;
        guint            need_div_check : 1;
        guint            no_unaligned_access : 1;
 +      guint            disable_div_with_mul : 1;
        int              monitor_enter_adjustment;
        int              dyn_call_param_area;
  } MonoBackend;