From f7fad34e43db22000b06711d492dc6a9ae0b274a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Strehovsk=C3=BD?= Date: Mon, 9 Dec 2024 08:46:46 +0100 Subject: [PATCH] Remove some RuntimeExport/RuntimeImport indirections (#110437) We had indirections set up where we'd `RuntimeExport` a method under a symbolic name and then `RuntimeImport` it elsewhere (or call the export from JIT-generated code). Most of this was motivated by the old Redhawk layering where things like casting and interface dispatch were part of Runtime.Base and not part of CoreLib. Since we decided if we ever reintroduce a Runtime.Base, we wouldn't have casting in it, this indirection will no longer be needed. Motivated by #110267 (and also the reason why I'm only doing it for `RuntimeExport`s used from the JIT right now). Once that PR gets in, calling methods through `RuntimeExport`s would actually become a bigger deoptimization than it is now. --- .../System/Runtime/CompilerServices/Unsafe.cs | 15 ++++++++ .../src/System/Runtime/RuntimeExports.cs | 4 --- .../src/System/Runtime/TypeCast.cs | 11 ------ .../Runtime/Augments/RuntimeAugments.cs | 10 +++--- .../src/System/Array.NativeAot.cs | 10 +++--- .../src/System/InvokeUtils.cs | 2 +- .../System/Reflection/DynamicInvokeInfo.cs | 8 ++--- .../RuntimeHelpers.NativeAot.cs | 2 +- .../src/System/Runtime/RuntimeImports.cs | 8 ----- .../src/System/RuntimeType.cs | 2 +- .../src/System/ValueType.cs | 2 +- .../Test.CoreLib/src/System/Buffer.cs | 15 ++++++++ .../Test.CoreLib/src/System/SpanHelpers.cs | 34 ++++++++++++++++++ .../Test.CoreLib/src/Test.CoreLib.csproj | 2 ++ .../Common/TypeSystem/IL/HelperExtensions.cs | 6 ++++ .../ILCompiler.Compiler/Compiler/ILScanner.cs | 13 +++++++ .../ILCompiler.Compiler/Compiler/JitHelper.cs | 36 +++++++++---------- .../IL/ILImporter.Scanner.cs | 10 +++++- .../src/System/Buffer.cs | 3 -- .../src/System/SpanHelpers.ByteMemOps.cs | 9 ----- 20 files changed, 130 insertions(+), 72 deletions(-) create mode 100644 src/coreclr/nativeaot/Test.CoreLib/src/System/Buffer.cs create mode 100644 src/coreclr/nativeaot/Test.CoreLib/src/System/SpanHelpers.cs diff --git a/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/CompilerServices/Unsafe.cs b/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/CompilerServices/Unsafe.cs index 89eedc1638a72..7f95b9bd401fc 100644 --- a/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/CompilerServices/Unsafe.cs +++ b/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/CompilerServices/Unsafe.cs @@ -16,6 +16,21 @@ namespace System.Runtime.CompilerServices /// public static unsafe class Unsafe { + /// + /// Determines the byte offset from origin to target from the given references. + /// + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static IntPtr ByteOffset(ref readonly T origin, ref readonly T target) + { + throw new PlatformNotSupportedException(); + + // ldarg .1 + // ldarg .0 + // sub + // ret + } + /// /// Returns a pointer to the given by-ref parameter. /// diff --git a/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/RuntimeExports.cs b/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/RuntimeExports.cs index b7a1863d3727d..ae2b81bfa418d 100644 --- a/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/RuntimeExports.cs +++ b/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/RuntimeExports.cs @@ -73,7 +73,6 @@ public static unsafe object RhNewArray(MethodTable* pEEType, int length) } } - [RuntimeExport("RhBox")] public static unsafe object RhBox(MethodTable* pEEType, ref byte data) { // A null can be passed for boxing of a null ref. @@ -207,7 +206,6 @@ public static unsafe void RhUnboxAny(object? o, ref byte data, MethodTable* pUnb // // Unbox helpers with RyuJIT conventions // - [RuntimeExport("RhUnbox2")] public static unsafe ref byte RhUnbox2(MethodTable* pUnboxToEEType, object obj) { if ((obj == null) || !UnboxAnyTypeCompare(obj.GetMethodTable(), pUnboxToEEType)) @@ -218,7 +216,6 @@ public static unsafe ref byte RhUnbox2(MethodTable* pUnboxToEEType, object obj) return ref obj.GetRawData(); } - [RuntimeExport("RhUnboxNullable")] public static unsafe void RhUnboxNullable(ref byte data, MethodTable* pUnboxToEEType, object obj) { if (obj != null && obj.GetMethodTable() != pUnboxToEEType->NullableType) @@ -228,7 +225,6 @@ public static unsafe void RhUnboxNullable(ref byte data, MethodTable* pUnboxToEE RhUnbox(obj, ref data, pUnboxToEEType); } - [RuntimeExport("RhUnboxTypeTest")] public static unsafe void RhUnboxTypeTest(MethodTable* pType, MethodTable* pBoxType) { Debug.Assert(pType->IsValueType); diff --git a/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/TypeCast.cs b/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/TypeCast.cs index 20427987539c3..8425f31f16cc1 100644 --- a/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/TypeCast.cs +++ b/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/TypeCast.cs @@ -63,7 +63,6 @@ internal enum AssignmentVariation // IsInstanceOf test used for unusual cases (naked type parameters, variant generic types) // Unlike the IsInstanceOfInterface and IsInstanceOfClass functions, // this test must deal with all kinds of type tests - [RuntimeExport("RhTypeCast_IsInstanceOfAny")] public static unsafe object? IsInstanceOfAny(MethodTable* pTargetType, object? obj) { if (obj != null) @@ -94,7 +93,6 @@ internal enum AssignmentVariation return IsInstanceOfAny_NoCacheLookup(pTargetType, obj); } - [RuntimeExport("RhTypeCast_IsInstanceOfInterface")] public static unsafe object? IsInstanceOfInterface(MethodTable* pTargetType, object? obj) { Debug.Assert(pTargetType->IsInterface); @@ -184,7 +182,6 @@ internal enum AssignmentVariation return obj; } - [RuntimeExport("RhTypeCast_IsInstanceOfClass")] public static unsafe object? IsInstanceOfClass(MethodTable* pTargetType, object? obj) { Debug.Assert(!pTargetType->IsParameterizedType, "IsInstanceOfClass called with parameterized MethodTable"); @@ -248,7 +245,6 @@ internal enum AssignmentVariation return obj; } - [RuntimeExport("RhTypeCast_IsInstanceOfException")] public static unsafe bool IsInstanceOfException(MethodTable* pTargetType, object? obj) { // Based on IsInstanceOfClass @@ -279,7 +275,6 @@ public static unsafe bool IsInstanceOfException(MethodTable* pTargetType, object // ChkCast test used for unusual cases (naked type parameters, variant generic types) // Unlike the ChkCastInterface and ChkCastClass functions, // this test must deal with all kinds of type tests - [RuntimeExport("RhTypeCast_CheckCastAny")] public static unsafe object CheckCastAny(MethodTable* pTargetType, object obj) { CastResult result; @@ -307,7 +302,6 @@ public static unsafe object CheckCastAny(MethodTable* pTargetType, object obj) return objRet; } - [RuntimeExport("RhTypeCast_CheckCastInterface")] public static unsafe object CheckCastInterface(MethodTable* pTargetType, object obj) { Debug.Assert(pTargetType->IsInterface); @@ -393,7 +387,6 @@ private static unsafe object CheckCastInterface_Helper(MethodTable* pTargetType, return ThrowInvalidCastException(pTargetType); } - [RuntimeExport("RhTypeCast_CheckCastClass")] public static unsafe object CheckCastClass(MethodTable* pTargetType, object obj) { Debug.Assert(!pTargetType->IsParameterizedType, "CheckCastClass called with parameterized MethodTable"); @@ -411,7 +404,6 @@ public static unsafe object CheckCastClass(MethodTable* pTargetType, object obj) // Optimized helper for classes. Assumes that the trivial cases // has been taken care of by the inlined check - [RuntimeExport("RhTypeCast_CheckCastClassSpecial")] private static unsafe object CheckCastClassSpecial(MethodTable* pTargetType, object obj) { Debug.Assert(!pTargetType->IsParameterizedType, "CheckCastClassSpecial called with parameterized MethodTable"); @@ -761,8 +753,6 @@ private static unsafe void ThrowArrayMismatchException(object?[] array) // // Array stelem/ldelema helpers with RyuJIT conventions // - - [RuntimeExport("RhpLdelemaRef")] public static unsafe ref object? LdelemaRef(object?[] array, nint index, MethodTable* elementType) { Debug.Assert(array is null || array.GetMethodTable()->IsArray, "first argument must be an array"); @@ -794,7 +784,6 @@ private static unsafe void ThrowArrayMismatchException(object?[] array) return ref element; } - [RuntimeExport("RhpStelemRef")] public static unsafe void StelemRef(object?[] array, nint index, object? obj) { // This is supported only on arrays diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/Internal/Runtime/Augments/RuntimeAugments.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/Internal/Runtime/Augments/RuntimeAugments.cs index 363a544f8c74d..6fb23a261f333 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/Internal/Runtime/Augments/RuntimeAugments.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/Internal/Runtime/Augments/RuntimeAugments.cs @@ -216,7 +216,7 @@ public static unsafe void StoreValueTypeField(IntPtr address, object fieldValue, public static unsafe object LoadValueTypeField(IntPtr address, RuntimeTypeHandle fieldType) { - return RuntimeImports.RhBox(fieldType.ToMethodTable(), ref *(byte*)address); + return RuntimeExports.RhBox(fieldType.ToMethodTable(), ref *(byte*)address); } public static unsafe object LoadPointerTypeField(IntPtr address, RuntimeTypeHandle fieldType) @@ -236,7 +236,7 @@ public static unsafe void StoreValueTypeField(object obj, int fieldOffset, objec public static unsafe object LoadValueTypeField(object obj, int fieldOffset, RuntimeTypeHandle fieldType) { ref byte address = ref Unsafe.AddByteOffset(ref obj.GetRawData(), new IntPtr(fieldOffset - ObjectHeaderSize)); - return RuntimeImports.RhBox(fieldType.ToMethodTable(), ref address); + return RuntimeExports.RhBox(fieldType.ToMethodTable(), ref address); } public static unsafe object LoadPointerTypeField(object obj, int fieldOffset, RuntimeTypeHandle fieldType) @@ -244,7 +244,7 @@ public static unsafe object LoadPointerTypeField(object obj, int fieldOffset, Ru ref byte address = ref Unsafe.AddByteOffset(ref obj.GetRawData(), new IntPtr(fieldOffset - ObjectHeaderSize)); if (fieldType.ToMethodTable()->IsFunctionPointer) - return RuntimeImports.RhBox(MethodTable.Of(), ref address); + return RuntimeExports.RhBox(MethodTable.Of(), ref address); return ReflectionPointer.Box((void*)Unsafe.As(ref address), Type.GetTypeFromHandle(fieldType)); } @@ -285,7 +285,7 @@ public static object LoadValueTypeFieldValueFromValueType(TypedReference typedRe Debug.Assert(TypedReference.TargetTypeToken(typedReference).ToMethodTable()->IsValueType); Debug.Assert(fieldTypeHandle.ToMethodTable()->IsValueType); - return RuntimeImports.RhBox(fieldTypeHandle.ToMethodTable(), ref Unsafe.Add(ref typedReference.Value, fieldOffset)); + return RuntimeExports.RhBox(fieldTypeHandle.ToMethodTable(), ref Unsafe.Add(ref typedReference.Value, fieldOffset)); } [CLSCompliant(false)] @@ -391,7 +391,7 @@ public static bool IsInterface(RuntimeTypeHandle type) public static unsafe object Box(RuntimeTypeHandle type, IntPtr address) { - return RuntimeImports.RhBox(type.ToMethodTable(), ref *(byte*)address); + return RuntimeExports.RhBox(type.ToMethodTable(), ref *(byte*)address); } //============================================================================================== diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Array.NativeAot.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Array.NativeAot.cs index dc30aaecd1f06..09439509355e8 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Array.NativeAot.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Array.NativeAot.cs @@ -330,7 +330,7 @@ private static unsafe void CopyImplGcRefArray(Array sourceArray, int sourceIndex for (int i = 0; i < length; i++) { object? value = Unsafe.Add(ref refSourceArray, sourceIndex - i); - if (mustCastCheckEachElement && value != null && RuntimeImports.IsInstanceOf(destinationElementEEType, value) == null) + if (mustCastCheckEachElement && value != null && TypeCast.IsInstanceOfAny(destinationElementEEType, value) == null) throw new InvalidCastException(SR.InvalidCast_DownCastArrayElement); Unsafe.Add(ref refDestinationArray, destinationIndex - i) = value; } @@ -340,7 +340,7 @@ private static unsafe void CopyImplGcRefArray(Array sourceArray, int sourceIndex for (int i = 0; i < length; i++) { object? value = Unsafe.Add(ref refSourceArray, sourceIndex + i); - if (mustCastCheckEachElement && value != null && RuntimeImports.IsInstanceOf(destinationElementEEType, value) == null) + if (mustCastCheckEachElement && value != null && TypeCast.IsInstanceOfAny(destinationElementEEType, value) == null) throw new InvalidCastException(SR.InvalidCast_DownCastArrayElement); Unsafe.Add(ref refDestinationArray, destinationIndex + i) = value; } @@ -370,7 +370,7 @@ private static unsafe void CopyImplValueTypeArrayToReferenceArray(Array sourceAr ref object refDestinationArray = ref Unsafe.As(ref MemoryMarshal.GetArrayDataReference(destinationArray)); for (int i = 0; i < length; i++) { - object boxedValue = RuntimeImports.RhBox(sourceElementEEType, ref *pElement); + object boxedValue = RuntimeExports.RhBox(sourceElementEEType, ref *pElement); Unsafe.Add(ref refDestinationArray, destinationIndex + i) = boxedValue; pElement += sourceElementSize; } @@ -457,7 +457,7 @@ private static unsafe void CopyImplValueTypeArrayWithInnerGcRefs(Array sourceArr pDestinationElement -= cbElementSize; } - object boxedValue = RuntimeImports.RhBox(sourceElementEEType, ref *pSourceElement); + object boxedValue = RuntimeExports.RhBox(sourceElementEEType, ref *pSourceElement); if (boxedElements != null) boxedElements[i] = boxedValue; else @@ -768,7 +768,7 @@ internal unsafe nint GetFlattenedIndex(ReadOnlySpan indices) MethodTable* pElementEEType = ElementMethodTable; if (pElementEEType->IsValueType) { - return RuntimeImports.RhBox(pElementEEType, ref element); + return RuntimeExports.RhBox(pElementEEType, ref element); } else { diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/InvokeUtils.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/InvokeUtils.cs index b6fc499829d17..61a2d5367c7cb 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/InvokeUtils.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/InvokeUtils.cs @@ -133,7 +133,7 @@ private static Exception ConvertOrWidenPrimitivesEnumsAndPointersIfPossible(obje if (dstElementType == srcElementType) { // Rebox the value if the EETypeElementTypes match - dstObject = RuntimeImports.RhBox(dstEEType, ref srcObject.GetRawData()); + dstObject = RuntimeExports.RhBox(dstEEType, ref srcObject.GetRawData()); } else { diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/DynamicInvokeInfo.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/DynamicInvokeInfo.cs index 45bc2f9e19978..d7837bdc649e1 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/DynamicInvokeInfo.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/DynamicInvokeInfo.cs @@ -783,7 +783,7 @@ private unsafe void CopyBackToArray(ref object? src, object?[] dest) } else { - obj = RuntimeImports.RhBox( + obj = RuntimeExports.RhBox( (transform & Transform.FunctionPointer) != 0 ? MethodTable.Of() : argumentInfo.Type, ref obj.GetRawData()); } @@ -818,7 +818,7 @@ private unsafe void CopyBackToSpan(Span src, Span dest) } else { - obj = RuntimeImports.RhBox( + obj = RuntimeExports.RhBox( (transform & Transform.FunctionPointer) != 0 ? MethodTable.Of() : argumentInfo.Type, ref obj.GetRawData()); } @@ -849,7 +849,7 @@ private unsafe object ReturnTransform(ref byte byref, bool wrapInTargetInvocatio else if ((_returnTransform & Transform.FunctionPointer) != 0) { Debug.Assert(Type.GetTypeFromMethodTable(_returnType).IsFunctionPointer); - obj = RuntimeImports.RhBox(MethodTable.Of(), ref byref); + obj = RuntimeExports.RhBox(MethodTable.Of(), ref byref); } else if ((_returnTransform & Transform.Reference) != 0) { @@ -859,7 +859,7 @@ private unsafe object ReturnTransform(ref byte byref, bool wrapInTargetInvocatio else { Debug.Assert((_returnTransform & (Transform.ByRef | Transform.Nullable)) != 0); - obj = RuntimeImports.RhBox(_returnType, ref byref); + obj = RuntimeExports.RhBox(_returnType, ref byref); } return obj; } diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Runtime/CompilerServices/RuntimeHelpers.NativeAot.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Runtime/CompilerServices/RuntimeHelpers.NativeAot.cs index 8488a99f12a26..b30bfd88ef082 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Runtime/CompilerServices/RuntimeHelpers.NativeAot.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Runtime/CompilerServices/RuntimeHelpers.NativeAot.cs @@ -380,7 +380,7 @@ public static unsafe object GetUninitializedObject( if (mt->IsByRefLike) throw new NotSupportedException(SR.NotSupported_ByRefLike); - return RuntimeImports.RhBox(mt, ref target); + return RuntimeExports.RhBox(mt, ref target); } /// diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Runtime/RuntimeImports.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Runtime/RuntimeImports.cs index 15587b4746721..454c5a1e0c4be 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Runtime/RuntimeImports.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Runtime/RuntimeImports.cs @@ -379,10 +379,6 @@ internal static IntPtr RhHandleAllocDependent(object primary, object secondary) [RuntimeImport(RuntimeLibrary, "RhTypeCast_CheckArrayStore")] internal static extern void RhCheckArrayStore(object array, object? obj); - [MethodImpl(MethodImplOptions.InternalCall)] - [RuntimeImport(RuntimeLibrary, "RhTypeCast_IsInstanceOfAny")] - internal static extern unsafe object IsInstanceOf(MethodTable* pTargetType, object obj); - // // calls to runtime for allocation // These calls are needed in types which cannot use "new" to allocate and need to do it manually @@ -405,10 +401,6 @@ internal static IntPtr RhHandleAllocDependent(object primary, object secondary) [RuntimeImport(RuntimeLibrary, "RhNewString")] internal static extern unsafe string RhNewString(MethodTable* pEEType, int length); - [MethodImpl(MethodImplOptions.InternalCall)] - [RuntimeImport(RuntimeLibrary, "RhBox")] - internal static extern unsafe object RhBox(MethodTable* pEEType, ref byte data); - [MethodImpl(MethodImplOptions.InternalCall)] [RuntimeImport(RuntimeLibrary, "RhUnbox")] internal static extern unsafe void RhUnbox(object? obj, ref byte data, MethodTable* pUnboxToEEType); diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/RuntimeType.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/RuntimeType.cs index 1ccb983b64bc3..1854e6ddeb210 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/RuntimeType.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/RuntimeType.cs @@ -630,7 +630,7 @@ public override bool IsInstanceOfType([NotNullWhen(true)] object? o) return false; if (pEEType->IsNullable) pEEType = pEEType->NullableType; - return RuntimeImports.IsInstanceOf(pEEType, o) != null; + return TypeCast.IsInstanceOfAny(pEEType, o) != null; } // diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/ValueType.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/ValueType.cs index 968e97c425cf8..c19988c9bd678 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/ValueType.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/ValueType.cs @@ -146,7 +146,7 @@ private unsafe void RegularGetValueTypeHashCode(ref HashCode hashCode, ref byte // of __GetFieldHelper, decodes the unboxing stub pointed to by the slot to the real target // (we already have that part), and calls the entrypoint that expects a byref `this`, and use the // data to decide between calling fast or regular hashcode helper. - var fieldValue = (ValueType)RuntimeImports.RhBox(fieldType, ref fieldData); + var fieldValue = (ValueType)RuntimeExports.RhBox(fieldType, ref fieldData); if (fieldValue != null) { hashCode.Add(fieldValue); diff --git a/src/coreclr/nativeaot/Test.CoreLib/src/System/Buffer.cs b/src/coreclr/nativeaot/Test.CoreLib/src/System/Buffer.cs new file mode 100644 index 0000000000000..9549be1ae49c7 --- /dev/null +++ b/src/coreclr/nativeaot/Test.CoreLib/src/System/Buffer.cs @@ -0,0 +1,15 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Runtime; +using System.Runtime.CompilerServices; + +namespace System +{ + public static partial class Buffer + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static void BulkMoveWithWriteBarrier(ref byte destination, ref byte source, nuint byteCount) => + RuntimeImports.RhBulkMoveWithWriteBarrier(ref destination, ref source, byteCount); + } +} diff --git a/src/coreclr/nativeaot/Test.CoreLib/src/System/SpanHelpers.cs b/src/coreclr/nativeaot/Test.CoreLib/src/System/SpanHelpers.cs new file mode 100644 index 0000000000000..77c20f716a4d6 --- /dev/null +++ b/src/coreclr/nativeaot/Test.CoreLib/src/System/SpanHelpers.cs @@ -0,0 +1,34 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Runtime.CompilerServices; + +namespace System +{ + internal static partial class SpanHelpers + { + [Intrinsic] + public static unsafe void ClearWithoutReferences(ref byte dest, nuint len) + { + Fill(ref dest, 0, len); + } + + [Intrinsic] + internal static unsafe void Memmove(ref byte dest, ref byte src, nuint len) + { + if ((nuint)(nint)Unsafe.ByteOffset(ref src, ref dest) >= len) + for (nuint i = 0; i < len; i++) + Unsafe.Add(ref dest, (nint)i) = Unsafe.Add(ref src, (nint)i); + else + for (nuint i = len; i > 0; i--) + Unsafe.Add(ref dest, (nint)(i - 1)) = Unsafe.Add(ref src, (nint)(i - 1)); + } + + + internal static void Fill(ref byte dest, byte value, nuint len) + { + for (nuint i = 0; i < len; i++) + Unsafe.Add(ref dest, (nint)i) = value; + } + } +} diff --git a/src/coreclr/nativeaot/Test.CoreLib/src/Test.CoreLib.csproj b/src/coreclr/nativeaot/Test.CoreLib/src/Test.CoreLib.csproj index 9d606a6b75711..b838c2ed7c14b 100644 --- a/src/coreclr/nativeaot/Test.CoreLib/src/Test.CoreLib.csproj +++ b/src/coreclr/nativeaot/Test.CoreLib/src/Test.CoreLib.csproj @@ -232,6 +232,8 @@ + + diff --git a/src/coreclr/tools/Common/TypeSystem/IL/HelperExtensions.cs b/src/coreclr/tools/Common/TypeSystem/IL/HelperExtensions.cs index 4ccaff2d6dd9f..a02c9bbf9da98 100644 --- a/src/coreclr/tools/Common/TypeSystem/IL/HelperExtensions.cs +++ b/src/coreclr/tools/Common/TypeSystem/IL/HelperExtensions.cs @@ -33,6 +33,12 @@ public static MethodDesc GetHelperEntryPoint(this TypeSystemContext context, str return helperMethod; } + public static MethodDesc GetCoreLibEntryPoint(this TypeSystemContext context, string namespaceName, string typeName, string methodName, MethodSignature signature) + { + MetadataType owningType = context.SystemModule.GetKnownType(namespaceName, typeName); + return owningType.GetKnownMethod(methodName, signature); + } + public static MethodDesc GetOptionalHelperEntryPoint(this TypeSystemContext context, string typeName, string methodName) { MetadataType helperType = context.GetOptionalHelperType(typeName); diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/ILScanner.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/ILScanner.cs index d1fc6c593eef8..4d9328f1a34ee 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/ILScanner.cs +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/ILScanner.cs @@ -137,6 +137,19 @@ private void CompileSingleMethod(ScannedMethodNode methodCodeNodeNeedingCode) ILScanResults IILScanner.Scan() { + _dependencyGraph.AddRoot(GetHelperEntrypoint(ReadyToRunHelper.BulkWriteBarrier), "Not tracked by scanner"); + _dependencyGraph.AddRoot(GetHelperEntrypoint(ReadyToRunHelper.MemCpy), "Not tracked by scanner"); + _dependencyGraph.AddRoot(GetHelperEntrypoint(ReadyToRunHelper.MemSet), "Not tracked by scanner"); + _dependencyGraph.AddRoot(GetHelperEntrypoint(ReadyToRunHelper.MemZero), "Not tracked by scanner"); + _dependencyGraph.AddRoot(GetHelperEntrypoint(ReadyToRunHelper.CheckCastAny), "Not tracked by scanner"); + _dependencyGraph.AddRoot(GetHelperEntrypoint(ReadyToRunHelper.CheckCastInterface), "Not tracked by scanner"); + _dependencyGraph.AddRoot(GetHelperEntrypoint(ReadyToRunHelper.CheckCastClass), "Not tracked by scanner"); + _dependencyGraph.AddRoot(GetHelperEntrypoint(ReadyToRunHelper.CheckCastClassSpecial), "Not tracked by scanner"); + _dependencyGraph.AddRoot(GetHelperEntrypoint(ReadyToRunHelper.CheckInstanceAny), "Not tracked by scanner"); + _dependencyGraph.AddRoot(GetHelperEntrypoint(ReadyToRunHelper.CheckInstanceInterface), "Not tracked by scanner"); + _dependencyGraph.AddRoot(GetHelperEntrypoint(ReadyToRunHelper.CheckInstanceClass), "Not tracked by scanner"); + _dependencyGraph.AddRoot(GetHelperEntrypoint(ReadyToRunHelper.IsInstanceOfException), "Not tracked by scanner"); + _dependencyGraph.ComputeMarkedNodes(); _nodeFactory.SetMarkingComplete(); diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/JitHelper.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/JitHelper.cs index 8861535467c8c..1d78df875c125 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/JitHelper.cs +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/JitHelper.cs @@ -73,7 +73,7 @@ public static void GetEntryPoint(TypeSystemContext context, ReadyToRunHelper id, mangledName = context.Target.Architecture == TargetArchitecture.ARM64 ? "RhpCheckedAssignRefArm64" : "RhpCheckedAssignRef"; break; case ReadyToRunHelper.BulkWriteBarrier: - mangledName = "RhBuffer_BulkMoveWithWriteBarrier"; + methodDesc = context.GetCoreLibEntryPoint("System", "Buffer", "BulkMoveWithWriteBarrier", null); break; case ReadyToRunHelper.ByRefWriteBarrier: mangledName = context.Target.Architecture == TargetArchitecture.ARM64 ? "RhpByRefAssignRefArm64" : "RhpByRefAssignRef"; @@ -116,16 +116,16 @@ public static void GetEntryPoint(TypeSystemContext context, ReadyToRunHelper id, break; case ReadyToRunHelper.Box: case ReadyToRunHelper.Box_Nullable: - mangledName = "RhBox"; + methodDesc = context.GetCoreLibEntryPoint("System.Runtime", "RuntimeExports", "RhBox", null); break; case ReadyToRunHelper.Unbox: - mangledName = "RhUnbox2"; + methodDesc = context.GetCoreLibEntryPoint("System.Runtime", "RuntimeExports", "RhUnbox2", null); break; case ReadyToRunHelper.Unbox_Nullable: - mangledName = "RhUnboxNullable"; + methodDesc = context.GetCoreLibEntryPoint("System.Runtime", "RuntimeExports", "RhUnboxNullable", null); break; case ReadyToRunHelper.Unbox_TypeTest: - mangledName = "RhUnboxTypeTest"; + methodDesc = context.GetCoreLibEntryPoint("System.Runtime", "RuntimeExports", "RhUnboxTypeTest", null); break; case ReadyToRunHelper.NewMultiDimArr: @@ -143,20 +143,20 @@ public static void GetEntryPoint(TypeSystemContext context, ReadyToRunHelper id, break; case ReadyToRunHelper.Stelem_Ref: - mangledName = "RhpStelemRef"; + methodDesc = context.GetCoreLibEntryPoint("System.Runtime", "TypeCast", "StelemRef", null); break; case ReadyToRunHelper.Ldelema_Ref: - mangledName = "RhpLdelemaRef"; + methodDesc = context.GetCoreLibEntryPoint("System.Runtime", "TypeCast", "LdelemaRef", null); break; case ReadyToRunHelper.MemCpy: - mangledName = "RhSpanHelpers_MemCopy"; + methodDesc = context.GetCoreLibEntryPoint("System", "SpanHelpers", "Memmove", null); break; case ReadyToRunHelper.MemSet: - mangledName = "RhSpanHelpers_MemSet"; + methodDesc = context.GetCoreLibEntryPoint("System", "SpanHelpers", "Fill", null); break; case ReadyToRunHelper.MemZero: - mangledName = "RhSpanHelpers_MemZero"; + methodDesc = context.GetCoreLibEntryPoint("System", "SpanHelpers", "ClearWithoutReferences", null); break; case ReadyToRunHelper.NativeMemSet: mangledName = "memset"; @@ -284,29 +284,29 @@ public static void GetEntryPoint(TypeSystemContext context, ReadyToRunHelper id, break; case ReadyToRunHelper.CheckCastAny: - mangledName = "RhTypeCast_CheckCastAny"; + methodDesc = context.GetCoreLibEntryPoint("System.Runtime", "TypeCast", "CheckCastAny", null); break; case ReadyToRunHelper.CheckCastInterface: - mangledName = "RhTypeCast_CheckCastInterface"; + methodDesc = context.GetCoreLibEntryPoint("System.Runtime", "TypeCast", "CheckCastInterface", null); break; case ReadyToRunHelper.CheckCastClass: - mangledName = "RhTypeCast_CheckCastClass"; + methodDesc = context.GetCoreLibEntryPoint("System.Runtime", "TypeCast", "CheckCastClass", null); break; case ReadyToRunHelper.CheckCastClassSpecial: - mangledName = "RhTypeCast_CheckCastClassSpecial"; + methodDesc = context.GetCoreLibEntryPoint("System.Runtime", "TypeCast", "CheckCastClassSpecial", null); break; case ReadyToRunHelper.CheckInstanceAny: - mangledName = "RhTypeCast_IsInstanceOfAny"; + methodDesc = context.GetCoreLibEntryPoint("System.Runtime", "TypeCast", "IsInstanceOfAny", null); break; case ReadyToRunHelper.CheckInstanceInterface: - mangledName = "RhTypeCast_IsInstanceOfInterface"; + methodDesc = context.GetCoreLibEntryPoint("System.Runtime", "TypeCast", "IsInstanceOfInterface", null); break; case ReadyToRunHelper.CheckInstanceClass: - mangledName = "RhTypeCast_IsInstanceOfClass"; + methodDesc = context.GetCoreLibEntryPoint("System.Runtime", "TypeCast", "IsInstanceOfClass", null); break; case ReadyToRunHelper.IsInstanceOfException: - mangledName = "RhTypeCast_IsInstanceOfException"; + methodDesc = context.GetCoreLibEntryPoint("System.Runtime", "TypeCast", "IsInstanceOfException", null); break; case ReadyToRunHelper.MonitorEnter: diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/IL/ILImporter.Scanner.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/IL/ILImporter.Scanner.cs index 611d11e02edd1..00a0d56d48150 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/IL/ILImporter.Scanner.cs +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/IL/ILImporter.Scanner.cs @@ -897,6 +897,7 @@ private void ImportUnbox(int token, ILOpcode opCode) if (opCode == ILOpcode.unbox) { helper = ReadyToRunHelper.Unbox; + _dependencies.Add(GetHelperEntrypoint(ReadyToRunHelper.Unbox_TypeTest), "Unbox"); } else { @@ -1237,11 +1238,16 @@ private void ImportLoadElement(TypeDesc elementType) private void ImportStoreElement(int token) { - _dependencies.Add(GetHelperEntrypoint(ReadyToRunHelper.RngChkFail), "stelem"); + ImportStoreElement((TypeDesc)_methodIL.GetObject(token)); } private void ImportStoreElement(TypeDesc elementType) { + if (elementType == null || elementType.IsGCPointer) + { + _dependencies.Add(GetHelperEntrypoint(ReadyToRunHelper.Stelem_Ref), "stelem"); + } + _dependencies.Add(GetHelperEntrypoint(ReadyToRunHelper.RngChkFail), "stelem"); } @@ -1254,6 +1260,8 @@ private void ImportAddressOfElement(int token) _dependencies.Add(GetGenericLookupHelper(ReadyToRunHelperId.TypeHandle, elementType), "ldelema"); else _dependencies.Add(_factory.NecessaryTypeSymbol(elementType), "ldelema"); + + _dependencies.Add(GetHelperEntrypoint(ReadyToRunHelper.Ldelema_Ref), "ldelema"); } _dependencies.Add(GetHelperEntrypoint(ReadyToRunHelper.RngChkFail), "ldelema"); diff --git a/src/libraries/System.Private.CoreLib/src/System/Buffer.cs b/src/libraries/System.Private.CoreLib/src/System/Buffer.cs index 2a1e2a0299950..30ee85041633d 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Buffer.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Buffer.cs @@ -175,9 +175,6 @@ ref Unsafe.As(ref source), private const uint BulkMoveWithWriteBarrierChunk = 0x4000; #endif -#if NATIVEAOT - [System.Runtime.RuntimeExport("RhBuffer_BulkMoveWithWriteBarrier")] -#endif internal static void BulkMoveWithWriteBarrier(ref byte destination, ref byte source, nuint byteCount) { if (byteCount <= BulkMoveWithWriteBarrierChunk) diff --git a/src/libraries/System.Private.CoreLib/src/System/SpanHelpers.ByteMemOps.cs b/src/libraries/System.Private.CoreLib/src/System/SpanHelpers.ByteMemOps.cs index c4831969ccb0c..e2b33b5d4227f 100644 --- a/src/libraries/System.Private.CoreLib/src/System/SpanHelpers.ByteMemOps.cs +++ b/src/libraries/System.Private.CoreLib/src/System/SpanHelpers.ByteMemOps.cs @@ -33,9 +33,6 @@ private struct Block16 {} private struct Block64 {} #endif // HAS_CUSTOM_BLOCKS -#if NATIVEAOT - [System.Runtime.RuntimeExport("RhSpanHelpers_MemCopy")] -#endif [Intrinsic] // Unrolled for small constant lengths internal static unsafe void Memmove(ref byte dest, ref byte src, nuint len) { @@ -245,9 +242,6 @@ internal static unsafe void Memmove(ref byte dest, ref byte src, nuint len) Buffer._Memmove(ref dest, ref src, len); } -#if NATIVEAOT - [System.Runtime.RuntimeExport("RhSpanHelpers_MemZero")] -#endif [Intrinsic] // Unrolled for small sizes public static unsafe void ClearWithoutReferences(ref byte dest, nuint len) { @@ -434,9 +428,6 @@ public static unsafe void ClearWithoutReferences(ref byte dest, nuint len) Buffer._ZeroMemory(ref dest, len); } -#if NATIVEAOT - [System.Runtime.RuntimeExport("RhSpanHelpers_MemSet")] -#endif internal static void Fill(ref byte dest, byte value, nuint len) { if (!Vector.IsHardwareAccelerated)