Merge pull request #4710 from Unity-Technologies/additional-config-checks
[mono.git] / mono / mini / method-to-ir.c
index 342f357f466dd0e881829b1a02cd1f594c4411b9..c47792226c4e983bd2eb1332ff5495c43292e7a1 100644 (file)
@@ -1261,16 +1261,22 @@ mono_get_got_var (MonoCompile *cfg)
        return cfg->got_var;
 }
 
-static MonoInst *
-mono_get_vtable_var (MonoCompile *cfg)
+static void
+mono_create_rgctx_var (MonoCompile *cfg)
 {
-       g_assert (cfg->gshared);
-
        if (!cfg->rgctx_var) {
                cfg->rgctx_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
                /* force the var to be stack allocated */
                cfg->rgctx_var->flags |= MONO_INST_VOLATILE;
        }
+}
+
+static MonoInst *
+mono_get_vtable_var (MonoCompile *cfg)
+{
+       g_assert (cfg->gshared);
+
+       mono_create_rgctx_var (cfg);
 
        return cfg->rgctx_var;
 }
@@ -3002,11 +3008,18 @@ emit_write_barrier (MonoCompile *cfg, MonoInst *ptr, MonoInst *value)
                wbarrier->sreg1 = ptr->dreg;
                wbarrier->sreg2 = value->dreg;
                MONO_ADD_INS (cfg->cbb, wbarrier);
-       } else if (card_table && !cfg->compile_aot && !mono_gc_card_table_nursery_check ()) {
+       } else if (card_table) {
                int offset_reg = alloc_preg (cfg);
                int card_reg;
                MonoInst *ins;
 
+               /*
+                * We emit a fast light weight write barrier. This always marks cards as in the concurrent
+                * collector case, so, for the serial collector, it might slightly slow down nursery
+                * collections. We also expect that the host system and the target system have the same card
+                * table configuration, which is the case if they have the same pointer size.
+                */
+
                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);
@@ -3040,24 +3053,11 @@ mono_emit_wb_aware_memcpy (MonoCompile *cfg, MonoClass *klass, MonoInst *iargs[4
        if (align < SIZEOF_VOID_P)
                return FALSE;
 
-       /*This value cannot be bigger than 32 due to the way we calculate the required wb bitmap.*/
-       if (size > 32 * SIZEOF_VOID_P)
+       if (size > 5 * SIZEOF_VOID_P)
                return FALSE;
 
        create_write_barrier_bitmap (cfg, klass, &need_wb, 0);
 
-       /* We don't unroll more than 5 stores to avoid code bloat. */
-       if (size > 5 * SIZEOF_VOID_P) {
-               /*This is harmless and simplify mono_gc_wbarrier_value_copy_bitmap */
-               size += (SIZEOF_VOID_P - 1);
-               size &= ~(SIZEOF_VOID_P - 1);
-
-               EMIT_NEW_ICONST (cfg, iargs [2], size);
-               EMIT_NEW_ICONST (cfg, iargs [3], need_wb);
-               mono_emit_jit_icall (cfg, mono_gc_wbarrier_value_copy_bitmap, iargs);
-               return TRUE;
-       }
-
        destreg = iargs [0]->dreg;
        srcreg = iargs [1]->dreg;
        offset = 0;
@@ -3151,6 +3151,8 @@ mini_emit_stobj (MonoCompile *cfg, MonoInst *dest, MonoInst *src, MonoClass *kla
        else
                n = mono_class_value_size (klass, &align);
 
+       if (!align)
+               align = SIZEOF_VOID_P;
        /* if native is true there should be no references in the struct */
        if (cfg->gen_write_barriers && (klass->has_references || size_ins) && !native) {
                /* Avoid barriers when storing to the stack */
@@ -3166,19 +3168,27 @@ mini_emit_stobj (MonoCompile *cfg, MonoInst *dest, MonoInst *src, MonoClass *kla
                        /* It's ok to intrinsify under gsharing since shared code types are layout stable. */
                        if (!size_ins && (cfg->opt & MONO_OPT_INTRINS) && mono_emit_wb_aware_memcpy (cfg, klass, iargs, n, align)) {
                                return;
-                       } else if (context_used) {
-                               iargs [2] = mini_emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
-                       }  else {
-                               iargs [2] = emit_runtime_constant (cfg, MONO_PATCH_INFO_CLASS, klass);
-                               if (!cfg->compile_aot)
-                                       mono_class_compute_gc_descriptor (klass);
-                       }
+                       } else if (size_ins || align < SIZEOF_VOID_P) {
+                               if (context_used) {
+                                       iargs [2] = mini_emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
+                               }  else {
+                                       iargs [2] = emit_runtime_constant (cfg, MONO_PATCH_INFO_CLASS, klass);
+                                       if (!cfg->compile_aot)
+                                               mono_class_compute_gc_descriptor (klass);
+                               }
+                               if (size_ins)
+                                       mono_emit_jit_icall (cfg, mono_gsharedvt_value_copy, iargs);
+                               else
+                                       mono_emit_jit_icall (cfg, mono_value_copy, iargs);
+                       } else {
+                               /* We don't unroll more than 5 stores to avoid code bloat. */
+                               /*This is harmless and simplify mono_gc_get_range_copy_func */
+                               n += (SIZEOF_VOID_P - 1);
+                               n &= ~(SIZEOF_VOID_P - 1);
 
-                       if (size_ins)
-                               mono_emit_jit_icall (cfg, mono_gsharedvt_value_copy, iargs);
-                       else
-                               mono_emit_jit_icall (cfg, mono_value_copy, iargs);
-                       return;
+                               EMIT_NEW_ICONST (cfg, iargs [2], n);
+                               mono_emit_jit_icall (cfg, mono_gc_get_range_copy_func (), iargs);
+                       }
                }
        }
 
@@ -3281,6 +3291,16 @@ emit_get_rgctx (MonoCompile *cfg, MonoMethod *method, int context_used)
                mrgctx_loc = mono_get_vtable_var (cfg);
                EMIT_NEW_TEMPLOAD (cfg, mrgctx_var, mrgctx_loc->inst_c0);
 
+               return mrgctx_var;
+       } else if (MONO_CLASS_IS_INTERFACE (cfg->method->klass)) {
+               MonoInst *mrgctx_loc, *mrgctx_var;
+
+               /* Default interface methods need an mrgctx since the vtabke at runtime points at an implementing class */
+               mrgctx_loc = mono_get_vtable_var (cfg);
+               EMIT_NEW_TEMPLOAD (cfg, mrgctx_var, mrgctx_loc->inst_c0);
+
+               g_assert (mono_method_needs_static_rgctx_invoke (cfg->method, TRUE));
+
                return mrgctx_var;
        } else if (method->flags & METHOD_ATTRIBUTE_STATIC || method->klass->valuetype) {
                MonoInst *vtable_loc, *vtable_var;
@@ -4579,9 +4599,11 @@ mono_method_check_inlining (MonoCompile *cfg, MonoMethod *method)
        /* also consider num_locals? */
        /* Do the size check early to avoid creating vtables */
        if (!inline_limit_inited) {
-               if (g_getenv ("MONO_INLINELIMIT"))
-                       inline_limit = atoi (g_getenv ("MONO_INLINELIMIT"));
-               else
+               char *inlinelimit;
+               if ((inlinelimit = g_getenv ("MONO_INLINELIMIT"))) {
+                       inline_limit = atoi (inlinelimit);
+                       g_free (inlinelimit);
+               } else
                        inline_limit = INLINE_LENGTH_LIMIT;
                inline_limit_inited = TRUE;
        }
@@ -4715,7 +4737,11 @@ 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 */
        if (COMPILE_LLVM (cfg)) {
-               /* Not needed */
+               /*
+                * abcrem can't handle the OP_SEXT_I4, so add this after abcrem,
+                * during OP_BOUNDS_CHECK decomposition, and in the implementation
+                * of OP_X86_LEA for llvm.
+                */
                index2_reg = index_reg;
        } else {
                index2_reg = alloc_preg (cfg);
@@ -4884,13 +4910,13 @@ static MonoBreakPolicyFunc break_policy_func = always_insert_breakpoint;
  * \param policy_callback the new callback function
  *
  * Allow embedders to decide wherther to actually obey breakpoint instructions
- * (both break IL instructions and \c Debugger.Break() method calls), for example
+ * (both break IL instructions and \c 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.
  *
  * \p policy_callback will be called every time a break point instruction needs to
- * be inserted with the method argument being the method that calls \c Debugger.Break()
- * or has the IL break instruction. The callback should return \c MONO_BREAK_POLICY_NEVER
+ * be inserted with the method argument being the method that calls \c Debugger.Break
+ * or has the IL \c break instruction. The callback should return \c MONO_BREAK_POLICY_NEVER
  * if it wants the breakpoint to not be effective in the given method.
  * \c MONO_BREAK_POLICY_ALWAYS is the default.
  */
@@ -6890,14 +6916,12 @@ initialize_array_data (MonoMethod *method, gboolean aot, unsigned char *ip, Mono
                        return NULL;
                if (strcmp (cmethod->name, "InitializeArray") || strcmp (cmethod->klass->name, "RuntimeHelpers") || cmethod->klass->image != mono_defaults.corlib)
                        return NULL;
-               switch (mono_type_get_underlying_type (&klass->byval_arg)->type) {
-               case MONO_TYPE_BOOLEAN:
+               switch (mini_get_underlying_type (&klass->byval_arg)->type) {
                case MONO_TYPE_I1:
                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 TARGET_BYTE_ORDER == G_LITTLE_ENDIAN
-               case MONO_TYPE_CHAR:
                case MONO_TYPE_I2:
                case MONO_TYPE_U2:
                        size = 2; break;
@@ -11186,6 +11210,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
 
                        klass = mini_get_class (method, token, generic_context);
                        CHECK_TYPELOAD (klass);
+                       if (klass->byval_arg.type == MONO_TYPE_VOID)
+                               UNVERIFIED;
 
                        context_used = mini_class_check_context_used (cfg, klass);
 
@@ -12342,6 +12368,21 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                ins->type = STACK_I4;
                                MONO_ADD_INS (cfg->cbb, ins);
 
+                               ip += 2;
+                               *sp++ = ins;
+                               break;
+                       case CEE_MONO_GET_RGCTX_ARG:
+                               CHECK_OPSIZE (2);
+                               CHECK_STACK_OVF (1);
+
+                               mono_create_rgctx_var (cfg);
+
+                               MONO_INST_NEW (cfg, ins, OP_MOVE);
+                               ins->dreg = alloc_dreg (cfg, STACK_PTR);
+                               ins->sreg1 = cfg->rgctx_var->dreg;
+                               ins->type = STACK_PTR;
+                               MONO_ADD_INS (cfg->cbb, ins);
+
                                ip += 2;
                                *sp++ = ins;
                                break;