[netcore] Copy Array.Clear impl from CoreCLR (mono/mono#17411)
authorEgor Bogatov <egorbo@gmail.com>
Mon, 4 Nov 2019 17:48:04 +0000 (20:48 +0300)
committerZoltan Varga <vargaz@gmail.com>
Mon, 4 Nov 2019 17:48:04 +0000 (12:48 -0500)
* Address feedback

* fix build error

* Fix has_reference usage in object.c

* Fix fallback impl

* Rename to ArrayHasReferences

* Rename to ObjectHasReferences

* Rollback to ArrayHasReferences

* Rename to ObjectHasReference

* remove redundant is_array variable

* ObjectHasReferences can accept any object

* undo changes in Program.cs

* undo changes in Program.cs

Commit migrated from https://github.com/mono/mono/commit/cf8495e2f73a56770d5a9d876ab865485b4f353b

src/mono/mono/metadata/class-internals.h
src/mono/mono/metadata/icall-def-netcore.h
src/mono/mono/metadata/object.c
src/mono/mono/mini/intrinsics.c
src/mono/netcore/System.Private.CoreLib/src/System/Array.Mono.cs
src/mono/netcore/System.Private.CoreLib/src/System/Runtime/CompilerServices/RuntimeHelpers.Mono.cs

index dc3e5fa..d4b52bf 100644 (file)
@@ -334,7 +334,8 @@ typedef gpointer MonoRuntimeGenericContext;
 
 typedef enum {
        /* array or string */
-       MONO_VT_FLAG_ARRAY_OR_STRING = (1 << 0)
+       MONO_VT_FLAG_ARRAY_OR_STRING = (1 << 0),
+       MONO_VT_FLAG_HAS_REFERENCES = (1 << 1)
 } MonoVTableFlags;
 
 /* the interface_offsets array is stored in memory before this struct */
index 7091c0f..5f33179 100644 (file)
@@ -38,7 +38,6 @@ NOHANDLES(ICALL(ARGI_4, "Setup",                 ves_icall_System_ArgIterator_Se
 
 ICALL_TYPE(ARRAY, "System.Array", ARRAY_0)
 HANDLES(ARRAY_0, "CanChangePrimitive",  ves_icall_System_Array_CanChangePrimitive, MonoBoolean, 3, (MonoReflectionType, MonoReflectionType, MonoBoolean))
-HANDLES(ARRAY_1, "ClearInternal", ves_icall_System_Array_ClearInternal, void, 3, (MonoArray, int, int))
 HANDLES(ARRAY_4, "FastCopy",         ves_icall_System_Array_FastCopy, MonoBoolean, 5, (MonoArray, int, MonoArray, int, int))
 NOHANDLES(ICALL(ARRAY_5, "GetGenericValue_icall", ves_icall_System_Array_GetGenericValue_icall))
 HANDLES(ARRAY_6, "GetLength",        ves_icall_System_Array_GetLength, gint32, 2, (MonoArray, gint32))
index a22b9be..0197ba2 100644 (file)
@@ -2105,6 +2105,9 @@ mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *klass, MonoErro
        vt->domain = domain;
        if ((vt->rank > 0) || klass == mono_get_string_class ())
                vt->flags |= MONO_VT_FLAG_ARRAY_OR_STRING;
+       
+       if (m_class_has_references (klass))
+               vt->flags |= MONO_VT_FLAG_HAS_REFERENCES;
 
        MONO_PROFILER_RAISE (vtable_loading, (vt));
 
index 7ed565d..a9ef42a 100644 (file)
@@ -912,6 +912,15 @@ mini_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSign
                        EMIT_NEW_UNALU (cfg, ins, OP_ICGT, dreg, -1);
                        ins->type = STACK_I4;
                        return ins;
+               } else if (!strcmp (cmethod->name, "ObjectHasReferences")) {
+                       int dreg = alloc_ireg (cfg);
+                       MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOAD_MEMBASE, dreg, args [0]->dreg, MONO_STRUCT_OFFSET (MonoObject, vtable));
+                       MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, dreg, dreg, MONO_STRUCT_OFFSET (MonoVTable, flags));
+                       MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, dreg, dreg, MONO_VT_FLAG_HAS_REFERENCES);
+                       EMIT_NEW_BIALU_IMM (cfg, ins, OP_COMPARE_IMM, -1, dreg, 0);
+                       EMIT_NEW_UNALU (cfg, ins, OP_ICGT, dreg, -1);
+                       ins->type = STACK_I4;
+                       return ins;
                } else
                        return NULL;
        } else if (cmethod->klass == mono_defaults.monitor_class) {
index 0b400ea..6f4b24f 100644 (file)
@@ -7,6 +7,12 @@ using System.Collections;
 using System.Collections.Generic;
 using System.Runtime.CompilerServices;
 using System.Runtime.InteropServices;
+using Mono;
+#if BIT64
+using nuint = System.UInt64;
+#else
+using nuint = System.UInt32;
+#endif
 
 namespace System
 {
@@ -48,24 +54,27 @@ namespace System
                        }
                }
 
-               public static void Clear (Array array, int index, int length)
+               public static unsafe void Clear (Array array, int index, int length)
                {
                        if (array == null)
-                               ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array);
-                       if (length < 0)
-                               ThrowHelper.ThrowIndexOutOfRangeException();
+                               ThrowHelper.ThrowArgumentNullException (ExceptionArgument.array);
 
-                       int low = array!.GetLowerBound (0);
-                       if (index < low)
-                               ThrowHelper.ThrowIndexOutOfRangeException();
+                       int lowerBound = array.GetLowerBound (0);
+                       int elementSize = array.GetElementSize ();
+                       nuint numComponents = (nuint) Unsafe.As<RawData> (array).Count;
 
-                       index = index - low;
+                       int offset = index - lowerBound;
 
-                       // re-ordered to avoid possible integer overflow
-                       if (index > array.Length - length)
-                               ThrowHelper.ThrowIndexOutOfRangeException();
+                       if (index < lowerBound || offset < 0 || length < 0 || (uint) (offset + length) > numComponents)
+                               ThrowHelper.ThrowIndexOutOfRangeException ();
+
+                       ref byte ptr = ref Unsafe.AddByteOffset (ref array.GetRawSzArrayData(), (uint) offset * (nuint) elementSize);
+                       nuint byteLength = (uint) length * (nuint) elementSize;
 
-                       ClearInternal (array, index, length);
+                       if (RuntimeHelpers.ObjectHasReferences (array))
+                               SpanHelpers.ClearWithReferences (ref Unsafe.As<byte, IntPtr> (ref ptr), byteLength / (uint)sizeof (IntPtr));
+                       else
+                               SpanHelpers.ClearWithoutReferences (ref ptr, byteLength);
                }
 
                public static void ConstrainedCopy (Array sourceArray, int sourceIndex, Array destinationArray, int destinationIndex, int length)
@@ -485,9 +494,6 @@ namespace System
                }
 
                [MethodImplAttribute (MethodImplOptions.InternalCall)]
-               extern static void ClearInternal (Array a, int index, int count);
-
-               [MethodImplAttribute (MethodImplOptions.InternalCall)]
                extern static bool CanChangePrimitive (Type srcType, Type dstType, bool reliable);
 
                [MethodImplAttribute (MethodImplOptions.InternalCall)]
@@ -499,6 +505,7 @@ namespace System
                [MethodImplAttribute (MethodImplOptions.InternalCall)]
                public extern int GetLength (int dimension);
 
+               [Intrinsic] // when dimension is `0` constant
                [MethodImplAttribute (MethodImplOptions.InternalCall)]
                public extern int GetLowerBound (int dimension);
 
index 1fb26a1..23d16af 100644 (file)
@@ -112,11 +112,17 @@ namespace System.Runtime.CompilerServices
                }
 
                [Intrinsic]
-               internal static unsafe bool ObjectHasComponentSize (object obj)
+               internal static bool ObjectHasComponentSize (object obj)
                {
                        throw new NotImplementedException ();
                }
 
+               [Intrinsic]
+               internal static bool ObjectHasReferences (object obj)
+               {
+                       return RuntimeTypeHandle.HasReferences (obj.GetType () as RuntimeType);
+               }
+
                static object GetUninitializedObjectInternal (Type type)
                {
                        return GetUninitializedObjectInternal (new RuntimeTypeHandle ((RuntimeType)type).Value);