Skip to content
Permalink

Comparing changes

This is a direct comparison between two commits made in this repository or its related repositories. View the default comparison for this range or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: dotnet/runtime
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 78385ca7515f57bcd1a10248fefd4ba88284be19
Choose a base ref
..
head repository: dotnet/runtime
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: cb4a61c97bd0719e2e1f521cf41aa34fe94f764c
Choose a head ref
Showing with 1,244 additions and 313 deletions.
  1. +2 −1 src/coreclr/System.Private.CoreLib/System.Private.CoreLib.csproj
  2. +8 −8 src/coreclr/System.Private.CoreLib/src/System/Array.CoreCLR.cs
  3. +25 −7 src/coreclr/System.Private.CoreLib/src/System/Enum.CoreCLR.cs
  4. +9 −5 src/coreclr/System.Private.CoreLib/src/System/RuntimeHandles.cs
  5. +31 −13 src/coreclr/System.Private.CoreLib/src/System/RuntimeType.ActivatorCache.cs
  6. +69 −52 src/coreclr/System.Private.CoreLib/src/System/RuntimeType.CoreCLR.cs
  7. +6 −2 src/coreclr/System.Private.CoreLib/src/System/RuntimeType.CreateUninitializedCache.CoreCLR.cs
  8. +167 −0 src/coreclr/System.Private.CoreLib/src/System/RuntimeType.GenericCache.cs
  9. +3 −0 src/coreclr/jit/emitarm64sve.cpp
  10. +1 −1 src/coreclr/jit/hwintrinsiccodegenarm64.cpp
  11. +12 −0 src/coreclr/jit/hwintrinsiclistarm64sve.h
  12. +3 −1 src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/SubstitutedILProvider.cs
  13. +26 −9 src/coreclr/vm/reflectioninvocation.cpp
  14. +1 −0 src/coreclr/vm/runtimehandles.h
  15. +21 −4 src/libraries/System.Private.CoreLib/src/System/Activator.RuntimeType.cs
  16. +1 −1 src/libraries/System.Private.CoreLib/src/System/Enum.EnumInfo.cs
  17. +1 −1 src/libraries/System.Private.CoreLib/src/System/Globalization/CompareInfo.WebAssembly.cs
  18. +102 −0 src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Arm/Sve.PlatformNotSupported.cs
  19. +102 −0 src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Arm/Sve.cs
  20. +13 −0 src/libraries/System.Runtime.Intrinsics/ref/System.Runtime.Intrinsics.cs
  21. +73 −65 src/libraries/System.Runtime.Numerics/src/System/Numerics/BigInteger.cs
  22. +11 −9 src/libraries/System.Runtime.Numerics/tests/BigInteger/op_rightshift.cs
  23. +1 −1 src/libraries/System.Runtime/ref/System.Runtime.cs
  24. +37 −93 ...ibraries/System.Runtime/tests/System.Globalization.Tests/CompareInfo/CompareInfoTests.HashCode.cs
  25. +39 −2 src/mono/System.Private.CoreLib/src/System/RuntimeType.Mono.cs
  26. +8 −3 src/native/external/llvm-libunwind/src/UnwindRegistersRestore.S
  27. +48 −35 src/tests/Common/GenerateHWIntrinsicTests/GenerateHWIntrinsicTests_Arm.cs
  28. +413 −0 src/tests/JIT/HardwareIntrinsics/Arm/Shared/SveLoadNonFaultingUnOpTest.template
  29. +11 −0 src/tests/Loader/classloader/generics/ByRefLike/Validate.cs
Original file line number Diff line number Diff line change
@@ -237,7 +237,8 @@
<Compile Include="$(CommonPath)System\Collections\Generic\ArrayBuilder.cs">
<Link>Common\System\Collections\Generic\ArrayBuilder.cs</Link>
</Compile>
<Compile Include="src\System\RuntimeType.CreateUninitializedCache.CoreCLR.cs" />
<Compile Include="src\System\RuntimeType.CreateUninitializedCache.CoreCLR.cs" />
<Compile Include="src\System\RuntimeType.GenericCache.cs" />
</ItemGroup>
<ItemGroup Condition="'$(FeatureComWrappers)' == 'true'">
<Compile Include="$(BclSourcesRoot)\System\Runtime\InteropServices\ComWrappers.cs" />
16 changes: 8 additions & 8 deletions src/coreclr/System.Private.CoreLib/src/System/Array.CoreCLR.cs
Original file line number Diff line number Diff line change
@@ -642,11 +642,7 @@ public unsafe void Initialize()

RuntimeType arrayType = (RuntimeType)GetType();

if (arrayType.GenericCache is not ArrayInitializeCache cache)
{
cache = new ArrayInitializeCache(arrayType);
arrayType.GenericCache = cache;
}
ArrayInitializeCache cache = arrayType.GetOrCreateCacheEntry<ArrayInitializeCache>();

delegate*<ref byte, void> constructorFtn = cache.ConstructorEntrypoint;
ref byte arrayRef = ref MemoryMarshal.GetArrayDataReference(this);
@@ -659,17 +655,21 @@ public unsafe void Initialize()
}
}

private sealed unsafe partial class ArrayInitializeCache
internal sealed unsafe partial class ArrayInitializeCache : RuntimeType.IGenericCacheEntry<ArrayInitializeCache>
{
internal readonly delegate*<ref byte, void> ConstructorEntrypoint;

[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "Array_GetElementConstructorEntrypoint")]
private static partial delegate*<ref byte, void> GetElementConstructorEntrypoint(QCallTypeHandle arrayType);

public ArrayInitializeCache(RuntimeType arrayType)
private ArrayInitializeCache(delegate*<ref byte, void> constructorEntrypoint)
{
ConstructorEntrypoint = GetElementConstructorEntrypoint(new QCallTypeHandle(ref arrayType));
ConstructorEntrypoint = constructorEntrypoint;
}

public static ArrayInitializeCache Create(RuntimeType arrayType) => new(GetElementConstructorEntrypoint(new QCallTypeHandle(ref arrayType)));
public void InitializeCompositeCache(RuntimeType.CompositeCacheEntry compositeEntry) => compositeEntry._arrayInitializeCache = this;
public static ref ArrayInitializeCache? GetStorageRef(RuntimeType.CompositeCacheEntry compositeEntry) => ref compositeEntry._arrayInitializeCache;
}
}

32 changes: 25 additions & 7 deletions src/coreclr/System.Private.CoreLib/src/System/Enum.CoreCLR.cs
Original file line number Diff line number Diff line change
@@ -87,31 +87,49 @@ private static EnumInfo<TStorage> GetEnumInfo<TStorage>(RuntimeType enumType, bo
typeof(TStorage) == typeof(nuint) || typeof(TStorage) == typeof(float) || typeof(TStorage) == typeof(double) || typeof(TStorage) == typeof(char),
$"Unexpected {nameof(TStorage)} == {typeof(TStorage)}");

return enumType.GenericCache is EnumInfo<TStorage> info && (!getNames || info.Names is not null) ?
return enumType.FindCacheEntry<EnumInfo<TStorage>>() is {} info && (!getNames || info.Names is not null) ?
info :
InitializeEnumInfo(enumType, getNames);

[MethodImpl(MethodImplOptions.NoInlining)]
static EnumInfo<TStorage> InitializeEnumInfo(RuntimeType enumType, bool getNames)
{
// If we're asked to get the cache with names,
// force that copy into the cache even if we already have a cache entry without names
// so we don't have to recompute the names if asked again.
return getNames
? enumType.ReplaceCacheEntry(EnumInfo<TStorage>.Create(enumType, getNames: true))
: enumType.GetOrCreateCacheEntry<EnumInfo<TStorage>>();
}
}

internal sealed partial class EnumInfo<TStorage> : RuntimeType.IGenericCacheEntry<EnumInfo<TStorage>>
{
public static EnumInfo<TStorage> Create(RuntimeType type, bool getNames)
{
TStorage[]? values = null;
string[]? names = null;

GetEnumValuesAndNames(
new QCallTypeHandle(ref enumType),
new QCallTypeHandle(ref type),
ObjectHandleOnStack.Create(ref values),
ObjectHandleOnStack.Create(ref names),
getNames ? Interop.BOOL.TRUE : Interop.BOOL.FALSE);

Debug.Assert(values!.GetType() == typeof(TStorage[]));
Debug.Assert(!getNames || names!.GetType() == typeof(string[]));

bool hasFlagsAttribute = enumType.IsDefined(typeof(FlagsAttribute), inherit: false);
bool hasFlagsAttribute = type.IsDefined(typeof(FlagsAttribute), inherit: false);

var entry = new EnumInfo<TStorage>(hasFlagsAttribute, values, names!);
enumType.GenericCache = entry;
return entry;
return new EnumInfo<TStorage>(hasFlagsAttribute, values, names!);
}

public static EnumInfo<TStorage> Create(RuntimeType type) => Create(type, getNames: false);

public void InitializeCompositeCache(RuntimeType.CompositeCacheEntry compositeEntry) => compositeEntry._enumInfo = this;

// This type is the only type that will be stored in the _enumInfo field, so we can use Unsafe.As here.
public static ref EnumInfo<TStorage>? GetStorageRef(RuntimeType.CompositeCacheEntry compositeEntry)
=> ref Unsafe.As<RuntimeType.IGenericCacheEntry?, EnumInfo<TStorage>?>(ref compositeEntry._enumInfo);
}
}
}
14 changes: 9 additions & 5 deletions src/coreclr/System.Private.CoreLib/src/System/RuntimeHandles.cs
Original file line number Diff line number Diff line change
@@ -270,24 +270,27 @@ internal static void GetActivationInfo(
RuntimeType rt,
out delegate*<void*, object> pfnAllocator,
out void* vAllocatorFirstArg,
out delegate*<object, void> pfnCtor,
out delegate*<object, void> pfnRefCtor,
out delegate*<ref byte, void> pfnValueCtor,
out bool ctorIsPublic)
{
Debug.Assert(rt != null);

delegate*<void*, object> pfnAllocatorTemp = default;
void* vAllocatorFirstArgTemp = default;
delegate*<object, void> pfnCtorTemp = default;
delegate*<object, void> pfnRefCtorTemp = default;
delegate*<ref byte, void> pfnValueCtorTemp = default;
Interop.BOOL fCtorIsPublicTemp = default;

GetActivationInfo(
ObjectHandleOnStack.Create(ref rt),
&pfnAllocatorTemp, &vAllocatorFirstArgTemp,
&pfnCtorTemp, &fCtorIsPublicTemp);
&pfnRefCtorTemp, &pfnValueCtorTemp, &fCtorIsPublicTemp);

pfnAllocator = pfnAllocatorTemp;
vAllocatorFirstArg = vAllocatorFirstArgTemp;
pfnCtor = pfnCtorTemp;
pfnRefCtor = pfnRefCtorTemp;
pfnValueCtor = pfnValueCtorTemp;
ctorIsPublic = fCtorIsPublicTemp != Interop.BOOL.FALSE;
}

@@ -296,7 +299,8 @@ private static partial void GetActivationInfo(
ObjectHandleOnStack pRuntimeType,
delegate*<void*, object>* ppfnAllocator,
void** pvAllocatorFirstArg,
delegate*<object, void>* ppfnCtor,
delegate*<object, void>* ppfnRefCtor,
delegate*<ref byte, void>* ppfnValueCtor,
Interop.BOOL* pfCtorIsPublic);

#if FEATURE_COMINTEROP
Original file line number Diff line number Diff line change
@@ -13,24 +13,27 @@ internal sealed partial class RuntimeType
/// A cache which allows optimizing <see cref="Activator.CreateInstance"/>,
/// <see cref="CreateInstanceDefaultCtor"/>, and related APIs.
/// </summary>
private sealed unsafe class ActivatorCache
internal sealed unsafe class ActivatorCache : IGenericCacheEntry<ActivatorCache>
{
// The managed calli to the newobj allocator, plus its first argument (MethodTable*).
// In the case of the COM allocator, first arg is ComClassFactory*, not MethodTable*.
private readonly delegate*<void*, object?> _pfnAllocator;
private readonly void* _allocatorFirstArg;

// The managed calli to the parameterless ctor, taking "this" (as object) as its first argument.
private readonly delegate*<object?, void> _pfnCtor;
private readonly delegate*<object?, void> _pfnRefCtor;
private readonly delegate*<ref byte, void> _pfnValueCtor;
private readonly bool _ctorIsPublic;

private CreateUninitializedCache? _createUninitializedCache;

#if DEBUG
private readonly RuntimeType _originalRuntimeType;
#endif

internal ActivatorCache(RuntimeType rt)
public static ActivatorCache Create(RuntimeType type) => new(type);
public void InitializeCompositeCache(RuntimeType.CompositeCacheEntry compositeEntry) => compositeEntry._activatorCache = this;
public static ref ActivatorCache? GetStorageRef(RuntimeType.CompositeCacheEntry compositeEntry) => ref compositeEntry._activatorCache;

private ActivatorCache(RuntimeType rt)
{
Debug.Assert(rt != null);

@@ -48,7 +51,7 @@ internal ActivatorCache(RuntimeType rt)
{
RuntimeTypeHandle.GetActivationInfo(rt,
out _pfnAllocator!, out _allocatorFirstArg,
out _pfnCtor!, out _ctorIsPublic);
out _pfnRefCtor!, out _pfnValueCtor!, out _ctorIsPublic);
}
catch (Exception ex)
{
@@ -87,14 +90,29 @@ internal ActivatorCache(RuntimeType rt)
// would have thrown an exception if 'rt' were a normal reference type
// without a ctor.

if (_pfnCtor == null)
if (_pfnRefCtor == null)
{
static void CtorNoopStub(object? uninitializedObject) { }
_pfnCtor = &CtorNoopStub; // we use null singleton pattern if no ctor call is necessary
static void RefCtorNoopStub(object? uninitializedObject) { }
_pfnRefCtor = &RefCtorNoopStub; // we use null singleton pattern if no ctor call is necessary

Debug.Assert(_ctorIsPublic); // implicit parameterless ctor is always considered public
}

if (rt.IsValueType)
{
if (_pfnValueCtor == null)
{
static void ValueRefCtorNoopStub(ref byte uninitializedObject) { }
_pfnValueCtor = &ValueRefCtorNoopStub; // we use null singleton pattern if no ctor call is necessary

Debug.Assert(_ctorIsPublic); // implicit parameterless ctor is always considered public
}
}
else
{
Debug.Assert(_pfnValueCtor == null); // Non-value types shouldn't have a value constructor.
}

// We don't need to worry about invoking cctors here. The runtime will figure it
// out for us when the instance ctor is called. For value types, because we're
// creating a boxed default(T), the static cctor is called when *any* instance
@@ -120,15 +138,15 @@ static void CtorNoopStub(object? uninitializedObject) { }
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal void CallConstructor(object? uninitializedObject) => _pfnCtor(uninitializedObject);
internal void CallRefConstructor(object? uninitializedObject) => _pfnRefCtor(uninitializedObject);

[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal CreateUninitializedCache GetCreateUninitializedCache(RuntimeType rt)
internal void CallValueConstructor(ref byte uninitializedObject)
{
#if DEBUG
CheckOriginalRuntimeType(rt);
Debug.Assert(_originalRuntimeType.IsValueType);
#endif
return _createUninitializedCache ??= new CreateUninitializedCache(rt);
_pfnValueCtor(ref uninitializedObject);
}

#if DEBUG
Loading