From 5b3d9e5edca71c5ac755aaef4bb67472f414f02a Mon Sep 17 00:00:00 2001 From: Egor Bogatov Date: Mon, 4 Nov 2019 20:48:04 +0300 Subject: [PATCH] [netcore] Copy Array.Clear impl from CoreCLR (mono/mono#17411) * 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 | 3 +- src/mono/mono/metadata/icall-def-netcore.h | 1 - src/mono/mono/metadata/object.c | 3 ++ src/mono/mono/mini/intrinsics.c | 9 ++++++ .../src/System/Array.Mono.cs | 37 +++++++++++++--------- .../CompilerServices/RuntimeHelpers.Mono.cs | 8 ++++- 6 files changed, 43 insertions(+), 18 deletions(-) diff --git a/src/mono/mono/metadata/class-internals.h b/src/mono/mono/metadata/class-internals.h index dc3e5fa..d4b52bf 100644 --- a/src/mono/mono/metadata/class-internals.h +++ b/src/mono/mono/metadata/class-internals.h @@ -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 */ diff --git a/src/mono/mono/metadata/icall-def-netcore.h b/src/mono/mono/metadata/icall-def-netcore.h index 7091c0f..5f33179 100644 --- a/src/mono/mono/metadata/icall-def-netcore.h +++ b/src/mono/mono/metadata/icall-def-netcore.h @@ -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)) diff --git a/src/mono/mono/metadata/object.c b/src/mono/mono/metadata/object.c index a22b9be..0197ba2 100644 --- a/src/mono/mono/metadata/object.c +++ b/src/mono/mono/metadata/object.c @@ -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)); diff --git a/src/mono/mono/mini/intrinsics.c b/src/mono/mono/mini/intrinsics.c index 7ed565d..a9ef42a 100644 --- a/src/mono/mono/mini/intrinsics.c +++ b/src/mono/mono/mini/intrinsics.c @@ -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) { diff --git a/src/mono/netcore/System.Private.CoreLib/src/System/Array.Mono.cs b/src/mono/netcore/System.Private.CoreLib/src/System/Array.Mono.cs index 0b400ea..6f4b24f 100644 --- a/src/mono/netcore/System.Private.CoreLib/src/System/Array.Mono.cs +++ b/src/mono/netcore/System.Private.CoreLib/src/System/Array.Mono.cs @@ -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 (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 (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); diff --git a/src/mono/netcore/System.Private.CoreLib/src/System/Runtime/CompilerServices/RuntimeHelpers.Mono.cs b/src/mono/netcore/System.Private.CoreLib/src/System/Runtime/CompilerServices/RuntimeHelpers.Mono.cs index 1fb26a1..23d16af 100644 --- a/src/mono/netcore/System.Private.CoreLib/src/System/Runtime/CompilerServices/RuntimeHelpers.Mono.cs +++ b/src/mono/netcore/System.Private.CoreLib/src/System/Runtime/CompilerServices/RuntimeHelpers.Mono.cs @@ -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); -- 2.7.4