From 4810ba1bf0cfbf9f10dad0327327a41cf16eb291 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Strehovsk=C3=BD?= Date: Mon, 22 Apr 2024 15:34:23 +0900 Subject: [PATCH 001/161] Fix mismatch between boxed/unboxed method entrypoints (#99443) Fixes #99198. --- .../CompilerServices/FunctionPointerOps.cs | 10 ++- .../TypeLoader/NativeLayoutInfoLoadContext.cs | 10 +-- .../Runtime/TypeLoader/TypeBuilder.cs | 8 +- ...ronment.ConstructedGenericMethodsLookup.cs | 8 +- .../TypeLoaderEnvironment.GVMResolution.cs | 4 +- ...peLoaderEnvironment.LdTokenResultLookup.cs | 4 +- .../TypeLoader/TypeLoaderEnvironment.cs | 2 +- .../Internal/TypeSystem/MethodDesc.Runtime.cs | 22 ++---- .../TypeSystem/RuntimeMethodDesc.Canon.cs | 2 +- .../Internal/TypeSystem/RuntimeMethodDesc.cs | 4 +- .../TypeSystem/TypeSystemContext.Runtime.cs | 24 ++---- .../SmokeTests/UnitTests/Generics.cs | 75 +++++++++++++++++++ 12 files changed, 111 insertions(+), 62 deletions(-) diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/Internal/Runtime/CompilerServices/FunctionPointerOps.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/Internal/Runtime/CompilerServices/FunctionPointerOps.cs index e77a106b252baf..c0bceb7963c8ad 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/Internal/Runtime/CompilerServices/FunctionPointerOps.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/Internal/Runtime/CompilerServices/FunctionPointerOps.cs @@ -5,7 +5,7 @@ using System.Collections.Generic; using System.Runtime.InteropServices; -using Internal.Runtime.Augments; +using Debug = System.Diagnostics.Debug; namespace Internal.Runtime.CompilerServices { @@ -56,6 +56,8 @@ public override int GetHashCode() public static unsafe IntPtr GetGenericMethodFunctionPointer(IntPtr canonFunctionPointer, IntPtr instantiationArgument) { + Debug.Assert(canonFunctionPointer != IntPtr.Zero); + if (instantiationArgument == IntPtr.Zero) return canonFunctionPointer; @@ -79,7 +81,7 @@ public static unsafe IntPtr GetGenericMethodFunctionPointer(IntPtr canonFunction // Generate new chunk if existing chunks are insufficient if (s_genericFunctionPointerCollection.Count <= newChunkIndex) { - System.Diagnostics.Debug.Assert(newSubChunkIndex == 0); + Debug.Assert(newSubChunkIndex == 0); // New generic descriptors are allocated on the native heap and not tracked in the GC. IntPtr pNewMem = (IntPtr)NativeMemory.Alloc(c_genericDictionaryChunkSize, (nuint)sizeof(GenericMethodDescriptor)); @@ -100,8 +102,8 @@ public static unsafe IntPtr GetGenericMethodFunctionPointer(IntPtr canonFunction uint subChunkIndex = index % c_genericDictionaryChunkSize; GenericMethodDescriptor* genericFunctionPointer = &((GenericMethodDescriptor*)s_genericFunctionPointerCollection[chunkIndex])[subChunkIndex]; - System.Diagnostics.Debug.Assert(canonFunctionPointer == genericFunctionPointer->MethodFunctionPointer); - System.Diagnostics.Debug.Assert(instantiationArgument == genericFunctionPointer->InstantiationArgument); + Debug.Assert(canonFunctionPointer == genericFunctionPointer->MethodFunctionPointer); + Debug.Assert(instantiationArgument == genericFunctionPointer->InstantiationArgument); return (IntPtr)((byte*)genericFunctionPointer + FatFunctionPointerOffset); } diff --git a/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/NativeLayoutInfoLoadContext.cs b/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/NativeLayoutInfoLoadContext.cs index 04958f81927abf..90a2c9857c6dc1 100644 --- a/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/NativeLayoutInfoLoadContext.cs +++ b/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/NativeLayoutInfoLoadContext.cs @@ -193,18 +193,16 @@ internal MethodDesc GetMethod(ref NativeParser parser, out RuntimeSignature meth { TypeDesc[] typeArguments = GetTypeSequence(ref parser); Debug.Assert(typeArguments.Length > 0); - retVal = this._typeSystemContext.ResolveGenericMethodInstantiation(unboxingStub, containingType, nameAndSignature, new Instantiation(typeArguments), functionPointer, (flags & MethodFlags.FunctionPointerIsUSG) != 0); + retVal = this._typeSystemContext.ResolveGenericMethodInstantiation(unboxingStub, containingType, nameAndSignature, new Instantiation(typeArguments)); } else { - retVal = this._typeSystemContext.ResolveRuntimeMethod(unboxingStub, containingType, nameAndSignature, functionPointer, (flags & MethodFlags.FunctionPointerIsUSG) != 0); + retVal = this._typeSystemContext.ResolveRuntimeMethod(unboxingStub, containingType, nameAndSignature); } - if ((flags & MethodFlags.FunctionPointerIsUSG) != 0) + if ((flags & MethodFlags.HasFunctionPointer) != 0) { - // TODO, consider a change such that if a USG function pointer is passed in, but we have - // a way to get a non-usg pointer, that may be preferable - Debug.Assert(retVal.UsgFunctionPointer != IntPtr.Zero); + retVal.SetFunctionPointer(functionPointer); } return retVal; diff --git a/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/TypeBuilder.cs b/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/TypeBuilder.cs index 8ee004b11d42c7..43ea9b81d8bf0e 100644 --- a/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/TypeBuilder.cs +++ b/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/TypeBuilder.cs @@ -300,7 +300,7 @@ internal void ParseNativeLayoutInfo(InstantiatedMethod method) if (method.UnboxingStub) { // Strip unboxing stub, note the first parameter which is false - nonTemplateMethod = (InstantiatedMethod)method.Context.ResolveGenericMethodInstantiation(false, (DefType)method.OwningType, method.NameAndSignature, method.Instantiation, IntPtr.Zero, false); + nonTemplateMethod = (InstantiatedMethod)method.Context.ResolveGenericMethodInstantiation(false, (DefType)method.OwningType, method.NameAndSignature, method.Instantiation); } uint nativeLayoutInfoToken; @@ -311,9 +311,11 @@ internal void ParseNativeLayoutInfo(InstantiatedMethod method) throw new MissingTemplateException(); } - if (templateMethod.FunctionPointer != IntPtr.Zero) + // We might have a mismatch between unboxing/non-unboxing variants so only remember it for static methods + if (TypeLoaderEnvironment.IsStaticMethodSignature(templateMethod.NameAndSignature) + && templateMethod.FunctionPointer != IntPtr.Zero) { - nonTemplateMethod.SetFunctionPointer(templateMethod.FunctionPointer, isFunctionPointerUSG: false); + nonTemplateMethod.SetFunctionPointer(templateMethod.FunctionPointer); } // Ensure that if this method is non-shareable from a normal canonical perspective, then diff --git a/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/TypeLoaderEnvironment.ConstructedGenericMethodsLookup.cs b/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/TypeLoaderEnvironment.ConstructedGenericMethodsLookup.cs index c5f5308226148d..c8437c4a4e437c 100644 --- a/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/TypeLoaderEnvironment.ConstructedGenericMethodsLookup.cs +++ b/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/TypeLoaderEnvironment.ConstructedGenericMethodsLookup.cs @@ -153,7 +153,7 @@ internal override bool MatchParsedEntry(ref NativeParser entryParser, ref Extern DefType parsedDeclaringType = context.ResolveRuntimeTypeHandle(parsedDeclaringTypeHandle) as DefType; Instantiation parsedArgs = context.ResolveRuntimeTypeHandles(parsedArgsHandles); - InstantiatedMethod parsedGenericMethod = (InstantiatedMethod)context.ResolveGenericMethodInstantiation(false, parsedDeclaringType, nameAndSignature, parsedArgs, IntPtr.Zero, false); + InstantiatedMethod parsedGenericMethod = (InstantiatedMethod)context.ResolveGenericMethodInstantiation(false, parsedDeclaringType, nameAndSignature, parsedArgs); return parsedGenericMethod == _methodToLookup; } @@ -164,7 +164,7 @@ internal override bool MatchGenericMethodEntry(GenericMethodEntry entry) DefType parsedDeclaringType = context.ResolveRuntimeTypeHandle(entry._declaringTypeHandle) as DefType; Instantiation parsedArgs = context.ResolveRuntimeTypeHandles(entry._genericMethodArgumentHandles); - InstantiatedMethod parsedGenericMethod = (InstantiatedMethod)context.ResolveGenericMethodInstantiation(false, parsedDeclaringType, entry._methodNameAndSignature, parsedArgs, IntPtr.Zero, false); + InstantiatedMethod parsedGenericMethod = (InstantiatedMethod)context.ResolveGenericMethodInstantiation(false, parsedDeclaringType, entry._methodNameAndSignature, parsedArgs); return parsedGenericMethod == _methodToLookup; } @@ -267,9 +267,7 @@ public bool TryGetGenericVirtualMethodPointer(InstantiatedMethod method, out Int return false; } - methodPointer = templateMethod.IsCanonicalMethod(CanonicalFormKind.Universal) ? - templateMethod.UsgFunctionPointer : - templateMethod.FunctionPointer; + methodPointer = templateMethod.FunctionPointer; if (!TryLookupGenericMethodDictionary(new MethodDescBasedGenericMethodLookup(method), out dictionaryPointer)) { diff --git a/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/TypeLoaderEnvironment.GVMResolution.cs b/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/TypeLoaderEnvironment.GVMResolution.cs index d9416b32863869..c73df4af62b5d7 100644 --- a/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/TypeLoaderEnvironment.GVMResolution.cs +++ b/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/TypeLoaderEnvironment.GVMResolution.cs @@ -309,7 +309,7 @@ private static InstantiatedMethod FindMatchingInterfaceSlot(NativeFormatModuleIn Debug.Assert(interfaceImplType != null); } - return (InstantiatedMethod)context.ResolveGenericMethodInstantiation(false, interfaceImplType, targetMethodNameAndSignature, slotMethod.Instantiation, IntPtr.Zero, false); + return (InstantiatedMethod)context.ResolveGenericMethodInstantiation(false, interfaceImplType, targetMethodNameAndSignature, slotMethod.Instantiation); } } } @@ -500,7 +500,7 @@ private static InstantiatedMethod ResolveGenericVirtualMethodTarget(DefType targ Debug.Assert(targetMethodNameAndSignature != null); TypeSystemContext context = slotMethod.Context; - return (InstantiatedMethod)context.ResolveGenericMethodInstantiation(false, targetType, targetMethodNameAndSignature, slotMethod.Instantiation, IntPtr.Zero, false); + return (InstantiatedMethod)context.ResolveGenericMethodInstantiation(false, targetType, targetMethodNameAndSignature, slotMethod.Instantiation); } } diff --git a/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/TypeLoaderEnvironment.LdTokenResultLookup.cs b/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/TypeLoaderEnvironment.LdTokenResultLookup.cs index 9ddec8a39d7aa3..dd2bc75e3d61d4 100644 --- a/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/TypeLoaderEnvironment.LdTokenResultLookup.cs +++ b/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/TypeLoaderEnvironment.LdTokenResultLookup.cs @@ -388,10 +388,10 @@ public MethodDesc GetMethodDescForDynamicRuntimeMethodHandle(TypeSystemContext c if (genericMethodArgs != null) { Instantiation methodInst = context.ResolveRuntimeTypeHandles(genericMethodArgs); - return context.ResolveGenericMethodInstantiation(unboxingStub: false, type, nameAndSignature, methodInst, default, default); + return context.ResolveGenericMethodInstantiation(unboxingStub: false, type, nameAndSignature, methodInst); } - return context.ResolveRuntimeMethod(unboxingStub: false, type, nameAndSignature, default, default); + return context.ResolveRuntimeMethod(unboxingStub: false, type, nameAndSignature); } private unsafe bool TryGetStaticRuntimeMethodHandleComponents(RuntimeMethodHandle runtimeMethodHandle, out RuntimeTypeHandle declaringTypeHandle, out MethodNameAndSignature nameAndSignature, out RuntimeTypeHandle[] genericMethodArgs) diff --git a/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/TypeLoaderEnvironment.cs b/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/TypeLoaderEnvironment.cs index 42864c10f2ebc7..22c07b2e837bc6 100644 --- a/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/TypeLoaderEnvironment.cs +++ b/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/TypeLoaderEnvironment.cs @@ -485,7 +485,7 @@ public bool TryGetGenericMethodDictionaryForComponents(RuntimeTypeHandle declari TypeSystemContext context = TypeSystemContextFactory.Create(); DefType declaringType = (DefType)context.ResolveRuntimeTypeHandle(declaringTypeHandle); - InstantiatedMethod methodBeingLoaded = (InstantiatedMethod)context.ResolveGenericMethodInstantiation(false, declaringType, nameAndSignature, context.ResolveRuntimeTypeHandles(genericMethodArgHandles), IntPtr.Zero, false); + InstantiatedMethod methodBeingLoaded = (InstantiatedMethod)context.ResolveGenericMethodInstantiation(false, declaringType, nameAndSignature, context.ResolveRuntimeTypeHandles(genericMethodArgHandles)); if (TryLookupGenericMethodDictionary(new MethodDescBasedGenericMethodLookup(methodBeingLoaded), out methodDictionary)) { diff --git a/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/TypeSystem/MethodDesc.Runtime.cs b/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/TypeSystem/MethodDesc.Runtime.cs index 89161ce5309d72..24dceff6d0f05f 100644 --- a/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/TypeSystem/MethodDesc.Runtime.cs +++ b/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/TypeSystem/MethodDesc.Runtime.cs @@ -6,19 +6,18 @@ using Internal.Runtime.CompilerServices; +using Debug = System.Diagnostics.Debug; + namespace Internal.TypeSystem { public partial class MethodDesc { private IntPtr _functionPointer; - private IntPtr _usgFunctionPointer; - public void SetFunctionPointer(IntPtr functionPointer, bool isFunctionPointerUSG) + public void SetFunctionPointer(IntPtr functionPointer) { - if (isFunctionPointerUSG) - _usgFunctionPointer = functionPointer; - else - _functionPointer = functionPointer; + Debug.Assert(_functionPointer == IntPtr.Zero || _functionPointer == functionPointer); + _functionPointer = functionPointer; } /// @@ -32,17 +31,6 @@ public IntPtr FunctionPointer } } - /// - /// Pointer to function's universal shared generics code. May be IntPtr.Zero - /// - public IntPtr UsgFunctionPointer - { - get - { - return _usgFunctionPointer; - } - } - public abstract MethodNameAndSignature NameAndSignature { get; } private bool? _isNonSharableCache; diff --git a/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/TypeSystem/RuntimeMethodDesc.Canon.cs b/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/TypeSystem/RuntimeMethodDesc.Canon.cs index 956dcdcafb9761..ad12ea96f00817 100644 --- a/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/TypeSystem/RuntimeMethodDesc.Canon.cs +++ b/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/TypeSystem/RuntimeMethodDesc.Canon.cs @@ -23,7 +23,7 @@ public override MethodDesc GetCanonMethodTarget(CanonicalFormKind kind) if (canonicalizedTypeOfTargetMethod == OwningType) return this; - return Context.ResolveRuntimeMethod(this.UnboxingStub, canonicalizedTypeOfTargetMethod, this.NameAndSignature, IntPtr.Zero, false); + return Context.ResolveRuntimeMethod(this.UnboxingStub, canonicalizedTypeOfTargetMethod, this.NameAndSignature); } } } diff --git a/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/TypeSystem/RuntimeMethodDesc.cs b/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/TypeSystem/RuntimeMethodDesc.cs index f95b8561e3a9dc..042b1957e22b65 100644 --- a/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/TypeSystem/RuntimeMethodDesc.cs +++ b/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/TypeSystem/RuntimeMethodDesc.cs @@ -117,7 +117,7 @@ public override MethodDesc GetTypicalMethodDefinition() } // Otherwise, find its equivalent on the type definition of the owning type - return Context.ResolveRuntimeMethod(UnboxingStub, (DefType)owningTypeDefinition, _nameAndSignature, IntPtr.Zero, false); + return Context.ResolveRuntimeMethod(UnboxingStub, (DefType)owningTypeDefinition, _nameAndSignature); } public override MethodDesc InstantiateSignature(Instantiation typeInstantiation, Instantiation methodInstantiation) @@ -127,7 +127,7 @@ public override MethodDesc InstantiateSignature(Instantiation typeInstantiation, TypeDesc owningType = method.OwningType; TypeDesc instantiatedOwningType = owningType.InstantiateSignature(typeInstantiation, methodInstantiation); if (owningType != instantiatedOwningType) - method = instantiatedOwningType.Context.ResolveRuntimeMethod(UnboxingStub, (DefType)instantiatedOwningType, _nameAndSignature, IntPtr.Zero, false); + method = instantiatedOwningType.Context.ResolveRuntimeMethod(UnboxingStub, (DefType)instantiatedOwningType, _nameAndSignature); Instantiation instantiation = method.Instantiation; TypeDesc[] clone = null; diff --git a/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/TypeSystem/TypeSystemContext.Runtime.cs b/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/TypeSystem/TypeSystemContext.Runtime.cs index 464a370a5f7be3..1e4b888552220a 100644 --- a/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/TypeSystem/TypeSystemContext.Runtime.cs +++ b/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/TypeSystem/TypeSystemContext.Runtime.cs @@ -417,7 +417,7 @@ protected override MethodDesc CreateValueFromKey(RuntimeMethodKey key) // Instantiated Types always get their methods through GetMethodForInstantiatedType if (key._owningType is InstantiatedType) { - MethodDesc typicalMethod = key._owningType.Context.ResolveRuntimeMethod(key._unboxingStub, (DefType)key._owningType.GetTypeDefinition(), key._methodNameAndSignature, IntPtr.Zero, false); + MethodDesc typicalMethod = key._owningType.Context.ResolveRuntimeMethod(key._unboxingStub, (DefType)key._owningType.GetTypeDefinition(), key._methodNameAndSignature); return typicalMethod.Context.GetMethodForInstantiatedType(typicalMethod, (InstantiatedType)key._owningType); } } @@ -434,18 +434,10 @@ protected override MethodDesc CreateValueFromKey(RuntimeMethodKey key) private RuntimeMethodKey.RuntimeMethodKeyHashtable _runtimeMethods; - internal MethodDesc ResolveRuntimeMethod(bool unboxingStub, DefType owningType, MethodNameAndSignature nameAndSignature, IntPtr functionPointer, bool usgFunctionPointer) + internal MethodDesc ResolveRuntimeMethod(bool unboxingStub, DefType owningType, MethodNameAndSignature nameAndSignature) { _runtimeMethods ??= new RuntimeMethodKey.RuntimeMethodKeyHashtable(); - - MethodDesc retVal = _runtimeMethods.GetOrCreateValue(new RuntimeMethodKey(unboxingStub, owningType, nameAndSignature)); - - if (functionPointer != IntPtr.Zero) - { - retVal.SetFunctionPointer(functionPointer, usgFunctionPointer); - } - - return retVal; + return _runtimeMethods.GetOrCreateValue(new RuntimeMethodKey(unboxingStub, owningType, nameAndSignature)); } private LowLevelDictionary _genericTypeInstances; @@ -479,9 +471,9 @@ public DefType ResolveGenericInstantiation(DefType typeDef, Instantiation argume /// /// Find a method based on owner type and nativelayout name, method instantiation, and signature. /// - public MethodDesc ResolveGenericMethodInstantiation(bool unboxingStub, DefType owningType, MethodNameAndSignature nameAndSignature, Instantiation methodInstantiation, IntPtr functionPointer, bool usgFunctionPointer) + public MethodDesc ResolveGenericMethodInstantiation(bool unboxingStub, DefType owningType, MethodNameAndSignature nameAndSignature, Instantiation methodInstantiation) { - var uninstantiatedMethod = ResolveRuntimeMethod(unboxingStub, owningType, nameAndSignature, IntPtr.Zero, false); + var uninstantiatedMethod = ResolveRuntimeMethod(unboxingStub, owningType, nameAndSignature); MethodDesc returnedMethod; if (methodInstantiation.IsNull || (methodInstantiation.Length == 0)) @@ -492,12 +484,6 @@ public MethodDesc ResolveGenericMethodInstantiation(bool unboxingStub, DefType o { returnedMethod = GetInstantiatedMethod(uninstantiatedMethod, methodInstantiation); } - - if (functionPointer != IntPtr.Zero) - { - returnedMethod.SetFunctionPointer(functionPointer, usgFunctionPointer); - } - return returnedMethod; } diff --git a/src/tests/nativeaot/SmokeTests/UnitTests/Generics.cs b/src/tests/nativeaot/SmokeTests/UnitTests/Generics.cs index a9d3d44c758dde..f362c08d424649 100644 --- a/src/tests/nativeaot/SmokeTests/UnitTests/Generics.cs +++ b/src/tests/nativeaot/SmokeTests/UnitTests/Generics.cs @@ -55,6 +55,7 @@ internal static int Run() TestRecursionThroughGenericLookups.Run(); TestRecursionInFields.Run(); TestGvmLookupDependency.Run(); + Test99198Regression.Run(); TestInvokeMemberCornerCaseInGenerics.Run(); TestRefAny.Run(); TestNullableCasting.Run(); @@ -3480,6 +3481,80 @@ public static void Run() } } + class Test99198Regression + { + delegate void Set(ref T t, IFoo ifoo); + + interface IFoo + { + void Do(); + } + + class Atom { } + + struct Foo : IFoo + { + public nint Cookie1; + public nint Cookie2; + + public void Do() + { + Cookie1 = 42; + } + } + + class C where T : IFoo + { + [MethodImpl(MethodImplOptions.NoInlining)] + public static void Set(ref T t, IFoo ifoo) + { + t.Do(); + ifoo.Do(); + } + } + + public static void RunDynamic() + { + static Type GetObject() => typeof(Foo); + var s = typeof(C<>).MakeGenericType(GetObject()).GetMethod("Set").CreateDelegate>>(); + + Foo ob = default; + IFoo boxed = ob; + + s(ref ob, boxed); + + if (ob.Cookie1 != 42 || ob.Cookie2 != 0) + throw new Exception(); + + ob = (Foo)boxed; + if (ob.Cookie1 != 42 || ob.Cookie2 != 0) + throw new Exception(); + } + + public static void Run() + { + new C>().ToString(); + + static Type GetObject() => typeof(Foo); + var s = typeof(C<>).MakeGenericType(GetObject()).GetMethod("Set").CreateDelegate>>(); + + Foo ob = default; + IFoo boxed = ob; + + s(ref ob, boxed); + + if (ob.Cookie1 != 42 || ob.Cookie2 != 0) + throw new Exception(); + + ob = (Foo)boxed; + if (ob.Cookie1 != 42 || ob.Cookie2 != 0) + throw new Exception(); + + static Type GetAtom() => typeof(Atom); + typeof(Test99198Regression).GetMethod(nameof(RunDynamic)).MakeGenericMethod(GetAtom()).Invoke(null, []); + } + } + class TestInvokeMemberCornerCaseInGenerics { class Generic From d8eecb714fcc29556b0bd573d540ad49b4a8bcce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Strehovsk=C3=BD?= Date: Mon, 22 Apr 2024 18:44:17 +0900 Subject: [PATCH 002/161] Run trimming tests as AOT tests (#101229) Not everything is passing, so I baselined this. Some we'll probably exclude permanently, others are more concerning and we need to determine if it's test issues or product issues. --- Directory.Build.props | 10 ++++------ .../coreclr/nativeaot-post-build-steps.yml | 8 -------- .../execute-trimming-tests-steps.yml | 6 ++++++ eng/pipelines/runtime-linker-tests.yml | 1 + .../linker/SupportFiles/Directory.Build.props | 1 + eng/testing/linker/trimmingTests.props | 4 +++- eng/testing/linker/trimmingTests.targets | 5 ++++- src/libraries/Directory.Build.props | 2 +- src/libraries/Directory.Build.targets | 2 +- ...stics.DiagnosticSource.NativeAotTests.proj | 10 ---------- .../DiagnosticSourceEventSourceTests.cs | 0 .../System.Diagnostics.DiagnosticSource.proj | 2 ++ src/libraries/tests.proj | 19 +++++++++++++------ 13 files changed, 36 insertions(+), 34 deletions(-) delete mode 100644 src/libraries/System.Diagnostics.DiagnosticSource/tests/NativeAotTests/System.Diagnostics.DiagnosticSource.NativeAotTests.proj rename src/libraries/System.Diagnostics.DiagnosticSource/tests/{NativeAotTests => TrimmingTests}/DiagnosticSourceEventSourceTests.cs (100%) diff --git a/Directory.Build.props b/Directory.Build.props index b1ac2559f9ed1e..ef0e8c1b44d76d 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -397,12 +397,10 @@ true true - true - true - true + true - false + false @@ -413,7 +411,7 @@ '$(IsReferenceAssemblyProject)' != 'true' and '$(IsGeneratorProject)' != 'true' and '$(IsTestProject)' != 'true' and - '$(IsPublishedAppTestProject)' != 'true' and + '$(IsTrimmingTestProject)' != 'true' and '$(IsTestSupportProject)' != 'true' and '$(UsingMicrosoftDotNetSharedFrameworkSdk)' != 'true' and '$(MSBuildProjectExtension)' != '.pkgproj' and @@ -464,7 +462,7 @@ - + true diff --git a/eng/pipelines/coreclr/nativeaot-post-build-steps.yml b/eng/pipelines/coreclr/nativeaot-post-build-steps.yml index 94761028f48ab0..bc29a657c456ce 100644 --- a/eng/pipelines/coreclr/nativeaot-post-build-steps.yml +++ b/eng/pipelines/coreclr/nativeaot-post-build-steps.yml @@ -21,11 +21,3 @@ steps: nativeAotTest: true helixQueues: ${{ parameters.helixQueues }} liveLibrariesBuildConfig: ${{ parameters.liveLibrariesBuildConfig }} - - # Can't run arm/arm64 tests on x64 build machines - - ${{ if and(ne(parameters.archType, 'arm'), ne(parameters.archType, 'arm64')) }}: - - # Publishing tooling doesn't support different configs between runtime and libs, so only run tests in Release config - - ${{ if eq(parameters.buildConfig, 'release') }}: - - script: $(Build.SourcesDirectory)$(dir)build$(scriptExt) -ci -arch ${{ parameters.archType }} $(_osParameter) -s libs.tests -c $(_BuildConfig) $(crossArg) $(_nativeSanitizersArg) /p:TestAssemblies=false /p:RunNativeAotTestApps=true $(_officialBuildParameter) /bl:$(Build.SourcesDirectory)/artifacts/log/$(buildConfigUpper)/NativeAotTests.binlog ${{ parameters.extraTestArgs }} - displayName: Run NativeAot Library Tests diff --git a/eng/pipelines/libraries/execute-trimming-tests-steps.yml b/eng/pipelines/libraries/execute-trimming-tests-steps.yml index 567abab0bb984e..13778ee0ab63a5 100644 --- a/eng/pipelines/libraries/execute-trimming-tests-steps.yml +++ b/eng/pipelines/libraries/execute-trimming-tests-steps.yml @@ -1,8 +1,14 @@ parameters: archType: '' extraTestArgs: '' + runAotTests: true steps: # Execute tests - script: $(Build.SourcesDirectory)$(dir)build$(scriptExt) -ci -arch ${{ parameters.archType }} $(_osParameter) -s libs.tests -c $(_BuildConfig) $(crossArg) /p:TestAssemblies=false /p:TestTrimming=true $(_officialBuildParameter) /bl:$(Build.SourcesDirectory)/artifacts/log/$(buildConfigUpper)/TrimmingTests.binlog ${{ parameters.extraTestArgs }} displayName: Run Trimming Tests + + # Execute AOT test app tests + - ${{ if eq(parameters.runAotTests, true) }}: + - script: $(Build.SourcesDirectory)$(dir)build$(scriptExt) -ci -arch ${{ parameters.archType }} $(_osParameter) -s libs.tests -c $(_BuildConfig) $(crossArg) /p:TestAssemblies=false /p:RunNativeAotTestApps=true $(_officialBuildParameter) /bl:$(Build.SourcesDirectory)/artifacts/log/$(buildConfigUpper)/NativeAotTestAppTests.binlog ${{ parameters.extraTestArgs }} + displayName: Run Native AOT Test App Tests diff --git a/eng/pipelines/runtime-linker-tests.yml b/eng/pipelines/runtime-linker-tests.yml index aec5e1057ac538..2b001b769f50f9 100644 --- a/eng/pipelines/runtime-linker-tests.yml +++ b/eng/pipelines/runtime-linker-tests.yml @@ -135,3 +135,4 @@ extends: - template: /eng/pipelines/libraries/execute-trimming-tests-steps.yml parameters: extraTestArgs: '/p:WasmBuildNative=false' + runAotTests: false diff --git a/eng/testing/linker/SupportFiles/Directory.Build.props b/eng/testing/linker/SupportFiles/Directory.Build.props index 5a54c83e569231..4e33801ab12837 100644 --- a/eng/testing/linker/SupportFiles/Directory.Build.props +++ b/eng/testing/linker/SupportFiles/Directory.Build.props @@ -11,6 +11,7 @@ false true + true $(NoWarn);IL2121 diff --git a/eng/testing/linker/trimmingTests.props b/eng/testing/linker/trimmingTests.props index b917cd5fe38268..b822294a93d04c 100644 --- a/eng/testing/linker/trimmingTests.props +++ b/eng/testing/linker/trimmingTests.props @@ -1,6 +1,8 @@ - $([MSBuild]::NormalizeDirectory('$(ArtifactsBinDir)', 'trimmingTests')) + $([MSBuild]::NormalizeDirectory('$(ArtifactsBinDir)', 'trimmingTests')) + $([MSBuild]::NormalizeDirectory('$(ArtifactsBinDir)', 'aotTests')) + $([MSBuild]::NormalizeDirectory('$(TrimmingTestDir)', 'projects')) $(MSBuildThisFileDirectory)project.csproj.template true diff --git a/eng/testing/linker/trimmingTests.targets b/eng/testing/linker/trimmingTests.targets index b29bc1dc75cf5b..9ff325e82972c0 100644 --- a/eng/testing/linker/trimmingTests.targets +++ b/eng/testing/linker/trimmingTests.targets @@ -81,6 +81,9 @@ <_additionalPropertiesString>@(_propertiesAsItems->'<%(Identity)>%(Value)</%(Identity)>', '%0a ') + + + - + diff --git a/src/libraries/Directory.Build.targets b/src/libraries/Directory.Build.targets index b219e7cf41a913..e3d599b2d8276a 100644 --- a/src/libraries/Directory.Build.targets +++ b/src/libraries/Directory.Build.targets @@ -131,7 +131,7 @@ - + diff --git a/src/libraries/System.Diagnostics.DiagnosticSource/tests/NativeAotTests/System.Diagnostics.DiagnosticSource.NativeAotTests.proj b/src/libraries/System.Diagnostics.DiagnosticSource/tests/NativeAotTests/System.Diagnostics.DiagnosticSource.NativeAotTests.proj deleted file mode 100644 index 8001203352b581..00000000000000 --- a/src/libraries/System.Diagnostics.DiagnosticSource/tests/NativeAotTests/System.Diagnostics.DiagnosticSource.NativeAotTests.proj +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - diff --git a/src/libraries/System.Diagnostics.DiagnosticSource/tests/NativeAotTests/DiagnosticSourceEventSourceTests.cs b/src/libraries/System.Diagnostics.DiagnosticSource/tests/TrimmingTests/DiagnosticSourceEventSourceTests.cs similarity index 100% rename from src/libraries/System.Diagnostics.DiagnosticSource/tests/NativeAotTests/DiagnosticSourceEventSourceTests.cs rename to src/libraries/System.Diagnostics.DiagnosticSource/tests/TrimmingTests/DiagnosticSourceEventSourceTests.cs diff --git a/src/libraries/System.Diagnostics.DiagnosticSource/tests/TrimmingTests/System.Diagnostics.DiagnosticSource.proj b/src/libraries/System.Diagnostics.DiagnosticSource/tests/TrimmingTests/System.Diagnostics.DiagnosticSource.proj index ca9483e224ffb4..919c0b7614b145 100644 --- a/src/libraries/System.Diagnostics.DiagnosticSource/tests/TrimmingTests/System.Diagnostics.DiagnosticSource.proj +++ b/src/libraries/System.Diagnostics.DiagnosticSource/tests/TrimmingTests/System.Diagnostics.DiagnosticSource.proj @@ -2,6 +2,8 @@ + diff --git a/src/libraries/tests.proj b/src/libraries/tests.proj index 659fda6a8d7d65..f89150c3e25d60 100644 --- a/src/libraries/tests.proj +++ b/src/libraries/tests.proj @@ -646,16 +646,23 @@ BuildInParallel="$(BuildTestInParallel)" /> + + + + + + + + + + + + - - Date: Mon, 22 Apr 2024 09:53:36 +0000 Subject: [PATCH 003/161] JIT: Remove fgCanonicalizedFirstBB (#101358) --- src/coreclr/jit/compiler.h | 1 - src/coreclr/jit/fgbasic.cpp | 1 - src/coreclr/jit/optimizer.cpp | 2 -- 3 files changed, 4 deletions(-) diff --git a/src/coreclr/jit/compiler.h b/src/coreclr/jit/compiler.h index 819c20629de134..3c19969d0c90d8 100644 --- a/src/coreclr/jit/compiler.h +++ b/src/coreclr/jit/compiler.h @@ -5166,7 +5166,6 @@ class Compiler bool fgModified; // True if the flow graph has been modified recently bool fgPredsComputed; // Have we computed the bbPreds list bool fgOptimizedFinally; // Did we optimize any try-finallys? - bool fgCanonicalizedFirstBB; // TODO-Quirk: did we end up canonicalizing first BB? bool fgHasSwitch; // any BBJ_SWITCH jumps? diff --git a/src/coreclr/jit/fgbasic.cpp b/src/coreclr/jit/fgbasic.cpp index 1638dfec507324..808d591a77f5c8 100644 --- a/src/coreclr/jit/fgbasic.cpp +++ b/src/coreclr/jit/fgbasic.cpp @@ -167,7 +167,6 @@ void Compiler::fgInit() fgHistogramInstrumentor = nullptr; fgValueInstrumentor = nullptr; fgPredListSortVector = nullptr; - fgCanonicalizedFirstBB = false; } //------------------------------------------------------------------------ diff --git a/src/coreclr/jit/optimizer.cpp b/src/coreclr/jit/optimizer.cpp index f2de86fcdef21f..0de4cacc7bb0c5 100644 --- a/src/coreclr/jit/optimizer.cpp +++ b/src/coreclr/jit/optimizer.cpp @@ -5316,8 +5316,6 @@ PhaseStatus Compiler::fgCanonicalizeFirstBB() assert(!fgFirstBBisScratch()); fgEnsureFirstBBisScratch(); - // TODO-Quirk: Remove - fgCanonicalizedFirstBB = true; return PhaseStatus::MODIFIED_EVERYTHING; } From 66ce263237282f1f74ecb7b76edae2e1f634471d Mon Sep 17 00:00:00 2001 From: Ilona Tomkowicz <32700855+ilonatommy@users.noreply.github.com> Date: Mon, 22 Apr 2024 14:15:35 +0200 Subject: [PATCH 004/161] [mt] Add signalR WBT on WASM browser app (#100723) * WIP, fixing net::ERR_CONNECTION_REFUSED. * Change of setup - aspnet project serving WASM static files. * Enable SharedArrayBuffer. * WIP, investigating `JsonSerializerIsReflectionDisabled` * Fix serialization issue. * Fixed * Cleanup. * Trying to fix integrity check issue. * Async interop + more logging. * Move test preparation code to a method. * Remove buttons, match other TestAppScenarios style. * Moved the test out of TestAppScenarios. Standalone version works. * Working version of test. * Cleanup. * Cleanup. * @maraf's feedback - simplify the prebuild steps. * WIP - merging blazor and wasmapp into one proj. * Missing change in a non-related test. * Do not pack blazor into a subfolder. * Remove old app. * Connect test logic, simplify. * Not intentional. * AspServer serves only "standard content types" * Prevent loosing `InnerException` on exceptions thrown during `TaskCompletionSource` completion. * Revert. * Cleanup. * @maraf's cleanup * SignalR hub is located in a url with path. * Fix "GET http://localhost:5000/wasmclient, Response status code: 404" --- .../scenarios/BuildWasmAppsJobsList.txt | 3 +- .../AspNetCore/SignalRClientTests.cs | 27 ++++ .../Blazor/BlazorWasmTestBase.cs | 2 +- .../Blazor/SignalRClientTests.cs | 30 +++++ .../wasm/Wasm.Build.Tests/SignalRTestsBase.cs | 49 ++++++++ .../TestAppScenarios/AppSettingsTests.cs | 2 +- .../TestAppScenarios/AppTestBase.cs | 37 +++--- .../TestAppScenarios/DebugLevelTests.cs | 14 +-- .../TestAppScenarios/LazyLoadingTests.cs | 4 +- .../LibraryInitializerTests.cs | 4 +- .../TestAppScenarios/ModuleConfigTests.cs | 4 +- .../TestAppScenarios/SatelliteLoadingTests.cs | 2 +- .../TestAppScenarios/SignalRClientTests.cs | 101 --------------- .../BlazorHosted.Client/Helper.cs | 42 ------- .../BlazorHosted.Client/Pages/Chat.razor | 116 ------------------ .../BlazorHosted.Client/wwwroot/favicon.ico | Bin 5430 -> 0 bytes .../BlazorHosted.Server/Program.cs | 52 -------- .../BlazorHosted.Server/appsettings.json | 8 -- .../AspNetCoreServer/AspNetCoreServer.csproj} | 5 +- .../AspNetCoreServer}/ChatHub.cs | 3 +- .../AspNetCoreServer/Program.cs | 62 ++++++++++ .../BlazorClient}/App.razor | 0 .../BlazorClient/BlazorClient.csproj} | 11 +- .../BlazorClient}/Layout/MainLayout.razor | 0 .../BlazorClient/Pages/Chat.razor | 34 +++++ .../BlazorClient}/Program.cs | 2 +- .../BlazorClient}/_Imports.razor | 5 +- .../BlazorClient}/wwwroot/index.html | 11 +- .../WasmOnAspNetCore/Shared/QueryParser.cs | 24 ++++ .../WasmOnAspNetCore/Shared/Shared.csproj | 19 +++ .../WasmOnAspNetCore/Shared/SignalRTest.cs | 114 +++++++++++++++++ .../WasmOnAspNetCore/Shared/TestOutput.cs | 20 +++ .../WasmBrowserClient/Program.cs | 21 ++++ .../WasmBrowserClient/TestOutput.cs | 18 +++ .../WasmBrowserClient.csproj | 17 +++ .../WasmBrowserClient/wwwroot/index.html | 17 +++ .../WasmBrowserClient/wwwroot/main.js | 19 +++ 37 files changed, 528 insertions(+), 371 deletions(-) create mode 100644 src/mono/wasm/Wasm.Build.Tests/AspNetCore/SignalRClientTests.cs create mode 100644 src/mono/wasm/Wasm.Build.Tests/Blazor/SignalRClientTests.cs create mode 100644 src/mono/wasm/Wasm.Build.Tests/SignalRTestsBase.cs delete mode 100644 src/mono/wasm/Wasm.Build.Tests/TestAppScenarios/SignalRClientTests.cs delete mode 100644 src/mono/wasm/testassets/BlazorHostedApp/BlazorHosted.Client/Helper.cs delete mode 100644 src/mono/wasm/testassets/BlazorHostedApp/BlazorHosted.Client/Pages/Chat.razor delete mode 100644 src/mono/wasm/testassets/BlazorHostedApp/BlazorHosted.Client/wwwroot/favicon.ico delete mode 100644 src/mono/wasm/testassets/BlazorHostedApp/BlazorHosted.Server/Program.cs delete mode 100644 src/mono/wasm/testassets/BlazorHostedApp/BlazorHosted.Server/appsettings.json rename src/mono/wasm/testassets/{BlazorHostedApp/BlazorHosted.Server/BlazorHosted.Server.csproj => WasmOnAspNetCore/AspNetCoreServer/AspNetCoreServer.csproj} (63%) rename src/mono/wasm/testassets/{BlazorHostedApp/BlazorHosted.Server => WasmOnAspNetCore/AspNetCoreServer}/ChatHub.cs (93%) create mode 100644 src/mono/wasm/testassets/WasmOnAspNetCore/AspNetCoreServer/Program.cs rename src/mono/wasm/testassets/{BlazorHostedApp/BlazorHosted.Client => WasmOnAspNetCore/BlazorClient}/App.razor (100%) rename src/mono/wasm/testassets/{BlazorHostedApp/BlazorHosted.Client/BlazorHosted.Client.csproj => WasmOnAspNetCore/BlazorClient/BlazorClient.csproj} (67%) rename src/mono/wasm/testassets/{BlazorHostedApp/BlazorHosted.Client => WasmOnAspNetCore/BlazorClient}/Layout/MainLayout.razor (100%) create mode 100644 src/mono/wasm/testassets/WasmOnAspNetCore/BlazorClient/Pages/Chat.razor rename src/mono/wasm/testassets/{BlazorHostedApp/BlazorHosted.Client => WasmOnAspNetCore/BlazorClient}/Program.cs (95%) rename src/mono/wasm/testassets/{BlazorHostedApp/BlazorHosted.Client => WasmOnAspNetCore/BlazorClient}/_Imports.razor (72%) rename src/mono/wasm/testassets/{BlazorHostedApp/BlazorHosted.Client => WasmOnAspNetCore/BlazorClient}/wwwroot/index.html (62%) create mode 100644 src/mono/wasm/testassets/WasmOnAspNetCore/Shared/QueryParser.cs create mode 100644 src/mono/wasm/testassets/WasmOnAspNetCore/Shared/Shared.csproj create mode 100644 src/mono/wasm/testassets/WasmOnAspNetCore/Shared/SignalRTest.cs create mode 100644 src/mono/wasm/testassets/WasmOnAspNetCore/Shared/TestOutput.cs create mode 100644 src/mono/wasm/testassets/WasmOnAspNetCore/WasmBrowserClient/Program.cs create mode 100644 src/mono/wasm/testassets/WasmOnAspNetCore/WasmBrowserClient/TestOutput.cs create mode 100644 src/mono/wasm/testassets/WasmOnAspNetCore/WasmBrowserClient/WasmBrowserClient.csproj create mode 100644 src/mono/wasm/testassets/WasmOnAspNetCore/WasmBrowserClient/wwwroot/index.html create mode 100644 src/mono/wasm/testassets/WasmOnAspNetCore/WasmBrowserClient/wwwroot/main.js diff --git a/eng/testing/scenarios/BuildWasmAppsJobsList.txt b/eng/testing/scenarios/BuildWasmAppsJobsList.txt index 63c4453b4ff66b..6afea6cb3e2237 100644 --- a/eng/testing/scenarios/BuildWasmAppsJobsList.txt +++ b/eng/testing/scenarios/BuildWasmAppsJobsList.txt @@ -17,6 +17,7 @@ Wasm.Build.Tests.Blazor.NoopNativeRebuildTest Wasm.Build.Tests.Blazor.WorkloadRequiredTests Wasm.Build.Tests.Blazor.IcuTests Wasm.Build.Tests.Blazor.IcuShardingTests +Wasm.Build.Tests.Blazor.SignalRClientTests Wasm.Build.Tests.BuildPublishTests Wasm.Build.Tests.ConfigSrcTests Wasm.Build.Tests.HybridGlobalizationTests @@ -37,7 +38,7 @@ Wasm.Build.Tests.TestAppScenarios.LazyLoadingTests Wasm.Build.Tests.TestAppScenarios.LibraryInitializerTests Wasm.Build.Tests.TestAppScenarios.SatelliteLoadingTests Wasm.Build.Tests.TestAppScenarios.ModuleConfigTests -Wasm.Build.Tests.TestAppScenarios.SignalRClientTests +Wasm.Build.Tests.AspNetCore.SignalRClientTests Wasm.Build.Tests.WasmBuildAppTest Wasm.Build.Tests.WasmNativeDefaultsTests Wasm.Build.Tests.WasmRunOutOfAppBundleTests diff --git a/src/mono/wasm/Wasm.Build.Tests/AspNetCore/SignalRClientTests.cs b/src/mono/wasm/Wasm.Build.Tests/AspNetCore/SignalRClientTests.cs new file mode 100644 index 00000000000000..85f538fac1c20b --- /dev/null +++ b/src/mono/wasm/Wasm.Build.Tests/AspNetCore/SignalRClientTests.cs @@ -0,0 +1,27 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Threading.Tasks; +using Xunit.Abstractions; +using Xunit; + +#nullable enable + +namespace Wasm.Build.Tests.AspNetCore; + +public class SignalRClientTests : SignalRTestsBase +{ + public SignalRClientTests(ITestOutputHelper output, SharedBuildPerTestClassFixture buildContext) + : base(output, buildContext) + { + } + + [ConditionalTheory(typeof(BuildTestBase), nameof(IsWorkloadWithMultiThreadingForDefaultFramework))] + [InlineData("Debug", "LongPolling")] + [InlineData("Release", "LongPolling")] + [InlineData("Debug", "WebSockets")] + [InlineData("Release", "WebSockets")] + public async Task SignalRPassMessageWasmBrowser(string config, string transport) => + await SignalRPassMessage("wasmclient", config, transport); +} diff --git a/src/mono/wasm/Wasm.Build.Tests/Blazor/BlazorWasmTestBase.cs b/src/mono/wasm/Wasm.Build.Tests/Blazor/BlazorWasmTestBase.cs index da9c7764f2d1f2..46c8f2ce132870 100644 --- a/src/mono/wasm/Wasm.Build.Tests/Blazor/BlazorWasmTestBase.cs +++ b/src/mono/wasm/Wasm.Build.Tests/Blazor/BlazorWasmTestBase.cs @@ -205,7 +205,7 @@ public async Task BlazorRunTest(string runArgs, onConsoleMessage: OnConsoleMessage, onServerMessage: runOptions.OnServerMessage, onError: OnErrorMessage, - modifyBrowserUrl: browserUrl => browserUrl + runOptions.BrowserPath + runOptions.QueryString); + modifyBrowserUrl: browserUrl => new Uri(new Uri(browserUrl), runOptions.BrowserPath + runOptions.QueryString).ToString()); _testOutput.WriteLine("Waiting for page to load"); await page.WaitForLoadStateAsync(LoadState.DOMContentLoaded, new () { Timeout = 1 * 60 * 1000 }); diff --git a/src/mono/wasm/Wasm.Build.Tests/Blazor/SignalRClientTests.cs b/src/mono/wasm/Wasm.Build.Tests/Blazor/SignalRClientTests.cs new file mode 100644 index 00000000000000..cf4f938bc1885d --- /dev/null +++ b/src/mono/wasm/Wasm.Build.Tests/Blazor/SignalRClientTests.cs @@ -0,0 +1,30 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; + +using System.Threading.Tasks; +using Xunit.Abstractions; +using Xunit; + +#nullable enable + +namespace Wasm.Build.Tests.Blazor; + +public class SignalRClientTests : SignalRTestsBase +{ + public SignalRClientTests(ITestOutputHelper output, SharedBuildPerTestClassFixture buildContext) + : base(output, buildContext) + { + } + + [ConditionalTheory(typeof(BuildTestBase), nameof(IsWorkloadWithMultiThreadingForDefaultFramework))] + [ActiveIssue("https://github.com/dotnet/runtime/issues/100445")] // to be fixed by: "https://github.com/dotnet/aspnetcore/issues/54365" + [InlineData("Debug", "LongPolling")] + [InlineData("Release", "LongPolling")] + [InlineData("Debug", "WebSockets")] + [InlineData("Release", "WebSockets")] + public async Task SignalRPassMessageBlazor(string config, string transport) => + await SignalRPassMessage("blazorclient", config, transport); +} + diff --git a/src/mono/wasm/Wasm.Build.Tests/SignalRTestsBase.cs b/src/mono/wasm/Wasm.Build.Tests/SignalRTestsBase.cs new file mode 100644 index 00000000000000..183d984b39b481 --- /dev/null +++ b/src/mono/wasm/Wasm.Build.Tests/SignalRTestsBase.cs @@ -0,0 +1,49 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Text; +using System.Text.RegularExpressions; +using System.Threading.Tasks; +using System.Collections.Generic; +using Wasm.Build.Tests.TestAppScenarios; +using Xunit.Abstractions; +using Xunit; +#nullable enable + +namespace Wasm.Build.Tests; + +public class SignalRTestsBase : AppTestBase +{ + public SignalRTestsBase(ITestOutputHelper output, SharedBuildPerTestClassFixture buildContext) + : base(output, buildContext) + { + } + + protected async Task SignalRPassMessage(string staticWebAssetBasePath, string config, string transport) + { + CopyTestAsset("WasmOnAspNetCore", "SignalRClientTests", "AspNetCoreServer"); + PublishProject(config, runtimeType: RuntimeVariant.MultiThreaded, assertAppBundle: false); + + var result = await RunSdkStyleAppForBuild(new( + Configuration: config, + ServerEnvironment: new Dictionary { ["ASPNETCORE_ENVIRONMENT"] = "Development" }, + BrowserPath: staticWebAssetBasePath, + BrowserQueryString: new Dictionary { ["transport"] = transport, ["message"] = "ping" } )); + + string testOutput = string.Join("\n", result.TestOutput) ?? ""; + Assert.NotEmpty(testOutput); + // check sending and receiving threadId + string threadIdUsedForSending = GetThreadOfAction(testOutput, @"SignalRPassMessages was sent by CurrentManagedThreadId=(\d+)", "signalR message was sent"); + string threadIdUsedForReceiving = GetThreadOfAction(testOutput, @"ReceiveMessage from server on CurrentManagedThreadId=(\d+)", "signalR message was received"); + string consoleOutput = string.Join("\n", result.ConsoleOutput); + Assert.True("1" != threadIdUsedForSending || "1" != threadIdUsedForReceiving, + $"Expected to send/receive with signalR in non-UI threads, instead only CurrentManagedThreadId=1 was used. ConsoleOutput: {consoleOutput}."); + } + + private string GetThreadOfAction(string testOutput, string pattern, string actionDescription) + { + Match match = Regex.Match(testOutput, pattern); + Assert.True(match.Success, $"Expected to find a log that {actionDescription}. TestOutput: {testOutput}."); + return match.Groups[1].Value ?? ""; + } +} diff --git a/src/mono/wasm/Wasm.Build.Tests/TestAppScenarios/AppSettingsTests.cs b/src/mono/wasm/Wasm.Build.Tests/TestAppScenarios/AppSettingsTests.cs index 5d028cc238909a..4ce41342917778 100644 --- a/src/mono/wasm/Wasm.Build.Tests/TestAppScenarios/AppSettingsTests.cs +++ b/src/mono/wasm/Wasm.Build.Tests/TestAppScenarios/AppSettingsTests.cs @@ -25,7 +25,7 @@ public AppSettingsTests(ITestOutputHelper output, SharedBuildPerTestClassFixture [InlineData("Production")] public async Task LoadAppSettingsBasedOnApplicationEnvironment(string applicationEnvironment) { - CopyTestAsset("WasmBasicTestApp", "AppSettingsTests"); + CopyTestAsset("WasmBasicTestApp", "AppSettingsTests", "App"); PublishProject("Debug"); var result = await RunSdkStyleAppForPublish(new( diff --git a/src/mono/wasm/Wasm.Build.Tests/TestAppScenarios/AppTestBase.cs b/src/mono/wasm/Wasm.Build.Tests/TestAppScenarios/AppTestBase.cs index 01a1afe96c0bbb..9b228c65faaa44 100644 --- a/src/mono/wasm/Wasm.Build.Tests/TestAppScenarios/AppTestBase.cs +++ b/src/mono/wasm/Wasm.Build.Tests/TestAppScenarios/AppTestBase.cs @@ -23,7 +23,7 @@ protected AppTestBase(ITestOutputHelper output, SharedBuildPerTestClassFixture b protected string Id { get; set; } protected string LogPath { get; set; } - protected void CopyTestAsset(string assetName, string generatedProjectNamePrefix = null) + protected void CopyTestAsset(string assetName, string generatedProjectNamePrefix = null, string? projectDirSuffix = null) { Id = $"{generatedProjectNamePrefix ?? assetName}_{GetRandomId()}"; InitBlazorWasmProjectDir(Id); @@ -31,27 +31,21 @@ protected void CopyTestAsset(string assetName, string generatedProjectNamePrefix LogPath = Path.Combine(s_buildEnv.LogRootPath, Id); Utils.DirectoryCopy(Path.Combine(BuildEnvironment.TestAssetsPath, assetName), Path.Combine(_projectDir!)); - switch(assetName) + if (!string.IsNullOrEmpty(projectDirSuffix)) { - case "WasmBasicTestApp": - // WasmBasicTestApp consists of App + Library projects - _projectDir = Path.Combine(_projectDir!, "App"); - break; - case "BlazorHostedApp": - // BlazorHostedApp consists of BlazorHosted.Client and BlazorHosted.Server projects - _projectDir = Path.Combine(_projectDir!, "BlazorHosted.Server"); - break; + _projectDir = Path.Combine(_projectDir, projectDirSuffix); } } protected void BlazorHostedBuild( string config, string assetName, + string projectDirSuffix, string clientDirRelativeToProjectDir = "", string? generatedProjectNamePrefix = null, RuntimeVariant runtimeType = RuntimeVariant.SingleThreaded) { - CopyTestAsset(assetName, generatedProjectNamePrefix); + CopyTestAsset(assetName, generatedProjectNamePrefix, projectDirSuffix); string frameworkDir = FindBlazorHostedBinFrameworkDir(config, forPublish: false, clientDirRelativeToProjectDir: clientDirRelativeToProjectDir); @@ -76,9 +70,17 @@ protected void BuildProject( result.EnsureSuccessful(); } - protected void PublishProject(string configuration, params string[] extraArgs) + protected void PublishProject( + string configuration, + RuntimeVariant runtimeType = RuntimeVariant.SingleThreaded, + bool assertAppBundle = true, + params string[] extraArgs) { - (CommandResult result, _) = BlazorPublish(new BlazorBuildOptions(Id, configuration), extraArgs); + (CommandResult result, _) = BlazorPublish(new BlazorBuildOptions( + Id: Id, + Config: configuration, + RuntimeType: runtimeType, + AssertAppBundle: assertAppBundle), extraArgs); result.EnsureSuccessful(); } @@ -99,12 +101,11 @@ private async Task RunSdkStyleApp(RunOptions options, BlazorRunHost h query.Add("test", options.TestScenario); var queryString = query.Any() ? "?" + string.Join("&", query.Select(kvp => $"{kvp.Key}={kvp.Value}")) : ""; - var tcs = new TaskCompletionSource(); List testOutput = new(); List consoleOutput = new(); List serverOutput = new(); - Regex exitRegex = new Regex("(WASM EXIT (?[0-9]+)$)|(Program terminated with exit\\((?[0-9]+)\\))"); + Regex exitRegex = new Regex("WASM EXIT (?[0-9]+)$"); BlazorRunOptions blazorRunOptions = new( CheckCounter: false, @@ -114,7 +115,8 @@ private async Task RunSdkStyleApp(RunOptions options, BlazorRunHost h OnServerMessage: OnServerMessage, BrowserPath: options.BrowserPath, QueryString: queryString, - Host: host); + Host: host, + ExtraArgs: options.ExtraArgs); await BlazorRunTest(blazorRunOptions); @@ -171,7 +173,8 @@ protected record RunOptions( Dictionary ServerEnvironment = null, Action OnConsoleMessage = null, Action OnServerMessage = null, - int? ExpectedExitCode = 0 + int? ExpectedExitCode = 0, + string? ExtraArgs = null ); protected record RunResult( diff --git a/src/mono/wasm/Wasm.Build.Tests/TestAppScenarios/DebugLevelTests.cs b/src/mono/wasm/Wasm.Build.Tests/TestAppScenarios/DebugLevelTests.cs index 1bbe8691d80db3..ee69b34819bbdc 100644 --- a/src/mono/wasm/Wasm.Build.Tests/TestAppScenarios/DebugLevelTests.cs +++ b/src/mono/wasm/Wasm.Build.Tests/TestAppScenarios/DebugLevelTests.cs @@ -33,7 +33,7 @@ private void AssertDebugLevel(RunResult result, int value) [InlineData("Release")] public async Task BuildWithDefaultLevel(string configuration) { - CopyTestAsset("WasmBasicTestApp", $"DebugLevelTests_BuildWithDefaultLevel_{configuration}"); + CopyTestAsset("WasmBasicTestApp", $"DebugLevelTests_BuildWithDefaultLevel_{configuration}", "App"); BuildProject(configuration); var result = await RunSdkStyleAppForBuild(new( @@ -50,7 +50,7 @@ public async Task BuildWithDefaultLevel(string configuration) [InlineData("Release", 0)] public async Task BuildWithExplicitValue(string configuration, int debugLevel) { - CopyTestAsset("WasmBasicTestApp", $"DebugLevelTests_BuildWithExplicitValue_{configuration}"); + CopyTestAsset("WasmBasicTestApp", $"DebugLevelTests_BuildWithExplicitValue_{configuration}", "App"); BuildProject(configuration: configuration, extraArgs: $"-p:WasmDebugLevel={debugLevel}"); var result = await RunSdkStyleAppForBuild(new( @@ -65,7 +65,7 @@ public async Task BuildWithExplicitValue(string configuration, int debugLevel) [InlineData("Release")] public async Task PublishWithDefaultLevel(string configuration) { - CopyTestAsset("WasmBasicTestApp", $"DebugLevelTests_PublishWithDefaultLevel_{configuration}"); + CopyTestAsset("WasmBasicTestApp", $"DebugLevelTests_PublishWithDefaultLevel_{configuration}", "App"); PublishProject(configuration); var result = await RunSdkStyleAppForPublish(new( @@ -82,8 +82,8 @@ public async Task PublishWithDefaultLevel(string configuration) [InlineData("Release", -1)] public async Task PublishWithExplicitValue(string configuration, int debugLevel) { - CopyTestAsset("WasmBasicTestApp", $"DebugLevelTests_PublishWithExplicitValue_{configuration}"); - PublishProject(configuration, $"-p:WasmDebugLevel={debugLevel}"); + CopyTestAsset("WasmBasicTestApp", $"DebugLevelTests_PublishWithExplicitValue_{configuration}", "App"); + PublishProject(configuration, RuntimeVariant.SingleThreaded, assertAppBundle: true, $"-p:WasmDebugLevel={debugLevel}"); var result = await RunSdkStyleAppForPublish(new( Configuration: configuration, @@ -97,8 +97,8 @@ public async Task PublishWithExplicitValue(string configuration, int debugLevel) [InlineData("Release")] public async Task PublishWithDefaultLevelAndPdbs(string configuration) { - CopyTestAsset("WasmBasicTestApp", $"DebugLevelTests_PublishWithDefaultLevelAndPdbs_{configuration}"); - PublishProject(configuration, $"-p:CopyOutputSymbolsToPublishDirectory=true"); + CopyTestAsset("WasmBasicTestApp", $"DebugLevelTests_PublishWithDefaultLevelAndPdbs_{configuration}", "App"); + PublishProject(configuration, RuntimeVariant.SingleThreaded, assertAppBundle: true, $"-p:CopyOutputSymbolsToPublishDirectory=true"); var result = await RunSdkStyleAppForPublish(new( Configuration: configuration, diff --git a/src/mono/wasm/Wasm.Build.Tests/TestAppScenarios/LazyLoadingTests.cs b/src/mono/wasm/Wasm.Build.Tests/TestAppScenarios/LazyLoadingTests.cs index cf16a0536a38da..038951e1822e68 100644 --- a/src/mono/wasm/Wasm.Build.Tests/TestAppScenarios/LazyLoadingTests.cs +++ b/src/mono/wasm/Wasm.Build.Tests/TestAppScenarios/LazyLoadingTests.cs @@ -23,7 +23,7 @@ public LazyLoadingTests(ITestOutputHelper output, SharedBuildPerTestClassFixture [Fact] public async Task LoadLazyAssemblyBeforeItIsNeeded() { - CopyTestAsset("WasmBasicTestApp", "LazyLoadingTests"); + CopyTestAsset("WasmBasicTestApp", "LazyLoadingTests", "App"); PublishProject("Debug"); var result = await RunSdkStyleAppForPublish(new(Configuration: "Debug", TestScenario: "LazyLoadingTest")); @@ -33,7 +33,7 @@ public async Task LoadLazyAssemblyBeforeItIsNeeded() [Fact] public async Task FailOnMissingLazyAssembly() { - CopyTestAsset("WasmBasicTestApp", "LazyLoadingTests"); + CopyTestAsset("WasmBasicTestApp", "LazyLoadingTests", "App"); PublishProject("Debug"); var result = await RunSdkStyleAppForPublish(new( diff --git a/src/mono/wasm/Wasm.Build.Tests/TestAppScenarios/LibraryInitializerTests.cs b/src/mono/wasm/Wasm.Build.Tests/TestAppScenarios/LibraryInitializerTests.cs index e985ad23d89a0b..c4380ed755a591 100644 --- a/src/mono/wasm/Wasm.Build.Tests/TestAppScenarios/LibraryInitializerTests.cs +++ b/src/mono/wasm/Wasm.Build.Tests/TestAppScenarios/LibraryInitializerTests.cs @@ -26,7 +26,7 @@ public LibraryInitializerTests(ITestOutputHelper output, SharedBuildPerTestClass [Fact] public async Task LoadLibraryInitializer() { - CopyTestAsset("WasmBasicTestApp", "LibraryInitializerTests_LoadLibraryInitializer"); + CopyTestAsset("WasmBasicTestApp", "LibraryInitializerTests_LoadLibraryInitializer", "App"); PublishProject("Debug"); var result = await RunSdkStyleAppForPublish(new(Configuration: "Debug", TestScenario: "LibraryInitializerTest")); @@ -39,7 +39,7 @@ public async Task LoadLibraryInitializer() [Fact] public async Task AbortStartupOnError() { - CopyTestAsset("WasmBasicTestApp", "LibraryInitializerTests_AbortStartupOnError"); + CopyTestAsset("WasmBasicTestApp", "LibraryInitializerTests_AbortStartupOnError", "App"); PublishProject("Debug"); var result = await RunSdkStyleAppForPublish(new( diff --git a/src/mono/wasm/Wasm.Build.Tests/TestAppScenarios/ModuleConfigTests.cs b/src/mono/wasm/Wasm.Build.Tests/TestAppScenarios/ModuleConfigTests.cs index 4dc20e7358aa5b..532751a4ac5347 100644 --- a/src/mono/wasm/Wasm.Build.Tests/TestAppScenarios/ModuleConfigTests.cs +++ b/src/mono/wasm/Wasm.Build.Tests/TestAppScenarios/ModuleConfigTests.cs @@ -25,7 +25,7 @@ public ModuleConfigTests(ITestOutputHelper output, SharedBuildPerTestClassFixtur [InlineData(true)] public async Task DownloadProgressFinishes(bool failAssemblyDownload) { - CopyTestAsset("WasmBasicTestApp", $"ModuleConfigTests_DownloadProgressFinishes_{failAssemblyDownload}"); + CopyTestAsset("WasmBasicTestApp", $"ModuleConfigTests_DownloadProgressFinishes_{failAssemblyDownload}", "App"); PublishProject("Debug"); var result = await RunSdkStyleAppForPublish(new( @@ -58,7 +58,7 @@ public async Task DownloadProgressFinishes(bool failAssemblyDownload) [Fact] public async Task OutErrOverrideWorks() { - CopyTestAsset("WasmBasicTestApp", $"ModuleConfigTests_OutErrOverrideWorks"); + CopyTestAsset("WasmBasicTestApp", $"ModuleConfigTests_OutErrOverrideWorks", "App"); PublishProject("Debug"); var result = await RunSdkStyleAppForPublish(new( diff --git a/src/mono/wasm/Wasm.Build.Tests/TestAppScenarios/SatelliteLoadingTests.cs b/src/mono/wasm/Wasm.Build.Tests/TestAppScenarios/SatelliteLoadingTests.cs index 2088e1522ad73b..517f34255f9969 100644 --- a/src/mono/wasm/Wasm.Build.Tests/TestAppScenarios/SatelliteLoadingTests.cs +++ b/src/mono/wasm/Wasm.Build.Tests/TestAppScenarios/SatelliteLoadingTests.cs @@ -26,7 +26,7 @@ public SatelliteLoadingTests(ITestOutputHelper output, SharedBuildPerTestClassFi [Fact] public async Task LoadSatelliteAssembly() { - CopyTestAsset("WasmBasicTestApp", "SatelliteLoadingTests"); + CopyTestAsset("WasmBasicTestApp", "SatelliteLoadingTests", "App"); BuildProject("Debug"); var result = await RunSdkStyleAppForBuild(new(Configuration: "Debug", TestScenario: "SatelliteAssembliesTest")); diff --git a/src/mono/wasm/Wasm.Build.Tests/TestAppScenarios/SignalRClientTests.cs b/src/mono/wasm/Wasm.Build.Tests/TestAppScenarios/SignalRClientTests.cs deleted file mode 100644 index 1b09272b487931..00000000000000 --- a/src/mono/wasm/Wasm.Build.Tests/TestAppScenarios/SignalRClientTests.cs +++ /dev/null @@ -1,101 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Text; -using System.Text.RegularExpressions; -using System.Threading.Tasks; -using Microsoft.Playwright; -using Xunit.Abstractions; -using Xunit; - -#nullable enable - -namespace Wasm.Build.Tests.TestAppScenarios; - -public class SignalRClientTests : AppTestBase -{ - public SignalRClientTests(ITestOutputHelper output, SharedBuildPerTestClassFixture buildContext) - : base(output, buildContext) - { - } - - [ConditionalTheory(typeof(BuildTestBase), nameof(IsWorkloadWithMultiThreadingForDefaultFramework))] - [ActiveIssue("https://github.com/dotnet/runtime/issues/100445")] // to be fixed by: "https://github.com/dotnet/aspnetcore/issues/54365" - [InlineData("Debug", "LongPolling")] - [InlineData("Release", "LongPolling")] - [InlineData("Debug", "WebSockets")] - [InlineData("Release", "WebSockets")] - public async Task SignalRPassMessages(string config, string transport) - { - BlazorHostedBuild(config, - assetName: "BlazorHostedApp", - clientDirRelativeToProjectDir: "../BlazorHosted.Client", - generatedProjectNamePrefix: "SignalRClientTests", - runtimeType: RuntimeVariant.MultiThreaded); - - List consoleOutput = new(); - List serverOutput = new(); - - var result = await RunSdkStyleAppForBuild(new( - Configuration: config, - // We are using build (not publish), - // we need to instruct static web assets to use manifest file, - // because wwwroot in bin doesn't contain all files (for build) - ServerEnvironment: new Dictionary { ["ASPNETCORE_ENVIRONMENT"] = "Development" }, - BrowserPath: "/chat", - BrowserQueryString: new Dictionary { ["transport"] = transport, ["message"] = "ping" }, - OnServerMessage: (msg) => serverOutput.Add(msg), - OnConsoleMessage: async (page, msg) => - { - consoleOutput.Add(msg.Text); - if (msg.Text.Contains("TestOutput ->")) - _testOutput.WriteLine(msg.Text); - - // prevent timeouts with [Long Running Test] on error - if (msg.Text.ToLowerInvariant().Contains("error")) - { - Console.WriteLine(msg.Text); - Console.WriteLine(_testOutput); - throw new Exception(msg.Text); - } - - if (msg.Text.Contains("Finished GetQueryParameters")) - await SaveClickButtonAsync(page, "button#connectButton"); - - if (msg.Text.Contains("SignalR connected")) - await SaveClickButtonAsync(page, "button#subscribeButton"); - - if (msg.Text.Contains("Subscribed to ReceiveMessage")) - await SaveClickButtonAsync(page, "button#sendMessageButton"); - - if (msg.Text.Contains("ReceiveMessage from server")) - await SaveClickButtonAsync(page, "button#exitProgramButton"); - } - )); - - string output = _testOutput.ToString() ?? ""; - Assert.NotEmpty(output); - // check sending and receiving threadId - string threadIdUsedForSending = GetThreadOfAction(output, @"SignalRPassMessages was sent by CurrentManagedThreadId=(\d+)", "signalR message was sent"); - string threadIdUsedForReceiving = GetThreadOfAction(output, @"ReceiveMessage from server on CurrentManagedThreadId=(\d+)", "signalR message was received"); - Assert.True("1" != threadIdUsedForSending || "1" != threadIdUsedForReceiving, - $"Expected to send/receive with signalR in non-UI threads, instead only CurrentManagedThreadId=1 was used. TestOutput: {output}."); - } - - private string GetThreadOfAction(string testOutput, string pattern, string actionDescription) - { - Match match = Regex.Match(testOutput, pattern); - Assert.True(match.Success, $"Expected to find a log that {actionDescription}. TestOutput: {testOutput}."); - return match.Groups[1].Value ?? ""; - } - - private async Task SaveClickButtonAsync(IPage page, string selector) - { - await page.WaitForSelectorAsync(selector); - await page.ClickAsync(selector); - } -} diff --git a/src/mono/wasm/testassets/BlazorHostedApp/BlazorHosted.Client/Helper.cs b/src/mono/wasm/testassets/BlazorHostedApp/BlazorHosted.Client/Helper.cs deleted file mode 100644 index 38ead1438099f3..00000000000000 --- a/src/mono/wasm/testassets/BlazorHostedApp/BlazorHosted.Client/Helper.cs +++ /dev/null @@ -1,42 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System.Collections.Specialized; -using Microsoft.AspNetCore.Http.Connections; - -namespace BlazorHosted.Client; - -public static class Helper -{ - public static string GetValue(NameValueCollection parameters, string key) - { - var values = parameters.GetValues(key); - if (values == null || values.Length == 0) - { - throw new Exception($"Parameter '{key}' is required in the query string"); - } - if (values.Length > 1) - { - throw new Exception($"Parameter '{key}' should be unique in the query string"); - } - return values[0]; - } - - public static HttpTransportType StringToTransportType(string transport) - { - switch (transport.ToLowerInvariant()) - { - case "longpolling": - return HttpTransportType.LongPolling; - case "websockets": - return HttpTransportType.WebSockets; - default: - throw new Exception($"{transport} is invalid transport type"); - } - } - - public static void TestOutputWriteLine(string message) - { - Console.WriteLine("TestOutput -> " + message); - } -} diff --git a/src/mono/wasm/testassets/BlazorHostedApp/BlazorHosted.Client/Pages/Chat.razor b/src/mono/wasm/testassets/BlazorHostedApp/BlazorHosted.Client/Pages/Chat.razor deleted file mode 100644 index f90aa96c87b92b..00000000000000 --- a/src/mono/wasm/testassets/BlazorHostedApp/BlazorHosted.Client/Pages/Chat.razor +++ /dev/null @@ -1,116 +0,0 @@ -@page "/chat" -@using Microsoft.AspNetCore.SignalR -@using Microsoft.AspNetCore.SignalR.Client -@using Microsoft.AspNetCore.Http.Connections; -@using System.Web; -@inject NavigationManager NavigationManager -@inject IJSRuntime JSRuntime - -

Chat Room

- - - - - -
- @foreach (var chatMessage in chatMessages) - { -

@chatMessage

- } -
- -@code { - private string _hubUrl = string.Empty; - private HubConnection? _hubConnection; - private string message = string.Empty; - private string transport = string.Empty; - private List chatMessages = new List(); - private string wrongQueryError = "Query string with parameters 'message' and 'transport' are required"; - - // remove when https://github.com/dotnet/runtime/issues/96546 is fixed - // log that rendering is about to start in case we hit the issue before OnAfterRender is called - protected override bool ShouldRender() - { - bool shouldRender = base.ShouldRender(); - Helper.TestOutputWriteLine($"ShouldRender = {shouldRender}"); - return shouldRender; - } - - protected override void OnAfterRender(bool firstRender) - { - if (firstRender) - { - Helper.TestOutputWriteLine($"OnAfterRender on CurrentManagedThreadId={Environment.CurrentManagedThreadId}"); - GetQueryParameters(); - } - base.OnAfterRender(firstRender); - } - - private void GetQueryParameters() - { - var uri = new Uri(NavigationManager.Uri); - if (string.IsNullOrEmpty(uri.Query)) - { - throw new Exception(wrongQueryError); - } - var parameters = HttpUtility.ParseQueryString(uri.Query); - if (parameters == null) - { - throw new Exception(wrongQueryError); - } - transport = Helper.GetValue(parameters, "transport"); - message = $"{transport} {Helper.GetValue(parameters, "message")}" ; - Helper.TestOutputWriteLine($"Finished GetQueryParameters on CurrentManagedThreadId={Environment.CurrentManagedThreadId}."); - } - - private async Task Connect() - { - _hubUrl = NavigationManager.BaseUri + "chathub"; - HttpTransportType httpTransportType = Helper.StringToTransportType(transport); - _hubConnection = new HubConnectionBuilder() - .WithUrl(_hubUrl, options => - { - options.Transports = httpTransportType; - }) - .Build(); - - await _hubConnection.StartAsync(); - Helper.TestOutputWriteLine($"SignalR connected by CurrentManagedThreadId={Environment.CurrentManagedThreadId}"); - } - - private void Subscribe() - { - _hubConnection.On("ReceiveMessage", (message) => - { - Helper.TestOutputWriteLine($"Message = [{message}]. ReceiveMessage from server on CurrentManagedThreadId={Environment.CurrentManagedThreadId}"); - chatMessages.Add(message); - }); - Helper.TestOutputWriteLine($"Subscribed to ReceiveMessage by CurrentManagedThreadId={Environment.CurrentManagedThreadId}"); - } - - private async Task SignalRPassMessages() => - await Task.Run(async () => - { - await _hubConnection.SendAsync( "SendMessage", message, Environment.CurrentManagedThreadId); - Helper.TestOutputWriteLine($"SignalRPassMessages was sent by CurrentManagedThreadId={Environment.CurrentManagedThreadId}"); - }); - - private async Task SendExitSignal() - { - await DisposeHubConnection(); - // exit the client - Helper.TestOutputWriteLine($"SendExitSignal by CurrentManagedThreadId={Environment.CurrentManagedThreadId}"); - await JSRuntime.InvokeVoidAsync("eval", "setTimeout(() => { getDotnetRuntime(0).exit(0); }, 50);"); - } - - private async Task DisposeHubConnection() - { - if (_hubConnection != null) - { - _hubConnection.Remove("ReceiveMessage"); - await _hubConnection.DisposeAsync(); - _hubConnection = null; - } - Helper.TestOutputWriteLine($"SignalR disconnected by CurrentManagedThreadId={Environment.CurrentManagedThreadId}"); - } -} diff --git a/src/mono/wasm/testassets/BlazorHostedApp/BlazorHosted.Client/wwwroot/favicon.ico b/src/mono/wasm/testassets/BlazorHostedApp/BlazorHosted.Client/wwwroot/favicon.ico deleted file mode 100644 index 63e859b476eff5055e0e557aaa151ca8223fbeef..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5430 zcmc&&Yj2xp8Fqnv;>&(QB_ve7>^E#o2mu=cO~A%R>DU-_hfbSRv1t;m7zJ_AMrntN zy0+^f&8be>q&YYzH%(88lQ?#KwiCzaCO*ZEo%j&v;<}&Lj_stKTKK>#U3nin@AF>w zb3ONSAFR{u(S1d?cdw53y}Gt1b-Hirbh;;bm(Rcbnoc*%@jiaXM|4jU^1WO~`TYZ~ zC-~jh9~b-f?fX`DmwvcguQzn*uV}c^Vd&~?H|RUs4Epv~gTAfR(B0lT&?RWQOtduM z^1vUD9{HQsW!{a9|0crA34m7Z6lpG^}f6f?={zD+ zXAzk^i^aKN_}s2$eX81wjSMONE#WVdzf|MT)Ap*}Vsn!XbvsI#6o&ij{87^d%$|A{ z=F{KB%)g%@z76yBzbb7seW**Ju8r4e*Z3PWNX3_tTDgzZatz7)Q6ytwB%@&@A|XT; zecM`Snxx5po$C)%yCP!KEtos~eOS)@2=kX-RIm)4glMCoagTEFxrBeSX%Euz734Fk z%7)x(k~T!@Hbg_37NSQL!vlTBXoURSzt~I**Zw`&F24fH*&kx=%nvZv|49SC*daD( zIw<~%#=lk8{2-l(BcIjy^Q$Q&m#KlWL9?UG{b8@qhlD z;umc+6p%|NsAT~0@DgV4-NKgQuWPWrmPIK&&XhV&n%`{l zOl^bbWYjQNuVXTXESO)@|iUKVmErPUDfz2Wh`4dF@OFiaCW|d`3paV^@|r^8T_ZxM)Z+$p5qx# z#K=z@%;aBPO=C4JNNGqVv6@UGolIz;KZsAro``Rz8X%vq_gpi^qEV&evgHb_=Y9-l z`)imdx0UC>GWZYj)3+3aKh?zVb}=@%oNzg7a8%kfVl)SV-Amp1Okw&+hEZ3|v(k8vRjXW9?ih`&FFM zV$~{j3IzhtcXk?Mu_!12;=+I7XK-IR2>Yd%VB^?oI9c^E&Chb&&je$NV0P-R;ujkP z;cbLCCPEF6|22NDj=S`F^2e~XwT1ZnRX8ra0#DaFa9-X|8(xNW_+JhD75WnSd7cxo z2>I_J5{c|WPfrgl7E2R)^c}F7ry()Z>$Jhk9CzZxiPKL#_0%`&{MX>P_%b~Dx0D^S z7xP1(DQ!d_Icpk!RN3I1w@~|O1ru#CO==h#9M~S4Chx*@?=EKUPGBv$tmU+7Zs_al z`!jR?6T&Z7(%uVq>#yLu`abWk!FBlnY{RFNHlj~6zh*;@u}+}viRKsD`IIxN#R-X3 z@vxu#EA_m}I503U(8Qmx^}u;)KfGP`O9E1H1Q|xeeksX8jC%@!{YT1)!lWgO=+Y3*jr=iSxvOW1}^HSy=y){tOMQJ@an>sOl4FYniE z;GOxd7AqxZNbYFNqobpv&HVO$c-w!Y*6r;$2oJ~h(a#(Bp<-)dg*mNigX~9rPqcHv z^;c*|Md?tD)$y?6FO$DWl$jUGV`F1G_^E&E>sY*YnA~ruv3=z9F8&&~Xpm<<75?N3 z>x~`I&M9q)O1=zWZHN9hZWx>RQ}zLP+iL57Q)%&_^$Sme^^G7;e-P~CR?kqU#Io#( z(nH1Wn*Ig)|M>WLGrxoU?FZrS`4GO&w;+39A3f8w{{Q7eg|$+dIlNFPAe+tN=FOYU z{A&Fg|H73+w1IK(W=j*L>JQgz$g0 z7JpKXLHIh}#$wm|N`s}o-@|L_`>*(gTQ~)wr3Eap7g%PVNisKw82im;Gdv#85x#s+ zoqqtnwu4ycd>cOQgRh-=aEJbnvVK`}ja%+FZx}&ehtX)n(9nVfe4{mn0bgijUbNr7Tf5X^$*{qh2%`?--%+sbSrjE^;1e3>% zqa%jdY16{Y)a1hSy*mr0JGU05Z%=qlx5vGvTjSpTt6k%nR06q}1DU`SQh_ZAeJ}A@`hL~xvv05U?0%=spP`R>dk?cOWM9^KNb7B?xjex>OZo%JMQQ1Q zB|q@}8RiP@DWn-(fB;phPaIOP2Yp)XN3-Fsn)S3w($4&+p8f5W_f%gac}QvmkHfCj$2=!t`boCvQ zCW;&Dto=f8v##}dy^wg3VNaBy&kCe3N;1|@n@pUaMPT?(aJ9b*(gJ28$}(2qFt$H~u5z94xcIQkcOI++)*exzbrk?WOOOf*|%k5#KV zL=&ky3)Eirv$wbRJ2F2s_ILQY--D~~7>^f}W|Aw^e7inXr#WLI{@h`0|jHud2Y~cI~Yn{r_kU^Vo{1gja -{ - options.KeepAliveInterval = TimeSpan.Zero; // minimize keep-alive messages -}); - -var app = builder.Build(); - -// Configure the HTTP request pipeline. -if (app.Environment.IsDevelopment()) -{ - app.UseWebAssemblyDebugging(); -} -else -{ - app.UseExceptionHandler("/Error"); - // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts. - app.UseHsts(); -} - -// Add headers to enable SharedArrayBuffer -app.Use(async (context, next) => -{ - var response = context.Response; - response.Headers.Append("Cross-Origin-Opener-Policy", "same-origin"); - response.Headers.Append("Cross-Origin-Embedder-Policy", "require-corp"); - - await next(); -}); -app.UseBlazorFrameworkFiles(); -app.UseStaticFiles(); - -app.UseRouting(); - -app.MapRazorPages(); -app.MapControllers(); -app.MapFallbackToFile("index.html"); - -app.MapHub("/chathub"); - -app.Run(); diff --git a/src/mono/wasm/testassets/BlazorHostedApp/BlazorHosted.Server/appsettings.json b/src/mono/wasm/testassets/BlazorHostedApp/BlazorHosted.Server/appsettings.json deleted file mode 100644 index 75b7c2aa1ecedb..00000000000000 --- a/src/mono/wasm/testassets/BlazorHostedApp/BlazorHosted.Server/appsettings.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "Logging": { - "LogLevel": { - "Default": "Information", - "Microsoft.AspNetCore": "Warning" - } - } -} \ No newline at end of file diff --git a/src/mono/wasm/testassets/BlazorHostedApp/BlazorHosted.Server/BlazorHosted.Server.csproj b/src/mono/wasm/testassets/WasmOnAspNetCore/AspNetCoreServer/AspNetCoreServer.csproj similarity index 63% rename from src/mono/wasm/testassets/BlazorHostedApp/BlazorHosted.Server/BlazorHosted.Server.csproj rename to src/mono/wasm/testassets/WasmOnAspNetCore/AspNetCoreServer/AspNetCoreServer.csproj index db0b51cd370081..9b556e8a965da2 100644 --- a/src/mono/wasm/testassets/BlazorHostedApp/BlazorHosted.Server/BlazorHosted.Server.csproj +++ b/src/mono/wasm/testassets/WasmOnAspNetCore/AspNetCoreServer/AspNetCoreServer.csproj @@ -4,6 +4,7 @@ net9.0 enable enable + true CA2007
@@ -13,7 +14,9 @@ - + + +
diff --git a/src/mono/wasm/testassets/BlazorHostedApp/BlazorHosted.Server/ChatHub.cs b/src/mono/wasm/testassets/WasmOnAspNetCore/AspNetCoreServer/ChatHub.cs similarity index 93% rename from src/mono/wasm/testassets/BlazorHostedApp/BlazorHosted.Server/ChatHub.cs rename to src/mono/wasm/testassets/WasmOnAspNetCore/AspNetCoreServer/ChatHub.cs index 8b2e77807c6fbc..2a1267d102c2fd 100644 --- a/src/mono/wasm/testassets/BlazorHostedApp/BlazorHosted.Server/ChatHub.cs +++ b/src/mono/wasm/testassets/WasmOnAspNetCore/AspNetCoreServer/ChatHub.cs @@ -3,7 +3,8 @@ using Microsoft.AspNetCore.SignalR; -namespace BlazorHosted.Server.Hubs; +namespace Server; + public class ChatHub : Hub { public async Task SendMessage(string message, int sendingThreadId) diff --git a/src/mono/wasm/testassets/WasmOnAspNetCore/AspNetCoreServer/Program.cs b/src/mono/wasm/testassets/WasmOnAspNetCore/AspNetCoreServer/Program.cs new file mode 100644 index 00000000000000..b22b8ded516a02 --- /dev/null +++ b/src/mono/wasm/testassets/WasmOnAspNetCore/AspNetCoreServer/Program.cs @@ -0,0 +1,62 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Http.Connections; +using Microsoft.AspNetCore.SignalR; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.FileProviders; +using Microsoft.AspNetCore.StaticFiles; +using Server; + +var builder = WebApplication.CreateBuilder(args); +builder.Services.AddSignalR(); +var app = builder.Build(); + +// Add headers to enable SharedArrayBuffer +app.Use(async (context, next) => +{ + var response = context.Response; + response.Headers.Append("Cross-Origin-Opener-Policy", "same-origin"); + response.Headers.Append("Cross-Origin-Embedder-Policy", "require-corp"); + + await next(); +}); + +app.UseDefaultFiles(); + +var provider = new FileExtensionContentTypeProvider(); +provider.Mappings[".dll"] = "application/octet-stream"; +provider.Mappings[".pdb"] = "application/octet-stream"; +provider.Mappings[".dat"] = "application/octet-stream"; +app.UseStaticFiles(new StaticFileOptions +{ + ContentTypeProvider = provider, +}); + +ConfigureClientApp(app, "wasmclient"); +ConfigureClientApp(app, "blazorclient"); + +app.Run(); + + +static void ConfigureClientApp(WebApplication app, string clientAppPath) +{ + app.MapWhen( + ctx => ctx.Request.Path.StartsWithSegments($"/{clientAppPath}", out var rest), + clientApp => + { + clientApp + .UseBlazorFrameworkFiles($"/{clientAppPath}") + .UsePathBase($"/{clientAppPath}") + .UseRouting() + .UseEndpoints(endpoints => + { + endpoints.MapHub("/chathub"); + endpoints.MapFallbackToFile($"{clientAppPath}/index.html"); + }); + } + ); +} diff --git a/src/mono/wasm/testassets/BlazorHostedApp/BlazorHosted.Client/App.razor b/src/mono/wasm/testassets/WasmOnAspNetCore/BlazorClient/App.razor similarity index 100% rename from src/mono/wasm/testassets/BlazorHostedApp/BlazorHosted.Client/App.razor rename to src/mono/wasm/testassets/WasmOnAspNetCore/BlazorClient/App.razor diff --git a/src/mono/wasm/testassets/BlazorHostedApp/BlazorHosted.Client/BlazorHosted.Client.csproj b/src/mono/wasm/testassets/WasmOnAspNetCore/BlazorClient/BlazorClient.csproj similarity index 67% rename from src/mono/wasm/testassets/BlazorHostedApp/BlazorHosted.Client/BlazorHosted.Client.csproj rename to src/mono/wasm/testassets/WasmOnAspNetCore/BlazorClient/BlazorClient.csproj index 237c5cf2d75acd..5c974a459386c2 100644 --- a/src/mono/wasm/testassets/BlazorHostedApp/BlazorHosted.Client/BlazorHosted.Client.csproj +++ b/src/mono/wasm/testassets/WasmOnAspNetCore/BlazorClient/BlazorClient.csproj @@ -7,13 +7,16 @@ true CS8604;CS4014 + blazorclient
- - - - + + + + + + diff --git a/src/mono/wasm/testassets/BlazorHostedApp/BlazorHosted.Client/Layout/MainLayout.razor b/src/mono/wasm/testassets/WasmOnAspNetCore/BlazorClient/Layout/MainLayout.razor similarity index 100% rename from src/mono/wasm/testassets/BlazorHostedApp/BlazorHosted.Client/Layout/MainLayout.razor rename to src/mono/wasm/testassets/WasmOnAspNetCore/BlazorClient/Layout/MainLayout.razor diff --git a/src/mono/wasm/testassets/WasmOnAspNetCore/BlazorClient/Pages/Chat.razor b/src/mono/wasm/testassets/WasmOnAspNetCore/BlazorClient/Pages/Chat.razor new file mode 100644 index 00000000000000..6009840f502213 --- /dev/null +++ b/src/mono/wasm/testassets/WasmOnAspNetCore/BlazorClient/Pages/Chat.razor @@ -0,0 +1,34 @@ +@page "/" +@inject NavigationManager NavigationManager + +

Chat Room

+@code { + private SignalRTest signalRTest = new(); + + // remove when https://github.com/dotnet/runtime/issues/96546 is fixed + // log that rendering is about to start in case we hit the issue before OnAfterRender is called + protected override bool ShouldRender() + { + bool shouldRender = base.ShouldRender(); + TestOutput.WriteLine($"ShouldRender = {shouldRender}"); + return shouldRender; + } + + protected override async Task OnAfterRenderAsync(bool firstRender) + { + if (firstRender) + { + TestOutput.WriteLine($"SignalRTest is started on CurrentManagedThreadId={Environment.CurrentManagedThreadId}"); + try + { + int result = await signalRTest.Run(NavigationManager.BaseUri, NavigationManager.Uri); + TestOutput.WriteLine($"SignalRTest finished with code {result}. WASM EXIT {result}"); + } + catch (Exception ex) + { + TestOutput.WriteLine($"SignalRTest failed with exception {ex}. WASM EXIT -1"); + } + } + base.OnAfterRenderAsync(firstRender); + } +} diff --git a/src/mono/wasm/testassets/BlazorHostedApp/BlazorHosted.Client/Program.cs b/src/mono/wasm/testassets/WasmOnAspNetCore/BlazorClient/Program.cs similarity index 95% rename from src/mono/wasm/testassets/BlazorHostedApp/BlazorHosted.Client/Program.cs rename to src/mono/wasm/testassets/WasmOnAspNetCore/BlazorClient/Program.cs index 67a2fb06d6a1e1..bcc0dff43d9868 100644 --- a/src/mono/wasm/testassets/BlazorHostedApp/BlazorHosted.Client/Program.cs +++ b/src/mono/wasm/testassets/WasmOnAspNetCore/BlazorClient/Program.cs @@ -1,7 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using BlazorHosted.Client; +using BlazorClient; using Microsoft.AspNetCore.Components.Web; using Microsoft.AspNetCore.Components.WebAssembly.Hosting; diff --git a/src/mono/wasm/testassets/BlazorHostedApp/BlazorHosted.Client/_Imports.razor b/src/mono/wasm/testassets/WasmOnAspNetCore/BlazorClient/_Imports.razor similarity index 72% rename from src/mono/wasm/testassets/BlazorHostedApp/BlazorHosted.Client/_Imports.razor rename to src/mono/wasm/testassets/WasmOnAspNetCore/BlazorClient/_Imports.razor index d39afd384f8990..1c193c143df2ce 100644 --- a/src/mono/wasm/testassets/BlazorHostedApp/BlazorHosted.Client/_Imports.razor +++ b/src/mono/wasm/testassets/WasmOnAspNetCore/BlazorClient/_Imports.razor @@ -2,5 +2,6 @@ @using Microsoft.AspNetCore.Components.Routing @using Microsoft.AspNetCore.Components.Web @using Microsoft.JSInterop -@using BlazorHosted.Client -@using BlazorHosted.Client.Layout \ No newline at end of file +@using BlazorClient +@using BlazorClient.Layout +@using Shared \ No newline at end of file diff --git a/src/mono/wasm/testassets/BlazorHostedApp/BlazorHosted.Client/wwwroot/index.html b/src/mono/wasm/testassets/WasmOnAspNetCore/BlazorClient/wwwroot/index.html similarity index 62% rename from src/mono/wasm/testassets/BlazorHostedApp/BlazorHosted.Client/wwwroot/index.html rename to src/mono/wasm/testassets/WasmOnAspNetCore/BlazorClient/wwwroot/index.html index 56dd2027fdf839..f911682fdf48bb 100644 --- a/src/mono/wasm/testassets/BlazorHostedApp/BlazorHosted.Client/wwwroot/index.html +++ b/src/mono/wasm/testassets/WasmOnAspNetCore/BlazorClient/wwwroot/index.html @@ -5,7 +5,7 @@ BlazorHosted - + @@ -16,14 +16,7 @@ Reload 🗙 - - + diff --git a/src/mono/wasm/testassets/WasmOnAspNetCore/Shared/QueryParser.cs b/src/mono/wasm/testassets/WasmOnAspNetCore/Shared/QueryParser.cs new file mode 100644 index 00000000000000..b863fa4ed54914 --- /dev/null +++ b/src/mono/wasm/testassets/WasmOnAspNetCore/Shared/QueryParser.cs @@ -0,0 +1,24 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Collections.Specialized; + +namespace Shared; + +public static class QueryParser +{ + public static string GetValue(NameValueCollection parameters, string key) + { + var values = parameters.GetValues(key); + if (values == null || values.Length == 0) + { + throw new Exception($"Parameter '{key}' is required in the query string"); + } + if (values.Length > 1) + { + throw new Exception($"Parameter '{key}' should be unique in the query string"); + } + return values[0]; + } +} diff --git a/src/mono/wasm/testassets/WasmOnAspNetCore/Shared/Shared.csproj b/src/mono/wasm/testassets/WasmOnAspNetCore/Shared/Shared.csproj new file mode 100644 index 00000000000000..5980a8781983ac --- /dev/null +++ b/src/mono/wasm/testassets/WasmOnAspNetCore/Shared/Shared.csproj @@ -0,0 +1,19 @@ + + + + net9.0 + Library + true + enable + CA2007 + + + + + + + + + + + diff --git a/src/mono/wasm/testassets/WasmOnAspNetCore/Shared/SignalRTest.cs b/src/mono/wasm/testassets/WasmOnAspNetCore/Shared/SignalRTest.cs new file mode 100644 index 00000000000000..5b4253646413b5 --- /dev/null +++ b/src/mono/wasm/testassets/WasmOnAspNetCore/Shared/SignalRTest.cs @@ -0,0 +1,114 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Collections.Specialized; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Http.Connections; +using Microsoft.AspNetCore.SignalR.Client; +using System.Web; + +namespace Shared; + +public class SignalRTest +{ + private TaskCompletionSource? tcs; + private HubConnection? _hubConnection; + private string transport = string.Empty; + private string message = string.Empty; + private string wrongQueryError = "Query string with parameters 'message' and 'transport' is required"; + + public async Task Run(string origin, string fullUrl) + { + tcs = new TaskCompletionSource(); + GetQueryParameters(fullUrl); + await Connect(origin); + await SignalRPassMessages(); + + int delayInMin = 2; + await Task.WhenAny( + tcs!.Task, + Task.Delay(TimeSpan.FromMinutes(delayInMin))); + + if (!tcs!.Task.IsCompleted) + throw new TimeoutException($"Test timed out after waiting {delayInMin} minutes for process to exit."); + return tcs.Task.Result; + + } + + private void SetResult(int value) => tcs?.SetResult(value); + + private void GetQueryParameters(string url) + { + var uri = new Uri(url); + if (string.IsNullOrEmpty(uri.Query)) + { + throw new Exception(wrongQueryError); + } + var parameters = HttpUtility.ParseQueryString(uri.Query); + if (parameters == null) + { + throw new Exception(wrongQueryError); + } + transport = QueryParser.GetValue(parameters, "transport"); + message = $"{transport} {QueryParser.GetValue(parameters, "message")}" ; + TestOutput.WriteLine($"Finished GetQueryParameters on CurrentManagedThreadId={Environment.CurrentManagedThreadId}."); + } + + private async Task Connect(string baseUri) + { + string hubUrl = new Uri(new Uri(baseUri), "chathub").ToString(); + Console.WriteLine($"hubUrl: {hubUrl}"); + HttpTransportType httpTransportType = StringToTransportType(transport); + _hubConnection = new HubConnectionBuilder() + .WithUrl(hubUrl, options => + { + options.Transports = httpTransportType; + }) + .Build(); + + _hubConnection.On("ReceiveMessage", async (message) => + { + TestOutput.WriteLine($"Message = [{message}]. ReceiveMessage from server on CurrentManagedThreadId={Environment.CurrentManagedThreadId}"); + await DisposeHubConnection(); + SetResult(0); + }); + TestOutput.WriteLine($"Subscribed to ReceiveMessage by CurrentManagedThreadId={Environment.CurrentManagedThreadId}"); + + await _hubConnection.StartAsync(); + TestOutput.WriteLine($"SignalR connected by CurrentManagedThreadId={Environment.CurrentManagedThreadId}"); + } + + private static HttpTransportType StringToTransportType(string transport) + { + switch (transport.ToLowerInvariant()) + { + case "longpolling": + return HttpTransportType.LongPolling; + case "websockets": + return HttpTransportType.WebSockets; + default: + throw new Exception($"{transport} is invalid transport type"); + } + } + + private async Task SignalRPassMessages() => + await Task.Run(async () => + { + if (_hubConnection == null) + throw new Exception("Cannot send messages before establishing hub connection"); + await _hubConnection!.SendAsync("SendMessage", message, Environment.CurrentManagedThreadId); + TestOutput.WriteLine($"SignalRPassMessages was sent by CurrentManagedThreadId={Environment.CurrentManagedThreadId}"); + }); + + private async Task DisposeHubConnection() + { + if (_hubConnection != null) + { + _hubConnection.Remove("ReceiveMessage"); + await _hubConnection.DisposeAsync(); + _hubConnection = null; + } + TestOutput.WriteLine($"SignalR disconnected by CurrentManagedThreadId={Environment.CurrentManagedThreadId}"); + } +} diff --git a/src/mono/wasm/testassets/WasmOnAspNetCore/Shared/TestOutput.cs b/src/mono/wasm/testassets/WasmOnAspNetCore/Shared/TestOutput.cs new file mode 100644 index 00000000000000..3cb92a24277c28 --- /dev/null +++ b/src/mono/wasm/testassets/WasmOnAspNetCore/Shared/TestOutput.cs @@ -0,0 +1,20 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; + +namespace Shared; + +public static class TestOutput +{ + public static void WriteLine(string message) + { + Console.WriteLine("TestOutput -> " + message); + } + + public static void WriteLine(object message) + { + Console.Write("TestOutput -> "); + Console.WriteLine(message); + } +} diff --git a/src/mono/wasm/testassets/WasmOnAspNetCore/WasmBrowserClient/Program.cs b/src/mono/wasm/testassets/WasmOnAspNetCore/WasmBrowserClient/Program.cs new file mode 100644 index 00000000000000..88bed62c360863 --- /dev/null +++ b/src/mono/wasm/testassets/WasmOnAspNetCore/WasmBrowserClient/Program.cs @@ -0,0 +1,21 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Threading.Tasks; +using Shared; + +public partial class Program +{ + public static async Task Main(string[] args) + { + if (args.Length < 2) + throw new Exception("Expected url origin and href passed as arguments"); + + SignalRTest test = new(); + Console.WriteLine($"arg0: {args[0]}, arg1: {args[1]}"); + int result = await test.Run(origin: args[0], fullUrl: args[1]); + if (result != 0) + throw new Exception($"WasmBrowser finished with non-success code: {result}"); + } +} diff --git a/src/mono/wasm/testassets/WasmOnAspNetCore/WasmBrowserClient/TestOutput.cs b/src/mono/wasm/testassets/WasmOnAspNetCore/WasmBrowserClient/TestOutput.cs new file mode 100644 index 00000000000000..5755b753b5e492 --- /dev/null +++ b/src/mono/wasm/testassets/WasmOnAspNetCore/WasmBrowserClient/TestOutput.cs @@ -0,0 +1,18 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; + +public static class TestOutput +{ + public static void WriteLine(string message) + { + Console.WriteLine("TestOutput -> " + message); + } + + public static void WriteLine(object message) + { + Console.Write("TestOutput -> "); + Console.WriteLine(message); + } +} diff --git a/src/mono/wasm/testassets/WasmOnAspNetCore/WasmBrowserClient/WasmBrowserClient.csproj b/src/mono/wasm/testassets/WasmOnAspNetCore/WasmBrowserClient/WasmBrowserClient.csproj new file mode 100644 index 00000000000000..a74e1246d8bddf --- /dev/null +++ b/src/mono/wasm/testassets/WasmOnAspNetCore/WasmBrowserClient/WasmBrowserClient.csproj @@ -0,0 +1,17 @@ + + + net9.0 + browser-wasm + Exe + true + enable + + CA1050;CA2007;CA1861;IL2104 + true + wasmclient + + + + + + diff --git a/src/mono/wasm/testassets/WasmOnAspNetCore/WasmBrowserClient/wwwroot/index.html b/src/mono/wasm/testassets/WasmOnAspNetCore/WasmBrowserClient/wwwroot/index.html new file mode 100644 index 00000000000000..86bc345d2e23ad --- /dev/null +++ b/src/mono/wasm/testassets/WasmOnAspNetCore/WasmBrowserClient/wwwroot/index.html @@ -0,0 +1,17 @@ + + + + + + + WasmBrowser + + + + + + + + + + \ No newline at end of file diff --git a/src/mono/wasm/testassets/WasmOnAspNetCore/WasmBrowserClient/wwwroot/main.js b/src/mono/wasm/testassets/WasmOnAspNetCore/WasmBrowserClient/wwwroot/main.js new file mode 100644 index 00000000000000..f182fd9eff9919 --- /dev/null +++ b/src/mono/wasm/testassets/WasmOnAspNetCore/WasmBrowserClient/wwwroot/main.js @@ -0,0 +1,19 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +import { dotnet, exit } from './_framework/dotnet.js' + +try { + const dotnetRuntime = await dotnet + .withElementOnExit() + .withExitCodeLogging() + .withExitOnUnhandledError() + .create(); + const config = dotnetRuntime.getConfig(); + var url = window.location.origin + window.location.pathname; + await dotnetRuntime.runMainAndExit(config.mainAssemblyName, [url, window.location.href]); + +} +catch (err) { + exit(2, err); +} \ No newline at end of file From f021ccfaf35b51d1adbcd1e94b646e48738c27b2 Mon Sep 17 00:00:00 2001 From: Egor Bogatov Date: Mon, 22 Apr 2024 15:35:14 +0200 Subject: [PATCH 005/161] Fix Redundant bound check for span.Length == 0 pattern (#101323) --- src/coreclr/jit/rangecheck.cpp | 33 ++++++++++++++++++++++++++++++--- 1 file changed, 30 insertions(+), 3 deletions(-) diff --git a/src/coreclr/jit/rangecheck.cpp b/src/coreclr/jit/rangecheck.cpp index e1046de8b99863..1fb068068e845c 100644 --- a/src/coreclr/jit/rangecheck.cpp +++ b/src/coreclr/jit/rangecheck.cpp @@ -866,10 +866,37 @@ void RangeCheck::MergeEdgeAssertions(ValueNum normalLclVN, ASSERT_VALARG_TP asse continue; } - // Doesn't tighten the current bound. So skip. - if (pRange->uLimit.IsConstant() && limit.vn != arrLenVN) + // Skip if it doesn't tighten the current bound: + if (pRange->uLimit.IsConstant() && ((cmpOper == GT_LE) || (cmpOper == GT_LT))) { - continue; + if (!limit.IsConstant() && (limit.vn != arrLenVN)) + { + // If our new limit is not constant and doesn't represent the array's length - bail out. + // NOTE: it's fine to replace the current constant limit with a non-constant arrLenVN. + continue; + } + if (limit.IsConstant() && (limit.cns > pRange->uLimit.cns)) + { + // The new constant limit doesn't tighten the current constant bound. + // E.g. current is "X < 10" and the new one is "X < 100" + continue; + } + } + // Same for the lower bound: + if (pRange->lLimit.IsConstant() && ((cmpOper == GT_GE) || (cmpOper == GT_GT))) + { + if (!limit.IsConstant() && (limit.vn != arrLenVN)) + { + // If our new limit is not constant and doesn't represent the array's length - bail out. + // NOTE: it's fine to replace the current constant limit with a non-constant arrLenVN. + continue; + } + if (limit.IsConstant() && (limit.cns < pRange->lLimit.cns)) + { + // The new constant limit doesn't tighten the current constant bound. + // E.g. current is "X > 10" and the new one is "X > 5" + continue; + } } // Check if the incoming limit from assertions tightens the existing upper limit. From 9ff6bb88cb04f9f7d39f9b01f9ac270a6764b12e Mon Sep 17 00:00:00 2001 From: Steve Pfister Date: Mon, 22 Apr 2024 09:56:22 -0400 Subject: [PATCH 006/161] Enable control flow guard for mono on windows (#101293) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Resolves binskim warnings for the runtime and aot compilers on windows. Co-authored-by: Jan Kotas Co-authored-by: Alexander Köplinger --- src/mono/CMakeLists.txt | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/mono/CMakeLists.txt b/src/mono/CMakeLists.txt index 47dc6aecf82c64..9fcbb6d8219659 100644 --- a/src/mono/CMakeLists.txt +++ b/src/mono/CMakeLists.txt @@ -272,12 +272,14 @@ elseif(CLR_CMAKE_HOST_OS STREQUAL "windows") set(MONO_ZERO_LEN_ARRAY 1) set(INTERNAL_ZLIB 1) set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$:Debug>") # statically link VC runtime library - add_compile_options($<$:/W4>) # set warning level 4 - add_compile_options($<$:/WX>) # treat warnings as errors - add_compile_options($<$:/wd4324>) # 'struct_name' : structure was padded due to __declspec(align()) - add_compile_options($<$:/EHsc>) # set exception handling behavior - add_compile_options($<$:/FC>) # use full pathnames in diagnostics + add_compile_options($<$:/W4>) # set warning level 4 + add_compile_options($<$:/WX>) # treat warnings as errors + add_compile_options($<$:/wd4324>) # 'struct_name' : structure was padded due to __declspec(align()) + add_compile_options($<$:/EHsc>) # set exception handling behavior + add_compile_options($<$:/FC>) # use full pathnames in diagnostics + add_compile_options($<$:/guard:cf>) # Enable control flow guard add_link_options(/STACK:0x800000) # set stack size to 8MB (default is 1MB) + add_link_options(/guard:cf) if(CMAKE_BUILD_TYPE STREQUAL "Release") add_compile_options($<$:/Oi>) # enable intrinsics add_compile_options($<$:/GF>) # enable string pooling From aaebdd89e9453bf7d09325fd86aa15292e7c8560 Mon Sep 17 00:00:00 2001 From: Andy Ayers Date: Mon, 22 Apr 2024 07:25:48 -0700 Subject: [PATCH 007/161] JIT: Move profile checking back until just before inlining (#101011) Fixes the following areas with proper profile updates: * GDV chaining * instrumentation-introduces flow * OSR step blocks * fgSplitEdge (used by instrumentation) Adds checking bypasses for: * callfinally pair tails * original method entries in OSR methods Contributes to #93020 --- src/coreclr/jit/compiler.cpp | 10 ++-- src/coreclr/jit/fgbasic.cpp | 54 +++++++++++++++++---- src/coreclr/jit/fgopt.cpp | 51 ++++++++++++------- src/coreclr/jit/fgprofile.cpp | 50 ++++++++++++++++++- src/coreclr/jit/indirectcalltransformer.cpp | 46 +++++++++++++++++- 5 files changed, 175 insertions(+), 36 deletions(-) diff --git a/src/coreclr/jit/compiler.cpp b/src/coreclr/jit/compiler.cpp index a32867660a01c3..d0bda29cb30891 100644 --- a/src/coreclr/jit/compiler.cpp +++ b/src/coreclr/jit/compiler.cpp @@ -4629,11 +4629,6 @@ void Compiler::compCompile(void** methodCodePtr, uint32_t* methodCodeSize, JitFl // DoPhase(this, PHASE_IMPORTATION, &Compiler::fgImport); - // Drop back to just checking profile likelihoods. - // - activePhaseChecks &= ~PhaseChecks::CHECK_PROFILE; - activePhaseChecks |= PhaseChecks::CHECK_LIKELIHOODS; - // If this is a failed inline attempt, we're done. // if (compIsForInlining() && compInlineResult->IsFailure()) @@ -4688,6 +4683,11 @@ void Compiler::compCompile(void** methodCodePtr, uint32_t* methodCodeSize, JitFl return; } + // Drop back to just checking profile likelihoods. + // + activePhaseChecks &= ~PhaseChecks::CHECK_PROFILE; + activePhaseChecks |= PhaseChecks::CHECK_LIKELIHOODS; + // At this point in the phase list, all the inlinee phases have // been run, and inlinee compiles have exited, so we should only // get this far if we are jitting the root method. diff --git a/src/coreclr/jit/fgbasic.cpp b/src/coreclr/jit/fgbasic.cpp index 808d591a77f5c8..fb717e1a5a50ea 100644 --- a/src/coreclr/jit/fgbasic.cpp +++ b/src/coreclr/jit/fgbasic.cpp @@ -214,10 +214,33 @@ bool Compiler::fgEnsureFirstBBisScratch() block = BasicBlock::New(this); - // If we have profile data the new block will inherit fgFirstBlock's weight + // If we have profile data determine the weight of the scratch BB + // if (fgFirstBB->hasProfileWeight()) { - block->inheritWeight(fgFirstBB); + // If current entry has preds, sum up those weights + // + weight_t nonEntryWeight = 0; + for (FlowEdge* const edge : fgFirstBB->PredEdges()) + { + nonEntryWeight += edge->getLikelyWeight(); + } + + // entry weight is weight not from any pred + // + weight_t const entryWeight = fgFirstBB->bbWeight - nonEntryWeight; + if (entryWeight <= 0) + { + // If the result is clearly nonsensical, just inherit + // + JITDUMP("\fgEnsureFirstBBisScratch: Profile data could not be locally repaired. Data %s inconsisent.\n", + fgPgoConsistent ? "is now" : "was already"); + block->inheritWeight(fgFirstBB); + } + else + { + block->setBBProfileWeight(entryWeight); + } } // The new scratch bb will fall through to the old first bb @@ -5062,17 +5085,28 @@ BasicBlock* Compiler::fgSplitEdge(BasicBlock* curr, BasicBlock* succ) fgReplaceJumpTarget(curr, succ, newBlock); // And 'succ' has 'newBlock' as a new predecessor. - FlowEdge* const newEdge = fgAddRefPred(succ, newBlock); - newBlock->SetTargetEdge(newEdge); + FlowEdge* const newSuccEdge = fgAddRefPred(succ, newBlock); + newBlock->SetTargetEdge(newSuccEdge); - // This isn't accurate, but it is complex to compute a reasonable number so just assume that we take the - // branch 50% of the time. - // - // TODO: leverage edge likelihood. + // Set weight for newBlock // - if (!curr->KindIs(BBJ_ALWAYS)) + if (curr->KindIs(BBJ_ALWAYS)) + { + newBlock->inheritWeight(curr); + } + else { - newBlock->inheritWeightPercentage(curr, 50); + if (curr->hasProfileWeight()) + { + FlowEdge* const currNewEdge = fgGetPredForBlock(newBlock, curr); + newBlock->setBBProfileWeight(currNewEdge->getLikelyWeight()); + } + else + { + // Todo: use likelihood even w/o profile? + // + newBlock->inheritWeightPercentage(curr, 50); + } } // The bbLiveIn and bbLiveOut are both equal to the bbLiveIn of 'succ' diff --git a/src/coreclr/jit/fgopt.cpp b/src/coreclr/jit/fgopt.cpp index c1b919d37830a2..ac008eb140f9d7 100644 --- a/src/coreclr/jit/fgopt.cpp +++ b/src/coreclr/jit/fgopt.cpp @@ -731,17 +731,8 @@ PhaseStatus Compiler::fgPostImportationCleanup() // auto addConditionalFlow = [this, entryStateVar, &entryJumpTarget, &addedBlocks](BasicBlock* fromBlock, BasicBlock* toBlock) { - // We may have previously though this try entry was unreachable, but now we're going to - // step through it on the way to the OSR entry. So ensure it has plausible profile weight. - // - if (fgHaveProfileWeights() && !fromBlock->hasProfileWeight()) - { - JITDUMP("Updating block weight for now-reachable try entry " FMT_BB " via " FMT_BB "\n", - fromBlock->bbNum, fgFirstBB->bbNum); - fromBlock->inheritWeight(fgFirstBB); - } - BasicBlock* const newBlock = fgSplitBlockAtBeginning(fromBlock); + newBlock->inheritWeight(fromBlock); fromBlock->SetFlags(BBF_INTERNAL); newBlock->RemoveFlags(BBF_DONT_REMOVE); addedBlocks++; @@ -754,16 +745,40 @@ PhaseStatus Compiler::fgPostImportationCleanup() fgNewStmtAtBeg(fromBlock, jumpIfEntryStateZero); FlowEdge* const osrTryEntryEdge = fgAddRefPred(toBlock, fromBlock); - newBlock->inheritWeight(fromBlock); fromBlock->SetCond(osrTryEntryEdge, normalTryEntryEdge); - // Not sure what the correct edge likelihoods are just yet; - // for now we'll say the OSR path is the likely one. - // - // Todo: can we leverage profile data here to get a better answer? - // - osrTryEntryEdge->setLikelihood(0.9); - normalTryEntryEdge->setLikelihood(0.1); + if (fgHaveProfileWeights()) + { + // We are adding a path from (ultimately) the method entry to "fromBlock" + // Update the profile weight. + // + weight_t const entryWeight = fgFirstBB->bbWeight; + + JITDUMP("Updating block weight for now-reachable try entry " FMT_BB " via " FMT_BB "\n", + fromBlock->bbNum, fgFirstBB->bbNum); + fromBlock->setBBProfileWeight(fromBlock->bbWeight + entryWeight); + + // We updated the weight of fromBlock above. + // + // Set the likelihoods such that the additional weight flows to toBlock + // (and so the "normal path" profile out of fromBlock to newBlock is unaltered) + // + // In some stress cases we may have a zero-weight OSR entry. + // Tolerate this by capping the fromToLikelihood. + // + weight_t const fromWeight = fromBlock->bbWeight; + weight_t const fromToLikelihood = min(1.0, entryWeight / fromWeight); + + osrTryEntryEdge->setLikelihood(fromToLikelihood); + normalTryEntryEdge->setLikelihood(1.0 - fromToLikelihood); + } + else + { + // Just set likelihoods arbitrarily + // + osrTryEntryEdge->setLikelihood(0.9); + normalTryEntryEdge->setLikelihood(0.1); + } entryJumpTarget = fromBlock; }; diff --git a/src/coreclr/jit/fgprofile.cpp b/src/coreclr/jit/fgprofile.cpp index 79cd63e3ac3b51..05f97ffd14ef59 100644 --- a/src/coreclr/jit/fgprofile.cpp +++ b/src/coreclr/jit/fgprofile.cpp @@ -1689,16 +1689,42 @@ void EfficientEdgeCountInstrumentor::RelocateProbes() { BasicBlock* intermediary = m_comp->fgNewBBbefore(BBJ_ALWAYS, block, /* extendRegion */ true); intermediary->SetFlags(BBF_IMPORTED); - intermediary->inheritWeight(block); FlowEdge* const newEdge = m_comp->fgAddRefPred(block, intermediary); intermediary->SetTargetEdge(newEdge); NewRelocatedProbe(intermediary, probe->source, probe->target, &leader); SetModifiedFlow(); + // Redirect flow and figure out profile impact. + // + // We don't expect to see mixtures of profiled and unprofiled preds, + // but if we do, fall back to our old default behavior. + // + weight_t weight = 0; + bool allPredsHaveProfile = true; + while (criticalPreds.Height() > 0) { BasicBlock* const pred = criticalPreds.Pop(); m_comp->fgReplaceJumpTarget(pred, block, intermediary); + + if (pred->hasProfileWeight()) + { + FlowEdge* const predIntermediaryEdge = m_comp->fgGetPredForBlock(intermediary, pred); + weight += predIntermediaryEdge->getLikelyWeight(); + } + else + { + allPredsHaveProfile = false; + } + } + + if (allPredsHaveProfile) + { + intermediary->setBBProfileWeight(weight); + } + else + { + intermediary->inheritWeight(block); } } } @@ -4773,6 +4799,19 @@ bool Compiler::fgDebugCheckProfileWeights(ProfileChecks checks) verifyIncoming = false; } + // Original entries in OSR methods that also are + // loop headers. + // + // These will frequently have a profile imbalance as + // synthesis will have injected profile weight for + // method entry, but when we transform flow for OSR, + // only the loop back edges remain. + // + if (block == fgEntryBB) + { + verifyIncoming = false; + } + // Handler entries // if (block->hasEHBoundaryIn()) @@ -4935,6 +4974,15 @@ bool Compiler::fgDebugCheckIncomingProfileData(BasicBlock* block, ProfileChecks foundEHPreds = false; } + // We almost certainly won't get the likelihoods on a BBJ_EHFINALLYRET right, + // so special-case BBJ_CALLFINALLYRET incoming flow. + // + if (block->isBBCallFinallyPairTail()) + { + incomingLikelyWeight = block->Prev()->bbWeight; + foundEHPreds = false; + } + bool likelyWeightsValid = true; // If we have EH preds we may not have consistent incoming flow. diff --git a/src/coreclr/jit/indirectcalltransformer.cpp b/src/coreclr/jit/indirectcalltransformer.cpp index fad60de969d4c3..b8a2b2162fd26f 100644 --- a/src/coreclr/jit/indirectcalltransformer.cpp +++ b/src/coreclr/jit/indirectcalltransformer.cpp @@ -1052,7 +1052,7 @@ class IndirectCallTransformer // thenBlock = CreateAndInsertBasicBlock(BBJ_ALWAYS, checkBlock); thenBlock->CopyFlags(currBlock, BBF_SPLIT_GAINED); - thenBlock->inheritWeight(currBlock); + thenBlock->inheritWeight(checkBlock); thenBlock->scaleBBWeight(adjustedThenLikelihood); FlowEdge* const thenRemainderEdge = compiler->fgAddRefPred(remainderBlock, thenBlock); thenBlock->SetTargetEdge(thenRemainderEdge); @@ -1214,10 +1214,52 @@ class IndirectCallTransformer checkStmt = nextStmt; } - // Finally, rewire the cold block to jump to the else block, + // Rewire the cold block to jump to the else block, // not fall through to the check block. // compiler->fgRedirectTargetEdge(coldBlock, elseBlock); + + // Update the profile data + // + if (coldBlock->hasProfileWeight()) + { + // Check block + // + FlowEdge* const coldElseEdge = compiler->fgGetPredForBlock(elseBlock, coldBlock); + weight_t newCheckWeight = checkBlock->bbWeight - coldElseEdge->getLikelyWeight(); + + if (newCheckWeight < 0) + { + // If weights were consistent, we expect at worst a slight underflow. + // + if (compiler->fgPgoConsistent) + { + bool const isReasonableUnderflow = Compiler::fgProfileWeightsEqual(newCheckWeight, 0.0); + assert(isReasonableUnderflow); + + if (!isReasonableUnderflow) + { + compiler->fgPgoConsistent = false; + } + } + + // No matter what, the minimum weight is zero + // + newCheckWeight = 0; + } + checkBlock->setBBProfileWeight(newCheckWeight); + + // Else block + // + FlowEdge* const checkElseEdge = compiler->fgGetPredForBlock(elseBlock, checkBlock); + weight_t const newElseWeight = checkElseEdge->getLikelyWeight() + coldElseEdge->getLikelyWeight(); + elseBlock->setBBProfileWeight(newElseWeight); + + // Then block + // + FlowEdge* const checkThenEdge = compiler->fgGetPredForBlock(thenBlock, checkBlock); + thenBlock->setBBProfileWeight(checkThenEdge->getLikelyWeight()); + } } // When the current candidate has sufficiently high likelihood, scan From ec0a1e7a2413c21989d83bb4246ccd1852b67e26 Mon Sep 17 00:00:00 2001 From: Fan Yang <52458914+fanyang-mono@users.noreply.github.com> Date: Mon, 22 Apr 2024 10:58:58 -0400 Subject: [PATCH 008/161] [mono] UnsafeAccessor: Enable tests for extern static methods without type parameters (#101265) * Enable tests for methods without type parameters * Enable more field tests * Enable all field tests * Fix the type to get size for --- src/mono/mono/metadata/marshal-lightweight.c | 4 ++-- .../UnsafeAccessors/UnsafeAccessorsTests.Generics.cs | 4 ---- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/src/mono/mono/metadata/marshal-lightweight.c b/src/mono/mono/metadata/marshal-lightweight.c index 86f64eeb40bba6..6399b315cfd208 100644 --- a/src/mono/mono/metadata/marshal-lightweight.c +++ b/src/mono/mono/metadata/marshal-lightweight.c @@ -2322,7 +2322,7 @@ method_sig_from_accessor_sig (MonoMethodBuilder *mb, gboolean hasthis, MonoMetho ret->hasthis = hasthis; for (int i = 1; i < ret->param_count; i++) ret->params [i - 1] = ret->params [i]; - memset (&ret->params[ret->param_count - 1], 0, sizeof (MonoType)); // just in case + memset (&ret->params[ret->param_count - 1], 0, sizeof (MonoType*)); // just in case ret->param_count--; return ret; } @@ -2467,7 +2467,7 @@ emit_unsafe_accessor_method_wrapper (MonoMethodBuilder *mb, MonoMethod *accessor static void emit_unsafe_accessor_wrapper_ilgen (MonoMethodBuilder *mb, MonoMethod *accessor_method, MonoMethodSignature *sig, MonoGenericContext *ctx, MonoUnsafeAccessorKind kind, const char *member_name) { - if (accessor_method->is_inflated || accessor_method->is_generic || mono_class_is_ginst (accessor_method->klass) || ctx != NULL) { + if (accessor_method->is_generic || ctx != NULL) { mono_mb_emit_exception_full (mb, "System", "BadImageFormatException", "UnsafeAccessor_Generics"); return; } diff --git a/src/tests/baseservices/compilerservices/UnsafeAccessors/UnsafeAccessorsTests.Generics.cs b/src/tests/baseservices/compilerservices/UnsafeAccessors/UnsafeAccessorsTests.Generics.cs index e1029797bf12cc..e4fb9593dd3ed6 100644 --- a/src/tests/baseservices/compilerservices/UnsafeAccessors/UnsafeAccessorsTests.Generics.cs +++ b/src/tests/baseservices/compilerservices/UnsafeAccessors/UnsafeAccessorsTests.Generics.cs @@ -63,7 +63,6 @@ private void Add(Struct a) => } [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/89439", TestRuntimes.Mono)] public static void Verify_Generic_AccessStaticFieldClass() { Console.WriteLine($"Running {nameof(Verify_Generic_AccessStaticFieldClass)}"); @@ -99,7 +98,6 @@ public static void Verify_Generic_AccessStaticFieldClass() } [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/89439", TestRuntimes.Mono)] public static void Verify_Generic_AccessFieldClass() { Console.WriteLine($"Running {nameof(Verify_Generic_AccessFieldClass)}"); @@ -284,7 +282,6 @@ public static void Verify_Generic_CallCtor() } [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/89439", TestRuntimes.Mono)] public static void Verify_Generic_GenericTypeNonGenericInstanceMethod() { Console.WriteLine($"Running {nameof(Verify_Generic_GenericTypeNonGenericInstanceMethod)}"); @@ -358,7 +355,6 @@ public static void Verify_Generic_GenericTypeGenericInstanceMethod() } [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/89439", TestRuntimes.Mono)] public static void Verify_Generic_GenericTypeNonGenericStaticMethod() { Console.WriteLine($"Running {nameof(Verify_Generic_GenericTypeNonGenericStaticMethod)}"); From 264e39c7b3bcde1c75b20bfef60005ab059b8290 Mon Sep 17 00:00:00 2001 From: Huo Yaoyuan Date: Tue, 23 Apr 2024 00:53:33 +0800 Subject: [PATCH 009/161] Optimize BigInteger formatting (#100181) * Cleanup DecStr formatting * Cleanup ToNumber portion * Clean and pool base1E9 buffer * Split leaf span and array path * Post cherry-pick update * Remove unworthy positive/negative span/string split * Use stackalloc for buffers * Update constant usage * Use UInt32ToDecChars * Fix type assert * Fix strLength --------- Co-authored-by: Tanner Gooding --- .../src/System/Number.Formatting.Common.cs | 2 + .../System.Private.CoreLib.Shared.projitems | 1 + .../FormattingHelpers.CountDigits.Int128.cs | 59 +++++ .../Text/FormattingHelpers.CountDigits.cs | 49 ---- .../src/System/Number.Formatting.cs | 2 - .../src/System.Runtime.Numerics.csproj | 2 + .../src/System/Number.BigInteger.cs | 217 ++++++++---------- .../src/System/Number.Polyfill.cs | 15 ++ 8 files changed, 179 insertions(+), 168 deletions(-) create mode 100644 src/libraries/System.Private.CoreLib/src/System/Buffers/Text/FormattingHelpers.CountDigits.Int128.cs diff --git a/src/libraries/Common/src/System/Number.Formatting.Common.cs b/src/libraries/Common/src/System/Number.Formatting.Common.cs index 4caa59472eaea4..672ff2402682b9 100644 --- a/src/libraries/Common/src/System/Number.Formatting.Common.cs +++ b/src/libraries/Common/src/System/Number.Formatting.Common.cs @@ -12,6 +12,8 @@ namespace System { internal static partial class Number { + private const int CharStackBufferSize = 32; + private const int DefaultPrecisionExponentialFormat = 6; private const int MaxUInt32DecDigits = 10; diff --git a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems index 22a4ddea6ed606..b9f4be64bc9a74 100644 --- a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems +++ b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems @@ -133,6 +133,7 @@ + diff --git a/src/libraries/System.Private.CoreLib/src/System/Buffers/Text/FormattingHelpers.CountDigits.Int128.cs b/src/libraries/System.Private.CoreLib/src/System/Buffers/Text/FormattingHelpers.CountDigits.Int128.cs new file mode 100644 index 00000000000000..5264f100112eb7 --- /dev/null +++ b/src/libraries/System.Private.CoreLib/src/System/Buffers/Text/FormattingHelpers.CountDigits.Int128.cs @@ -0,0 +1,59 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Diagnostics; +using System.Runtime.CompilerServices; + +namespace System.Buffers.Text +{ + internal static partial class FormattingHelpers + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int CountDigits(UInt128 value) + { + ulong upper = value.Upper; + + // 1e19 is 8AC7_2304_89E8_0000 + // 1e20 is 5_6BC7_5E2D_6310_0000 + // 1e21 is 36_35C9_ADC5_DEA0_0000 + + if (upper == 0) + { + // We have less than 64-bits, so just return the lower count + return CountDigits(value.Lower); + } + + // We have more than 1e19, so we have at least 20 digits + int digits = 20; + + if (upper > 5) + { + // ((2^128) - 1) / 1e20 < 34_02_823_669_209_384_635 which + // is 18.5318 digits, meaning the result definitely fits + // into 64-bits and we only need to add the lower digit count + + value /= new UInt128(0x5, 0x6BC7_5E2D_6310_0000); // value /= 1e20 + Debug.Assert(value.Upper == 0); + + digits += CountDigits(value.Lower); + } + else if ((upper == 5) && (value.Lower >= 0x6BC75E2D63100000)) + { + // We're greater than 1e20, but definitely less than 1e21 + // so we have exactly 21 digits + + digits++; + Debug.Assert(digits == 21); + } + + return digits; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int CountHexDigits(UInt128 value) + { + // The number of hex digits is log16(value) + 1, or log2(value) / 4 + 1 + return ((int)UInt128.Log2(value) >> 2) + 1; + } + } +} diff --git a/src/libraries/System.Private.CoreLib/src/System/Buffers/Text/FormattingHelpers.CountDigits.cs b/src/libraries/System.Private.CoreLib/src/System/Buffers/Text/FormattingHelpers.CountDigits.cs index 3da8684132f077..18eac2cf08eb7e 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Buffers/Text/FormattingHelpers.CountDigits.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Buffers/Text/FormattingHelpers.CountDigits.cs @@ -1,7 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Buffers.Binary; using System.Diagnostics; using System.Numerics; using System.Runtime.CompilerServices; @@ -11,47 +10,6 @@ namespace System.Buffers.Text { internal static partial class FormattingHelpers { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int CountDigits(UInt128 value) - { - ulong upper = value.Upper; - - // 1e19 is 8AC7_2304_89E8_0000 - // 1e20 is 5_6BC7_5E2D_6310_0000 - // 1e21 is 36_35C9_ADC5_DEA0_0000 - - if (upper == 0) - { - // We have less than 64-bits, so just return the lower count - return CountDigits(value.Lower); - } - - // We have more than 1e19, so we have at least 20 digits - int digits = 20; - - if (upper > 5) - { - // ((2^128) - 1) / 1e20 < 34_02_823_669_209_384_635 which - // is 18.5318 digits, meaning the result definitely fits - // into 64-bits and we only need to add the lower digit count - - value /= new UInt128(0x5, 0x6BC7_5E2D_6310_0000); // value /= 1e20 - Debug.Assert(value.Upper == 0); - - digits += CountDigits(value.Lower); - } - else if ((upper == 5) && (value.Lower >= 0x6BC75E2D63100000)) - { - // We're greater than 1e20, but definitely less than 1e21 - // so we have exactly 21 digits - - digits++; - Debug.Assert(digits == 21); - } - - return digits; - } - // Based on do_count_digits from https://github.com/fmtlib/fmt/blob/662adf4f33346ba9aba8b072194e319869ede54a/include/fmt/format.h#L1124 [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int CountDigits(ulong value) @@ -149,13 +107,6 @@ public static int CountDigits(uint value) return (int)((value + tableValue) >> 32); } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int CountHexDigits(UInt128 value) - { - // The number of hex digits is log16(value) + 1, or log2(value) / 4 + 1 - return ((int)UInt128.Log2(value) >> 2) + 1; - } - [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int CountHexDigits(ulong value) { diff --git a/src/libraries/System.Private.CoreLib/src/System/Number.Formatting.cs b/src/libraries/System.Private.CoreLib/src/System/Number.Formatting.cs index ad75d88cbda7c1..2a89bf96385294 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Number.Formatting.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Number.Formatting.cs @@ -269,8 +269,6 @@ internal static partial class Number private const int SinglePrecisionCustomFormat = 7; private const int DoublePrecisionCustomFormat = 15; - private const int CharStackBufferSize = 32; - /// The non-inclusive upper bound of . /// /// This is a semi-arbitrary bound. For mono, which is often used for more size-constrained workloads, diff --git a/src/libraries/System.Runtime.Numerics/src/System.Runtime.Numerics.csproj b/src/libraries/System.Runtime.Numerics/src/System.Runtime.Numerics.csproj index d2003757c60f3d..6526656921c343 100644 --- a/src/libraries/System.Runtime.Numerics/src/System.Runtime.Numerics.csproj +++ b/src/libraries/System.Runtime.Numerics/src/System.Runtime.Numerics.csproj @@ -25,6 +25,8 @@ + fo return spanSuccess; } + private const uint kuBase = 1_000_000_000; // 10^9 + private const int kcchBase = 9; + private static unsafe string? FormatBigInteger( bool targetSpan, BigInteger value, string? formatString, ReadOnlySpan formatSpan, @@ -882,6 +886,7 @@ internal static bool TryFormatBigInteger(BigInteger value, ReadOnlySpan fo } else { + Debug.Assert(formatString != null); charsWritten = 0; spanSuccess = false; return value._sign.ToString(formatString, info); @@ -889,17 +894,17 @@ internal static bool TryFormatBigInteger(BigInteger value, ReadOnlySpan fo } // First convert to base 10^9. - const uint kuBase = 1000000000; // 10^9 - const int kcchBase = 9; - int cuSrc = value._bits.Length; - int cuMax; - try - { - cuMax = checked(cuSrc * 10 / 9 + 2); - } - catch (OverflowException e) { throw new FormatException(SR.Format_TooLarge, e); } - uint[] rguDst = new uint[cuMax]; + // A quick conservative max length of base 10^9 representation + // A uint contributes to no more than 10/9 of 10^9 block, +1 for ceiling of division + int cuMax = cuSrc * (kcchBase + 1) / kcchBase + 1; + Debug.Assert((long)BigInteger.MaxLength * (kcchBase + 1) / kcchBase + 1 < (long)int.MaxValue); // won't overflow + + uint[]? bufferToReturn = null; + Span base1E9Buffer = cuMax < BigIntegerCalculator.StackAllocThreshold ? + stackalloc uint[cuMax] : + (bufferToReturn = ArrayPool.Shared.Rent(cuMax)); + int cuDst = 0; for (int iuSrc = cuSrc; --iuSrc >= 0;) @@ -907,93 +912,86 @@ internal static bool TryFormatBigInteger(BigInteger value, ReadOnlySpan fo uint uCarry = value._bits[iuSrc]; for (int iuDst = 0; iuDst < cuDst; iuDst++) { - Debug.Assert(rguDst[iuDst] < kuBase); - ulong uuRes = NumericsHelpers.MakeUInt64(rguDst[iuDst], uCarry); - rguDst[iuDst] = (uint)(uuRes % kuBase); - uCarry = (uint)(uuRes / kuBase); + Debug.Assert(base1E9Buffer[iuDst] < kuBase); + + // Use X86Base.DivRem when stable + ulong uuRes = NumericsHelpers.MakeUInt64(base1E9Buffer[iuDst], uCarry); + (ulong quo, ulong rem) = Math.DivRem(uuRes, kuBase); + uCarry = (uint)quo; + base1E9Buffer[iuDst] = (uint)rem; } if (uCarry != 0) { - rguDst[cuDst++] = uCarry % kuBase; - uCarry /= kuBase; + (uCarry, base1E9Buffer[cuDst++]) = Math.DivRem(uCarry, kuBase); if (uCarry != 0) - rguDst[cuDst++] = uCarry; + base1E9Buffer[cuDst++] = uCarry; } } - int cchMax; - try - { - // Each uint contributes at most 9 digits to the decimal representation. - cchMax = checked(cuDst * kcchBase); - } - catch (OverflowException e) { throw new FormatException(SR.Format_TooLarge, e); } + ReadOnlySpan base1E9Value = base1E9Buffer[..cuDst]; + + int valueDigits = (base1E9Value.Length - 1) * kcchBase + FormattingHelpers.CountDigits(base1E9Value[^1]); + + string? strResult; - bool decimalFmt = (fmt == 'g' || fmt == 'G' || fmt == 'd' || fmt == 'D' || fmt == 'r' || fmt == 'R'); - if (decimalFmt) + if (fmt == 'g' || fmt == 'G' || fmt == 'd' || fmt == 'D' || fmt == 'r' || fmt == 'R') { - if (digits > 0 && digits > cchMax) - cchMax = digits; - if (value._sign < 0) + int strDigits = Math.Max(digits, valueDigits); + string? sNegative = value.Sign < 0 ? info.NegativeSign : null; + int strLength = strDigits + (sNegative?.Length ?? 0); + + if (targetSpan) { - try + if (destination.Length < strLength) + { + spanSuccess = false; + charsWritten = 0; + } + else { - // Leave an extra slot for a minus sign. - cchMax = checked(cchMax + info.NegativeSign.Length); + sNegative?.CopyTo(destination); + fixed (char* ptr = &MemoryMarshal.GetReference(destination)) + { + BigIntegerToDecChars((Utf16Char*)ptr + strLength, base1E9Value, digits); + } + charsWritten = strLength; + spanSuccess = true; } - catch (OverflowException e) { throw new FormatException(SR.Format_TooLarge, e); } + strResult = null; } - } - - int rgchBufSize; - - try - { - // We'll pass the rgch buffer to native code, which is going to treat it like a string of digits, so it needs - // to be null terminated. Let's ensure that we can allocate a buffer of that size. - rgchBufSize = checked(cchMax + 1); - } - catch (OverflowException e) { throw new FormatException(SR.Format_TooLarge, e); } - - char[] rgch = new char[rgchBufSize]; - - int ichDst = cchMax; - - for (int iuDst = 0; iuDst < cuDst - 1; iuDst++) - { - uint uDig = rguDst[iuDst]; - Debug.Assert(uDig < kuBase); - for (int cch = kcchBase; --cch >= 0;) + else { - rgch[--ichDst] = (char)('0' + uDig % 10); - uDig /= 10; + spanSuccess = false; + charsWritten = 0; + fixed (uint* ptr = base1E9Value) + { + strResult = string.Create(strLength, (digits, ptr: (IntPtr)ptr, base1E9Value.Length, sNegative), static (span, state) => + { + state.sNegative?.CopyTo(span); + fixed (char* ptr = &MemoryMarshal.GetReference(span)) + { + BigIntegerToDecChars((Utf16Char*)ptr + span.Length, new ReadOnlySpan((void*)state.ptr, state.Length), state.digits); + } + }); + } } } - for (uint uDig = rguDst[cuDst - 1]; uDig != 0;) - { - rgch[--ichDst] = (char)('0' + uDig % 10); - uDig /= 10; - } - - if (!decimalFmt) + else { - // sign = true for negative and false for 0 and positive values - bool sign = (value._sign < 0); - int scale = cchMax - ichDst; - - byte[]? buffer = ArrayPool.Shared.Rent(rgchBufSize + 1); - fixed (byte* ptr = buffer) // NumberBuffer expects pinned Digits + byte[]? numberBufferToReturn = null; + Span numberBuffer = valueDigits + 1 <= CharStackBufferSize ? + stackalloc byte[valueDigits + 1] : + (numberBufferToReturn = ArrayPool.Shared.Rent(valueDigits + 1)); + fixed (byte* ptr = numberBuffer) // NumberBuffer expects pinned Digits { - scoped NumberBuffer number = new NumberBuffer(NumberBufferKind.Integer, buffer); + scoped NumberBuffer number = new NumberBuffer(NumberBufferKind.Integer, ptr, valueDigits + 1); + BigIntegerToDecChars((Utf8Char*)ptr + valueDigits, base1E9Value, valueDigits); + number.Digits[^1] = 0; + number.DigitsCount = valueDigits; + number.Scale = valueDigits; + number.IsNegative = value.Sign < 0; - for (int i = 0; i < rgch.Length - ichDst; i++) - number.Digits[i] = (byte)rgch[ichDst + i]; - number.Digits[rgch.Length - ichDst] = 0; - number.DigitsCount = rgch.Length - ichDst - 1; // The cut-off point to switch (G)eneral from (F)ixed-point to (E)xponential form - number.Scale = scale; - number.IsNegative = sign; - - scoped var vlb = new ValueListBuilder(stackalloc Utf16Char[128]); // arbitrary stack cut-off + scoped var vlb = new ValueListBuilder(stackalloc Utf16Char[CharStackBufferSize]); // arbitrary stack cut-off if (fmt != 0) { @@ -1007,59 +1005,44 @@ internal static bool TryFormatBigInteger(BigInteger value, ReadOnlySpan fo if (targetSpan) { spanSuccess = vlb.TryCopyTo(MemoryMarshal.Cast(destination), out charsWritten); - vlb.Dispose(); - return null; + strResult = null; } else { charsWritten = 0; spanSuccess = false; - string result = MemoryMarshal.Cast(vlb.AsSpan()).ToString(); - vlb.Dispose(); - return result; + strResult = MemoryMarshal.Cast(vlb.AsSpan()).ToString(); + } + + vlb.Dispose(); + if (numberBufferToReturn != null) + { + ArrayPool.Shared.Return(numberBufferToReturn); } } } - // Format Round-trip decimal - // This format is supported for integral types only. The number is converted to a string of - // decimal digits (0-9), prefixed by a minus sign if the number is negative. The precision - // specifier indicates the minimum number of digits desired in the resulting string. If required, - // the number is padded with zeros to its left to produce the number of digits given by the - // precision specifier. - int numDigitsPrinted = cchMax - ichDst; - while (digits > 0 && digits > numDigitsPrinted) - { - // pad leading zeros - rgch[--ichDst] = '0'; - digits--; - } - if (value._sign < 0) + if (bufferToReturn != null) { - string negativeSign = info.NegativeSign; - for (int i = negativeSign.Length - 1; i > -1; i--) - rgch[--ichDst] = negativeSign[i]; + ArrayPool.Shared.Return(bufferToReturn); } - int resultLength = cchMax - ichDst; - if (!targetSpan) - { - charsWritten = 0; - spanSuccess = false; - return new string(rgch, ichDst, cchMax - ichDst); - } - else if (new ReadOnlySpan(rgch, ichDst, cchMax - ichDst).TryCopyTo(destination)) - { - charsWritten = resultLength; - spanSuccess = true; - return null; - } - else + return strResult; + } + + private static unsafe TChar* BigIntegerToDecChars(TChar* bufferEnd, ReadOnlySpan base1E9Value, int digits) + where TChar : unmanaged, IUtfChar + { + Debug.Assert(base1E9Value[^1] != 0, "Leading zeros should be trimmed by caller."); + + // The base 10^9 value is in reverse order + for (int i = 0; i < base1E9Value.Length - 1; i++) { - charsWritten = 0; - spanSuccess = false; - return null; + bufferEnd = UInt32ToDecChars(bufferEnd, base1E9Value[i], kcchBase); + digits -= kcchBase; } + + return UInt32ToDecChars(bufferEnd, base1E9Value[^1], digits); } } diff --git a/src/libraries/System.Runtime.Numerics/src/System/Number.Polyfill.cs b/src/libraries/System.Runtime.Numerics/src/System/Number.Polyfill.cs index d5de46b5842eb5..9c1c2a89daf5ef 100644 --- a/src/libraries/System.Runtime.Numerics/src/System/Number.Polyfill.cs +++ b/src/libraries/System.Runtime.Numerics/src/System/Number.Polyfill.cs @@ -43,6 +43,21 @@ internal readonly struct Utf16Char(char ch) : IUtfChar public bool Equals(Utf16Char other) => value == other.value; } +#pragma warning disable CA1067 // Polyfill only type + internal readonly struct Utf8Char(byte ch) : IUtfChar +#pragma warning restore CA1067 + { + private readonly byte value = ch; + + public static Utf8Char CastFrom(byte value) => new(value); + public static Utf8Char CastFrom(char value) => new((byte)value); + public static Utf8Char CastFrom(int value) => new((byte)value); + public static Utf8Char CastFrom(uint value) => new((byte)value); + public static Utf8Char CastFrom(ulong value) => new((byte)value); + public static uint CastToUInt32(Utf8Char value) => value.value; + public bool Equals(Utf8Char other) => value == other.value; + } + internal static partial class Number { internal static bool AllowHyphenDuringParsing(this NumberFormatInfo info) From 9bba3836ed4ddf2592ae9b92b3110dc6af03e453 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20K=C3=B6plinger?= Date: Mon, 22 Apr 2024 20:18:23 +0200 Subject: [PATCH 010/161] Disable AllItemsEnumeratedOnce_For test on s390x (#101389) It is currently hanging in CI: https://github.com/dotnet/runtime/issues/101380 --- .../tests/ParallelForEachAsyncTests.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libraries/System.Threading.Tasks.Parallel/tests/ParallelForEachAsyncTests.cs b/src/libraries/System.Threading.Tasks.Parallel/tests/ParallelForEachAsyncTests.cs index 77c16ddd72c928..01a4dd37908ee7 100644 --- a/src/libraries/System.Threading.Tasks.Parallel/tests/ParallelForEachAsyncTests.cs +++ b/src/libraries/System.Threading.Tasks.Parallel/tests/ParallelForEachAsyncTests.cs @@ -459,6 +459,7 @@ await Parallel.ForEachAsync(EnumerableRangeAsync(0, 0), (item, cancellationToken [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] [InlineData(false)] [InlineData(true)] + [ActiveIssue("https://github.com/dotnet/runtime/issues/101380", typeof(PlatformDetection), nameof(PlatformDetection.IsS390xProcess))] public async Task AllItemsEnumeratedOnce_For(bool yield) { await Test(yield); From c1f91610c53681c7069ae1c1502a88e2644f2543 Mon Sep 17 00:00:00 2001 From: Stephen Toub Date: Mon, 22 Apr 2024 15:01:47 -0400 Subject: [PATCH 011/161] Simplify ReadOnlySpan pointer ctor (#101362) --- .../System.Private.CoreLib/src/System/ReadOnlySpan.cs | 5 +++-- src/libraries/System.Private.CoreLib/src/System/Span.cs | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/libraries/System.Private.CoreLib/src/System/ReadOnlySpan.cs b/src/libraries/System.Private.CoreLib/src/System/ReadOnlySpan.cs index b182d42b66ecd9..e2c49c820d7738 100644 --- a/src/libraries/System.Private.CoreLib/src/System/ReadOnlySpan.cs +++ b/src/libraries/System.Private.CoreLib/src/System/ReadOnlySpan.cs @@ -10,7 +10,8 @@ using EditorBrowsableAttribute = System.ComponentModel.EditorBrowsableAttribute; using EditorBrowsableState = System.ComponentModel.EditorBrowsableState; -#pragma warning disable 0809 //warning CS0809: Obsolete member 'Span.Equals(object)' overrides non-obsolete member 'object.Equals(object)' +#pragma warning disable 0809 // Obsolete member 'Span.Equals(object)' overrides non-obsolete member 'object.Equals(object)' +#pragma warning disable 8500 // address / sizeof of managed types namespace System { @@ -107,7 +108,7 @@ public unsafe ReadOnlySpan(void* pointer, int length) if (length < 0) ThrowHelper.ThrowArgumentOutOfRangeException(); - _reference = ref Unsafe.As(ref *(byte*)pointer); + _reference = ref *(T*)pointer; _length = length; } diff --git a/src/libraries/System.Private.CoreLib/src/System/Span.cs b/src/libraries/System.Private.CoreLib/src/System/Span.cs index 38b94e872b0cb3..691b2eb558f35b 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Span.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Span.cs @@ -9,7 +9,7 @@ using EditorBrowsableAttribute = System.ComponentModel.EditorBrowsableAttribute; using EditorBrowsableState = System.ComponentModel.EditorBrowsableState; -#pragma warning disable 0809 //warning CS0809: Obsolete member 'Span.Equals(object)' overrides non-obsolete member 'object.Equals(object)' +#pragma warning disable 0809 // Obsolete member 'Span.Equals(object)' overrides non-obsolete member 'object.Equals(object)' #pragma warning disable 8500 // address / sizeof of managed types namespace System From 6578e695d95213ae977642fae84f9708a0787b77 Mon Sep 17 00:00:00 2001 From: Jeremy Koritzinsky Date: Mon, 22 Apr 2024 14:10:04 -0700 Subject: [PATCH 012/161] Download contents into a subfolder to preserve previous paths (#101391) --- eng/pipelines/official/jobs/prepare-signed-artifacts.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eng/pipelines/official/jobs/prepare-signed-artifacts.yml b/eng/pipelines/official/jobs/prepare-signed-artifacts.yml index f52d685e964ef7..eb25d311890a98 100644 --- a/eng/pipelines/official/jobs/prepare-signed-artifacts.yml +++ b/eng/pipelines/official/jobs/prepare-signed-artifacts.yml @@ -33,7 +33,7 @@ jobs: fetchDepth: 20 - input: pipelineArtifact artifactName: IntermediateArtifacts - targetPath: $(Build.SourcesDirectory)\artifacts\PackageDownload + targetPath: $(Build.SourcesDirectory)\artifacts\PackageDownload\IntermediateArtifacts outputs: - output: pipelineArtifact displayName: 'Publish BuildLogs' From a4337b780f9d13a02633bd44b9ae675feb2c87df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Strehovsk=C3=BD?= Date: Tue, 23 Apr 2024 06:14:35 +0900 Subject: [PATCH 013/161] Remove `IlcKeepManagedDebuggerSupport` (#101369) This was introduced in #82696, but on a second thought, we should be able to use the documented `DebuggerSupport` for this. We still don't want to full on default this to `false` for reasons described in the PR, but the explicit value of `true` can be the escape hatch. --- .../BuildIntegration/Microsoft.NETCore.Native.targets | 2 +- .../tests/System.Runtime.Tests/System.Runtime.Tests.csproj | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.targets b/src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.targets index ce4a3236f58e30..2c9a4e02aa496d 100644 --- a/src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.targets +++ b/src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.targets @@ -289,7 +289,7 @@ The .NET Foundation licenses this file to you under the MIT license. - + diff --git a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System.Runtime.Tests.csproj b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System.Runtime.Tests.csproj index 4bf5a231b12ed2..1e6b01ecf75b30 100644 --- a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System.Runtime.Tests.csproj +++ b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System.Runtime.Tests.csproj @@ -12,9 +12,7 @@ true - - true - + true false From f191f5f44ece8e8a7ea134ca6bb4fe4531f33a16 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Strehovsk=C3=BD?= Date: Tue, 23 Apr 2024 06:15:13 +0900 Subject: [PATCH 014/161] Skip DispatchProxy app test on native AOT (#101374) --- eng/testing/linker/trimmingTests.targets | 8 +++++++- .../System.Reflection.DispatchProxy.TrimmingTests.proj | 7 +++++++ src/libraries/tests.proj | 1 - 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/eng/testing/linker/trimmingTests.targets b/eng/testing/linker/trimmingTests.targets index 9ff325e82972c0..d474e19b69accd 100644 --- a/eng/testing/linker/trimmingTests.targets +++ b/eng/testing/linker/trimmingTests.targets @@ -38,7 +38,13 @@ - + <_SkippedAppSourceFiles Include="@(TestConsoleAppSourceFiles)" Condition="$([System.String]::Copy('%(TestConsoleAppSourceFiles.SkipOnTestRuntimes)').Contains('$(PackageRID)'))" /> + + <_SkippedAppSourceFiles Include="@(TestConsoleAppSourceFiles)" Condition="'$(RunNativeAotTestApps)' == 'true' and '%(TestConsoleAppSourceFiles.NativeAotIncompatible)' == 'true'" /> + + <_AppSourceFiles Include="@(TestConsoleAppSourceFiles)" Exclude="@(_SkippedAppSourceFiles)" /> + + %(FullPath) diff --git a/src/libraries/System.Reflection.DispatchProxy/tests/TrimmingTests/System.Reflection.DispatchProxy.TrimmingTests.proj b/src/libraries/System.Reflection.DispatchProxy/tests/TrimmingTests/System.Reflection.DispatchProxy.TrimmingTests.proj index da4a46f2ae141a..adb54eab7335a0 100644 --- a/src/libraries/System.Reflection.DispatchProxy/tests/TrimmingTests/System.Reflection.DispatchProxy.TrimmingTests.proj +++ b/src/libraries/System.Reflection.DispatchProxy/tests/TrimmingTests/System.Reflection.DispatchProxy.TrimmingTests.proj @@ -1,5 +1,12 @@ + + + + true + + + diff --git a/src/libraries/tests.proj b/src/libraries/tests.proj index f89150c3e25d60..75eeb492b87c2d 100644 --- a/src/libraries/tests.proj +++ b/src/libraries/tests.proj @@ -652,7 +652,6 @@ - From f8903fe264818a77eb32097fab0b444ce426d5ed Mon Sep 17 00:00:00 2001 From: Jackson Schuster <36744439+jtschuster@users.noreply.github.com> Date: Mon, 22 Apr 2024 14:32:36 -0700 Subject: [PATCH 015/161] Only add interface methods to _virtual_methods cache (#101139) We only ever do operations on interface methods, so we can only keep interface methods rather than all virtual methods --- .../src/linker/Linker.Steps/MarkStep.cs | 56 ++++++++++--------- 1 file changed, 30 insertions(+), 26 deletions(-) diff --git a/src/tools/illink/src/linker/Linker.Steps/MarkStep.cs b/src/tools/illink/src/linker/Linker.Steps/MarkStep.cs index 876ca9da73122b..f26a176c304120 100644 --- a/src/tools/illink/src/linker/Linker.Steps/MarkStep.cs +++ b/src/tools/illink/src/linker/Linker.Steps/MarkStep.cs @@ -60,7 +60,7 @@ protected LinkContext Context { } protected Queue<(MethodDefinition, DependencyInfo, MessageOrigin)> _methods; - protected Dictionary _virtual_methods; + protected Dictionary _interface_methods; protected Queue _assemblyLevelAttributes; protected Queue<(AttributeProviderPair, DependencyInfo, MarkScopeStack.Scope)> _lateMarkedAttributes; protected List<(TypeDefinition, MarkScopeStack.Scope)> _typesWithInterfaces; @@ -219,7 +219,7 @@ internal DynamicallyAccessedMembersTypeHierarchy DynamicallyAccessedMembersTypeH public MarkStep () { _methods = new Queue<(MethodDefinition, DependencyInfo, MessageOrigin)> (); - _virtual_methods = new Dictionary (); + _interface_methods = new Dictionary (); _assemblyLevelAttributes = new Queue (); _lateMarkedAttributes = new Queue<(AttributeProviderPair, DependencyInfo, MarkScopeStack.Scope)> (); _typesWithInterfaces = new List<(TypeDefinition, MarkScopeStack.Scope)> (); @@ -437,7 +437,7 @@ bool ProcessPrimaryQueue () while (!QueueIsEmpty ()) { ProcessQueue (); - ProcessVirtualMethods (); + ProcessInterfaceMethods (); ProcessMarkedTypesWithInterfaces (); ProcessDynamicCastableImplementationInterfaces (); ProcessPendingBodies (); @@ -530,11 +530,11 @@ protected virtual void EnqueueMethod (MethodDefinition method, in DependencyInfo _methods.Enqueue ((method, reason, origin)); } - void ProcessVirtualMethods () + void ProcessInterfaceMethods () { - foreach ((var method, var scope) in _virtual_methods) { + foreach ((var method, var scope) in _interface_methods) { using (ScopeStack.PushLocalScope (scope)) { - ProcessVirtualMethod (method); + ProcessInterfaceMethod (method); } } } @@ -568,7 +568,7 @@ void ProcessMarkedTypesWithInterfaces () continue; foreach (var ov in baseMethods) { if (ov.Base.DeclaringType is not null && ov.Base.DeclaringType.IsInterface && IgnoreScope (ov.Base.DeclaringType.Scope)) { - _virtual_methods.TryAdd (ov.Base, ScopeStack.CurrentScope); + MarkMethodAsVirtual (ov.Base, ScopeStack.CurrentScope); } } } @@ -651,28 +651,32 @@ void ProcessPendingBodies () } } } - - void ProcessVirtualMethod (MethodDefinition method) + void MarkMethodAsVirtual (MethodDefinition method, MarkScopeStack.Scope scope) { Annotations.EnqueueVirtualMethod (method); - if (method.DeclaringType.IsInterface) { - var defaultImplementations = Annotations.GetDefaultInterfaceImplementations (method); - if (defaultImplementations is not null) { - foreach (var dimInfo in defaultImplementations) { - ProcessDefaultImplementation (dimInfo); + _interface_methods.TryAdd (method, scope); + } + } - if (IsInterfaceImplementationMethodNeededByTypeDueToInterface (dimInfo)) - MarkMethod (dimInfo.Override, new DependencyInfo (DependencyKind.Override, dimInfo.Base), ScopeStack.CurrentScope.Origin); - } + void ProcessInterfaceMethod (MethodDefinition method) + { + Debug.Assert (method.DeclaringType.IsInterface); + var defaultImplementations = Annotations.GetDefaultInterfaceImplementations (method); + if (defaultImplementations is not null) { + foreach (var dimInfo in defaultImplementations) { + ProcessDefaultImplementation (dimInfo); + + if (IsInterfaceImplementationMethodNeededByTypeDueToInterface (dimInfo)) + MarkMethod (dimInfo.Override, new DependencyInfo (DependencyKind.Override, dimInfo.Base), ScopeStack.CurrentScope.Origin); } - List? overridingMethods = (List?)Annotations.GetOverrides (method); - if (overridingMethods is not null) { - for (int i = 0; i < overridingMethods.Count; i++) { - OverrideInformation ov = overridingMethods[i]; - if (IsInterfaceImplementationMethodNeededByTypeDueToInterface (ov)) - MarkMethod (ov.Override, new DependencyInfo (DependencyKind.Override, ov.Base), ScopeStack.CurrentScope.Origin); - } + } + List? overridingMethods = (List?)Annotations.GetOverrides (method); + if (overridingMethods is not null) { + for (int i = 0; i < overridingMethods.Count; i++) { + OverrideInformation ov = overridingMethods[i]; + if (IsInterfaceImplementationMethodNeededByTypeDueToInterface (ov)) + MarkMethod (ov.Override, new DependencyInfo (DependencyKind.Override, ov.Base), ScopeStack.CurrentScope.Origin); } } } @@ -3227,7 +3231,7 @@ protected virtual void ProcessMethod (MethodDefinition method, in DependencyInfo MarkMethodSpecialCustomAttributes (method); if (method.IsVirtual) - _virtual_methods.TryAdd (method, ScopeStack.CurrentScope); + MarkMethodAsVirtual (method, ScopeStack.CurrentScope); MarkNewCodeDependencies (method); @@ -3435,7 +3439,7 @@ void MarkBaseMethods (MethodDefinition method) // This will produce warnings for all interface methods and virtual methods regardless of whether the interface, interface implementation, or interface method is kept or not. if (ov.Base.DeclaringType.IsInterface && !method.DeclaringType.IsInterface) { // These are all virtual, no need to check IsVirtual before adding to list - _virtual_methods.TryAdd (ov.Base, ScopeStack.CurrentScope); + MarkMethodAsVirtual (ov.Base, ScopeStack.CurrentScope); continue; } From aa9edcc5c8b37e41554779c299cf52c17297723d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Strehovsk=C3=BD?= Date: Tue, 23 Apr 2024 06:33:23 +0900 Subject: [PATCH 016/161] Fix S.D.Tracing testapps with AOT (#101373) I believe what the test is doing is not trim safe and only succeeds due to lucky IL trimming implementation details. --- .../tests/TrimmingTests/EventSourcePropertyValueTest.cs | 2 ++ src/libraries/tests.proj | 1 - 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/libraries/System.Diagnostics.Tracing/tests/TrimmingTests/EventSourcePropertyValueTest.cs b/src/libraries/System.Diagnostics.Tracing/tests/TrimmingTests/EventSourcePropertyValueTest.cs index 6682cb0fd45eb8..e98a84a45ae888 100644 --- a/src/libraries/System.Diagnostics.Tracing/tests/TrimmingTests/EventSourcePropertyValueTest.cs +++ b/src/libraries/System.Diagnostics.Tracing/tests/TrimmingTests/EventSourcePropertyValueTest.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Collections.ObjectModel; +using System.Diagnostics.CodeAnalysis; using System.Diagnostics.Tracing; /// @@ -34,6 +35,7 @@ private class TestEventSource : EventSource public TestEventSource() : base(EventSourceSettings.EtwSelfDescribingEventFormat) { } [Event(1)] + [DynamicDependency(DynamicallyAccessedMemberTypes.PublicProperties, typeof(TestSubData))] public void LogData(TestData data) { Write("LogData", data); diff --git a/src/libraries/tests.proj b/src/libraries/tests.proj index 75eeb492b87c2d..5d1b0a0c7fb4fe 100644 --- a/src/libraries/tests.proj +++ b/src/libraries/tests.proj @@ -648,7 +648,6 @@ Condition="'$(TestPackages)' == 'true'" /> - From e751fe855a4788a1e133b88f6972891d87256c41 Mon Sep 17 00:00:00 2001 From: Elinor Fung Date: Mon, 22 Apr 2024 14:57:14 -0700 Subject: [PATCH 017/161] [cdac] Read contract descriptor from target (#101208) - Get `DotNetRuntimeContractDescriptor` address from the target - Read contract descriptor to determine endianness and pointer size - Parse JSON descriptor and store contracts --- src/coreclr/debug/daccess/cdac.cpp | 20 +- src/coreclr/debug/daccess/cdac.h | 7 +- src/coreclr/debug/daccess/daccess.cpp | 10 +- .../src/ContractDescriptorParser.cs | 21 +- .../managed/cdacreader/src/Entrypoints.cs | 5 +- src/native/managed/cdacreader/src/Root.cs | 12 + src/native/managed/cdacreader/src/Target.cs | 208 ++++++++++++++++-- .../managed/cdacreader/src/cdacreader.csproj | 1 + .../tests/ContractDescriptorParserTests.cs | 2 + ...iagnostics.DataContractReader.Tests.csproj | 1 + 10 files changed, 241 insertions(+), 46 deletions(-) create mode 100644 src/native/managed/cdacreader/src/Root.cs diff --git a/src/coreclr/debug/daccess/cdac.cpp b/src/coreclr/debug/daccess/cdac.cpp index 23478592371a16..a4146709ec7233 100644 --- a/src/coreclr/debug/daccess/cdac.cpp +++ b/src/coreclr/debug/daccess/cdac.cpp @@ -28,8 +28,12 @@ namespace int ReadFromTargetCallback(uint64_t addr, uint8_t* dest, uint32_t count, void* context) { - CDAC* cdac = reinterpret_cast(context); - return cdac->ReadFromTarget(addr, dest, count); + ICorDebugDataTarget* target = reinterpret_cast(context); + HRESULT hr = ReadFromDataTarget(target, addr, dest, count); + if (FAILED(hr)) + return hr; + + return S_OK; } } @@ -52,11 +56,12 @@ CDAC::CDAC(HMODULE module, uint64_t descriptorAddr, ICorDebugDataTarget* target) return; } + m_target->AddRef(); decltype(&cdac_reader_init) init = reinterpret_cast(::GetProcAddress(m_module, "cdac_reader_init")); decltype(&cdac_reader_get_sos_interface) getSosInterface = reinterpret_cast(::GetProcAddress(m_module, "cdac_reader_get_sos_interface")); _ASSERTE(init != nullptr && getSosInterface != nullptr); - init(descriptorAddr, &ReadFromTargetCallback, this, &m_cdac_handle); + init(descriptorAddr, &ReadFromTargetCallback, m_target, &m_cdac_handle); getSosInterface(m_cdac_handle, &m_sos); } @@ -77,12 +82,3 @@ IUnknown* CDAC::SosInterface() { return m_sos; } - -int CDAC::ReadFromTarget(uint64_t addr, uint8_t* dest, uint32_t count) -{ - HRESULT hr = ReadFromDataTarget(m_target, addr, dest, count); - if (FAILED(hr)) - return hr; - - return S_OK; -} diff --git a/src/coreclr/debug/daccess/cdac.h b/src/coreclr/debug/daccess/cdac.h index 54418dc549f1f0..d5c0eecb0f7373 100644 --- a/src/coreclr/debug/daccess/cdac.h +++ b/src/coreclr/debug/daccess/cdac.h @@ -21,7 +21,7 @@ class CDAC final CDAC(CDAC&& other) : m_module{ other.m_module } , m_cdac_handle{ other.m_cdac_handle } - , m_target{ other.m_target } + , m_target{ other.m_target.Extract() } , m_sos{ other.m_sos.Extract() } { other.m_module = NULL; @@ -34,7 +34,7 @@ class CDAC final { m_module = other.m_module; m_cdac_handle = other.m_cdac_handle; - m_target = other.m_target; + m_target = other.m_target.Extract(); m_sos = other.m_sos.Extract(); other.m_module = NULL; @@ -54,7 +54,6 @@ class CDAC final // This does not AddRef the returned interface IUnknown* SosInterface(); - int ReadFromTarget(uint64_t addr, uint8_t* dest, uint32_t count); private: CDAC(HMODULE module, uint64_t descriptorAddr, ICorDebugDataTarget* target); @@ -62,7 +61,7 @@ class CDAC final private: HMODULE m_module; intptr_t m_cdac_handle; - ICorDebugDataTarget* m_target; + NonVMComHolder m_target; NonVMComHolder m_sos; }; diff --git a/src/coreclr/debug/daccess/daccess.cpp b/src/coreclr/debug/daccess/daccess.cpp index 2f08750bc5c61b..971b8b90980b32 100644 --- a/src/coreclr/debug/daccess/daccess.cpp +++ b/src/coreclr/debug/daccess/daccess.cpp @@ -30,6 +30,8 @@ #include #else extern "C" bool TryGetSymbol(ICorDebugDataTarget* dataTarget, uint64_t baseAddress, const char* symbolName, uint64_t* symbolAddress); +// cDAC depends on symbol lookup to find the contract descriptor +#define CAN_USE_CDAC #endif #include "dwbucketmanager.hpp" @@ -5493,15 +5495,16 @@ ClrDataAccess::Initialize(void) IfFailRet(GetDacGlobalValues()); IfFailRet(DacGetHostVtPtrs()); +// TODO: [cdac] TryGetSymbol is only implemented for Linux, OSX, and Windows. +#ifdef CAN_USE_CDAC CLRConfigNoCache enable = CLRConfigNoCache::Get("ENABLE_CDAC"); if (enable.IsSet()) { DWORD val; if (enable.TryAsInteger(10, val) && val == 1) { - // TODO: [cdac] Get contract descriptor from exported symbol uint64_t contractDescriptorAddr = 0; - //if (TryGetSymbol(m_pTarget, m_globalBase, "DotNetRuntimeContractDescriptor", &contractDescriptorAddr)) + if (TryGetSymbol(m_pTarget, m_globalBase, "DotNetRuntimeContractDescriptor", &contractDescriptorAddr)) { m_cdac = CDAC::Create(contractDescriptorAddr, m_pTarget); if (m_cdac.IsValid()) @@ -5514,6 +5517,7 @@ ClrDataAccess::Initialize(void) } } } +#endif // // DAC is now setup and ready to use @@ -6946,7 +6950,7 @@ GetDacTableAddress(ICorDebugDataTarget* dataTarget, ULONG64 baseAddress, PULONG6 return E_INVALIDARG; } #endif - // On MacOS, FreeBSD or NetBSD use the RVA include file + // On FreeBSD, NetBSD, or SunOS use the RVA include file *dacTableAddress = baseAddress + DAC_TABLE_RVA; #else // Otherwise, try to get the dac table address via the export symbol diff --git a/src/native/managed/cdacreader/src/ContractDescriptorParser.cs b/src/native/managed/cdacreader/src/ContractDescriptorParser.cs index fbf76cd4e8d439..a82235731e4a07 100644 --- a/src/native/managed/cdacreader/src/ContractDescriptorParser.cs +++ b/src/native/managed/cdacreader/src/ContractDescriptorParser.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.Diagnostics.Contracts; using System.Text.Json; using System.Text.Json.Serialization; @@ -23,13 +24,15 @@ public partial class ContractDescriptorParser /// /// Parses the "compact" representation of a contract descriptor. /// + // Workaround for https://github.com/dotnet/runtime/issues/101205 + [DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(Root))] public static ContractDescriptor? ParseCompact(ReadOnlySpan json) { return JsonSerializer.Deserialize(json, ContractDescriptorContext.Default.ContractDescriptor); } [JsonSerializable(typeof(ContractDescriptor))] - [JsonSerializable(typeof(int))] + [JsonSerializable(typeof(int?))] [JsonSerializable(typeof(string))] [JsonSerializable(typeof(Dictionary))] [JsonSerializable(typeof(Dictionary))] @@ -38,11 +41,17 @@ public partial class ContractDescriptorParser [JsonSerializable(typeof(TypeDescriptor))] [JsonSerializable(typeof(FieldDescriptor))] [JsonSerializable(typeof(GlobalDescriptor))] + [JsonSerializable(typeof(Dictionary))] [JsonSourceGenerationOptions(AllowTrailingCommas = true, DictionaryKeyPolicy = JsonKnownNamingPolicy.Unspecified, // contracts, types and globals are case sensitive PropertyNamingPolicy = JsonKnownNamingPolicy.CamelCase, NumberHandling = JsonNumberHandling.AllowReadingFromString, - ReadCommentHandling = JsonCommentHandling.Skip)] + ReadCommentHandling = JsonCommentHandling.Skip, + UnmappedMemberHandling = JsonUnmappedMemberHandling.Skip, + UnknownTypeHandling = JsonUnknownTypeHandling.JsonElement, + Converters = [typeof(TypeDescriptorConverter), + typeof(FieldDescriptorConverter), + typeof(GlobalDescriptorConverter)])] internal sealed partial class ContractDescriptorContext : JsonSerializerContext { } @@ -58,7 +67,13 @@ public class ContractDescriptor public Dictionary? Globals { get; set; } [JsonExtensionData] - public Dictionary? Extras { get; set; } + public Dictionary? Extras { get; set; } + + public override string ToString() + { + return $"Version: {Version}, Baseline: {Baseline}, Contracts: {Contracts?.Count}, Types: {Types?.Count}, Globals: {Globals?.Count}"; + } + } [JsonConverter(typeof(TypeDescriptorConverter))] diff --git a/src/native/managed/cdacreader/src/Entrypoints.cs b/src/native/managed/cdacreader/src/Entrypoints.cs index 30cab9ec851887..908d534fe60c4e 100644 --- a/src/native/managed/cdacreader/src/Entrypoints.cs +++ b/src/native/managed/cdacreader/src/Entrypoints.cs @@ -14,7 +14,10 @@ internal static class Entrypoints [UnmanagedCallersOnly(EntryPoint = $"{CDAC}init")] private static unsafe int Init(ulong descriptor, delegate* unmanaged readFromTarget, void* readContext, IntPtr* handle) { - Target target = new(descriptor, readFromTarget, readContext); + // TODO: [cdac] Better error code/details + if (!Target.TryCreate(descriptor, readFromTarget, readContext, out Target? target)) + return -1; + GCHandle gcHandle = GCHandle.Alloc(target); *handle = GCHandle.ToIntPtr(gcHandle); return 0; diff --git a/src/native/managed/cdacreader/src/Root.cs b/src/native/managed/cdacreader/src/Root.cs new file mode 100644 index 00000000000000..05aefea3dea2a5 --- /dev/null +++ b/src/native/managed/cdacreader/src/Root.cs @@ -0,0 +1,12 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Text.Json.Serialization; + +namespace Microsoft.Diagnostics.DataContractReader; + +internal static class Root +{ + // https://github.com/dotnet/runtime/issues/101205 + public static JsonDerivedTypeAttribute[] R1 = new JsonDerivedTypeAttribute[] { null! }; +} diff --git a/src/native/managed/cdacreader/src/Target.cs b/src/native/managed/cdacreader/src/Target.cs index 898cab774bfb56..049a9f80ed2265 100644 --- a/src/native/managed/cdacreader/src/Target.cs +++ b/src/native/managed/cdacreader/src/Target.cs @@ -3,6 +3,7 @@ using System; using System.Buffers.Binary; +using System.Collections.Generic; namespace Microsoft.Diagnostics.DataContractReader; @@ -16,49 +17,210 @@ public struct TargetPointer internal sealed unsafe class Target { - private readonly delegate* unmanaged _readFromTarget; - private readonly void* _readContext; + private const int StackAllocByteThreshold = 1024; - private bool _isLittleEndian; - private int _pointerSize; + private readonly struct Configuration + { + public bool IsLittleEndian { get; init; } + public int PointerSize { get; init; } + } + + private readonly Configuration _config; + private readonly Reader _reader; + + private readonly IReadOnlyDictionary _contracts = new Dictionary(); + private readonly TargetPointer[] _pointerData = []; + + public static bool TryCreate(ulong contractDescriptor, delegate* unmanaged readFromTarget, void* readContext, out Target? target) + { + Reader reader = new Reader(readFromTarget, readContext); + if (TryReadContractDescriptor(contractDescriptor, reader, out Configuration config, out ContractDescriptorParser.ContractDescriptor? descriptor, out TargetPointer[] pointerData)) + { + target = new Target(config, descriptor!, pointerData, reader); + return true; + } + + target = null; + return false; + } - public Target(ulong _, delegate* unmanaged readFromTarget, void* readContext) + private Target(Configuration config, ContractDescriptorParser.ContractDescriptor descriptor, TargetPointer[] pointerData, Reader reader) { - _readFromTarget = readFromTarget; - _readContext = readContext; + _config = config; + _reader = reader; + + // TODO: [cdac] Read globals and types + // note: we will probably want to store the globals and types into a more usable form + _contracts = descriptor.Contracts ?? []; - // TODO: [cdac] Populate from descriptor - _isLittleEndian = BitConverter.IsLittleEndian; - _pointerSize = IntPtr.Size; + _pointerData = pointerData; + } + + // See docs/design/datacontracts/contract-descriptor.md + private static bool TryReadContractDescriptor( + ulong address, + Reader reader, + out Configuration config, + out ContractDescriptorParser.ContractDescriptor? descriptor, + out TargetPointer[] pointerData) + { + config = default; + descriptor = null; + pointerData = []; + + // Magic - uint64_t + Span buffer = stackalloc byte[sizeof(ulong)]; + if (reader.ReadFromTarget(address, buffer) < 0) + return false; + + address += sizeof(ulong); + ReadOnlySpan magicLE = "DNCCDAC\0"u8; + ReadOnlySpan magicBE = "\0CADCCND"u8; + bool isLittleEndian = buffer.SequenceEqual(magicLE); + if (!isLittleEndian && !buffer.SequenceEqual(magicBE)) + return false; + + // Flags - uint32_t + if (!TryReadUInt32(address, isLittleEndian, reader, out uint flags)) + return false; + + address += sizeof(uint); + + // Bit 1 represents the pointer size. 0 = 64-bit, 1 = 32-bit. + int pointerSize = (int)(flags & 0x2) == 0 ? sizeof(ulong) : sizeof(uint); + + config = new Configuration { IsLittleEndian = isLittleEndian, PointerSize = pointerSize }; + + // Descriptor size - uint32_t + if (!TryReadUInt32(address, config.IsLittleEndian, reader, out uint descriptorSize)) + return false; + + address += sizeof(uint); + + // Descriptor - char* + if (!TryReadPointer(address, config, reader, out TargetPointer descriptorAddr)) + return false; + + address += (uint)pointerSize; + + // Pointer data count - uint32_t + if (!TryReadUInt32(address, config.IsLittleEndian, reader, out uint pointerDataCount)) + return false; + + address += sizeof(uint); + + // Padding - uint32_t + address += sizeof(uint); + + // Pointer data - uintptr_t* + if (!TryReadPointer(address, config, reader, out TargetPointer pointerDataAddr)) + return false; + + // Read descriptor + Span descriptorBuffer = descriptorSize <= StackAllocByteThreshold + ? stackalloc byte[(int)descriptorSize] + : new byte[(int)descriptorSize]; + if (reader.ReadFromTarget(descriptorAddr.Value, descriptorBuffer) < 0) + return false; + + descriptor = ContractDescriptorParser.ParseCompact(descriptorBuffer); + if (descriptor is null) + return false; + + // Read pointer data + pointerData = new TargetPointer[pointerDataCount]; + for (int i = 0; i < pointerDataCount; i++) + { + if (!TryReadPointer(pointerDataAddr.Value + (uint)(i * pointerSize), config, reader, out pointerData[i])) + return false; + } + + return true; + } + + public uint ReadUInt32(ulong address) + { + if (!TryReadUInt32(address, out uint value)) + throw new InvalidOperationException($"Failed to read uint32 at 0x{address:x8}."); + + return value; + } + + public bool TryReadUInt32(ulong address, out uint value) + => TryReadUInt32(address, _config.IsLittleEndian, _reader, out value); + + private static bool TryReadUInt32(ulong address, bool isLittleEndian, Reader reader, out uint value) + { + value = 0; + + Span buffer = stackalloc byte[sizeof(uint)]; + if (reader.ReadFromTarget(address, buffer) < 0) + return false; + + value = isLittleEndian + ? BinaryPrimitives.ReadUInt32LittleEndian(buffer) + : BinaryPrimitives.ReadUInt32BigEndian(buffer); + + return true; + } + + public TargetPointer ReadPointer(ulong address) + { + if (!TryReadPointer(address, out TargetPointer pointer)) + throw new InvalidOperationException($"Failed to read pointer at 0x{address:x8}."); + + return pointer; } public bool TryReadPointer(ulong address, out TargetPointer pointer) + => TryReadPointer(address, _config, _reader, out pointer); + + private static bool TryReadPointer(ulong address, Configuration config, Reader reader, out TargetPointer pointer) { pointer = TargetPointer.Null; - byte* buffer = stackalloc byte[_pointerSize]; - ReadOnlySpan span = new ReadOnlySpan(buffer, _pointerSize); - if (ReadFromTarget(address, buffer, (uint)_pointerSize) < 0) + Span buffer = stackalloc byte[config.PointerSize]; + if (reader.ReadFromTarget(address, buffer) < 0) return false; - if (_pointerSize == sizeof(uint)) + if (config.PointerSize == sizeof(uint)) { pointer = new TargetPointer( - _isLittleEndian - ? BinaryPrimitives.ReadUInt32LittleEndian(span) - : BinaryPrimitives.ReadUInt32BigEndian(span)); + config.IsLittleEndian + ? BinaryPrimitives.ReadUInt32LittleEndian(buffer) + : BinaryPrimitives.ReadUInt32BigEndian(buffer)); } - else if (_pointerSize == sizeof(ulong)) + else if (config.PointerSize == sizeof(ulong)) { pointer = new TargetPointer( - _isLittleEndian - ? BinaryPrimitives.ReadUInt64LittleEndian(span) - : BinaryPrimitives.ReadUInt64BigEndian(span)); + config.IsLittleEndian + ? BinaryPrimitives.ReadUInt64LittleEndian(buffer) + : BinaryPrimitives.ReadUInt64BigEndian(buffer)); } return true; } - private int ReadFromTarget(ulong address, byte* buffer, uint bytesToRead) - => _readFromTarget(address, buffer, bytesToRead, _readContext); + private sealed class Reader + { + private readonly delegate* unmanaged _readFromTarget; + private readonly void* _context; + + public Reader(delegate* unmanaged readFromTarget, void* context) + { + _readFromTarget = readFromTarget; + _context = context; + } + + public int ReadFromTarget(ulong address, Span buffer) + { + fixed (byte* bufferPtr = buffer) + { + return _readFromTarget(address, bufferPtr, (uint)buffer.Length, _context); + } + } + + public int ReadFromTarget(ulong address, byte* buffer, uint bytesToRead) + => _readFromTarget(address, buffer, bytesToRead, _context); + } } diff --git a/src/native/managed/cdacreader/src/cdacreader.csproj b/src/native/managed/cdacreader/src/cdacreader.csproj index 253bb3c6c27e01..20ecd197c70460 100644 --- a/src/native/managed/cdacreader/src/cdacreader.csproj +++ b/src/native/managed/cdacreader/src/cdacreader.csproj @@ -9,6 +9,7 @@ false true + false diff --git a/src/native/managed/cdacreader/tests/ContractDescriptorParserTests.cs b/src/native/managed/cdacreader/tests/ContractDescriptorParserTests.cs index eca740870727bb..6f93b1225670e4 100644 --- a/src/native/managed/cdacreader/tests/ContractDescriptorParserTests.cs +++ b/src/native/managed/cdacreader/tests/ContractDescriptorParserTests.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; +using System.Text.Json; using System.Text.Unicode; using Xunit; @@ -12,6 +13,7 @@ public class ContractDescriptorParserTests [Fact] public void ParsesEmptyContract() { + Assert.False(JsonSerializer.IsReflectionEnabledByDefault); ReadOnlySpan json = "{}"u8; ContractDescriptorParser.ContractDescriptor descriptor = ContractDescriptorParser.ParseCompact(json); Assert.Null(descriptor.Version); diff --git a/src/native/managed/cdacreader/tests/Microsoft.Diagnostics.DataContractReader.Tests.csproj b/src/native/managed/cdacreader/tests/Microsoft.Diagnostics.DataContractReader.Tests.csproj index 22e8d256e01df1..c12c45e6f1fe84 100644 --- a/src/native/managed/cdacreader/tests/Microsoft.Diagnostics.DataContractReader.Tests.csproj +++ b/src/native/managed/cdacreader/tests/Microsoft.Diagnostics.DataContractReader.Tests.csproj @@ -2,6 +2,7 @@ true $(NetCoreAppToolCurrent) + false From 6444f51b67324c4d86c7aa8c48385c8902767479 Mon Sep 17 00:00:00 2001 From: yowl Date: Mon, 22 Apr 2024 17:02:57 -0500 Subject: [PATCH 018/161] set generic ctx type to void* for non-x86 path also - fixes LLVM/Wasm type mismatch (#101394) --- .../Compiler/CompilerTypeSystemContext.InterfaceThunks.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/CompilerTypeSystemContext.InterfaceThunks.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/CompilerTypeSystemContext.InterfaceThunks.cs index 92a5be3fed38c4..51bf6a6888e2ff 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/CompilerTypeSystemContext.InterfaceThunks.cs +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/CompilerTypeSystemContext.InterfaceThunks.cs @@ -313,7 +313,7 @@ public override MethodSignature Signature } else { - parameters[0] = Context.GetWellKnownType(WellKnownType.IntPtr); + parameters[0] = Context.GetWellKnownType(WellKnownType.Void).MakePointerType(); for (int i = 0; i < _methodRepresented.Signature.Length; i++) parameters[i + 1] = _methodRepresented.Signature[i]; } From 7bb7e74d6b1f22e69654f038b06d7688a6ac45de Mon Sep 17 00:00:00 2001 From: Brennan Date: Mon, 22 Apr 2024 15:25:49 -0700 Subject: [PATCH 019/161] Fix queue count in rate limiters (#90810) (#97041) --- .../RateLimiting/ConcurrencyLimiter.cs | 40 ++++++++++++++++--- .../RateLimiting/FixedWindowRateLimiter.cs | 39 +++++++++++++++--- .../RateLimiting/SlidingWindowRateLimiter.cs | 39 +++++++++++++++--- .../RateLimiting/TokenBucketRateLimiter.cs | 40 ++++++++++++++++--- 4 files changed, 136 insertions(+), 22 deletions(-) diff --git a/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/ConcurrencyLimiter.cs b/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/ConcurrencyLimiter.cs index 6b5a4014990ef0..7131b4fe1d7999 100644 --- a/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/ConcurrencyLimiter.cs +++ b/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/ConcurrencyLimiter.cs @@ -156,8 +156,17 @@ protected override ValueTask AcquireAsyncCore(int permitCount, C Debug.Assert(_queueCount >= 0); if (!oldestRequest.TrySetResult(FailedLease)) { - // Updating queue count is handled by the cancellation code - _queueCount += oldestRequest.Count; + if (!oldestRequest.QueueCountModified) + { + // We already updated the queue count, the Cancel code is about to run or running and waiting on our lock, + // tell Cancel not to do anything + oldestRequest.QueueCountModified = true; + } + else + { + // Updating queue count was handled by the cancellation code, don't double count + _queueCount += oldestRequest.Count; + } } else { @@ -277,10 +286,19 @@ private void Release(int releaseCount) // Check if request was canceled if (!nextPendingRequest.TrySetResult(lease)) { - // Queued item was canceled so add count back + // Queued item was canceled so add count back, permits weren't acquired _permitCount += nextPendingRequest.Count; - // Updating queue count is handled by the cancellation code - _queueCount += nextPendingRequest.Count; + if (!nextPendingRequest.QueueCountModified) + { + // We already updated the queue count, the Cancel code is about to run or running and waiting on our lock, + // tell Cancel not to do anything + nextPendingRequest.QueueCountModified = true; + } + else + { + // Updating queue count was handled by the cancellation code, don't double count + _queueCount += nextPendingRequest.Count; + } } else { @@ -399,6 +417,9 @@ private sealed class RequestRegistration : TaskCompletionSource private readonly CancellationToken _cancellationToken; private CancellationTokenRegistration _cancellationTokenRegistration; + // Update under the limiter lock and only if the queue count was updated by the calling code + public bool QueueCountModified { get; set; } + // this field is used only by the disposal mechanics and never shared between threads private RequestRegistration? _next; @@ -429,7 +450,14 @@ private static void Cancel(object? state) var limiter = (ConcurrencyLimiter)registration.Task.AsyncState!; lock (limiter.Lock) { - limiter._queueCount -= registration.Count; + // Queuing and replenishing code might modify the _queueCount, since there is no guarantee of when the cancellation + // code runs and we only want to update the _queueCount once, we set a bool (under a lock) so either method + // can update the count and not double count. + if (!registration.QueueCountModified) + { + limiter._queueCount -= registration.Count; + registration.QueueCountModified = true; + } } } } diff --git a/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/FixedWindowRateLimiter.cs b/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/FixedWindowRateLimiter.cs index d09c7973b18aa7..daaed9cf5ce422 100644 --- a/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/FixedWindowRateLimiter.cs +++ b/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/FixedWindowRateLimiter.cs @@ -173,7 +173,17 @@ protected override ValueTask AcquireAsyncCore(int permitCount, C Debug.Assert(_queueCount >= 0); if (!oldestRequest.TrySetResult(FailedLease)) { - _queueCount += oldestRequest.Count; + if (!oldestRequest.QueueCountModified) + { + // We already updated the queue count, the Cancel code is about to run or running and waiting on our lock, + // tell Cancel not to do anything + oldestRequest.QueueCountModified = true; + } + else + { + // Updating queue count was handled by the cancellation code, don't double count + _queueCount += oldestRequest.Count; + } } else { @@ -330,10 +340,19 @@ private void ReplenishInternal(long nowTicks) if (!nextPendingRequest.TrySetResult(SuccessfulLease)) { - // Queued item was canceled so add count back + // Queued item was canceled so add count back, permits weren't acquired _permitCount += nextPendingRequest.Count; - // Updating queue count is handled by the cancellation code - _queueCount += nextPendingRequest.Count; + if (!nextPendingRequest.QueueCountModified) + { + // We already updated the queue count, the Cancel code is about to run or running and waiting on our lock, + // tell Cancel not to do anything + nextPendingRequest.QueueCountModified = true; + } + else + { + // Updating queue count was handled by the cancellation code, don't double count + _queueCount += nextPendingRequest.Count; + } } else { @@ -435,6 +454,9 @@ private sealed class RequestRegistration : TaskCompletionSource private readonly CancellationToken _cancellationToken; private CancellationTokenRegistration _cancellationTokenRegistration; + // Update under the limiter lock and only if the queue count was updated by the calling code + public bool QueueCountModified { get; set; } + // this field is used only by the disposal mechanics and never shared between threads private RequestRegistration? _next; @@ -465,7 +487,14 @@ private static void Cancel(object? state) var limiter = (FixedWindowRateLimiter)registration.Task.AsyncState!; lock (limiter.Lock) { - limiter._queueCount -= registration.Count; + // Queuing and replenishing code might modify the _queueCount, since there is no guarantee of when the cancellation + // code runs and we only want to update the _queueCount once, we set a bool (under a lock) so either method + // can update the count and not double count. + if (!registration.QueueCountModified) + { + limiter._queueCount -= registration.Count; + registration.QueueCountModified = true; + } } } } diff --git a/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/SlidingWindowRateLimiter.cs b/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/SlidingWindowRateLimiter.cs index a179720ede33fa..23dbf98e0fcdea 100644 --- a/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/SlidingWindowRateLimiter.cs +++ b/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/SlidingWindowRateLimiter.cs @@ -185,7 +185,17 @@ protected override ValueTask AcquireAsyncCore(int permitCount, C Debug.Assert(_queueCount >= 0); if (!oldestRequest.TrySetResult(FailedLease)) { - _queueCount += oldestRequest.Count; + if (!oldestRequest.QueueCountModified) + { + // We already updated the queue count, the Cancel code is about to run or running and waiting on our lock, + // tell Cancel not to do anything + oldestRequest.QueueCountModified = true; + } + else + { + // Updating queue count was handled by the cancellation code, don't double count + _queueCount += oldestRequest.Count; + } } else { @@ -342,11 +352,20 @@ private void ReplenishInternal(long nowTicks) if (!nextPendingRequest.TrySetResult(SuccessfulLease)) { - // Queued item was canceled so add count back + // Queued item was canceled so add count back, permits weren't acquired _permitCount += nextPendingRequest.Count; _requestsPerSegment[_currentSegmentIndex] -= nextPendingRequest.Count; - // Updating queue count is handled by the cancellation code - _queueCount += nextPendingRequest.Count; + if (!nextPendingRequest.QueueCountModified) + { + // We already updated the queue count, the Cancel code is about to run or running and waiting on our lock, + // tell Cancel not to do anything + nextPendingRequest.QueueCountModified = true; + } + else + { + // Updating queue count was handled by the cancellation code, don't double count + _queueCount += nextPendingRequest.Count; + } } else { @@ -448,6 +467,9 @@ private sealed class RequestRegistration : TaskCompletionSource private readonly CancellationToken _cancellationToken; private CancellationTokenRegistration _cancellationTokenRegistration; + // Update under the limiter lock and only if the queue count was updated by the calling code + public bool QueueCountModified { get; set; } + // this field is used only by the disposal mechanics and never shared between threads private RequestRegistration? _next; @@ -478,7 +500,14 @@ private static void Cancel(object? state) var limiter = (SlidingWindowRateLimiter)registration.Task.AsyncState!; lock (limiter.Lock) { - limiter._queueCount -= registration.Count; + // Queuing and replenishing code might modify the _queueCount, since there is no guarantee of when the cancellation + // code runs and we only want to update the _queueCount once, we set a bool (under a lock) so either method + // can update the count and not double count. + if (!registration.QueueCountModified) + { + limiter._queueCount -= registration.Count; + registration.QueueCountModified = true; + } } } } diff --git a/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/TokenBucketRateLimiter.cs b/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/TokenBucketRateLimiter.cs index 5ad7859792ff7f..67a3a55a29ad03 100644 --- a/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/TokenBucketRateLimiter.cs +++ b/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/TokenBucketRateLimiter.cs @@ -178,8 +178,17 @@ protected override ValueTask AcquireAsyncCore(int tokenCount, Ca Debug.Assert(_queueCount >= 0); if (!oldestRequest.TrySetResult(FailedLease)) { - // Updating queue count is handled by the cancellation code - _queueCount += oldestRequest.Count; + if (!oldestRequest.QueueCountModified) + { + // We already updated the queue count, the Cancel code is about to run or running and waiting on our lock, + // tell Cancel not to do anything + oldestRequest.QueueCountModified = true; + } + else + { + // Updating queue count was handled by the cancellation code, don't double count + _queueCount += oldestRequest.Count; + } } else { @@ -345,10 +354,19 @@ private void ReplenishInternal(long nowTicks) if (!nextPendingRequest.TrySetResult(SuccessfulLease)) { - // Queued item was canceled so add count back + // Queued item was canceled so add count back, permits weren't acquired _tokenCount += nextPendingRequest.Count; - // Updating queue count is handled by the cancellation code - _queueCount += nextPendingRequest.Count; + if (!nextPendingRequest.QueueCountModified) + { + // We already updated the queue count, the Cancel code is about to run or running and waiting on our lock, + // tell Cancel not to do anything + nextPendingRequest.QueueCountModified = true; + } + else + { + // Updating queue count was handled by the cancellation code, don't double count + _queueCount += nextPendingRequest.Count; + } } else { @@ -450,6 +468,9 @@ private sealed class RequestRegistration : TaskCompletionSource private readonly CancellationToken _cancellationToken; private CancellationTokenRegistration _cancellationTokenRegistration; + // Update under the limiter lock and only if the queue count was updated by the calling code + public bool QueueCountModified { get; set; } + // this field is used only by the disposal mechanics and never shared between threads private RequestRegistration? _next; @@ -480,7 +501,14 @@ private static void Cancel(object? state) var limiter = (TokenBucketRateLimiter)registration.Task.AsyncState!; lock (limiter.Lock) { - limiter._queueCount -= registration.Count; + // Queuing and replenishing code might modify the _queueCount, since there is no guarantee of when the cancellation + // code runs and we only want to update the _queueCount once, we set a bool (under a lock) so either method + // can update the count and not double count. + if (!registration.QueueCountModified) + { + limiter._queueCount -= registration.Count; + registration.QueueCountModified = true; + } } } } From 1c824d929b734db420babbc04f44a1491d8a7efb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Cant=C3=BA?= Date: Mon, 22 Apr 2024 21:58:44 -0500 Subject: [PATCH 020/161] Reapply params ReadOnlySpan overloads without params keyword (#101308) * Reapply "Add params ReadOnlySpan overloads (#100898)" (#101123) This reverts commit 3e569f5696ddf6c93e56eeaaf1703bb64e561f1b. * Comment-out params keyword * Remove /*params*/ from ref --- .../Common/tests/Tests/System/StringTests.cs | 201 +++++++++++++--- .../Collections/Immutable/ImmutableArray.cs | 2 +- .../Immutable/ImmutableArray_1.Builder.cs | 4 +- .../Collections/Immutable/ImmutableArray_1.cs | 4 +- .../Collections/Immutable/ImmutableHashSet.cs | 4 +- .../Collections/Immutable/ImmutableList.cs | 2 +- .../Collections/Immutable/ImmutableQueue.cs | 2 +- .../Immutable/ImmutableSortedSet.cs | 4 +- .../Collections/Immutable/ImmutableStack.cs | 2 +- .../tests/ImmutableHashSetTest.cs | 4 +- .../tests/ImmutableListTest.cs | 2 +- .../tests/ImmutableQueueTest.cs | 2 +- .../tests/ImmutableSortedSetTest.cs | 4 +- .../tests/ImmutableStackTest.cs | 2 +- .../src/System.Collections.NonGeneric.csproj | 1 + .../src/System.Collections.Specialized.csproj | 1 + ...stem.ComponentModel.EventBasedAsync.csproj | 1 + .../System.ComponentModel.Primitives.csproj | 1 + .../System.Console/ref/System.Console.cs | 2 + .../System.Console/src/System/Console.cs | 22 ++ .../System.Console/tests/ReadAndWrite.cs | 30 ++- ...em.Diagnostics.DiagnosticSourceActivity.cs | 8 +- .../src/System/Diagnostics/Metrics/Counter.cs | 2 +- .../System/Diagnostics/Metrics/Histogram.cs | 2 +- .../System/Diagnostics/Metrics/Measurement.cs | 2 +- .../src/System/Diagnostics/Metrics/TagList.cs | 2 +- .../Diagnostics/Metrics/UpDownCounter.cs | 2 +- .../tests/MetricsTests.cs | 113 +++++++-- .../tests/TagListTests.cs | 9 +- .../System.IO.FileSystem.AccessControl.csproj | 2 +- .../src/System.IO.IsolatedStorage.csproj | 1 + .../src/System.IO.Pipes.AccessControl.csproj | 1 + .../src/System.Linq.Expressions.csproj | 1 + .../src/System.Linq.Parallel.csproj | 1 + .../src/System.Linq.Queryable.csproj | 1 + .../src/System.Net.Http.Json.csproj | 2 + .../src/System.ObjectModel.csproj | 1 + .../CodeDom/Compiler/IndentedTextWriter.cs | 23 ++ .../Generic/CollectionExtensions.cs | 4 +- .../src/System/Delegate.cs | 28 ++- .../src/System/IO/Path.cs | 20 +- .../src/System/IO/StreamWriter.cs | 34 +++ .../IO/TextWriter.CreateBroadcasting.cs | 16 ++ .../src/System/IO/TextWriter.cs | 28 +++ .../src/System/MemoryExtensions.cs | 2 +- .../src/System/String.Manipulation.cs | 217 ++++++++++++++++-- .../src/System/Text/StringBuilder.cs | 155 ++++++++++--- .../Threading/CancellationTokenSource.cs | 12 +- .../src/System/Threading/Tasks/Task.cs | 152 +++++++++--- .../System.Reflection.DispatchProxy.csproj | 1 + .../src/System.Resources.Writer.csproj | 1 + ...em.Runtime.Serialization.Primitives.csproj | 1 + .../System.Runtime/ref/System.Runtime.cs | 34 +++ ...namic.context.method.regmethod.regclass.cs | 2 + ...amic.overloadResolution.Operators.basic.cs | 4 + .../System.IO.Tests/IndentedTextWriter.cs | 27 ++- .../Stream/Stream.NullTests.cs | 6 +- .../StreamWriter/StreamWriter.cs | 16 +- .../TextWriter/TextWriterTests.cs | 41 +++- .../System/IO/PathTests_Combine.cs | 5 + .../System/IO/PathTests_Join.cs | 6 + .../System/MulticastDelegateTests.cs | 30 ++- .../System/String.SplitTests.cs | 2 + .../System/Text/CompositeFormatTests.cs | 39 ++-- .../System/Text/StringBuilderTests.cs | 56 ++++- .../CancellationTokenTests.cs | 12 +- .../MethodCoverage.cs | 62 +++++ .../Task/TaskRtTests_Core.cs | 5 - .../src/System.Security.Claims.csproj | 1 + .../System.Text.Json/ref/System.Text.Json.cs | 3 + .../src/System/Text/Json/Nodes/JsonArray.cs | 44 +++- .../Metadata/JsonTypeInfoResolver.cs | 19 ++ .../JsonNode/JsonArrayTests.cs | 21 +- .../JsonTypeInfoResolverTests.cs | 72 +++--- .../src/System.Threading.Channels.csproj | 1 + .../System.Threading.Tasks.Dataflow.csproj | 1 + .../System.Threading.Tasks.Parallel.csproj | 1 + 77 files changed, 1388 insertions(+), 263 deletions(-) diff --git a/src/libraries/Common/tests/Tests/System/StringTests.cs b/src/libraries/Common/tests/Tests/System/StringTests.cs index f21dbe3baad6a6..8e465475a5200e 100644 --- a/src/libraries/Common/tests/Tests/System/StringTests.cs +++ b/src/libraries/Common/tests/Tests/System/StringTests.cs @@ -314,6 +314,7 @@ void Validate(string result) } Validate(string.Concat(values)); + Validate(string.Concat((ReadOnlySpan)values)); Validate(string.Concat((IEnumerable)values)); Validate(string.Concat((IEnumerable)values)); // Call the generic IEnumerable-based overload } @@ -418,6 +419,7 @@ public static void Concat_Objects(object[] values, string expected) Assert.Equal(expected, string.Concat(values[0], values[1], values[2], values[3])); } Assert.Equal(expected, string.Concat(values)); + Assert.Equal(expected, string.Concat((ReadOnlySpan)values)); Assert.Equal(expected, string.Concat((IEnumerable)values)); } @@ -2730,9 +2732,11 @@ public static IEnumerable Format_Valid_TestData() public static void Format_Valid(IFormatProvider provider, string format, object[] values, string expected) { Assert.Equal(expected, string.Format(provider, format, values)); + Assert.Equal(expected, string.Format(provider, format, (ReadOnlySpan)values)); if (provider is null) { Assert.Equal(expected, string.Format(format, values)); + Assert.Equal(expected, string.Format(format, (ReadOnlySpan)values)); } switch (values.Length) @@ -3967,6 +3971,7 @@ public static void Join_StringArray(string separator, string[] values, int start if (startIndex + count == values.Length && count != 0) { Assert.Equal(expected, string.Join(separator, values)); + Assert.Equal(expected, string.Join(separator, (ReadOnlySpan)values)); var iEnumerableStringOptimized = new List(values); Assert.Equal(expected, string.Join(separator, iEnumerableStringOptimized)); @@ -3984,6 +3989,44 @@ public static void Join_StringArray(string separator, string[] values, int start { var arrayOfObjects = (object[])values; Assert.Equal(expected, string.Join(separator, arrayOfObjects)); + Assert.Equal(expected, string.Join(separator, (ReadOnlySpan)arrayOfObjects)); + } + } + Assert.Equal(expected, string.Join(separator, values, startIndex, count)); + } + + [Theory] + [InlineData('$', new string[] { }, 0, 0, "")] + [InlineData('$', new string[] { null }, 0, 1, "")] + [InlineData('$', new string[] { null, "Bar", null }, 0, 3, "$Bar$")] + [InlineData('$', new string[] { "", "", "" }, 0, 3, "$$")] + [InlineData('$', new string[] { "Foo", "Bar", "Baz" }, 0, 3, "Foo$Bar$Baz")] + [InlineData('$', new string[] { "Foo", "Bar", "Baz" }, 3, 0, "")] + [InlineData('$', new string[] { "Foo", "Bar", "Baz" }, 1, 1, "Bar")] + public static void Join_CharSeparator_StringArray(char separator, string[] values, int startIndex, int count, string expected) + { + if (startIndex + count == values.Length && count != 0) + { + Assert.Equal(expected, string.Join(separator, values)); + Assert.Equal(expected, string.Join(separator, (ReadOnlySpan)values)); + + var iEnumerableStringOptimized = new List(values); + Assert.Equal(expected, string.Join(separator, iEnumerableStringOptimized)); + Assert.Equal(expected, string.Join(separator, iEnumerableStringOptimized)); // Call the generic IEnumerable-based overload + + var iEnumerableStringNotOptimized = new Queue(values); + Assert.Equal(expected, string.Join(separator, iEnumerableStringNotOptimized)); + Assert.Equal(expected, string.Join(separator, iEnumerableStringNotOptimized)); + + var iEnumerableObject = new List(values); + Assert.Equal(expected, string.Join(separator, iEnumerableObject)); + + // Bug/Documented behavior: Join(string, object[]) returns "" when the first item in the array is null + if (values.Length == 0 || values[0] != null) + { + var arrayOfObjects = (object[])values; + Assert.Equal(expected, string.Join(separator, arrayOfObjects)); + Assert.Equal(expected, string.Join(separator, (ReadOnlySpan)arrayOfObjects)); } } Assert.Equal(expected, string.Join(separator, values, startIndex, count)); @@ -4038,6 +4081,31 @@ public static void Join_ObjectArray(string separator, object[] values, string ex { Assert.Equal(expected, string.Join(separator, values)); Assert.Equal(expected, string.Join(separator, (IEnumerable)values)); + Assert.Equal(expected, string.Join(separator, (ReadOnlySpan)values)); + } + + public static IEnumerable Join_CharSeparator_ObjectArray_TestData() + { + yield return new object[] { '$', new object[] { }, "" }; + yield return new object[] { '$', new object[] { new ObjectWithNullToString() }, "" }; + yield return new object[] { '$', new object[] { "Foo" }, "Foo" }; + yield return new object[] { '$', new object[] { "Foo", "Bar", "Baz" }, "Foo$Bar$Baz" }; + yield return new object[] { '$', new object[] { "Foo", null, "Baz" }, "Foo$$Baz" }; + + // Test join when first value is null + yield return new object[] { '$', new object[] { null, "Bar", "Baz" }, "$Bar$Baz" }; + + // Join should ignore objects that have a null ToString() value + yield return new object[] { "|", new object[] { new ObjectWithNullToString(), "Foo", new ObjectWithNullToString(), "Bar", new ObjectWithNullToString() }, "|Foo||Bar|" }; + } + + [Theory] + [MemberData(nameof(Join_CharSeparator_ObjectArray_TestData))] + public static void Join_CharSeparator_ObjectArray(char separator, object[] values, string expected) + { + Assert.Equal(expected, string.Join(separator, values)); + Assert.Equal(expected, string.Join(separator, (IEnumerable)values)); + Assert.Equal(expected, string.Join(separator, (ReadOnlySpan)values)); } [Fact] @@ -6098,6 +6166,7 @@ public static void Trim(string s, char[] trimChars, string expected) } Assert.Equal(expected, s.Trim(trimChars)); + Assert.Equal(expected, s.Trim((ReadOnlySpan)trimChars)); Assert.Equal(expected, s.AsSpan().Trim(trimChars).ToString()); } @@ -6128,6 +6197,7 @@ public static void TrimEnd(string s, char[] trimChars, string expected) } Assert.Equal(expected, s.TrimEnd(trimChars)); + Assert.Equal(expected, s.TrimEnd((ReadOnlySpan)trimChars)); Assert.Equal(expected, s.AsSpan().TrimEnd(trimChars).ToString()); } @@ -6158,6 +6228,7 @@ public static void TrimStart(string s, char[] trimChars, string expected) } Assert.Equal(expected, s.TrimStart(trimChars)); + Assert.Equal(expected, s.TrimStart((ReadOnlySpan)trimChars)); Assert.Equal(expected, s.AsSpan().TrimStart(trimChars).ToString()); } @@ -6388,18 +6459,27 @@ public static void ZeroLengthTrimCharacters() Assert.True(s1.SequenceEqual(s1.Trim(trimCharsString))); Assert.True(s1.SequenceEqual(s1.TrimStart(trimCharsString))); Assert.True(s1.SequenceEqual(s1.TrimEnd(trimCharsString))); + Assert.True(s1.SequenceEqual(s1.Trim((ReadOnlySpan)trimCharsString))); + Assert.True(s1.SequenceEqual(s1.TrimStart((ReadOnlySpan)trimCharsString))); + Assert.True(s1.SequenceEqual(s1.TrimEnd((ReadOnlySpan)trimCharsString))); char[] chars = { 'a', 'b', 'c', 'd', 'e' }; trimCharsString = chars; Assert.True(s1.SequenceEqual(s1.Trim(trimCharsString))); Assert.True(s1.SequenceEqual(s1.TrimStart(trimCharsString))); Assert.True(s1.SequenceEqual(s1.TrimEnd(trimCharsString))); + Assert.True(s1.SequenceEqual(s1.Trim((ReadOnlySpan)trimCharsString))); + Assert.True(s1.SequenceEqual(s1.TrimStart((ReadOnlySpan)trimCharsString))); + Assert.True(s1.SequenceEqual(s1.TrimEnd((ReadOnlySpan)trimCharsString))); string emptyString = string.Empty; char[] trimCharsArrayFromString = "abcde".ToCharArray(); Assert.True(emptyString.SequenceEqual(emptyString.Trim(trimCharsArrayFromString))); Assert.True(emptyString.SequenceEqual(emptyString.TrimStart(trimCharsArrayFromString))); Assert.True(emptyString.SequenceEqual(emptyString.TrimEnd(trimCharsArrayFromString))); + Assert.True(emptyString.SequenceEqual(emptyString.Trim((ReadOnlySpan)trimCharsArrayFromString))); + Assert.True(emptyString.SequenceEqual(emptyString.TrimStart((ReadOnlySpan)trimCharsArrayFromString))); + Assert.True(emptyString.SequenceEqual(emptyString.TrimEnd((ReadOnlySpan)trimCharsArrayFromString))); ReadOnlySpan span = s1.AsSpan(); ReadOnlySpan trimChars = trimCharsString.AsSpan(); @@ -6435,6 +6515,9 @@ public static void NoTrimCharacters() Assert.True(s1.SequenceEqual(s1.Trim(trimCharsString))); Assert.True(s1.SequenceEqual(s1.TrimStart(trimCharsString))); Assert.True(s1.SequenceEqual(s1.TrimEnd(trimCharsString))); + Assert.True(s1.SequenceEqual(s1.Trim((ReadOnlySpan)trimCharsString))); + Assert.True(s1.SequenceEqual(s1.TrimStart((ReadOnlySpan)trimCharsString))); + Assert.True(s1.SequenceEqual(s1.TrimEnd((ReadOnlySpan)trimCharsString))); ReadOnlySpan span = s1.AsSpan(); Assert.True(span.SequenceEqual(span.Trim(trimChars))); @@ -6454,6 +6537,9 @@ public static void NoTrimCharacters() Assert.True(s2.SequenceEqual(s2.Trim(chars))); Assert.True(s2.SequenceEqual(s2.TrimStart(chars))); Assert.True(s2.SequenceEqual(s2.TrimEnd(chars))); + Assert.True(s2.SequenceEqual(s2.Trim((ReadOnlySpan)chars))); + Assert.True(s2.SequenceEqual(s2.TrimStart((ReadOnlySpan)chars))); + Assert.True(s2.SequenceEqual(s2.TrimEnd((ReadOnlySpan)chars))); ReadOnlySpan span = s2.AsSpan(); Assert.True(span.SequenceEqual(span.Trim(chars))); @@ -6466,6 +6552,9 @@ public static void NoTrimCharacters() Assert.True(s3.SequenceEqual(s3.Trim(trimCharsFromString))); Assert.True(s3.SequenceEqual(s3.TrimStart(trimCharsFromString))); Assert.True(s3.SequenceEqual(s3.TrimEnd(trimCharsFromString))); + Assert.True(s3.SequenceEqual(s3.Trim((ReadOnlySpan)trimCharsFromString))); + Assert.True(s3.SequenceEqual(s3.TrimStart((ReadOnlySpan)trimCharsFromString))); + Assert.True(s3.SequenceEqual(s3.TrimEnd((ReadOnlySpan)trimCharsFromString))); ReadOnlySpan stringSpan = s3.AsSpan(); ReadOnlySpan trimCharsFromStringSpan = trimCharsFromString.AsSpan(); @@ -6490,6 +6579,9 @@ public static void OnlyTrimCharacters() Assert.True(string.Empty.SequenceEqual(s1.Trim(chars)), "G: " + length); Assert.True(string.Empty.SequenceEqual(s1.TrimStart(chars)), "H: " + length); Assert.True(string.Empty.SequenceEqual(s1.TrimEnd(chars)), "I: " + length); + Assert.True(string.Empty.SequenceEqual(s1.Trim((ReadOnlySpan)chars)), "G: " + length); + Assert.True(string.Empty.SequenceEqual(s1.TrimStart((ReadOnlySpan)chars)), "H: " + length); + Assert.True(string.Empty.SequenceEqual(s1.TrimEnd((ReadOnlySpan)chars)), "I: " + length); ReadOnlySpan span = s1.AsSpan(); Assert.True(ReadOnlySpan.Empty.SequenceEqual(span.Trim(chars)), "G: " + length); @@ -6502,6 +6594,9 @@ public static void OnlyTrimCharacters() Assert.True(string.Empty.SequenceEqual(s2.Trim(trimCharsString)), "J"); Assert.True(string.Empty.SequenceEqual(s2.TrimStart(trimCharsString)), "K"); Assert.True(string.Empty.SequenceEqual(s2.TrimEnd(trimCharsString)), "L"); + Assert.True(string.Empty.SequenceEqual(s2.Trim((ReadOnlySpan)trimCharsString)), "J"); + Assert.True(string.Empty.SequenceEqual(s2.TrimStart((ReadOnlySpan)trimCharsString)), "K"); + Assert.True(string.Empty.SequenceEqual(s2.TrimEnd((ReadOnlySpan)trimCharsString)), "L"); ReadOnlySpan stringSpan = s2.AsSpan(); ReadOnlySpan trimChars = trimCharsString.AsSpan(); @@ -6526,6 +6621,9 @@ public static void TrimCharactersAtStart() Assert.True(s1.Substring(1).SequenceEqual(s1.Trim(chars)), "A: " + length); Assert.True(s1.Substring(1).SequenceEqual(s1.TrimStart(chars)), "B: " + length); Assert.True(s1.SequenceEqual(s1.TrimEnd(chars)), "C: " + length); + Assert.True(s1.Substring(1).SequenceEqual(s1.Trim((ReadOnlySpan)chars)), "A: " + length); + Assert.True(s1.Substring(1).SequenceEqual(s1.TrimStart((ReadOnlySpan)chars)), "B: " + length); + Assert.True(s1.SequenceEqual(s1.TrimEnd((ReadOnlySpan)chars)), "C: " + length); ReadOnlySpan span = s1.AsSpan(); Assert.True(span.Slice(1).SequenceEqual(span.Trim(chars)), "A: " + length); @@ -6538,6 +6636,9 @@ public static void TrimCharactersAtStart() Assert.True(s2.Substring(3).SequenceEqual(s2.Trim(trimCharsString)), "D"); Assert.True(s2.Substring(3).SequenceEqual(s2.TrimStart(trimCharsString)), "E"); Assert.True(s2.SequenceEqual(s2.TrimEnd(trimCharsString)), "F"); + Assert.True(s2.Substring(3).SequenceEqual(s2.Trim((ReadOnlySpan)trimCharsString)), "D"); + Assert.True(s2.Substring(3).SequenceEqual(s2.TrimStart((ReadOnlySpan)trimCharsString)), "E"); + Assert.True(s2.SequenceEqual(s2.TrimEnd((ReadOnlySpan)trimCharsString)), "F"); ReadOnlySpan stringSpan = s2.AsSpan(); ReadOnlySpan trimChars = trimCharsString.AsSpan(); @@ -6563,6 +6664,9 @@ public static void TrimCharactersAtEnd() Assert.True(s1.Substring(0, length - 1).SequenceEqual(s1.Trim(chars))); Assert.True(s1.SequenceEqual(s1.TrimStart(chars))); Assert.True(s1.Substring(0, length - 1).SequenceEqual(s1.TrimEnd(chars))); + Assert.True(s1.Substring(0, length - 1).SequenceEqual(s1.Trim((ReadOnlySpan)chars))); + Assert.True(s1.SequenceEqual(s1.TrimStart((ReadOnlySpan)chars))); + Assert.True(s1.Substring(0, length - 1).SequenceEqual(s1.TrimEnd((ReadOnlySpan)chars))); ReadOnlySpan span = new ReadOnlySpan(a); Assert.True(span.Slice(0, length - 1).SequenceEqual(span.Trim(chars))); @@ -6600,6 +6704,9 @@ public static void TrimCharactersAtStartAndEnd() Assert.True(s1.Substring(1, length - 2).SequenceEqual(s1.Trim(chars))); Assert.True(s1.Substring(1).SequenceEqual(s1.TrimStart(chars))); Assert.True(s1.Substring(0, length - 1).SequenceEqual(s1.TrimEnd(chars))); + Assert.True(s1.Substring(1, length - 2).SequenceEqual(s1.Trim((ReadOnlySpan)chars))); + Assert.True(s1.Substring(1).SequenceEqual(s1.TrimStart((ReadOnlySpan)chars))); + Assert.True(s1.Substring(0, length - 1).SequenceEqual(s1.TrimEnd((ReadOnlySpan)chars))); ReadOnlySpan span = s1.AsSpan(); Assert.True(span.Slice(1, length - 2).SequenceEqual(span.Trim(chars))); @@ -6608,13 +6715,15 @@ public static void TrimCharactersAtStartAndEnd() } string s2 = "ccedafffffbdaa"; - char[] trimCharsString = "abcde".ToCharArray(); - Assert.True(s2.Substring(5, 5).SequenceEqual(s2.Trim(trimCharsString))); - Assert.True(s2.Substring(5).SequenceEqual(s2.TrimStart(trimCharsString))); - Assert.True(s2.Substring(0, 10).SequenceEqual(s2.TrimEnd(trimCharsString))); + Assert.True(s2.Substring(5, 5).SequenceEqual(s2.Trim(chars))); + Assert.True(s2.Substring(5).SequenceEqual(s2.TrimStart(chars))); + Assert.True(s2.Substring(0, 10).SequenceEqual(s2.TrimEnd(chars))); + Assert.True(s2.Substring(5, 5).SequenceEqual(s2.Trim((ReadOnlySpan)chars))); + Assert.True(s2.Substring(5).SequenceEqual(s2.TrimStart((ReadOnlySpan)chars))); + Assert.True(s2.Substring(0, 10).SequenceEqual(s2.TrimEnd((ReadOnlySpan)chars))); ReadOnlySpan stringSpan = s2.AsSpan(); - ReadOnlySpan trimChars = trimCharsString.AsSpan(); + ReadOnlySpan trimChars = chars.AsSpan(); Assert.True(stringSpan.Slice(5, 5).SequenceEqual(stringSpan.Trim(trimChars))); Assert.True(stringSpan.Slice(5).SequenceEqual(stringSpan.TrimStart(trimChars))); Assert.True(stringSpan.Slice(0, 10).SequenceEqual(stringSpan.TrimEnd(trimChars))); @@ -6637,6 +6746,9 @@ public static void TrimCharactersInMiddle() Assert.True(s1.SequenceEqual(s1.Trim(chars))); Assert.True(s1.SequenceEqual(s1.TrimStart(chars))); Assert.True(s1.SequenceEqual(s1.TrimEnd(chars))); + Assert.True(s1.SequenceEqual(s1.Trim((ReadOnlySpan)chars))); + Assert.True(s1.SequenceEqual(s1.TrimStart((ReadOnlySpan)chars))); + Assert.True(s1.SequenceEqual(s1.TrimEnd((ReadOnlySpan)chars))); ReadOnlySpan span = s1.AsSpan(); Assert.True(span.SequenceEqual(span.Trim(chars))); @@ -6645,13 +6757,15 @@ public static void TrimCharactersInMiddle() } string s2 = "fabbacddeeddef"; - char[] trimCharsString = "abcde".ToCharArray(); - Assert.True(s2.SequenceEqual(s2.Trim(trimCharsString))); - Assert.True(s2.SequenceEqual(s2.TrimStart(trimCharsString))); - Assert.True(s2.SequenceEqual(s2.TrimEnd(trimCharsString))); + Assert.True(s2.SequenceEqual(s2.Trim(chars))); + Assert.True(s2.SequenceEqual(s2.TrimStart(chars))); + Assert.True(s2.SequenceEqual(s2.TrimEnd(chars))); + Assert.True(s2.SequenceEqual(s2.Trim((ReadOnlySpan)chars))); + Assert.True(s2.SequenceEqual(s2.TrimStart((ReadOnlySpan)chars))); + Assert.True(s2.SequenceEqual(s2.TrimEnd((ReadOnlySpan)chars))); ReadOnlySpan stringSpan = s2.AsSpan(); - ReadOnlySpan trimChars = trimCharsString.AsSpan(); + ReadOnlySpan trimChars = chars.AsSpan(); Assert.True(stringSpan.SequenceEqual(stringSpan.Trim(trimChars))); Assert.True(stringSpan.SequenceEqual(stringSpan.TrimStart(trimChars))); Assert.True(stringSpan.SequenceEqual(stringSpan.TrimEnd(trimChars))); @@ -6684,6 +6798,19 @@ public static void TrimCharactersMultipleTimes() Assert.True(trimStartResultString.SequenceEqual(trimStartResultString.TrimStart(chars))); Assert.True(trimEndResultString.SequenceEqual(trimEndResultString.TrimEnd(chars))); + s1 = new string(a); + trimResultString = s1.Trim((ReadOnlySpan)chars); + trimStartResultString = s1.TrimStart((ReadOnlySpan)chars); + trimEndResultString = s1.TrimEnd((ReadOnlySpan)chars); + Assert.True(s1.Substring(1, length - 2).SequenceEqual(trimResultString)); + Assert.True(s1.Substring(1).SequenceEqual(trimStartResultString)); + Assert.True(s1.Substring(0, length - 1).SequenceEqual(trimEndResultString)); + + // 2nd attempt should do nothing + Assert.True(trimResultString.SequenceEqual(trimResultString.Trim((ReadOnlySpan)chars))); + Assert.True(trimStartResultString.SequenceEqual(trimStartResultString.TrimStart((ReadOnlySpan)chars))); + Assert.True(trimEndResultString.SequenceEqual(trimEndResultString.TrimEnd((ReadOnlySpan)chars))); + ReadOnlySpan span = s1.AsSpan(); ReadOnlySpan trimResult = span.Trim(chars); ReadOnlySpan trimStartResult = span.TrimStart(chars); @@ -6699,21 +6826,33 @@ public static void TrimCharactersMultipleTimes() } string s2 = "ccedafffffbdaa"; - char[] trimCharsString = "abcde".ToCharArray(); - string trimStringResultString = s2.Trim(trimCharsString); - string trimStartStringResultString = s2.TrimStart(trimCharsString); - string trimEndStringResultString = s2.TrimEnd(trimCharsString); + string trimStringResultString = s2.Trim(chars); + string trimStartStringResultString = s2.TrimStart(chars); + string trimEndStringResultString = s2.TrimEnd(chars); + Assert.True(s2.Substring(5, 5).SequenceEqual(trimStringResultString)); + Assert.True(s2.Substring(5).SequenceEqual(trimStartStringResultString)); + Assert.True(s2.Substring(0, 10).SequenceEqual(trimEndStringResultString)); + + // 2nd attempt should do nothing + Assert.True(trimStringResultString.SequenceEqual(trimStringResultString.Trim(chars))); + Assert.True(trimStartStringResultString.SequenceEqual(trimStartStringResultString.TrimStart(chars))); + Assert.True(trimEndStringResultString.SequenceEqual(trimEndStringResultString.TrimEnd(chars))); + + s2 = "ccedafffffbdaa"; + trimStringResultString = s2.Trim((ReadOnlySpan)chars); + trimStartStringResultString = s2.TrimStart((ReadOnlySpan)chars); + trimEndStringResultString = s2.TrimEnd((ReadOnlySpan)chars); Assert.True(s2.Substring(5, 5).SequenceEqual(trimStringResultString)); Assert.True(s2.Substring(5).SequenceEqual(trimStartStringResultString)); Assert.True(s2.Substring(0, 10).SequenceEqual(trimEndStringResultString)); // 2nd attempt should do nothing - Assert.True(trimStringResultString.SequenceEqual(trimStringResultString.Trim(trimCharsString))); - Assert.True(trimStartStringResultString.SequenceEqual(trimStartStringResultString.TrimStart(trimCharsString))); - Assert.True(trimEndStringResultString.SequenceEqual(trimEndStringResultString.TrimEnd(trimCharsString))); + Assert.True(trimStringResultString.SequenceEqual(trimStringResultString.Trim((ReadOnlySpan)chars))); + Assert.True(trimStartStringResultString.SequenceEqual(trimStartStringResultString.TrimStart((ReadOnlySpan)chars))); + Assert.True(trimEndStringResultString.SequenceEqual(trimEndStringResultString.TrimEnd((ReadOnlySpan)chars))); ReadOnlySpan stringSpan = s2.AsSpan(); - ReadOnlySpan trimChars = trimCharsString.AsSpan(); + ReadOnlySpan trimChars = chars.AsSpan(); ReadOnlySpan trimStringResult = stringSpan.Trim(trimChars); ReadOnlySpan trimStartStringResult = stringSpan.TrimStart(trimChars); @@ -6739,27 +6878,31 @@ public static void MakeSureNoTrimCharactersChecksGoOutOfRange() first[length - 1] = 'f'; string s1 = new string(first, 1, length - 2); Assert.Equal(s1.ToArray().Length, s1.Trim(chars).ToArray().Length); - Assert.True(s1.SequenceEqual(s1.Trim(chars)), "A : " + s1.Length); - Assert.True(s1.SequenceEqual(s1.TrimStart(chars)), "B :" + s1.Length); - Assert.True(s1.SequenceEqual(s1.TrimEnd(chars))); + Assert.True(s1.SequenceEqual(s1.Trim(chars)), "A: " + s1.Length); + Assert.True(s1.SequenceEqual(s1.TrimStart(chars)), "B: " + s1.Length); + Assert.True(s1.SequenceEqual(s1.TrimEnd(chars)), "C: " + s1.Length); ReadOnlySpan span = s1.AsSpan(); Assert.Equal(span.ToArray().Length, span.Trim(chars).ToArray().Length); - Assert.True(span.SequenceEqual(span.Trim(chars)), "A : " + span.Length); - Assert.True(span.SequenceEqual(span.TrimStart(chars)), "B :" + span.Length); - Assert.True(span.SequenceEqual(span.TrimEnd(chars))); + Assert.True(span.SequenceEqual(span.Trim(chars)), "A: " + span.Length); + Assert.True(span.SequenceEqual(span.TrimStart(chars)), "B: " + span.Length); + Assert.True(span.SequenceEqual(span.TrimEnd(chars)), "C: " + s1.Length); } string testString = "afghijklmnopqrstfe"; string s2 = testString.Substring(1, testString.Length - 2); - char[] trimCharsString = "abcde".ToCharArray(); - Assert.True(s2.SequenceEqual(s2.Trim(trimCharsString))); - Assert.True(s2.SequenceEqual(s2.TrimStart(trimCharsString))); - Assert.True(s2.SequenceEqual(s2.TrimEnd(trimCharsString))); + Assert.True(s2.SequenceEqual(s2.Trim(chars))); + Assert.True(s2.SequenceEqual(s2.TrimStart(chars))); + Assert.True(s2.SequenceEqual(s2.TrimEnd(chars))); + + s2 = testString.Substring(1, testString.Length - 2); + Assert.True(s2.SequenceEqual(s2.Trim((ReadOnlySpan)chars))); + Assert.True(s2.SequenceEqual(s2.TrimStart((ReadOnlySpan)chars))); + Assert.True(s2.SequenceEqual(s2.TrimEnd((ReadOnlySpan)chars))); ReadOnlySpan stringSpan = s2.AsSpan(); - ReadOnlySpan trimChars = trimCharsString.AsSpan(); + ReadOnlySpan trimChars = chars.AsSpan(); Assert.True(stringSpan.SequenceEqual(stringSpan.Trim(trimChars))); Assert.True(stringSpan.SequenceEqual(stringSpan.TrimStart(trimChars))); Assert.True(stringSpan.SequenceEqual(stringSpan.TrimEnd(trimChars))); diff --git a/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableArray.cs b/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableArray.cs index f2743d3f16f8c9..aafe4316eb7503 100644 --- a/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableArray.cs +++ b/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableArray.cs @@ -87,7 +87,7 @@ public static ImmutableArray Create(T item1, T item2, T item3, T item4) /// The type of element stored in the array. /// The elements to store in the array. /// An immutable array containing the specified items. - public static ImmutableArray Create(ReadOnlySpan items) + public static ImmutableArray Create(/*params*/ ReadOnlySpan items) { if (items.IsEmpty) { diff --git a/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableArray_1.Builder.cs b/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableArray_1.Builder.cs index 8af78d72a063e0..060492a40bd06e 100644 --- a/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableArray_1.Builder.cs +++ b/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableArray_1.Builder.cs @@ -430,7 +430,7 @@ public void AddRange(ImmutableArray items, int length) /// Adds the specified items to the end of the array. /// /// The items to add at the end of the array. - public void AddRange(ReadOnlySpan items) + public void AddRange(/*params*/ ReadOnlySpan items) { int offset = this.Count; this.Count += items.Length; @@ -443,7 +443,7 @@ public void AddRange(ReadOnlySpan items) /// /// The type that derives from the type of item already in the array. /// The items to add at the end of the array. - public void AddRange(ReadOnlySpan items) where TDerived : T + public void AddRange(/*params*/ ReadOnlySpan items) where TDerived : T { int offset = this.Count; this.Count += items.Length; diff --git a/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableArray_1.cs b/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableArray_1.cs index 2d203d015b828a..04e05477e0ff7c 100644 --- a/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableArray_1.cs +++ b/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableArray_1.cs @@ -880,7 +880,7 @@ public IEnumerable OfType() /// /// The values to add. /// A new list with the elements added. - public ImmutableArray AddRange(ReadOnlySpan items) + public ImmutableArray AddRange(/*params*/ ReadOnlySpan items) { ImmutableArray self = this; return self.InsertRange(self.Length, items); @@ -949,7 +949,7 @@ public ImmutableArray InsertRange(int index, T[] items) /// The index at which to insert the value. /// The elements to insert. /// The new immutable collection. - public ImmutableArray InsertRange(int index, ReadOnlySpan items) + public ImmutableArray InsertRange(int index, /*params*/ ReadOnlySpan items) { ImmutableArray self = this; self.ThrowNullRefIfNotInitialized(); diff --git a/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableHashSet.cs b/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableHashSet.cs index 9630bb33b5c0fe..13742785d7d81e 100644 --- a/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableHashSet.cs +++ b/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableHashSet.cs @@ -98,7 +98,7 @@ public static ImmutableHashSet Create(params T[] items) /// The type of items stored by the collection. /// The items to prepopulate. /// The new immutable collection. - public static ImmutableHashSet Create(ReadOnlySpan items) + public static ImmutableHashSet Create(/*params*/ ReadOnlySpan items) { return ImmutableHashSet.Empty.Union(items); } @@ -124,7 +124,7 @@ public static ImmutableHashSet Create(IEqualityComparer? equalityCompar /// The equality comparer. /// The items to prepopulate. /// The new immutable collection. - public static ImmutableHashSet Create(IEqualityComparer? equalityComparer, ReadOnlySpan items) + public static ImmutableHashSet Create(IEqualityComparer? equalityComparer, /*params*/ ReadOnlySpan items) { return ImmutableHashSet.Empty.WithComparer(equalityComparer).Union(items); } diff --git a/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableList.cs b/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableList.cs index f3004e3fd0199f..977686b880cc8c 100644 --- a/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableList.cs +++ b/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableList.cs @@ -52,7 +52,7 @@ public static ImmutableList Create(params T[] items) /// The type of items stored by the collection. /// A span that contains the items to prepopulate the list with. /// A new immutable list that contains the specified items. - public static ImmutableList Create(ReadOnlySpan items) => ImmutableList.Empty.AddRange(items); + public static ImmutableList Create(/*params*/ ReadOnlySpan items) => ImmutableList.Empty.AddRange(items); /// /// Creates a new immutable list builder. diff --git a/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableQueue.cs b/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableQueue.cs index 122bae100534f0..d2f5d142bbf869 100644 --- a/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableQueue.cs +++ b/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableQueue.cs @@ -83,7 +83,7 @@ public static ImmutableQueue Create(params T[] items) /// The type of items in the immutable queue. /// A span that contains the items to prepopulate the queue with. /// A new immutable queue that contains the specified items. - public static ImmutableQueue Create(ReadOnlySpan items) + public static ImmutableQueue Create(/*params*/ ReadOnlySpan items) { if (items.IsEmpty) { diff --git a/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableSortedSet.cs b/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableSortedSet.cs index 567997ed0472aa..ae5493ff083213 100644 --- a/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableSortedSet.cs +++ b/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableSortedSet.cs @@ -97,7 +97,7 @@ public static ImmutableSortedSet Create(params T[] items) /// The type of items in the immutable set. /// A span that contains the items to prepopulate the set with. /// A new immutable set that contains the specified items. - public static ImmutableSortedSet Create(ReadOnlySpan items) + public static ImmutableSortedSet Create(/*params*/ ReadOnlySpan items) { return ImmutableSortedSet.Empty.Union(items); } @@ -123,7 +123,7 @@ public static ImmutableSortedSet Create(IComparer? comparer, params T[] /// The comparer. /// The items to prepopulate. /// The new immutable collection. - public static ImmutableSortedSet Create(IComparer? comparer, ReadOnlySpan items) + public static ImmutableSortedSet Create(IComparer? comparer, /*params*/ ReadOnlySpan items) { return ImmutableSortedSet.Empty.WithComparer(comparer).Union(items); } diff --git a/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableStack.cs b/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableStack.cs index 4e11bb76888077..f964f55c79908c 100644 --- a/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableStack.cs +++ b/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableStack.cs @@ -70,7 +70,7 @@ public static ImmutableStack Create(params T[] items) /// The type of items in the immutable stack. /// A span that contains the items to prepopulate the stack with. /// A new immutable stack that contains the specified items. - public static ImmutableStack Create(ReadOnlySpan items) + public static ImmutableStack Create(/*params*/ ReadOnlySpan items) { ImmutableStack stack = ImmutableStack.Empty; foreach (T item in items) diff --git a/src/libraries/System.Collections.Immutable/tests/ImmutableHashSetTest.cs b/src/libraries/System.Collections.Immutable/tests/ImmutableHashSetTest.cs index 0aab9405d55930..d6a01aee099a26 100644 --- a/src/libraries/System.Collections.Immutable/tests/ImmutableHashSetTest.cs +++ b/src/libraries/System.Collections.Immutable/tests/ImmutableHashSetTest.cs @@ -118,7 +118,7 @@ public void Create() Assert.Equal(1, set.Count); Assert.Same(comparer, set.KeyComparer); - set = ImmutableHashSet.Create("a", "b"); + set = ImmutableHashSet.Create(new[] { "a", "b" }); Assert.Equal(2, set.Count); Assert.Same(EqualityComparer.Default, set.KeyComparer); @@ -126,7 +126,7 @@ public void Create() Assert.Equal(2, set.Count); Assert.Same(EqualityComparer.Default, set.KeyComparer); - set = ImmutableHashSet.Create(comparer, "a", "b"); + set = ImmutableHashSet.Create(comparer, new[] { "a", "b" }); Assert.Equal(2, set.Count); Assert.Same(comparer, set.KeyComparer); diff --git a/src/libraries/System.Collections.Immutable/tests/ImmutableListTest.cs b/src/libraries/System.Collections.Immutable/tests/ImmutableListTest.cs index ec569e77699464..7223c1305e9c62 100644 --- a/src/libraries/System.Collections.Immutable/tests/ImmutableListTest.cs +++ b/src/libraries/System.Collections.Immutable/tests/ImmutableListTest.cs @@ -584,7 +584,7 @@ public void Create() list = ImmutableList.Create("a"); Assert.Equal(1, list.Count); - list = ImmutableList.Create("a", "b"); + list = ImmutableList.Create(new[] { "a", "b" }); Assert.Equal(2, list.Count); list = ImmutableList.Create((ReadOnlySpan)new[] { "a", "b" }); diff --git a/src/libraries/System.Collections.Immutable/tests/ImmutableQueueTest.cs b/src/libraries/System.Collections.Immutable/tests/ImmutableQueueTest.cs index c03621929a5990..4aef1b5577a345 100644 --- a/src/libraries/System.Collections.Immutable/tests/ImmutableQueueTest.cs +++ b/src/libraries/System.Collections.Immutable/tests/ImmutableQueueTest.cs @@ -213,7 +213,7 @@ public void Create() Assert.False(queue.IsEmpty); Assert.Equal(new[] { 1 }, queue); - queue = ImmutableQueue.Create(1, 2); + queue = ImmutableQueue.Create(new int[] { 1, 2 }); Assert.False(queue.IsEmpty); Assert.Equal(new[] { 1, 2 }, queue); diff --git a/src/libraries/System.Collections.Immutable/tests/ImmutableSortedSetTest.cs b/src/libraries/System.Collections.Immutable/tests/ImmutableSortedSetTest.cs index eecff21ffb34b7..f16d59dd63ae1b 100644 --- a/src/libraries/System.Collections.Immutable/tests/ImmutableSortedSetTest.cs +++ b/src/libraries/System.Collections.Immutable/tests/ImmutableSortedSetTest.cs @@ -289,7 +289,7 @@ public void Create() Assert.Equal(1, set.Count); Assert.Same(comparer, set.KeyComparer); - set = ImmutableSortedSet.Create("a", "b"); + set = ImmutableSortedSet.Create(new [] { "a", "b" }); Assert.Equal(2, set.Count); Assert.Same(Comparer.Default, set.KeyComparer); @@ -297,7 +297,7 @@ public void Create() Assert.Equal(2, set.Count); Assert.Same(Comparer.Default, set.KeyComparer); - set = ImmutableSortedSet.Create(comparer, "a", "b"); + set = ImmutableSortedSet.Create(comparer, new[] { "a", "b" }); Assert.Equal(2, set.Count); Assert.Same(comparer, set.KeyComparer); diff --git a/src/libraries/System.Collections.Immutable/tests/ImmutableStackTest.cs b/src/libraries/System.Collections.Immutable/tests/ImmutableStackTest.cs index 26336209e12047..4abd031ed43b2d 100644 --- a/src/libraries/System.Collections.Immutable/tests/ImmutableStackTest.cs +++ b/src/libraries/System.Collections.Immutable/tests/ImmutableStackTest.cs @@ -241,7 +241,7 @@ public void Create() Assert.False(stack.IsEmpty); Assert.Equal(new[] { 1 }, stack); - stack = ImmutableStack.Create(1, 2); + stack = ImmutableStack.Create(new[] { 1, 2 }); Assert.False(stack.IsEmpty); Assert.Equal(new[] { 2, 1 }, stack); diff --git a/src/libraries/System.Collections.NonGeneric/src/System.Collections.NonGeneric.csproj b/src/libraries/System.Collections.NonGeneric/src/System.Collections.NonGeneric.csproj index 770e5fc0fc1816..1bc456cd13ba3a 100644 --- a/src/libraries/System.Collections.NonGeneric/src/System.Collections.NonGeneric.csproj +++ b/src/libraries/System.Collections.NonGeneric/src/System.Collections.NonGeneric.csproj @@ -21,6 +21,7 @@ + diff --git a/src/libraries/System.Collections.Specialized/src/System.Collections.Specialized.csproj b/src/libraries/System.Collections.Specialized/src/System.Collections.Specialized.csproj index 21e6fc760efae5..4301d885411c68 100644 --- a/src/libraries/System.Collections.Specialized/src/System.Collections.Specialized.csproj +++ b/src/libraries/System.Collections.Specialized/src/System.Collections.Specialized.csproj @@ -23,6 +23,7 @@ + diff --git a/src/libraries/System.ComponentModel.EventBasedAsync/src/System.ComponentModel.EventBasedAsync.csproj b/src/libraries/System.ComponentModel.EventBasedAsync/src/System.ComponentModel.EventBasedAsync.csproj index 0d413f6fd370ee..a5d9913733b441 100644 --- a/src/libraries/System.ComponentModel.EventBasedAsync/src/System.ComponentModel.EventBasedAsync.csproj +++ b/src/libraries/System.ComponentModel.EventBasedAsync/src/System.ComponentModel.EventBasedAsync.csproj @@ -18,6 +18,7 @@ + diff --git a/src/libraries/System.ComponentModel.Primitives/src/System.ComponentModel.Primitives.csproj b/src/libraries/System.ComponentModel.Primitives/src/System.ComponentModel.Primitives.csproj index 5fcff901309503..2938d1e641264e 100644 --- a/src/libraries/System.ComponentModel.Primitives/src/System.ComponentModel.Primitives.csproj +++ b/src/libraries/System.ComponentModel.Primitives/src/System.ComponentModel.Primitives.csproj @@ -47,6 +47,7 @@ + diff --git a/src/libraries/System.Console/ref/System.Console.cs b/src/libraries/System.Console/ref/System.Console.cs index 273290de2a89f2..7c5ca19cd01ad6 100644 --- a/src/libraries/System.Console/ref/System.Console.cs +++ b/src/libraries/System.Console/ref/System.Console.cs @@ -175,6 +175,7 @@ public static void Write([System.Diagnostics.CodeAnalysis.StringSyntaxAttribute( public static void Write([System.Diagnostics.CodeAnalysis.StringSyntaxAttribute("CompositeFormat")] string format, object? arg0, object? arg1) { } public static void Write([System.Diagnostics.CodeAnalysis.StringSyntaxAttribute("CompositeFormat")] string format, object? arg0, object? arg1, object? arg2) { } public static void Write([System.Diagnostics.CodeAnalysis.StringSyntaxAttribute("CompositeFormat")] string format, params object?[]? arg) { } + public static void Write([System.Diagnostics.CodeAnalysis.StringSyntaxAttribute("CompositeFormat")] string format, System.ReadOnlySpan arg) { } [System.CLSCompliantAttribute(false)] public static void Write(uint value) { } [System.CLSCompliantAttribute(false)] @@ -195,6 +196,7 @@ public static void WriteLine([System.Diagnostics.CodeAnalysis.StringSyntaxAttrib public static void WriteLine([System.Diagnostics.CodeAnalysis.StringSyntaxAttribute("CompositeFormat")] string format, object? arg0, object? arg1) { } public static void WriteLine([System.Diagnostics.CodeAnalysis.StringSyntaxAttribute("CompositeFormat")] string format, object? arg0, object? arg1, object? arg2) { } public static void WriteLine([System.Diagnostics.CodeAnalysis.StringSyntaxAttribute("CompositeFormat")] string format, params object?[]? arg) { } + public static void WriteLine([System.Diagnostics.CodeAnalysis.StringSyntaxAttribute("CompositeFormat")] string format, System.ReadOnlySpan arg) { } [System.CLSCompliantAttribute(false)] public static void WriteLine(uint value) { } [System.CLSCompliantAttribute(false)] diff --git a/src/libraries/System.Console/src/System/Console.cs b/src/libraries/System.Console/src/System/Console.cs index 63736b59741706..5e0e387b8299fb 100644 --- a/src/libraries/System.Console/src/System/Console.cs +++ b/src/libraries/System.Console/src/System/Console.cs @@ -865,6 +865,17 @@ public static void WriteLine([StringSyntax(StringSyntaxAttribute.CompositeFormat Out.WriteLine(format, arg); } + /// + /// Writes the text representation of the specified span of objects, followed by the current line terminator, to the standard output stream using the specified format information. + /// + /// A composite format string. + /// A span of objects to write using format. + [MethodImplAttribute(MethodImplOptions.NoInlining)] + public static void WriteLine([StringSyntax(StringSyntaxAttribute.CompositeFormat)] string format, /*params*/ ReadOnlySpan arg) + { + Out.WriteLine(format, arg); + } + [MethodImplAttribute(MethodImplOptions.NoInlining)] public static void Write([StringSyntax(StringSyntaxAttribute.CompositeFormat)] string format, object? arg0) { @@ -892,6 +903,17 @@ public static void Write([StringSyntax(StringSyntaxAttribute.CompositeFormat)] s Out.Write(format, arg); } + /// + /// Writes the text representation of the specified span of objects to the standard output stream using the specified format information. + /// + /// A composite format string. + /// A span of objects to write using format. + [MethodImplAttribute(MethodImplOptions.NoInlining)] + public static void Write([StringSyntax(StringSyntaxAttribute.CompositeFormat)] string format, /*params*/ ReadOnlySpan arg) + { + Out.Write(format, arg); + } + [MethodImplAttribute(MethodImplOptions.NoInlining)] public static void Write(bool value) { diff --git a/src/libraries/System.Console/tests/ReadAndWrite.cs b/src/libraries/System.Console/tests/ReadAndWrite.cs index 5fbf425fc84855..d60fd6aa34cc04 100644 --- a/src/libraries/System.Console/tests/ReadAndWrite.cs +++ b/src/libraries/System.Console/tests/ReadAndWrite.cs @@ -84,10 +84,14 @@ private static void WriteCore() Console.Write("{0}", null, null); Console.Write("{0} {1} {2}", 32, "Hello", (uint)50); Console.Write("{0}", null, null, null); - Console.Write("{0} {1} {2} {3}", 32, "Hello", (uint)50, (ulong)5); - Console.Write("{0}", null, null, null, null); - Console.Write("{0} {1} {2} {3} {4}", 32, "Hello", (uint)50, (ulong)5, 'a'); - Console.Write("{0}", null, null, null, null, null); + Console.Write("{0} {1} {2} {3}", new object[] { 32, "Hello", (uint)50, (ulong)5 }); + Console.Write("{0} {1} {2} {3}", new object[] { 32, "Hello", (uint)50, (ulong)5 }.AsSpan()); + Console.Write("{0}", new object[] { null, null, null, null }); + Console.Write("{0}", new object[] { null, null, null, null }.AsSpan()); + Console.Write("{0} {1} {2} {3} {4}", new object[] { 32, "Hello", (uint)50, (ulong)5, 'a' }); + Console.Write("{0} {1} {2} {3} {4}", new object[] { 32, "Hello", (uint)50, (ulong)5, 'a' }.AsSpan()); + Console.Write("{0}", new object[] { null, null, null, null, null }); + Console.Write("{0}", new object[] { null, null, null, null, null }.AsSpan()); Console.Write(true); Console.Write('a'); Console.Write(new char[] { 'a', 'b', 'c', 'd', }); @@ -120,10 +124,14 @@ private static void WriteLineCore() Console.WriteLine("{0}", null, null); Console.WriteLine("{0} {1} {2}", 32, "Hello", (uint)50); Console.WriteLine("{0}", null, null, null); - Console.WriteLine("{0} {1} {2} {3}", 32, "Hello", (uint)50, (ulong)5); - Console.WriteLine("{0}", null, null, null, null); - Console.WriteLine("{0} {1} {2} {3} {4}", 32, "Hello", (uint)50, (ulong)5, 'a'); - Console.WriteLine("{0}", null, null, null, null, null); + Console.WriteLine("{0} {1} {2} {3}", new object[] { 32, "Hello", (uint)50, (ulong)5 }); + Console.WriteLine("{0} {1} {2} {3}", new object[] { 32, "Hello", (uint)50, (ulong)5 }.AsSpan()); + Console.WriteLine("{0}", new object[] { null, null, null, null }); + Console.WriteLine("{0}", new object[] { null, null, null, null }.AsSpan()); + Console.WriteLine("{0} {1} {2} {3} {4}", new object[] { 32, "Hello", (uint)50, (ulong)5, 'a' }); + Console.WriteLine("{0} {1} {2} {3} {4}", new object[] { 32, "Hello", (uint)50, (ulong)5, 'a' }.AsSpan()); + Console.WriteLine("{0}", new object[] { null, null, null, null, null }); + Console.WriteLine("{0}", new object[] { null, null, null, null, null }.AsSpan()); Console.WriteLine(true); Console.WriteLine('a'); Console.WriteLine(new char[] { 'a', 'b', 'c', 'd', }); @@ -158,8 +166,10 @@ public static async Task OutWriteAndWriteLineOverloads() writer.Write("{0}", 32); writer.Write("{0} {1}", 32, "Hello"); writer.Write("{0} {1} {2}", 32, "Hello", (uint)50); - writer.Write("{0} {1} {2} {3}", 32, "Hello", (uint)50, (ulong)5); - writer.Write("{0} {1} {2} {3} {4}", 32, "Hello", (uint)50, (ulong)5, 'a'); + writer.Write("{0} {1} {2} {3}", new object[] { 32, "Hello", (uint)50, (ulong)5 }); + writer.Write("{0} {1} {2} {3}", new object[] { 32, "Hello", (uint)50, (ulong)5 }.AsSpan()); + writer.Write("{0} {1} {2} {3} {4}", new object[] { 32, "Hello", (uint)50, (ulong)5, 'a' }); + writer.Write("{0} {1} {2} {3} {4}", new object[] { 32, "Hello", (uint)50, (ulong)5, 'a' }.AsSpan()); writer.Write(true); writer.Write('a'); writer.Write(new char[] { 'a', 'b', 'c', 'd', }); diff --git a/src/libraries/System.Diagnostics.DiagnosticSource/ref/System.Diagnostics.DiagnosticSourceActivity.cs b/src/libraries/System.Diagnostics.DiagnosticSource/ref/System.Diagnostics.DiagnosticSourceActivity.cs index 7cb90d245dcf93..382499070cd1d9 100644 --- a/src/libraries/System.Diagnostics.DiagnosticSource/ref/System.Diagnostics.DiagnosticSourceActivity.cs +++ b/src/libraries/System.Diagnostics.DiagnosticSource/ref/System.Diagnostics.DiagnosticSourceActivity.cs @@ -336,7 +336,7 @@ public sealed class Counter : Instrument where T : struct public void Add(T delta, System.Collections.Generic.KeyValuePair tag) { throw null; } public void Add(T delta, System.Collections.Generic.KeyValuePair tag1, System.Collections.Generic.KeyValuePair tag2) { throw null; } public void Add(T delta, System.Collections.Generic.KeyValuePair tag1, System.Collections.Generic.KeyValuePair tag2, System.Collections.Generic.KeyValuePair tag3) { throw null; } - public void Add(T delta, ReadOnlySpan> tags) { throw null; } + public void Add(T delta, System.ReadOnlySpan> tags) { throw null; } public void Add(T delta, params System.Collections.Generic.KeyValuePair[] tags) { throw null; } public void Add(T delta, in TagList tagList) { throw null; } internal Counter(Meter meter, string name, string? unit, string? description) : @@ -348,7 +348,7 @@ public sealed class UpDownCounter : Instrument where T : struct public void Add(T delta, System.Collections.Generic.KeyValuePair tag) { throw null; } public void Add(T delta, System.Collections.Generic.KeyValuePair tag1, System.Collections.Generic.KeyValuePair tag2) { throw null; } public void Add(T delta, System.Collections.Generic.KeyValuePair tag1, System.Collections.Generic.KeyValuePair tag2, System.Collections.Generic.KeyValuePair tag3) { throw null; } - public void Add(T delta, ReadOnlySpan> tags) { throw null; } + public void Add(T delta, System.ReadOnlySpan> tags) { throw null; } public void Add(T delta, params System.Collections.Generic.KeyValuePair[] tags) { throw null; } public void Add(T delta, in TagList tagList) { throw null; } internal UpDownCounter(Meter meter, string name, string? unit, string? description) : @@ -362,7 +362,7 @@ public sealed class Histogram : Instrument where T : struct public void Record(T value, System.Collections.Generic.KeyValuePair tag1, System.Collections.Generic.KeyValuePair tag2) { throw null; } public void Record(T value, System.Collections.Generic.KeyValuePair tag1, System.Collections.Generic.KeyValuePair tag2, System.Collections.Generic.KeyValuePair tag3) { throw null; } public void Record(T value, in TagList tagList) { throw null; } - public void Record(T value, ReadOnlySpan> tags) { throw null; } + public void Record(T value, System.ReadOnlySpan> tags) { throw null; } public void Record(T value, params System.Collections.Generic.KeyValuePair[] tags) { throw null; } } public interface IMeterFactory : System.IDisposable @@ -398,7 +398,7 @@ public abstract class Instrument : Instrument where T : struct public Measurement(T value) { throw null; } public Measurement(T value, System.Collections.Generic.IEnumerable>? tags) { throw null; } public Measurement(T value, params System.Collections.Generic.KeyValuePair[]? tags) { throw null; } - public Measurement(T value, ReadOnlySpan> tags) { throw null; } + public Measurement(T value, System.ReadOnlySpan> tags) { throw null; } public ReadOnlySpan> Tags { get { throw null; } } public T Value { get { throw null; } } } diff --git a/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/Counter.cs b/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/Counter.cs index 1d311d62196391..9f15ff37c70104 100644 --- a/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/Counter.cs +++ b/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/Counter.cs @@ -59,7 +59,7 @@ internal Counter(Meter meter, string name, string? unit, string? description, IE /// /// The increment measurement. /// A span of key-value pair tags associated with the measurement. - public void Add(T delta, ReadOnlySpan> tags) => RecordMeasurement(delta, tags); + public void Add(T delta, /*params*/ ReadOnlySpan> tags) => RecordMeasurement(delta, tags); /// /// Record the increment value of the measurement. diff --git a/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/Histogram.cs b/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/Histogram.cs index ed3431edfce8be..91f5f40da6e80e 100644 --- a/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/Histogram.cs +++ b/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/Histogram.cs @@ -59,7 +59,7 @@ internal Histogram(Meter meter, string name, string? unit, string? description, /// /// The measurement value. /// A span of key-value pair tags associated with the measurement. - public void Record(T value, ReadOnlySpan> tags) => RecordMeasurement(value, tags); + public void Record(T value, /*params*/ ReadOnlySpan> tags) => RecordMeasurement(value, tags); /// /// Record a measurement value. diff --git a/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/Measurement.cs b/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/Measurement.cs index 49db3c86f8dbf1..f678ef66014ff0 100644 --- a/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/Measurement.cs +++ b/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/Measurement.cs @@ -59,7 +59,7 @@ public Measurement(T value, params KeyValuePair[]? tags) /// /// The measurement value. /// The measurement associated tags list. - public Measurement(T value, ReadOnlySpan> tags) + public Measurement(T value, /*params*/ ReadOnlySpan> tags) { _tags = tags.ToArray(); Value = value; diff --git a/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/TagList.cs b/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/TagList.cs index 7646bcc2d33a46..138da8875aeed6 100644 --- a/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/TagList.cs +++ b/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/TagList.cs @@ -43,7 +43,7 @@ public struct TagList : IList>, IReadOnlyList. /// /// A span of tags to initialize the list with. - public TagList(ReadOnlySpan> tagList) : this() + public TagList(/*params*/ ReadOnlySpan> tagList) : this() { _tagsCount = tagList.Length; switch (_tagsCount) diff --git a/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/UpDownCounter.cs b/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/UpDownCounter.cs index 79d0ed29d8f417..4a093865c5511d 100644 --- a/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/UpDownCounter.cs +++ b/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/UpDownCounter.cs @@ -58,7 +58,7 @@ internal UpDownCounter(Meter meter, string name, string? unit, string? descripti /// /// The amount to be added which can be positive, negative or zero. /// A span of key-value pair tags associated with the measurement. - public void Add(T delta, ReadOnlySpan> tags) => RecordMeasurement(delta, tags); + public void Add(T delta, /*params*/ ReadOnlySpan> tags) => RecordMeasurement(delta, tags); /// /// Record the delta value of the measurement. The delta can be positive, negative or zero. diff --git a/src/libraries/System.Diagnostics.DiagnosticSource/tests/MetricsTests.cs b/src/libraries/System.Diagnostics.DiagnosticSource/tests/MetricsTests.cs index 4a3cd242bb8be0..b292e55f1bcf20 100644 --- a/src/libraries/System.Diagnostics.DiagnosticSource/tests/MetricsTests.cs +++ b/src/libraries/System.Diagnostics.DiagnosticSource/tests/MetricsTests.cs @@ -4,6 +4,7 @@ using Microsoft.DotNet.RemoteExecutor; using System.Collections.Generic; using System.Diagnostics.Metrics; +using System.Diagnostics.Tests; using System.Linq; using System.Threading; using System.Threading.Tasks; @@ -13,6 +14,29 @@ namespace System.Diagnostics.Metrics.Tests { public class MetricsTests { + [Fact] + public void MeasurementConstructionTest() + { + for (int i = 0; i < 30; i++) + { + TagListTests.CreateTagList(i, out TagList tags); + TagListTests.ValidateTags(in tags, i); + KeyValuePair[] tagsArray = tags.ToArray(); + + var measurement = new Measurement(i, tags); + Assert.Equal(i, measurement.Value); + TagListTests.ValidateTags(new TagList(measurement.Tags), tagsArray); + + measurement = new Measurement(i, tagsArray); + Assert.Equal(i, measurement.Value); + TagListTests.ValidateTags(new TagList(measurement.Tags), tagsArray); + + measurement = new Measurement(i, tagsArray.AsSpan()); + Assert.Equal(i, measurement.Value); + TagListTests.ValidateTags(new TagList(measurement.Tags), tagsArray); + } + } + [ConditionalFact(typeof(RemoteExecutor), nameof(RemoteExecutor.IsSupported))] public void MeterConstructionTest() { @@ -238,76 +262,115 @@ public void ThrowingExceptionsFromObservableInstrumentCallbacks() }).Dispose(); } - [ConditionalFact(typeof(RemoteExecutor), nameof(RemoteExecutor.IsSupported))] - public void InstrumentMeasurementTest() + [ConditionalTheory(typeof(RemoteExecutor), nameof(RemoteExecutor.IsSupported))] + [InlineData(false)] + [InlineData(true)] + public void InstrumentMeasurementTest(bool useSpan) { - RemoteExecutor.Invoke(() => { + RemoteExecutor.Invoke((string useSpanStr) => { Meter meter = new Meter("InstrumentMeasurementTest"); + bool useSpan = bool.Parse(useSpanStr); Counter counter = meter.CreateCounter("byteCounter"); - InstrumentMeasurementAggregationValidation(counter, (value, tags) => { counter.Add(value, tags); } ); + InstrumentMeasurementAggregationValidation(counter, (value, tags) => { AddToCounter(counter, value, tags, useSpan); } ); UpDownCounter upDownCounter = meter.CreateUpDownCounter("byteUpDownCounter"); - InstrumentMeasurementAggregationValidation(upDownCounter, (value, tags) => { upDownCounter.Add(value, tags); }); + InstrumentMeasurementAggregationValidation(upDownCounter, (value, tags) => { AddToUpDownCounter(upDownCounter, value, tags, useSpan); }); Counter counter1 = meter.CreateCounter("shortCounter"); - InstrumentMeasurementAggregationValidation(counter1, (value, tags) => { counter1.Add(value, tags); } ); + InstrumentMeasurementAggregationValidation(counter1, (value, tags) => { AddToCounter(counter1, value, tags, useSpan); } ); UpDownCounter upDownCounter1 = meter.CreateUpDownCounter("shortUpDownCounter"); - InstrumentMeasurementAggregationValidation(upDownCounter1, (value, tags) => { upDownCounter1.Add(value, tags); }, true); + InstrumentMeasurementAggregationValidation(upDownCounter1, (value, tags) => { AddToUpDownCounter(upDownCounter1, value, tags, useSpan); }, true); Counter counter2 = meter.CreateCounter("intCounter"); - InstrumentMeasurementAggregationValidation(counter2, (value, tags) => { counter2.Add(value, tags); } ); + InstrumentMeasurementAggregationValidation(counter2, (value, tags) => { AddToCounter(counter2, value, tags, useSpan); } ); UpDownCounter upDownCounter2 = meter.CreateUpDownCounter("intUpDownCounter"); - InstrumentMeasurementAggregationValidation(upDownCounter2, (value, tags) => { upDownCounter2.Add(value, tags); }, true); + InstrumentMeasurementAggregationValidation(upDownCounter2, (value, tags) => { AddToUpDownCounter(upDownCounter2, value, tags, useSpan); }, true); Counter counter3 = meter.CreateCounter("longCounter"); - InstrumentMeasurementAggregationValidation(counter3, (value, tags) => { counter3.Add(value, tags); } ); + InstrumentMeasurementAggregationValidation(counter3, (value, tags) => { AddToCounter(counter3, value, tags, useSpan); } ); UpDownCounter upDownCounter3 = meter.CreateUpDownCounter("longUpDownCounter"); - InstrumentMeasurementAggregationValidation(upDownCounter3, (value, tags) => { upDownCounter3.Add(value, tags); }, true); + InstrumentMeasurementAggregationValidation(upDownCounter3, (value, tags) => { AddToUpDownCounter(upDownCounter3, value, tags, useSpan); }, true); Counter counter4 = meter.CreateCounter("floatCounter"); - InstrumentMeasurementAggregationValidation(counter4, (value, tags) => { counter4.Add(value, tags); } ); + InstrumentMeasurementAggregationValidation(counter4, (value, tags) => { AddToCounter(counter4, value, tags, useSpan); } ); UpDownCounter upDownCounter4 = meter.CreateUpDownCounter("floatUpDownCounter"); - InstrumentMeasurementAggregationValidation(upDownCounter4, (value, tags) => { upDownCounter4.Add(value, tags); }, true); + InstrumentMeasurementAggregationValidation(upDownCounter4, (value, tags) => { AddToUpDownCounter(upDownCounter4, value, tags, useSpan); }, true); Counter counter5 = meter.CreateCounter("doubleCounter"); - InstrumentMeasurementAggregationValidation(counter5, (value, tags) => { counter5.Add(value, tags); } ); + InstrumentMeasurementAggregationValidation(counter5, (value, tags) => { AddToCounter(counter5, value, tags, useSpan); } ); UpDownCounter upDownCounter5 = meter.CreateUpDownCounter("doubleUpDownCounter"); - InstrumentMeasurementAggregationValidation(upDownCounter5, (value, tags) => { upDownCounter5.Add(value, tags); }, true); + InstrumentMeasurementAggregationValidation(upDownCounter5, (value, tags) => { AddToUpDownCounter(upDownCounter5, value, tags, useSpan); }, true); Counter counter6 = meter.CreateCounter("decimalCounter"); - InstrumentMeasurementAggregationValidation(counter6, (value, tags) => { counter6.Add(value, tags); } ); + InstrumentMeasurementAggregationValidation(counter6, (value, tags) => { AddToCounter(counter6, value, tags, useSpan); } ); UpDownCounter upDownCounter6 = meter.CreateUpDownCounter("decimalUpDownCounter"); - InstrumentMeasurementAggregationValidation(upDownCounter6, (value, tags) => { upDownCounter6.Add(value, tags); }, true); + InstrumentMeasurementAggregationValidation(upDownCounter6, (value, tags) => { AddToUpDownCounter(upDownCounter6, value, tags, useSpan); }, true); Histogram histogram = meter.CreateHistogram("byteHistogram"); - InstrumentMeasurementAggregationValidation(histogram, (value, tags) => { histogram.Record(value, tags); } ); + InstrumentMeasurementAggregationValidation(histogram, (value, tags) => { Record(histogram, value, tags, useSpan); } ); Histogram histogram1 = meter.CreateHistogram("shortHistogram"); - InstrumentMeasurementAggregationValidation(histogram1, (value, tags) => { histogram1.Record(value, tags); } ); + InstrumentMeasurementAggregationValidation(histogram1, (value, tags) => { Record(histogram1, value, tags, useSpan); } ); Histogram histogram2 = meter.CreateHistogram("intHistogram"); - InstrumentMeasurementAggregationValidation(histogram2, (value, tags) => { histogram2.Record(value, tags); } ); + InstrumentMeasurementAggregationValidation(histogram2, (value, tags) => { Record(histogram2, value, tags, useSpan); } ); Histogram histogram3 = meter.CreateHistogram("longHistogram"); - InstrumentMeasurementAggregationValidation(histogram3, (value, tags) => { histogram3.Record(value, tags); } ); + InstrumentMeasurementAggregationValidation(histogram3, (value, tags) => { Record(histogram3, value, tags, useSpan); } ); Histogram histogram4 = meter.CreateHistogram("floatHistogram"); - InstrumentMeasurementAggregationValidation(histogram4, (value, tags) => { histogram4.Record(value, tags); } ); + InstrumentMeasurementAggregationValidation(histogram4, (value, tags) => { Record(histogram4, value, tags, useSpan); } ); Histogram histogram5 = meter.CreateHistogram("doubleHistogram"); - InstrumentMeasurementAggregationValidation(histogram5, (value, tags) => { histogram5.Record(value, tags); } ); + InstrumentMeasurementAggregationValidation(histogram5, (value, tags) => { Record(histogram5, value, tags, useSpan); } ); Histogram histogram6 = meter.CreateHistogram("decimalHistogram"); - InstrumentMeasurementAggregationValidation(histogram6, (value, tags) => { histogram6.Record(value, tags); } ); + InstrumentMeasurementAggregationValidation(histogram6, (value, tags) => { Record(histogram6, value, tags, useSpan); } ); - }).Dispose(); + }, useSpan.ToString()).Dispose(); + + void AddToCounter(Counter counter, T delta, KeyValuePair[] tags, bool useSpan) where T : struct + { + if (useSpan) + { + counter.Add(delta, (ReadOnlySpan>)tags); + } + else + { + counter.Add(delta, tags); + } + } + + void AddToUpDownCounter(UpDownCounter upDownCounter, T delta, KeyValuePair[] tags, bool useSpan) where T : struct + { + if (useSpan) + { + upDownCounter.Add(delta, (ReadOnlySpan>)tags); + } + else + { + upDownCounter.Add(delta, tags); + } + } + + void Record(Histogram histogram, T value, KeyValuePair[] tags, bool useSpan) where T : struct + { + if (useSpan) + { + histogram.Record(value, (ReadOnlySpan>)tags); + } + else + { + histogram.Record(value, tags); + } + } } diff --git a/src/libraries/System.Diagnostics.DiagnosticSource/tests/TagListTests.cs b/src/libraries/System.Diagnostics.DiagnosticSource/tests/TagListTests.cs index 9f35cb9d47c027..59edc168186a65 100644 --- a/src/libraries/System.Diagnostics.DiagnosticSource/tests/TagListTests.cs +++ b/src/libraries/System.Diagnostics.DiagnosticSource/tests/TagListTests.cs @@ -3,7 +3,6 @@ using Xunit; using System.Collections.Generic; -using System.Diagnostics; namespace System.Diagnostics.Tests { @@ -21,7 +20,7 @@ public void TestConstruction() KeyValuePair[] array = new KeyValuePair[tagList.Count]; tagList.CopyTo(array); TagList list = new TagList(array.AsSpan()); - ValidateTags(in tagList, i); + ValidateTags(in list, i); } } @@ -303,7 +302,7 @@ public void TestNegativeCases() Assert.Throws(() => list.RemoveAt(2)); } - private void ValidateTags(in TagList tagList, KeyValuePair[] array) + internal static void ValidateTags(in TagList tagList, KeyValuePair[] array) { Assert.True(tagList.Count <= array.Length); for (int i = 0; i < tagList.Count; i++) @@ -313,7 +312,7 @@ private void ValidateTags(in TagList tagList, KeyValuePair[] ar } } - private void ValidateTags(in TagList tagList, int tagsCount) + internal static void ValidateTags(in TagList tagList, int tagsCount) { Assert.Equal(tagsCount, tagList.Count); for (int i = 0; i < tagList.Count; i++) @@ -323,7 +322,7 @@ private void ValidateTags(in TagList tagList, int tagsCount) } } - private void CreateTagList(int tagsCount, out TagList tagList) + internal static void CreateTagList(int tagsCount, out TagList tagList) { tagList = new TagList(); for (int i = 0; i < tagsCount; i++) diff --git a/src/libraries/System.IO.FileSystem.AccessControl/src/System.IO.FileSystem.AccessControl.csproj b/src/libraries/System.IO.FileSystem.AccessControl/src/System.IO.FileSystem.AccessControl.csproj index e120f89518cc3f..03cbd816a2ff71 100644 --- a/src/libraries/System.IO.FileSystem.AccessControl/src/System.IO.FileSystem.AccessControl.csproj +++ b/src/libraries/System.IO.FileSystem.AccessControl/src/System.IO.FileSystem.AccessControl.csproj @@ -95,7 +95,7 @@ - + diff --git a/src/libraries/System.IO.IsolatedStorage/src/System.IO.IsolatedStorage.csproj b/src/libraries/System.IO.IsolatedStorage/src/System.IO.IsolatedStorage.csproj index 3b224099af7611..a11a0d7077cc65 100644 --- a/src/libraries/System.IO.IsolatedStorage/src/System.IO.IsolatedStorage.csproj +++ b/src/libraries/System.IO.IsolatedStorage/src/System.IO.IsolatedStorage.csproj @@ -46,6 +46,7 @@ + diff --git a/src/libraries/System.IO.Pipes.AccessControl/src/System.IO.Pipes.AccessControl.csproj b/src/libraries/System.IO.Pipes.AccessControl/src/System.IO.Pipes.AccessControl.csproj index fcd66e7adf9a64..6e48d964b2744e 100644 --- a/src/libraries/System.IO.Pipes.AccessControl/src/System.IO.Pipes.AccessControl.csproj +++ b/src/libraries/System.IO.Pipes.AccessControl/src/System.IO.Pipes.AccessControl.csproj @@ -19,6 +19,7 @@ Condition="'$(TargetPlatformIdentifier)' == 'windows'" /> + diff --git a/src/libraries/System.Linq.Expressions/src/System.Linq.Expressions.csproj b/src/libraries/System.Linq.Expressions/src/System.Linq.Expressions.csproj index 9213e4c6c944fe..66a070211ddca4 100644 --- a/src/libraries/System.Linq.Expressions/src/System.Linq.Expressions.csproj +++ b/src/libraries/System.Linq.Expressions/src/System.Linq.Expressions.csproj @@ -219,6 +219,7 @@ + diff --git a/src/libraries/System.Linq.Parallel/src/System.Linq.Parallel.csproj b/src/libraries/System.Linq.Parallel/src/System.Linq.Parallel.csproj index 3d7f38289ac0aa..15ff9887505a59 100644 --- a/src/libraries/System.Linq.Parallel/src/System.Linq.Parallel.csproj +++ b/src/libraries/System.Linq.Parallel/src/System.Linq.Parallel.csproj @@ -157,6 +157,7 @@ + diff --git a/src/libraries/System.Linq.Queryable/src/System.Linq.Queryable.csproj b/src/libraries/System.Linq.Queryable/src/System.Linq.Queryable.csproj index 8298f938086124..343028ced1ad2a 100644 --- a/src/libraries/System.Linq.Queryable/src/System.Linq.Queryable.csproj +++ b/src/libraries/System.Linq.Queryable/src/System.Linq.Queryable.csproj @@ -19,6 +19,7 @@ + diff --git a/src/libraries/System.Net.Http.Json/src/System.Net.Http.Json.csproj b/src/libraries/System.Net.Http.Json/src/System.Net.Http.Json.csproj index 4f8e58e36abfbb..ef01da51d137d3 100644 --- a/src/libraries/System.Net.Http.Json/src/System.Net.Http.Json.csproj +++ b/src/libraries/System.Net.Http.Json/src/System.Net.Http.Json.csproj @@ -53,6 +53,7 @@ System.Net.Http.Json.JsonContent + @@ -65,6 +66,7 @@ System.Net.Http.Json.JsonContent + diff --git a/src/libraries/System.ObjectModel/src/System.ObjectModel.csproj b/src/libraries/System.ObjectModel/src/System.ObjectModel.csproj index 1a8f23c29c492b..0ef93fda9ecd4b 100644 --- a/src/libraries/System.ObjectModel/src/System.ObjectModel.csproj +++ b/src/libraries/System.ObjectModel/src/System.ObjectModel.csproj @@ -33,6 +33,7 @@ + diff --git a/src/libraries/System.Private.CoreLib/src/System/CodeDom/Compiler/IndentedTextWriter.cs b/src/libraries/System.Private.CoreLib/src/System/CodeDom/Compiler/IndentedTextWriter.cs index 22ee77a8cc6e64..43608b97f78ff1 100644 --- a/src/libraries/System.Private.CoreLib/src/System/CodeDom/Compiler/IndentedTextWriter.cs +++ b/src/libraries/System.Private.CoreLib/src/System/CodeDom/Compiler/IndentedTextWriter.cs @@ -174,6 +174,17 @@ public override void Write([StringSyntax(StringSyntaxAttribute.CompositeFormat)] _writer.Write(format, arg); } + /// + /// Writes out a formatted string, using the same semantics as specified. + /// + /// The formatting string to use. + /// The argument span to output. + public override void Write([StringSyntax(StringSyntaxAttribute.CompositeFormat)] string format, /*params*/ ReadOnlySpan arg) + { + OutputTabs(); + _writer.Write(format, arg); + } + /// /// Asynchronously writes the specified to the underlying , inserting /// tabs at the start of every line. @@ -352,6 +363,18 @@ public override void WriteLine([StringSyntax(StringSyntaxAttribute.CompositeForm _tabsPending = true; } + /// + /// Writes out a formatted string, followed by a line terminator, using the same semantics as specified. + /// + /// The formatting string to use. + /// The argument span to output. + public override void WriteLine([StringSyntax(StringSyntaxAttribute.CompositeFormat)] string format, /*params*/ ReadOnlySpan arg) + { + OutputTabs(); + _writer.WriteLine(format, arg); + _tabsPending = true; + } + [CLSCompliant(false)] public override void WriteLine(uint value) { diff --git a/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/CollectionExtensions.cs b/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/CollectionExtensions.cs index 068536049a65f9..6c7949eed7bf74 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/CollectionExtensions.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/CollectionExtensions.cs @@ -82,7 +82,7 @@ public static ReadOnlyDictionary AsReadOnly(this IDi /// The list to which the elements should be added. /// The span whose elements should be added to the end of the . /// The is null. - public static void AddRange(this List list, ReadOnlySpan source) + public static void AddRange(this List list, /*params*/ ReadOnlySpan source) { if (list is null) { @@ -109,7 +109,7 @@ public static void AddRange(this List list, ReadOnlySpan source) /// The span whose elements should be added to the . /// The is null. /// is less than 0 or greater than 's . - public static void InsertRange(this List list, int index, ReadOnlySpan source) + public static void InsertRange(this List list, int index, /*params*/ ReadOnlySpan source) { if (list is null) { diff --git a/src/libraries/System.Private.CoreLib/src/System/Delegate.cs b/src/libraries/System.Private.CoreLib/src/System/Delegate.cs index d24059770d5f88..cc8a66e341b529 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Delegate.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Delegate.cs @@ -23,14 +23,30 @@ public abstract partial class Delegate : ICloneable, ISerializable return a.CombineImpl(b); } - public static Delegate? Combine(params Delegate?[]? delegates) + public static Delegate? Combine(params Delegate?[]? delegates) => + Combine((ReadOnlySpan)delegates); + + /// + /// Concatenates the invocation lists of an span of delegates. + /// + /// The span of delegates to combine. + /// + /// A new delegate with an invocation list that concatenates the invocation lists of the delegates in the span. + /// Returns if is , + /// if contains zero elements, or if every entry in is . + /// + public static Delegate? Combine(/*params*/ ReadOnlySpan delegates) { - if (delegates == null || delegates.Length == 0) - return null; + Delegate? d = null; - Delegate? d = delegates[0]; - for (int i = 1; i < delegates.Length; i++) - d = Combine(d, delegates[i]); + if (!delegates.IsEmpty) + { + d = delegates[0]; + for (int i = 1; i < delegates.Length; i++) + { + d = Combine(d, delegates[i]); + } + } return d; } diff --git a/src/libraries/System.Private.CoreLib/src/System/IO/Path.cs b/src/libraries/System.Private.CoreLib/src/System/IO/Path.cs index 9d1dced98c8c0b..e6cc976336bbfd 100644 --- a/src/libraries/System.Private.CoreLib/src/System/IO/Path.cs +++ b/src/libraries/System.Private.CoreLib/src/System/IO/Path.cs @@ -371,7 +371,16 @@ public static string Combine(string path1, string path2, string path3, string pa public static string Combine(params string[] paths) { ArgumentNullException.ThrowIfNull(paths); + return Combine((ReadOnlySpan)paths); + } + /// + /// Combines a span of strings into a path. + /// + /// A span of parts of the path. + /// The combined paths. + public static string Combine(/*params*/ ReadOnlySpan paths) + { int maxSize = 0; int firstComponent = 0; @@ -520,8 +529,17 @@ public static string Join(string? path1, string? path2, string? path3, string? p public static string Join(params string?[] paths) { ArgumentNullException.ThrowIfNull(paths); + return Join((ReadOnlySpan)paths); + } - if (paths.Length == 0) + /// + /// Concatenates a span of paths into a single path. + /// + /// A span of paths. + /// The concatenated path. + public static string Join(/*params*/ ReadOnlySpan paths) + { + if (paths.IsEmpty) { return string.Empty; } diff --git a/src/libraries/System.Private.CoreLib/src/System/IO/StreamWriter.cs b/src/libraries/System.Private.CoreLib/src/System/IO/StreamWriter.cs index d11c1313ba84d4..947c803d6d2747 100644 --- a/src/libraries/System.Private.CoreLib/src/System/IO/StreamWriter.cs +++ b/src/libraries/System.Private.CoreLib/src/System/IO/StreamWriter.cs @@ -568,6 +568,23 @@ public override void Write([StringSyntax(StringSyntaxAttribute.CompositeFormat)] } } + /// + /// Writes a formatted string to the stream, using the same semantics as . + /// + /// A composite format string. + /// An object span that contains zero or more objects to format and write. + public override void Write([StringSyntax(StringSyntaxAttribute.CompositeFormat)] string format, /*params*/ ReadOnlySpan arg) + { + if (GetType() == typeof(StreamWriter)) + { + WriteFormatHelper(format, arg, appendNewLine: false); + } + else + { + base.Write(format, arg); + } + } + public override void WriteLine([StringSyntax(StringSyntaxAttribute.CompositeFormat)] string format, object? arg0) { if (GetType() == typeof(StreamWriter)) @@ -619,6 +636,23 @@ public override void WriteLine([StringSyntax(StringSyntaxAttribute.CompositeForm } } + /// + /// Writes out a formatted string and a new line to the stream, using the same semantics as . + /// + /// A composite format string. + /// An object span that contains zero or more objects to format and write. + public override void WriteLine([StringSyntax(StringSyntaxAttribute.CompositeFormat)] string format, /*params*/ ReadOnlySpan arg) + { + if (GetType() == typeof(StreamWriter)) + { + WriteFormatHelper(format, arg, appendNewLine: true); + } + else + { + base.WriteLine(format, arg); + } + } + public override Task WriteAsync(char value) { // If we have been inherited into a subclass, the following implementation could be incorrect diff --git a/src/libraries/System.Private.CoreLib/src/System/IO/TextWriter.CreateBroadcasting.cs b/src/libraries/System.Private.CoreLib/src/System/IO/TextWriter.CreateBroadcasting.cs index 41fdf7eb56f964..82c9d6edd619d5 100644 --- a/src/libraries/System.Private.CoreLib/src/System/IO/TextWriter.CreateBroadcasting.cs +++ b/src/libraries/System.Private.CoreLib/src/System/IO/TextWriter.CreateBroadcasting.cs @@ -268,6 +268,14 @@ public override void Write([StringSyntax(StringSyntaxAttribute.CompositeFormat)] } } + public override void Write([StringSyntax(StringSyntaxAttribute.CompositeFormat)] string format, /*params*/ ReadOnlySpan arg) + { + foreach (TextWriter writer in _writers) + { + writer.Write(format, arg); + } + } + public override void WriteLine() { foreach (TextWriter writer in _writers) @@ -428,6 +436,14 @@ public override void WriteLine([StringSyntax(StringSyntaxAttribute.CompositeForm } } + public override void WriteLine([StringSyntax(StringSyntaxAttribute.CompositeFormat)] string format, /*params*/ ReadOnlySpan arg) + { + foreach (TextWriter writer in _writers) + { + writer.WriteLine(format, arg); + } + } + public override async Task WriteAsync(char value) { foreach (TextWriter writer in _writers) diff --git a/src/libraries/System.Private.CoreLib/src/System/IO/TextWriter.cs b/src/libraries/System.Private.CoreLib/src/System/IO/TextWriter.cs index 289ec5fac7a5e8..27a73516d4be96 100644 --- a/src/libraries/System.Private.CoreLib/src/System/IO/TextWriter.cs +++ b/src/libraries/System.Private.CoreLib/src/System/IO/TextWriter.cs @@ -317,6 +317,16 @@ public virtual void Write([StringSyntax(StringSyntaxAttribute.CompositeFormat)] Write(string.Format(FormatProvider, format, arg)); } + /// + /// Writes a formatted string to the text stream, using the same semantics as . + /// + /// A composite format string. + /// An object span that contains zero or more objects to format and write. + public virtual void Write([StringSyntax(StringSyntaxAttribute.CompositeFormat)] string format, /*params*/ ReadOnlySpan arg) + { + Write(string.Format(FormatProvider, format, arg)); + } + // Writes a line terminator to the text stream. The default line terminator // is Environment.NewLine, but this value can be changed by setting the NewLine property. // @@ -514,6 +524,16 @@ public virtual void WriteLine([StringSyntax(StringSyntaxAttribute.CompositeForma WriteLine(string.Format(FormatProvider, format, arg)); } + /// + /// Writes out a formatted string and a new line to the text stream, using the same semantics as . + /// + /// A composite format string. + /// An object span that contains zero or more objects to format and write. + public virtual void WriteLine([StringSyntax(StringSyntaxAttribute.CompositeFormat)] string format, /*params*/ ReadOnlySpan arg) + { + WriteLine(string.Format(FormatProvider, format, arg)); + } + #region Task based Async APIs public virtual Task WriteAsync(char value) => Task.Factory.StartNew(static state => @@ -700,6 +720,7 @@ public override void Write([StringSyntax(StringSyntaxAttribute.CompositeFormat)] public override void Write([StringSyntax(StringSyntaxAttribute.CompositeFormat)] string format, object? arg0, object? arg1) { } public override void Write([StringSyntax(StringSyntaxAttribute.CompositeFormat)] string format, object? arg0, object? arg1, object? arg2) { } public override void Write([StringSyntax(StringSyntaxAttribute.CompositeFormat)] string format, params object?[] arg) { } + public override void Write([StringSyntax(StringSyntaxAttribute.CompositeFormat)] string format, /*params*/ ReadOnlySpan arg) { } public override Task WriteAsync(char value) => Task.CompletedTask; public override Task WriteAsync(string? value) => Task.CompletedTask; public override Task WriteAsync(StringBuilder? value, CancellationToken cancellationToken = default) => Task.CompletedTask; @@ -725,6 +746,7 @@ public override void WriteLine([StringSyntax(StringSyntaxAttribute.CompositeForm public override void WriteLine([StringSyntax(StringSyntaxAttribute.CompositeFormat)] string format, object? arg0, object? arg1) { } public override void WriteLine([StringSyntax(StringSyntaxAttribute.CompositeFormat)] string format, object? arg0, object? arg1, object? arg2) { } public override void WriteLine([StringSyntax(StringSyntaxAttribute.CompositeFormat)] string format, params object?[] arg) { } + public override void WriteLine([StringSyntax(StringSyntaxAttribute.CompositeFormat)] string format, /*params*/ ReadOnlySpan arg) { } public override Task WriteLineAsync(char value) => Task.CompletedTask; public override Task WriteLineAsync(string? value) => Task.CompletedTask; public override Task WriteLineAsync(StringBuilder? value, CancellationToken cancellationToken = default) => Task.CompletedTask; @@ -833,6 +855,9 @@ protected override void Dispose(bool disposing) [MethodImpl(MethodImplOptions.Synchronized)] public override void Write([StringSyntax(StringSyntaxAttribute.CompositeFormat)] string format, object?[] arg) => _out.Write(format, arg); + [MethodImpl(MethodImplOptions.Synchronized)] + public override void Write([StringSyntax(StringSyntaxAttribute.CompositeFormat)] string format, ReadOnlySpan arg) => _out.Write(format, arg); + [MethodImpl(MethodImplOptions.Synchronized)] public override void WriteLine() => _out.WriteLine(); @@ -893,6 +918,9 @@ protected override void Dispose(bool disposing) [MethodImpl(MethodImplOptions.Synchronized)] public override void WriteLine([StringSyntax(StringSyntaxAttribute.CompositeFormat)] string format, object?[] arg) => _out.WriteLine(format, arg); + [MethodImpl(MethodImplOptions.Synchronized)] + public override void WriteLine([StringSyntax(StringSyntaxAttribute.CompositeFormat)] string format, ReadOnlySpan arg) => _out.WriteLine(format, arg); + // // On SyncTextWriter all APIs should run synchronously, even the async ones. // diff --git a/src/libraries/System.Private.CoreLib/src/System/MemoryExtensions.cs b/src/libraries/System.Private.CoreLib/src/System/MemoryExtensions.cs index 50a0d5b19d5acd..d3c9e28cb0ccda 100644 --- a/src/libraries/System.Private.CoreLib/src/System/MemoryExtensions.cs +++ b/src/libraries/System.Private.CoreLib/src/System/MemoryExtensions.cs @@ -4173,7 +4173,7 @@ public static bool TryWrite(this Span destination, IFormatProvider? provid /// if the entire interpolated string could be formatted successfully; otherwise, . /// is null. /// The index of a format item is greater than or equal to the number of supplied arguments. - public static bool TryWrite(this Span destination, IFormatProvider? provider, CompositeFormat format, out int charsWritten, ReadOnlySpan args) + public static bool TryWrite(this Span destination, IFormatProvider? provider, CompositeFormat format, out int charsWritten, /*params*/ ReadOnlySpan args) { ArgumentNullException.ThrowIfNull(format); format.ValidateNumberOfArgs(args.Length); diff --git a/src/libraries/System.Private.CoreLib/src/System/String.Manipulation.cs b/src/libraries/System.Private.CoreLib/src/System/String.Manipulation.cs index 7f4f642526d451..596e743ebe215d 100644 --- a/src/libraries/System.Private.CoreLib/src/System/String.Manipulation.cs +++ b/src/libraries/System.Private.CoreLib/src/System/String.Manipulation.cs @@ -62,10 +62,19 @@ public static string Concat(object? arg0, object? arg1, object? arg2) => public static string Concat(params object?[] args) { ArgumentNullException.ThrowIfNull(args); + return Concat((ReadOnlySpan)args); + } + /// + /// Concatenates the string representations of the elements in a specified span of objects. + /// + /// A span of objects that contains the elements to concatenate. + /// The concatenated string representations of the values of the elements in . + public static string Concat(/*params*/ ReadOnlySpan args) + { if (args.Length <= 1) { - return args.Length == 0 ? + return args.IsEmpty ? Empty : args[0]?.ToString() ?? Empty; } @@ -355,10 +364,19 @@ internal static string Concat(ReadOnlySpan str0, ReadOnlySpan str1, public static string Concat(params string?[] values) { ArgumentNullException.ThrowIfNull(values); + return Concat((ReadOnlySpan)values); + } + /// + /// Concatenates the elements of a specified span of . + /// + /// A span of instances. + /// The concatenated elements of . + public static string Concat(/*params*/ ReadOnlySpan values) + { if (values.Length <= 1) { - return values.Length == 0 ? + return values.IsEmpty ? Empty : values[0] ?? Empty; } @@ -416,7 +434,7 @@ public static string Concat(params string?[] values) // something changed concurrently to mutate the input array: fall back to // doing the concatenation again, but this time with a defensive copy. This // fall back should be extremely rare. - return copiedLength == totalLength ? result : Concat((string?[])values.Clone()); + return copiedLength == totalLength ? result : Concat((ReadOnlySpan)values.ToArray()); } public static string Format([StringSyntax(StringSyntaxAttribute.CompositeFormat)] string format, object? arg0) @@ -445,6 +463,17 @@ public static string Format([StringSyntax(StringSyntaxAttribute.CompositeFormat) ArgumentNullException.Throw(format is null ? nameof(format) : nameof(args)); } + return FormatHelper(null, format, (ReadOnlySpan)args); + } + + /// + /// Replaces the format item in a specified string with the string representation of a corresponding object in a specified span. + /// + /// A composite format string. + /// An object span that contains zero or more objects to format. + /// A copy of in which the format items have been replaced by the string representation of the corresponding objects in . + public static string Format([StringSyntax(StringSyntaxAttribute.CompositeFormat)] string format, /*params*/ ReadOnlySpan args) + { return FormatHelper(null, format, args); } @@ -474,6 +503,19 @@ public static string Format(IFormatProvider? provider, [StringSyntax(StringSynta ArgumentNullException.Throw(format is null ? nameof(format) : nameof(args)); } + return FormatHelper(provider, format, (ReadOnlySpan)args); + } + + /// + /// Replaces the format items in a string with the string representations of corresponding objects in a specified span. + /// A parameter supplies culture-specific formatting information. + /// + /// An object that supplies culture-specific formatting information. + /// A composite format string. + /// An object span that contains zero or more objects to format. + /// A copy of in which the format items have been replaced by the string representation of the corresponding objects in . + public static string Format(IFormatProvider? provider, [StringSyntax(StringSyntaxAttribute.CompositeFormat)] string format, /*params*/ ReadOnlySpan args) + { return FormatHelper(provider, format, args); } @@ -575,7 +617,7 @@ public static string Format(IFormatProvider? provider, CompositeFormat format, p /// The formatted string. /// is null. /// The index of a format item is greater than or equal to the number of supplied arguments. - public static string Format(IFormatProvider? provider, CompositeFormat format, ReadOnlySpan args) + public static string Format(IFormatProvider? provider, CompositeFormat format, /*params*/ ReadOnlySpan args) { ArgumentNullException.ThrowIfNull(format); format.ValidateNumberOfArgs(args.Length); @@ -669,6 +711,21 @@ public static string Join(char separator, params string?[] value) return JoinCore(new ReadOnlySpan(in separator), new ReadOnlySpan(value)); } + /// + /// Concatenates a span of strings, using the specified separator between each member. + /// + /// The character to use as a separator. is included in the returned string only if has more than one element. + /// A span that contains the elements to concatenate. + /// + /// A string that consists of the elements of delimited by the string. + /// -or- + /// if has zero elements. + /// + public static string Join(char separator, /*params*/ ReadOnlySpan value) + { + return JoinCore(new ReadOnlySpan(in separator), value); + } + public static string Join(string? separator, params string?[] value) { if (value == null) @@ -679,6 +736,21 @@ public static string Join(string? separator, params string?[] value) return JoinCore(separator.AsSpan(), new ReadOnlySpan(value)); } + /// + /// Concatenates a span of strings, using the specified separator between each member. + /// + /// The string to use as a separator. is included in the returned string only if has more than one element. + /// A span that contains the elements to concatenate. + /// + /// A string that consists of the elements of delimited by the string. + /// -or- + /// if has zero elements. + /// + public static string Join(string? separator, /*params*/ ReadOnlySpan value) + { + return JoinCore(separator.AsSpan(), value); + } + public static string Join(char separator, string?[] value, int startIndex, int count) => JoinCore(new ReadOnlySpan(in separator), value, startIndex, count); @@ -743,20 +815,55 @@ public static string Join(string? separator, IEnumerable values) } } - public static string Join(char separator, params object?[] values) => - JoinCore(new ReadOnlySpan(in separator), values); + public static string Join(char separator, params object?[] values) + { + if (values == null) + { + ThrowHelper.ThrowArgumentNullException(ExceptionArgument.values); + } - public static string Join(string? separator, params object?[] values) => - JoinCore(separator.AsSpan(), values); + return JoinCore(new ReadOnlySpan(in separator), (ReadOnlySpan)values); + } - private static string JoinCore(ReadOnlySpan separator, object?[] values) + /// + /// Concatenates the string representations of a span of objects, using the specified separator between each member. + /// + /// The character to use as a separator. is included in the returned string only if value has more than one element. + /// A span of objects whose string representations will be concatenated. + /// + /// A string that consists of the elements of delimited by the character. + /// -or- + /// if has zero elements. + /// + public static string Join(char separator, /*params*/ ReadOnlySpan values) => + JoinCore(new ReadOnlySpan(in separator), values); + + public static string Join(string? separator, params object?[] values) { if (values == null) { ThrowHelper.ThrowArgumentNullException(ExceptionArgument.values); } - if (values.Length == 0) + return JoinCore(separator.AsSpan(), (ReadOnlySpan)values); + } + + /// + /// Concatenates the string representations of a span of objects, using the specified separator between each member. + /// + /// The string to use as a separator. is included in the returned string only if has more than one element. + /// A span of objects whose string representations will be concatenated. + /// + /// A string that consists of the elements of delimited by the string. + /// -or- + /// if has zero elements. + /// + public static string Join(string? separator, /*params*/ ReadOnlySpan values) => + JoinCore(separator.AsSpan(), values); + + private static string JoinCore(ReadOnlySpan separator, ReadOnlySpan values) + { + if (values.IsEmpty) { return Empty; } @@ -793,11 +900,16 @@ public static string Join(string? separator, IEnumerable values) => private static string JoinCore(ReadOnlySpan separator, IEnumerable values) { + if (values is null) + { + ThrowHelper.ThrowArgumentNullException(ExceptionArgument.values); + } + if (typeof(T) == typeof(string)) { - if (values is List valuesList) + if (values.GetType() == typeof(List)) // avoid accidentally bypassing a derived type's reimplementation of IEnumerable { - return JoinCore(separator, CollectionsMarshal.AsSpan(valuesList)); + return JoinCore(separator, CollectionsMarshal.AsSpan(Unsafe.As>(values))); } if (values is string?[] valuesArray) @@ -806,11 +918,6 @@ private static string JoinCore(ReadOnlySpan separator, IEnumerable v } } - if (values == null) - { - ThrowHelper.ThrowArgumentNullException(ExceptionArgument.values); - } - using (IEnumerator e = values.GetEnumerator()) { if (!e.MoveNext()) @@ -1548,6 +1655,16 @@ public string[] Split(params char[]? separator) return SplitInternal(separator, int.MaxValue, StringSplitOptions.None); } + /// + /// Splits a string into substrings based on specified delimiting characters. + /// + /// A span of delimiting characters, or an empty span that contains no delimiters. + /// An array whose elements contain the substrings from this instance that are delimited by one or more characters in . + public string[] Split(/*params*/ ReadOnlySpan separator) + { + return SplitInternal(separator, int.MaxValue, StringSplitOptions.None); + } + // Creates an array of strings by splitting this string at each // occurrence of a separator. The separator is searched for, and if found, // the substring preceding the occurrence is stored as the first element in @@ -2241,6 +2358,28 @@ public unsafe string Trim(params char[]? trimChars) } } + /// + /// Removes all leading and trailing occurrences of a set of characters specified in a span from the current string. + /// + /// A span of Unicode characters to remove. + /// + /// The string that remains after all occurrences of the characters in the parameter are removed from the start and end of the current string. + /// If is empty, white-space characters are removed instead. + /// If no characters can be trimmed from the current instance, the method returns the current instance unchanged. + /// + public unsafe string Trim(/*params*/ ReadOnlySpan trimChars) + { + if (trimChars.IsEmpty) + { + return TrimWhiteSpaceHelper(TrimType.Both); + } + + fixed (char* pTrimChars = &MemoryMarshal.GetReference(trimChars)) + { + return TrimHelper(pTrimChars, trimChars.Length, TrimType.Both); + } + } + // Removes a set of characters from the beginning of this string. public string TrimStart() => TrimWhiteSpaceHelper(TrimType.Head); @@ -2260,6 +2399,28 @@ public unsafe string TrimStart(params char[]? trimChars) } } + /// + /// Removes all the leading occurrences of a set of characters specified in a span from the current string. + /// + /// A span of Unicode characters to remove. + /// + /// The string that remains after all occurrences of characters in the parameter are removed from the start of the current string. + /// If is empty, white-space characters are removed instead. + /// If no characters can be trimmed from the current instance, the method returns the current instance unchanged. + /// + public unsafe string TrimStart(/*params*/ ReadOnlySpan trimChars) + { + if (trimChars.IsEmpty) + { + return TrimWhiteSpaceHelper(TrimType.Head); + } + + fixed (char* pTrimChars = &MemoryMarshal.GetReference(trimChars)) + { + return TrimHelper(pTrimChars, trimChars.Length, TrimType.Head); + } + } + // Removes a set of characters from the end of this string. public string TrimEnd() => TrimWhiteSpaceHelper(TrimType.Tail); @@ -2279,6 +2440,28 @@ public unsafe string TrimEnd(params char[]? trimChars) } } + /// + /// Removes all the trailing occurrences of a set of characters specified in a span from the current string. + /// + /// A span of Unicode characters to remove. + /// + /// The string that remains after all occurrences of characters in the parameter are removed from the end of the current string. + /// If is empty, white-space characters are removed instead. + /// If no characters can be trimmed from the current instance, the method returns the current instance unchanged. + /// + public unsafe string TrimEnd(/*params*/ ReadOnlySpan trimChars) + { + if (trimChars.IsEmpty) + { + return TrimWhiteSpaceHelper(TrimType.Tail); + } + + fixed (char* pTrimChars = &trimChars[0]) + { + return TrimHelper(pTrimChars, trimChars.Length, TrimType.Tail); + } + } + private string TrimWhiteSpaceHelper(TrimType trimType) { // end will point to the first non-trimmed character on the right. diff --git a/src/libraries/System.Private.CoreLib/src/System/Text/StringBuilder.cs b/src/libraries/System.Private.CoreLib/src/System/Text/StringBuilder.cs index 6f7b0abfa9b91f..e7bee231dbf45d 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Text/StringBuilder.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Text/StringBuilder.cs @@ -1123,6 +1123,24 @@ public StringBuilder Append(ReadOnlySpan value) #region AppendJoin public StringBuilder AppendJoin(string? separator, params object?[] values) + { + if (values is null) + { + ThrowHelper.ThrowArgumentNullException(ExceptionArgument.values); + } + + separator ??= string.Empty; + return AppendJoinCore(ref separator.GetRawStringData(), separator.Length, values); + } + + /// + /// Concatenates the string representations of the elements in the provided span of objects, using the specified separator between each member, + /// then appends the result to the current instance of the string builder. + /// + /// The string to use as a separator. is included in the joined strings only if has more than one element. + /// A span that contains the strings to concatenate and append to the current instance of the string builder. + /// A reference to this instance after the append operation has completed. + public StringBuilder AppendJoin(string? separator, /*params*/ ReadOnlySpan values) { separator ??= string.Empty; return AppendJoinCore(ref separator.GetRawStringData(), separator.Length, values); @@ -1130,11 +1148,34 @@ public StringBuilder AppendJoin(string? separator, params object?[] values) public StringBuilder AppendJoin(string? separator, IEnumerable values) { + if (values is null) + { + ThrowHelper.ThrowArgumentNullException(ExceptionArgument.values); + } + separator ??= string.Empty; return AppendJoinCore(ref separator.GetRawStringData(), separator.Length, values); } public StringBuilder AppendJoin(string? separator, params string?[] values) + { + if (values is null) + { + ThrowHelper.ThrowArgumentNullException(ExceptionArgument.values); + } + + separator ??= string.Empty; + return AppendJoinCore(ref separator.GetRawStringData(), separator.Length, values); + } + + /// + /// Concatenates the strings of the provided span, using the specified separator between each string, + /// then appends the result to the current instance of the string builder. + /// + /// The string to use as a separator. is included in the joined strings only if has more than one element. + /// A span that contains the strings to concatenate and append to the current instance of the string builder. + /// A reference to this instance after the append operation has completed. + public StringBuilder AppendJoin(string? separator, /*params*/ ReadOnlySpan values) { separator ??= string.Empty; return AppendJoinCore(ref separator.GetRawStringData(), separator.Length, values); @@ -1142,30 +1183,60 @@ public StringBuilder AppendJoin(string? separator, params string?[] values) public StringBuilder AppendJoin(char separator, params object?[] values) { - return AppendJoinCore(ref separator, 1, values); + if (values is null) + { + ThrowHelper.ThrowArgumentNullException(ExceptionArgument.values); + } + + return AppendJoinCore(ref separator, 1, (ReadOnlySpan)values); } + /// + /// Concatenates the string representations of the elements in the provided span of objects, using the specified char separator between each member, + /// then appends the result to the current instance of the string builder. + /// + /// The character to use as a separator. is included in the joined strings only if has more than one element. + /// A span that contains the strings to concatenate and append to the current instance of the string builder. + /// A reference to this instance after the append operation has completed. + public StringBuilder AppendJoin(char separator, /*params*/ ReadOnlySpan values) => + AppendJoinCore(ref separator, 1, values); + public StringBuilder AppendJoin(char separator, IEnumerable values) { + if (values is null) + { + ThrowHelper.ThrowArgumentNullException(ExceptionArgument.values); + } + return AppendJoinCore(ref separator, 1, values); } public StringBuilder AppendJoin(char separator, params string?[] values) { - return AppendJoinCore(ref separator, 1, values); + if (values is null) + { + ThrowHelper.ThrowArgumentNullException(ExceptionArgument.values); + } + + return AppendJoinCore(ref separator, 1, (ReadOnlySpan)values); } + /// + /// Concatenates the strings of the provided span, using the specified char separator between each string, + /// then appends the result to the current instance of the string builder. + /// + /// The character to use as a separator. is included in the joined strings only if has more than one element. + /// A span that contains the strings to concatenate and append to the current instance of the string builder. + /// A reference to this instance after the append operation has completed. + public StringBuilder AppendJoin(char separator, /*params*/ ReadOnlySpan values) => + AppendJoinCore(ref separator, 1, values); + private StringBuilder AppendJoinCore(ref char separator, int separatorLength, IEnumerable values) { + Debug.Assert(values != null); Debug.Assert(!Unsafe.IsNullRef(ref separator)); Debug.Assert(separatorLength >= 0); - if (values == null) - { - ThrowHelper.ThrowArgumentNullException(ExceptionArgument.values); - } - - Debug.Assert(values != null); using (IEnumerator en = values.GetEnumerator()) { if (!en.MoveNext()) @@ -1192,15 +1263,9 @@ private StringBuilder AppendJoinCore(ref char separator, int separatorLength, return this; } - private StringBuilder AppendJoinCore(ref char separator, int separatorLength, T[] values) + private StringBuilder AppendJoinCore(ref char separator, int separatorLength, ReadOnlySpan values) { - if (values == null) - { - ThrowHelper.ThrowArgumentNullException(ExceptionArgument.values); - } - - Debug.Assert(values != null); - if (values.Length == 0) + if (values.IsEmpty) { return this; } @@ -1360,19 +1425,19 @@ private StringBuilder InsertSpanFormattable(int index, T value) where T : ISp public StringBuilder AppendFormat([StringSyntax(StringSyntaxAttribute.CompositeFormat)] string format, object? arg0) { - return AppendFormatHelper(null, format, new ReadOnlySpan(in arg0)); + return AppendFormat(null, format, new ReadOnlySpan(in arg0)); } public StringBuilder AppendFormat([StringSyntax(StringSyntaxAttribute.CompositeFormat)] string format, object? arg0, object? arg1) { TwoObjects two = new TwoObjects(arg0, arg1); - return AppendFormatHelper(null, format, two); + return AppendFormat(null, format, (ReadOnlySpan)two); } public StringBuilder AppendFormat([StringSyntax(StringSyntaxAttribute.CompositeFormat)] string format, object? arg0, object? arg1, object? arg2) { ThreeObjects three = new ThreeObjects(arg0, arg1, arg2); - return AppendFormatHelper(null, format, three); + return AppendFormat(null, format, (ReadOnlySpan)three); } public StringBuilder AppendFormat([StringSyntax(StringSyntaxAttribute.CompositeFormat)] string format, params object?[] args) @@ -1380,28 +1445,47 @@ public StringBuilder AppendFormat([StringSyntax(StringSyntaxAttribute.CompositeF if (args is null) { // To preserve the original exception behavior, throw an exception about format if both - // args and format are null. The actual null check for format is in AppendFormatHelper. + // args and format are null. The actual null check for format is in AppendFormat(..., span). ArgumentNullException.Throw(format is null ? nameof(format) : nameof(args)); } - return AppendFormatHelper(null, format, args); + return AppendFormat(null, format, args); + } + + /// + /// Appends the string returned by processing a composite format string, which contains zero or more format items, to this instance. + /// Each format item is replaced by the string representation of a corresponding argument in a parameter span. + /// + /// A composite format string. + /// A span of objects to format. + /// A reference to this instance after the append operation has completed. + /// is null. + /// The length of the expanded string would exceed . + /// + /// is invalid. + /// -or- + /// The index of a format item is less than 0 (zero), or greater than or equal to the length of the span. + /// + public StringBuilder AppendFormat([StringSyntax(StringSyntaxAttribute.CompositeFormat)] string format, /*params*/ ReadOnlySpan args) + { + return AppendFormat(null, format, args); } public StringBuilder AppendFormat(IFormatProvider? provider, [StringSyntax(StringSyntaxAttribute.CompositeFormat)] string format, object? arg0) { - return AppendFormatHelper(provider, format, new ReadOnlySpan(in arg0)); + return AppendFormat(provider, format, new ReadOnlySpan(in arg0)); } public StringBuilder AppendFormat(IFormatProvider? provider, [StringSyntax(StringSyntaxAttribute.CompositeFormat)] string format, object? arg0, object? arg1) { TwoObjects two = new TwoObjects(arg0, arg1); - return AppendFormatHelper(provider, format, two); + return AppendFormat(provider, format, (ReadOnlySpan)two); } public StringBuilder AppendFormat(IFormatProvider? provider, [StringSyntax(StringSyntaxAttribute.CompositeFormat)] string format, object? arg0, object? arg1, object? arg2) { ThreeObjects three = new ThreeObjects(arg0, arg1, arg2); - return AppendFormatHelper(provider, format, three); + return AppendFormat(provider, format, (ReadOnlySpan)three); } public StringBuilder AppendFormat(IFormatProvider? provider, [StringSyntax(StringSyntaxAttribute.CompositeFormat)] string format, params object?[] args) @@ -1409,14 +1493,29 @@ public StringBuilder AppendFormat(IFormatProvider? provider, [StringSyntax(Strin if (args is null) { // To preserve the original exception behavior, throw an exception about format if both - // args and format are null. The actual null check for format is in AppendFormatHelper. + // args and format are null. The actual null check for format is in AppendFormat(..., span). ArgumentNullException.Throw(format is null ? nameof(format) : nameof(args)); } - return AppendFormatHelper(provider, format, args); + return AppendFormat(provider, format, (ReadOnlySpan)args); } - internal StringBuilder AppendFormatHelper(IFormatProvider? provider, string format, ReadOnlySpan args) + /// + /// Appends the string returned by processing a composite format string, which contains zero or more format items, to this instance. + /// Each format item is replaced by the string representation of a corresponding argument in a parameter span using a specified format provider. + /// + /// An object that supplies culture-specific formatting information. + /// A composite format string. + /// A span of objects to format. + /// A reference to this instance after the append operation has completed. + /// is null. + /// The length of the expanded string would exceed . + /// + /// is invalid. + /// -or- + /// The index of a format item is less than 0 (zero), or greater than or equal to the length of the span. + /// + public StringBuilder AppendFormat(IFormatProvider? provider, [StringSyntax(StringSyntaxAttribute.CompositeFormat)] string format, /*params*/ ReadOnlySpan args) { ArgumentNullException.ThrowIfNull(format); @@ -1776,7 +1875,7 @@ public StringBuilder AppendFormat(IFormatProvider? provider, CompositeFormat for /// A reference to this instance after the append operation has completed. /// is null. /// The index of a format item is greater than or equal to the number of supplied arguments. - public StringBuilder AppendFormat(IFormatProvider? provider, CompositeFormat format, ReadOnlySpan args) + public StringBuilder AppendFormat(IFormatProvider? provider, CompositeFormat format, /*params*/ ReadOnlySpan args) { ArgumentNullException.ThrowIfNull(format); format.ValidateNumberOfArgs(args.Length); diff --git a/src/libraries/System.Private.CoreLib/src/System/Threading/CancellationTokenSource.cs b/src/libraries/System.Private.CoreLib/src/System/Threading/CancellationTokenSource.cs index ace2ed4b943d93..092b9467232157 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Threading/CancellationTokenSource.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Threading/CancellationTokenSource.cs @@ -868,7 +868,17 @@ public static CancellationTokenSource CreateLinkedTokenSource(CancellationToken public static CancellationTokenSource CreateLinkedTokenSource(params CancellationToken[] tokens) { ArgumentNullException.ThrowIfNull(tokens); + return CreateLinkedTokenSource((ReadOnlySpan)tokens); + } + /// + /// Creates a that will be in the canceled state + /// when any of the source tokens are in the canceled state. + /// + /// The CancellationToken instances to observe. + /// A that is linked to the source tokens. + public static CancellationTokenSource CreateLinkedTokenSource(/*params*/ ReadOnlySpan tokens) + { return tokens.Length switch { 0 => throw new ArgumentException(SR.CancellationToken_CreateLinkedToken_TokensIsEmpty), @@ -935,7 +945,7 @@ private sealed class LinkedNCancellationTokenSource : CancellationTokenSource }; private CancellationTokenRegistration[]? _linkingRegistrations; - internal LinkedNCancellationTokenSource(CancellationToken[] tokens) + internal LinkedNCancellationTokenSource(ReadOnlySpan tokens) { _linkingRegistrations = new CancellationTokenRegistration[tokens.Length]; diff --git a/src/libraries/System.Private.CoreLib/src/System/Threading/Tasks/Task.cs b/src/libraries/System.Private.CoreLib/src/System/Threading/Tasks/Task.cs index fa03b43aff87cc..ab532be3e3da4e 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Threading/Tasks/Task.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Threading/Tasks/Task.cs @@ -4690,6 +4690,26 @@ public static void WaitAll(params Task[] tasks) Debug.Assert(waitResult, "expected wait to succeed"); } + /// + /// Waits for all of the provided objects to complete execution. + /// + /// + /// An array of instances on which to wait. + /// + /// + /// The argument contains a null element. + /// + /// + /// At least one of the instances was canceled -or- an exception was thrown during + /// the execution of at least one of the instances. + /// + [UnsupportedOSPlatform("browser")] + public static void WaitAll(/*params*/ ReadOnlySpan tasks) + { + bool waitResult = WaitAllCore(tasks, Timeout.Infinite, default); + Debug.Assert(waitResult, "expected wait to succeed"); + } + /// /// Waits for all of the provided objects to complete execution. /// @@ -4724,7 +4744,7 @@ public static void WaitAll(params Task[] tasks) public static bool WaitAll(Task[] tasks, TimeSpan timeout) { long totalMilliseconds = (long)timeout.TotalMilliseconds; - if (totalMilliseconds < -1 || totalMilliseconds > int.MaxValue) + if (totalMilliseconds is < -1 or > int.MaxValue) { ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.timeout); } @@ -5953,7 +5973,7 @@ public static Task WhenAll(params Task[] tasks) /// /// /// The array contained a null task. - internal static Task WhenAll(ReadOnlySpan tasks) => // TODO https://github.com/dotnet/runtime/issues/77873: Make this public. + public static Task WhenAll(/*params*/ ReadOnlySpan tasks) => tasks.Length != 0 ? new WhenAllPromise(tasks) : CompletedTask; /// A Task that gets completed when all of its constituent tasks complete. @@ -6172,7 +6192,13 @@ public static Task WhenAll(IEnumerable> tasks) // Skip a List allocation/copy if tasks is a collection if (tasks is ICollection> taskCollection) { - taskArray = new Task[taskCollection.Count]; + int count = taskCollection.Count; + if (count == 0) + { + return new Task(false, Array.Empty(), TaskCreationOptions.None, default); + } + + taskArray = new Task[count]; taskCollection.CopyTo(taskArray, 0); foreach (Task task in taskArray) { @@ -6181,20 +6207,30 @@ public static Task WhenAll(IEnumerable> tasks) ThrowHelper.ThrowArgumentException(ExceptionResource.Task_MultiTaskContinuation_NullTask, ExceptionArgument.tasks); } } - return InternalWhenAll(taskArray); + + return new WhenAllPromise(taskArray); } // Do some argument checking and convert tasks into a List (later an array) - if (tasks == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.tasks); + if (tasks is null) + { + ThrowHelper.ThrowArgumentNullException(ExceptionArgument.tasks); + } + List> taskList = new List>(); foreach (Task task in tasks) { - if (task == null) ThrowHelper.ThrowArgumentException(ExceptionResource.Task_MultiTaskContinuation_NullTask, ExceptionArgument.tasks); + if (task is null) + { + ThrowHelper.ThrowArgumentException(ExceptionResource.Task_MultiTaskContinuation_NullTask, ExceptionArgument.tasks); + } + taskList.Add(task); } - // Delegate the rest to InternalWhenAll(). - return InternalWhenAll(taskList.ToArray()); + return taskList.Count == 0 ? + new Task(false, Array.Empty(), TaskCreationOptions.None, default) : + new WhenAllPromise(taskList.ToArray()); } /// @@ -6229,13 +6265,49 @@ public static Task WhenAll(IEnumerable> tasks) /// public static Task WhenAll(params Task[] tasks) { - // Do some argument checking and make a defensive copy of the tasks array - if (tasks == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.tasks); + if (tasks is null) + { + ThrowHelper.ThrowArgumentNullException(ExceptionArgument.tasks); + } - int taskCount = tasks.Length; - if (taskCount == 0) return InternalWhenAll(tasks); // small optimization in the case of an empty task array + return WhenAll((ReadOnlySpan>)tasks); + } + + /// + /// Creates a task that will complete when all of the supplied tasks have completed. + /// + /// The tasks to wait on for completion. + /// A task that represents the completion of all of the supplied tasks. + /// + /// + /// If any of the supplied tasks completes in a faulted state, the returned task will also complete in a Faulted state, + /// where its exceptions will contain the aggregation of the set of unwrapped exceptions from each of the supplied tasks. + /// + /// + /// If none of the supplied tasks faulted but at least one of them was canceled, the returned task will end in the Canceled state. + /// + /// + /// If none of the tasks faulted and none of the tasks were canceled, the resulting task will end in the RanToCompletion state. + /// The Result of the returned task will be set to an array containing all of the results of the + /// supplied tasks in the same order as they were provided (e.g. if the input tasks array contained t1, t2, t3, the output + /// task's Result will return an TResult[] where arr[0] == t1.Result, arr[1] == t2.Result, and arr[2] == t3.Result). + /// + /// + /// If the supplied array/enumerable contains no tasks, the returned task will immediately transition to a RanToCompletion + /// state before it's returned to the caller. The returned TResult[] will be an array of 0 elements. + /// + /// + /// + /// The array contained a null task. + /// + public static Task WhenAll(/*params*/ ReadOnlySpan> tasks) + { + if (tasks.IsEmpty) + { + return new Task(false, Array.Empty(), TaskCreationOptions.None, default); + } - Task[] tasksCopy = (Task[])tasks.Clone(); + Task[] tasksCopy = tasks.ToArray(); foreach (Task task in tasksCopy) { if (task is null) @@ -6244,17 +6316,7 @@ public static Task WhenAll(params Task[] tasks) } } - // Delegate the rest to InternalWhenAll() - return InternalWhenAll(tasksCopy); - } - - // Some common logic to support WhenAll methods - private static Task InternalWhenAll(Task[] tasks) - { - Debug.Assert(tasks != null, "Expected a non-null tasks array"); - return (tasks.Length == 0) ? // take shortcut if there are no tasks upon which to wait - new Task(false, Array.Empty(), TaskCreationOptions.None, default) : - new WhenAllPromise(tasks); + return new WhenAllPromise(tasksCopy); } // A Task that gets completed when all of its constituent tasks complete. @@ -6394,7 +6456,7 @@ public static Task WhenAny(params Task[] tasks) { ArgumentNullException.ThrowIfNull(tasks); - return WhenAny((ReadOnlySpan)tasks); + return WhenAnyCore((ReadOnlySpan)tasks); } /// @@ -6409,7 +6471,22 @@ public static Task WhenAny(params Task[] tasks) /// /// The array contained a null task, or was empty. /// - private static Task WhenAny(ReadOnlySpan tasks) where TTask : Task + public static Task WhenAny(/*params*/ ReadOnlySpan tasks) => + WhenAnyCore(tasks); + + /// + /// Creates a task that will complete when any of the supplied tasks have completed. + /// + /// The tasks to wait on for completion. + /// A task that represents the completion of one of the supplied tasks. The return Task's Result is the task that completed. + /// + /// The returned task will complete when any of the supplied tasks has completed. The returned task will always end in the RanToCompletion state + /// with its Result set to the first task to complete. This is true even if the first task to complete ended in the Canceled or Faulted state. + /// + /// + /// The array contained a null task, or was empty. + /// + private static Task WhenAnyCore(ReadOnlySpan tasks) where TTask : Task { if (tasks.Length == 2) { @@ -6589,13 +6666,13 @@ private static Task WhenAny(IEnumerable tasks) where TTask { // Take a more efficient path if tasks is actually a list or an array. Arrays are a bit less common, // since if argument was strongly-typed as an array, it would have bound to the array-based overload. - if (tasks is List tasksAsList) + if (tasks.GetType() == typeof(List)) { - return WhenAny((ReadOnlySpan)CollectionsMarshal.AsSpan(tasksAsList)); + return WhenAnyCore((ReadOnlySpan)CollectionsMarshal.AsSpan(Unsafe.As>(tasks))); } if (tasks is TTask[] tasksAsArray) { - return WhenAny((ReadOnlySpan)tasksAsArray); + return WhenAnyCore((ReadOnlySpan)tasksAsArray); } int count = tasksAsCollection.Count; @@ -6663,9 +6740,24 @@ public static Task> WhenAny(params Task[] tasks) { ArgumentNullException.ThrowIfNull(tasks); - return WhenAny((ReadOnlySpan>)tasks); + return WhenAnyCore((ReadOnlySpan>)tasks); } + /// + /// Creates a task that will complete when any of the supplied tasks have completed. + /// + /// The tasks to wait on for completion. + /// A task that represents the completion of one of the supplied tasks. The return Task's Result is the task that completed. + /// + /// The returned task will complete when any of the supplied tasks has completed. The returned task will always end in the RanToCompletion state + /// with its Result set to the first task to complete. This is true even if the first task to complete ended in the Canceled or Faulted state. + /// + /// + /// The array contained a null task, or was empty. + /// + public static Task> WhenAny(/*params*/ ReadOnlySpan> tasks) => + WhenAnyCore(tasks); + /// Creates a task that will complete when either of the supplied tasks have completed. /// The first task to wait on for completion. /// The second task to wait on for completion. diff --git a/src/libraries/System.Reflection.DispatchProxy/src/System.Reflection.DispatchProxy.csproj b/src/libraries/System.Reflection.DispatchProxy/src/System.Reflection.DispatchProxy.csproj index 2d021999f5869c..17c279ab521382 100644 --- a/src/libraries/System.Reflection.DispatchProxy/src/System.Reflection.DispatchProxy.csproj +++ b/src/libraries/System.Reflection.DispatchProxy/src/System.Reflection.DispatchProxy.csproj @@ -16,6 +16,7 @@ + diff --git a/src/libraries/System.Resources.Writer/src/System.Resources.Writer.csproj b/src/libraries/System.Resources.Writer/src/System.Resources.Writer.csproj index bbe21a704c7f81..b2e3aeb636444c 100644 --- a/src/libraries/System.Resources.Writer/src/System.Resources.Writer.csproj +++ b/src/libraries/System.Resources.Writer/src/System.Resources.Writer.csproj @@ -20,6 +20,7 @@ + diff --git a/src/libraries/System.Runtime.Serialization.Primitives/src/System.Runtime.Serialization.Primitives.csproj b/src/libraries/System.Runtime.Serialization.Primitives/src/System.Runtime.Serialization.Primitives.csproj index 08ff96e95af3e1..ca2ed33befc50b 100644 --- a/src/libraries/System.Runtime.Serialization.Primitives/src/System.Runtime.Serialization.Primitives.csproj +++ b/src/libraries/System.Runtime.Serialization.Primitives/src/System.Runtime.Serialization.Primitives.csproj @@ -22,6 +22,7 @@ + diff --git a/src/libraries/System.Runtime/ref/System.Runtime.cs b/src/libraries/System.Runtime/ref/System.Runtime.cs index 1080983cb9bb2c..14575b820c33ab 100644 --- a/src/libraries/System.Runtime/ref/System.Runtime.cs +++ b/src/libraries/System.Runtime/ref/System.Runtime.cs @@ -2163,6 +2163,7 @@ protected Delegate([System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembersAt [return: System.Diagnostics.CodeAnalysis.NotNullIfNotNullAttribute("b")] public static System.Delegate? Combine(System.Delegate? a, System.Delegate? b) { throw null; } public static System.Delegate? Combine(params System.Delegate?[]? delegates) { throw null; } + public static System.Delegate? Combine(System.ReadOnlySpan delegates) { throw null; } protected virtual System.Delegate CombineImpl(System.Delegate? d) { throw null; } public static System.Delegate CreateDelegate(System.Type type, object? firstArgument, System.Reflection.MethodInfo method) { throw null; } public static System.Delegate? CreateDelegate(System.Type type, object? firstArgument, System.Reflection.MethodInfo method, bool throwOnBindFailure) { throw null; } @@ -5242,6 +5243,7 @@ public unsafe String(sbyte* value, int startIndex, int length, System.Text.Encod public static string Concat(object? arg0, object? arg1) { throw null; } public static string Concat(object? arg0, object? arg1, object? arg2) { throw null; } public static string Concat(params object?[] args) { throw null; } + public static string Concat(System.ReadOnlySpan args) { throw null; } public static string Concat(System.ReadOnlySpan str0, System.ReadOnlySpan str1) { throw null; } public static string Concat(System.ReadOnlySpan str0, System.ReadOnlySpan str1, System.ReadOnlySpan str2) { throw null; } public static string Concat(System.ReadOnlySpan str0, System.ReadOnlySpan str1, System.ReadOnlySpan str2, System.ReadOnlySpan str3) { throw null; } @@ -5249,6 +5251,7 @@ public unsafe String(sbyte* value, int startIndex, int length, System.Text.Encod public static string Concat(string? str0, string? str1, string? str2) { throw null; } public static string Concat(string? str0, string? str1, string? str2, string? str3) { throw null; } public static string Concat(params string?[] values) { throw null; } + public static string Concat(System.ReadOnlySpan values) { throw null; } public static string Concat(System.Collections.Generic.IEnumerable values) { throw null; } public bool Contains(char value) { throw null; } public bool Contains(char value, System.StringComparison comparisonType) { throw null; } @@ -5276,12 +5279,14 @@ public void CopyTo(System.Span destination) { } public static string Format(System.IFormatProvider? provider, [System.Diagnostics.CodeAnalysis.StringSyntaxAttribute("CompositeFormat")] string format, object? arg0, object? arg1) { throw null; } public static string Format(System.IFormatProvider? provider, [System.Diagnostics.CodeAnalysis.StringSyntaxAttribute("CompositeFormat")] string format, object? arg0, object? arg1, object? arg2) { throw null; } public static string Format(System.IFormatProvider? provider, [System.Diagnostics.CodeAnalysis.StringSyntaxAttribute("CompositeFormat")] string format, params object?[] args) { throw null; } + public static string Format(System.IFormatProvider? provider, [System.Diagnostics.CodeAnalysis.StringSyntaxAttribute("CompositeFormat")] string format, System.ReadOnlySpan args) { throw null; } public static string Format(System.IFormatProvider? provider, System.Text.CompositeFormat format, params object?[] args) { throw null; } public static string Format(System.IFormatProvider? provider, System.Text.CompositeFormat format, System.ReadOnlySpan args) { throw null; } public static string Format([System.Diagnostics.CodeAnalysis.StringSyntaxAttribute("CompositeFormat")] string format, object? arg0) { throw null; } public static string Format([System.Diagnostics.CodeAnalysis.StringSyntaxAttribute("CompositeFormat")] string format, object? arg0, object? arg1) { throw null; } public static string Format([System.Diagnostics.CodeAnalysis.StringSyntaxAttribute("CompositeFormat")] string format, object? arg0, object? arg1, object? arg2) { throw null; } public static string Format([System.Diagnostics.CodeAnalysis.StringSyntaxAttribute("CompositeFormat")] string format, params object?[] args) { throw null; } + public static string Format([System.Diagnostics.CodeAnalysis.StringSyntaxAttribute("CompositeFormat")] string format, System.ReadOnlySpan args) { throw null; } public static string Format(System.IFormatProvider? provider, System.Text.CompositeFormat format, TArg0 arg0) { throw null; } public static string Format(System.IFormatProvider? provider, System.Text.CompositeFormat format, TArg0 arg0, TArg1 arg1) { throw null; } public static string Format(System.IFormatProvider? provider, System.Text.CompositeFormat format, TArg0 arg0, TArg1 arg1, TArg2 arg2) { throw null; } @@ -5314,11 +5319,15 @@ public void CopyTo(System.Span destination) { } public static bool IsNullOrEmpty([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(false)] string? value) { throw null; } public static bool IsNullOrWhiteSpace([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(false)] string? value) { throw null; } public static string Join(char separator, params object?[] values) { throw null; } + public static string Join(char separator, System.ReadOnlySpan values) { throw null; } public static string Join(char separator, params string?[] value) { throw null; } + public static string Join(char separator, System.ReadOnlySpan value) { throw null; } public static string Join(char separator, string?[] value, int startIndex, int count) { throw null; } public static string Join(string? separator, System.Collections.Generic.IEnumerable values) { throw null; } public static string Join(string? separator, params object?[] values) { throw null; } + public static string Join(string? separator, System.ReadOnlySpan values) { throw null; } public static string Join(string? separator, params string?[] value) { throw null; } + public static string Join(string? separator, System.ReadOnlySpan value) { throw null; } public static string Join(string? separator, string?[] value, int startIndex, int count) { throw null; } public static string Join(char separator, System.Collections.Generic.IEnumerable values) { throw null; } public static string Join(string? separator, System.Collections.Generic.IEnumerable values) { throw null; } @@ -5354,6 +5363,7 @@ public void CopyTo(System.Span destination) { } public string[] Split(char separator, int count, System.StringSplitOptions options = System.StringSplitOptions.None) { throw null; } public string[] Split(char separator, System.StringSplitOptions options = System.StringSplitOptions.None) { throw null; } public string[] Split(params char[]? separator) { throw null; } + public string[] Split(System.ReadOnlySpan separator) { throw null; } public string[] Split(char[]? separator, int count) { throw null; } public string[] Split(char[]? separator, int count, System.StringSplitOptions options) { throw null; } public string[] Split(char[]? separator, System.StringSplitOptions options) { throw null; } @@ -5401,12 +5411,15 @@ public void CopyTo(System.Span destination) { } public string Trim() { throw null; } public string Trim(char trimChar) { throw null; } public string Trim(params char[]? trimChars) { throw null; } + public string Trim(System.ReadOnlySpan trimChars) { throw null; } public string TrimEnd() { throw null; } public string TrimEnd(char trimChar) { throw null; } public string TrimEnd(params char[]? trimChars) { throw null; } + public string TrimEnd(System.ReadOnlySpan trimChars) { throw null; } public string TrimStart() { throw null; } public string TrimStart(char trimChar) { throw null; } public string TrimStart(params char[]? trimChars) { throw null; } + public string TrimStart(System.ReadOnlySpan trimChars) { throw null; } public bool TryCopyTo(System.Span destination) { throw null; } } public abstract partial class StringComparer : System.Collections.Generic.IComparer, System.Collections.Generic.IEqualityComparer, System.Collections.IComparer, System.Collections.IEqualityComparer @@ -7527,6 +7540,7 @@ public override void Write(string? s) { } public override void Write([System.Diagnostics.CodeAnalysis.StringSyntaxAttribute("CompositeFormat")] string format, object? arg0) { } public override void Write([System.Diagnostics.CodeAnalysis.StringSyntaxAttribute("CompositeFormat")] string format, object? arg0, object? arg1) { } public override void Write([System.Diagnostics.CodeAnalysis.StringSyntaxAttribute("CompositeFormat")] string format, params object?[] arg) { } + public override void Write([System.Diagnostics.CodeAnalysis.StringSyntaxAttribute("CompositeFormat")] string format, System.ReadOnlySpan arg) { } public override System.Threading.Tasks.Task WriteAsync(char value) { throw null; } public override System.Threading.Tasks.Task WriteAsync(char[] buffer, int index, int count) { throw null; } public override System.Threading.Tasks.Task WriteAsync(System.ReadOnlyMemory buffer, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } @@ -7546,6 +7560,7 @@ public override void WriteLine(string? s) { } public override void WriteLine([System.Diagnostics.CodeAnalysis.StringSyntaxAttribute("CompositeFormat")] string format, object? arg0) { } public override void WriteLine([System.Diagnostics.CodeAnalysis.StringSyntaxAttribute("CompositeFormat")] string format, object? arg0, object? arg1) { } public override void WriteLine([System.Diagnostics.CodeAnalysis.StringSyntaxAttribute("CompositeFormat")] string format, params object?[] arg) { } + public override void WriteLine([System.Diagnostics.CodeAnalysis.StringSyntaxAttribute("CompositeFormat")] string format, System.ReadOnlySpan arg) { } [System.CLSCompliantAttribute(false)] public override void WriteLine(uint value) { } public override System.Threading.Tasks.Task WriteLineAsync() { throw null; } @@ -10112,6 +10127,7 @@ public static partial class Path public static string Combine(string path1, string path2, string path3) { throw null; } public static string Combine(string path1, string path2, string path3, string path4) { throw null; } public static string Combine(params string[] paths) { throw null; } + public static string Combine(System.ReadOnlySpan paths) { throw null; } public static bool EndsInDirectorySeparator(System.ReadOnlySpan path) { throw null; } public static bool EndsInDirectorySeparator([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] string? path) { throw null; } public static bool Exists([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] string? path) { throw null; } @@ -10149,6 +10165,7 @@ public static partial class Path public static string Join(string? path1, string? path2, string? path3) { throw null; } public static string Join(string? path1, string? path2, string? path3, string? path4) { throw null; } public static string Join(params string?[] paths) { throw null; } + public static string Join(System.ReadOnlySpan paths) { throw null; } public static System.ReadOnlySpan TrimEndingDirectorySeparator(System.ReadOnlySpan path) { throw null; } public static string TrimEndingDirectorySeparator(string path) { throw null; } public static bool TryJoin(System.ReadOnlySpan path1, System.ReadOnlySpan path2, System.ReadOnlySpan path3, System.Span destination, out int charsWritten) { throw null; } @@ -10315,6 +10332,7 @@ public override void Write([System.Diagnostics.CodeAnalysis.StringSyntaxAttribut public override void Write([System.Diagnostics.CodeAnalysis.StringSyntaxAttribute("CompositeFormat")] string format, object? arg0, object? arg1) { } public override void Write([System.Diagnostics.CodeAnalysis.StringSyntaxAttribute("CompositeFormat")] string format, object? arg0, object? arg1, object? arg2) { } public override void Write([System.Diagnostics.CodeAnalysis.StringSyntaxAttribute("CompositeFormat")] string format, params object?[] arg) { } + public override void Write([System.Diagnostics.CodeAnalysis.StringSyntaxAttribute("CompositeFormat")] string format, System.ReadOnlySpan arg) { } public override System.Threading.Tasks.Task WriteAsync(char value) { throw null; } public override System.Threading.Tasks.Task WriteAsync(char[] buffer, int index, int count) { throw null; } public override System.Threading.Tasks.Task WriteAsync(System.ReadOnlyMemory buffer, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } @@ -10325,6 +10343,7 @@ public override void WriteLine([System.Diagnostics.CodeAnalysis.StringSyntaxAttr public override void WriteLine([System.Diagnostics.CodeAnalysis.StringSyntaxAttribute("CompositeFormat")] string format, object? arg0, object? arg1) { } public override void WriteLine([System.Diagnostics.CodeAnalysis.StringSyntaxAttribute("CompositeFormat")] string format, object? arg0, object? arg1, object? arg2) { } public override void WriteLine([System.Diagnostics.CodeAnalysis.StringSyntaxAttribute("CompositeFormat")] string format, params object?[] arg) { } + public override void WriteLine([System.Diagnostics.CodeAnalysis.StringSyntaxAttribute("CompositeFormat")] string format, System.ReadOnlySpan arg) { } public override System.Threading.Tasks.Task WriteLineAsync() { throw null; } public override System.Threading.Tasks.Task WriteLineAsync(char value) { throw null; } public override System.Threading.Tasks.Task WriteLineAsync(char[] buffer, int index, int count) { throw null; } @@ -10442,6 +10461,7 @@ public virtual void Write([System.Diagnostics.CodeAnalysis.StringSyntaxAttribute public virtual void Write([System.Diagnostics.CodeAnalysis.StringSyntaxAttribute("CompositeFormat")] string format, object? arg0, object? arg1) { } public virtual void Write([System.Diagnostics.CodeAnalysis.StringSyntaxAttribute("CompositeFormat")] string format, object? arg0, object? arg1, object? arg2) { } public virtual void Write([System.Diagnostics.CodeAnalysis.StringSyntaxAttribute("CompositeFormat")] string format, params object?[] arg) { } + public virtual void Write([System.Diagnostics.CodeAnalysis.StringSyntaxAttribute("CompositeFormat")] string format, System.ReadOnlySpan arg) { } public virtual void Write(System.Text.StringBuilder? value) { } [System.CLSCompliantAttribute(false)] public virtual void Write(uint value) { } @@ -10470,6 +10490,7 @@ public virtual void WriteLine([System.Diagnostics.CodeAnalysis.StringSyntaxAttri public virtual void WriteLine([System.Diagnostics.CodeAnalysis.StringSyntaxAttribute("CompositeFormat")] string format, object? arg0, object? arg1) { } public virtual void WriteLine([System.Diagnostics.CodeAnalysis.StringSyntaxAttribute("CompositeFormat")] string format, object? arg0, object? arg1, object? arg2) { } public virtual void WriteLine([System.Diagnostics.CodeAnalysis.StringSyntaxAttribute("CompositeFormat")] string format, params object?[] arg) { } + public virtual void WriteLine([System.Diagnostics.CodeAnalysis.StringSyntaxAttribute("CompositeFormat")] string format, System.ReadOnlySpan arg) { } public virtual void WriteLine(System.Text.StringBuilder? value) { } [System.CLSCompliantAttribute(false)] public virtual void WriteLine(uint value) { } @@ -14915,19 +14936,25 @@ public StringBuilder(string? value, int startIndex, int length, int capacity) { public System.Text.StringBuilder AppendFormat(System.IFormatProvider? provider, [System.Diagnostics.CodeAnalysis.StringSyntaxAttribute("CompositeFormat")] string format, object? arg0, object? arg1) { throw null; } public System.Text.StringBuilder AppendFormat(System.IFormatProvider? provider, [System.Diagnostics.CodeAnalysis.StringSyntaxAttribute("CompositeFormat")] string format, object? arg0, object? arg1, object? arg2) { throw null; } public System.Text.StringBuilder AppendFormat(System.IFormatProvider? provider, [System.Diagnostics.CodeAnalysis.StringSyntaxAttribute("CompositeFormat")] string format, params object?[] args) { throw null; } + public System.Text.StringBuilder AppendFormat(System.IFormatProvider? provider, [System.Diagnostics.CodeAnalysis.StringSyntaxAttribute("CompositeFormat")] string format, System.ReadOnlySpan args) { throw null; } public System.Text.StringBuilder AppendFormat(System.IFormatProvider? provider, System.Text.CompositeFormat format, params object?[] args) { throw null; } public System.Text.StringBuilder AppendFormat(System.IFormatProvider? provider, System.Text.CompositeFormat format, System.ReadOnlySpan args) { throw null; } public System.Text.StringBuilder AppendFormat([System.Diagnostics.CodeAnalysis.StringSyntaxAttribute("CompositeFormat")] string format, object? arg0) { throw null; } public System.Text.StringBuilder AppendFormat([System.Diagnostics.CodeAnalysis.StringSyntaxAttribute("CompositeFormat")] string format, object? arg0, object? arg1) { throw null; } public System.Text.StringBuilder AppendFormat([System.Diagnostics.CodeAnalysis.StringSyntaxAttribute("CompositeFormat")] string format, object? arg0, object? arg1, object? arg2) { throw null; } public System.Text.StringBuilder AppendFormat([System.Diagnostics.CodeAnalysis.StringSyntaxAttribute("CompositeFormat")] string format, params object?[] args) { throw null; } + public System.Text.StringBuilder AppendFormat([System.Diagnostics.CodeAnalysis.StringSyntaxAttribute("CompositeFormat")] string format, System.ReadOnlySpan args) { throw null; } public System.Text.StringBuilder AppendFormat(System.IFormatProvider? provider, System.Text.CompositeFormat format, TArg0 arg0) { throw null; } public System.Text.StringBuilder AppendFormat(System.IFormatProvider? provider, System.Text.CompositeFormat format, TArg0 arg0, TArg1 arg1) { throw null; } public System.Text.StringBuilder AppendFormat(System.IFormatProvider? provider, System.Text.CompositeFormat format, TArg0 arg0, TArg1 arg1, TArg2 arg2) { throw null; } public System.Text.StringBuilder AppendJoin(char separator, params object?[] values) { throw null; } public System.Text.StringBuilder AppendJoin(char separator, params string?[] values) { throw null; } + public System.Text.StringBuilder AppendJoin(char separator, System.ReadOnlySpan values) { throw null; } + public System.Text.StringBuilder AppendJoin(char separator, System.ReadOnlySpan values) { throw null; } public System.Text.StringBuilder AppendJoin(string? separator, params object?[] values) { throw null; } public System.Text.StringBuilder AppendJoin(string? separator, params string?[] values) { throw null; } + public System.Text.StringBuilder AppendJoin(string? separator, System.ReadOnlySpan values) { throw null; } + public System.Text.StringBuilder AppendJoin(string? separator, System.ReadOnlySpan values) { throw null; } public System.Text.StringBuilder AppendJoin(char separator, System.Collections.Generic.IEnumerable values) { throw null; } public System.Text.StringBuilder AppendJoin(string? separator, System.Collections.Generic.IEnumerable values) { throw null; } public System.Text.StringBuilder AppendLine() { throw null; } @@ -15103,6 +15130,7 @@ public void CancelAfter(System.TimeSpan delay) { } public System.Threading.Tasks.Task CancelAsync() { throw null; } public static System.Threading.CancellationTokenSource CreateLinkedTokenSource(System.Threading.CancellationToken token) { throw null; } public static System.Threading.CancellationTokenSource CreateLinkedTokenSource(System.Threading.CancellationToken token1, System.Threading.CancellationToken token2) { throw null; } + public static System.Threading.CancellationTokenSource CreateLinkedTokenSource(System.ReadOnlySpan tokens) { throw null; } public static System.Threading.CancellationTokenSource CreateLinkedTokenSource(params System.Threading.CancellationToken[] tokens) { throw null; } public void Dispose() { } protected virtual void Dispose(bool disposing) { } @@ -15309,6 +15337,8 @@ public void Wait(System.Threading.CancellationToken cancellationToken) { } [System.Runtime.Versioning.UnsupportedOSPlatformAttribute("browser")] public static void WaitAll(System.Collections.Generic.IEnumerable tasks, System.Threading.CancellationToken cancellationToken = default) { } [System.Runtime.Versioning.UnsupportedOSPlatformAttribute("browser")] + public static void WaitAll(System.ReadOnlySpan tasks) { } + [System.Runtime.Versioning.UnsupportedOSPlatformAttribute("browser")] public static void WaitAll(params System.Threading.Tasks.Task[] tasks) { } [System.Runtime.Versioning.UnsupportedOSPlatformAttribute("browser")] public static bool WaitAll(System.Threading.Tasks.Task[] tasks, int millisecondsTimeout) { throw null; } @@ -15329,14 +15359,18 @@ public static void WaitAll(System.Threading.Tasks.Task[] tasks, System.Threading public System.Threading.Tasks.Task WaitAsync(System.TimeSpan timeout, System.TimeProvider timeProvider) { throw null; } public System.Threading.Tasks.Task WaitAsync(System.TimeSpan timeout, System.TimeProvider timeProvider, System.Threading.CancellationToken cancellationToken) { throw null; } public static System.Threading.Tasks.Task WhenAll(System.Collections.Generic.IEnumerable tasks) { throw null; } + public static System.Threading.Tasks.Task WhenAll(System.ReadOnlySpan tasks) { throw null; } public static System.Threading.Tasks.Task WhenAll(params System.Threading.Tasks.Task[] tasks) { throw null; } public static System.Threading.Tasks.Task WhenAll(System.Collections.Generic.IEnumerable> tasks) { throw null; } + public static System.Threading.Tasks.Task WhenAll(System.ReadOnlySpan> tasks) { throw null; } public static System.Threading.Tasks.Task WhenAll(params System.Threading.Tasks.Task[] tasks) { throw null; } public static System.Threading.Tasks.Task WhenAny(System.Collections.Generic.IEnumerable tasks) { throw null; } public static System.Threading.Tasks.Task WhenAny(System.Threading.Tasks.Task task1, System.Threading.Tasks.Task task2) { throw null; } + public static System.Threading.Tasks.Task WhenAny(System.ReadOnlySpan tasks) { throw null; } public static System.Threading.Tasks.Task WhenAny(params System.Threading.Tasks.Task[] tasks) { throw null; } public static System.Threading.Tasks.Task> WhenAny(System.Collections.Generic.IEnumerable> tasks) { throw null; } public static System.Threading.Tasks.Task> WhenAny(System.Threading.Tasks.Task task1, System.Threading.Tasks.Task task2) { throw null; } + public static System.Threading.Tasks.Task> WhenAny(System.ReadOnlySpan> tasks) { throw null; } public static System.Threading.Tasks.Task> WhenAny(params System.Threading.Tasks.Task[] tasks) { throw null; } public static System.Collections.Generic.IAsyncEnumerable WhenEach(System.Collections.Generic.IEnumerable tasks) { throw null; } public static System.Collections.Generic.IAsyncEnumerable WhenEach(params System.Threading.Tasks.Task[] tasks) { throw null; } diff --git a/src/libraries/System.Runtime/tests/System.Dynamic.Runtime.Tests/Dynamic.Context/Conformance.dynamic.context.method.regmethod.regclass.cs b/src/libraries/System.Runtime/tests/System.Dynamic.Runtime.Tests/Dynamic.Context/Conformance.dynamic.context.method.regmethod.regclass.cs index 4ab40934105281..6cf3503569751f 100644 --- a/src/libraries/System.Runtime/tests/System.Dynamic.Runtime.Tests/Dynamic.Context/Conformance.dynamic.context.method.regmethod.regclass.cs +++ b/src/libraries/System.Runtime/tests/System.Dynamic.Runtime.Tests/Dynamic.Context/Conformance.dynamic.context.method.regmethod.regclass.cs @@ -714,7 +714,9 @@ public static void CalledFrom_UsingExpression() { using (StreamWriter sw = new StreamWriter(sm)) { +#pragma warning disable CS9220 // One or more overloads of method having non-array params collection parameter might be applicable only in expanded form which is not supported during dynamic dispatch. sw.WriteLine(mc.Method_ReturnString('a')); +#pragma warning restore CS9220 sw.Flush(); sm.Position = 0; using (StreamReader sr = new StreamReader(sm, (bool)mc.Method_ReturnBool())) diff --git a/src/libraries/System.Runtime/tests/System.Dynamic.Runtime.Tests/Dynamic.OverloadResolution/Conformance.dynamic.overloadResolution.Operators.basic.cs b/src/libraries/System.Runtime/tests/System.Dynamic.Runtime.Tests/Dynamic.OverloadResolution/Conformance.dynamic.overloadResolution.Operators.basic.cs index 1230648a1f443b..5d5933aaf4eea2 100644 --- a/src/libraries/System.Runtime/tests/System.Dynamic.Runtime.Tests/Dynamic.OverloadResolution/Conformance.dynamic.overloadResolution.Operators.basic.cs +++ b/src/libraries/System.Runtime/tests/System.Dynamic.Runtime.Tests/Dynamic.OverloadResolution/Conformance.dynamic.overloadResolution.Operators.basic.cs @@ -1169,7 +1169,9 @@ public static void ExecPositiveTest(dynamic dobj, Type exp_type, T exp_underv } else { +#pragma warning disable CS9220 // One or more overloads of method having non-array params collection parameter might be applicable only in expanded form which is not supported during dynamic dispatch. System.Console.WriteLine("Got invalid result when testing {0}: {1}[{2}]", tip, dr, dr.GetType()); +#pragma warning restore CS9220 } } catch (Exception ex) @@ -1186,7 +1188,9 @@ public static void ExecNegativeTestWithBadOps(dynamic dobj, string[] exp_msg, st try { dynamic dr = test(dobj); +#pragma warning disable CS9220 // One or more overloads of method having non-array params collection parameter might be applicable only in expanded form which is not supported during dynamic dispatch. System.Console.WriteLine("Got invalid result when testing {0}: {1}[{2}]", tip, dr, dr.GetType()); +#pragma warning restore CS9220 } catch (Microsoft.CSharp.RuntimeBinder.RuntimeBinderException ex) { diff --git a/src/libraries/System.Runtime/tests/System.IO.Tests/IndentedTextWriter.cs b/src/libraries/System.Runtime/tests/System.IO.Tests/IndentedTextWriter.cs index 0de5d90f77bbdb..84ebd066786a22 100644 --- a/src/libraries/System.Runtime/tests/System.IO.Tests/IndentedTextWriter.cs +++ b/src/libraries/System.Runtime/tests/System.IO.Tests/IndentedTextWriter.cs @@ -104,6 +104,12 @@ public override void Write(string format, params object[] arg) LastCalledMethod = nameof(Write); } + public override void Write(string format, /*params*/ ReadOnlySpan arg) + { + base.Write(format, arg); + LastCalledMethod = nameof(Write); + } + public override void Write(string value) { base.Write(value); @@ -212,6 +218,12 @@ public override void WriteLine(string format, params object[] arg) LastCalledMethod = nameof(WriteLine); } + public override void WriteLine(string format, /*params*/ ReadOnlySpan arg) + { + base.WriteLine(format, arg); + LastCalledMethod = nameof(WriteLine); + } + public override void WriteLine(string value) { base.WriteLine(value); @@ -416,7 +428,8 @@ public static async Task Writes_ProducesExpectedOutput(string newline) itw.Write("{0}", 14); itw.Write("{0} {1}", 15, 16); itw.Write("{0} {1} {2}", 15, 16, 17); - itw.Write("{0} {1} {2} {3}", 15, 16, 17, 18); + itw.Write("{0} {1} {2} {3}", new object[] { 15, 16, 17, 18 }); + itw.Write("{0} {1} {2} {3}", (ReadOnlySpan)new object[] { 15, 16, 17, 18 }); itw.WriteLine(true); itw.WriteLine('a'); @@ -434,7 +447,8 @@ public static async Task Writes_ProducesExpectedOutput(string newline) itw.WriteLine("{0}", 14); itw.WriteLine("{0} {1}", 15, 16); itw.WriteLine("{0} {1} {2}", 15, 16, 17); - itw.WriteLine("{0} {1} {2} {3}", 15, 16, 17, 18); + itw.WriteLine("{0} {1} {2} {3}", new object[] { 15, 16, 17, 18 }); + itw.WriteLine("{0} {1} {2} {3}", (ReadOnlySpan)new object[] { 15, 16, 17, 18 }); await itw.WriteAsync('a'); await itw.WriteAsync(new char[] { 'b', 'c' }); @@ -450,7 +464,7 @@ public static async Task Writes_ProducesExpectedOutput(string newline) Assert.Equal( "t" + newline + - "tTrueabcde45.66.789101112131415 1615 16 1715 16 17 18True" + newline + + "tTrueabcde45.66.789101112131415 1615 16 1715 16 17 1815 16 17 18True" + newline + "ta" + newline + "tbc" + newline + "tde" + newline + @@ -467,6 +481,7 @@ public static async Task Writes_ProducesExpectedOutput(string newline) "t15 16" + newline + "t15 16 17" + newline + "t15 16 17 18" + newline + + "t15 16 17 18" + newline + "tabcde1a" + newline + "tbc" + newline + "tde" + newline + @@ -499,7 +514,8 @@ object[] CreateParameters(Action callWrite, string expected) yield return CreateParameters(x => x.Write("Hello {0} World", "Digital"), "Hello Digital World"); yield return CreateParameters(x => x.Write("Hello {0} World{1}", "Digital", "!!"), "Hello Digital World!!"); yield return CreateParameters(x => x.Write("Hello {0} {1} World{2}", "Dot", "NET", "!!"), "Hello Dot NET World!!"); - yield return CreateParameters(x => x.Write("Hello {0} {1} {2} World{3}", "Digital", "Dot", "NET", "!!"), "Hello Digital Dot NET World!!"); + yield return CreateParameters(x => x.Write("Hello {0} {1} {2} World{3}", new object[] { "Digital", "Dot", "NET", "!!" }), "Hello Digital Dot NET World!!"); + yield return CreateParameters(x => x.Write("Hello {0} {1} {2} World{3}", (ReadOnlySpan)new object[] { "Digital", "Dot", "NET", "!!" }), "Hello Digital Dot NET World!!"); yield return CreateParameters(x => x.Write("Hello World".ToCharArray(), 6, 5), "World"); } } @@ -530,7 +546,8 @@ object[] CreateParameters(Action callWriteLine, string expec yield return CreateParameters(x => x.WriteLine("Hello {0} {1} World", "Dot", "NET"), $"Hello Dot NET World{NewLine}"); yield return CreateParameters(x => x.WriteLine("Hello {0} {1} World{2}", "Dot", "NET", "!!"), $"Hello Dot NET World!!{NewLine}"); yield return CreateParameters(x => x.WriteLine("Hello World".ToCharArray(), 6, 5), $"World{NewLine}"); - yield return CreateParameters(x => x.WriteLine("Hello {0} {1} {2} World{3}", "Digital", "Dot", "NET", "!!"), $"Hello Digital Dot NET World!!{NewLine}"); + yield return CreateParameters(x => x.WriteLine("Hello {0} {1} {2} World{3}", new object[] { "Digital", "Dot", "NET", "!!" }), $"Hello Digital Dot NET World!!{NewLine}"); + yield return CreateParameters(x => x.WriteLine("Hello {0} {1} {2} World{3}", (ReadOnlySpan)new object[] { "Digital", "Dot", "NET", "!!" }), $"Hello Digital Dot NET World!!{NewLine}"); } } diff --git a/src/libraries/System.Runtime/tests/System.IO.Tests/Stream/Stream.NullTests.cs b/src/libraries/System.Runtime/tests/System.IO.Tests/Stream/Stream.NullTests.cs index 86ebfba5efbefb..3714ff3b2020dc 100644 --- a/src/libraries/System.Runtime/tests/System.IO.Tests/Stream/Stream.NullTests.cs +++ b/src/libraries/System.Runtime/tests/System.IO.Tests/Stream/Stream.NullTests.cs @@ -234,7 +234,8 @@ public static void TextNullTextWriter(TextWriter output) output.Write(" {0} ", "Friday"); output.Write(" {0}{1} ", "Saturday", "Sunday"); output.Write(" {0} {1} {2}", TimeSpan.FromSeconds(1), TimeSpan.FromMinutes(2), TimeSpan.FromDays(3)); - output.Write(" {0} {1} {2} {3}", (Int128)4, (UInt128)5, (nint)6, (nuint)7); + output.Write(" {0} {1} {2} {3}", new object[] { (Int128)4, (UInt128)5, (nint)6, (nuint)7 }); + output.Write(" {0} {1} {2} {3} {4}", (ReadOnlySpan)new object[] { (Int128)4, (UInt128)5, (nint)6, (nuint)7, "8" }); output.WriteLine(); output.WriteLine(true); output.WriteLine('a'); @@ -256,7 +257,8 @@ public static void TextNullTextWriter(TextWriter output) output.WriteLine(" {0} ", "Friday"); output.WriteLine(" {0}{1} ", "Saturday", "Sunday"); output.WriteLine(" {0} {1} {2}", TimeSpan.FromSeconds(1), TimeSpan.FromMinutes(2), TimeSpan.FromDays(3)); - output.WriteLine(" {0} {1} {2} {3}", (Int128)4, (UInt128)5, (nint)6, (nuint)7); + output.WriteLine(" {0} {1} {2} {3}", new object[] { (Int128)4, (UInt128)5, (nint)6, (nuint)7 }); + output.WriteLine(" {0} {1} {2} {3} {4}", (ReadOnlySpan)new object[] { (Int128)4, (UInt128)5, (nint)6, (nuint)7, "8" }); Assert.True(output.WriteAsync('a').IsCompletedSuccessfully); Assert.True(output.WriteAsync((char[])null).IsCompletedSuccessfully); Assert.True(output.WriteAsync(new char[] { 'b', 'c' }).IsCompletedSuccessfully); diff --git a/src/libraries/System.Runtime/tests/System.IO.Tests/StreamWriter/StreamWriter.cs b/src/libraries/System.Runtime/tests/System.IO.Tests/StreamWriter/StreamWriter.cs index 0d34fe6730f0ac..69edb13a8a1fce 100644 --- a/src/libraries/System.Runtime/tests/System.IO.Tests/StreamWriter/StreamWriter.cs +++ b/src/libraries/System.Runtime/tests/System.IO.Tests/StreamWriter/StreamWriter.cs @@ -58,20 +58,28 @@ public void FormatOverloadsCallWrite() Assert.Equal(2, writer.WriteCalls); writer.Write("{0}{1}{2}", "Zero", "One", "Two"); Assert.Equal(3, writer.WriteCalls); - writer.Write("{0}{1}{2}{3}", "Zero", "One", "Two", "Three"); + writer.Write("{0}{1}{2}{3}", new object[] { "Zero", "One", "Two", "Three" }); Assert.Equal(4, writer.WriteCalls); - writer.Write("{0}{1}{2}{3}{4}", "Zero", "One", "Two", "Three", "Four"); + writer.Write("{0}{1}{2}{3}", (ReadOnlySpan)new object[] { "Zero", "One", "Two", "Three" }); Assert.Equal(5, writer.WriteCalls); + writer.Write("{0}{1}{2}{3}{4}", new object[] { "Zero", "One", "Two", "Three", "Four" }); + Assert.Equal(6, writer.WriteCalls); + writer.Write("{0}{1}{2}{3}{4}", (ReadOnlySpan)new object[] { "Zero", "One", "Two", "Three", "Four" }); + Assert.Equal(7, writer.WriteCalls); writer.WriteLine("{0}", "Zero"); Assert.Equal(1, writer.WriteLineCalls); writer.WriteLine("{0}{1}", "Zero", "One"); Assert.Equal(2, writer.WriteLineCalls); writer.WriteLine("{0}{1}{2}", "Zero", "One", "Two"); Assert.Equal(3, writer.WriteLineCalls); - writer.WriteLine("{0}{1}{2}{3}", "Zero", "One", "Two", "Three"); + writer.WriteLine("{0}{1}{2}{3}", new object[] { "Zero", "One", "Two", "Three" }); Assert.Equal(4, writer.WriteLineCalls); - writer.WriteLine("{0}{1}{2}{3}{4}", "Zero", "One", "Two", "Three", "Four"); + writer.WriteLine("{0}{1}{2}{3}", (ReadOnlySpan)new object[] { "Zero", "One", "Two", "Three" }); Assert.Equal(5, writer.WriteLineCalls); + writer.WriteLine("{0}{1}{2}{3}{4}", new object[] { "Zero", "One", "Two", "Three", "Four" }); + Assert.Equal(6, writer.WriteLineCalls); + writer.WriteLine("{0}{1}{2}{3}{4}", (ReadOnlySpan)new object[] { "Zero", "One", "Two", "Three", "Four" }); + Assert.Equal(7, writer.WriteLineCalls); } } } diff --git a/src/libraries/System.Runtime/tests/System.IO.Tests/TextWriter/TextWriterTests.cs b/src/libraries/System.Runtime/tests/System.IO.Tests/TextWriter/TextWriterTests.cs index de3ed9530a1ee2..2299dc86f567db 100644 --- a/src/libraries/System.Runtime/tests/System.IO.Tests/TextWriter/TextWriterTests.cs +++ b/src/libraries/System.Runtime/tests/System.IO.Tests/TextWriter/TextWriterTests.cs @@ -226,15 +226,24 @@ public void WriteStringThreeObjectsTest() } [Fact] - public void WriteStringMultipleObjectsTest() + public void WriteStringMultipleObjectsArrayTest() { using (CharArrayTextWriter tw = NewTextWriter) { - tw.Write(TestDataProvider.FormatStringMultipleObjects, TestDataProvider.MultipleObjects); + tw.Write(TestDataProvider.FormatStringMultipleObjects, (object[])TestDataProvider.MultipleObjects); Assert.Equal(string.Format(TestDataProvider.FormatStringMultipleObjects, TestDataProvider.MultipleObjects), tw.Text); } } + [Fact] + public void WriteStringMultipleObjectsSpanTest() + { + using (CharArrayTextWriter tw = NewTextWriter) + { + tw.Write(TestDataProvider.FormatStringMultipleObjects, (ReadOnlySpan)TestDataProvider.MultipleObjects); + Assert.Equal(string.Format(TestDataProvider.FormatStringMultipleObjects, TestDataProvider.MultipleObjects), tw.Text); + } + } #endregion #region WriteLine Overloads @@ -454,11 +463,21 @@ public void WriteLineStringThreeObjectsTest() } [Fact] - public void WriteLineStringMultipleObjectsTest() + public void WriteLineStringMultipleObjectsArrayTest() { using (CharArrayTextWriter tw = NewTextWriter) { - tw.WriteLine(TestDataProvider.FormatStringMultipleObjects, TestDataProvider.MultipleObjects); + tw.WriteLine(TestDataProvider.FormatStringMultipleObjects, (object[])TestDataProvider.MultipleObjects); + Assert.Equal(string.Format(TestDataProvider.FormatStringMultipleObjects + tw.NewLine, TestDataProvider.MultipleObjects), tw.Text); + } + } + + [Fact] + public void WriteLineStringMultipleObjectsSpanTest() + { + using (CharArrayTextWriter tw = NewTextWriter) + { + tw.WriteLine(TestDataProvider.FormatStringMultipleObjects, (ReadOnlySpan)TestDataProvider.MultipleObjects); Assert.Equal(string.Format(TestDataProvider.FormatStringMultipleObjects + tw.NewLine, TestDataProvider.MultipleObjects), tw.Text); } } @@ -772,8 +791,11 @@ public async Task CreateBroadcasting_DelegatesToAllWriters() oracle.Write(" {0} {1} {2}", TimeSpan.FromSeconds(1), TimeSpan.FromMinutes(2), TimeSpan.FromDays(3)); broadcasting.Write(" {0} {1} {2}", TimeSpan.FromSeconds(1), TimeSpan.FromMinutes(2), TimeSpan.FromDays(3)); - oracle.Write(" {0} {1} {2} {3}", (Int128)4, (UInt128)5, (nint)6, (nuint)7); - broadcasting.Write(" {0} {1} {2} {3}", (Int128)4, (UInt128)5, (nint)6, (nuint)7); + oracle.Write(" {0} {1} {2} {3}", new object[] { (Int128)4, (UInt128)5, (nint)6, (nuint)7 }); + broadcasting.Write(" {0} {1} {2} {3}", new object[] { (Int128)4, (UInt128)5, (nint)6, (nuint)7 }); + + oracle.Write(" {0} {1} {2} {3} {4}", (ReadOnlySpan)new object[] { (Int128)4, (UInt128)5, (nint)6, (nuint)7, "8" }); + broadcasting.Write(" {0} {1} {2} {3} {4}", (ReadOnlySpan)new object[] { (Int128)4, (UInt128)5, (nint)6, (nuint)7, "8" }); oracle.WriteLine(); broadcasting.WriteLine(); @@ -835,8 +857,11 @@ public async Task CreateBroadcasting_DelegatesToAllWriters() oracle.WriteLine(" {0} {1} {2}", TimeSpan.FromSeconds(1), TimeSpan.FromMinutes(2), TimeSpan.FromDays(3)); broadcasting.WriteLine(" {0} {1} {2}", TimeSpan.FromSeconds(1), TimeSpan.FromMinutes(2), TimeSpan.FromDays(3)); - oracle.WriteLine(" {0} {1} {2} {3}", (Int128)4, (UInt128)5, (nint)6, (nuint)7); - broadcasting.WriteLine(" {0} {1} {2} {3}", (Int128)4, (UInt128)5, (nint)6, (nuint)7); + oracle.WriteLine(" {0} {1} {2} {3}", new object[] { (Int128)4, (UInt128)5, (nint)6, (nuint)7 }); + broadcasting.WriteLine(" {0} {1} {2} {3}", new object[] { (Int128)4, (UInt128)5, (nint)6, (nuint)7 }); + + oracle.WriteLine(" {0} {1} {2} {3} {4}", (ReadOnlySpan)new object[] { (Int128)4, (UInt128)5, (nint)6, (nuint)7, "8" }); + broadcasting.WriteLine(" {0} {1} {2} {3} {4}", (ReadOnlySpan)new object[] { (Int128)4, (UInt128)5, (nint)6, (nuint)7, "8" }); await oracle.WriteAsync('a'); await broadcasting.WriteAsync('a'); diff --git a/src/libraries/System.Runtime/tests/System.Runtime.Extensions.Tests/System/IO/PathTests_Combine.cs b/src/libraries/System.Runtime/tests/System.Runtime.Extensions.Tests/System/IO/PathTests_Combine.cs index 033168ce649a17..9493d5aed543ab 100644 --- a/src/libraries/System.Runtime/tests/System.Runtime.Extensions.Tests/System/IO/PathTests_Combine.cs +++ b/src/libraries/System.Runtime/tests/System.Runtime.Extensions.Tests/System/IO/PathTests_Combine.cs @@ -98,6 +98,7 @@ public static void Combine(string[] paths) // Combine(string[]) Assert.Equal(expected, Path.Combine(paths)); + Assert.Equal(expected, Path.Combine((ReadOnlySpan)paths)); // Verify special cases switch (paths.Length) @@ -166,6 +167,10 @@ public static void ContainsInvalidCharWithRooted_Windows_core() private static void VerifyException(string[] paths) where T : Exception { Assert.Throws(() => Path.Combine(paths)); + if (paths != null) + { + Assert.Throws(() => Path.Combine((ReadOnlySpan)paths)); + } //verify passed as elements case if (paths != null) diff --git a/src/libraries/System.Runtime/tests/System.Runtime.Extensions.Tests/System/IO/PathTests_Join.cs b/src/libraries/System.Runtime/tests/System.Runtime.Extensions.Tests/System/IO/PathTests_Join.cs index 0984a9145385ac..f8b61049251fee 100644 --- a/src/libraries/System.Runtime/tests/System.Runtime.Extensions.Tests/System/IO/PathTests_Join.cs +++ b/src/libraries/System.Runtime/tests/System.Runtime.Extensions.Tests/System/IO/PathTests_Join.cs @@ -200,36 +200,42 @@ public void JoinStringArray_ThrowsArgumentNullException() public void JoinStringArray_ZeroLengthArray() { Assert.Equal(string.Empty, Path.Join(new string[0])); + Assert.Equal(string.Empty, Path.Join((ReadOnlySpan)new string[0])); } [Theory, MemberData(nameof(TestData_JoinOnePath))] public void JoinStringArray_1(string path1, string expected) { Assert.Equal(expected, Path.Join(new string[] { path1 })); + Assert.Equal(expected, Path.Join((ReadOnlySpan)new string[] { path1 })); } [Theory, MemberData(nameof(TestData_JoinTwoPaths))] public void JoinStringArray_2(string path1, string path2, string expected) { Assert.Equal(expected, Path.Join(new string[] { path1, path2 })); + Assert.Equal(expected, Path.Join((ReadOnlySpan)new string[] { path1, path2 })); } [Theory, MemberData(nameof(TestData_JoinThreePaths))] public void JoinStringArray_3(string path1, string path2, string path3, string expected) { Assert.Equal(expected, Path.Join(new string[] { path1, path2, path3 })); + Assert.Equal(expected, Path.Join((ReadOnlySpan)new string[] { path1, path2, path3 })); } [Theory, MemberData(nameof(TestData_JoinFourPaths))] public void JoinStringArray_4(string path1, string path2, string path3, string path4, string expected) { Assert.Equal(expected, Path.Join(new string[] { path1, path2, path3, path4 })); + Assert.Equal(expected, Path.Join((ReadOnlySpan)new string[] { path1, path2, path3, path4 })); } [Theory, MemberData(nameof(TestData_JoinFourPaths))] public void JoinStringArray_8(string path1, string path2, string path3, string path4, string fourJoined) { Assert.Equal(Path.Join(fourJoined, fourJoined), Path.Join(new string[] { path1, path2, path3, path4, path1, path2, path3, path4 })); + Assert.Equal(Path.Join(fourJoined, fourJoined), Path.Join((ReadOnlySpan)new string[] { path1, path2, path3, path4, path1, path2, path3, path4 })); } } } diff --git a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/MulticastDelegateTests.cs b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/MulticastDelegateTests.cs index 9994fa02f10fac..ab798d6442beb0 100644 --- a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/MulticastDelegateTests.cs +++ b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/MulticastDelegateTests.cs @@ -105,7 +105,19 @@ public static void Combine() D nothing = (D)(Delegate.Combine()); Assert.Null(nothing); - D one = (D)(Delegate.Combine(a)); + nothing = (D)(Delegate.Combine(null)); + Assert.Null(nothing); + + nothing = (D)(Delegate.Combine(ReadOnlySpan.Empty)); + Assert.Null(nothing); + + D one = (D)(Delegate.Combine(new[] { a })); + t1.Clear(); + one(5); + Assert.Equal("A5", t1.S); + CheckInvokeList(new D[] { a }, one, t1); + + one = (D)(Delegate.Combine((ReadOnlySpan)new[] { a })); t1.Clear(); one(5); Assert.Equal("A5", t1.S); @@ -117,13 +129,25 @@ public static void Combine() Assert.Equal("A5B5", t1.S); CheckInvokeList(new D[] { a, b }, ab, t1); - D abc = (D)(Delegate.Combine(a, b, c)); + D abc = (D)(Delegate.Combine(new[] { a, b, c })); t1.Clear(); abc(5); Assert.Equal("A5B5C5", t1.S); CheckInvokeList(new D[] { a, b, c }, abc, t1); - D abcdabc = (D)(Delegate.Combine(abc, d, abc)); + abc = (D)(Delegate.Combine((ReadOnlySpan)new[] { a, b, c })); + t1.Clear(); + abc(5); + Assert.Equal("A5B5C5", t1.S); + CheckInvokeList(new D[] { a, b, c }, abc, t1); + + D abcdabc = (D)(Delegate.Combine(new[] { abc, d, abc })); + t1.Clear(); + abcdabc(9); + Assert.Equal("A9B9C9D9A9B9C9", t1.S); + CheckInvokeList(new D[] { a, b, c, d, a, b, c }, abcdabc, t1); + + abcdabc = (D)(Delegate.Combine((ReadOnlySpan)new[] { abc, d, abc })); t1.Clear(); abcdabc(9); Assert.Equal("A9B9C9D9A9B9C9", t1.S); diff --git a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/String.SplitTests.cs b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/String.SplitTests.cs index b12bd2cb74fc48..037e7a98a95878 100644 --- a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/String.SplitTests.cs +++ b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/String.SplitTests.cs @@ -141,6 +141,7 @@ public static void SplitNoMatchSingleResult() Assert.Equal(expected, Value.Split(',', Options)); Assert.Equal(expected, Value.Split(',', Count, Options)); Assert.Equal(expected, Value.Split(new[] { ',' })); + Assert.Equal(expected, Value.Split((ReadOnlySpan)new[] { ',' })); Assert.Equal(expected, Value.Split(new[] { ',' }, Options)); Assert.Equal(expected, Value.Split(new[] { ',' }, Count)); Assert.Equal(expected, Value.Split(new[] { ',' }, Count, Options)); @@ -516,6 +517,7 @@ public static void SplitCharSeparator(string value, char separator, int count, S { Assert.Equal(expected, value.Split(separator)); Assert.Equal(expected, value.Split(new[] { separator })); + Assert.Equal(expected, value.Split((ReadOnlySpan)new[] { separator })); Assert.Equal(expected, value.Split(separator.ToString())); } diff --git a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/Text/CompositeFormatTests.cs b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/Text/CompositeFormatTests.cs index bdfde206c850f4..64c0caf8f8c396 100644 --- a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/Text/CompositeFormatTests.cs +++ b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/Text/CompositeFormatTests.cs @@ -68,12 +68,15 @@ public static void MinimumArgumentCount_MatchesExpectedValue(string format, int Assert.Equal(expected, cf.MinimumArgumentCount); - string s = string.Format(null, cf, Enumerable.Repeat((object)"arg", expected).ToArray()); - Assert.NotNull(s); + object[] args = Enumerable.Repeat((object)"arg", expected).ToArray(); + Assert.NotNull(string.Format(null, cf, args)); + Assert.NotNull(string.Format(null, cf, (ReadOnlySpan)args)); if (expected != 0) { - Assert.Throws(() => string.Format(null, cf, Enumerable.Repeat((object)"arg", expected - 1).ToArray())); + args = Enumerable.Repeat((object)"arg", expected - 1).ToArray(); + Assert.Throws(() => string.Format(null, cf, args)); + Assert.Throws(() => string.Format(null, cf, (ReadOnlySpan)args)); } } @@ -86,21 +89,20 @@ public static void StringFormat_Valid(IFormatProvider provider, string format, o Assert.Same(format, cf.Format); Assert.Equal(expected, string.Format(provider, cf, values)); - - Assert.Equal(expected, string.Format(provider, cf, (ReadOnlySpan)values)); + Assert.Equal(expected, string.Format(provider, cf, (ReadOnlySpan)values)); switch (values.Length) { case 1: - Assert.Equal(expected, string.Format(provider, cf, values[0])); + Assert.Equal(expected, string.Format(provider, cf, arg0: values[0])); break; case 2: - Assert.Equal(expected, string.Format(provider, cf, values[0], values[1])); + Assert.Equal(expected, string.Format(provider, cf, arg0: values[0], arg1: values[1])); break; case 3: - Assert.Equal(expected, string.Format(provider, cf, values[0], values[1], values[2])); + Assert.Equal(expected, string.Format(provider, cf, arg0: values[0], arg1: values[1], arg2: values[2])); break; } } @@ -188,6 +190,8 @@ public static void MemoryExtensionsTryWrite_Valid(IFormatProvider provider, stri dest = new char[expected.Length - 1]; Assert.False(dest.AsSpan().TryWrite(provider, cf, out charsWritten, values)); Assert.Equal(0, charsWritten); + Assert.False(dest.AsSpan().TryWrite(provider, cf, out charsWritten, (ReadOnlySpan)values)); + Assert.Equal(0, charsWritten); } } @@ -209,16 +213,17 @@ public static void StringFormat_Invalid_FormatExceptionFromArgs(IFormatProvider Assert.NotNull(cf); Assert.Throws(() => string.Format(provider, cf, args)); + Assert.Throws(() => string.Format(provider, cf, (ReadOnlySpan)args)); switch (args.Length) { case 1: - Assert.Throws(() => string.Format(provider, cf, args[0])); + Assert.Throws(() => string.Format(provider, cf, arg0: args[0])); break; case 2: - Assert.Throws(() => string.Format(provider, cf, args[0], args[1])); + Assert.Throws(() => string.Format(provider, cf, arg0: args[0], arg1: args[1])); break; case 3: - Assert.Throws(() => string.Format(provider, cf, args[0], args[1], args[2])); + Assert.Throws(() => string.Format(provider, cf, arg0: args[0], arg1: args[1], arg2: args[2])); break; } } @@ -233,16 +238,17 @@ public static void StringBuilderAppendFormat_Invalid_FormatExceptionFromArgs(IFo var sb = new StringBuilder(); Assert.Throws(() => sb.AppendFormat(provider, cf, args)); + Assert.Throws(() => sb.AppendFormat(provider, cf, (ReadOnlySpan)args)); switch (args.Length) { case 1: - Assert.Throws(() => sb.AppendFormat(provider, cf, args[0])); + Assert.Throws(() => sb.AppendFormat(provider, cf, arg0: args[0])); break; case 2: - Assert.Throws(() => sb.AppendFormat(provider, cf, args[0], args[1])); + Assert.Throws(() => sb.AppendFormat(provider, cf, arg0: args[0], arg1: args[1])); break; case 3: - Assert.Throws(() => sb.AppendFormat(provider, cf, args[0], args[1], args[2])); + Assert.Throws(() => sb.AppendFormat(provider, cf, arg0: args[0], arg1: args[1], arg2: args[2])); break; } } @@ -257,16 +263,17 @@ public static void MemoryExtensionsTryWrite_Invalid_FormatExceptionFromArgs(IFor char[] dest = new char[1024]; Assert.Throws(() => new Span(dest).TryWrite(provider, cf, out _, args)); + Assert.Throws(() => new Span(dest).TryWrite(provider, cf, out _, (ReadOnlySpan)args)); switch (args.Length) { case 1: Assert.Throws(() => new Span(dest).TryWrite(provider, cf, out _, args[0])); break; case 2: - Assert.Throws(() => new Span(dest).TryWrite(provider, cf, out _, args[0], args[1])); + Assert.Throws(() => new Span(dest).TryWrite(provider, cf, out _, arg0: args[0], arg1: args[1])); break; case 3: - Assert.Throws(() => new Span(dest).TryWrite(provider, cf, out _, args[0], args[1], args[2])); + Assert.Throws(() => new Span(dest).TryWrite(provider, cf, out _, arg0: args[0], arg1: args[1], arg2: args[2])); break; } } diff --git a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/Text/StringBuilderTests.cs b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/Text/StringBuilderTests.cs index 2d1f569dd103be..5671c6d3614e57 100644 --- a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/Text/StringBuilderTests.cs +++ b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/Text/StringBuilderTests.cs @@ -842,6 +842,19 @@ public static void AppendFormat(string original, IFormatProvider provider, strin builder = new StringBuilder(original); builder.AppendFormat(provider, format, values); Assert.Equal(expected, builder.ToString()); + + // Use AppendFormat(string, ReadOnlySpan) or AppendFormat(IFormatProvider, string, ReadOnlySpan) + if (provider == null) + { + // Use AppendFormat(string, ReadOnlySpan) + builder = new StringBuilder(original); + builder.AppendFormat(format, (ReadOnlySpan)values); + Assert.Equal(expected, builder.ToString()); + } + // Use AppendFormat(IFormatProvider, string, ReadOnlySpan) + builder = new StringBuilder(original); + builder.AppendFormat(provider, format, (ReadOnlySpan)values); + Assert.Equal(expected, builder.ToString()); } [Fact] @@ -855,17 +868,21 @@ public static void AppendFormat_Invalid() var obj2 = new object(); var obj3 = new object(); var obj4 = new object(); + var objArray = new object[] { obj1, obj2, obj3, obj4 }; AssertExtensions.Throws("format", () => builder.AppendFormat(null, obj1)); // Format is null AssertExtensions.Throws("format", () => builder.AppendFormat(null, obj1, obj2, obj3)); // Format is null - AssertExtensions.Throws("format", () => builder.AppendFormat(null, obj1, obj2, obj3)); // Format is null AssertExtensions.Throws("format", () => builder.AppendFormat(null, obj1, obj2, obj3, obj4)); // Format is null + AssertExtensions.Throws("format", () => builder.AppendFormat(null, objArray)); // Format is null + AssertExtensions.Throws("format", () => builder.AppendFormat(null, (ReadOnlySpan)objArray)); // Format is null AssertExtensions.Throws("args", () => builder.AppendFormat("", null)); // Args is null AssertExtensions.Throws("format", () => builder.AppendFormat(null, (object[])null)); // Both format and args are null AssertExtensions.Throws("format", () => builder.AppendFormat(formatter, (string)null, obj1)); // Format is null AssertExtensions.Throws("format", () => builder.AppendFormat(formatter, (string)null, obj1, obj2)); // Format is null AssertExtensions.Throws("format", () => builder.AppendFormat(formatter, (string)null, obj1, obj2, obj3)); // Format is null AssertExtensions.Throws("format", () => builder.AppendFormat(formatter, (string)null, obj1, obj2, obj3, obj4)); // Format is null + AssertExtensions.Throws("format", () => builder.AppendFormat(formatter, (string)null, objArray)); // Format is null + AssertExtensions.Throws("format", () => builder.AppendFormat(formatter, (string)null, (ReadOnlySpan)objArray)); // Format is null AssertExtensions.Throws("args", () => builder.AppendFormat(formatter, "", null)); // Args is null AssertExtensions.Throws("format", () => builder.AppendFormat(formatter, (string)null, null)); // Both format and args are null @@ -873,19 +890,27 @@ public static void AppendFormat_Invalid() Assert.Throws(() => builder.AppendFormat("{-1}", obj1, obj2)); // Format has value < 0 Assert.Throws(() => builder.AppendFormat("{-1}", obj1, obj2, obj3)); // Format has value < 0 Assert.Throws(() => builder.AppendFormat("{-1}", obj1, obj2, obj3, obj4)); // Format has value < 0 + Assert.Throws(() => builder.AppendFormat("{-1}", objArray)); // Format has value < 0 + Assert.Throws(() => builder.AppendFormat("{-1}", (ReadOnlySpan)objArray)); // Format has value < 0 Assert.Throws(() => builder.AppendFormat(formatter, "{-1}", obj1)); // Format has value < 0 Assert.Throws(() => builder.AppendFormat(formatter, "{-1}", obj1, obj2)); // Format has value < 0 Assert.Throws(() => builder.AppendFormat(formatter, "{-1}", obj1, obj2, obj3)); // Format has value < 0 Assert.Throws(() => builder.AppendFormat(formatter, "{-1}", obj1, obj2, obj3, obj4)); // Format has value < 0 + Assert.Throws(() => builder.AppendFormat(formatter, "{-1}", objArray)); // Format has value < 0 + Assert.Throws(() => builder.AppendFormat(formatter, "{-1}", (ReadOnlySpan)objArray)); // Format has value < 0 Assert.Throws(() => builder.AppendFormat("{1}", obj1)); // Format has value >= 1 Assert.Throws(() => builder.AppendFormat("{2}", obj1, obj2)); // Format has value >= 2 Assert.Throws(() => builder.AppendFormat("{3}", obj1, obj2, obj3)); // Format has value >= 3 Assert.Throws(() => builder.AppendFormat("{4}", obj1, obj2, obj3, obj4)); // Format has value >= 4 + Assert.Throws(() => builder.AppendFormat("{4}", objArray)); // Format has value >= 4 + Assert.Throws(() => builder.AppendFormat("{4}", (ReadOnlySpan)objArray)); // Format has value >= 4 Assert.Throws(() => builder.AppendFormat(formatter, "{1}", obj1)); // Format has value >= 1 Assert.Throws(() => builder.AppendFormat(formatter, "{2}", obj1, obj2)); // Format has value >= 2 Assert.Throws(() => builder.AppendFormat(formatter, "{3}", obj1, obj2, obj3)); // Format has value >= 3 Assert.Throws(() => builder.AppendFormat(formatter, "{4}", obj1, obj2, obj3, obj4)); // Format has value >= 4 + Assert.Throws(() => builder.AppendFormat(formatter, "{4}", objArray)); // Format has value >= 4 + Assert.Throws(() => builder.AppendFormat(formatter, "{4}", (ReadOnlySpan)objArray)); // Format has value >= 4 Assert.Throws(() => builder.AppendFormat("{", "")); // Format has unescaped { Assert.Throws(() => builder.AppendFormat("{a", "")); // Format has unescaped { @@ -900,7 +925,9 @@ public static void AppendFormat_Invalid() Assert.Throws(() => builder.AppendFormat("{0 ", "")); // Format with index and spaces is not closed Assert.Throws(() => builder.AppendFormat("{1000000", new string[10])); // Format index is too long + Assert.Throws(() => builder.AppendFormat("{1000000", (ReadOnlySpan)new string[10])); // Format index is too long Assert.Throws(() => builder.AppendFormat("{10000000}", new string[10])); // Format index is too long + Assert.Throws(() => builder.AppendFormat("{10000000}", (ReadOnlySpan)new string[10])); // Format index is too long Assert.Throws(() => builder.AppendFormat("{0,", "")); // Format with comma is not closed Assert.Throws(() => builder.AppendFormat("{0, ", "")); // Format with comma and spaces is not closed @@ -910,13 +937,19 @@ public static void AppendFormat_Invalid() Assert.Throws(() => builder.AppendFormat("{0,-a", "")); // Format has invalid character after minus sign Assert.Throws(() => builder.AppendFormat("{0,1000000", new string[10])); // Format length is too long + Assert.Throws(() => builder.AppendFormat("{0,1000000", (ReadOnlySpan)new string[10])); // Format length is too long Assert.Throws(() => builder.AppendFormat("{0,10000000}", new string[10])); // Format length is too long + Assert.Throws(() => builder.AppendFormat("{0,10000000}", (ReadOnlySpan)new string[10])); // Format length is too long Assert.Throws(() => builder.AppendFormat("{0:", new string[10])); // Format with colon is not closed + Assert.Throws(() => builder.AppendFormat("{0:", (ReadOnlySpan)new string[10])); // Format with colon is not closed Assert.Throws(() => builder.AppendFormat("{0: ", new string[10])); // Format with colon and spaces is not closed + Assert.Throws(() => builder.AppendFormat("{0: ", (ReadOnlySpan)new string[10])); // Format with colon and spaces is not closed Assert.Throws(() => builder.AppendFormat("{0:{", new string[10])); // Format with custom format contains unescaped { + Assert.Throws(() => builder.AppendFormat("{0:{", (ReadOnlySpan)new string[10])); // Format with custom format contains unescaped { Assert.Throws(() => builder.AppendFormat("{0:{}", new string[10])); // Format with custom format contains unescaped { + Assert.Throws(() => builder.AppendFormat("{0:{}", (ReadOnlySpan)new string[10])); // Format with custom format contains unescaped { Assert.Throws(() => builder.AppendFormat("{0}", new TooManyCharsWrittenSpanFormattable())); // ISpanFormattable that returns more characters than it actually wrote } @@ -1775,11 +1808,15 @@ public static void AppendJoin_TestValues(object[] values, string expected) var enumerable = values.Select(_ => _); Assert.Equal(expected, new StringBuilder().AppendJoin('|', values).ToString()); + Assert.Equal(expected, new StringBuilder().AppendJoin('|', (ReadOnlySpan)values).ToString()); Assert.Equal(expected, new StringBuilder().AppendJoin('|', enumerable).ToString()); Assert.Equal(expected, new StringBuilder().AppendJoin('|', stringValues).ToString()); + Assert.Equal(expected, new StringBuilder().AppendJoin('|', (ReadOnlySpan)stringValues).ToString()); Assert.Equal(expected, new StringBuilder().AppendJoin("|", values).ToString()); + Assert.Equal(expected, new StringBuilder().AppendJoin("|", (ReadOnlySpan)values).ToString()); Assert.Equal(expected, new StringBuilder().AppendJoin("|", enumerable).ToString()); Assert.Equal(expected, new StringBuilder().AppendJoin("|", stringValues).ToString()); + Assert.Equal(expected, new StringBuilder().AppendJoin("|", (ReadOnlySpan)stringValues).ToString()); } [Fact] @@ -1801,9 +1838,14 @@ private sealed class NullToStringObject [InlineData(", ", "1, 2, 3")] public static void AppendJoin_TestStringSeparators(string separator, string expected) { - Assert.Equal(expected, new StringBuilder().AppendJoin(separator, new object[] { 1, 2, 3 }).ToString()); + var values = new object[] { 1, 2, 3 }; + var stringValues = new string[] { "1", "2", "3" }; + + Assert.Equal(expected, new StringBuilder().AppendJoin(separator, values).ToString()); + Assert.Equal(expected, new StringBuilder().AppendJoin(separator, (ReadOnlySpan)values).ToString()); Assert.Equal(expected, new StringBuilder().AppendJoin(separator, Enumerable.Range(1, 3)).ToString()); - Assert.Equal(expected, new StringBuilder().AppendJoin(separator, new string[] { "1", "2", "3" }).ToString()); + Assert.Equal(expected, new StringBuilder().AppendJoin(separator, stringValues).ToString()); + Assert.Equal(expected, new StringBuilder().AppendJoin(separator, (ReadOnlySpan)stringValues).ToString()); } @@ -1825,12 +1867,16 @@ public static void AppendJoin_NoValues_NoSpareCapacity_DoesNotThrow(string separ if (separator?.Length == 1) { CreateBuilderWithNoSpareCapacity().AppendJoin(separator[0], values); + CreateBuilderWithNoSpareCapacity().AppendJoin(separator[0], (ReadOnlySpan)values); CreateBuilderWithNoSpareCapacity().AppendJoin(separator[0], enumerable); CreateBuilderWithNoSpareCapacity().AppendJoin(separator[0], stringValues); + CreateBuilderWithNoSpareCapacity().AppendJoin(separator[0], (ReadOnlySpan)stringValues); } CreateBuilderWithNoSpareCapacity().AppendJoin(separator, values); + CreateBuilderWithNoSpareCapacity().AppendJoin(separator, (ReadOnlySpan)values); CreateBuilderWithNoSpareCapacity().AppendJoin(separator, enumerable); CreateBuilderWithNoSpareCapacity().AppendJoin(separator, stringValues); + CreateBuilderWithNoSpareCapacity().AppendJoin(separator, (ReadOnlySpan)stringValues); } [Theory] @@ -1849,12 +1895,16 @@ public static void AppendJoin_NoSpareCapacity_ThrowsArgumentOutOfRangeException( if (separator?.Length == 1) { AssertExtensions.Throws(s_noCapacityParamName, () => CreateBuilderWithNoSpareCapacity().AppendJoin(separator[0], values)); + AssertExtensions.Throws(s_noCapacityParamName, () => CreateBuilderWithNoSpareCapacity().AppendJoin(separator[0], (ReadOnlySpan)values)); AssertExtensions.Throws(s_noCapacityParamName, () => CreateBuilderWithNoSpareCapacity().AppendJoin(separator[0], enumerable)); AssertExtensions.Throws(s_noCapacityParamName, () => CreateBuilderWithNoSpareCapacity().AppendJoin(separator[0], stringValues)); + AssertExtensions.Throws(s_noCapacityParamName, () => CreateBuilderWithNoSpareCapacity().AppendJoin(separator[0], (ReadOnlySpan)stringValues)); } AssertExtensions.Throws(s_noCapacityParamName, () => CreateBuilderWithNoSpareCapacity().AppendJoin(separator, values)); + AssertExtensions.Throws(s_noCapacityParamName, () => CreateBuilderWithNoSpareCapacity().AppendJoin(separator, (ReadOnlySpan)values)); AssertExtensions.Throws(s_noCapacityParamName, () => CreateBuilderWithNoSpareCapacity().AppendJoin(separator, enumerable)); AssertExtensions.Throws(s_noCapacityParamName, () => CreateBuilderWithNoSpareCapacity().AppendJoin(separator, stringValues)); + AssertExtensions.Throws(s_noCapacityParamName, () => CreateBuilderWithNoSpareCapacity().AppendJoin(separator, (ReadOnlySpan)stringValues)); } [Theory] diff --git a/src/libraries/System.Runtime/tests/System.Threading.Tasks.Tests/CancellationTokenTests.cs b/src/libraries/System.Runtime/tests/System.Threading.Tasks.Tests/CancellationTokenTests.cs index ba75f617bf0b5d..bc66b33cd9b68a 100644 --- a/src/libraries/System.Runtime/tests/System.Threading.Tasks.Tests/CancellationTokenTests.cs +++ b/src/libraries/System.Runtime/tests/System.Threading.Tasks.Tests/CancellationTokenTests.cs @@ -207,6 +207,7 @@ public static void TokenSourceDispose_Negative() //shouldn't throw CancellationTokenSource.CreateLinkedTokenSource(new[] { token, token }); + CancellationTokenSource.CreateLinkedTokenSource((ReadOnlySpan)new[] { token, token }); } /// @@ -431,15 +432,20 @@ public static void CreateLinkedTokenSource_Simple_TwoToken() "CreateLinkedToken_Simple_TwoToken: The combined token should now be signalled"); } - [Fact] - public static void CreateLinkedTokenSource_Simple_MultiToken() + [Theory] + [InlineData(false)] + [InlineData(true)] + public static void CreateLinkedTokenSource_Simple_MultiToken(bool useSpan) { CancellationTokenSource signal1 = new CancellationTokenSource(); CancellationTokenSource signal2 = new CancellationTokenSource(); CancellationTokenSource signal3 = new CancellationTokenSource(); //Neither token is signalled. - CancellationTokenSource combined = CancellationTokenSource.CreateLinkedTokenSource(new[] { signal1.Token, signal2.Token, signal3.Token }); + CancellationTokenSource combined = useSpan ? + CancellationTokenSource.CreateLinkedTokenSource((ReadOnlySpan)new[] { signal1.Token, signal2.Token, signal3.Token }) : + CancellationTokenSource.CreateLinkedTokenSource(new[] { signal1.Token, signal2.Token, signal3.Token }); + Assert.False(combined.IsCancellationRequested, "CreateLinkedToken_Simple_MultiToken: The combined token should start unsignalled"); diff --git a/src/libraries/System.Runtime/tests/System.Threading.Tasks.Tests/MethodCoverage.cs b/src/libraries/System.Runtime/tests/System.Threading.Tasks.Tests/MethodCoverage.cs index 2634e8340ef9ec..01af9fb525c035 100644 --- a/src/libraries/System.Runtime/tests/System.Threading.Tasks.Tests/MethodCoverage.cs +++ b/src/libraries/System.Runtime/tests/System.Threading.Tasks.Tests/MethodCoverage.cs @@ -188,14 +188,30 @@ public static void Task_WhenAny_TwoTasks_InvalidArgs_Throws() AssertExtensions.Throws("task2", () => Task.WhenAny(Task.FromResult(2), null)); } + [Fact] + public static void Task_WhenAny_NullTaskElement_Throws() + { + AssertExtensions.Throws("tasks", () => { Task.WhenAny(new Task[] { null }); }); + AssertExtensions.Throws("tasks", () => { Task.WhenAny((ReadOnlySpan)new Task[] { null }); }); + AssertExtensions.Throws("tasks", () => { Task.WhenAny(NullElementIterator()); }); + + AssertExtensions.Throws("tasks", () => { Task.WhenAny(new Task[] { null }); }); + AssertExtensions.Throws("tasks", () => { Task.WhenAny((ReadOnlySpan>)new Task[] { null }); }); + AssertExtensions.Throws("tasks", () => { Task.WhenAny(NullElementIterator>()); }); + + static IEnumerable NullElementIterator() where T : Task { yield return null; } + } + [Fact] public static void Task_WhenAny_NoTasks_Throws() { AssertExtensions.Throws("tasks", () => { Task.WhenAny(new Task[0]); }); + AssertExtensions.Throws("tasks", () => { Task.WhenAny(ReadOnlySpan.Empty); }); AssertExtensions.Throws("tasks", () => { Task.WhenAny(new List()); }); AssertExtensions.Throws("tasks", () => { Task.WhenAny(EmptyIterator()); }); AssertExtensions.Throws("tasks", () => { Task.WhenAny(new Task[0]); }); + AssertExtensions.Throws("tasks", () => { Task.WhenAny(ReadOnlySpan>.Empty); }); AssertExtensions.Throws("tasks", () => { Task.WhenAny(new List>()); }); AssertExtensions.Throws("tasks", () => { Task.WhenAny(EmptyIterator>()); }); @@ -353,6 +369,36 @@ public static void FromAsync() mre2.WaitOne(); } + [Fact] + public static void Task_WaitAll_NullArgument_Throws() + { + AssertExtensions.Throws("tasks", () => { Task.WaitAll((Task[])null); }); + AssertExtensions.Throws("tasks", () => { Task.WaitAll((Task[])null, CancellationToken.None); }); + AssertExtensions.Throws("tasks", () => { Task.WaitAll((Task[])null, 30_000); }); + AssertExtensions.Throws("tasks", () => { Task.WaitAll((Task[])null, TimeSpan.FromSeconds(30)); }); + AssertExtensions.Throws("tasks", () => { Task.WaitAll((Task[])null, 30_000, CancellationToken.None); }); + } + + [Fact] + public static void Task_WaitAll_NullTaskElement_Throws() + { + Task[] nullElement = [null]; + AssertExtensions.Throws("tasks", () => { Task.WaitAll(nullElement); }); + AssertExtensions.Throws("tasks", () => { Task.WaitAll((ReadOnlySpan)nullElement); }); + AssertExtensions.Throws("tasks", () => { Task.WaitAll(nullElement, CancellationToken.None); }); + AssertExtensions.Throws("tasks", () => { Task.WaitAll(nullElement, 30_000); }); + AssertExtensions.Throws("tasks", () => { Task.WaitAll(nullElement, TimeSpan.FromSeconds(30)); }); + AssertExtensions.Throws("tasks", () => { Task.WaitAll(nullElement, 30_000, CancellationToken.None); }); + } + + [Fact] + public static void Task_WaitAll_InvalidArgument_Throws() + { + Assert.Throws(() => Task.WaitAll([Task.Factory.StartNew(() => { })], -2)); + Assert.Throws(() => Task.WaitAll([Task.Factory.StartNew(() => { })], -2, CancellationToken.None)); + Assert.Throws(() => Task.WaitAll([Task.Factory.StartNew(() => { })], TimeSpan.FromMilliseconds(-2))); + } + [Fact] public static void Task_WhenAll_NullArgument_Throws() { @@ -363,14 +409,30 @@ public static void Task_WhenAll_NullArgument_Throws() AssertExtensions.Throws("tasks", () => { Task.WhenAll((IEnumerable>)null); }); } + [Fact] + public static void Task_WhenAll_NullTaskElement_Throws() + { + AssertExtensions.Throws("tasks", () => { Task.WhenAll(new Task[] { null }); }); + AssertExtensions.Throws("tasks", () => { Task.WhenAll((ReadOnlySpan)new Task[] { null }); }); + AssertExtensions.Throws("tasks", () => { Task.WhenAll(NullElementIterator()); }); + + AssertExtensions.Throws("tasks", () => { Task.WhenAll(new Task[] { null }); }); + AssertExtensions.Throws("tasks", () => { Task.WhenAll((ReadOnlySpan>)new Task[] { null }); }); + AssertExtensions.Throws("tasks", () => { Task.WhenAll(NullElementIterator>()); }); + + static IEnumerable NullElementIterator() where T : Task { yield return null; } + } + [Fact] public static void Task_WhenAll_NoTasks_IsCompletedSuccessfully() { Assert.True(Task.WhenAll(new Task[0]).IsCompletedSuccessfully); + Assert.True(Task.WhenAll(ReadOnlySpan.Empty).IsCompletedSuccessfully); Assert.True(Task.WhenAll(new List()).IsCompletedSuccessfully); Assert.True(Task.WhenAll(EmptyIterator()).IsCompletedSuccessfully); AssertIsCompletedWithEmptyResult(Task.WhenAll(new Task[0])); + AssertIsCompletedWithEmptyResult(Task.WhenAll(ReadOnlySpan>.Empty)); AssertIsCompletedWithEmptyResult(Task.WhenAll(new List>())); AssertIsCompletedWithEmptyResult(Task.WhenAll(EmptyIterator>())); diff --git a/src/libraries/System.Runtime/tests/System.Threading.Tasks.Tests/Task/TaskRtTests_Core.cs b/src/libraries/System.Runtime/tests/System.Threading.Tasks.Tests/Task/TaskRtTests_Core.cs index 088c45ddc116fc..1225ca6433a291 100644 --- a/src/libraries/System.Runtime/tests/System.Threading.Tasks.Tests/Task/TaskRtTests_Core.cs +++ b/src/libraries/System.Runtime/tests/System.Threading.Tasks.Tests/Task/TaskRtTests_Core.cs @@ -1338,11 +1338,6 @@ public static void RunTaskWaitAnyTests_WithCancellationTokenTests() [OuterLoop] public static void RunTaskWaitAllTests() { - Assert.Throws(() => Task.WaitAll((Task[])null)); - AssertExtensions.Throws("tasks", () => Task.WaitAll(new Task[] { null })); - Assert.Throws(() => Task.WaitAll(new Task[] { Task.Factory.StartNew(() => { }) }, -2)); - Assert.Throws(() => Task.WaitAll(new Task[] { Task.Factory.StartNew(() => { }) }, TimeSpan.FromMilliseconds(-2))); - ThreadPoolHelpers.EnsureMinThreadsAtLeast(10); RunTaskWaitAllTest(false, 1); RunTaskWaitAllTest(false, 10); diff --git a/src/libraries/System.Security.Claims/src/System.Security.Claims.csproj b/src/libraries/System.Security.Claims/src/System.Security.Claims.csproj index e1e3b9838c4c25..4376906dbbc4bf 100644 --- a/src/libraries/System.Security.Claims/src/System.Security.Claims.csproj +++ b/src/libraries/System.Security.Claims/src/System.Security.Claims.csproj @@ -18,6 +18,7 @@ + diff --git a/src/libraries/System.Text.Json/ref/System.Text.Json.cs b/src/libraries/System.Text.Json/ref/System.Text.Json.cs index 0ff5bdc90a66ee..e16277de475290 100644 --- a/src/libraries/System.Text.Json/ref/System.Text.Json.cs +++ b/src/libraries/System.Text.Json/ref/System.Text.Json.cs @@ -659,7 +659,9 @@ namespace System.Text.Json.Nodes public sealed partial class JsonArray : System.Text.Json.Nodes.JsonNode, System.Collections.Generic.ICollection, System.Collections.Generic.IEnumerable, System.Collections.Generic.IList, System.Collections.IEnumerable { public JsonArray(System.Text.Json.Nodes.JsonNodeOptions? options = default(System.Text.Json.Nodes.JsonNodeOptions?)) { } + public JsonArray(System.Text.Json.Nodes.JsonNodeOptions options, System.ReadOnlySpan items) { } public JsonArray(System.Text.Json.Nodes.JsonNodeOptions options, params System.Text.Json.Nodes.JsonNode?[] items) { } + public JsonArray(System.ReadOnlySpan items) { } public JsonArray(params System.Text.Json.Nodes.JsonNode?[] items) { } public int Count { get { throw null; } } bool System.Collections.Generic.ICollection.IsReadOnly { get { throw null; } } @@ -1352,6 +1354,7 @@ public enum JsonTypeInfoKind } public static partial class JsonTypeInfoResolver { + public static System.Text.Json.Serialization.Metadata.IJsonTypeInfoResolver Combine(System.ReadOnlySpan resolvers) { throw null; } public static System.Text.Json.Serialization.Metadata.IJsonTypeInfoResolver Combine(params System.Text.Json.Serialization.Metadata.IJsonTypeInfoResolver?[] resolvers) { throw null; } public static System.Text.Json.Serialization.Metadata.IJsonTypeInfoResolver WithAddedModifier(this System.Text.Json.Serialization.Metadata.IJsonTypeInfoResolver resolver, System.Action modifier) { throw null; } } diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Nodes/JsonArray.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Nodes/JsonArray.cs index f8429dad3ffeef..600249db627b2b 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Nodes/JsonArray.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Nodes/JsonArray.cs @@ -39,6 +39,16 @@ public JsonArray(JsonNodeOptions options, params JsonNode?[] items) : base(optio InitializeFromArray(items); } + /// + /// Initializes a new instance of the class that contains items from the specified params span. + /// + /// Options to control the behavior. + /// The items to add to the new . + public JsonArray(JsonNodeOptions options, /*params*/ ReadOnlySpan items) : base(options) + { + InitializeFromSpan(items); + } + /// /// Initializes a new instance of the class that contains items from the specified array. /// @@ -48,6 +58,15 @@ public JsonArray(params JsonNode?[] items) : base() InitializeFromArray(items); } + /// + /// Initializes a new instance of the class that contains items from the specified span. + /// + /// The items to add to the new . + public JsonArray(/*params*/ ReadOnlySpan items) : base() + { + InitializeFromSpan(items); + } + internal override JsonValueKind GetValueKindCore() => JsonValueKind.Array; internal override JsonNode DeepCloneCore() @@ -129,9 +148,30 @@ private void InitializeFromArray(JsonNode?[] items) { var list = new List(items); - for (int i = 0; i < items.Length; i++) + for (int i = 0; i < list.Count; i++) + { + list[i]?.AssignParent(this); + } + + _list = list; + } + + private void InitializeFromSpan(ReadOnlySpan items) + { + List list = new(items.Length); + +#if NET8_0_OR_GREATER + list.AddRange(items); +#else + foreach (JsonNode? item in items) + { + list.Add(item); + } +#endif + + for (int i = 0; i < list.Count; i++) { - items[i]?.AssignParent(this); + list[i]?.AssignParent(this); } _list = list; diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Metadata/JsonTypeInfoResolver.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Metadata/JsonTypeInfoResolver.cs index 216329609f3b90..9bd63188cbe525 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Metadata/JsonTypeInfoResolver.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Metadata/JsonTypeInfoResolver.cs @@ -30,6 +30,25 @@ public static IJsonTypeInfoResolver Combine(params IJsonTypeInfoResolver?[] reso ThrowHelper.ThrowArgumentNullException(nameof(resolvers)); } + return Combine((ReadOnlySpan)resolvers); + } + + /// + /// Combines multiple sources into one. + /// + /// Sequence of contract resolvers to be queried for metadata. + /// A combining results from . + /// + /// The combined resolver will query each of in the specified order, + /// returning the first result that is non-null. If all return null, + /// then the combined resolver will also return . + /// + /// Can be used to combine multiple sources, + /// which typically define contract metadata for small subsets of types. + /// It can also be used to fall back to wherever necessary. + /// + public static IJsonTypeInfoResolver Combine(/*params*/ ReadOnlySpan resolvers) + { var resolverChain = new JsonTypeInfoResolverChain(); foreach (IJsonTypeInfoResolver? resolver in resolvers) { diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/JsonNode/JsonArrayTests.cs b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/JsonNode/JsonArrayTests.cs index ef51703958151c..3b8a7b8c4b6b4e 100644 --- a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/JsonNode/JsonArrayTests.cs +++ b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/JsonNode/JsonArrayTests.cs @@ -12,6 +12,25 @@ namespace System.Text.Json.Nodes.Tests { public static class JsonArrayTests { + [Fact] + public static void ParamsContructors() + { + JsonArray expectedArray = [41, 42, 43]; + JsonNodeOptions options = new JsonNodeOptions { PropertyNameCaseInsensitive = true }; + + Verify(new JsonArray(new JsonNode[] { 41, 42, 43 }), null); + Verify(new JsonArray((ReadOnlySpan)new JsonNode[] { 41, 42, 43 }), null); + Verify(new JsonArray(options, new JsonNode[] { 41, 42, 43 }), options); + Verify(new JsonArray(options, (ReadOnlySpan)new JsonNode[] { 41, 42, 43 }), options); + + void Verify(JsonArray jsonArray, JsonNodeOptions? expectedOptions) + { + Assert.Equal(expectedArray.Count, jsonArray.Count); + JsonNodeTests.AssertDeepEqual(expectedArray, jsonArray); + Assert.Equal(expectedOptions, jsonArray.Options); + } + } + [Fact] public static void FromElement() { @@ -34,7 +53,7 @@ public static void FromElement() public static void FromElement_WrongNodeTypeThrows(string json) { using (JsonDocument document = JsonDocument.Parse(json)) - Assert.Throws(() => JsonArray.Create(document.RootElement)); + Assert.Throws(() => JsonArray.Create(document.RootElement)); } [Fact] diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/MetadataTests/JsonTypeInfoResolverTests.cs b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/MetadataTests/JsonTypeInfoResolverTests.cs index 9136555b0fd9c9..17e1a73c970a00 100644 --- a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/MetadataTests/JsonTypeInfoResolverTests.cs +++ b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/MetadataTests/JsonTypeInfoResolverTests.cs @@ -7,32 +7,46 @@ namespace System.Text.Json.Serialization.Tests { - public static partial class JsonTypeInfoResolverTests + public class JsonTypeInfoResolverCombineArrayTests : JsonTypeInfoResolverCombineTests { + public override IJsonTypeInfoResolver Combine(params IJsonTypeInfoResolver?[] resolvers) => + JsonTypeInfoResolver.Combine(resolvers); + [Fact] - public static void CombineNullArgument() + public void CombineNullArgument() { IJsonTypeInfoResolver[] resolvers = null; - Assert.Throws(() => JsonTypeInfoResolver.Combine(resolvers)); + Assert.Throws(() => Combine(resolvers)); } + } + + public class JsonTypeInfoResolverCombineSpanTests : JsonTypeInfoResolverCombineTests + { + public override IJsonTypeInfoResolver Combine(params IJsonTypeInfoResolver?[] resolvers) => + JsonTypeInfoResolver.Combine((ReadOnlySpan)resolvers); + } + + public abstract class JsonTypeInfoResolverCombineTests + { + public abstract IJsonTypeInfoResolver Combine(params IJsonTypeInfoResolver?[] resolvers); [Fact] - public static void Combine_ShouldFlattenResolvers() + public void Combine_ShouldFlattenResolvers() { DefaultJsonTypeInfoResolver nonNullResolver1 = new(); DefaultJsonTypeInfoResolver nonNullResolver2 = new(); DefaultJsonTypeInfoResolver nonNullResolver3 = new(); - ValidateCombinations(Array.Empty(), JsonTypeInfoResolver.Combine()); - ValidateCombinations(Array.Empty(), JsonTypeInfoResolver.Combine(new IJsonTypeInfoResolver[] { null })); - ValidateCombinations(Array.Empty(), JsonTypeInfoResolver.Combine(null, null)); - ValidateCombinations(new[] { nonNullResolver1 }, JsonTypeInfoResolver.Combine(nonNullResolver1, null)); - ValidateCombinations(new[] { nonNullResolver1, nonNullResolver2 }, JsonTypeInfoResolver.Combine(nonNullResolver1, nonNullResolver2, null)); - ValidateCombinations(new[] { nonNullResolver1, nonNullResolver2 }, JsonTypeInfoResolver.Combine(nonNullResolver1, null, nonNullResolver2)); - ValidateCombinations(new[] { nonNullResolver1, nonNullResolver2, nonNullResolver3 }, JsonTypeInfoResolver.Combine(JsonTypeInfoResolver.Combine(JsonTypeInfoResolver.Combine(nonNullResolver1), nonNullResolver2), nonNullResolver3)); - ValidateCombinations(new[] { nonNullResolver1, nonNullResolver2, nonNullResolver3 }, JsonTypeInfoResolver.Combine(JsonTypeInfoResolver.Combine(nonNullResolver1, null, nonNullResolver2), nonNullResolver3)); + ValidateCombinations(Array.Empty(), Combine()); + ValidateCombinations(Array.Empty(), Combine(new IJsonTypeInfoResolver[] { null })); + ValidateCombinations(Array.Empty(), Combine(null, null)); + ValidateCombinations(new[] { nonNullResolver1 }, Combine(nonNullResolver1, null)); + ValidateCombinations(new[] { nonNullResolver1, nonNullResolver2 }, Combine(nonNullResolver1, nonNullResolver2, null)); + ValidateCombinations(new[] { nonNullResolver1, nonNullResolver2 }, Combine(nonNullResolver1, null, nonNullResolver2)); + ValidateCombinations(new[] { nonNullResolver1, nonNullResolver2, nonNullResolver3 }, Combine(Combine(Combine(nonNullResolver1), nonNullResolver2), nonNullResolver3)); + ValidateCombinations(new[] { nonNullResolver1, nonNullResolver2, nonNullResolver3 }, Combine(Combine(nonNullResolver1, null, nonNullResolver2), nonNullResolver3)); - static void ValidateCombinations(IJsonTypeInfoResolver[] expectedResolvers, IJsonTypeInfoResolver combinedResolver) + void ValidateCombinations(IJsonTypeInfoResolver[] expectedResolvers, IJsonTypeInfoResolver combinedResolver) { if (expectedResolvers.Length == 1) { @@ -46,9 +60,9 @@ static void ValidateCombinations(IJsonTypeInfoResolver[] expectedResolvers, IJso } [Fact] - public static void CombiningZeroResolversProducesValidResolver() + public void CombiningZeroResolversProducesValidResolver() { - IJsonTypeInfoResolver resolver = JsonTypeInfoResolver.Combine(); + IJsonTypeInfoResolver resolver = Combine(); Assert.NotNull(resolver); // calling twice to make sure we get the same answer @@ -57,7 +71,7 @@ public static void CombiningZeroResolversProducesValidResolver() } [Fact] - public static void CombiningSingleResolverProducesSameAnswersAsInputResolver() + public void CombiningSingleResolverProducesSameAnswersAsInputResolver() { JsonSerializerOptions options = new(); JsonTypeInfo t1 = JsonTypeInfo.CreateJsonTypeInfo(typeof(int), options); @@ -74,7 +88,7 @@ public static void CombiningSingleResolverProducesSameAnswersAsInputResolver() return null; }); - IJsonTypeInfoResolver combined = JsonTypeInfoResolver.Combine(resolver); + IJsonTypeInfoResolver combined = Combine(resolver); Assert.Same(t1, combined.GetTypeInfo(typeof(int), options)); Assert.Same(t2, combined.GetTypeInfo(typeof(uint), options)); @@ -84,7 +98,7 @@ public static void CombiningSingleResolverProducesSameAnswersAsInputResolver() } [Fact] - public static void CombiningUsesAndRespectsAllResolversInOrder() + public void CombiningUsesAndRespectsAllResolversInOrder() { JsonSerializerOptions options = new(); JsonTypeInfo t1 = JsonTypeInfo.CreateJsonTypeInfo(typeof(int), options); @@ -121,7 +135,7 @@ public static void CombiningUsesAndRespectsAllResolversInOrder() return null; }); - IJsonTypeInfoResolver combined = JsonTypeInfoResolver.Combine(r1, r2, r3); + IJsonTypeInfoResolver combined = Combine(r1, r2, r3); resolverId = 1; Assert.Same(t1, combined.GetTypeInfo(typeof(int), options)); @@ -144,7 +158,7 @@ public static void CombiningUsesAndRespectsAllResolversInOrder() Assert.Equal(4, resolverId); } - private static IList GetAndValidateCombinedResolvers(IJsonTypeInfoResolver resolver) + private IList GetAndValidateCombinedResolvers(IJsonTypeInfoResolver resolver) { var list = (IList)resolver; @@ -155,8 +169,12 @@ private static IList GetAndValidateCombinedResolvers(IJso return list; } + } + + public class JsonTypeInfoResolverTests + { [Fact] - public static void WithAddedModifier_CallsModifierOnResolvedMetadata() + public void WithAddedModifier_CallsModifierOnResolvedMetadata() { int modifierInvocationCount = 0; JsonSerializerOptions options = new(); @@ -175,11 +193,11 @@ public static void WithAddedModifier_CallsModifierOnResolvedMetadata() } [Fact] - public static void WithAddedModifier_DoesNotCallModifierOnUnResolvedMetadata() + public void WithAddedModifier_DoesNotCallModifierOnUnResolvedMetadata() { int modifierInvocationCount = 0; JsonSerializerOptions options = new(); - TestResolver resolver = new((_,_) => null); + TestResolver resolver = new((_, _) => null); IJsonTypeInfoResolver resolverWithModifier = resolver.WithAddedModifier(_ => modifierInvocationCount++); @@ -191,7 +209,7 @@ public static void WithAddedModifier_DoesNotCallModifierOnUnResolvedMetadata() } [Fact] - public static void WithAddedModifier_CanChainMultipleModifiers() + public void WithAddedModifier_CanChainMultipleModifiers() { int modifier1InvocationCount = 0; int modifier2InvocationCount = 0; @@ -208,7 +226,7 @@ public static void WithAddedModifier_CanChainMultipleModifiers() } [Fact] - public static void WithAddedModifier_ChainingDoesNotMutateIntermediateResolvers() + public void WithAddedModifier_ChainingDoesNotMutateIntermediateResolvers() { int modifier1InvocationCount = 0; int modifier2InvocationCount = 0; @@ -233,7 +251,7 @@ public static void WithAddedModifier_ChainingDoesNotMutateIntermediateResolvers( } [Fact] - public static void WithAddedModifier_ThrowsOnNullArguments() + public void WithAddedModifier_ThrowsOnNullArguments() { TestResolver resolver = new(JsonTypeInfo.CreateJsonTypeInfo); @@ -242,7 +260,7 @@ public static void WithAddedModifier_ThrowsOnNullArguments() } [Fact] - public static void NullResolver_ReturnsObjectMetadata() + public void NullResolver_ReturnsObjectMetadata() { var options = new JsonSerializerOptions(); var resolver = new NullResolver(); diff --git a/src/libraries/System.Threading.Channels/src/System.Threading.Channels.csproj b/src/libraries/System.Threading.Channels/src/System.Threading.Channels.csproj index 21e101ecd6d94e..c058b0b216b17a 100644 --- a/src/libraries/System.Threading.Channels/src/System.Threading.Channels.csproj +++ b/src/libraries/System.Threading.Channels/src/System.Threading.Channels.csproj @@ -50,6 +50,7 @@ System.Threading.Channel<T> + diff --git a/src/libraries/System.Threading.Tasks.Dataflow/src/System.Threading.Tasks.Dataflow.csproj b/src/libraries/System.Threading.Tasks.Dataflow/src/System.Threading.Tasks.Dataflow.csproj index 2a1eaf2804e355..21e1af10705020 100644 --- a/src/libraries/System.Threading.Tasks.Dataflow/src/System.Threading.Tasks.Dataflow.csproj +++ b/src/libraries/System.Threading.Tasks.Dataflow/src/System.Threading.Tasks.Dataflow.csproj @@ -80,6 +80,7 @@ System.Threading.Tasks.Dataflow.WriteOnceBlock<T> + diff --git a/src/libraries/System.Threading.Tasks.Parallel/src/System.Threading.Tasks.Parallel.csproj b/src/libraries/System.Threading.Tasks.Parallel/src/System.Threading.Tasks.Parallel.csproj index 3278b9f2c5e19d..32d0f7c8cf6a3f 100644 --- a/src/libraries/System.Threading.Tasks.Parallel/src/System.Threading.Tasks.Parallel.csproj +++ b/src/libraries/System.Threading.Tasks.Parallel/src/System.Threading.Tasks.Parallel.csproj @@ -24,6 +24,7 @@ + From 5111fdc0dc464f01647d6b6078342f451bf3a499 Mon Sep 17 00:00:00 2001 From: Qiao Pengcheng Date: Tue, 23 Apr 2024 14:54:08 +0800 Subject: [PATCH 021/161] [LoongArch64] amend the LoongArch64Classifier::Classify for passing struct. (#101365) --- src/coreclr/jit/targetloongarch64.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/coreclr/jit/targetloongarch64.cpp b/src/coreclr/jit/targetloongarch64.cpp index 47f74094fab9dc..6d63951c8ea205 100644 --- a/src/coreclr/jit/targetloongarch64.cpp +++ b/src/coreclr/jit/targetloongarch64.cpp @@ -104,7 +104,7 @@ ABIPassingInformation LoongArch64Classifier::Classify(Compiler* comp, } else if ((floatFlags & STRUCT_FLOAT_FIELD_FIRST) != 0) { - slots = 1; + slots = 2; canPassArgInRegisters = (m_floatRegs.Count() > 0) && (m_intRegs.Count() > 0); argRegTypeInStruct1 = (floatFlags & STRUCT_FIRST_FIELD_SIZE_IS8) ? TYP_DOUBLE : TYP_FLOAT; @@ -112,7 +112,7 @@ ABIPassingInformation LoongArch64Classifier::Classify(Compiler* comp, } else if ((floatFlags & STRUCT_FLOAT_FIELD_SECOND) != 0) { - slots = 1; + slots = 2; canPassArgInRegisters = (m_floatRegs.Count() > 0) && (m_intRegs.Count() > 0); argRegTypeInStruct1 = (floatFlags & STRUCT_FIRST_FIELD_SIZE_IS8) ? TYP_LONG : TYP_INT; From 774bc93087ad61ef292030afa4392daa34c0233a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Paulus=20P=C3=A4rssinen?= Date: Tue, 23 Apr 2024 14:10:29 +0300 Subject: [PATCH 022/161] Use BitOperations.RoundUpToPowerOf2 in more places (#101405) * Use BitOperations.RoundUpToPowerOf2 in ThreadLocal * Use BitOperations.RoundUpToPowerOf2 in CacheDict --- .../src/System/Dynamic/Utils/CacheDict.cs | 19 ++--------- .../src/System/Threading/ThreadLocal.cs | 34 +++---------------- 2 files changed, 7 insertions(+), 46 deletions(-) diff --git a/src/libraries/System.Linq.Expressions/src/System/Dynamic/Utils/CacheDict.cs b/src/libraries/System.Linq.Expressions/src/System/Dynamic/Utils/CacheDict.cs index b1446848ce6174..9a1c951c1b184f 100644 --- a/src/libraries/System.Linq.Expressions/src/System/Dynamic/Utils/CacheDict.cs +++ b/src/libraries/System.Linq.Expressions/src/System/Dynamic/Utils/CacheDict.cs @@ -3,6 +3,7 @@ using System.Diagnostics; using System.Diagnostics.CodeAnalysis; +using System.Numerics; using System.Threading; namespace System.Dynamic.Utils @@ -40,27 +41,11 @@ internal Entry(int hash, TKey key, TValue value) /// The maximum number of elements to store will be this number aligned to next ^2. internal CacheDict(int size) { - int alignedSize = AlignSize(size); + int alignedSize = (int)BitOperations.RoundUpToPowerOf2((uint)size); _mask = alignedSize - 1; _entries = new Entry[alignedSize]; } - private static int AlignSize(int size) - { - Debug.Assert(size > 0); - - size--; - size |= size >> 1; - size |= size >> 2; - size |= size >> 4; - size |= size >> 8; - size |= size >> 16; - size++; - - Debug.Assert((size & (~size + 1)) == size, "aligned size should be a power of 2"); - return size; - } - /// /// Tries to get the value associated with 'key', returning true if it's found and /// false if it's not present. diff --git a/src/libraries/System.Private.CoreLib/src/System/Threading/ThreadLocal.cs b/src/libraries/System.Private.CoreLib/src/System/Threading/ThreadLocal.cs index 8890cde64f70d4..aa0c2e4478ca64 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Threading/ThreadLocal.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Threading/ThreadLocal.cs @@ -4,6 +4,7 @@ using System.Collections.Generic; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; +using System.Numerics; // A class that provides a simple, lightweight implementation of thread-local lazy-initialization, where a value is initialized once per accessing // thread; this provides an alternative to using a ThreadStatic static variable and having @@ -552,40 +553,15 @@ private static int GetNewTableSize(int minSize) } Debug.Assert(minSize > 0); - // - // Round up the size to the next power of 2 - // - // The algorithm takes three steps: - // input -> subtract one -> propagate 1-bits to the right -> add one - // - // Let's take a look at the 3 steps in both interesting cases: where the input - // is (Example 1) and isn't (Example 2) a power of 2. - // - // Example 1: 100000 -> 011111 -> 011111 -> 100000 - // Example 2: 011010 -> 011001 -> 011111 -> 100000 - // - int newSize = minSize; - - // Step 1: Decrement - newSize--; - - // Step 2: Propagate 1-bits to the right. - newSize |= newSize >> 1; - newSize |= newSize >> 2; - newSize |= newSize >> 4; - newSize |= newSize >> 8; - newSize |= newSize >> 16; - - // Step 3: Increment - newSize++; + uint newSize = BitOperations.RoundUpToPowerOf2((uint)minSize); // Don't set newSize to more than Array.MaxArrayLength - if ((uint)newSize > Array.MaxLength) + if (newSize > Array.MaxLength) { - newSize = Array.MaxLength; + newSize = (uint)Array.MaxLength; } - return newSize; + return (int)newSize; } /// From edb6e7c154a4a75c8d1430cd6a996e6f1f9b401e Mon Sep 17 00:00:00 2001 From: Qiao Pengcheng Date: Tue, 23 Apr 2024 19:41:05 +0800 Subject: [PATCH 023/161] Adjust the calleeSavedRegs on top frame for LoongArch64/RISCV64 (#100962) The frame layout: | | |-----------------------| | incoming arguments | +=======================+ <---- Caller's SP | Varargs regs space | // Only for varargs main functions; not used for LA64. |-----------------------| | MonitorAcquired | // 8 bytes; for synchronized methods |-----------------------| | PSP slot | // 8 bytes (omitted in NativeAOT ABI) |-----------------------| |Callee saved registers | // multiple of 8 bytes, not includting FP/RA |-----------------------| | Saved RA | // 8 bytes |-----------------------| | Saved FP | // 8 bytes |-----------------------| | possible GS cookie | |-----------------------| | locals, temps, etc. | |-----------------------| | possible GS cookie | |-----------------------| | Outgoing arg space | // multiple of 8 bytes; if required (i.e., #outsz != 0) |-----------------------| <---- Ambient SP | | | ~ | Stack grows ~ | | downward | --- src/coreclr/jit/codegen.h | 23 +- src/coreclr/jit/codegencommon.cpp | 17 +- src/coreclr/jit/codegenloongarch64.cpp | 587 +++++++++---------------- src/coreclr/jit/codegenriscv64.cpp | 485 ++++++++------------ src/coreclr/jit/lclvars.cpp | 61 ++- src/coreclr/jit/regset.h | 3 +- 6 files changed, 450 insertions(+), 726 deletions(-) diff --git a/src/coreclr/jit/codegen.h b/src/coreclr/jit/codegen.h index 3511935a062b0a..f5e0dc857a7d4c 100644 --- a/src/coreclr/jit/codegen.h +++ b/src/coreclr/jit/codegen.h @@ -437,7 +437,7 @@ class CodeGen final : public CodeGenInterface FuncletFrameInfoDsc genFuncletInfo; -#elif defined(TARGET_LOONGARCH64) +#elif defined(TARGET_LOONGARCH64) || defined(TARGET_RISCV64) // A set of information that is used by funclet prolog and epilog generation. // It is collected once, before funclet prologs and epilogs are generated, @@ -448,26 +448,6 @@ class CodeGen final : public CodeGenInterface int fiFunction_CallerSP_to_FP_delta; // Delta between caller SP and the frame pointer in the parent function // (negative) int fiSP_to_CalleeSaved_delta; // CalleeSaved register save offset from SP (positive) - int fiCalleeSavedPadding; // CalleeSaved offset padding (positive) - int fiSP_to_PSP_slot_delta; // PSP slot offset from SP (positive) - int fiCallerSP_to_PSP_slot_delta; // PSP slot offset from Caller SP (negative) - int fiSpDelta; // Stack pointer delta (negative) - }; - - FuncletFrameInfoDsc genFuncletInfo; - -#elif defined(TARGET_RISCV64) - - // A set of information that is used by funclet prolog and epilog generation. - // It is collected once, before funclet prologs and epilogs are generated, - // and used by all funclet prologs and epilogs, which must all be the same. - struct FuncletFrameInfoDsc - { - regMaskTP fiSaveRegs; // Set of callee-saved registers saved in the funclet prolog (includes RA) - int fiFunction_CallerSP_to_FP_delta; // Delta between caller SP and the frame pointer in the parent function - // (negative) - int fiSP_to_CalleeSaved_delta; // CalleeSaved register save offset from SP (positive) - int fiCalleeSavedPadding; // CalleeSaved offset padding (positive) int fiSP_to_PSP_slot_delta; // PSP slot offset from SP (positive) int fiCallerSP_to_PSP_slot_delta; // PSP slot offset from Caller SP (negative) int fiSpDelta; // Stack pointer delta (negative) @@ -1272,7 +1252,6 @@ class CodeGen final : public CodeGenInterface void genJmpMethod(GenTree* jmp); BasicBlock* genCallFinally(BasicBlock* block); #if defined(TARGET_LOONGARCH64) || defined(TARGET_RISCV64) - // TODO: refactor for LA. void genCodeForJumpCompare(GenTreeOpCC* tree); #endif #if defined(TARGET_ARM64) diff --git a/src/coreclr/jit/codegencommon.cpp b/src/coreclr/jit/codegencommon.cpp index 417a7e6f31695d..c8211a7e731440 100644 --- a/src/coreclr/jit/codegencommon.cpp +++ b/src/coreclr/jit/codegencommon.cpp @@ -4744,20 +4744,13 @@ void CodeGen::genFinalizeFrame() #endif // defined(TARGET_XARCH) #if defined(TARGET_LOONGARCH64) || defined(TARGET_RISCV64) - if (isFramePointerUsed()) - { - // For a FP based frame we have to push/pop the FP register - // - maskCalleeRegsPushed |= RBM_FPBASE; + // This assert check that we are not using REG_FP + assert(!regSet.rsRegsModified(RBM_FPBASE)); - // This assert check that we are not using REG_FP - // as both the frame pointer and as a codegen register - // - assert(!regSet.rsRegsModified(RBM_FPBASE)); - } + assert(isFramePointerUsed()); + // we always push FP/RA. See genPushCalleeSavedRegisters + maskCalleeRegsPushed |= (RBM_FPBASE | RBM_RA); - // we always push RA. See genPushCalleeSavedRegisters - maskCalleeRegsPushed |= RBM_RA; #endif // TARGET_LOONGARCH64 || TARGET_RISCV64 compiler->compCalleeRegsPushed = genCountBits(maskCalleeRegsPushed); diff --git a/src/coreclr/jit/codegenloongarch64.cpp b/src/coreclr/jit/codegenloongarch64.cpp index 2954a989c74668..1bd29a432ce170 100644 --- a/src/coreclr/jit/codegenloongarch64.cpp +++ b/src/coreclr/jit/codegenloongarch64.cpp @@ -190,8 +190,7 @@ void CodeGen::genStackPointerAdjustment(ssize_t spDelta, regNumber tmpReg, bool* // reg1 - First register of pair to save. // reg2 - Second register of pair to save. // spOffset - The offset from SP to store reg1 (must be positive or zero). -// spDelta - If non-zero, the amount to add to SP before the register saves (must be negative or -// zero). +// spDelta - Always zero for LoongArch64 now. // useSaveNextPair - True if the last prolog instruction was to save the previous register pair. This // allows us to emit the "save_next" unwind code. // tmpReg - An available temporary register. Needed for the case of large frames. @@ -210,8 +209,7 @@ void CodeGen::genPrologSaveRegPair(regNumber reg1, bool* pTmpRegIsZero) { assert(spOffset >= 0); - assert(spDelta <= 0); - assert((spDelta % 16) == 0); // SP changes must be 16-byte aligned + assert(spDelta == 0); assert(genIsValidFloatReg(reg1) == genIsValidFloatReg(reg2)); // registers must be both general-purpose, or both // FP/SIMD @@ -221,16 +219,6 @@ void CodeGen::genPrologSaveRegPair(regNumber reg1, ins = INS_fst_d; } - if (spDelta != 0) - { - // generate addi.d SP,SP,-imm - genStackPointerAdjustment(spDelta, tmpReg, pTmpRegIsZero, /* reportUnwindData */ true); - - assert((spDelta + spOffset + 16) <= 0); - - assert(spOffset <= 2031); // 2047-16 - } - GetEmitter()->emitIns_R_R_I(ins, EA_PTRSIZE, reg1, REG_SPBASE, spOffset); compiler->unwindSaveReg(reg1, spOffset); @@ -249,8 +237,7 @@ void CodeGen::genPrologSaveRegPair(regNumber reg1, // Arguments: // reg1 - Register to save. // spOffset - The offset from SP to store reg1 (must be positive or zero). -// spDelta - If non-zero, the amount to add to SP before the register saves (must be negative or -// zero). +// spDelta - Always zero for LoongArch64 now. // tmpReg - An available temporary register. Needed for the case of large frames. // pTmpRegIsZero - If we use tmpReg, and pTmpRegIsZero is non-null, we set *pTmpRegIsZero to 'false'. // Otherwise, we don't touch it. @@ -261,8 +248,7 @@ void CodeGen::genPrologSaveRegPair(regNumber reg1, void CodeGen::genPrologSaveReg(regNumber reg1, int spOffset, int spDelta, regNumber tmpReg, bool* pTmpRegIsZero) { assert(spOffset >= 0); - assert(spDelta <= 0); - assert((spDelta % 16) == 0); // SP changes must be 16-byte aligned + assert(spDelta == 0); instruction ins = INS_st_d; if (genIsValidFloatReg(reg1)) @@ -270,12 +256,6 @@ void CodeGen::genPrologSaveReg(regNumber reg1, int spOffset, int spDelta, regNum ins = INS_fst_d; } - if (spDelta != 0) - { - // generate addi.d SP,SP,-imm - genStackPointerAdjustment(spDelta, tmpReg, pTmpRegIsZero, /* reportUnwindData */ true); - } - GetEmitter()->emitIns_R_R_I(ins, EA_PTRSIZE, reg1, REG_SPBASE, spOffset); compiler->unwindSaveReg(reg1, spOffset); } @@ -290,8 +270,7 @@ void CodeGen::genPrologSaveReg(regNumber reg1, int spOffset, int spDelta, regNum // reg1 - First register of pair to restore. // reg2 - Second register of pair to restore. // spOffset - The offset from SP to load reg1 (must be positive or zero). -// spDelta - If non-zero, the amount to add to SP after the register restores (must be positive or -// zero). +// spDelta - Always zero for LoongArch64 now. // useSaveNextPair - True if the last prolog instruction was to save the previous register pair. This // allows us to emit the "save_next" unwind code. // tmpReg - An available temporary register. Needed for the case of large frames. @@ -310,8 +289,7 @@ void CodeGen::genEpilogRestoreRegPair(regNumber reg1, bool* pTmpRegIsZero) { assert(spOffset >= 0); - assert(spDelta >= 0); - assert((spDelta % 16) == 0); // SP changes must be 16-byte aligned + assert(spDelta == 0); assert(genIsValidFloatReg(reg1) == genIsValidFloatReg(reg2)); // registers must be both general-purpose, or both // FP/SIMD @@ -321,27 +299,11 @@ void CodeGen::genEpilogRestoreRegPair(regNumber reg1, ins = INS_fld_d; } - if (spDelta != 0) - { - assert(!useSaveNextPair); - - GetEmitter()->emitIns_R_R_I(ins, EA_PTRSIZE, reg2, REG_SPBASE, spOffset + 8); - compiler->unwindSaveReg(reg2, spOffset + 8); - - GetEmitter()->emitIns_R_R_I(ins, EA_PTRSIZE, reg1, REG_SPBASE, spOffset); - compiler->unwindSaveReg(reg1, spOffset); - - // generate addi.d SP,SP,imm - genStackPointerAdjustment(spDelta, tmpReg, pTmpRegIsZero, /* reportUnwindData */ true); - } - else - { - GetEmitter()->emitIns_R_R_I(ins, EA_PTRSIZE, reg2, REG_SPBASE, spOffset + 8); - compiler->unwindSaveReg(reg2, spOffset + 8); + GetEmitter()->emitIns_R_R_I(ins, EA_PTRSIZE, reg2, REG_SPBASE, spOffset + 8); + compiler->unwindSaveReg(reg2, spOffset + 8); - GetEmitter()->emitIns_R_R_I(ins, EA_PTRSIZE, reg1, REG_SPBASE, spOffset); - compiler->unwindSaveReg(reg1, spOffset); - } + GetEmitter()->emitIns_R_R_I(ins, EA_PTRSIZE, reg1, REG_SPBASE, spOffset); + compiler->unwindSaveReg(reg1, spOffset); } //------------------------------------------------------------------------ @@ -350,8 +312,7 @@ void CodeGen::genEpilogRestoreRegPair(regNumber reg1, // Arguments: // reg1 - Register to restore. // spOffset - The offset from SP to restore reg1 (must be positive or zero). -// spDelta - If non-zero, the amount to add to SP after the register restores (must be positive or -// zero). +// spDelta - Always zero for LoongArch64 now. // tmpReg - An available temporary register. Needed for the case of large frames. // pTmpRegIsZero - If we use tmpReg, and pTmpRegIsZero is non-null, we set *pTmpRegIsZero to 'false'. // Otherwise, we don't touch it. @@ -362,8 +323,7 @@ void CodeGen::genEpilogRestoreRegPair(regNumber reg1, void CodeGen::genEpilogRestoreReg(regNumber reg1, int spOffset, int spDelta, regNumber tmpReg, bool* pTmpRegIsZero) { assert(spOffset >= 0); - assert(spDelta >= 0); - assert((spDelta % 16) == 0); // SP changes must be 16-byte aligned + assert(spDelta == 0); instruction ins = INS_ld_d; if (genIsValidFloatReg(reg1)) @@ -371,20 +331,8 @@ void CodeGen::genEpilogRestoreReg(regNumber reg1, int spOffset, int spDelta, reg ins = INS_fld_d; } - if (spDelta != 0) - { - // ld.d reg1,SP,offset - GetEmitter()->emitIns_R_R_I(ins, EA_PTRSIZE, reg1, REG_SPBASE, spOffset); - compiler->unwindSaveReg(reg1, spOffset); - - // generate addi.d SP,SP,imm - genStackPointerAdjustment(spDelta, tmpReg, pTmpRegIsZero, /* reportUnwindData */ true); - } - else - { - GetEmitter()->emitIns_R_R_I(ins, EA_PTRSIZE, reg1, REG_SPBASE, spOffset); - compiler->unwindSaveReg(reg1, spOffset); - } + GetEmitter()->emitIns_R_R_I(ins, EA_PTRSIZE, reg1, REG_SPBASE, spOffset); + compiler->unwindSaveReg(reg1, spOffset); } //------------------------------------------------------------------------ @@ -519,12 +467,13 @@ int CodeGen::genGetSlotSizeForRegsInMask(regMaskTP regsMask) // genSaveCalleeSavedRegisterGroup: Saves the group of registers described by the mask. // // Arguments: -// regsMask - a mask of registers for prolog generation; -// spDelta - if non-zero, the amount to add to SP before the first register save (or together with it); -// spOffset - the offset from SP that is the beginning of the callee-saved register area; +// regsMask - a mask of registers for prolog generation; +// spDelta - Always zero for LoongArch64 now. +// spOffset - the offset from SP that is the beginning of the callee-saved register area; // void CodeGen::genSaveCalleeSavedRegisterGroup(regMaskTP regsMask, int spDelta, int spOffset) { + assert(spDelta == 0); const int slotSize = genGetSlotSizeForRegsInMask(regsMask); ArrayStack regStack(compiler->getAllocator(CMK_Codegen)); @@ -536,19 +485,16 @@ void CodeGen::genSaveCalleeSavedRegisterGroup(regMaskTP regsMask, int spDelta, i if (regPair.reg2 != REG_NA) { // We can use two SD instructions. - genPrologSaveRegPair(regPair.reg1, regPair.reg2, spOffset, spDelta, regPair.useSaveNextPair, REG_R21, - nullptr); + genPrologSaveRegPair(regPair.reg1, regPair.reg2, spOffset, 0, regPair.useSaveNextPair, REG_R21, nullptr); spOffset += 2 * slotSize; } else { // No register pair; we use a SD instruction. - genPrologSaveReg(regPair.reg1, spOffset, spDelta, REG_R21, nullptr); + genPrologSaveReg(regPair.reg1, spOffset, 0, REG_R21, nullptr); spOffset += slotSize; } - - spDelta = 0; // We've now changed SP already, if necessary; don't do it again. } } @@ -574,34 +520,22 @@ void CodeGen::genSaveCalleeSavedRegisterGroup(regMaskTP regsMask, int spDelta, i // // Arguments: // regsToSaveMask - The mask of callee-saved registers to save. If empty, this function does nothing. -// lowestCalleeSavedOffset - The offset from SP that is the beginning of the callee-saved register area. Note that -// if non-zero spDelta, then this is the offset of the first save *after* that -// SP adjustment. -// spDelta - If non-zero, the amount to add to SP before the register saves (must be negative or -// zero). +// lowestCalleeSavedOffset - The offset from SP that is the beginning of the callee-saved register area. +// spDelta - Always zero for LoongArch64 now. // // Notes: // The save set can not contain FP/RA in which case FP/RA is saved along with the other callee-saved registers. // void CodeGen::genSaveCalleeSavedRegistersHelp(regMaskTP regsToSaveMask, int lowestCalleeSavedOffset, int spDelta) { - assert(spDelta <= 0); + assert(spDelta == 0); - unsigned regsToSaveCount = genCountBits(regsToSaveMask); - if (regsToSaveCount == 0) + if (regsToSaveMask == 0) { - if (spDelta != 0) - { - // Currently this is the case for varargs only - // whose size is MAX_REG_ARG * REGSIZE_BYTES = 64 bytes. - genStackPointerAdjustment(spDelta, REG_R21, nullptr, /* reportUnwindData */ true); - } return; } - assert((spDelta % 16) == 0); - - assert(regsToSaveCount <= genCountBits(RBM_CALLEE_SAVED)); + assert(genCountBits(regsToSaveMask) <= genCountBits(RBM_CALLEE_SAVED)); // Save integer registers at higher addresses than floating-point registers. @@ -610,15 +544,14 @@ void CodeGen::genSaveCalleeSavedRegistersHelp(regMaskTP regsToSaveMask, int lowe if (maskSaveRegsFloat != RBM_NONE) { - genSaveCalleeSavedRegisterGroup(maskSaveRegsFloat, spDelta, lowestCalleeSavedOffset); - spDelta = 0; + genSaveCalleeSavedRegisterGroup(maskSaveRegsFloat, 0, lowestCalleeSavedOffset); lowestCalleeSavedOffset += genCountBits(maskSaveRegsFloat) * FPSAVE_REGSIZE_BYTES; } if (maskSaveRegsInt != RBM_NONE) { - genSaveCalleeSavedRegisterGroup(maskSaveRegsInt, spDelta, lowestCalleeSavedOffset); - // No need to update spDelta, lowestCalleeSavedOffset since they're not used after this. + // No need to update spDelta. + genSaveCalleeSavedRegisterGroup(maskSaveRegsInt, 0, lowestCalleeSavedOffset); } } @@ -627,11 +560,12 @@ void CodeGen::genSaveCalleeSavedRegistersHelp(regMaskTP regsToSaveMask, int lowe // // Arguments: // regsMask - a mask of registers for epilog generation; -// spDelta - if non-zero, the amount to add to SP after the last register restore (or together with it); +// spDelta - Always zero for LoongArch64 now. // spOffset - the offset from SP that is the beginning of the callee-saved register area; // void CodeGen::genRestoreCalleeSavedRegisterGroup(regMaskTP regsMask, int spDelta, int spOffset) { + assert(spDelta == 0); const int slotSize = genGetSlotSizeForRegsInMask(regsMask); ArrayStack regStack(compiler->getAllocator(CMK_Codegen)); @@ -640,15 +574,6 @@ void CodeGen::genRestoreCalleeSavedRegisterGroup(regMaskTP regsMask, int spDelta int stackDelta = 0; for (int i = 0; i < regStack.Height(); ++i) { - bool lastRestoreInTheGroup = (i == regStack.Height() - 1); - bool updateStackDelta = lastRestoreInTheGroup && (spDelta != 0); - if (updateStackDelta) - { - // Update stack delta only if it is the last restore (the first save). - assert(stackDelta == 0); - stackDelta = spDelta; - } - RegPair regPair = regStack.Top(i); if (regPair.reg2 != REG_NA) { @@ -670,10 +595,9 @@ void CodeGen::genRestoreCalleeSavedRegisterGroup(regMaskTP regsMask, int spDelta // in the function or funclet epilog. This exactly reverses the actions of genSaveCalleeSavedRegistersHelp(). // // Arguments: -// regsToRestoreMask - The mask of callee-saved registers to restore. If empty, this function does nothing. -// lowestCalleeSavedOffset - The offset from SP that is the beginning of the callee-saved register area. -// spDelta - If non-zero, the amount to add to SP after the register restores (must be positive or -// zero). +// regsToRestoreMask - The mask of callee-saved registers to restore. If empty, this function does nothing. +// lowestCalleeSavedOffset - The offset from SP that is the beginning of the callee-saved register area. +// spDelta - Always zero for LoongArch64 now. // // Here's an example restore sequence: // ld.d s8,sp,#xxx @@ -694,23 +618,15 @@ void CodeGen::genRestoreCalleeSavedRegisterGroup(regMaskTP regsMask, int spDelta void CodeGen::genRestoreCalleeSavedRegistersHelp(regMaskTP regsToRestoreMask, int lowestCalleeSavedOffset, int spDelta) { - assert(spDelta >= 0); - unsigned regsToRestoreCount = genCountBits(regsToRestoreMask); - if (regsToRestoreCount == 0) + assert(spDelta == 0); + if (regsToRestoreMask == 0) { - if (spDelta != 0) - { - // Currently this is the case for varargs only - // whose size is MAX_REG_ARG * REGSIZE_BYTES = 64 bytes. - genStackPointerAdjustment(spDelta, REG_R21, nullptr, /* reportUnwindData */ true); - } return; } - assert((spDelta % 16) == 0); - - // We also can restore FP and RA, even though they are not in RBM_CALLEE_SAVED. - assert(regsToRestoreCount <= genCountBits(RBM_CALLEE_SAVED | RBM_FP | RBM_RA)); + unsigned regsToRestoreCount = genCountBits(regsToRestoreMask); + // The FP and RA are not in RBM_CALLEE_SAVED. + assert(regsToRestoreCount <= genCountBits(RBM_CALLEE_SAVED)); // Point past the end, to start. We predecrement to find the offset to load from. static_assert_no_msg(REGSIZE_BYTES == FPSAVE_REGSIZE_BYTES); @@ -725,15 +641,13 @@ void CodeGen::genRestoreCalleeSavedRegistersHelp(regMaskTP regsToRestoreMask, in if (maskRestoreRegsInt != RBM_NONE) { - int spIntDelta = (maskRestoreRegsFloat != RBM_NONE) ? 0 : spDelta; // should we delay the SP adjustment? - genRestoreCalleeSavedRegisterGroup(maskRestoreRegsInt, spIntDelta, spOffset); + genRestoreCalleeSavedRegisterGroup(maskRestoreRegsInt, 0, spOffset); spOffset -= genCountBits(maskRestoreRegsInt) * REGSIZE_BYTES; } if (maskRestoreRegsFloat != RBM_NONE) { - // If there is any spDelta, it must be used here. - genRestoreCalleeSavedRegisterGroup(maskRestoreRegsFloat, spDelta, spOffset); + genRestoreCalleeSavedRegisterGroup(maskRestoreRegsFloat, 0, spOffset); // No need to update spOffset since it's not used after this. } } @@ -755,7 +669,7 @@ void CodeGen::genRestoreCalleeSavedRegistersHelp(regMaskTP regsToRestoreMask, in * filter: a0 = non-zero if the handler should handle the exception, zero otherwise (see GT_RETFILT) * finally/fault: none * - * The LOONGARCH64 funclet prolog is the following (Note: #framesz is total funclet frame size, + * The LoongArch64 funclet prolog is the following (Note: #framesz is total funclet frame size, * including everything; #outsz is outgoing argument space. #framesz must be a multiple of 16): * * Frame type liking: @@ -771,19 +685,17 @@ void CodeGen::genRestoreCalleeSavedRegistersHelp(regMaskTP regsToRestoreMask, in * |-----------------------| * | incoming arguments | * +=======================+ <---- Caller's SP - * | OSR padding | // If required - * |-----------------------| - * | Varargs regs space | // Only for varargs main functions; 64 bytes + * | Varargs regs space | // Only for varargs main functions; not used for LA64. * |-----------------------| * | MonitorAcquired | // 8 bytes; for synchronized methods * |-----------------------| * | PSP slot | // 8 bytes (omitted in NativeAOT ABI) * |-----------------------| - * ~ alignment padding ~ // To make the whole frame 16 byte aligned + * |Callee saved registers | // multiple of 8 bytes, not including FP/RA * |-----------------------| * | Saved FP, RA | // 16 bytes * |-----------------------| - * |Callee saved registers | // multiple of 8 bytes, not includting FP/RA + * ~ alignment padding ~ // To make the whole frame 16 byte aligned * |-----------------------| * | Outgoing arg space | // multiple of 8 bytes; if required (i.e., #outsz != 0) * |-----------------------| <---- Ambient SP @@ -793,38 +705,22 @@ void CodeGen::genRestoreCalleeSavedRegistersHelp(regMaskTP regsToRestoreMask, in * V * * - * Both #1 and #2 only change SP once. That means that there will be a maximum of one alignment slot needed. For the general case, #3, - * it is possible that we will need to add alignment to both changes to SP, leading to 16 bytes of alignment. Remember that the stack - * pointer needs to be 16 byte aligned at all times. The size of the PSP slot plus callee-saved registers space is a maximum of 232 bytes: - * - * FP,RA registers - * 9 int callee-saved register s0-s8 - * 8 float callee-saved registers f24-f31 - * 8 saved integer argument registers a0-a7, if varargs function support. - * 1 PSP slot - * == 20 slots * 8 bytes = 160 bytes. - * * The outgoing argument size, however, can be very large, if we call a function that takes a large number of * arguments (note that we currently use the same outgoing argument space size in the funclet as for the main * function, even if the funclet doesn't have any calls, or has a much smaller, or larger, maximum number of - * outgoing arguments for any call). In that case, we need to 16-byte align the initial change to SP, before - * saving off the callee-saved registers and establishing the PSPsym, so we can use the limited immediate offset - * encodings we have available, before doing another 16-byte aligned SP adjustment to create the outgoing argument - * space. Both changes to SP might need to add alignment padding. - * - * In addition to the above "standard" frames, we also need to support a frame where the saved FP/RA are at the - * highest addresses. This is to match the frame layout (specifically, callee-saved registers including FP/RA - * and the PSPSym) that is used in the main function when a GS cookie is required due to the use of localloc. - * (Note that localloc cannot be used in a funclet.) In these variants, not only has the position of FP/RA - * changed, but where the alignment padding is placed has also changed. - * + * outgoing arguments for any call). * - * Note that in all cases, the PSPSym is in exactly the same position with respect to Caller-SP, and that location is the same relative to Caller-SP - * as in the main function. + * Note that in all cases, the PSPSym is in exactly the same position with respect to Caller-SP, + * and that location is the same relative to Caller-SP as in the main function where higher than + * the callee-saved registers. + * That is to say, the PSPSym's relative offset to Caller-SP is not depended on the callee-saved registers. + * TODO-LoongArch64: the funclet's callee-saved registers should not shared with main function. * * Funclets do not have varargs arguments. However, because the PSPSym must exist at the same offset from Caller-SP as in the main function, we * must add buffer space for the saved varargs/argument registers here, if the main function did the same. * + * Note that localloc cannot be used in a funclet. + * * ; After this header, fill the PSP slot, for use by the VM (it gets reported with the GC info), or by code generation of nested filters. * ; This is not part of the "OS prolog"; it has no associated unwind data, and is not reversed in the funclet epilog. * @@ -880,7 +776,9 @@ void CodeGen::genFuncletProlog(BasicBlock* block) { #ifdef DEBUG if (verbose) + { printf("*************** In genFuncletProlog()\n"); + } #endif assert(block != NULL); @@ -910,42 +808,39 @@ void CodeGen::genFuncletProlog(BasicBlock* block) maskArgRegsLiveIn = RBM_A0; } - regMaskTP maskSaveRegs = genFuncletInfo.fiSaveRegs & RBM_CALLEE_SAVED; - int regsSavedSize = (compiler->compCalleeRegsPushed - 2) << 3; + regMaskTP maskSaveRegs = genFuncletInfo.fiSaveRegs & RBM_CALLEE_SAVED; + int FP_offset = genFuncletInfo.fiSP_to_CalleeSaved_delta; - int SP_to_CalleeSaved_delta = genFuncletInfo.fiSP_to_CalleeSaved_delta; - if ((SP_to_CalleeSaved_delta + regsSavedSize + genFuncletInfo.fiCalleeSavedPadding) <= 2040) + if ((FP_offset + (genCountBits(maskSaveRegs) << 3)) <= (2040 - 16)) // no FP/RA. { - SP_to_CalleeSaved_delta += genFuncletInfo.fiCalleeSavedPadding; - genStackPointerAdjustment(frameSize, REG_R21, nullptr, /* reportUnwindData */ true); - genSaveCalleeSavedRegistersHelp(maskSaveRegs, SP_to_CalleeSaved_delta, 0); - SP_to_CalleeSaved_delta += regsSavedSize; + GetEmitter()->emitIns_R_R_I(INS_st_d, EA_PTRSIZE, REG_FP, REG_SPBASE, FP_offset); + compiler->unwindSaveReg(REG_FP, FP_offset); - GetEmitter()->emitIns_R_R_I(INS_st_d, EA_PTRSIZE, REG_RA, REG_SPBASE, SP_to_CalleeSaved_delta); - compiler->unwindSaveReg(REG_RA, SP_to_CalleeSaved_delta); + GetEmitter()->emitIns_R_R_I(INS_st_d, EA_PTRSIZE, REG_RA, REG_SPBASE, FP_offset + 8); + compiler->unwindSaveReg(REG_RA, FP_offset + 8); - GetEmitter()->emitIns_R_R_I(INS_st_d, EA_PTRSIZE, REG_FP, REG_SPBASE, SP_to_CalleeSaved_delta + 8); - compiler->unwindSaveReg(REG_FP, SP_to_CalleeSaved_delta + 8); + genSaveCalleeSavedRegistersHelp(maskSaveRegs, FP_offset + 16, 0); } else { assert(frameSize < -2040); - int SP_delta = frameSize + SP_to_CalleeSaved_delta; - genStackPointerAdjustment(SP_delta, REG_R21, nullptr, /* reportUnwindData */ true); + genStackPointerAdjustment(frameSize + (FP_offset & -16), REG_R21, nullptr, true); - genSaveCalleeSavedRegistersHelp(maskSaveRegs, genFuncletInfo.fiCalleeSavedPadding, 0); - regsSavedSize += genFuncletInfo.fiCalleeSavedPadding; + frameSize = -(FP_offset & -16); + FP_offset &= 0xf; - GetEmitter()->emitIns_R_R_I(INS_st_d, EA_PTRSIZE, REG_RA, REG_SPBASE, regsSavedSize); - compiler->unwindSaveReg(REG_RA, regsSavedSize); + GetEmitter()->emitIns_R_R_I(INS_st_d, EA_PTRSIZE, REG_FP, REG_SPBASE, FP_offset); + compiler->unwindSaveReg(REG_FP, FP_offset); - GetEmitter()->emitIns_R_R_I(INS_st_d, EA_PTRSIZE, REG_FP, REG_SPBASE, regsSavedSize + 8); - compiler->unwindSaveReg(REG_FP, regsSavedSize + 8); + GetEmitter()->emitIns_R_R_I(INS_st_d, EA_PTRSIZE, REG_RA, REG_SPBASE, FP_offset + 8); + compiler->unwindSaveReg(REG_RA, FP_offset + 8); - genStackPointerAdjustment(-SP_to_CalleeSaved_delta, REG_R21, nullptr, /* reportUnwindData */ true); + genSaveCalleeSavedRegistersHelp(maskSaveRegs, FP_offset + 16, 0); + + genStackPointerAdjustment(frameSize, REG_R21, nullptr, true); } // This is the end of the OS-reported prolog for purposes of unwinding @@ -1012,41 +907,28 @@ void CodeGen::genFuncletEpilog() int frameSize = genFuncletInfo.fiSpDelta; assert(frameSize < 0); - regMaskTP regsToRestoreMask = genFuncletInfo.fiSaveRegs & RBM_CALLEE_SAVED; - int regsRestoreSize = (compiler->compCalleeRegsPushed - 2) << 3; + regMaskTP maskSaveRegs = genFuncletInfo.fiSaveRegs & RBM_CALLEE_SAVED; + int FP_offset = genFuncletInfo.fiSP_to_CalleeSaved_delta; - int SP_to_CalleeSaved_delta = genFuncletInfo.fiSP_to_CalleeSaved_delta; - if ((SP_to_CalleeSaved_delta + regsRestoreSize + genFuncletInfo.fiCalleeSavedPadding) <= 2040) + if ((FP_offset + (genCountBits(maskSaveRegs) << 3)) > (2040 - 16)) // no FP/RA. { - SP_to_CalleeSaved_delta += genFuncletInfo.fiCalleeSavedPadding; - genRestoreCalleeSavedRegistersHelp(regsToRestoreMask, SP_to_CalleeSaved_delta, 0); - SP_to_CalleeSaved_delta += regsRestoreSize; - - GetEmitter()->emitIns_R_R_I(INS_ld_d, EA_PTRSIZE, REG_RA, REG_SPBASE, SP_to_CalleeSaved_delta); - compiler->unwindSaveReg(REG_RA, SP_to_CalleeSaved_delta); + assert(frameSize < -2040); - GetEmitter()->emitIns_R_R_I(INS_ld_d, EA_PTRSIZE, REG_FP, REG_SPBASE, SP_to_CalleeSaved_delta + 8); - compiler->unwindSaveReg(REG_FP, SP_to_CalleeSaved_delta + 8); + genStackPointerAdjustment(FP_offset & -16, REG_R21, nullptr, /* reportUnwindData */ true); - genStackPointerAdjustment(-frameSize, REG_R21, nullptr, /* reportUnwindData */ true); + frameSize += FP_offset & -16; + FP_offset = FP_offset & 0xf; } - else - { - assert(frameSize < -2040); - - genStackPointerAdjustment(SP_to_CalleeSaved_delta, REG_R21, nullptr, /* reportUnwindData */ true); - genRestoreCalleeSavedRegistersHelp(regsToRestoreMask, genFuncletInfo.fiCalleeSavedPadding, 0); - regsRestoreSize += genFuncletInfo.fiCalleeSavedPadding; + genRestoreCalleeSavedRegistersHelp(maskSaveRegs, FP_offset + 16, 0); - GetEmitter()->emitIns_R_R_I(INS_ld_d, EA_PTRSIZE, REG_RA, REG_SPBASE, regsRestoreSize); - compiler->unwindSaveReg(REG_RA, regsRestoreSize); + GetEmitter()->emitIns_R_R_I(INS_ld_d, EA_PTRSIZE, REG_RA, REG_SPBASE, FP_offset + 8); + compiler->unwindSaveReg(REG_RA, FP_offset + 8); - GetEmitter()->emitIns_R_R_I(INS_ld_d, EA_PTRSIZE, REG_FP, REG_SPBASE, regsRestoreSize + 8); - compiler->unwindSaveReg(REG_FP, regsRestoreSize + 8); + GetEmitter()->emitIns_R_R_I(INS_ld_d, EA_PTRSIZE, REG_FP, REG_SPBASE, FP_offset); + compiler->unwindSaveReg(REG_FP, FP_offset); - genStackPointerAdjustment(-frameSize - SP_to_CalleeSaved_delta, REG_R21, nullptr, /* reportUnwindData */ true); - } + genStackPointerAdjustment(-frameSize, REG_R21, nullptr, /* reportUnwindData */ true); GetEmitter()->emitIns_R_R_I(INS_jirl, emitActualTypeSize(TYP_I_IMPL), REG_R0, REG_RA, 0); compiler->unwindReturn(REG_RA); @@ -1072,7 +954,6 @@ void CodeGen::genCaptureFuncletPrologEpilogInfo() } assert(isFramePointerUsed()); - // The frame size and offsets must be finalized assert(compiler->lvaDoneFrameLayout == Compiler::FINAL_FRAME_LAYOUT); @@ -1080,58 +961,40 @@ void CodeGen::genCaptureFuncletPrologEpilogInfo() assert((rsMaskSaveRegs & RBM_RA) != 0); assert((rsMaskSaveRegs & RBM_FP) != 0); - unsigned PSPSize = (compiler->lvaPSPSym != BAD_VAR_NUM) ? 8 : 0; - // Because a method and funclets must have the same caller-relative PSPSym offset, // if there is a PSPSym, we have to pad the funclet frame size for OSR. // - unsigned osrPad = 0; - if (compiler->opts.IsOSR() && (PSPSize > 0)) + int osrPad = 0; + if (compiler->opts.IsOSR()) { - osrPad = compiler->info.compPatchpointInfo->TotalFrameSize(); + osrPad -= compiler->info.compPatchpointInfo->TotalFrameSize(); // OSR pad must be already aligned to stack size. assert((osrPad % STACK_ALIGN) == 0); } - genFuncletInfo.fiCalleeSavedPadding = 0; - genFuncletInfo.fiFunction_CallerSP_to_FP_delta = genCallerSPtoFPdelta() - osrPad; - - unsigned regsSavedSize = genCountBits(rsMaskSaveRegs) << 3; - assert(genCountBits(rsMaskSaveRegs) == compiler->compCalleeRegsPushed); - - unsigned saveRegsPlusPSPSize = regsSavedSize + PSPSize; - - assert(compiler->lvaOutgoingArgSpaceSize % REGSIZE_BYTES == 0); - unsigned outgoingArgSpaceAligned = roundUp(compiler->lvaOutgoingArgSpaceSize, STACK_ALIGN); + /* Now save it for future use */ + genFuncletInfo.fiFunction_CallerSP_to_FP_delta = genCallerSPtoFPdelta() + osrPad; - unsigned funcletFrameSize = osrPad + saveRegsPlusPSPSize + compiler->lvaOutgoingArgSpaceSize; - unsigned funcletFrameSizeAligned = roundUp(funcletFrameSize, STACK_ALIGN); + int funcletFrameSize = compiler->lvaOutgoingArgSpaceSize; - int SP_to_CalleeSaved_delta = compiler->lvaOutgoingArgSpaceSize; - if ((SP_to_CalleeSaved_delta + regsSavedSize) >= 2040) - { - int offset = funcletFrameSizeAligned - SP_to_CalleeSaved_delta; - SP_to_CalleeSaved_delta = AlignUp((UINT)offset, STACK_ALIGN); + genFuncletInfo.fiSP_to_CalleeSaved_delta = funcletFrameSize; - genFuncletInfo.fiCalleeSavedPadding = SP_to_CalleeSaved_delta - offset; - } + funcletFrameSize += genCountBits(rsMaskSaveRegs) * REGSIZE_BYTES; - if (compiler->lvaMonAcquired != BAD_VAR_NUM && !compiler->opts.IsOSR()) + int delta_PSP = -TARGET_POINTER_SIZE; + if ((compiler->lvaMonAcquired != BAD_VAR_NUM) && !compiler->opts.IsOSR()) { - // We furthermore allocate the "monitor acquired" bool between PSP and - // the saved registers because this is part of the EnC header. - // Note that OSR methods reuse the monitor bool created by tier 0. - osrPad += compiler->lvaLclSize(compiler->lvaMonAcquired); + delta_PSP -= TARGET_POINTER_SIZE; } - /* Now save it for future use */ - genFuncletInfo.fiSpDelta = -(int)funcletFrameSizeAligned; - genFuncletInfo.fiSaveRegs = rsMaskSaveRegs; - genFuncletInfo.fiSP_to_CalleeSaved_delta = SP_to_CalleeSaved_delta; + funcletFrameSize = funcletFrameSize - delta_PSP - osrPad; + funcletFrameSize = roundUp((unsigned)funcletFrameSize, STACK_ALIGN); - genFuncletInfo.fiSP_to_PSP_slot_delta = funcletFrameSizeAligned - osrPad - 8; - genFuncletInfo.fiCallerSP_to_PSP_slot_delta = -(int)osrPad - 8; + genFuncletInfo.fiSpDelta = -funcletFrameSize; + genFuncletInfo.fiSaveRegs = rsMaskSaveRegs; + genFuncletInfo.fiSP_to_PSP_slot_delta = funcletFrameSize + delta_PSP + osrPad; + genFuncletInfo.fiCallerSP_to_PSP_slot_delta = osrPad + delta_PSP; #ifdef DEBUG if (verbose) @@ -4278,9 +4141,17 @@ void CodeGen::genCodeForJumpCompare(GenTreeOpCC* tree) int CodeGenInterface::genSPtoFPdelta() const { assert(isFramePointerUsed()); - assert(compiler->compCalleeRegsPushed >= 2); + assert(compiler->compCalleeRegsPushed >= 2); // always FP/RA. - int delta = compiler->lvaOutgoingArgSpaceSize + (compiler->compCalleeRegsPushed << 3) - 8; + int delta = compiler->compLclFrameSize; + if (compiler->lvaPSPSym != BAD_VAR_NUM) + { + delta -= TARGET_POINTER_SIZE; + } + if ((compiler->lvaMonAcquired != BAD_VAR_NUM) && !compiler->opts.IsOSR()) + { + delta -= TARGET_POINTER_SIZE; + } assert(delta >= 0); return delta; @@ -7660,8 +7531,8 @@ void CodeGen::instGen_MemoryBarrier(BarrierKind barrierKind) * ... * st.d s8,sp,off2+8*8 * - * st.d ra,sp,off3 - * st.d fp,sp,off3+8 + * st.d ra,sp,off3+8 + * st.d fp,sp,off3 * * Notes: * 1. FP is always saved, and the first store is FP, RA. @@ -7669,37 +7540,41 @@ void CodeGen::instGen_MemoryBarrier(BarrierKind barrierKind) * 3. For frames with varargs, not implemented completely and not tested ! * 4. We allocate the frame here; no further changes to SP are allowed (except in the body, for localloc). * - * For functions with GS and localloc, we change the frame so the frame pointer and RA are saved at the top - * of the frame, just under the varargs registers (if any). Note that the funclet frames must follow the same - * rule, and both main frame and funclet frames (if any) must put PSPSym in the same offset from Caller-SP. + * For functions with GS and localloc, we had saved the frame pointer and RA at the top + * of the frame. Note that the funclet frames must follow the same rule, + * and both main frame and funclet frames (if any) must put PSPSym in the same offset from Caller-SP. * Since this frame type is relatively rare, we force using it via stress modes, for additional coverage. * * The frames look like the following (simplified to only include components that matter for establishing the * frames). See also Compiler::lvaAssignFrameOffsets(). * - * * The LoongArch64's frame layout is liking: * + * If we need to generate a GS cookie, we need to make sure the saved frame pointer and return address + * (FP and RA) are protected from buffer overrun by the GS cookie. + * So we always save the FP/RA along with the rest of the callee-saved registers above. + * * | | * |-----------------------| * | incoming arguments | * +=======================+ <---- Caller's SP - * | Arguments Or | // if needed. * | Varargs regs space | // Only for varargs functions; (varargs not implemented for LoongArch64) * |-----------------------| * | MonitorAcquired | // 8 bytes; for synchronized methods * |-----------------------| - * | PSP slot | // 8 bytes (omitted in NativeAOT ABI) + * | PSPSym | // 8 bytes, Only for frames with EH, (omitted in NativeAOT ABI) * |-----------------------| - * | locals, temps, etc. | + * |Callee saved registers | // not including FP/RA; multiple of 8 bytes * |-----------------------| - * | possible GS cookie | + * | Saved RA | // 8 bytes * |-----------------------| * | Saved FP | // 8 bytes * |-----------------------| - * | Saved RA | // 8 bytes + * | possible GS cookie | * |-----------------------| - * |Callee saved registers | // not including FP/RA; multiple of 8 bytes + * | locals, temps, etc. | + * |-----------------------| + * | possible GS cookie | * |-----------------------| * | Outgoing arg space | // multiple of 8 bytes; if required (i.e., #outsz != 0) * |-----------------------| <---- Ambient SP @@ -7748,6 +7623,9 @@ void CodeGen::genPushCalleeSavedRegisters(regNumber initReg, bool* pInitRegZeroe regSet.rsMaskCalleeSaved = rsPushRegs | RBM_FPBASE | RBM_RA; #ifdef DEBUG + JITDUMP("Frame info. #outsz=%d; #framesz=%d; LclFrameSize=%d;\n", unsigned(compiler->lvaOutgoingArgSpaceSize), + genTotalFrameSize(), compiler->compLclFrameSize); + if (compiler->compCalleeRegsPushed != genCountBits(regSet.rsMaskCalleeSaved)) { printf("Error: unexpected number of callee-saved registers to push. Expected: %d. Got: %d ", @@ -7770,84 +7648,52 @@ void CodeGen::genPushCalleeSavedRegisters(regNumber initReg, bool* pInitRegZeroe } #endif // DEBUG - // The frameType number is arbitrary, is defined below, and corresponds to one of the frame styles we - // generate based on various sizes. - int frameType = 0; - - // The amount to add from SP before starting to store the callee-saved registers. - int calleeSaveSPDelta = 0; - - // If we need to generate a GS cookie, we need to make sure the saved frame pointer and return address - // (FP and RA) are protected from buffer overrun by the GS cookie. If FP/RA are at the lowest addresses, - // then they are safe, since they are lower than any unsafe buffers. And the GS cookie we add will - // protect our caller's frame. If we have a localloc, however, that is dynamically placed lower than our - // saved FP/RA. In that case, we save FP/RA along with the rest of the callee-saved registers, above - // the GS cookie. - // - // After the frame is allocated, the frame pointer is established, pointing at the saved frame pointer to - // create a frame pointer chain. - // + int totalFrameSize = genTotalFrameSize(); + int leftFrameSize = 0; + int localFrameSize = compiler->compLclFrameSize; + if (compiler->lvaPSPSym != BAD_VAR_NUM) + { + localFrameSize -= TARGET_POINTER_SIZE; + } + if ((compiler->lvaMonAcquired != BAD_VAR_NUM) && !compiler->opts.IsOSR()) + { + localFrameSize -= TARGET_POINTER_SIZE; + } - // This will be the starting place for saving the callee-saved registers, in increasing order. - int offset = compiler->lvaOutgoingArgSpaceSize; +#ifdef DEBUG + if (compiler->opts.disAsm) + { + printf("Frame info. #outsz=%d; #framesz=%d; lcl=%d\n", unsigned(compiler->lvaOutgoingArgSpaceSize), + genTotalFrameSize(), localFrameSize); + } +#endif - int totalFrameSize = genTotalFrameSize(); - // The (totalFrameSize <= 2040) condition ensures the offsets of st.d/ld.d. + int FP_offset = localFrameSize; if (totalFrameSize <= 2040) { GetEmitter()->emitIns_R_R_I(INS_addi_d, EA_PTRSIZE, REG_SPBASE, REG_SPBASE, -totalFrameSize); compiler->unwindAllocStack(totalFrameSize); - - // Case #1. - // - // Generate: - // addi.d sp, sp, -framesz - // st.d callee_saved_registers ### not including the fp and ra. - // st.d ra,sp,outsz - // st.d fp,sp,outsz+8 - // - // After saving callee-saved registers, ra and fp, we establish the frame pointer with: - // addi.d fp, sp, (the offset of saving fp) - // We do this *after* saving callee-saved registers, so the prolog/epilog unwind codes mostly match. - - JITDUMP("Frame type 1. #outsz=%d; #framesz=%d; LclFrameSize=%d\n", unsigned(compiler->lvaOutgoingArgSpaceSize), - totalFrameSize, compiler->compLclFrameSize); - - frameType = 1; } else { - JITDUMP("Frame type 2. #outsz=%d; #framesz=%d; LclFrameSize=%d\n", unsigned(compiler->lvaOutgoingArgSpaceSize), - totalFrameSize, compiler->compLclFrameSize); - - frameType = 2; - - if ((offset + (compiler->compCalleeRegsPushed << 3)) >= 2040) - { - offset = totalFrameSize - compiler->lvaOutgoingArgSpaceSize; - calleeSaveSPDelta = AlignUp((UINT)offset, STACK_ALIGN); - offset = calleeSaveSPDelta - offset; - - genStackPointerAdjustment(-calleeSaveSPDelta, initReg, pInitRegZeroed, /* reportUnwindData */ true); - } - else + if ((localFrameSize + (compiler->compCalleeRegsPushed << 3)) > 2040) { - genStackPointerAdjustment(-totalFrameSize, initReg, pInitRegZeroed, /* reportUnwindData */ true); + leftFrameSize = localFrameSize & -16; + totalFrameSize = totalFrameSize - (localFrameSize & -16); + FP_offset = localFrameSize & 0xf; } + genStackPointerAdjustment(-totalFrameSize, initReg, pInitRegZeroed, /* reportUnwindData */ true); } + GetEmitter()->emitIns_R_R_I(INS_st_d, EA_PTRSIZE, REG_FP, REG_SPBASE, FP_offset); + compiler->unwindSaveReg(REG_FP, FP_offset); - JITDUMP(" offset=%d, calleeSaveSPDelta=%d\n", offset, calleeSaveSPDelta); - genSaveCalleeSavedRegistersHelp(rsPushRegs, offset, 0); - offset += (int)(genCountBits(rsPushRegs) << 3); - - GetEmitter()->emitIns_R_R_I(INS_st_d, EA_PTRSIZE, REG_RA, REG_SPBASE, offset); - compiler->unwindSaveReg(REG_RA, offset); + GetEmitter()->emitIns_R_R_I(INS_st_d, EA_PTRSIZE, REG_RA, REG_SPBASE, FP_offset + 8); + compiler->unwindSaveReg(REG_RA, FP_offset + 8); - GetEmitter()->emitIns_R_R_I(INS_st_d, EA_PTRSIZE, REG_FP, REG_SPBASE, offset + 8); - compiler->unwindSaveReg(REG_FP, offset + 8); + genSaveCalleeSavedRegistersHelp(rsPushRegs, FP_offset + 16, 0); - JITDUMP(" offsetSpToSavedFp=%d\n", offset + 8); - genEstablishFramePointer(offset + 8, /* reportUnwindData */ true); + JITDUMP(" offsetSpToSavedFp=%d\n", FP_offset); + genEstablishFramePointer(FP_offset, /* reportUnwindData */ true); // For varargs, home the incoming arg registers last. Note that there is nothing to unwind here, // so we just report "NOP" unwind codes. If there's no more frame setup after this, we don't @@ -7858,19 +7704,9 @@ void CodeGen::genPushCalleeSavedRegisters(regNumber initReg, bool* pInitRegZeroe NYI_LOONGARCH64("genPushCalleeSavedRegisters unsupports compIsVarArgs"); } -#ifdef DEBUG - if (compiler->opts.disAsm) - { - assert(frameType != 0); - printf("DEBUG: LOONGARCH64, frameType:%d\n\n", frameType); - } -#endif - - if (calleeSaveSPDelta != 0) + if (leftFrameSize != 0) { - assert(frameType == 2); - calleeSaveSPDelta = totalFrameSize - calleeSaveSPDelta; - genStackPointerAdjustment(-calleeSaveSPDelta, initReg, pInitRegZeroed, /* reportUnwindData */ true); + genStackPointerAdjustment(-leftFrameSize, initReg, pInitRegZeroed, /* reportUnwindData */ true); } } @@ -7882,85 +7718,78 @@ void CodeGen::genPopCalleeSavedRegisters(bool jmpEpilog) assert(isFramePointerUsed()); - // This will be the starting place for restoring the callee-saved registers, in decreasing order. - int calleeSaveSPOffset = 0; - int remainingSPSize = 0; - int totalFrameSize = genTotalFrameSize(); - if (totalFrameSize <= 2040) + int localFrameSize = compiler->compLclFrameSize; + if (compiler->lvaPSPSym != BAD_VAR_NUM) + { + localFrameSize -= TARGET_POINTER_SIZE; + } + if ((compiler->lvaMonAcquired != BAD_VAR_NUM) && !compiler->opts.IsOSR()) { - JITDUMP("Frame type 1. #outsz=%d; #framesz=%d; localloc? %s\n", unsigned(compiler->lvaOutgoingArgSpaceSize), - totalFrameSize, dspBool(compiler->compLocallocUsed)); + localFrameSize -= TARGET_POINTER_SIZE; + } + + JITDUMP("Frame type. #outsz=%d; #framesz=%d; #calleeSaveRegsPushed:%d; " + "localloc? %s\n", + unsigned(compiler->lvaOutgoingArgSpaceSize), totalFrameSize, compiler->compCalleeRegsPushed, + dspBool(compiler->compLocallocUsed)); + emitter* emit = GetEmitter(); + int FP_offset = localFrameSize; + int remainingSPSize = totalFrameSize; + if (totalFrameSize <= 2040) + { if (compiler->compLocallocUsed) { - int SPtoFPdelta = (compiler->compCalleeRegsPushed << 3) - 8 + compiler->lvaOutgoingArgSpaceSize; - + int SPtoFPdelta = genSPtoFPdelta(); // Restore sp from fp - GetEmitter()->emitIns_R_R_I(INS_addi_d, EA_PTRSIZE, REG_SPBASE, REG_FPBASE, -SPtoFPdelta); + emit->emitIns_R_R_I(INS_addi_d, EA_PTRSIZE, REG_SPBASE, REG_FPBASE, -SPtoFPdelta); compiler->unwindSetFrameReg(REG_FPBASE, SPtoFPdelta); } - calleeSaveSPOffset = compiler->lvaOutgoingArgSpaceSize; - remainingSPSize = totalFrameSize; } else { - JITDUMP("Frame type 2. #outsz=%d; #framesz=%d; #calleeSaveRegsPushed:%d; " - "localloc? %s\n", - unsigned(compiler->lvaOutgoingArgSpaceSize), totalFrameSize, compiler->compCalleeRegsPushed, - dspBool(compiler->compLocallocUsed)); - - if ((compiler->lvaOutgoingArgSpaceSize + (compiler->compCalleeRegsPushed << 3)) > 2047) + if (compiler->compLocallocUsed) { - calleeSaveSPOffset = compiler->lvaOutgoingArgSpaceSize & -16; - if (compiler->compLocallocUsed) + int SPtoFPdelta = genSPtoFPdelta(); + // Restore sp from fp + if (emitter::isValidSimm12(SPtoFPdelta)) { - int SPtoFPdelta = (compiler->compCalleeRegsPushed << 3) - 8; - - // Restore sp from fp - GetEmitter()->emitIns_R_R_I(INS_addi_d, EA_PTRSIZE, REG_SPBASE, REG_FPBASE, -SPtoFPdelta); - compiler->unwindSetFrameReg(REG_FPBASE, SPtoFPdelta); + emit->emitIns_R_R_I(INS_addi_d, EA_PTRSIZE, REG_SPBASE, REG_FPBASE, -SPtoFPdelta); } else { - genStackPointerAdjustment(calleeSaveSPOffset, REG_RA, nullptr, /* reportUnwindData */ true); + emit->emitIns_I_la(EA_PTRSIZE, REG_RA, SPtoFPdelta); + emit->emitIns_R_R_R(INS_sub_d, EA_PTRSIZE, REG_SPBASE, REG_FPBASE, REG_RA); } - remainingSPSize = totalFrameSize - calleeSaveSPOffset; - calleeSaveSPOffset = compiler->lvaOutgoingArgSpaceSize - calleeSaveSPOffset; } - else + if ((localFrameSize + (compiler->compCalleeRegsPushed << 3)) > 2040) { - if (compiler->compLocallocUsed) - { - int SPtoFPdelta = (compiler->compCalleeRegsPushed << 3) - 8 + compiler->lvaOutgoingArgSpaceSize; + remainingSPSize = localFrameSize & -16; + genStackPointerAdjustment(remainingSPSize, REG_RA, nullptr, /* reportUnwindData */ true); - // Restore sp from fp - GetEmitter()->emitIns_R_R_I(INS_addi_d, EA_PTRSIZE, REG_SPBASE, REG_FPBASE, -SPtoFPdelta); - compiler->unwindSetFrameReg(REG_FPBASE, SPtoFPdelta); - } - calleeSaveSPOffset = compiler->lvaOutgoingArgSpaceSize; - remainingSPSize = totalFrameSize; + remainingSPSize = totalFrameSize - remainingSPSize; + FP_offset = localFrameSize & 0xf; } } - JITDUMP(" calleeSaveSPOffset=%d\n", calleeSaveSPOffset); - genRestoreCalleeSavedRegistersHelp(regsToRestoreMask, calleeSaveSPOffset, 0); - calleeSaveSPOffset += (compiler->compCalleeRegsPushed - 2) << 3; + JITDUMP(" calleeSaveSPOffset=%d\n", FP_offset + 16); + genRestoreCalleeSavedRegistersHelp(regsToRestoreMask, FP_offset + 16, 0); - GetEmitter()->emitIns_R_R_I(INS_ld_d, EA_PTRSIZE, REG_RA, REG_SPBASE, calleeSaveSPOffset); - compiler->unwindSaveReg(REG_RA, calleeSaveSPOffset); + emit->emitIns_R_R_I(INS_ld_d, EA_PTRSIZE, REG_RA, REG_SPBASE, FP_offset + 8); + compiler->unwindSaveReg(REG_RA, FP_offset + 8); - GetEmitter()->emitIns_R_R_I(INS_ld_d, EA_PTRSIZE, REG_FP, REG_SPBASE, calleeSaveSPOffset + 8); - compiler->unwindSaveReg(REG_FP, calleeSaveSPOffset + 8); + emit->emitIns_R_R_I(INS_ld_d, EA_PTRSIZE, REG_FP, REG_SPBASE, FP_offset); + compiler->unwindSaveReg(REG_FP, FP_offset); if (emitter::isValidUimm11(remainingSPSize)) { - GetEmitter()->emitIns_R_R_I(INS_addi_d, EA_PTRSIZE, REG_SPBASE, REG_SPBASE, remainingSPSize); + emit->emitIns_R_R_I(INS_addi_d, EA_PTRSIZE, REG_SPBASE, REG_SPBASE, remainingSPSize); } else { - GetEmitter()->emitIns_I_la(EA_PTRSIZE, REG_R21, remainingSPSize); - GetEmitter()->emitIns_R_R_R(INS_add_d, EA_PTRSIZE, REG_SPBASE, REG_SPBASE, REG_R21); + emit->emitIns_I_la(EA_PTRSIZE, REG_R21, remainingSPSize); + emit->emitIns_R_R_R(INS_add_d, EA_PTRSIZE, REG_SPBASE, REG_SPBASE, REG_R21); } compiler->unwindAllocStack(remainingSPSize); @@ -7972,12 +7801,12 @@ void CodeGen::genPopCalleeSavedRegisters(bool jmpEpilog) if (emitter::isValidUimm11(tier0FrameSize)) { - GetEmitter()->emitIns_R_R_I(INS_addi_d, EA_PTRSIZE, REG_SPBASE, REG_SPBASE, tier0FrameSize); + emit->emitIns_R_R_I(INS_addi_d, EA_PTRSIZE, REG_SPBASE, REG_SPBASE, tier0FrameSize); } else { - GetEmitter()->emitIns_I_la(EA_PTRSIZE, REG_R21, tier0FrameSize); - GetEmitter()->emitIns_R_R_R(INS_add_d, EA_PTRSIZE, REG_SPBASE, REG_SPBASE, REG_R21); + emit->emitIns_I_la(EA_PTRSIZE, REG_R21, tier0FrameSize); + emit->emitIns_R_R_R(INS_add_d, EA_PTRSIZE, REG_SPBASE, REG_SPBASE, REG_R21); } compiler->unwindAllocStack(tier0FrameSize); } diff --git a/src/coreclr/jit/codegenriscv64.cpp b/src/coreclr/jit/codegenriscv64.cpp index 546ba7b3180899..b7c119be94987c 100644 --- a/src/coreclr/jit/codegenriscv64.cpp +++ b/src/coreclr/jit/codegenriscv64.cpp @@ -770,8 +770,8 @@ void CodeGen::genRestoreCalleeSavedRegistersHelp(regMaskTP regsToRestoreMask, in * addi sp, sp, -#framesz ; establish the frame * sd s1, #outsz(sp) ; save callee-saved registers, as necessary * sd s2, #(outsz+8)(sp) - * sd ra, #(outsz+?)(sp) ; save RA (8 bytes) - * sd fp, #(outsz+?+8)(sp) ; save FP (8 bytes) + * sd ra, #(outsz+?+8)(sp) ; save RA (8 bytes) + * sd fp, #(outsz+?)(sp) ; save FP (8 bytes) * * The funclet frame layout: * @@ -779,8 +779,7 @@ void CodeGen::genRestoreCalleeSavedRegistersHelp(regMaskTP regsToRestoreMask, in * |-----------------------| * | incoming arguments | * +=======================+ <---- Caller's SP - * | Arguments Or | // if needed - * | Varargs regs space | // Only for varargs functions; NYI on RV64 + * | Varargs regs space | // Only for varargs main functions; not used for RV64. * |-----------------------| * | MonitorAcquired | // 8 bytes; for synchronized methods * |-----------------------| @@ -788,11 +787,9 @@ void CodeGen::genRestoreCalleeSavedRegistersHelp(regMaskTP regsToRestoreMask, in * |-----------------------| * ~ alignment padding ~ // To make the whole frame 16 byte aligned * |-----------------------| - * | Saved FP | // 8 bytes + * |Callee saved registers | // multiple of 8 bytes, not including FP/RA * |-----------------------| - * | Saved RA | // 8 bytes - * |-----------------------| - * |Callee saved registers | // multiple of 8 bytes, not includting RA/FP + * | Saved FP, RA | // 16 bytes * |-----------------------| * | Outgoing arg space | // multiple of 8 bytes; if required (i.e., #outsz != 0) * |-----------------------| <---- Ambient SP @@ -801,31 +798,27 @@ void CodeGen::genRestoreCalleeSavedRegistersHelp(regMaskTP regsToRestoreMask, in * | | downward | * V * - * Note, that SP only change once. That means, there will be a maximum of one alignment slot needed. - * Also remember, the stack oiubter needs to be 16 byte aligned at all times. - * The size of the PSP slot plus callee-saved registers space is a maximum of 280 bytes: - * - * RA,FP registers - * 11 int callee-saved register s1-s11 - * 12 float callee-saved registers f8-f9, f18-f27 - * 8 saved integer argument registers a0-a7, if varargs function support. - * 1 PSP slot - * 1 alignment slot or monitor acquired slot - * == 35 slots * 8 bytes = 280 bytes. * * The outgoing argument size, however, can be very large, if we call a function that takes a large number of * arguments (note that we currently use the same outgoing argument space size in the funclet as for the main * function, even if the funclet doesn't have any calls, or has a much smaller, or larger, maximum number of - * outgoing arguments for any call). In that case, we need to 16-byte align the initial change to SP, before - * saving off the callee-saved registers and establishing the PSPsym, so we can use the limited immediate offset - * encodings we have available, before doing another 16-byte aligned SP adjustment to create the outgoing argument - * space. Both changes to SP might need to add alignment padding. + * outgoing arguments for any call). + * + * Note that in all cases, the PSPSym is in exactly the same position with respect to Caller-SP, + * and that location is the same relative to Caller-SP as in the main function where higher than + * the callee-saved registers. + * That is to say, the PSPSym's relative offset to Caller-SP is not depended on the callee-saved registers. + * + * Funclets do not have varargs arguments. However, because the PSPSym must exist at the same offset from Caller-SP as in the main function, we + * must add buffer space for the saved varargs/argument registers here, if the main function did the same. + * + * Note that localloc cannot be used in a funclet. * * An example epilog sequence: * addi sp, sp, #outsz ; if any outgoing argument space * ld s1, #(xxx-8)(sp) ; restore callee-saved registers * ld s2, #xxx(sp) - * ld ra, #(xxx+?-8)(sp) ; restore RA + * ld ra, #(xxx+?+8)(sp) ; restore RA * ld fp, #(xxx+?)(sp) ; restore FP * addi sp, sp, #framesz * jarl zero, ra @@ -840,8 +833,8 @@ void CodeGen::genFuncletProlog(BasicBlock* block) printf("*************** In genFuncletProlog()\n"); } #endif + // TODO-RISCV64: Implement varargs (NYI_RISCV64) - // TODO-RISCV64-CQ: We can use C extension for optimization assert(block != NULL); assert(block->HasFlag(BBF_FUNCLET_BEG)); @@ -852,9 +845,8 @@ void CodeGen::genFuncletProlog(BasicBlock* block) compiler->unwindBegProlog(); - const bool isFilter = (block->bbCatchTyp == BBCT_FILTER); - const int frameSize = genFuncletInfo.fiSpDelta; - + bool isFilter = (block->bbCatchTyp == BBCT_FILTER); + int frameSize = genFuncletInfo.fiSpDelta; assert(frameSize < 0); regMaskTP maskArgRegsLiveIn; @@ -871,53 +863,39 @@ void CodeGen::genFuncletProlog(BasicBlock* block) maskArgRegsLiveIn = RBM_A0; } - regMaskTP maskSaveRegs = genFuncletInfo.fiSaveRegs & RBM_CALLEE_SAVED; - int regsSavedSize = (compiler->compCalleeRegsPushed - 2) << 3; - - int calleeSavedDelta = genFuncletInfo.fiSP_to_CalleeSaved_delta; - - emitter* emit = GetEmitter(); + regMaskTP maskSaveRegs = genFuncletInfo.fiSaveRegs & RBM_CALLEE_SAVED; + int FP_offset = genFuncletInfo.fiSP_to_CalleeSaved_delta; - if (calleeSavedDelta + regsSavedSize + genFuncletInfo.fiCalleeSavedPadding <= 2040) + if ((FP_offset + (genCountBits(maskSaveRegs) << 3)) <= (2040 - 16)) // no FP/RA. { - calleeSavedDelta += genFuncletInfo.fiCalleeSavedPadding; - - // addi sp, sp, #frameSize genStackPointerAdjustment(frameSize, REG_SCRATCH, nullptr, /* reportUnwindData */ true); - genSaveCalleeSavedRegistersHelp(maskSaveRegs, calleeSavedDelta, 0); - calleeSavedDelta += regsSavedSize; + GetEmitter()->emitIns_R_R_I(INS_sd, EA_PTRSIZE, REG_FP, REG_SPBASE, FP_offset); + compiler->unwindSaveReg(REG_FP, FP_offset); - // sd ra, #calleeSavedDelta(sp) - emit->emitIns_R_R_I(INS_sd, EA_PTRSIZE, REG_RA, REG_SPBASE, calleeSavedDelta); - compiler->unwindSaveReg(REG_RA, calleeSavedDelta); + GetEmitter()->emitIns_R_R_I(INS_sd, EA_PTRSIZE, REG_RA, REG_SPBASE, FP_offset + 8); + compiler->unwindSaveReg(REG_RA, FP_offset + 8); - // sd fp, #(calleeSavedDelta+8)(sp) - emit->emitIns_R_R_I(INS_sd, EA_PTRSIZE, REG_FP, REG_SPBASE, calleeSavedDelta + 8); - compiler->unwindSaveReg(REG_FP, calleeSavedDelta + 8); + genSaveCalleeSavedRegistersHelp(maskSaveRegs, FP_offset + 16, 0); } else { assert(frameSize < -2040); - int spDelta = frameSize + calleeSavedDelta; + genStackPointerAdjustment(frameSize + (FP_offset & -16), REG_SCRATCH, nullptr, true); - // addi sp, sp, #spDelta - genStackPointerAdjustment(spDelta, REG_SCRATCH, nullptr, /* reportUnwindData */ true); + frameSize = -(FP_offset & -16); + FP_offset &= 0xf; - genSaveCalleeSavedRegistersHelp(maskSaveRegs, genFuncletInfo.fiCalleeSavedPadding, 0); - regsSavedSize += genFuncletInfo.fiCalleeSavedPadding; + GetEmitter()->emitIns_R_R_I(INS_sd, EA_PTRSIZE, REG_FP, REG_SPBASE, FP_offset); + compiler->unwindSaveReg(REG_FP, FP_offset); - // sd ra, #regsSavedSize(sp) - emit->emitIns_R_R_I(INS_sd, EA_PTRSIZE, REG_RA, REG_SPBASE, regsSavedSize); - compiler->unwindSaveReg(REG_RA, regsSavedSize); + GetEmitter()->emitIns_R_R_I(INS_sd, EA_PTRSIZE, REG_RA, REG_SPBASE, FP_offset + 8); + compiler->unwindSaveReg(REG_RA, FP_offset + 8); - // sd fp, #(regsSavedSize+8)(sp) - emit->emitIns_R_R_I(INS_sd, EA_PTRSIZE, REG_FP, REG_SPBASE, regsSavedSize + 8); - compiler->unwindSaveReg(REG_FP, regsSavedSize + 8); + genSaveCalleeSavedRegistersHelp(maskSaveRegs, FP_offset + 16, 0); - // addi sp, sp -#calleeSavedDelta - genStackPointerAdjustment(-calleeSavedDelta, REG_SCRATCH, nullptr, /* reportUnwindData */ true); + genStackPointerAdjustment(frameSize, REG_SCRATCH, nullptr, true); } // This is the end of the OS-reported prolog for purposes of unwinding @@ -977,66 +955,38 @@ void CodeGen::genFuncletEpilog() printf("*************** In genFuncletEpilog()\n"); } #endif - // TODO-RISCV64: Implement varargs (NYI_RISCV64) - // TODO-RISCV64-CQ: We can use C extension for optimization ScopedSetVariable _setGeneratingEpilog(&compiler->compGeneratingEpilog, true); compiler->unwindBegEpilog(); - const int frameSize = genFuncletInfo.fiSpDelta; - + int frameSize = genFuncletInfo.fiSpDelta; assert(frameSize < 0); - regMaskTP maskRestoreRegs = genFuncletInfo.fiSaveRegs & RBM_CALLEE_SAVED; - int regsRestoreSize = (compiler->compCalleeRegsPushed - 2) << 3; - - int calleeSavedDelta = genFuncletInfo.fiSP_to_CalleeSaved_delta; + regMaskTP maskSaveRegs = genFuncletInfo.fiSaveRegs & RBM_CALLEE_SAVED; + int FP_offset = genFuncletInfo.fiSP_to_CalleeSaved_delta; - emitter* emit = GetEmitter(); - regNumber tempReg = rsGetRsvdReg(); - - if (calleeSavedDelta + regsRestoreSize + genFuncletInfo.fiCalleeSavedPadding <= 2040) + if ((FP_offset + (genCountBits(maskSaveRegs) << 3)) > (2040 - 16)) // no FP/RA. { - calleeSavedDelta += genFuncletInfo.fiCalleeSavedPadding; - genRestoreCalleeSavedRegistersHelp(maskRestoreRegs, calleeSavedDelta, 0); - calleeSavedDelta += regsRestoreSize; - - // ld ra, #calleeSavedDelta(sp) - emit->emitIns_R_R_I(INS_ld, EA_PTRSIZE, REG_RA, REG_SPBASE, calleeSavedDelta); - compiler->unwindSaveReg(REG_RA, calleeSavedDelta); + assert(frameSize < -2040); - // ld fp, #(calleeSavedDelta+8)(sp) - emit->emitIns_R_R_I(INS_ld, EA_PTRSIZE, REG_FP, REG_SPBASE, calleeSavedDelta + 8); - compiler->unwindSaveReg(REG_FP, calleeSavedDelta + 8); + genStackPointerAdjustment(FP_offset & -16, REG_SCRATCH, nullptr, /* reportUnwindData */ true); - // addi sp, sp, -#frameSize - genStackPointerAdjustment(-frameSize, tempReg, nullptr, /* reportUnwindData */ true); + frameSize += FP_offset & -16; + FP_offset = FP_offset & 0xf; } - else - { - assert(frameSize < -2040); - - // addi sp, sp, #calleeSavedDelta - genStackPointerAdjustment(calleeSavedDelta, tempReg, nullptr, /* reportUnwindData */ true); - genRestoreCalleeSavedRegistersHelp(maskRestoreRegs, genFuncletInfo.fiCalleeSavedPadding, 0); - regsRestoreSize += genFuncletInfo.fiCalleeSavedPadding; + genRestoreCalleeSavedRegistersHelp(maskSaveRegs, FP_offset + 16, 0); - // ld ra, #regsRestoreSize(sp) - emit->emitIns_R_R_I(INS_ld, EA_PTRSIZE, REG_RA, REG_SPBASE, regsRestoreSize); - compiler->unwindSaveReg(REG_RA, regsRestoreSize); + GetEmitter()->emitIns_R_R_I(INS_ld, EA_PTRSIZE, REG_RA, REG_SPBASE, FP_offset + 8); + compiler->unwindSaveReg(REG_RA, FP_offset + 8); - // ld fp, #(regsRestoreSize+8)(sp) - emit->emitIns_R_R_I(INS_ld, EA_PTRSIZE, REG_FP, REG_SPBASE, regsRestoreSize + 8); - compiler->unwindSaveReg(REG_FP, regsRestoreSize + 8); + GetEmitter()->emitIns_R_R_I(INS_ld, EA_PTRSIZE, REG_FP, REG_SPBASE, FP_offset); + compiler->unwindSaveReg(REG_FP, FP_offset); - // addi sp, sp, -#(frameSize + calleeSavedDelta) - genStackPointerAdjustment(-(frameSize + calleeSavedDelta), tempReg, nullptr, /* reportUnwindData */ true); - } + genStackPointerAdjustment(-frameSize, REG_SCRATCH, nullptr, /* reportUnwindData */ true); - // jarl zero, ra - emit->emitIns_R_R_I(INS_jalr, emitActualTypeSize(TYP_I_IMPL), REG_R0, REG_RA, 0); + GetEmitter()->emitIns_R_R_I(INS_jalr, emitActualTypeSize(TYP_I_IMPL), REG_R0, REG_RA, 0); compiler->unwindReturn(REG_RA); compiler->unwindEndEpilog(); @@ -1059,7 +1009,6 @@ void CodeGen::genCaptureFuncletPrologEpilogInfo() } assert(isFramePointerUsed()); - // The frame size and offsets must be finalized assert(compiler->lvaDoneFrameLayout == Compiler::FINAL_FRAME_LAYOUT); @@ -1067,74 +1016,56 @@ void CodeGen::genCaptureFuncletPrologEpilogInfo() assert((rsMaskSaveRegs & RBM_RA) != 0); assert((rsMaskSaveRegs & RBM_FP) != 0); - unsigned pspSize = (compiler->lvaPSPSym != BAD_VAR_NUM) ? 8 : 0; - - // If there is a PSP slot, we have to pad the funclet frame size for OSR. - // For more details see CodeGen::genFuncletProlog + // Because a method and funclets must have the same caller-relative PSPSym offset, + // if there is a PSPSym, we have to pad the funclet frame size for OSR. // - unsigned osrPad = 0; - if (compiler->opts.IsOSR() && (pspSize != 0)) + int osrPad = 0; + if (compiler->opts.IsOSR()) { - osrPad = compiler->info.compPatchpointInfo->TotalFrameSize(); + osrPad -= compiler->info.compPatchpointInfo->TotalFrameSize(); - // osrPad must be aligned to stackSize - assert(osrPad % STACK_ALIGN == 0); + // OSR pad must be already aligned to stack size. + assert((osrPad % STACK_ALIGN) == 0); } - genFuncletInfo.fiCalleeSavedPadding = 0; - genFuncletInfo.fiFunction_CallerSP_to_FP_delta = genCallerSPtoFPdelta() - osrPad; - - unsigned savedRegsSize = genCountBits(rsMaskSaveRegs); - assert(savedRegsSize == compiler->compCalleeRegsPushed); - savedRegsSize <<= 3; + /* Now save it for future use */ + genFuncletInfo.fiFunction_CallerSP_to_FP_delta = genCallerSPtoFPdelta() + osrPad; - unsigned saveRegsPlusPSPSize = savedRegsSize + pspSize; + int funcletFrameSize = compiler->lvaOutgoingArgSpaceSize; - assert(compiler->lvaOutgoingArgSpaceSize % REGSIZE_BYTES == 0); - unsigned outgoingArgSpaceAligned = roundUp(compiler->lvaOutgoingArgSpaceSize, STACK_ALIGN); + genFuncletInfo.fiSP_to_CalleeSaved_delta = funcletFrameSize; - unsigned funcletFrameSize = osrPad + saveRegsPlusPSPSize + compiler->lvaOutgoingArgSpaceSize; - unsigned funcletFrameSizeAligned = roundUp(funcletFrameSize, STACK_ALIGN); + funcletFrameSize += genCountBits(rsMaskSaveRegs) * REGSIZE_BYTES; - int SP_to_CalleeSaved_delta = compiler->lvaOutgoingArgSpaceSize; - if ((SP_to_CalleeSaved_delta + savedRegsSize) >= 2040) + int delta_PSP = -TARGET_POINTER_SIZE; + if ((compiler->lvaMonAcquired != BAD_VAR_NUM) && !compiler->opts.IsOSR()) { - int offset = funcletFrameSizeAligned - SP_to_CalleeSaved_delta; - SP_to_CalleeSaved_delta = AlignUp((UINT)offset, STACK_ALIGN); - - genFuncletInfo.fiCalleeSavedPadding = SP_to_CalleeSaved_delta - offset; + delta_PSP -= TARGET_POINTER_SIZE; } - if (compiler->lvaMonAcquired != BAD_VAR_NUM && !compiler->opts.IsOSR()) - { - // We furthermore allocate the "monitor acquired" bool between PSP and - // the saved registers because this is part of the EnC header. - // Note that OSR methods reuse the monitor bool created by tier 0. - osrPad += compiler->lvaLclSize(compiler->lvaMonAcquired); - } + funcletFrameSize = funcletFrameSize - delta_PSP - osrPad; + funcletFrameSize = roundUp((unsigned)funcletFrameSize, STACK_ALIGN); - /* Now save it for future use */ - genFuncletInfo.fiSpDelta = -(int)funcletFrameSizeAligned; + genFuncletInfo.fiSpDelta = -funcletFrameSize; genFuncletInfo.fiSaveRegs = rsMaskSaveRegs; - genFuncletInfo.fiSP_to_CalleeSaved_delta = SP_to_CalleeSaved_delta; - genFuncletInfo.fiSP_to_PSP_slot_delta = funcletFrameSizeAligned - osrPad - 8; - genFuncletInfo.fiCallerSP_to_PSP_slot_delta = -(int)osrPad - 8; + genFuncletInfo.fiSP_to_PSP_slot_delta = funcletFrameSize + delta_PSP + osrPad; + genFuncletInfo.fiCallerSP_to_PSP_slot_delta = osrPad + delta_PSP; #ifdef DEBUG if (verbose) { printf("\n"); printf("Funclet prolog / epilog info\n"); - printf(" Save regs: "); + printf(" Save regs: "); dspRegMask(genFuncletInfo.fiSaveRegs); printf("\n"); if (compiler->opts.IsOSR()) { - printf(" OSR Pad: %d\n", osrPad); + printf(" OSR Pad: %d\n", osrPad); } - printf(" Function CallerSP-to-FP delta: %d\n", genFuncletInfo.fiFunction_CallerSP_to_FP_delta); + printf(" Function CallerSP-to-FP delta: %d\n", genFuncletInfo.fiFunction_CallerSP_to_FP_delta); printf(" SP to CalleeSaved location delta: %d\n", genFuncletInfo.fiSP_to_CalleeSaved_delta); - printf(" SP delta: %d\n", genFuncletInfo.fiSpDelta); + printf(" SP delta: %d\n", genFuncletInfo.fiSpDelta); } assert(genFuncletInfo.fiSP_to_CalleeSaved_delta >= 0); @@ -4224,9 +4155,17 @@ void CodeGen::genCodeForJumpCompare(GenTreeOpCC* tree) int CodeGenInterface::genSPtoFPdelta() const { assert(isFramePointerUsed()); - assert(compiler->compCalleeRegsPushed >= 2); + assert(compiler->compCalleeRegsPushed >= 2); // always FP/RA. - int delta = compiler->lvaOutgoingArgSpaceSize + (compiler->compCalleeRegsPushed << 3) - 8; + int delta = compiler->compLclFrameSize; + if (compiler->lvaPSPSym != BAD_VAR_NUM) + { + delta -= TARGET_POINTER_SIZE; + } + if ((compiler->lvaMonAcquired != BAD_VAR_NUM) && !compiler->opts.IsOSR()) + { + delta -= TARGET_POINTER_SIZE; + } assert(delta >= 0); return delta; @@ -7733,8 +7672,8 @@ void CodeGen::instGen_MemoryBarrier(BarrierKind barrierKind) * sd s11, #(offset+8*10)(sp) * * ; save ra, fp - * sd ra, #offset3(sp) ; save RA (8 bytes) - * sd fp, #(offset3+8)(sp) ; save FP (8 bytes) + * sd ra, #offset3+8(sp) ; save RA (8 bytes) + * sd fp, #(offset3)(sp) ; save FP (8 bytes) * * Notes: * 1. FP is always saved, and the first store is FP, RA. @@ -7742,9 +7681,9 @@ void CodeGen::instGen_MemoryBarrier(BarrierKind barrierKind) * 3. For frames with varargs, not implemented completely and not tested ! * 4. We allocate the frame here; no further changes to SP are allowed (except in the body, for localloc). * - * For functions with GS and localloc, we change the frame so the frame pointer and RA are saved at the top - * of the frame, just under the varargs registers (if any). Note that the funclet frames must follow the same - * rule, and both main frame and funclet frames (if any) must put PSPSym in the same offset from Caller-SP. + * For functions with GS and localloc, we had saved the frame pointer and RA at the top + * of the frame. Note that the funclet frames must follow the same rule, + * and both main frame and funclet frames (if any) must put PSPSym in the same offset from Caller-SP. * Since this frame type is relatively rare, we force using it via stress modes, for additional coverage. * * The frames look like the following (simplified to only include components that matter for establishing the @@ -7752,6 +7691,10 @@ void CodeGen::instGen_MemoryBarrier(BarrierKind barrierKind) * * The RISC-V's frame layout is liking: * + * If we need to generate a GS cookie, we need to make sure the saved frame pointer and return address + * (FP and RA) are protected from buffer overrun by the GS cookie. + * So we always save the FP/RA along with the rest of the callee-saved registers above. + * * | | * |-----------------------| * | incoming arguments | @@ -7763,15 +7706,17 @@ void CodeGen::instGen_MemoryBarrier(BarrierKind barrierKind) * |-----------------------| * | PSP slot | // 8 bytes (omitted in NativeAOT ABI) * |-----------------------| - * | locals, temps, etc. | - * |-----------------------| - * | possible GS cookie | + * |Callee saved registers | // not including FP/RA; multiple of 8 bytes * |-----------------------| * | Saved FP | // 8 bytes * |-----------------------| * | Saved RA | // 8 bytes * |-----------------------| - * |Callee saved registers | // not including FP/RA; multiple of 8 bytes + * | possible GS cookie | + * |-----------------------| + * | locals, temps, etc. | + * |-----------------------| + * | possible GS cookie | * |-----------------------| * | Outgoing arg space | // multiple of 8 bytes; if required (i.e., #outsz != 0) * |-----------------------| <---- Ambient SP @@ -7785,12 +7730,6 @@ void CodeGen::genPushCalleeSavedRegisters(regNumber initReg, bool* pInitRegZeroe { assert(compiler->compGeneratingProlog); - // The 'initReg' could have been calculated as one of the callee-saved registers (let's say T0, T1 and T2 are in - // use, so the next possible register is S1, which should be callee-save register). This is fine, as long as we - // save callee-saved registers before using 'initReg' for the first time. Instead, we can use REG_SCRATCH - // beforehand. We don't care if REG_SCRATCH will be overwritten, so we'll skip 'RegZeroed check'. - // - // Unlike on x86/x64, we can also push float registers to stack regMaskTP rsPushRegs = regSet.rsGetModifiedCalleeSavedRegsMask(); #if ETW_EBP_FRAMED @@ -7800,7 +7739,7 @@ void CodeGen::genPushCalleeSavedRegisters(regNumber initReg, bool* pInitRegZeroe } #endif - // On RV64 we always use the FP (frame-pointer) + // We always use the FP (frame-pointer). assert(isFramePointerUsed()); // @@ -7823,25 +7762,25 @@ void CodeGen::genPushCalleeSavedRegisters(regNumber initReg, bool* pInitRegZeroe // is not worth it. // - // we will push callee-saved registers along with fp and ra registers to stack - regMaskTP rsPushRegsMask = rsPushRegs | RBM_FP | RBM_RA; - regSet.rsMaskCalleeSaved = rsPushRegsMask; + regSet.rsMaskCalleeSaved = rsPushRegs | RBM_FPBASE | RBM_RA; #ifdef DEBUG - if (compiler->compCalleeRegsPushed != genCountBits(rsPushRegsMask)) + JITDUMP("Frame info. #outsz=%d; #framesz=%d; LclFrameSize=%d;\n", unsigned(compiler->lvaOutgoingArgSpaceSize), + genTotalFrameSize(), compiler->compLclFrameSize); + + if (compiler->compCalleeRegsPushed != genCountBits(regSet.rsMaskCalleeSaved)) { printf("Error: unexpected number of callee-saved registers to push. Expected: %d. Got: %d ", - compiler->compCalleeRegsPushed, genCountBits(rsPushRegsMask)); - dspRegMask(rsPushRegsMask); + compiler->compCalleeRegsPushed, genCountBits(rsPushRegs | RBM_FPBASE | RBM_RA)); + dspRegMask(rsPushRegs | RBM_FPBASE | RBM_RA); printf("\n"); - assert(compiler->compCalleeRegsPushed == genCountBits(rsPushRegsMask)); + assert(compiler->compCalleeRegsPushed == genCountBits(rsPushRegs | RBM_FPBASE | RBM_RA)); } if (verbose) { - regMaskTP maskSaveRegsFloat = rsPushRegs & RBM_FLT_CALLEE_SAVED; - regMaskTP maskSaveRegsInt = rsPushRegs & RBM_INT_CALLEE_SAVED; - + regMaskTP maskSaveRegsFloat = rsPushRegs & RBM_ALLFLOAT; + regMaskTP maskSaveRegsInt = rsPushRegs & ~maskSaveRegsFloat; printf("Save float regs: "); dspRegMask(maskSaveRegsFloat); printf("\n"); @@ -7851,80 +7790,57 @@ void CodeGen::genPushCalleeSavedRegisters(regNumber initReg, bool* pInitRegZeroe } #endif // DEBUG - // The frameType number is arbitrary, is defined below, and corresponds to one of the frame styles we - // generate based on various sizes. - int frameType = 0; - - // The amount to subtract from SP before starting to store the callee-saved registers. It might be folded into the - // first save instruction as a "predecrement" amount, if possible. - int calleeSaveSPDelta = 0; - - // If we need to generate a GS cookie, we need to make sure the saved frame pointer and return address - // (FP and RA) are protected from buffer overrun by the GS cookie. If FP/RA are at the lowest addresses, - // then they are safe, since they are lower than any unsafe buffers. And the GS cookie we add will - // protect our caller's frame. If we have a localloc, however, that is dynamically placed lower than our - // saved FP/RA. In that case, we save FP/RA along with the rest of the callee-saved registers, above - // the GS cookie. - // - // After the frame is allocated, the frame pointer is established, pointing at the saved frame pointer to - // create a frame pointer chain. - // - - // This will be the starting place for saving the callee-saved registers, in increasing order. - int offset = compiler->lvaOutgoingArgSpaceSize; - int totalFrameSize = genTotalFrameSize(); + int leftFrameSize = 0; + int localFrameSize = compiler->compLclFrameSize; + if (compiler->lvaPSPSym != BAD_VAR_NUM) + { + localFrameSize -= TARGET_POINTER_SIZE; + } + if ((compiler->lvaMonAcquired != BAD_VAR_NUM) && !compiler->opts.IsOSR()) + { + localFrameSize -= TARGET_POINTER_SIZE; + } - emitter* emit = GetEmitter(); +#ifdef DEBUG + if (compiler->opts.disAsm) + { + printf("Frame info. #outsz=%d; #framesz=%d; lcl=%d\n", unsigned(compiler->lvaOutgoingArgSpaceSize), + genTotalFrameSize(), localFrameSize); + } +#endif - // ensure offset of sd/ld + int FP_offset = localFrameSize; if (totalFrameSize <= 2040) { - frameType = 1; - - emit->emitIns_R_R_I(INS_addi, EA_PTRSIZE, REG_SPBASE, REG_SPBASE, -totalFrameSize); + GetEmitter()->emitIns_R_R_I(INS_addi, EA_PTRSIZE, REG_SPBASE, REG_SPBASE, -totalFrameSize); compiler->unwindAllocStack(totalFrameSize); - - JITDUMP("Frame type 1. #outsz=%d; #framesz=%d; LclFrameSize=%d\n", unsigned(compiler->lvaOutgoingArgSpaceSize), - totalFrameSize, compiler->compLclFrameSize); } else { - frameType = 2; - // we have to adjust stack pointer; probably using add instead of addi - - JITDUMP("Frame type 2. #outsz=%d; #framesz=%d; LclFrameSize=%d\n", unsigned(compiler->lvaOutgoingArgSpaceSize), - totalFrameSize, compiler->compLclFrameSize); - - if ((offset + (compiler->compCalleeRegsPushed << 3)) >= 2040) - { - offset = totalFrameSize - compiler->lvaOutgoingArgSpaceSize; - calleeSaveSPDelta = AlignUp((UINT)offset, STACK_ALIGN); - offset = calleeSaveSPDelta - offset; - - genStackPointerAdjustment(-calleeSaveSPDelta, REG_SCRATCH, nullptr, /* reportUnwindData */ true); - } - else + if ((localFrameSize + (compiler->compCalleeRegsPushed << 3)) > 2040) { - genStackPointerAdjustment(-totalFrameSize, REG_SCRATCH, nullptr, /* reportUnwindData */ true); + leftFrameSize = localFrameSize & -16; + totalFrameSize = totalFrameSize - (localFrameSize & -16); + FP_offset = localFrameSize & 0xf; } + // The 'initReg' could have been calculated as one of the callee-saved registers (let's say T0, T1 and T2 are in + // use, so the next possible register is S1, which should be callee-save register). This is fine, as long as we + // save callee-saved registers before using 'initReg' for the first time. Instead, we can use REG_SCRATCH + // beforehand. We don't care if REG_SCRATCH will be overwritten, so we'll skip 'RegZeroed check'. + // TODO-RV64: this should be resolved before calling `genPushCalleeSavedRegisters`. + genStackPointerAdjustment(-totalFrameSize, REG_SCRATCH, nullptr, /* reportUnwindData */ true); } + GetEmitter()->emitIns_R_R_I(INS_sd, EA_PTRSIZE, REG_FP, REG_SPBASE, FP_offset); + compiler->unwindSaveReg(REG_FP, FP_offset); - JITDUMP(" offset=%d, calleeSaveSPDelta=%d\n", offset, calleeSaveSPDelta); - - genSaveCalleeSavedRegistersHelp(rsPushRegs, offset, 0); - offset += (int)(genCountBits(rsPushRegs) << 3); // each reg has 8 bytes + GetEmitter()->emitIns_R_R_I(INS_sd, EA_PTRSIZE, REG_RA, REG_SPBASE, FP_offset + 8); + compiler->unwindSaveReg(REG_RA, FP_offset + 8); - // From now on, we can safely use initReg. + genSaveCalleeSavedRegistersHelp(rsPushRegs, FP_offset + 16, 0); - emit->emitIns_R_R_I(INS_sd, EA_PTRSIZE, REG_RA, REG_SPBASE, offset); - compiler->unwindSaveReg(REG_RA, offset); - - emit->emitIns_R_R_I(INS_sd, EA_PTRSIZE, REG_FP, REG_SPBASE, offset + 8); - compiler->unwindSaveReg(REG_FP, offset + 8); - - JITDUMP(" offsetSpToSavedFp=%d\n", offset + 8); - genEstablishFramePointer(offset + 8, /* reportUnwindData */ true); + JITDUMP(" offsetSpToSavedFp=%d\n", FP_offset); + genEstablishFramePointer(FP_offset, /* reportUnwindData */ true); // For varargs, home the incoming arg registers last. Note that there is nothing to unwind here, // so we just report "NOP" unwind codes. If there's no more frame setup after this, we don't @@ -7935,18 +7851,9 @@ void CodeGen::genPushCalleeSavedRegisters(regNumber initReg, bool* pInitRegZeroe NYI_RISCV64("genPushCalleeSavedRegisters unsupports compIsVarArgs"); } -#ifdef DEBUG - if (compiler->opts.disAsm) - { - printf("DEBUG: RISCV64, frameType:%d\n\n", frameType); - } -#endif - - if (calleeSaveSPDelta != 0) + if (leftFrameSize != 0) { - assert(frameType == 2); - calleeSaveSPDelta = totalFrameSize - calleeSaveSPDelta; - genStackPointerAdjustment(-calleeSaveSPDelta, initReg, pInitRegZeroed, /* reportUnwindData */ true); + genStackPointerAdjustment(-leftFrameSize, REG_SCRATCH, nullptr, /* reportUnwindData */ true); } } @@ -7956,80 +7863,72 @@ void CodeGen::genPopCalleeSavedRegisters(bool jmpEpilog) regMaskTP regsToRestoreMask = regSet.rsGetModifiedCalleeSavedRegsMask(); - // On RV64 we always use the FP (frame-pointer) assert(isFramePointerUsed()); - int totalFrameSize = genTotalFrameSize(); - int remainingSPSize = totalFrameSize; - int callerSPtoFPdelta = 0; - int calleeSaveSPOffset = 0; // This will be the starting place for restoring - // the callee-saved registers, in decreasing order. + int totalFrameSize = genTotalFrameSize(); + int localFrameSize = compiler->compLclFrameSize; + if (compiler->lvaPSPSym != BAD_VAR_NUM) + { + localFrameSize -= TARGET_POINTER_SIZE; + } + if ((compiler->lvaMonAcquired != BAD_VAR_NUM) && !compiler->opts.IsOSR()) + { + localFrameSize -= TARGET_POINTER_SIZE; + } - emitter* emit = GetEmitter(); + JITDUMP("Frame type. #outsz=%d; #framesz=%d; #calleeSaveRegsPushed:%d; " + "localloc? %s\n", + unsigned(compiler->lvaOutgoingArgSpaceSize), totalFrameSize, compiler->compCalleeRegsPushed, + dspBool(compiler->compLocallocUsed)); - // ensure offset of sd/ld + emitter* emit = GetEmitter(); + int FP_offset = localFrameSize; + int remainingSPSize = totalFrameSize; if (totalFrameSize <= 2040) { - JITDUMP("Frame type 1. #outsz=%d; #framesz=%d; localloc? %s\n", unsigned(compiler->lvaOutgoingArgSpaceSize), - totalFrameSize, dspBool(compiler->compLocallocUsed)); - if (compiler->compLocallocUsed) { - callerSPtoFPdelta = (compiler->compCalleeRegsPushed << 3) - 8 + compiler->lvaOutgoingArgSpaceSize; + int SPtoFPdelta = genSPtoFPdelta(); + // Restore sp from fp + emit->emitIns_R_R_I(INS_addi, EA_PTRSIZE, REG_SPBASE, REG_FPBASE, -SPtoFPdelta); + compiler->unwindSetFrameReg(REG_FPBASE, SPtoFPdelta); } - calleeSaveSPOffset = compiler->lvaOutgoingArgSpaceSize; - // remainingSPSize = totalFrameSize; } else { - JITDUMP("Frame type 2. #outsz=%d; #framesz=%d; calleeSaveRegsPushed: %d; localloc? %s\n", - unsigned(compiler->lvaOutgoingArgSpaceSize), totalFrameSize, compiler->compCalleeRegsPushed, - dspBool(compiler->compLocallocUsed)); - - if ((compiler->lvaOutgoingArgSpaceSize + (compiler->compCalleeRegsPushed << 3)) > 2047) + if (compiler->compLocallocUsed) { - calleeSaveSPOffset = compiler->lvaOutgoingArgSpaceSize & 0xfffffff0; - - if (compiler->compLocallocUsed) + int SPtoFPdelta = genSPtoFPdelta(); + // Restore sp from fp + if (emitter::isValidSimm12(SPtoFPdelta)) { - callerSPtoFPdelta = (compiler->compCalleeRegsPushed << 3) - 8; + emit->emitIns_R_R_I(INS_addi, EA_PTRSIZE, REG_SPBASE, REG_FPBASE, -SPtoFPdelta); } else { - genStackPointerAdjustment(calleeSaveSPOffset, REG_RA, nullptr, /* reportUnwindData */ true); + regNumber tempReg = rsGetRsvdReg(); + emit->emitLoadImmediate(EA_PTRSIZE, tempReg, SPtoFPdelta); + emit->emitIns_R_R_R(INS_sub, EA_PTRSIZE, REG_SPBASE, REG_FPBASE, tempReg); } - remainingSPSize = totalFrameSize - calleeSaveSPOffset; - calleeSaveSPOffset = compiler->lvaOutgoingArgSpaceSize - calleeSaveSPOffset; } - else + if ((localFrameSize + (compiler->compCalleeRegsPushed << 3)) > 2040) { - if (compiler->compLocallocUsed) - { - callerSPtoFPdelta = (compiler->compCalleeRegsPushed << 3) - 8 + compiler->lvaOutgoingArgSpaceSize; - } - calleeSaveSPOffset = compiler->lvaOutgoingArgSpaceSize; - // remainingSPSize = totalFrameSize; - } - } + remainingSPSize = localFrameSize & -16; + genStackPointerAdjustment(remainingSPSize, REG_RA, nullptr, /* reportUnwindData */ true); - if (compiler->compLocallocUsed) - { - // restore sp form fp: addi sp, -#callerSPtoFPdelta(fp) - emit->emitIns_R_R_I(INS_addi, EA_PTRSIZE, REG_SPBASE, REG_FPBASE, -callerSPtoFPdelta); - compiler->unwindSetFrameReg(REG_FPBASE, callerSPtoFPdelta); + remainingSPSize = totalFrameSize - remainingSPSize; + FP_offset = localFrameSize & 0xf; + } } - JITDUMP(" calleeSaveSPOffset=%d, callerSPtoFPdelta=%d\n", calleeSaveSPOffset, callerSPtoFPdelta); - genRestoreCalleeSavedRegistersHelp(regsToRestoreMask, calleeSaveSPOffset, 0); - - // restore ra/fp regs - calleeSaveSPOffset += (compiler->compCalleeRegsPushed - 2) << 3; + JITDUMP(" calleeSaveSPOffset=%d\n", FP_offset + 16); + genRestoreCalleeSavedRegistersHelp(regsToRestoreMask, FP_offset + 16, 0); - emit->emitIns_R_R_I(INS_ld, EA_PTRSIZE, REG_RA, REG_SPBASE, calleeSaveSPOffset); - compiler->unwindSaveReg(REG_RA, calleeSaveSPOffset); + emit->emitIns_R_R_I(INS_ld, EA_PTRSIZE, REG_RA, REG_SPBASE, FP_offset + 8); + compiler->unwindSaveReg(REG_RA, FP_offset + 8); - emit->emitIns_R_R_I(INS_ld, EA_PTRSIZE, REG_FP, REG_SPBASE, calleeSaveSPOffset + 8); - compiler->unwindSaveReg(REG_FP, calleeSaveSPOffset + 8); + emit->emitIns_R_R_I(INS_ld, EA_PTRSIZE, REG_FP, REG_SPBASE, FP_offset); + compiler->unwindSaveReg(REG_FP, FP_offset); if (emitter::isValidUimm11(remainingSPSize)) { @@ -8043,7 +7942,7 @@ void CodeGen::genPopCalleeSavedRegisters(bool jmpEpilog) } compiler->unwindAllocStack(remainingSPSize); - // for OSR we have to adjust SP to remove tier0 frame + // For OSR, we must also adjust the SP to remove the Tier0 frame. if (compiler->opts.IsOSR()) { const int tier0FrameSize = compiler->info.compPatchpointInfo->TotalFrameSize(); diff --git a/src/coreclr/jit/lclvars.cpp b/src/coreclr/jit/lclvars.cpp index c101955fdea7ed..e6645e1f03d8f4 100644 --- a/src/coreclr/jit/lclvars.cpp +++ b/src/coreclr/jit/lclvars.cpp @@ -5669,23 +5669,52 @@ void Compiler::lvaFixVirtualFrameOffsets() // We set FP to be after LR, FP delta += 2 * REGSIZE_BYTES; } -#elif defined(TARGET_AMD64) || defined(TARGET_ARM64) || defined(TARGET_LOONGARCH64) || defined(TARGET_RISCV64) +#elif defined(TARGET_AMD64) || defined(TARGET_ARM64) else { // FP is used. JITDUMP("--- delta bump %d for FP frame\n", codeGen->genTotalFrameSize() - codeGen->genSPtoFPdelta()); delta += codeGen->genTotalFrameSize() - codeGen->genSPtoFPdelta(); } -#endif // TARGET_AMD64 || TARGET_ARM64 || TARGET_LOONGARCH64 || TARGET_RISCV64 +#elif defined(TARGET_LOONGARCH64) || defined(TARGET_RISCV64) + else + { + // FP is used. + delta += (compCalleeRegsPushed << 3); + + if ((lvaMonAcquired != BAD_VAR_NUM) && !opts.IsOSR()) + { + int offset = lvaTable[lvaMonAcquired].GetStackOffset() + delta; + lvaTable[lvaMonAcquired].SetStackOffset(offset); + + if (lvaPSPSym != BAD_VAR_NUM) + { + int offset = lvaTable[lvaPSPSym].GetStackOffset() + delta; + lvaTable[lvaPSPSym].SetStackOffset(offset); + delta += TARGET_POINTER_SIZE; + } + + delta += lvaLclSize(lvaMonAcquired); + } + else if (lvaPSPSym != BAD_VAR_NUM) + { + int offset = lvaTable[lvaPSPSym].GetStackOffset() + delta; + lvaTable[lvaPSPSym].SetStackOffset(offset); + delta += TARGET_POINTER_SIZE; + } + + JITDUMP("--- delta bump %d for FP frame\n", delta); + } +#endif // !TARGET_LOONGARCH64 || !TARGET_RISCV64 if (opts.IsOSR()) { -#if defined(TARGET_AMD64) || defined(TARGET_ARM64) || defined(TARGET_LOONGARCH64) || defined(TARGET_RISCV64) +#if defined(TARGET_AMD64) || defined(TARGET_ARM64) // Stack offset includes Tier0 frame. // JITDUMP("--- delta bump %d for OSR + Tier0 frame\n", info.compPatchpointInfo->TotalFrameSize()); delta += info.compPatchpointInfo->TotalFrameSize(); -#endif +#endif // TARGET_AMD64 || TARGET_ARM64 } JITDUMP("--- virtual stack offset to actual stack offset delta is %d\n", delta); @@ -5775,26 +5804,20 @@ void Compiler::lvaFixVirtualFrameOffsets() #endif // FEATURE_FIXED_OUT_ARGS -#if defined(TARGET_ARM64) +#if defined(TARGET_ARM64) || defined(TARGET_LOONGARCH64) || defined(TARGET_RISCV64) // We normally add alignment below the locals between them and the outgoing // arg space area. When we store fp/lr(ra) at the bottom, however, this will // be below the alignment. So we should not apply the alignment adjustment to // them. It turns out we always store these at +0 and +8 of the FP, // so instead of dealing with skipping adjustment just for them we just set // them here always. + // For LoongArch64 and RISCV64, the RA is always at fp+8. assert(codeGen->isFramePointerUsed()); if (lvaRetAddrVar != BAD_VAR_NUM) { lvaTable[lvaRetAddrVar].SetStackOffset(REGSIZE_BYTES); } -#elif defined(TARGET_LOONGARCH64) || defined(TARGET_RISCV64) - assert(codeGen->isFramePointerUsed()); - if (lvaRetAddrVar != BAD_VAR_NUM) - { - // For LoongArch64 and RISCV64, the RA is below the fp. see the `genPushCalleeSavedRegisters` - lvaTable[lvaRetAddrVar].SetStackOffset(-REGSIZE_BYTES); - } -#endif // !TARGET_LOONGARCH64 +#endif // !TARGET_ARM64 || !TARGET_LOONGARCH64 || !TARGET_RISCV64 } #ifdef TARGET_ARM @@ -6548,9 +6571,13 @@ void Compiler::lvaAssignVirtualFrameOffsetsToLocals() // if (opts.IsOSR()) { +#if defined(TARGET_LOONGARCH64) || defined(TARGET_RISCV64) + originalFrameStkOffs = info.compPatchpointInfo->TotalFrameSize(); +#else originalFrameSize = info.compPatchpointInfo->TotalFrameSize(); originalFrameStkOffs = stkOffs; stkOffs -= originalFrameSize; +#endif } #ifdef TARGET_XARCH @@ -6606,7 +6633,8 @@ void Compiler::lvaAssignVirtualFrameOffsetsToLocals() #elif defined(TARGET_LOONGARCH64) || defined(TARGET_RISCV64) - assert(compCalleeRegsPushed >= 2); + assert(compCalleeRegsPushed >= 2); // always FP/RA. + stkOffs -= (compCalleeRegsPushed << 3); #else // !TARGET_LOONGARCH64 && !TARGET_RISCV64 #ifdef TARGET_ARM @@ -7331,14 +7359,9 @@ void Compiler::lvaAssignVirtualFrameOffsetsToLocals() } #endif // FEATURE_FIXED_OUT_ARGS -#if defined(TARGET_LOONGARCH64) || defined(TARGET_RISCV64) - // For LoongArch64 and RISCV64, CalleeSavedRegs are at bottom. - int pushedCount = 0; -#else // compLclFrameSize equals our negated virtual stack offset minus the pushed registers and return address // and the pushed frame pointer register which for some strange reason isn't part of 'compCalleeRegsPushed'. int pushedCount = compCalleeRegsPushed; -#endif #ifdef TARGET_ARM64 if (info.compIsVarArgs) diff --git a/src/coreclr/jit/regset.h b/src/coreclr/jit/regset.h index dae93baebad306..20b55610594fc6 100644 --- a/src/coreclr/jit/regset.h +++ b/src/coreclr/jit/regset.h @@ -158,8 +158,9 @@ class RegSet regMaskTP _rsMaskVars; // backing store for rsMaskVars property #if defined(TARGET_ARMARCH) || defined(TARGET_LOONGARCH64) || defined(TARGET_RISCV64) + // TODO: the funclet's callee-saved registers should not shared with main function. regMaskTP rsMaskCalleeSaved; // mask of the registers pushed/popped in the prolog/epilog -#endif // TARGET_ARMARCH || TARGET_LOONGARCH64 +#endif // TARGET_ARMARCH || TARGET_LOONGARCH64 || TARGET_RISCV64 public: // TODO-Cleanup: Should be private, but Compiler uses it regMaskTP rsMaskResvd; // mask of the registers that are reserved for special purposes (typically empty) From 56dcfd700383a9462d4b8632e88abd75b4252357 Mon Sep 17 00:00:00 2001 From: Stephen Toub Date: Tue, 23 Apr 2024 08:15:15 -0400 Subject: [PATCH 024/161] Remove some dead code from SharedArrayPool (#101410) In Trim, for high memory pressure, we're already setting the number of arrays to trim equal to the max number possible, so the subsequent logic that would increase the count wasn't useful. Deleting that also deleted the last use of _elementSize, which in turn allowed for the path that provided that value to be cleaned up. --- .../src/System/Buffers/SharedArrayPool.cs | 68 ++++--------------- 1 file changed, 15 insertions(+), 53 deletions(-) diff --git a/src/libraries/System.Private.CoreLib/src/System/Buffers/SharedArrayPool.cs b/src/libraries/System.Private.CoreLib/src/System/Buffers/SharedArrayPool.cs index 89bbd450452391..3fa044d074d607 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Buffers/SharedArrayPool.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Buffers/SharedArrayPool.cs @@ -40,10 +40,7 @@ internal sealed partial class SharedArrayPool : ArrayPool /// Allocate a new and try to store it into the array. private unsafe SharedArrayPoolPartitions CreatePerCorePartitions(int bucketIndex) { -#pragma warning disable 8500 // sizeof of managed types - int elementSize = sizeof(T); -#pragma warning restore 8500 - var inst = new SharedArrayPoolPartitions(elementSize); + var inst = new SharedArrayPoolPartitions(); return Interlocked.CompareExchange(ref _buckets[bucketIndex], inst, null) ?? inst; } @@ -199,7 +196,7 @@ public bool Trim() SharedArrayPoolPartitions?[] perCoreBuckets = _buckets; for (int i = 0; i < perCoreBuckets.Length; i++) { - perCoreBuckets[i]?.Trim(currentMilliseconds, Id, pressure, Utilities.GetMaxSizeForBucket(i)); + perCoreBuckets[i]?.Trim(currentMilliseconds, Id, pressure); } // Trim each of the TLS buckets. Note that threads may be modifying their TLS slots concurrently with @@ -323,14 +320,13 @@ internal sealed class SharedArrayPoolPartitions private readonly Partition[] _partitions; /// Initializes the partitions. - /// The size of the elements stored in arrays. - public SharedArrayPoolPartitions(int elementSize) + public SharedArrayPoolPartitions() { // Create the partitions. We create as many as there are processors, limited by our max. var partitions = new Partition[SharedArrayPoolStatics.s_partitionCount]; for (int i = 0; i < partitions.Length; i++) { - partitions[i] = new Partition(elementSize); + partitions[i] = new Partition(); } _partitions = partitions; } @@ -374,23 +370,20 @@ public bool TryPush(Array array) return null; } - public void Trim(int currentMilliseconds, int id, Utilities.MemoryPressure pressure, int bucketSize) + public void Trim(int currentMilliseconds, int id, Utilities.MemoryPressure pressure) { Partition[] partitions = _partitions; for (int i = 0; i < partitions.Length; i++) { - partitions[i].Trim(currentMilliseconds, id, pressure, bucketSize); + partitions[i].Trim(currentMilliseconds, id, pressure); } } /// Provides a simple, bounded stack of arrays, protected by a lock. - /// The size of the elements stored in arrays. - private sealed class Partition(int elementSize) + private sealed class Partition { /// The arrays in the partition. private readonly Array?[] _arrays = new Array[SharedArrayPoolStatics.s_maxArraysPerPartition]; - /// The size of the elements stored in arrays. - private readonly int _elementSize = elementSize; /// Number of arrays stored in . private int _count; /// Timestamp set by Trim when it sees this as 0. @@ -437,20 +430,11 @@ public bool TryPush(Array array) return arr; } - public void Trim(int currentMilliseconds, int id, Utilities.MemoryPressure pressure, int bucketSize) + public void Trim(int currentMilliseconds, int id, Utilities.MemoryPressure pressure) { const int TrimAfterMS = 60 * 1000; // Trim after 60 seconds for low/moderate pressure const int HighTrimAfterMS = 10 * 1000; // Trim after 10 seconds for high pressure - const int LargeBucket = 16384; // If the bucket is larger than this we'll trim an extra when under high pressure - - const int ModerateTypeSize = 16; // If T is larger than this we'll trim an extra when under high pressure - const int LargeTypeSize = 32; // If T is larger than this we'll trim an extra (additional) when under high pressure - - const int LowTrimCount = 1; // Trim one item when pressure is low - const int MediumTrimCount = 2; // Trim two items when pressure is moderate - int HighTrimCount = SharedArrayPoolStatics.s_maxArraysPerPartition; // Trim all items when pressure is high - if (_count == 0) { return; @@ -477,38 +461,16 @@ public void Trim(int currentMilliseconds, int id, Utilities.MemoryPressure press } // We've elapsed enough time since the first item went into the partition. - // Drop the top item so it can be collected and make the partition look a little newer. + // Drop the top item(s) so they can be collected. - ArrayPoolEventSource log = ArrayPoolEventSource.Log; - int trimCount = LowTrimCount; - switch (pressure) + int trimCount = pressure switch { - case Utilities.MemoryPressure.High: - trimCount = HighTrimCount; - - // When pressure is high, aggressively trim larger arrays. - if (bucketSize > LargeBucket) - { - trimCount++; - } - - if (_elementSize > ModerateTypeSize) - { - trimCount++; - - if (_elementSize > LargeTypeSize) - { - trimCount++; - } - } - - break; - - case Utilities.MemoryPressure.Medium: - trimCount = MediumTrimCount; - break; - } + Utilities.MemoryPressure.High => SharedArrayPoolStatics.s_maxArraysPerPartition, + Utilities.MemoryPressure.Medium => 2, + _ => 1, + }; + ArrayPoolEventSource log = ArrayPoolEventSource.Log; while (_count > 0 && trimCount-- > 0) { Array? array = _arrays[--_count]; From b4e0169bfe10cfe69f6e7a8952b8f80fdfe9e31e Mon Sep 17 00:00:00 2001 From: Stephen Toub Date: Tue, 23 Apr 2024 09:11:55 -0400 Subject: [PATCH 025/161] Dedup UnboundedChannel and UnboundedPriorityChannel (#101396) * Dedup UnboundedChannel and UnboundedPriorityChannel We can use generic specialization to avoid duplicating all the code for the different queue types. This should also make it much simpler to add other queue types in the future. * Address PR feedback --- .../src/System.Threading.Channels.csproj | 2 +- .../src/System/Threading/Channels/Channel.cs | 35 +- .../Threading/Channels/Channel.netcoreapp.cs | 44 ++- .../Threading/Channels/IDebugEnumerator.cs | 4 +- .../Channels/IUnboundedChannelQueue.cs | 35 ++ .../Threading/Channels/UnboundedChannel.cs | 92 +++-- .../Channels/UnboundedPriorityChannel.cs | 369 ------------------ 7 files changed, 179 insertions(+), 402 deletions(-) create mode 100644 src/libraries/System.Threading.Channels/src/System/Threading/Channels/IUnboundedChannelQueue.cs delete mode 100644 src/libraries/System.Threading.Channels/src/System/Threading/Channels/UnboundedPriorityChannel.cs diff --git a/src/libraries/System.Threading.Channels/src/System.Threading.Channels.csproj b/src/libraries/System.Threading.Channels/src/System.Threading.Channels.csproj index c058b0b216b17a..a5030bcee65616 100644 --- a/src/libraries/System.Threading.Channels/src/System.Threading.Channels.csproj +++ b/src/libraries/System.Threading.Channels/src/System.Threading.Channels.csproj @@ -25,6 +25,7 @@ System.Threading.Channel<T> + @@ -44,7 +45,6 @@ System.Threading.Channel<T> - diff --git a/src/libraries/System.Threading.Channels/src/System/Threading/Channels/Channel.cs b/src/libraries/System.Threading.Channels/src/System/Threading/Channels/Channel.cs index 317636579a05fd..834d8ad88ed1d7 100644 --- a/src/libraries/System.Threading.Channels/src/System/Threading/Channels/Channel.cs +++ b/src/libraries/System.Threading.Channels/src/System/Threading/Channels/Channel.cs @@ -1,6 +1,10 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; + namespace System.Threading.Channels { /// Provides static methods for creating channels. @@ -9,7 +13,7 @@ public static partial class Channel /// Creates an unbounded channel usable by any number of readers and writers concurrently. /// The created channel. public static Channel CreateUnbounded() => - new UnboundedChannel(runContinuationsAsynchronously: true); + new UnboundedChannel>(new(new()), runContinuationsAsynchronously: true); /// Creates an unbounded channel subject to the provided options. /// Specifies the type of data in the channel. @@ -27,7 +31,7 @@ public static Channel CreateUnbounded(UnboundedChannelOptions options) return new SingleConsumerUnboundedChannel(!options.AllowSynchronousContinuations); } - return new UnboundedChannel(!options.AllowSynchronousContinuations); + return new UnboundedChannel>(new(new()), !options.AllowSynchronousContinuations); } /// Creates a channel with the specified maximum capacity. @@ -71,5 +75,32 @@ public static Channel CreateBounded(BoundedChannelOptions options, Action< return new BoundedChannel(options.Capacity, options.FullMode, !options.AllowSynchronousContinuations, itemDropped); } + + /// Provides an for a . + private readonly struct UnboundedChannelConcurrentQueue(ConcurrentQueue queue) : IUnboundedChannelQueue + { + private readonly ConcurrentQueue _queue = queue; + + /// + public bool IsThreadSafe => true; + + /// + public void Enqueue(T item) => _queue.Enqueue(item); + + /// + public bool TryDequeue([MaybeNullWhen(false)] out T item) => _queue.TryDequeue(out item); + + /// + public bool TryPeek([MaybeNullWhen(false)] out T item) => _queue.TryPeek(out item); + + /// + public int Count => _queue.Count; + + /// + public bool IsEmpty => _queue.IsEmpty; + + /// + public IEnumerator GetEnumerator() => _queue.GetEnumerator(); + } } } diff --git a/src/libraries/System.Threading.Channels/src/System/Threading/Channels/Channel.netcoreapp.cs b/src/libraries/System.Threading.Channels/src/System/Threading/Channels/Channel.netcoreapp.cs index 6c24b3e41ec7b5..c8fc9baebae7db 100644 --- a/src/libraries/System.Threading.Channels/src/System/Threading/Channels/Channel.netcoreapp.cs +++ b/src/libraries/System.Threading.Channels/src/System/Threading/Channels/Channel.netcoreapp.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; namespace System.Threading.Channels { @@ -9,13 +10,14 @@ namespace System.Threading.Channels public static partial class Channel { /// Creates an unbounded prioritized channel usable by any number of readers and writers concurrently. + /// Specifies the type of data in the channel. /// The created channel. /// /// is used to determine priority of elements. /// The next item read from the channel will be the element available in the channel with the lowest priority value. /// public static Channel CreateUnboundedPrioritized() => - new UnboundedPrioritizedChannel(runContinuationsAsynchronously: true, comparer: null); + new UnboundedChannel>(new(new()), runContinuationsAsynchronously: true); /// Creates an unbounded prioritized channel subject to the provided options. /// Specifies the type of data in the channel. @@ -30,7 +32,45 @@ public static Channel CreateUnboundedPrioritized(UnboundedPrioritizedChann { ArgumentNullException.ThrowIfNull(options); - return new UnboundedPrioritizedChannel(!options.AllowSynchronousContinuations, options.Comparer); + return new UnboundedChannel>(new(new(options.Comparer)), !options.AllowSynchronousContinuations); + } + + /// Provides an for a . + private readonly struct UnboundedChannelPriorityQueue(PriorityQueue queue) : IUnboundedChannelQueue + { + private readonly PriorityQueue _queue = queue; + + /// + public bool IsThreadSafe => false; + + /// + public void Enqueue(T item) => _queue.Enqueue(true, item); + + /// + public bool TryDequeue([MaybeNullWhen(false)] out T item) => _queue.TryDequeue(out _, out item); + + /// + public bool TryPeek([MaybeNullWhen(false)] out T item) => _queue.TryPeek(out _, out item); + + /// + public int Count => _queue.Count; + + /// + public bool IsEmpty => _queue.Count == 0; + + /// + public IEnumerator GetEnumerator() + { + List list = []; + foreach ((bool _, T Priority) item in _queue.UnorderedItems) + { + list.Add(item.Priority); + } + + list.Sort(_queue.Comparer); + + return list.GetEnumerator(); + } } } } diff --git a/src/libraries/System.Threading.Channels/src/System/Threading/Channels/IDebugEnumerator.cs b/src/libraries/System.Threading.Channels/src/System/Threading/Channels/IDebugEnumerator.cs index a3d072ee9f7cb4..af2a77bb1bf775 100644 --- a/src/libraries/System.Threading.Channels/src/System/Threading/Channels/IDebugEnumerator.cs +++ b/src/libraries/System.Threading.Channels/src/System/Threading/Channels/IDebugEnumerator.cs @@ -11,7 +11,7 @@ internal interface IDebugEnumerable IEnumerator GetEnumerator(); } - internal sealed class DebugEnumeratorDebugView + internal class DebugEnumeratorDebugView { public DebugEnumeratorDebugView(IDebugEnumerable enumerable) { @@ -26,4 +26,6 @@ public DebugEnumeratorDebugView(IDebugEnumerable enumerable) [DebuggerBrowsable(DebuggerBrowsableState.RootHidden)] public T[] Items { get; } } + + internal sealed class DebugEnumeratorDebugView(IDebugEnumerable enumerable) : DebugEnumeratorDebugView(enumerable); } diff --git a/src/libraries/System.Threading.Channels/src/System/Threading/Channels/IUnboundedChannelQueue.cs b/src/libraries/System.Threading.Channels/src/System/Threading/Channels/IUnboundedChannelQueue.cs new file mode 100644 index 00000000000000..b1b65a1dffeb10 --- /dev/null +++ b/src/libraries/System.Threading.Channels/src/System/Threading/Channels/IUnboundedChannelQueue.cs @@ -0,0 +1,35 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; + +namespace System.Threading.Channels +{ + /// Representation of the queue data structure used by . + internal interface IUnboundedChannelQueue : IDebugEnumerable + { + /// Gets whether the other members are safe to use concurrently with each other and themselves. + bool IsThreadSafe { get; } + + /// Enqueues an item into the queue. + /// The item to enqueue. + void Enqueue(T item); + + /// Dequeues an item from the queue, if possible. + /// The dequeued item, or default if the queue was empty. + /// Whether an item was dequeued. + bool TryDequeue([MaybeNullWhen(false)] out T item); + + /// Peeks at the next item from the queue that would be dequeued, if possible. + /// The peeked item, or default if the queue was empty. + /// Whether an item was peeked. + bool TryPeek([MaybeNullWhen(false)] out T item); + + /// Gets the number of elements in the queue. + int Count { get; } + + /// Gets whether the queue is empty. + bool IsEmpty { get; } + } +} diff --git a/src/libraries/System.Threading.Channels/src/System/Threading/Channels/UnboundedChannel.cs b/src/libraries/System.Threading.Channels/src/System/Threading/Channels/UnboundedChannel.cs index fb3facf83dc47e..ad7ee0e3608d3c 100644 --- a/src/libraries/System.Threading.Channels/src/System/Threading/Channels/UnboundedChannel.cs +++ b/src/libraries/System.Threading.Channels/src/System/Threading/Channels/UnboundedChannel.cs @@ -5,19 +5,20 @@ using System.Collections.Generic; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; +using System.Runtime.CompilerServices; using System.Threading.Tasks; namespace System.Threading.Channels { /// Provides a buffered channel of unbounded capacity. [DebuggerDisplay("Items = {ItemsCountForDebugger}, Closed = {ChannelIsClosedForDebugger}")] - [DebuggerTypeProxy(typeof(DebugEnumeratorDebugView<>))] - internal sealed class UnboundedChannel : Channel, IDebugEnumerable + [DebuggerTypeProxy(typeof(DebugEnumeratorDebugView<,>))] + internal sealed class UnboundedChannel : Channel, IDebugEnumerable where TQueue : struct, IUnboundedChannelQueue { /// Task that indicates the channel has completed. private readonly TaskCompletionSource _completion; /// The items in the channel. - private readonly ConcurrentQueue _items = new ConcurrentQueue(); + private readonly TQueue _items; /// Readers blocked reading from the channel. private readonly Deque> _blockedReaders = new Deque>(); /// Whether to force continuations to be executed asynchronously from producer writes. @@ -29,8 +30,9 @@ internal sealed class UnboundedChannel : Channel, IDebugEnumerable private Exception? _doneWriting; /// Initialize the channel. - internal UnboundedChannel(bool runContinuationsAsynchronously) + internal UnboundedChannel(TQueue items, bool runContinuationsAsynchronously) { + _items = items; _runContinuationsAsynchronously = runContinuationsAsynchronously; _completion = new TaskCompletionSource(runContinuationsAsynchronously ? TaskCreationOptions.RunContinuationsAsynchronously : TaskCreationOptions.None); Reader = new UnboundedChannelReader(this); @@ -38,14 +40,14 @@ internal UnboundedChannel(bool runContinuationsAsynchronously) } [DebuggerDisplay("Items = {Count}")] - [DebuggerTypeProxy(typeof(DebugEnumeratorDebugView<>))] + [DebuggerTypeProxy(typeof(DebugEnumeratorDebugView<,>))] private sealed class UnboundedChannelReader : ChannelReader, IDebugEnumerable { - internal readonly UnboundedChannel _parent; + internal readonly UnboundedChannel _parent; private readonly AsyncOperation _readerSingleton; private readonly AsyncOperation _waiterSingleton; - internal UnboundedChannelReader(UnboundedChannel parent) + internal UnboundedChannelReader(UnboundedChannel parent) { _parent = parent; _readerSingleton = new AsyncOperation(parent._runContinuationsAsynchronously, pooled: true); @@ -68,8 +70,8 @@ public override ValueTask ReadAsync(CancellationToken cancellationToken) } // Dequeue an item if we can. - UnboundedChannel parent = _parent; - if (parent._items.TryDequeue(out T? item)) + UnboundedChannel parent = _parent; + if (parent._items.IsThreadSafe && parent._items.TryDequeue(out T? item)) { CompleteIfDone(parent); return new ValueTask(item); @@ -112,24 +114,60 @@ public override ValueTask ReadAsync(CancellationToken cancellationToken) public override bool TryRead([MaybeNullWhen(false)] out T item) { - UnboundedChannel parent = _parent; + UnboundedChannel parent = _parent; + return parent._items.IsThreadSafe ? + LockFree(parent, out item) : + Locked(parent, out item); - // Dequeue an item if we can - if (parent._items.TryDequeue(out item)) + static bool LockFree(UnboundedChannel parent, [MaybeNullWhen(false)] out T item) { - CompleteIfDone(parent); - return true; + if (parent._items.TryDequeue(out item)) + { + CompleteIfDone(parent); + return true; + } + + item = default; + return false; } - item = default; - return false; + static bool Locked(UnboundedChannel parent, [MaybeNullWhen(false)] out T item) + { + lock (parent.SyncObj) + { + if (parent._items.TryDequeue(out item)) + { + CompleteIfDone(parent); + return true; + } + } + + item = default; + return false; + } } - public override bool TryPeek([MaybeNullWhen(false)] out T item) => - _parent._items.TryPeek(out item); + public override bool TryPeek([MaybeNullWhen(false)] out T item) + { + UnboundedChannel parent = _parent; + return parent._items.IsThreadSafe ? + parent._items.TryPeek(out item) : + Locked(parent, out item); + + // Separated out to keep the try/finally from preventing TryPeek from being inlined + static bool Locked(UnboundedChannel parent, [MaybeNullWhen(false)] out T item) + { + lock (parent.SyncObj) + { + return parent._items.TryPeek(out item); + } + } + } - private static void CompleteIfDone(UnboundedChannel parent) + private static void CompleteIfDone(UnboundedChannel parent) { + Debug.Assert(parent._items.IsThreadSafe || Monitor.IsEntered(parent.SyncObj)); + if (parent._doneWriting != null && parent._items.IsEmpty) { // If we've now emptied the items queue and we're not getting any more, complete. @@ -144,12 +182,12 @@ public override ValueTask WaitToReadAsync(CancellationToken cancellationTo return new ValueTask(Task.FromCanceled(cancellationToken)); } - if (!_parent._items.IsEmpty) + if (_parent._items.IsThreadSafe && !_parent._items.IsEmpty) { return new ValueTask(true); } - UnboundedChannel parent = _parent; + UnboundedChannel parent = _parent; lock (parent.SyncObj) { @@ -192,15 +230,15 @@ public override ValueTask WaitToReadAsync(CancellationToken cancellationTo } [DebuggerDisplay("Items = {ItemsCountForDebugger}")] - [DebuggerTypeProxy(typeof(DebugEnumeratorDebugView<>))] + [DebuggerTypeProxy(typeof(DebugEnumeratorDebugView<,>))] private sealed class UnboundedChannelWriter : ChannelWriter, IDebugEnumerable { - internal readonly UnboundedChannel _parent; - internal UnboundedChannelWriter(UnboundedChannel parent) => _parent = parent; + internal readonly UnboundedChannel _parent; + internal UnboundedChannelWriter(UnboundedChannel parent) => _parent = parent; public override bool TryComplete(Exception? error) { - UnboundedChannel parent = _parent; + UnboundedChannel parent = _parent; bool completeTask; lock (parent.SyncObj) @@ -240,7 +278,7 @@ public override bool TryComplete(Exception? error) public override bool TryWrite(T item) { - UnboundedChannel parent = _parent; + UnboundedChannel parent = _parent; while (true) { AsyncOperation? blockedReader = null; @@ -321,7 +359,7 @@ public override ValueTask WriteAsync(T item, CancellationToken cancellationToken } /// Gets the object used to synchronize access to all state on this instance. - private object SyncObj => _items; + private object SyncObj => _blockedReaders; [Conditional("DEBUG")] private void AssertInvariants() diff --git a/src/libraries/System.Threading.Channels/src/System/Threading/Channels/UnboundedPriorityChannel.cs b/src/libraries/System.Threading.Channels/src/System/Threading/Channels/UnboundedPriorityChannel.cs deleted file mode 100644 index 7af18b9413ee29..00000000000000 --- a/src/libraries/System.Threading.Channels/src/System/Threading/Channels/UnboundedPriorityChannel.cs +++ /dev/null @@ -1,369 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System.Collections.Generic; -using System.Diagnostics; -using System.Diagnostics.CodeAnalysis; -using System.Threading.Tasks; - -// This file is primarily a copy of UnboundedChannel, subsequently tweaked to account for differences -// between ConcurrentQueue and PriorityQueue, e.g. that PQ isn't thread safe and so fast -// paths outside of locks need to be removed, that Enqueue/Dequeue methods take priorities, etc. Any -// changes made to this or that file should largely be kept in sync. - -namespace System.Threading.Channels -{ - /// Provides a buffered channel of unbounded capacity. - [DebuggerDisplay("Items = {ItemsCountForDebugger}, Closed = {ChannelIsClosedForDebugger}")] - [DebuggerTypeProxy(typeof(DebugEnumeratorDebugView<>))] - internal sealed class UnboundedPrioritizedChannel : Channel, IDebugEnumerable - { - /// Task that indicates the channel has completed. - private readonly TaskCompletionSource _completion; - /// The items in the channel. - /// To avoid double storing of a potentially large struct T, the priority doubles as the element and the element is ignored. - private readonly PriorityQueue _items; - /// Readers blocked reading from the channel. - private readonly Deque> _blockedReaders = new Deque>(); - /// Whether to force continuations to be executed asynchronously from producer writes. - private readonly bool _runContinuationsAsynchronously; - - /// Readers waiting for a notification that data is available. - private AsyncOperation? _waitingReadersTail; - /// Set to non-null once Complete has been called. - private Exception? _doneWriting; - - /// Initialize the channel. - internal UnboundedPrioritizedChannel(bool runContinuationsAsynchronously, IComparer? comparer) - { - _runContinuationsAsynchronously = runContinuationsAsynchronously; - _completion = new TaskCompletionSource(runContinuationsAsynchronously ? TaskCreationOptions.RunContinuationsAsynchronously : TaskCreationOptions.None); - Reader = new UnboundedPrioritizedChannelReader(this); - Writer = new UnboundedPrioritizedChannelWriter(this); - _items = new PriorityQueue(comparer); - } - - [DebuggerDisplay("Items = {Count}")] - [DebuggerTypeProxy(typeof(DebugEnumeratorDebugView<>))] - private sealed class UnboundedPrioritizedChannelReader : ChannelReader, IDebugEnumerable - { - internal readonly UnboundedPrioritizedChannel _parent; - private readonly AsyncOperation _readerSingleton; - private readonly AsyncOperation _waiterSingleton; - - internal UnboundedPrioritizedChannelReader(UnboundedPrioritizedChannel parent) - { - _parent = parent; - _readerSingleton = new AsyncOperation(parent._runContinuationsAsynchronously, pooled: true); - _waiterSingleton = new AsyncOperation(parent._runContinuationsAsynchronously, pooled: true); - } - - public override Task Completion => _parent._completion.Task; - - public override bool CanCount => true; - - public override bool CanPeek => true; - - public override int Count => _parent._items.Count; - - public override ValueTask ReadAsync(CancellationToken cancellationToken) - { - if (cancellationToken.IsCancellationRequested) - { - return ValueTask.FromCanceled(cancellationToken); - } - - // Dequeue an item if we can. - UnboundedPrioritizedChannel parent = _parent; - lock (parent.SyncObj) - { - parent.AssertInvariants(); - - // Try to dequeue again, now that we hold the lock. - if (parent._items.TryDequeue(out _, out T? item)) - { - CompleteIfDone(parent); - return new ValueTask(item); - } - - // There are no items, so if we're done writing, fail. - if (parent._doneWriting != null) - { - return ChannelUtilities.GetInvalidCompletionValueTask(parent._doneWriting); - } - - // If we're able to use the singleton reader, do so. - if (!cancellationToken.CanBeCanceled) - { - AsyncOperation singleton = _readerSingleton; - if (singleton.TryOwnAndReset()) - { - parent._blockedReaders.EnqueueTail(singleton); - return singleton.ValueTaskOfT; - } - } - - // Otherwise, create and queue a reader. - var reader = new AsyncOperation(parent._runContinuationsAsynchronously, cancellationToken); - parent._blockedReaders.EnqueueTail(reader); - return reader.ValueTaskOfT; - } - } - - public override bool TryRead([MaybeNullWhen(false)] out T item) - { - UnboundedPrioritizedChannel parent = _parent; - lock (parent.SyncObj) - { - // Dequeue an item if we can - if (parent._items.TryDequeue(out _, out item)) - { - CompleteIfDone(parent); - return true; - } - - item = default; - return false; - } - } - - public override bool TryPeek([MaybeNullWhen(false)] out T item) => - _parent._items.TryPeek(out _, out item); - - private static void CompleteIfDone(UnboundedPrioritizedChannel parent) - { - Debug.Assert(Monitor.IsEntered(parent.SyncObj)); - - if (parent._doneWriting != null && parent._items.Count == 0) - { - // If we've now emptied the items queue and we're not getting any more, complete. - ChannelUtilities.Complete(parent._completion, parent._doneWriting); - } - } - - public override ValueTask WaitToReadAsync(CancellationToken cancellationToken) - { - if (cancellationToken.IsCancellationRequested) - { - return ValueTask.FromCanceled(cancellationToken); - } - - UnboundedPrioritizedChannel parent = _parent; - lock (parent.SyncObj) - { - parent.AssertInvariants(); - - // Try again to read now that we're synchronized with writers. - if (parent._items.Count != 0) - { - return new ValueTask(true); - } - - // There are no items, so if we're done writing, there's never going to be data available. - if (parent._doneWriting != null) - { - return parent._doneWriting != ChannelUtilities.s_doneWritingSentinel ? - ValueTask.FromException(parent._doneWriting) : - default; - } - - // If we're able to use the singleton waiter, do so. - if (!cancellationToken.CanBeCanceled) - { - AsyncOperation singleton = _waiterSingleton; - if (singleton.TryOwnAndReset()) - { - ChannelUtilities.QueueWaiter(ref parent._waitingReadersTail, singleton); - return singleton.ValueTaskOfT; - } - } - - // Otherwise, create and queue a waiter. - var waiter = new AsyncOperation(parent._runContinuationsAsynchronously, cancellationToken); - ChannelUtilities.QueueWaiter(ref parent._waitingReadersTail, waiter); - return waiter.ValueTaskOfT; - } - } - - /// Gets an enumerator the debugger can use to show the contents of the channel. - IEnumerator IDebugEnumerable.GetEnumerator() => _parent.GetEnumerator(); - } - - [DebuggerDisplay("Items = {ItemsCountForDebugger}")] - [DebuggerTypeProxy(typeof(DebugEnumeratorDebugView<>))] - private sealed class UnboundedPrioritizedChannelWriter : ChannelWriter, IDebugEnumerable - { - internal readonly UnboundedPrioritizedChannel _parent; - internal UnboundedPrioritizedChannelWriter(UnboundedPrioritizedChannel parent) => _parent = parent; - - public override bool TryComplete(Exception? error) - { - UnboundedPrioritizedChannel parent = _parent; - bool completeTask; - - lock (parent.SyncObj) - { - parent.AssertInvariants(); - - // If we've already marked the channel as completed, bail. - if (parent._doneWriting != null) - { - return false; - } - - // Mark that we're done writing. - parent._doneWriting = error ?? ChannelUtilities.s_doneWritingSentinel; - completeTask = parent._items.Count == 0; - } - - // If there are no items in the queue, complete the channel's task, - // as no more data can possibly arrive at this point. We do this outside - // of the lock in case we'll be running synchronous completions, and we - // do it before completing blocked/waiting readers, so that when they - // wake up they'll see the task as being completed. - if (completeTask) - { - ChannelUtilities.Complete(parent._completion, error); - } - - // At this point, _blockedReaders and _waitingReaders will not be mutated: - // they're only mutated by readers while holding the lock, and only if _doneWriting is null. - // freely manipulate _blockedReaders and _waitingReaders without any concurrency concerns. - ChannelUtilities.FailOperations, T>(parent._blockedReaders, ChannelUtilities.CreateInvalidCompletionException(error)); - ChannelUtilities.WakeUpWaiters(ref parent._waitingReadersTail, result: false, error: error); - - // Successfully transitioned to completed. - return true; - } - - public override bool TryWrite(T item) - { - UnboundedPrioritizedChannel parent = _parent; - while (true) - { - AsyncOperation? blockedReader = null; - AsyncOperation? waitingReadersTail = null; - lock (parent.SyncObj) - { - // If writing has already been marked as done, fail the write. - parent.AssertInvariants(); - if (parent._doneWriting != null) - { - return false; - } - - // If there aren't any blocked readers, just add the data to the queue, - // and let any waiting readers know that they should try to read it. - // We can only complete such waiters here under the lock if they run - // continuations asynchronously (otherwise the synchronous continuations - // could be invoked under the lock). If we don't complete them here, we - // need to do so outside of the lock. - if (parent._blockedReaders.IsEmpty) - { - parent._items.Enqueue(true, item); - waitingReadersTail = parent._waitingReadersTail; - if (waitingReadersTail == null) - { - return true; - } - parent._waitingReadersTail = null; - } - else - { - // There were blocked readers. Grab one, and then complete it outside of the lock. - blockedReader = parent._blockedReaders.DequeueHead(); - } - } - - if (blockedReader != null) - { - // Complete the reader. It's possible the reader was canceled, in which - // case we loop around to try everything again. - if (blockedReader.TrySetResult(item)) - { - return true; - } - } - else - { - // Wake up all of the waiters. Since we've released the lock, it's possible - // we could cause some spurious wake-ups here, if we tell a waiter there's - // something available but all data has already been removed. It's a benign - // race condition, though, as consumers already need to account for such things. - ChannelUtilities.WakeUpWaiters(ref waitingReadersTail, result: true); - return true; - } - } - } - - public override ValueTask WaitToWriteAsync(CancellationToken cancellationToken) - { - Exception? doneWriting = _parent._doneWriting; - return - cancellationToken.IsCancellationRequested ? ValueTask.FromCanceled(cancellationToken) : - doneWriting == null ? new ValueTask(true) : // unbounded writing can always be done if we haven't completed - doneWriting != ChannelUtilities.s_doneWritingSentinel ? ValueTask.FromException(doneWriting) : - default; - } - - public override ValueTask WriteAsync(T item, CancellationToken cancellationToken) => - cancellationToken.IsCancellationRequested ? ValueTask.FromCanceled(cancellationToken) : - TryWrite(item) ? default : - ValueTask.FromException(ChannelUtilities.CreateInvalidCompletionException(_parent._doneWriting)); - - /// Gets the number of items in the channel. This should only be used by the debugger. - private int ItemsCountForDebugger => _parent._items.Count; - - /// Gets an enumerator the debugger can use to show the contents of the channel. - IEnumerator IDebugEnumerable.GetEnumerator() => _parent.GetEnumerator(); - } - - /// Gets the object used to synchronize access to all state on this instance. - private object SyncObj => _items; - - [Conditional("DEBUG")] - private void AssertInvariants() - { - Debug.Assert(SyncObj != null, "The sync obj must not be null."); - Debug.Assert(Monitor.IsEntered(SyncObj), "Invariants can only be validated while holding the lock."); - - if (_items.Count != 0) - { - if (_runContinuationsAsynchronously) - { - Debug.Assert(_blockedReaders.IsEmpty, "There's data available, so there shouldn't be any blocked readers."); - Debug.Assert(_waitingReadersTail == null, "There's data available, so there shouldn't be any waiting readers."); - } - Debug.Assert(!_completion.Task.IsCompleted, "We still have data available, so shouldn't be completed."); - } - if ((!_blockedReaders.IsEmpty || _waitingReadersTail != null) && _runContinuationsAsynchronously) - { - Debug.Assert(_items.Count == 0, "There are blocked/waiting readers, so there shouldn't be any data available."); - } - if (_completion.Task.IsCompleted) - { - Debug.Assert(_doneWriting != null, "We're completed, so we must be done writing."); - } - } - - /// Gets the number of items in the channel. This should only be used by the debugger. - private int ItemsCountForDebugger => _items.Count; - - /// Report if the channel is closed or not. This should only be used by the debugger. - private bool ChannelIsClosedForDebugger => _doneWriting != null; - - /// Gets an enumerator the debugger can use to show the contents of the channel. - public IEnumerator GetEnumerator() - { - List list = []; - foreach ((bool _, T Priority) item in _items.UnorderedItems) - { - list.Add(item.Priority); - } - - list.Sort(_items.Comparer); - - return list.GetEnumerator(); - } - } -} From 0a220d534b30495ff332b3bd65a04889e66b44f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20K=C3=B6plinger?= Date: Tue, 23 Apr 2024 15:23:13 +0200 Subject: [PATCH 026/161] Bump minimum Apple OS versions (#101342) As defined in the ".NET 9 - Supported OS versions" document: https://github.com/dotnet/core/blob/main/release-notes/9.0/supported-os.md - macOS 12.0 - iOS/iOSSimulator 12.2 - tvOS/tvOSSimulator 12.2 - MacCatalyst 15.0 (== macOS 12.0) Fixes https://github.com/dotnet/runtime/issues/91736 --- Directory.Build.props | 14 ++++++++----- eng/native/build-commons.sh | 8 ++++---- eng/native/configurecompiler.cmake | 20 ++++++++++++------- .../Microsoft.NETCore.Native.Unix.targets | 7 +++---- .../Compiler/ObjectWriter/MachObjectWriter.cs | 10 +++------- ...-framework-distribution-template-arm64.xml | 2 +- ...ed-framework-distribution-template-x64.xml | 2 +- .../NativeExports/NativeExports.csproj | 8 ++++---- .../Security/Cryptography/AesGcm.macOS.cs | 2 +- .../Cryptography/ChaCha20Poly1305.macOS.cs | 2 +- .../tests/ChaCha20Poly1305Tests.cs | 2 +- src/mono/mono.proj | 8 ++++---- .../mono/tools/offsets-tool/offsets-tool.py | 4 ++-- .../msbuild/apple/build/AppleBuild.targets | 4 ++-- .../pal_signverify.c | 9 +++++++++ .../pal_ssl.c | 4 ++++ .../pal_x509.c | 11 +--------- .../pal_x509chain.c | 3 +++ src/native/libs/build-native.sh | 8 ++++---- .../AotCompilerTask/MonoAOTCompiler.props | 4 ++-- src/tasks/AppleAppBuilder/Xcode.cs | 19 +++++++++++++----- .../MobileBuildTasks/Apple/AppleProject.cs | 2 +- 22 files changed, 87 insertions(+), 66 deletions(-) diff --git a/Directory.Build.props b/Directory.Build.props index ef0e8c1b44d76d..40c75f103b8be8 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -56,18 +56,22 @@ - eng/native/configurecompiler.cmake - eng/native/build-commons.sh - src/native/libs/build-native.sh - - src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/ObjectWriter.cs + - src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/ObjectWriter/MachObjectWriter.cs - src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.Unix.targets + - src/mono/mono/tools/offsets-tool/offsets-tool.py + - src/mono/msbuild/apple/build/AppleBuild.targets - src/installer/pkg/sfx/bundle/shared-framework-distribution-template-x64.xml - src/installer/pkg/sfx/bundle/shared-framework-distribution-template-arm64.xml + - src/tasks/AotCompilerTask/MonoAOTCompiler.props + - src/tasks/AppleAppBuilder/Xcode.cs - src/tasks/MobileBuildTasks/Apple/AppleProject.cs - dotnet/installer repo > src/redist/targets/GeneratePKG.targets --> 21 - 11.0 - 11.0 - 10.15 - 11.0 + 12.2 + 12.2 + 12.0 + 15.0 diff --git a/eng/native/build-commons.sh b/eng/native/build-commons.sh index 0916abb396fa46..2cf33442a93253 100755 --- a/eng/native/build-commons.sh +++ b/eng/native/build-commons.sh @@ -109,7 +109,7 @@ build_native() # set default iOS simulator deployment target # keep in sync with SetOSTargetMinVersions in the root Directory.Build.props - cmakeArgs="-DCMAKE_SYSTEM_NAME=iOS -DCMAKE_OSX_SYSROOT=iphonesimulator -DCMAKE_OSX_DEPLOYMENT_TARGET=11.0 $cmakeArgs" + cmakeArgs="-DCMAKE_SYSTEM_NAME=iOS -DCMAKE_OSX_SYSROOT=iphonesimulator -DCMAKE_OSX_DEPLOYMENT_TARGET=12.2 $cmakeArgs" if [[ "$__TargetArch" == x64 ]]; then cmakeArgs="-DCMAKE_OSX_ARCHITECTURES=\"x86_64\" $cmakeArgs" elif [[ "$__TargetArch" == arm64 ]]; then @@ -123,7 +123,7 @@ build_native() # set default iOS device deployment target # keep in sync with SetOSTargetMinVersions in the root Directory.Build.props - cmakeArgs="-DCMAKE_SYSTEM_NAME=iOS -DCMAKE_OSX_SYSROOT=iphoneos -DCMAKE_OSX_DEPLOYMENT_TARGET=11.0 $cmakeArgs" + cmakeArgs="-DCMAKE_SYSTEM_NAME=iOS -DCMAKE_OSX_SYSROOT=iphoneos -DCMAKE_OSX_DEPLOYMENT_TARGET=12.2 $cmakeArgs" if [[ "$__TargetArch" == arm64 ]]; then cmakeArgs="-DCMAKE_OSX_ARCHITECTURES=\"arm64\" $cmakeArgs" else @@ -135,7 +135,7 @@ build_native() # set default tvOS simulator deployment target # keep in sync with SetOSTargetMinVersions in the root Directory.Build.props - cmakeArgs="-DCMAKE_SYSTEM_NAME=tvOS -DCMAKE_OSX_SYSROOT=appletvsimulator -DCMAKE_OSX_DEPLOYMENT_TARGET=11.0 $cmakeArgs" + cmakeArgs="-DCMAKE_SYSTEM_NAME=tvOS -DCMAKE_OSX_SYSROOT=appletvsimulator -DCMAKE_OSX_DEPLOYMENT_TARGET=12.2 $cmakeArgs" if [[ "$__TargetArch" == x64 ]]; then cmakeArgs="-DCMAKE_OSX_ARCHITECTURES=\"x86_64\" $cmakeArgs" elif [[ "$__TargetArch" == arm64 ]]; then @@ -149,7 +149,7 @@ build_native() # set default tvOS device deployment target # keep in sync with SetOSTargetMinVersions in the root Directory.Build.props - cmakeArgs="-DCMAKE_SYSTEM_NAME=tvOS -DCMAKE_OSX_SYSROOT=appletvos -DCMAKE_OSX_DEPLOYMENT_TARGET=11.0 $cmakeArgs" + cmakeArgs="-DCMAKE_SYSTEM_NAME=tvOS -DCMAKE_OSX_SYSROOT=appletvos -DCMAKE_OSX_DEPLOYMENT_TARGET=12.2 $cmakeArgs" if [[ "$__TargetArch" == arm64 ]]; then cmakeArgs="-DCMAKE_OSX_ARCHITECTURES=\"arm64\" $cmakeArgs" else diff --git a/eng/native/configurecompiler.cmake b/eng/native/configurecompiler.cmake index bdf370fdf966b6..4675a8b07cb6b4 100644 --- a/eng/native/configurecompiler.cmake +++ b/eng/native/configurecompiler.cmake @@ -14,6 +14,7 @@ set(CMAKE_CXX_STANDARD_REQUIRED ON) include(CheckCCompilerFlag) include(CheckCXXCompilerFlag) +include(CheckLinkerFlag) # "configureoptimization.cmake" must be included after CLR_CMAKE_HOST_UNIX has been set. include(${CMAKE_CURRENT_LIST_DIR}/configureoptimization.cmake) @@ -300,7 +301,13 @@ elseif(CLR_CMAKE_HOST_SUNOS) add_definitions(-D__EXTENSIONS__ -D_XPG4_2 -D_POSIX_PTHREAD_SEMANTICS) elseif(CLR_CMAKE_HOST_OSX AND NOT CLR_CMAKE_HOST_MACCATALYST AND NOT CLR_CMAKE_HOST_IOS AND NOT CLR_CMAKE_HOST_TVOS) add_definitions(-D_XOPEN_SOURCE) - add_linker_flag("-Wl,-bind_at_load") + + # the new linker in Xcode 15 (ld_new/ld_prime) deprecated the -bind_at_load flag for macOS which causes a warning + # that fails the build since we build with -Werror. Only pass the flag if we need it, i.e. older linkers. + check_linker_flag(C "-Wl,-bind_at_load,-fatal_warnings" LINKER_SUPPORTS_BIND_AT_LOAD_FLAG) + if(LINKER_SUPPORTS_BIND_AT_LOAD_FLAG) + add_linker_flag("-Wl,-bind_at_load") + endif() elseif(CLR_CMAKE_HOST_HAIKU) add_compile_options($<$:-Wa,--noexecstack>) add_linker_flag("-Wl,--no-undefined") @@ -662,11 +669,11 @@ if (CLR_CMAKE_HOST_UNIX) set(DISABLE_OVERRIDING_MIN_VERSION_ERROR -Wno-overriding-t-option) add_link_options(-Wno-overriding-t-option) if(CLR_CMAKE_HOST_ARCH_ARM64) - set(MACOS_VERSION_MIN_FLAGS "-target arm64-apple-ios14.2-macabi") - add_link_options(-target arm64-apple-ios14.2-macabi) + set(MACOS_VERSION_MIN_FLAGS "-target arm64-apple-ios15.0-macabi") + add_link_options(-target arm64-apple-ios15.0-macabi) elseif(CLR_CMAKE_HOST_ARCH_AMD64) - set(MACOS_VERSION_MIN_FLAGS "-target x86_64-apple-ios13.5-macabi") - add_link_options(-target x86_64-apple-ios13.5-macabi) + set(MACOS_VERSION_MIN_FLAGS "-target x86_64-apple-ios15.0-macabi") + add_link_options(-target x86_64-apple-ios15.0-macabi) else() clr_unknown_arch() endif() @@ -679,11 +686,10 @@ if (CLR_CMAKE_HOST_UNIX) set(CMAKE_OBJC_FLAGS "${CMAKE_OBJC_FLAGS} ${MACOS_VERSION_MIN_FLAGS} ${DISABLE_OVERRIDING_MIN_VERSION_ERROR}") set(CMAKE_OBJCXX_FLAGS "${CMAKE_OBJCXX_FLAGS} ${MACOS_VERSION_MIN_FLAGS} ${DISABLE_OVERRIDING_MIN_VERSION_ERROR}") elseif(CLR_CMAKE_HOST_OSX) + set(CMAKE_OSX_DEPLOYMENT_TARGET "12.0") if(CLR_CMAKE_HOST_ARCH_ARM64) - set(CMAKE_OSX_DEPLOYMENT_TARGET "11.0") add_compile_options(-arch arm64) elseif(CLR_CMAKE_HOST_ARCH_AMD64) - set(CMAKE_OSX_DEPLOYMENT_TARGET "10.15") add_compile_options(-arch x86_64) else() clr_unknown_arch() diff --git a/src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.Unix.targets b/src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.Unix.targets index c9314487b0507d..7441f7da0f6249 100644 --- a/src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.Unix.targets +++ b/src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.Unix.targets @@ -74,9 +74,8 @@ The .NET Foundation licenses this file to you under the MIT license. - 13.5 - 14.2 - 11.0 + 15.0 + 12.2 <_AppleSdkName Condition="'$(_targetOS)' == 'ios'">iphoneos <_AppleSdkName Condition="'$(_targetOS)' == 'iossimulator'">iphonesimulator @@ -96,7 +95,7 @@ The .NET Foundation licenses this file to you under the MIT license. - 11.0 + 12.0 x86_64-apple-macos$(AppleMinOSVersion) arm64-apple-macos$(AppleMinOSVersion) diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/ObjectWriter/MachObjectWriter.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/ObjectWriter/MachObjectWriter.cs index 86ac433262f990..e65f7c889dd19a 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/ObjectWriter/MachObjectWriter.cs +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/ObjectWriter/MachObjectWriter.cs @@ -244,16 +244,12 @@ private protected override void EmitObjectFile(string objectFilePath) { case TargetOS.OSX: buildVersion.Platform = PLATFORM_MACOS; - buildVersion.MinimumPlatformVersion = 0x0A_0C_00; // 10.12.0 + buildVersion.MinimumPlatformVersion = 0x0C_00_00; // 12.0.0 break; case TargetOS.MacCatalyst: buildVersion.Platform = PLATFORM_MACCATALYST; - buildVersion.MinimumPlatformVersion = _cpuType switch - { - CPU_TYPE_X86_64 => 0x0D_05_00u, // 13.5.0 - _ => 0x0E_02_00u, // 14.2.0 - }; + buildVersion.MinimumPlatformVersion = 0x0F_02_00; // 15.0.0 break; case TargetOS.iOS: @@ -268,7 +264,7 @@ private protected override void EmitObjectFile(string objectFilePath) TargetOS.tvOSSimulator => PLATFORM_TVOSSIMULATOR, _ => 0, }; - buildVersion.MinimumPlatformVersion = 0x0B_00_00; // 11.0.0 + buildVersion.MinimumPlatformVersion = 0x0C_02_00; // 12.2.0 break; } buildVersion.Write(outputFileStream); diff --git a/src/installer/pkg/sfx/bundle/shared-framework-distribution-template-arm64.xml b/src/installer/pkg/sfx/bundle/shared-framework-distribution-template-arm64.xml index 1b0dca06e4095d..2d501b30731695 100644 --- a/src/installer/pkg/sfx/bundle/shared-framework-distribution-template-arm64.xml +++ b/src/installer/pkg/sfx/bundle/shared-framework-distribution-template-arm64.xml @@ -7,7 +7,7 @@ - + diff --git a/src/installer/pkg/sfx/bundle/shared-framework-distribution-template-x64.xml b/src/installer/pkg/sfx/bundle/shared-framework-distribution-template-x64.xml index 419795e0f348fe..538f475d5d5836 100644 --- a/src/installer/pkg/sfx/bundle/shared-framework-distribution-template-x64.xml +++ b/src/installer/pkg/sfx/bundle/shared-framework-distribution-template-x64.xml @@ -7,7 +7,7 @@ - + diff --git a/src/libraries/System.Runtime.InteropServices/tests/TestAssets/NativeExports/NativeExports.csproj b/src/libraries/System.Runtime.InteropServices/tests/TestAssets/NativeExports/NativeExports.csproj index 3daf1f99fe8b06..ad5bd11ee41cc2 100644 --- a/src/libraries/System.Runtime.InteropServices/tests/TestAssets/NativeExports/NativeExports.csproj +++ b/src/libraries/System.Runtime.InteropServices/tests/TestAssets/NativeExports/NativeExports.csproj @@ -91,12 +91,12 @@ - arm64-apple-ios14.2-macabi - x86_64-apple-ios13.5-macabi + arm64-apple-ios$(MacCatalystVersionMin)-macabi + x86_64-apple-ios$(MacCatalystVersionMin)-macabi - arm64-apple-macos11 - x86_64-apple-macos10.15 + arm64-apple-macos$(macOSVersionMin) + x86_64-apple-macos$(macOSVersionMin) macosx diff --git a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/AesGcm.macOS.cs b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/AesGcm.macOS.cs index 3b528f496f4d91..d9f036f61ca5d7 100644 --- a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/AesGcm.macOS.cs +++ b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/AesGcm.macOS.cs @@ -11,7 +11,7 @@ public sealed partial class AesGcm { private FixedMemoryKeyBox _keyBox; - // CryptoKit added AES.GCM in macOS 10.15, which is our minimum target for macOS. + // CryptoKit added AES.GCM in macOS 10.15, which is lower than our minimum target for macOS. public static bool IsSupported => true; // CryptoKit only supports 16 byte tags. diff --git a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/ChaCha20Poly1305.macOS.cs b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/ChaCha20Poly1305.macOS.cs index aa2cba5f234ba7..7e45061f971a6e 100644 --- a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/ChaCha20Poly1305.macOS.cs +++ b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/ChaCha20Poly1305.macOS.cs @@ -8,7 +8,7 @@ namespace System.Security.Cryptography { public sealed partial class ChaCha20Poly1305 { - // CryptoKit added ChaCha20Poly1305 in macOS 10.15, which is our minimum target for macOS. + // CryptoKit added ChaCha20Poly1305 in macOS 10.15, which is lower than our minimum target for macOS. public static bool IsSupported => true; private FixedMemoryKeyBox _keyBox; diff --git a/src/libraries/System.Security.Cryptography/tests/ChaCha20Poly1305Tests.cs b/src/libraries/System.Security.Cryptography/tests/ChaCha20Poly1305Tests.cs index ced6edcf350951..00ae5286b25a92 100644 --- a/src/libraries/System.Security.Cryptography/tests/ChaCha20Poly1305Tests.cs +++ b/src/libraries/System.Security.Cryptography/tests/ChaCha20Poly1305Tests.cs @@ -475,7 +475,7 @@ public static void CheckIsSupported() } else if (PlatformDetection.IsOSX) { - // CryptoKit is supported on macOS 10.15+, which is our minimum target. + // CryptoKit is supported on macOS 10.15+, which is lower than our minimum target. expectedIsSupported = true; } else if (PlatformDetection.OpenSslPresentOnSystem && PlatformDetection.IsOpenSslSupported) diff --git a/src/mono/mono.proj b/src/mono/mono.proj index 8b57badb1a2e38..47eeb0937a88fa 100644 --- a/src/mono/mono.proj +++ b/src/mono/mono.proj @@ -401,11 +401,11 @@ <_MonoCMakeArgs Include="-DCMAKE_SYSTEM_VARIANT=maccatalyst" /> <_MonoCPPFLAGS Include="-Wno-overriding-t-option" /> - <_MonoCFlags Condition="'$(TargetArchitecture)' == 'arm64'" Include="-target arm64-apple-ios14.2-macabi" /> - <_MonoCFlags Condition="'$(TargetArchitecture)' == 'x64'" Include="-target x86_64-apple-ios13.5-macabi" /> + <_MonoCFlags Condition="'$(TargetArchitecture)' == 'arm64'" Include="-target arm64-apple-ios$(MacCatalystVersionMin)-macabi" /> + <_MonoCFlags Condition="'$(TargetArchitecture)' == 'x64'" Include="-target x86_64-apple-ios$(MacCatalystVersionMin)-macabi" /> <_MonoCFLAGS Condition="'$(TargetArchitecture)' == 'arm64'" Include="-arch arm64" /> - <_MonoCXXFlags Condition="'$(TargetArchitecture)' == 'arm64'" Include="-target arm64-apple-ios14.2-macabi" /> - <_MonoCXXFlags Condition="'$(TargetArchitecture)' == 'x64'" Include="-target x86_64-apple-ios13.5-macabi" /> + <_MonoCXXFlags Condition="'$(TargetArchitecture)' == 'arm64'" Include="-target arm64-apple-ios$(MacCatalystVersionMin)-macabi" /> + <_MonoCXXFlags Condition="'$(TargetArchitecture)' == 'x64'" Include="-target x86_64-apple-ios$(MacCatalystVersionMin)-macabi" /> <_MonoCXXFLAGS Condition="'$(TargetArchitecture)' == 'arm64'" Include="-arch arm64" /> <_MonoBuildEnv Condition="'$(BuildArchitecture)' == 'arm64'" Include="arch -arch arm64" /> diff --git a/src/mono/mono/tools/offsets-tool/offsets-tool.py b/src/mono/mono/tools/offsets-tool/offsets-tool.py index ad450989afed50..058d27373d28dc 100644 --- a/src/mono/mono/tools/offsets-tool/offsets-tool.py +++ b/src/mono/mono/tools/offsets-tool/offsets-tool.py @@ -159,13 +159,13 @@ def require_emscipten_path (args): elif "x86_64-apple-maccatalyst" == args.abi: require_sysroot (args) self.target = Target ("TARGET_AMD64", "TARGET_MACCAT", IOS_DEFINES) - self.target_args += ["-target", "x86_64-apple-ios13.5-macabi"] + self.target_args += ["-target", "x86_64-apple-ios15.0-macabi"] self.target_args += ["-isysroot", args.sysroot] elif "aarch64-apple-maccatalyst" == args.abi: require_sysroot (args) self.target = Target ("TARGET_ARM64", "TARGET_MACCAT", IOS_DEFINES) - self.target_args += ["-target", "arm64-apple-ios14.2-macabi"] + self.target_args += ["-target", "arm64-apple-ios15.0-macabi"] self.target_args += ["-isysroot", args.sysroot] # watchOS diff --git a/src/mono/msbuild/apple/build/AppleBuild.targets b/src/mono/msbuild/apple/build/AppleBuild.targets index 914351a5cee4da..35d0f16c35b4b8 100644 --- a/src/mono/msbuild/apple/build/AppleBuild.targets +++ b/src/mono/msbuild/apple/build/AppleBuild.targets @@ -159,9 +159,9 @@ - + - + diff --git a/src/native/libs/System.Security.Cryptography.Native.Apple/pal_signverify.c b/src/native/libs/System.Security.Cryptography.Native.Apple/pal_signverify.c index 6e7c77e9d7d070..37f61c7b1215ad 100644 --- a/src/native/libs/System.Security.Cryptography.Native.Apple/pal_signverify.c +++ b/src/native/libs/System.Security.Cryptography.Native.Apple/pal_signverify.c @@ -16,7 +16,10 @@ static int32_t ExecuteSignTransform(SecTransformRef signer, CFDataRef* pSignatur assert(pErrorOut != NULL); int32_t ret = INT_MIN; +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" CFTypeRef signerResponse = SecTransformExecute(signer, pErrorOut); +#pragma clang diagnostic pop CFDataRef signature = NULL; if (signerResponse == NULL || *pErrorOut != NULL) @@ -62,7 +65,10 @@ static int32_t ExecuteVerifyTransform(SecTransformRef verifier, CFErrorRef* pErr assert(pErrorOut != NULL); int32_t ret = kErrorSeeError; +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" CFTypeRef verifierResponse = SecTransformExecute(verifier, pErrorOut); +#pragma clang diagnostic pop if (verifierResponse != NULL) { @@ -79,6 +85,8 @@ static int32_t ExecuteVerifyTransform(SecTransformRef verifier, CFErrorRef* pErr static int32_t ConfigureSignVerifyTransform(SecTransformRef xform, CFDataRef cfDataHash, CFErrorRef* pErrorOut) { +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" if (!SecTransformSetAttribute(xform, kSecInputIsAttributeName, kSecInputIsDigest, pErrorOut)) { return 0; @@ -88,6 +96,7 @@ static int32_t ConfigureSignVerifyTransform(SecTransformRef xform, CFDataRef cfD { return 0; } +#pragma clang diagnostic pop return 1; } diff --git a/src/native/libs/System.Security.Cryptography.Native.Apple/pal_ssl.c b/src/native/libs/System.Security.Cryptography.Native.Apple/pal_ssl.c index d37f08ed14e2ec..9b44cbbef8e093 100644 --- a/src/native/libs/System.Security.Cryptography.Native.Apple/pal_ssl.c +++ b/src/native/libs/System.Security.Cryptography.Native.Apple/pal_ssl.c @@ -463,7 +463,11 @@ int32_t AppleCryptoNative_SslIsHostnameMatch(SSLContextRef sslContext, CFStringR for (CFIndex i = 0; i < certificateCount; i++) { +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" SecCertificateRef item = SecTrustGetCertificateAtIndex(existingTrust, i); +#pragma clang diagnostic pop + CFArrayAppendValue(certs, item); // Copy the EE cert into the anchors set, this will make the chain part diff --git a/src/native/libs/System.Security.Cryptography.Native.Apple/pal_x509.c b/src/native/libs/System.Security.Cryptography.Native.Apple/pal_x509.c index 94e22f28c8794a..39b8e4619912b3 100644 --- a/src/native/libs/System.Security.Cryptography.Native.Apple/pal_x509.c +++ b/src/native/libs/System.Security.Cryptography.Native.Apple/pal_x509.c @@ -43,16 +43,7 @@ AppleCryptoNative_X509GetPublicKey(SecCertificateRef cert, SecKeyRef* pPublicKey if (cert == NULL || pPublicKeyOut == NULL) return kErrorUnknownState; - if (__builtin_available(macOS 10.14, iOS 12, tvOS 12, *)) - { - *pPublicKeyOut = SecCertificateCopyKey(cert); - } -#if defined(TARGET_IOS) || defined(TARGET_TVOS) - else - { - *pPublicKeyOut = SecCertificateCopyPublicKey(cert); - } -#endif + *pPublicKeyOut = SecCertificateCopyKey(cert); return 1; } diff --git a/src/native/libs/System.Security.Cryptography.Native.Apple/pal_x509chain.c b/src/native/libs/System.Security.Cryptography.Native.Apple/pal_x509chain.c index 152ed890ed6eda..de1a84f26798d4 100644 --- a/src/native/libs/System.Security.Cryptography.Native.Apple/pal_x509chain.c +++ b/src/native/libs/System.Security.Cryptography.Native.Apple/pal_x509chain.c @@ -92,7 +92,10 @@ SecCertificateRef AppleCryptoNative_X509ChainGetCertificateAtIndex(SecTrustRef c if (chain == NULL || index < 0) return NULL; +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" return SecTrustGetCertificateAtIndex(chain, index); +#pragma clang diagnostic pop } CFArrayRef AppleCryptoNative_X509ChainGetTrustResults(SecTrustRef chain) diff --git a/src/native/libs/build-native.sh b/src/native/libs/build-native.sh index 3e90b3805aaec9..d3fefa7685a974 100755 --- a/src/native/libs/build-native.sh +++ b/src/native/libs/build-native.sh @@ -105,7 +105,7 @@ elif [[ "$__TargetOS" == linux-bionic && -z "$ROOTFS_DIR" ]]; then elif [[ "$__TargetOS" == iossimulator ]]; then # set default iOS simulator deployment target # keep in sync with SetOSTargetMinVersions in the root Directory.Build.props - __CMakeArgs="-DCMAKE_SYSTEM_NAME=iOS -DCMAKE_OSX_SYSROOT=iphonesimulator -DCMAKE_OSX_DEPLOYMENT_TARGET=11.0 $__CMakeArgs" + __CMakeArgs="-DCMAKE_SYSTEM_NAME=iOS -DCMAKE_OSX_SYSROOT=iphonesimulator -DCMAKE_OSX_DEPLOYMENT_TARGET=12.2 $__CMakeArgs" if [[ "$__TargetArch" == x64 ]]; then __CMakeArgs="-DCMAKE_OSX_ARCHITECTURES=\"x86_64\" $__CMakeArgs" elif [[ "$__TargetArch" == x86 ]]; then @@ -119,7 +119,7 @@ elif [[ "$__TargetOS" == iossimulator ]]; then elif [[ "$__TargetOS" == ios ]]; then # set default iOS device deployment target # keep in sync with SetOSTargetMinVersions in the root Directory.Build.props - __CMakeArgs="-DCMAKE_SYSTEM_NAME=iOS -DCMAKE_OSX_SYSROOT=iphoneos -DCMAKE_OSX_DEPLOYMENT_TARGET=11.0 $__CMakeArgs" + __CMakeArgs="-DCMAKE_SYSTEM_NAME=iOS -DCMAKE_OSX_SYSROOT=iphoneos -DCMAKE_OSX_DEPLOYMENT_TARGET=12.2 $__CMakeArgs" if [[ "$__TargetArch" == arm64 ]]; then __CMakeArgs="-DCMAKE_OSX_ARCHITECTURES=\"arm64\" $__CMakeArgs" elif [[ "$__TargetArch" == arm ]]; then @@ -131,7 +131,7 @@ elif [[ "$__TargetOS" == ios ]]; then elif [[ "$__TargetOS" == tvossimulator ]]; then # set default tvOS simulator deployment target # keep in sync with SetOSTargetMinVersions in the root Directory.Build.props - __CMakeArgs="-DCMAKE_SYSTEM_NAME=tvOS -DCMAKE_OSX_SYSROOT=appletvsimulator -DCMAKE_OSX_DEPLOYMENT_TARGET=11.0 $__CMakeArgs" + __CMakeArgs="-DCMAKE_SYSTEM_NAME=tvOS -DCMAKE_OSX_SYSROOT=appletvsimulator -DCMAKE_OSX_DEPLOYMENT_TARGET=12.2 $__CMakeArgs" if [[ "$__TargetArch" == x64 ]]; then __CMakeArgs="-DCMAKE_OSX_ARCHITECTURES=\"x86_64\" $__CMakeArgs" elif [[ "$__TargetArch" == arm64 ]]; then @@ -143,7 +143,7 @@ elif [[ "$__TargetOS" == tvossimulator ]]; then elif [[ "$__TargetOS" == tvos ]]; then # set default tvOS device deployment target # keep in sync with the root Directory.Build.props - __CMakeArgs="-DCMAKE_SYSTEM_NAME=tvOS -DCMAKE_OSX_SYSROOT=appletvos -DCMAKE_OSX_DEPLOYMENT_TARGET=11.0 $__CMakeArgs" + __CMakeArgs="-DCMAKE_SYSTEM_NAME=tvOS -DCMAKE_OSX_SYSROOT=appletvos -DCMAKE_OSX_DEPLOYMENT_TARGET=12.2 $__CMakeArgs" if [[ "$__TargetArch" == arm64 ]]; then __CMakeArgs="-DCMAKE_OSX_ARCHITECTURES=\"arm64\" $__CMakeArgs" else diff --git a/src/tasks/AotCompilerTask/MonoAOTCompiler.props b/src/tasks/AotCompilerTask/MonoAOTCompiler.props index 1c7bc065d2a475..1fc8e8f41adf50 100644 --- a/src/tasks/AotCompilerTask/MonoAOTCompiler.props +++ b/src/tasks/AotCompilerTask/MonoAOTCompiler.props @@ -1,9 +1,9 @@ - + - + diff --git a/src/tasks/AppleAppBuilder/Xcode.cs b/src/tasks/AppleAppBuilder/Xcode.cs index a9bf648f8129a3..aed4bf7dfaeba3 100644 --- a/src/tasks/AppleAppBuilder/Xcode.cs +++ b/src/tasks/AppleAppBuilder/Xcode.cs @@ -218,15 +218,24 @@ public void CreateXcodeProject(string projectName, string cmakeDirectoryPath) targetName = Target.ToString(); break; } - var deployTarget = (Target == TargetNames.MacCatalyst) ? " -DCMAKE_OSX_ARCHITECTURES=" + XcodeArch : " -DCMAKE_OSX_DEPLOYMENT_TARGET=11.0"; var cmakeArgs = new StringBuilder(); cmakeArgs .Append("-S.") .Append(" -B").Append(projectName) .Append(" -GXcode") .Append(" -DTARGETS_APPLE_MOBILE=1") - .Append(" -DCMAKE_SYSTEM_NAME=").Append(targetName) - .Append(deployTarget); + .Append(" -DCMAKE_SYSTEM_NAME=").Append(targetName); + + if (Target == TargetNames.MacCatalyst) + { + // min deploy target version is passed later when invoking xcodebuild + cmakeArgs.Append(" -DCMAKE_OSX_ARCHITECTURES=" + XcodeArch); + } + else + { + // arch is passed later when invoking xcodebuild + cmakeArgs.Append(" -DCMAKE_OSX_DEPLOYMENT_TARGET=12.2"); + } Utils.RunProcess(Logger, "cmake", cmakeArgs.ToString(), workingDir: cmakeDirectoryPath); } @@ -608,7 +617,7 @@ public string BuildAppBundle( .Append(" -UseModernBuildSystem=YES") .Append(" -archivePath \"").Append(Path.GetDirectoryName(xcodePrjPath)).Append('"') .Append(" -derivedDataPath \"").Append(Path.GetDirectoryName(xcodePrjPath)).Append('"') - .Append(" IPHONEOS_DEPLOYMENT_TARGET=14.2"); + .Append(" IPHONEOS_DEPLOYMENT_TARGET=15.0"); break; } } @@ -633,7 +642,7 @@ public string BuildAppBundle( .Append(" -UseModernBuildSystem=YES") .Append(" -archivePath \"").Append(Path.GetDirectoryName(xcodePrjPath)).Append('"') .Append(" -derivedDataPath \"").Append(Path.GetDirectoryName(xcodePrjPath)).Append('"') - .Append(" IPHONEOS_DEPLOYMENT_TARGET=13.5"); + .Append(" IPHONEOS_DEPLOYMENT_TARGET=15.0"); break; } } diff --git a/src/tasks/MobileBuildTasks/Apple/AppleProject.cs b/src/tasks/MobileBuildTasks/Apple/AppleProject.cs index f7927fa2bb5a81..6a0f61c1968c41 100644 --- a/src/tasks/MobileBuildTasks/Apple/AppleProject.cs +++ b/src/tasks/MobileBuildTasks/Apple/AppleProject.cs @@ -27,7 +27,7 @@ public AppleProject(string projectName, string runtimeIdentifier, TaskLoggingHel { GetTargets(runtimeIdentifier, out targetOS, out targetArchitecture); - defaultMinOSVersion = (targetOS == "maccatalyst") ? "13.1" : "11.0"; + defaultMinOSVersion = (targetOS == "maccatalyst") ? "15.0" : "12.2"; targetAbi = DetermineAbi(targetArchitecture); AppleSdk sdk = new AppleSdk(targetOS, logger); From d3a4043c23c3c5b4406552558c885b34b88d295b Mon Sep 17 00:00:00 2001 From: Jo Shields Date: Tue, 23 Apr 2024 10:36:02 -0400 Subject: [PATCH 027/161] Switch s390x and PPC64 to Mariner host OS, not ancient Ubuntu (#101424) --- eng/pipelines/common/templates/pipeline-with-resources.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/eng/pipelines/common/templates/pipeline-with-resources.yml b/eng/pipelines/common/templates/pipeline-with-resources.yml index b9db26f6cb151c..e5e821f60fbc0e 100644 --- a/eng/pipelines/common/templates/pipeline-with-resources.yml +++ b/eng/pipelines/common/templates/pipeline-with-resources.yml @@ -77,12 +77,12 @@ extends: image: mcr.microsoft.com/dotnet-buildtools/prereqs:almalinux-8-source-build linux_s390x: - image: mcr.microsoft.com/dotnet-buildtools/prereqs:ubuntu-18.04-cross-s390x + image: mcr.microsoft.com/dotnet-buildtools/prereqs:cbl-mariner-2.0-cross-s390x env: ROOTFS_DIR: /crossrootfs/s390x linux_ppc64le: - image: mcr.microsoft.com/dotnet-buildtools/prereqs:ubuntu-18.04-cross-ppc64le + image: mcr.microsoft.com/dotnet-buildtools/prereqs:cbl-mariner-2.0-cross-ppc64le env: ROOTFS_DIR: /crossrootfs/ppc64le @@ -121,4 +121,4 @@ extends: image: mcr.microsoft.com/dotnet-buildtools/prereqs:ubuntu-22.04-debpkg rpmpkg: - image: mcr.microsoft.com/dotnet-buildtools/prereqs:cbl-mariner-2.0-fpm \ No newline at end of file + image: mcr.microsoft.com/dotnet-buildtools/prereqs:cbl-mariner-2.0-fpm From d688ac290cd73af89e2048f1a13bf5ef89287b35 Mon Sep 17 00:00:00 2001 From: Andy Ayers Date: Tue, 23 Apr 2024 07:43:45 -0700 Subject: [PATCH 028/161] JIT: metrics for profile consistency, gdv, devirt... (#101403) Add some metrics to early jit phases. Also add the ability to automatically merge inlinee counts to the root method, for successful inlines. --- src/coreclr/jit/fgbasic.cpp | 7 +++ src/coreclr/jit/fginline.cpp | 5 ++ src/coreclr/jit/fgprofilesynthesis.cpp | 3 ++ src/coreclr/jit/importer.cpp | 5 ++ src/coreclr/jit/importercalls.cpp | 5 ++ src/coreclr/jit/indirectcalltransformer.cpp | 12 ++++- src/coreclr/jit/jitmetadata.cpp | 14 ++++++ src/coreclr/jit/jitmetadata.h | 1 + src/coreclr/jit/jitmetadatalist.h | 55 ++++++++++++++------- 9 files changed, 87 insertions(+), 20 deletions(-) diff --git a/src/coreclr/jit/fgbasic.cpp b/src/coreclr/jit/fgbasic.cpp index fb717e1a5a50ea..af02d257d5dc29 100644 --- a/src/coreclr/jit/fgbasic.cpp +++ b/src/coreclr/jit/fgbasic.cpp @@ -235,6 +235,13 @@ bool Compiler::fgEnsureFirstBBisScratch() // JITDUMP("\fgEnsureFirstBBisScratch: Profile data could not be locally repaired. Data %s inconsisent.\n", fgPgoConsistent ? "is now" : "was already"); + + if (fgPgoConsistent) + { + Metrics.ProfileInconsistentScratchBB++; + fgPgoConsistent = false; + } + block->inheritWeight(fgFirstBB); } else diff --git a/src/coreclr/jit/fginline.cpp b/src/coreclr/jit/fginline.cpp index 6812dfbffdb7e9..8fcea689c6c993 100644 --- a/src/coreclr/jit/fginline.cpp +++ b/src/coreclr/jit/fginline.cpp @@ -1590,6 +1590,11 @@ void Compiler::fgInsertInlineeBlocks(InlineInfo* pInlineInfo) // Update no-return call count optNoReturnCallCount += InlineeCompiler->optNoReturnCallCount; +#ifdef DEBUG + // Update metrics + Metrics.mergeToRoot(InlineeCompiler); +#endif + // Update optMethodFlags #ifdef DEBUG diff --git a/src/coreclr/jit/fgprofilesynthesis.cpp b/src/coreclr/jit/fgprofilesynthesis.cpp index d7661e5b873fae..b9ff493c87d49f 100644 --- a/src/coreclr/jit/fgprofilesynthesis.cpp +++ b/src/coreclr/jit/fgprofilesynthesis.cpp @@ -146,9 +146,12 @@ void ProfileSynthesis::Run(ProfileSynthesisOption option) m_comp->fgPgoSynthesized = true; m_comp->fgPgoConsistent = !m_approximate; + m_comp->Metrics.ProfileSynthesizedBlendedOrRepaired++; + if (m_approximate) { JITDUMP("Profile is inconsistent. Bypassing post-phase consistency checks.\n"); + m_comp->Metrics.ProfileInconsistentInitially++; } #ifdef DEBUG diff --git a/src/coreclr/jit/importer.cpp b/src/coreclr/jit/importer.cpp index 62e215e7d65016..4998dbd6293fa9 100644 --- a/src/coreclr/jit/importer.cpp +++ b/src/coreclr/jit/importer.cpp @@ -5139,6 +5139,7 @@ void Compiler::impResetLeaveBlock(BasicBlock* block, unsigned jmpAddr) JITDUMP("\nimpResetLeaveBlock: Profile data could not be locally repaired. Data %s inconsisent.\n", fgPgoConsistent ? "is now" : "was already"); fgPgoConsistent = false; + Metrics.ProfileInconsistentResetLeave++; } } @@ -7319,6 +7320,7 @@ void Compiler::impImportBlockCode(BasicBlock* block) fgRemoveRefPred(removedEdge); block->SetKindAndTargetEdge(BBJ_ALWAYS, retainedEdge); + Metrics.ImporterBranchFold++; // If we removed an edge carrying profile, try to do a local repair. // @@ -7370,6 +7372,7 @@ void Compiler::impImportBlockCode(BasicBlock* block) JITDUMP("Profile data could not be locally repaired. Data %s inconsistent.\n", fgPgoConsistent ? "is now" : "was already"); fgPgoConsistent = false; + Metrics.ProfileInconsistentImporterBranchFold++; } } } @@ -7615,6 +7618,7 @@ void Compiler::impImportBlockCode(BasicBlock* block) unsigned jumpCnt = block->GetSwitchTargets()->bbsCount; FlowEdge** jumpTab = block->GetSwitchTargets()->bbsDstTab; bool foundVal = false; + Metrics.ImporterSwitchFold++; for (unsigned val = 0; val < jumpCnt; val++, jumpTab++) { @@ -7656,6 +7660,7 @@ void Compiler::impImportBlockCode(BasicBlock* block) JITDUMP("Profile data could not be locally repaired. Data %s inconsisent.\n", fgPgoConsistent ? "is now" : "was already"); fgPgoConsistent = false; + Metrics.ProfileInconsistentImporterSwitchFold++; } // Create a NOP node diff --git a/src/coreclr/jit/importercalls.cpp b/src/coreclr/jit/importercalls.cpp index 07681c75c0e95c..0ec0d6b9afd3e8 100644 --- a/src/coreclr/jit/importercalls.cpp +++ b/src/coreclr/jit/importercalls.cpp @@ -7760,6 +7760,7 @@ void Compiler::impDevirtualizeCall(GenTreeCall* call, // the resulting method would be a generic method of the non-generic SZArrayHelper class. // assert(canDevirtualize); + Metrics.DevirtualizedCall++; JITDUMP(" %s; can devirtualize\n", note); @@ -7988,6 +7989,8 @@ void Compiler::impDevirtualizeCall(GenTreeCall* call, // We may end up inlining this call, so the local copy must be marked as "aliased", // making sure the inlinee importer will know when to spill references to its value. lvaGetDesc(localCopyThis->AsLclFld())->lvHasLdAddrOp = true; + Metrics.DevirtualizedCallRemovedBox++; + Metrics.DevirtualizedCallUnboxedEntry++; #if FEATURE_TAILCALL_OPT if (call->IsImplicitTailCall()) @@ -8051,6 +8054,7 @@ void Compiler::impDevirtualizeCall(GenTreeCall* call, derivedMethodAttribs = unboxedMethodAttribs; call->gtArgs.InsertInstParam(this, methodTableArg); + Metrics.DevirtualizedCallUnboxedEntry++; } } else @@ -8066,6 +8070,7 @@ void Compiler::impDevirtualizeCall(GenTreeCall* call, INDEBUG(call->gtCallDebugFlags |= GTF_CALL_MD_UNBOXED); derivedMethod = unboxedEntryMethod; pDerivedResolvedToken = &dvInfo.resolvedTokenDevirtualizedUnboxedMethod; + Metrics.DevirtualizedCallUnboxedEntry++; } } } diff --git a/src/coreclr/jit/indirectcalltransformer.cpp b/src/coreclr/jit/indirectcalltransformer.cpp index b8a2b2162fd26f..3f0c311e84a614 100644 --- a/src/coreclr/jit/indirectcalltransformer.cpp +++ b/src/coreclr/jit/indirectcalltransformer.cpp @@ -509,6 +509,12 @@ class IndirectCallTransformer (GetChecksCount() == 1) && ((origCall->gtCallMoreFlags & GTF_CALL_M_GUARDED_DEVIRT_EXACT) == 0); if (canChainGdv) { + compiler->Metrics.GDV++; + if (GetChecksCount() > 1) + { + compiler->Metrics.MultiGuessGDV++; + } + const bool isChainedGdv = (origCall->gtCallMoreFlags & GTF_CALL_M_GUARDED_DEVIRT_CHAIN) != 0; if (isChainedGdv) @@ -520,6 +526,7 @@ class IndirectCallTransformer if (isChainedGdv) { + compiler->Metrics.ChainedGDV++; TransformForChainedGdv(); } @@ -691,6 +698,7 @@ class IndirectCallTransformer GenTree* targetMethodTable = compiler->gtNewIconEmbClsHndNode(clsHnd); compare = compiler->gtNewOperNode(GT_NE, TYP_INT, targetMethodTable, methodTable); + compiler->Metrics.ClassGDV++; } else { @@ -725,6 +733,7 @@ class IndirectCallTransformer GenTree* compareTarTree = CreateTreeForLookup(methHnd, lookup); compare = compiler->gtNewOperNode(GT_NE, TYP_INT, compareTarTree, tarTree); } + compiler->Metrics.MethodGDV++; } GenTree* jmpTree = compiler->gtNewOperNode(GT_JTRUE, TYP_VOID, compare); @@ -1240,10 +1249,11 @@ class IndirectCallTransformer if (!isReasonableUnderflow) { compiler->fgPgoConsistent = false; + compiler->Metrics.ProfileInconsistentChainedGDV++; } } - // No matter what, the minimum weight is zero + // No matter what, the minimum weight is zero // newCheckWeight = 0; } diff --git a/src/coreclr/jit/jitmetadata.cpp b/src/coreclr/jit/jitmetadata.cpp index 905cdb7317d8bb..bdf8a8d06d029e 100644 --- a/src/coreclr/jit/jitmetadata.cpp +++ b/src/coreclr/jit/jitmetadata.cpp @@ -46,6 +46,20 @@ void JitMetrics::report(Compiler* comp) #include "jitmetadatalist.h" } +//------------------------------------------------------------------------ +// JitMetrics::mergeToRoot: Merge inlinee compiler metrics to root compiler instance +// +// Parameters: +// inlineeComp - inlinee compiler instance +// +void JitMetrics::mergeToRoot(Compiler* inlineeComp) +{ + Compiler* const root = inlineeComp->impInlineRoot(); +#define JITMETADATAINFO(name, type, flags) +#define JITMETADATAMETRIC(name, type, flags) root->Metrics.name += inlineeComp->Metrics.name; +#include "jitmetadatalist.h" +} + //------------------------------------------------------------------------ // printMetric: Print a double metric value to jitstdout. // diff --git a/src/coreclr/jit/jitmetadata.h b/src/coreclr/jit/jitmetadata.h index 3b4b324497cc21..5dbd623a86daf3 100644 --- a/src/coreclr/jit/jitmetadata.h +++ b/src/coreclr/jit/jitmetadata.h @@ -23,4 +23,5 @@ class JitMetrics void report(Compiler* comp); void dump(); + void mergeToRoot(Compiler* inlineeComp); }; diff --git a/src/coreclr/jit/jitmetadatalist.h b/src/coreclr/jit/jitmetadatalist.h index f36c15ab9991d6..43afa6384d4c67 100644 --- a/src/coreclr/jit/jitmetadatalist.h +++ b/src/coreclr/jit/jitmetadatalist.h @@ -24,25 +24,42 @@ // and int64_t types supported). Their reporting is handled automatically and // they will be propagated all the way into SPMI replay/diff results. -// Name, type flags -JITMETADATAINFO(MethodFullName, const char*, 0) -JITMETADATAINFO(TieringName, const char*, 0) -JITMETADATAMETRIC(PhysicallyPromotedFields, int, 0) -JITMETADATAMETRIC(LoopsFoundDuringOpts, int, 0) -JITMETADATAMETRIC(LoopsCloned, int, 0) -JITMETADATAMETRIC(LoopsUnrolled, int, 0) -JITMETADATAMETRIC(LoopAlignmentCandidates, int, 0) -JITMETADATAMETRIC(LoopsAligned, int, 0) -JITMETADATAMETRIC(LoopsIVWidened, int, 0) -JITMETADATAMETRIC(WidenedIVs, int, 0) -JITMETADATAMETRIC(VarsInSsa, int, 0) -JITMETADATAMETRIC(HoistedExpressions, int, 0) -JITMETADATAMETRIC(RedundantBranchesEliminated, int, JIT_METADATA_HIGHER_IS_BETTER) -JITMETADATAMETRIC(JumpThreadingsPerformed, int, JIT_METADATA_HIGHER_IS_BETTER) -JITMETADATAMETRIC(CseCount, int, 0) -JITMETADATAMETRIC(BasicBlocksAtCodegen, int, 0) -JITMETADATAMETRIC(PerfScore, double, JIT_METADATA_LOWER_IS_BETTER) -JITMETADATAMETRIC(BytesAllocated, int64_t, JIT_METADATA_LOWER_IS_BETTER) +// Name, type flags +JITMETADATAINFO(MethodFullName, const char*, 0) +JITMETADATAINFO(TieringName, const char*, 0) +JITMETADATAMETRIC(PhysicallyPromotedFields, int, 0) +JITMETADATAMETRIC(LoopsFoundDuringOpts, int, 0) +JITMETADATAMETRIC(LoopsCloned, int, 0) +JITMETADATAMETRIC(LoopsUnrolled, int, 0) +JITMETADATAMETRIC(LoopAlignmentCandidates, int, 0) +JITMETADATAMETRIC(LoopsAligned, int, 0) +JITMETADATAMETRIC(LoopsIVWidened, int, 0) +JITMETADATAMETRIC(WidenedIVs, int, 0) +JITMETADATAMETRIC(VarsInSsa, int, 0) +JITMETADATAMETRIC(HoistedExpressions, int, 0) +JITMETADATAMETRIC(RedundantBranchesEliminated, int, JIT_METADATA_HIGHER_IS_BETTER) +JITMETADATAMETRIC(JumpThreadingsPerformed, int, JIT_METADATA_HIGHER_IS_BETTER) +JITMETADATAMETRIC(CseCount, int, 0) +JITMETADATAMETRIC(BasicBlocksAtCodegen, int, 0) +JITMETADATAMETRIC(PerfScore, double, JIT_METADATA_LOWER_IS_BETTER) +JITMETADATAMETRIC(BytesAllocated, int64_t, JIT_METADATA_LOWER_IS_BETTER) +JITMETADATAMETRIC(ImporterBranchFold, int, 0) +JITMETADATAMETRIC(ImporterSwitchFold, int, 0) +JITMETADATAMETRIC(DevirtualizedCall, int, 0) +JITMETADATAMETRIC(DevirtualizedCallUnboxedEntry, int, 0) +JITMETADATAMETRIC(DevirtualizedCallRemovedBox, int, 0) +JITMETADATAMETRIC(GDV, int, 0) +JITMETADATAMETRIC(ClassGDV, int, 0) +JITMETADATAMETRIC(MethodGDV, int, 0) +JITMETADATAMETRIC(MultiGuessGDV, int, 0) +JITMETADATAMETRIC(ChainedGDV, int, 0) +JITMETADATAMETRIC(ProfileSynthesizedBlendedOrRepaired, int, 0) +JITMETADATAMETRIC(ProfileInconsistentInitially, int, 0) +JITMETADATAMETRIC(ProfileInconsistentResetLeave, int, 0) +JITMETADATAMETRIC(ProfileInconsistentImporterBranchFold, int, 0) +JITMETADATAMETRIC(ProfileInconsistentImporterSwitchFold, int, 0) +JITMETADATAMETRIC(ProfileInconsistentChainedGDV, int, 0) +JITMETADATAMETRIC(ProfileInconsistentScratchBB, int, 0) #undef JITMETADATA #undef JITMETADATAINFO From b6281b60f9813f803e48f07e61a1b152dcb6ec65 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Tue, 23 Apr 2024 11:12:49 -0400 Subject: [PATCH 029/161] Update dependencies from https://github.com/dotnet/source-build-externals build 20240422.1 (#101426) Microsoft.SourceBuild.Intermediate.source-build-externals From Version 9.0.0-alpha.1.24216.3 -> To Version 9.0.0-alpha.1.24222.1 Co-authored-by: dotnet-maestro[bot] --- eng/Version.Details.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 1f9d9e699d07b9..60e81c18d6d3ee 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -85,9 +85,9 @@ - + https://github.com/dotnet/source-build-externals - 5a273649709de76f61957e3d69e1f031e5ac82e2 + 1223ec47c74e79d44950d429a36386de6c7bf9c8 From 1f9e7e869636312c66e0b66c8ff492bb5477eaf1 Mon Sep 17 00:00:00 2001 From: Sven Boemer Date: Tue, 23 Apr 2024 08:13:46 -0700 Subject: [PATCH 030/161] Remove AD0001 from NoWarn (#101404) --- .../System.Private.CoreLib/src/System.Private.CoreLib.csproj | 2 -- src/mono/System.Private.CoreLib/System.Private.CoreLib.csproj | 3 +-- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System.Private.CoreLib.csproj b/src/coreclr/nativeaot/System.Private.CoreLib/src/System.Private.CoreLib.csproj index 70928c997a5084..c7bfa7ff2215ed 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System.Private.CoreLib.csproj +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System.Private.CoreLib.csproj @@ -1,8 +1,6 @@ true - - $(NoWarn);AD0001 diff --git a/src/mono/System.Private.CoreLib/System.Private.CoreLib.csproj b/src/mono/System.Private.CoreLib/System.Private.CoreLib.csproj index 905dc83eb08dee..076fc42815c65c 100644 --- a/src/mono/System.Private.CoreLib/System.Private.CoreLib.csproj +++ b/src/mono/System.Private.CoreLib/System.Private.CoreLib.csproj @@ -36,8 +36,7 @@ $(ProductVersion) $(ProductVersion) - - $(NoWarn),0419,0649,AD0001 + $(NoWarn),0419,0649 enable From 2e75aac8dbbae5420a93f6fbe9568812dbeb3472 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Tue, 23 Apr 2024 11:17:55 -0400 Subject: [PATCH 031/161] Update dependencies from https://dev.azure.com/dnceng/internal/_git/dotnet-optimization build 20240419.3 (#101375) optimization.linux-arm64.MIBC.Runtime , optimization.linux-x64.MIBC.Runtime , optimization.windows_nt-arm64.MIBC.Runtime , optimization.windows_nt-x64.MIBC.Runtime , optimization.windows_nt-x86.MIBC.Runtime , optimization.PGO.CoreCLR From Version 1.0.0-prerelease.24106.4 -> To Version 1.0.0-prerelease.24219.3 Co-authored-by: dotnet-maestro[bot] --- eng/Version.Details.xml | 24 ++++++++++++------------ eng/Versions.props | 12 ++++++------ 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 60e81c18d6d3ee..d3abb581e0f162 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -336,21 +336,21 @@ https://github.com/dotnet/arcade b4f4d40741f161e2c0d96c19c51a4013850ef65f - + https://dev.azure.com/dnceng/internal/_git/dotnet-optimization - 78a5b978e1965c1335edb4b9a22bc4d6ff5a77a6 + c54b8e8611d50594cc926fd7c81205871a38be6f - + https://dev.azure.com/dnceng/internal/_git/dotnet-optimization - 78a5b978e1965c1335edb4b9a22bc4d6ff5a77a6 + c54b8e8611d50594cc926fd7c81205871a38be6f - + https://dev.azure.com/dnceng/internal/_git/dotnet-optimization - 78a5b978e1965c1335edb4b9a22bc4d6ff5a77a6 + c54b8e8611d50594cc926fd7c81205871a38be6f - + https://dev.azure.com/dnceng/internal/_git/dotnet-optimization - 78a5b978e1965c1335edb4b9a22bc4d6ff5a77a6 + c54b8e8611d50594cc926fd7c81205871a38be6f https://github.com/dotnet/hotreload-utils @@ -396,13 +396,13 @@ cf8c24575410adf397c0823fd7061f9451049ea1 - + https://dev.azure.com/dnceng/internal/_git/dotnet-optimization - 78a5b978e1965c1335edb4b9a22bc4d6ff5a77a6 + c54b8e8611d50594cc926fd7c81205871a38be6f - + https://dev.azure.com/dnceng/internal/_git/dotnet-optimization - 78a5b978e1965c1335edb4b9a22bc4d6ff5a77a6 + c54b8e8611d50594cc926fd7c81205871a38be6f diff --git a/eng/Versions.props b/eng/Versions.props index b9c65331748549..95e1a7403b2580 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -153,12 +153,12 @@ 9.0.0-beta.24215.1 9.0.0-beta.24215.1 - 1.0.0-prerelease.24106.4 - 1.0.0-prerelease.24106.4 - 1.0.0-prerelease.24106.4 - 1.0.0-prerelease.24106.4 - 1.0.0-prerelease.24106.4 - 1.0.0-prerelease.24106.4 + 1.0.0-prerelease.24219.3 + 1.0.0-prerelease.24219.3 + 1.0.0-prerelease.24219.3 + 1.0.0-prerelease.24219.3 + 1.0.0-prerelease.24219.3 + 1.0.0-prerelease.24219.3 2.0.0 17.8.0-beta1.23475.2 From bbf3a4a4031a13142a7c536c5b945b121497bf79 Mon Sep 17 00:00:00 2001 From: Katelyn Gadd Date: Tue, 23 Apr 2024 08:48:23 -0700 Subject: [PATCH 032/161] [mono] Miscellaneous startup optimizations (#101263) * Optimize out an unnecessary memset under g_slist_prepend * Don't inline constructors of Exception or its descendants into interpreter method bodies --- src/mono/mono/eglib/gslist.c | 3 ++- src/mono/mono/metadata/class-getters.h | 1 + src/mono/mono/metadata/class-init.c | 12 ++++++++++++ src/mono/mono/metadata/class-private-definition.h | 5 +++-- src/mono/mono/mini/interp/transform.c | 3 +++ 5 files changed, 21 insertions(+), 3 deletions(-) diff --git a/src/mono/mono/eglib/gslist.c b/src/mono/mono/eglib/gslist.c index 71cd6dfd972e97..aa03c4be8d1536 100644 --- a/src/mono/mono/eglib/gslist.c +++ b/src/mono/mono/eglib/gslist.c @@ -52,7 +52,8 @@ g_slist_append (GSList *list, gpointer data) GSList* g_slist_prepend (GSList *list, gpointer data) { - GSList *head = g_slist_alloc (); + // We don't need to zero the allocation using g_slist_alloc since we fully initialize the node + GSList *head = g_new (GSList, 1); head->data = data; head->next = list; diff --git a/src/mono/mono/metadata/class-getters.h b/src/mono/mono/metadata/class-getters.h index 8e9804ba45aa8b..30cc66fcf7c176 100644 --- a/src/mono/mono/metadata/class-getters.h +++ b/src/mono/mono/metadata/class-getters.h @@ -48,6 +48,7 @@ MONO_CLASS_GETTER(m_class_is_interfaces_inited, gboolean, , MonoClass, interface MONO_CLASS_GETTER(m_class_is_simd_type, gboolean, , MonoClass, simd_type) MONO_CLASS_GETTER(m_class_is_has_finalize_inited, gboolean, , MonoClass, has_finalize_inited) MONO_CLASS_GETTER(m_class_is_fields_inited, gboolean, , MonoClass, fields_inited) +MONO_CLASS_GETTER(m_class_is_exception_class, gboolean, , MonoClass, is_exception_class) MONO_CLASS_GETTER(m_class_has_failure, gboolean, , MonoClass, has_failure) MONO_CLASS_GETTER(m_class_has_deferred_failure, gboolean, , MonoClass, has_deferred_failure) MONO_CLASS_GETTER(m_class_has_weak_fields, gboolean, , MonoClass, has_weak_fields) diff --git a/src/mono/mono/metadata/class-init.c b/src/mono/mono/metadata/class-init.c index c2210a0e41765c..13cf1fa612b359 100644 --- a/src/mono/mono/metadata/class-init.c +++ b/src/mono/mono/metadata/class-init.c @@ -735,6 +735,17 @@ mono_class_create_from_typedef (MonoImage *image, guint32 type_token, MonoError } } + // compute is_exception_class, used by interp to avoid inlining exception handling code + if ( + klass->parent && !m_class_is_valuetype (klass) && + !m_class_is_interface (klass) + ) { + if (m_class_is_exception_class (klass->parent)) + klass->is_exception_class = 1; + else if (!strcmp (klass->name, "Exception") && !strcmp(klass->name_space, "System")) + klass->is_exception_class = 1; + } + mono_loader_unlock (); MONO_PROFILER_RAISE (class_loaded, (klass)); @@ -926,6 +937,7 @@ mono_class_create_generic_inst (MonoGenericClass *gclass) klass->this_arg.byref__ = TRUE; klass->is_inlinearray = gklass->is_inlinearray; klass->inlinearray_value = gklass->inlinearray_value; + klass->is_exception_class = gklass->is_exception_class; klass->enumtype = gklass->enumtype; klass->valuetype = gklass->valuetype; diff --git a/src/mono/mono/metadata/class-private-definition.h b/src/mono/mono/metadata/class-private-definition.h index ff33e6dd8a78e6..1e0c01ab336b3b 100644 --- a/src/mono/mono/metadata/class-private-definition.h +++ b/src/mono/mono/metadata/class-private-definition.h @@ -68,9 +68,8 @@ struct _MonoClass { guint no_special_static_fields : 1; /* has no thread/context static fields */ guint nested_classes_inited : 1; /* Whenever nested_class is initialized */ - - /* next byte*/ guint interfaces_inited : 1; /* interfaces is initialized */ + /* next byte*/ guint simd_type : 1; /* class is a simd intrinsic type */ guint has_finalize_inited : 1; /* has_finalize is initialized */ guint fields_inited : 1; /* setup_fields () has finished */ @@ -79,6 +78,8 @@ struct _MonoClass { guint has_dim_conflicts : 1; /* Class has conflicting default interface methods */ guint any_field_has_auto_layout : 1; /* a field in this type's layout uses auto-layout */ guint has_deferred_failure : 1; + /* next byte*/ + guint is_exception_class : 1; /* is System.Exception or derived from it */ MonoClass *parent; MonoClass *nested_in; diff --git a/src/mono/mono/mini/interp/transform.c b/src/mono/mono/mini/interp/transform.c index 88844dae725374..be1d722f146408 100644 --- a/src/mono/mono/mini/interp/transform.c +++ b/src/mono/mono/mini/interp/transform.c @@ -2907,6 +2907,9 @@ interp_method_check_inlining (TransformData *td, MonoMethod *method, MonoMethodS if (g_list_find (td->dont_inline, method)) return FALSE; + if (m_class_is_exception_class (method->klass) && !strcmp (method->name, ".ctor")) + return FALSE; + return TRUE; } From 02f10c1eb4eddc78496f0d803ed09d5838950185 Mon Sep 17 00:00:00 2001 From: Radek Doulik Date: Tue, 23 Apr 2024 17:51:26 +0200 Subject: [PATCH 033/161] [wasm] Do not use link flags for bitcode compilation (#101397) * [wasm] Do not use link flags for bitcode compilation This avoids errors like: /root/helix/work/correlation/build/wasm-shared/WasmApp.Common.targets(832,5): error : emcc: warning: linker setting ignored during compilation: 'EXPORT_ES6' [-Wunused-command-line-argument] [/root/helix/work/workitem/e/publish/ProxyProjectForAOTOnHelix.proj] /root/helix/work/correlation/build/wasm-shared/WasmApp.Common.targets(832,5): error : emcc: warning: linker setting ignored during compilation: 'EXPORT_EXCEPTION_HANDLING_HELPERS' [-Wunused-command-line-argument] [/root/helix/work/workitem/e/publish/ProxyProjectForAOTOnHelix.proj] * Rename _BitcodeLDFlags to _BitcodeCompileFlags Update the comment as well. _BitcodeLDFlags were used only for the BC compilation. This way we keep the possibility to add extra flags via EmccExtraBitcodeCompilationFlags and WasiClangExtraBitcodeCompileFlags. --- src/mono/browser/build/BrowserWasmApp.targets | 4 ++-- src/mono/wasi/build/WasiApp.targets | 4 ++-- src/mono/wasm/build/WasmApp.Common.targets | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/mono/browser/build/BrowserWasmApp.targets b/src/mono/browser/build/BrowserWasmApp.targets index aa231c45d8b7cc..484d3486c5eaa8 100644 --- a/src/mono/browser/build/BrowserWasmApp.targets +++ b/src/mono/browser/build/BrowserWasmApp.targets @@ -406,8 +406,8 @@ - <_BitcodeLDFlags Include="@(_EmccLDFlags)" /> - <_BitcodeLDFlags Include="$(EmccExtraBitcodeLDFlags)" /> + <_BitcodeCompileFlags Include="@(_EmccCommonFlags)" /> + <_BitcodeCompileFlags Include="$(EmccExtraBitcodeCompilationFlags)" /> diff --git a/src/mono/wasi/build/WasiApp.targets b/src/mono/wasi/build/WasiApp.targets index 37d6d40d1f172e..c5ecf84ad0c73c 100644 --- a/src/mono/wasi/build/WasiApp.targets +++ b/src/mono/wasi/build/WasiApp.targets @@ -265,8 +265,8 @@ - <_BitcodeLDFlags Include="@(_WasiClangLDFlags)" /> - <_BitcodeLDFlags Include="$(WasiClangExtraBitcodeLDFlags)" /> + <_BitcodeCompileFlags Include="@(_WasiClangCommonFlags)" /> + <_BitcodeCompileFlags Include="$(WasiClangExtraBitcodeCompileFlags)" /> diff --git a/src/mono/wasm/build/WasmApp.Common.targets b/src/mono/wasm/build/WasmApp.Common.targets index 7e4c7d343417fd..f06b9a1261fe5e 100644 --- a/src/mono/wasm/build/WasmApp.Common.targets +++ b/src/mono/wasm/build/WasmApp.Common.targets @@ -800,11 +800,11 @@ - + From 076ecd841e8059ccd9e48a85d79fa4e91c9c50c5 Mon Sep 17 00:00:00 2001 From: Katelyn Gadd Date: Tue, 23 Apr 2024 08:53:22 -0700 Subject: [PATCH 034/161] [mono] Optimize startup vtable setup (#101312) * Add new [ptr, ptr] -> ptr simdhash variant for caching * Cache mono_class_implement_interface_slow because we perform many redundant calls to it during application startup * Verify cache in checked builds --- src/mono/mono/metadata/CMakeLists.txt | 3 +- src/mono/mono/metadata/class-setup-vtable.c | 9 +- src/mono/mono/metadata/class.c | 116 +++++++++++++++++- src/native/containers/containers.cmake | 2 + .../containers/dn-simdhash-ptrpair-ptr.c | 39 ++++++ .../containers/dn-simdhash-specializations.h | 15 +++ src/native/containers/dn-simdhash.c | 16 ++- src/native/containers/dn-simdhash.h | 5 + 8 files changed, 196 insertions(+), 9 deletions(-) create mode 100644 src/native/containers/dn-simdhash-ptrpair-ptr.c diff --git a/src/mono/mono/metadata/CMakeLists.txt b/src/mono/mono/metadata/CMakeLists.txt index 9efd5ac0079c24..9d6010e95f3286 100644 --- a/src/mono/mono/metadata/CMakeLists.txt +++ b/src/mono/mono/metadata/CMakeLists.txt @@ -45,7 +45,8 @@ endif() set(imported_native_sources ../../../native/containers/dn-simdhash.c ../../../native/containers/dn-simdhash-string-ptr.c - ../../../native/containers/dn-simdhash-u32-ptr.c) + ../../../native/containers/dn-simdhash-u32-ptr.c + ../../../native/containers/dn-simdhash-ptrpair-ptr.c) set(metadata_common_sources appdomain.c diff --git a/src/mono/mono/metadata/class-setup-vtable.c b/src/mono/mono/metadata/class-setup-vtable.c index 9a235c1ec0cced..62afa76dde5b74 100644 --- a/src/mono/mono/metadata/class-setup-vtable.c +++ b/src/mono/mono/metadata/class-setup-vtable.c @@ -773,6 +773,13 @@ mono_method_get_method_definition (MonoMethod *method) static gboolean verify_class_overrides (MonoClass *klass, MonoMethod **overrides, int onum) { + // on windows and arm, we define NDEBUG for release builds + // on browser and wasi, we define DEBUG for debug builds +#ifdef ENABLE_CHECKED_BUILD + if (klass->image == mono_defaults.corlib) + return TRUE; +#endif + int i; for (i = 0; i < onum; ++i) { @@ -1760,7 +1767,7 @@ mono_class_setup_vtable_general (MonoClass *klass, MonoMethod **overrides, int o MonoMethod *override = iface_overrides [i*2 + 1]; if (mono_class_is_gtd (override->klass)) { override = mono_class_inflate_generic_method_full_checked (override, ic, mono_class_get_context (ic), error); - } + } // there used to be code here to inflate decl if decl->is_inflated, but in https://github.com/dotnet/runtime/pull/64102#discussion_r790019545 we // think that this does not correspond to any real code. if (!apply_override (klass, ic, vtable, decl, override, &override_map, &override_class_map, &conflict_map)) diff --git a/src/mono/mono/metadata/class.c b/src/mono/mono/metadata/class.c index 5ae4f1981d38ac..6045628bf49e7f 100644 --- a/src/mono/mono/metadata/class.c +++ b/src/mono/mono/metadata/class.c @@ -4331,12 +4331,16 @@ mono_class_is_variant_compatible_slow (MonoClass *klass, MonoClass *oklass) } return TRUE; } -/*Check if @candidate implements the interface @target*/ + static gboolean -mono_class_implement_interface_slow (MonoClass *target, MonoClass *candidate) +mono_class_implement_interface_slow_cached (MonoClass *target, MonoClass *candidate, dn_simdhash_ptrpair_ptr_t *cache); + +static gboolean +mono_class_implement_interface_slow_uncached (MonoClass *target, MonoClass *candidate, dn_simdhash_ptrpair_ptr_t *cache) { ERROR_DECL (error); int i; + gboolean is_variant = mono_class_has_variant_generic_params (target); if (is_variant && MONO_CLASS_IS_INTERFACE_INTERNAL (candidate)) { @@ -4365,7 +4369,7 @@ mono_class_implement_interface_slow (MonoClass *target, MonoClass *candidate) return TRUE; if (is_variant && mono_class_is_variant_compatible_slow (target, iface_class)) return TRUE; - if (mono_class_implement_interface_slow (target, iface_class)) + if (mono_class_implement_interface_slow_cached (target, iface_class, cache)) return TRUE; } } @@ -4390,7 +4394,7 @@ mono_class_implement_interface_slow (MonoClass *target, MonoClass *candidate) if (is_variant && mono_class_is_variant_compatible_slow (target, candidate_interfaces [i])) return TRUE; - if (mono_class_implement_interface_slow (target, candidate_interfaces [i])) + if (mono_class_implement_interface_slow_cached (target, candidate_interfaces [i], cache)) return TRUE; } } @@ -4400,6 +4404,107 @@ mono_class_implement_interface_slow (MonoClass *target, MonoClass *candidate) return FALSE; } +// #define LOG_INTERFACE_CACHE_HITS 1 + +#if LOG_INTERFACE_CACHE_HITS +static gint64 implement_interface_hits = 0, implement_interface_misses = 0; + +static void +log_hit_rate (dn_simdhash_ptrpair_ptr_t *cache) +{ + gint64 total_calls = implement_interface_hits + implement_interface_misses; + if ((total_calls % 500) != 0) + return; + double hit_rate = implement_interface_hits * 100.0 / total_calls; + g_printf ("implement_interface cache hit rate: %f (%lld total calls). Overflow count: %u\n", hit_rate, total_calls, dn_simdhash_overflow_count (cache)); +} +#endif + +static gboolean +mono_class_implement_interface_slow_cached (MonoClass *target, MonoClass *candidate, dn_simdhash_ptrpair_ptr_t *cache) +{ + gpointer cached_result = NULL; + dn_ptrpair_t key = { target, candidate }; + gboolean result = 0, cache_hit = 0; + + // Skip the caching logic for exact matches + if (candidate == target) + return TRUE; + + cache_hit = dn_simdhash_ptrpair_ptr_try_get_value (cache, key, &cached_result); + if (cache_hit) { + // Testing shows a cache hit rate of 60% on S.R.Tests and S.T.J.Tests, + // and 40-50% for small app startup. Near-zero overflow count. +#if LOG_INTERFACE_CACHE_HITS + implement_interface_hits++; + log_hit_rate (cache); +#endif + result = (cached_result != NULL); +#ifndef ENABLE_CHECKED_BUILD + return result; +#endif + } + + gboolean uncached_result = mono_class_implement_interface_slow_uncached (target, candidate, cache); + + if (!cache_hit) { +#if LOG_INTERFACE_CACHE_HITS + implement_interface_misses++; + log_hit_rate (cache); +#endif + dn_simdhash_ptrpair_ptr_try_add (cache, key, uncached_result ? GUINT_TO_POINTER(1) : NULL); + } + +#ifdef ENABLE_CHECKED_BUILD + if (cache_hit) { + if (result != uncached_result) + g_print ( + "Cache mismatch for %s.%s and %s.%s: cached=%d, uncached=%d\n", + m_class_get_name_space (target), m_class_get_name (target), + m_class_get_name_space (candidate), m_class_get_name (candidate), + result, uncached_result + ); + g_assert (result == uncached_result); + } +#endif + return uncached_result; +} + +static dn_simdhash_ptrpair_ptr_t *implement_interface_scratch_cache = NULL; + +/*Check if @candidate implements the interface @target*/ +static gboolean +mono_class_implement_interface_slow (MonoClass *target, MonoClass *candidate) +{ + gpointer cas_result; + gboolean result; + dn_simdhash_ptrpair_ptr_t *cache = (dn_simdhash_ptrpair_ptr_t *)mono_atomic_xchg_ptr ((volatile gpointer *)&implement_interface_scratch_cache, NULL); + if (!cache) + // Roughly 64KB of memory usage and big enough to have fast lookups + // Smaller is viable but makes the hit rate worse + cache = dn_simdhash_ptrpair_ptr_new (2048, NULL); + else if (dn_simdhash_count (cache) >= 2250) { + // FIXME: 2250 is arbitrary (roughly 256 11-item buckets w/load factor) + // One step down reduces hit rate by approximately 2-4% + // HACK: Only clear the scratch cache once it gets too big. + // The pattern is that (especially during startup), we have lots + // of mono_class_implement_interface_slow calls back to back that + // perform similar checks, so keeping the cache data around between + // sequential calls will potentially optimize them a lot. + dn_simdhash_clear (cache); + } + + result = mono_class_implement_interface_slow_cached (target, candidate, cache); + + // Under most circumstances we won't have multiple threads competing to run implement_interface_slow, + // so it's not worth making this thread-local and potentially keeping a cache instance around per-thread. + cas_result = mono_atomic_cas_ptr ((volatile gpointer *)&implement_interface_scratch_cache, cache, NULL); + if (cas_result != NULL) + dn_simdhash_free (cache); + + return result; +} + /* * Check if @oklass can be assigned to @klass. * This function does the same as mono_class_is_assignable_from_internal but is safe to be used from mono_class_init_internal context. @@ -4416,8 +4521,9 @@ mono_class_is_assignable_from_slow (MonoClass *target, MonoClass *candidate) return TRUE; /*If target is not an interface there is no need to check them.*/ - if (MONO_CLASS_IS_INTERFACE_INTERNAL (target)) + if (MONO_CLASS_IS_INTERFACE_INTERNAL (target)) { return mono_class_implement_interface_slow (target, candidate); + } if (m_class_is_delegate (target) && mono_class_has_variant_generic_params (target)) return mono_class_is_variant_compatible (target, candidate, FALSE); diff --git a/src/native/containers/containers.cmake b/src/native/containers/containers.cmake index 16c41eab5619f8..4749dceea2dd9a 100644 --- a/src/native/containers/containers.cmake +++ b/src/native/containers/containers.cmake @@ -13,6 +13,8 @@ list(APPEND SHARED_CONTAINER_SOURCES # dn-simdhash-string-ptr.c # dn-simdhash-u32-ptr.c # dn-simdhash-ptr-ptr.c + # dn-simdhash-ght-compatible.c + # dn-simdhash-ptrpair-ptr.c ) list(APPEND SHARED_CONTAINER_HEADERS diff --git a/src/native/containers/dn-simdhash-ptrpair-ptr.c b/src/native/containers/dn-simdhash-ptrpair-ptr.c new file mode 100644 index 00000000000000..d377647b6636ac --- /dev/null +++ b/src/native/containers/dn-simdhash-ptrpair-ptr.c @@ -0,0 +1,39 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +#include +#include "dn-simdhash.h" + +#include "dn-simdhash-utils.h" + +typedef struct dn_ptrpair_t { + void *first; + void *second; +} dn_ptrpair_t; + +static inline uint32_t +dn_ptrpair_t_hash (dn_ptrpair_t key) +{ + return (MurmurHash3_32_ptr(key.first, 0) ^ MurmurHash3_32_ptr(key.second, 1)); +} + +static inline uint8_t +dn_ptrpair_t_equals (dn_ptrpair_t lhs, dn_ptrpair_t rhs) +{ + return (lhs.first == rhs.first) && (lhs.second == rhs.second); +} + +#define DN_SIMDHASH_T dn_simdhash_ptrpair_ptr +#define DN_SIMDHASH_KEY_T dn_ptrpair_t +#define DN_SIMDHASH_VALUE_T void * +#define DN_SIMDHASH_KEY_HASHER(hash, key) dn_ptrpair_t_hash(key) +#define DN_SIMDHASH_KEY_EQUALS(hash, lhs, rhs) dn_ptrpair_t_equals(lhs, rhs) +#if SIZEOF_VOID_P == 8 +// 192 bytes holds 12 16-byte blocks, so 11 keys and one suffix table +#define DN_SIMDHASH_BUCKET_CAPACITY 11 +#else +// 128 bytes holds 16 8-byte blocks, so 14 keys and one suffix table +#define DN_SIMDHASH_BUCKET_CAPACITY 14 +#endif + +#include "dn-simdhash-specialization.h" diff --git a/src/native/containers/dn-simdhash-specializations.h b/src/native/containers/dn-simdhash-specializations.h index 4966c7575d19a0..9533edfc5f3d1f 100644 --- a/src/native/containers/dn-simdhash-specializations.h +++ b/src/native/containers/dn-simdhash-specializations.h @@ -59,4 +59,19 @@ typedef struct dn_simdhash_str_key dn_simdhash_str_key; #include "dn-simdhash-ght-compatible.h" + +typedef struct dn_ptrpair_t { + void *first, *second; +} dn_ptrpair_t; + +#define DN_SIMDHASH_T dn_simdhash_ptrpair_ptr +#define DN_SIMDHASH_KEY_T dn_ptrpair_t +#define DN_SIMDHASH_VALUE_T void * + +#include "dn-simdhash-specialization-declarations.h" + +#undef DN_SIMDHASH_T +#undef DN_SIMDHASH_KEY_T +#undef DN_SIMDHASH_VALUE_T + #endif diff --git a/src/native/containers/dn-simdhash.c b/src/native/containers/dn-simdhash.c index 03d4d2bf3951aa..d1e2b6e330b6ef 100644 --- a/src/native/containers/dn-simdhash.c +++ b/src/native/containers/dn-simdhash.c @@ -119,8 +119,7 @@ dn_simdhash_clear (dn_simdhash_t *hash) if (hash->vtable.destroy_all) hash->vtable.destroy_all(hash); hash->count = 0; - // TODO: Scan through buckets sequentially and only erase ones with data in them - // Maybe skip erasing the key slots too? + // TODO: Implement a fast clear algorithm that scans buckets and only clears ones w/nonzero count memset(hash->buffers.buckets, 0, hash->buffers.buckets_length * hash->meta->bucket_size_bytes); // Skip this for performance; memset is especially slow in wasm // memset(hash->buffers.values, 0, hash->buffers.values_length * hash->meta->value_size); @@ -140,6 +139,19 @@ dn_simdhash_count (dn_simdhash_t *hash) return hash->count; } +uint32_t +dn_simdhash_overflow_count (dn_simdhash_t *hash) +{ + assert(hash); + uint32_t result = 0; + for (uint32_t bucket_index = 0; bucket_index < hash->buffers.buckets_length; bucket_index++) { + uint8_t *suffixes = ((uint8_t *)hash->buffers.buckets) + (bucket_index * hash->meta->bucket_size_bytes); + uint8_t cascade_count = suffixes[DN_SIMDHASH_CASCADED_SLOT]; + result += cascade_count; + } + return result; +} + void dn_simdhash_ensure_capacity (dn_simdhash_t *hash, uint32_t capacity) { diff --git a/src/native/containers/dn-simdhash.h b/src/native/containers/dn-simdhash.h index da4a7914e18873..a2d6e87c9045fe 100644 --- a/src/native/containers/dn-simdhash.h +++ b/src/native/containers/dn-simdhash.h @@ -144,6 +144,11 @@ dn_simdhash_capacity (dn_simdhash_t *hash); uint32_t dn_simdhash_count (dn_simdhash_t *hash); +// Returns the estimated number of items that have overflowed out of a bucket. +// WARNING: This is expensive to calculate. +uint32_t +dn_simdhash_overflow_count (dn_simdhash_t *hash); + // Automatically resizes the table if it is too small to hold the requested number // of items. Will not shrink the table if it is already bigger. void From af52e82167b2eac37ede88a64da62ce56230b5f6 Mon Sep 17 00:00:00 2001 From: Ilona Tomkowicz <32700855+ilonatommy@users.noreply.github.com> Date: Tue, 23 Apr 2024 18:06:37 +0200 Subject: [PATCH 035/161] [browser][hybrid] drop `wrap_error_root`, `wrap_no_error_root` (#101390) * Calendar - done * Culture info - done. * Missing change to the previous commit. * Change case - done. * issing change to previous commit * Collation - done. * Locales - done. * Feedback * remove MonoString that is not thread-safe * Preserve stack from JS correctly. --- .../src/Interop/Browser/Interop.Calendar.cs | 2 +- .../Interop/Browser/Interop.CompareInfo.cs | 8 +- .../src/Interop/Browser/Interop.Locale.cs | 8 +- .../src/Interop/Browser/Interop.TextInfo.cs | 4 +- .../Globalization/CalendarData.Browser.cs | 53 ++++---- .../System/Globalization/CompareInfo.Icu.cs | 22 ++-- .../Globalization/CompareInfo.WebAssembly.cs | 66 ++++------ .../Globalization/CultureData.Browser.cs | 115 +++++++++++------ .../Globalization/TextInfo.WebAssembly.cs | 17 ++- src/mono/browser/runtime/corebindings.c | 23 ++-- .../runtime/hybrid-globalization/calendar.ts | 29 ++--- .../hybrid-globalization/change-case.ts | 36 ++---- .../hybrid-globalization/collations.ts | 116 ++++++++---------- .../hybrid-globalization/culture-info.ts | 30 ++--- .../runtime/hybrid-globalization/helpers.ts | 32 ----- .../runtime/hybrid-globalization/locales.ts | 79 +++++------- 16 files changed, 297 insertions(+), 343 deletions(-) diff --git a/src/libraries/Common/src/Interop/Browser/Interop.Calendar.cs b/src/libraries/Common/src/Interop/Browser/Interop.Calendar.cs index 2a7b1d02ad21ad..73fbfa924d141d 100644 --- a/src/libraries/Common/src/Interop/Browser/Interop.Calendar.cs +++ b/src/libraries/Common/src/Interop/Browser/Interop.Calendar.cs @@ -9,6 +9,6 @@ internal static partial class Interop internal static unsafe partial class JsGlobalization { [MethodImplAttribute(MethodImplOptions.InternalCall)] - internal static extern unsafe int GetCalendarInfo(in string culture, CalendarId calendarId, char* buffer, int bufferLength, out int exceptionalResult, out object result); + internal static extern unsafe nint GetCalendarInfo(char* culture, int cultureLength, CalendarId calendarId, char* buffer, int bufferMaxLength, out int bufferLength); } } diff --git a/src/libraries/Common/src/Interop/Browser/Interop.CompareInfo.cs b/src/libraries/Common/src/Interop/Browser/Interop.CompareInfo.cs index cb7edf5b380a26..638934edb416d6 100644 --- a/src/libraries/Common/src/Interop/Browser/Interop.CompareInfo.cs +++ b/src/libraries/Common/src/Interop/Browser/Interop.CompareInfo.cs @@ -8,15 +8,15 @@ internal static partial class Interop internal static unsafe partial class JsGlobalization { [MethodImplAttribute(MethodImplOptions.InternalCall)] - internal static extern unsafe int CompareString(in string culture, char* str1, int str1Len, char* str2, int str2Len, global::System.Globalization.CompareOptions options, out int exceptionalResult, out object result); + internal static extern unsafe nint CompareString(char* culture, int cultureLength, char* str1, int str1Len, char* str2, int str2Len, global::System.Globalization.CompareOptions options, out int resultPtr); [MethodImplAttribute(MethodImplOptions.InternalCall)] - internal static extern unsafe bool StartsWith(in string culture, char* str1, int str1Len, char* str2, int str2Len, global::System.Globalization.CompareOptions options, out int exceptionalResult, out object result); + internal static extern unsafe nint StartsWith(char* culture, int cultureLength, char* str1, int str1Len, char* str2, int str2Len, global::System.Globalization.CompareOptions options, out bool resultPtr); [MethodImplAttribute(MethodImplOptions.InternalCall)] - internal static extern unsafe bool EndsWith(in string culture, char* str1, int str1Len, char* str2, int str2Len, global::System.Globalization.CompareOptions options, out int exceptionalResult, out object result); + internal static extern unsafe nint EndsWith(char* culture, int cultureLength, char* str1, int str1Len, char* str2, int str2Len, global::System.Globalization.CompareOptions options, out bool resultPtr); [MethodImplAttribute(MethodImplOptions.InternalCall)] - internal static extern unsafe int IndexOf(in string culture, char* str1, int str1Len, char* str2, int str2Len, global::System.Globalization.CompareOptions options, bool fromBeginning, out int exceptionalResult, out object result); + internal static extern unsafe nint IndexOf(char* culture, int cultureLength, char* str1, int str1Len, char* str2, int str2Len, global::System.Globalization.CompareOptions options, bool fromBeginning, out int resultPtr); } } diff --git a/src/libraries/Common/src/Interop/Browser/Interop.Locale.cs b/src/libraries/Common/src/Interop/Browser/Interop.Locale.cs index b831e72e70cdbc..b2dc0db99c00c0 100644 --- a/src/libraries/Common/src/Interop/Browser/Interop.Locale.cs +++ b/src/libraries/Common/src/Interop/Browser/Interop.Locale.cs @@ -8,12 +8,12 @@ internal static partial class Interop internal static unsafe partial class JsGlobalization { [MethodImplAttribute(MethodImplOptions.InternalCall)] - internal static extern unsafe int GetCultureInfo(in string culture, char* buffer, int bufferLength, out int exceptionalResult, out object result); + internal static extern unsafe nint GetCultureInfo(char* culture, int cultureLength, char* buffer, int bufferMaxLength, out int resultLength); [MethodImplAttribute(MethodImplOptions.InternalCall)] - internal static extern unsafe int GetFirstDayOfWeek(in string culture, out int exceptionalResult, out object result); + internal static extern unsafe nint GetFirstDayOfWeek(char* culture, int cultureLength, out int resultPtr); [MethodImplAttribute(MethodImplOptions.InternalCall)] - internal static extern unsafe int GetFirstWeekOfYear(in string culture, out int exceptionalResult, out object result); + internal static extern unsafe nint GetFirstWeekOfYear(char* culture, int cultureLength, out int resultPtr); [MethodImplAttribute(MethodImplOptions.InternalCall)] - internal static extern unsafe int GetLocaleInfo(in string locale, in string culture, char* buffer, int bufferLength, out int exceptionalResult, out object result); + internal static extern unsafe nint GetLocaleInfo(char* locale, int localeLength, char* culture, int cultureLength, char* buffer, int bufferLength, out int resultLength); } } diff --git a/src/libraries/Common/src/Interop/Browser/Interop.TextInfo.cs b/src/libraries/Common/src/Interop/Browser/Interop.TextInfo.cs index ff157eb45f26cf..a10d2897f75be0 100644 --- a/src/libraries/Common/src/Interop/Browser/Interop.TextInfo.cs +++ b/src/libraries/Common/src/Interop/Browser/Interop.TextInfo.cs @@ -8,8 +8,8 @@ internal static partial class Interop internal static unsafe partial class JsGlobalization { [MethodImplAttribute(MethodImplOptions.InternalCall)] - internal static extern unsafe void ChangeCaseInvariant(char* src, int srcLen, char* dstBuffer, int dstBufferCapacity, bool bToUpper, out int exceptionalResult, out object result); + internal static extern unsafe nint ChangeCaseInvariant(char* src, int srcLen, char* dstBuffer, int dstBufferCapacity, bool bToUpper); [MethodImplAttribute(MethodImplOptions.InternalCall)] - internal static extern unsafe void ChangeCase(in string culture, char* src, int srcLen, char* dstBuffer, int dstBufferCapacity, bool bToUpper, out int exceptionalResult, out object result); + internal static extern unsafe nint ChangeCase(char* culture, int cultureLen, char* src, int srcLen, char* dstBuffer, int dstBufferCapacity, bool bToUpper); } } diff --git a/src/libraries/System.Private.CoreLib/src/System/Globalization/CalendarData.Browser.cs b/src/libraries/System.Private.CoreLib/src/System/Globalization/CalendarData.Browser.cs index 87199ed3f1eedf..582492c6c40f84 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Globalization/CalendarData.Browser.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Globalization/CalendarData.Browser.cs @@ -14,32 +14,33 @@ internal sealed partial class CalendarData private const int CALENDAR_INFO_BUFFER_LEN = 1000; private unsafe bool JSLoadCalendarDataFromBrowser(string localeName, CalendarId calendarId) { - char* buffer = stackalloc char[CALENDAR_INFO_BUFFER_LEN]; - int exception; - object exResult; - int resultLength = Interop.JsGlobalization.GetCalendarInfo(localeName, calendarId, buffer, CALENDAR_INFO_BUFFER_LEN, out exception, out exResult); - if (exception != 0) - throw new Exception((string)exResult); - string result = new string(buffer, 0, resultLength); - string[] subresults = result.Split("##"); - if (subresults.Length < 14) - throw new Exception("CalendarInfo recieved from the Browser is in icorrect format."); - // JS always has one result per locale, so even arrays are initialized with one element - this.sNativeName = string.IsNullOrEmpty(subresults[0]) ? ((CalendarId)calendarId).ToString() : subresults[0]; // this is EnglishName, not NativeName but it's the best we can do - this.saYearMonths = new string[] { subresults[1] }; - this.sMonthDay = subresults[2]; - this.saLongDates = new string[] { subresults[3] }; - this.saShortDates = new string[] { subresults[4] }; - this.saEraNames = new string[] { subresults[5] }; - this.saAbbrevEraNames = new string[] { subresults[6] }; - this.saDayNames = subresults[7].Split("||"); - this.saAbbrevDayNames = subresults[8].Split("||"); - this.saSuperShortDayNames = subresults[9].Split("||"); - this.saMonthNames = ResizeMonthsArray(subresults[10].Split("||")); - this.saAbbrevMonthNames = ResizeMonthsArray(subresults[11].Split("||")); - this.saMonthGenitiveNames = ResizeMonthsArray(subresults[12].Split("||")); - this.saAbbrevMonthGenitiveNames = ResizeMonthsArray(subresults[13].Split("||")); - return true; + ReadOnlySpan localeNameSpan = localeName.AsSpan(); + fixed (char* pLocaleName = &MemoryMarshal.GetReference(localeNameSpan)) + { + char* buffer = stackalloc char[CALENDAR_INFO_BUFFER_LEN]; + nint exceptionPtr = Interop.JsGlobalization.GetCalendarInfo(pLocaleName, localeNameSpan.Length, calendarId, buffer, CALENDAR_INFO_BUFFER_LEN, out int resultLength); + Helper.MarshalAndThrowIfException(exceptionPtr); + string result = new string(buffer, 0, resultLength); + string[] subresults = result.Split("##"); + if (subresults.Length < 14) + throw new Exception("CalendarInfo recieved from the Browser is in icorrect format."); + // JS always has one result per locale, so even arrays are initialized with one element + this.sNativeName = string.IsNullOrEmpty(subresults[0]) ? ((CalendarId)calendarId).ToString() : subresults[0]; // this is EnglishName, not NativeName but it's the best we can do + this.saYearMonths = new string[] { subresults[1] }; + this.sMonthDay = subresults[2]; + this.saLongDates = new string[] { subresults[3] }; + this.saShortDates = new string[] { subresults[4] }; + this.saEraNames = new string[] { subresults[5] }; + this.saAbbrevEraNames = new string[] { subresults[6] }; + this.saDayNames = subresults[7].Split("||"); + this.saAbbrevDayNames = subresults[8].Split("||"); + this.saSuperShortDayNames = subresults[9].Split("||"); + this.saMonthNames = ResizeMonthsArray(subresults[10].Split("||")); + this.saAbbrevMonthNames = ResizeMonthsArray(subresults[11].Split("||")); + this.saMonthGenitiveNames = ResizeMonthsArray(subresults[12].Split("||")); + this.saAbbrevMonthGenitiveNames = ResizeMonthsArray(subresults[13].Split("||")); + return true; + } static string[] ResizeMonthsArray(string[] months) { diff --git a/src/libraries/System.Private.CoreLib/src/System/Globalization/CompareInfo.Icu.cs b/src/libraries/System.Private.CoreLib/src/System/Globalization/CompareInfo.Icu.cs index 75440b2a23c458..bc532fcb26c059 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Globalization/CompareInfo.Icu.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Globalization/CompareInfo.Icu.cs @@ -198,10 +198,13 @@ private unsafe int IndexOfOrdinalIgnoreCaseHelper(ReadOnlySpan source, Rea #if TARGET_BROWSER if (GlobalizationMode.Hybrid) { - int result = Interop.JsGlobalization.IndexOf(m_name, b, target.Length, a, source.Length, options, fromBeginning, out int exception, out object ex_result); - if (exception != 0) - throw new Exception((string)ex_result); - return result; + ReadOnlySpan cultureNameSpan = m_name.AsSpan(); + fixed (char* pCultureName = &MemoryMarshal.GetReference(cultureNameSpan)) + { + nint exceptionPtr = Interop.JsGlobalization.IndexOf(pCultureName, cultureNameSpan.Length, b, target.Length, a, source.Length, options, fromBeginning, out int result); + Helper.MarshalAndThrowIfException(exceptionPtr); + return result; + } } #elif TARGET_MACCATALYST || TARGET_IOS || TARGET_TVOS if (GlobalizationMode.Hybrid) @@ -300,10 +303,13 @@ private unsafe int IndexOfOrdinalHelper(ReadOnlySpan source, ReadOnlySpan< #if TARGET_BROWSER if (GlobalizationMode.Hybrid) { - int result = Interop.JsGlobalization.IndexOf(m_name, b, target.Length, a, source.Length, options, fromBeginning, out int exception, out object ex_result); - if (exception != 0) - throw new Exception((string)ex_result); - return result; + ReadOnlySpan cultureNameSpan = m_name.AsSpan(); + fixed (char* pCultureName = &MemoryMarshal.GetReference(cultureNameSpan)) + { + nint exceptionPtr = Interop.JsGlobalization.IndexOf(pCultureName, cultureNameSpan.Length, b, target.Length, a, source.Length, options, fromBeginning, out int result); + Helper.MarshalAndThrowIfException(exceptionPtr); + return result; + } } #elif TARGET_MACCATALYST || TARGET_IOS || TARGET_TVOS if (GlobalizationMode.Hybrid) diff --git a/src/libraries/System.Private.CoreLib/src/System/Globalization/CompareInfo.WebAssembly.cs b/src/libraries/System.Private.CoreLib/src/System/Globalization/CompareInfo.WebAssembly.cs index 1d265dc70450a8..e8935a6d2439cc 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Globalization/CompareInfo.WebAssembly.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Globalization/CompareInfo.WebAssembly.cs @@ -47,86 +47,74 @@ private static void AssertIndexingSupported(CompareOptions options, string cultu private unsafe int JsCompareString(ReadOnlySpan string1, ReadOnlySpan string2, CompareOptions options) { AssertHybridOnWasm(options); - string cultureName = m_name; - AssertComparisonSupported(options, cultureName); + AssertComparisonSupported(options, m_name); - int cmpResult; + ReadOnlySpan cultureNameSpan = m_name.AsSpan(); fixed (char* pString1 = &MemoryMarshal.GetReference(string1)) fixed (char* pString2 = &MemoryMarshal.GetReference(string2)) + fixed (char* pCultureName = &MemoryMarshal.GetReference(cultureNameSpan)) { - cmpResult = Interop.JsGlobalization.CompareString(cultureName, pString1, string1.Length, pString2, string2.Length, options, out int exception, out object ex_result); - if (exception != 0) - throw new Exception((string)ex_result); + nint exceptionPtr = Interop.JsGlobalization.CompareString(pCultureName, cultureNameSpan.Length, pString1, string1.Length, pString2, string2.Length, options, out int cmpResult); + Helper.MarshalAndThrowIfException(exceptionPtr); + return cmpResult; } - - return cmpResult; } private unsafe bool JsStartsWith(ReadOnlySpan source, ReadOnlySpan prefix, CompareOptions options) { AssertHybridOnWasm(options); Debug.Assert(!prefix.IsEmpty); - string cultureName = m_name; - AssertIndexingSupported(options, cultureName); + AssertIndexingSupported(options, m_name); - bool result; + ReadOnlySpan cultureNameSpan = m_name.AsSpan(); fixed (char* pSource = &MemoryMarshal.GetReference(source)) fixed (char* pPrefix = &MemoryMarshal.GetReference(prefix)) + fixed (char* pCultureName = &MemoryMarshal.GetReference(cultureNameSpan)) { - result = Interop.JsGlobalization.StartsWith(cultureName, pSource, source.Length, pPrefix, prefix.Length, options, out int exception, out object ex_result); - if (exception != 0) - throw new Exception((string)ex_result); + nint exceptionPtr = Interop.JsGlobalization.StartsWith(pCultureName, cultureNameSpan.Length, pSource, source.Length, pPrefix, prefix.Length, options, out bool result); + Helper.MarshalAndThrowIfException(exceptionPtr); + return result; } - - - return result; } private unsafe bool JsEndsWith(ReadOnlySpan source, ReadOnlySpan prefix, CompareOptions options) { AssertHybridOnWasm(options); Debug.Assert(!prefix.IsEmpty); - string cultureName = m_name; - AssertIndexingSupported(options, cultureName); + AssertIndexingSupported(options, m_name); - bool result; + ReadOnlySpan cultureNameSpan = m_name.AsSpan(); fixed (char* pSource = &MemoryMarshal.GetReference(source)) fixed (char* pPrefix = &MemoryMarshal.GetReference(prefix)) + fixed (char* pCultureName = &MemoryMarshal.GetReference(cultureNameSpan)) { - result = Interop.JsGlobalization.EndsWith(cultureName, pSource, source.Length, pPrefix, prefix.Length, options, out int exception, out object ex_result); - if (exception != 0) - throw new Exception((string)ex_result); + nint exceptionPtr = Interop.JsGlobalization.EndsWith(pCultureName, cultureNameSpan.Length, pSource, source.Length, pPrefix, prefix.Length, options, out bool result); + Helper.MarshalAndThrowIfException(exceptionPtr); + return result; } - - return result; } private unsafe int JsIndexOfCore(ReadOnlySpan source, ReadOnlySpan target, CompareOptions options, int* matchLengthPtr, bool fromBeginning) { AssertHybridOnWasm(options); Debug.Assert(!target.IsEmpty); - string cultureName = m_name; - AssertIndexingSupported(options, cultureName); + AssertIndexingSupported(options, m_name); - int idx; if (_isAsciiEqualityOrdinal && CanUseAsciiOrdinalForOptions(options)) { - idx = (options & CompareOptions.IgnoreCase) != 0 ? + return (options & CompareOptions.IgnoreCase) != 0 ? IndexOfOrdinalIgnoreCaseHelper(source, target, options, matchLengthPtr, fromBeginning) : IndexOfOrdinalHelper(source, target, options, matchLengthPtr, fromBeginning); } - else + ReadOnlySpan cultureNameSpan = m_name.AsSpan(); + fixed (char* pSource = &MemoryMarshal.GetReference(source)) + fixed (char* pTarget = &MemoryMarshal.GetReference(target)) + fixed (char* pCultureName = &MemoryMarshal.GetReference(cultureNameSpan)) { - fixed (char* pSource = &MemoryMarshal.GetReference(source)) - fixed (char* pTarget = &MemoryMarshal.GetReference(target)) - { - idx = Interop.JsGlobalization.IndexOf(m_name, pTarget, target.Length, pSource, source.Length, options, fromBeginning, out int exception, out object ex_result); - if (exception != 0) - throw new Exception((string)ex_result); - } + nint exceptionPtr = Interop.JsGlobalization.IndexOf(pCultureName, cultureNameSpan.Length, pTarget, target.Length, pSource, source.Length, options, fromBeginning, out int idx); + Helper.MarshalAndThrowIfException(exceptionPtr); + return idx; } - - return idx; } // there are chars that are ignored by ICU hashing algorithm but not ignored by invariant hashing diff --git a/src/libraries/System.Private.CoreLib/src/System/Globalization/CultureData.Browser.cs b/src/libraries/System.Private.CoreLib/src/System/Globalization/CultureData.Browser.cs index 8a8edadaf326d0..417bd563bf3574 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Globalization/CultureData.Browser.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Globalization/CultureData.Browser.cs @@ -4,6 +4,7 @@ using System.Collections.Generic; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; +using System.Runtime.InteropServices; namespace System.Globalization { @@ -41,17 +42,22 @@ private void JSInitLocaleInfo() private unsafe (string, string) JSGetLocaleInfo(string cultureName, string localeName) { - char* buffer = stackalloc char[LOCALE_INFO_BUFFER_LEN]; - int resultLength = Interop.JsGlobalization.GetLocaleInfo(cultureName, localeName, buffer, LOCALE_INFO_BUFFER_LEN, out int exception, out object exResult); - if (exception != 0) - throw new Exception((string)exResult); - string result = new string(buffer, 0, resultLength); - string[] subresults = result.Split("##"); - if (subresults.Length == 0) - throw new Exception("LocaleInfo recieved from the Browser is in incorrect format."); - if (subresults.Length == 1) - return (subresults[0], ""); // Neutral culture - return (subresults[0], subresults[1]); + ReadOnlySpan cultureNameSpan = cultureName.AsSpan(); + ReadOnlySpan localeNameSpan = localeName.AsSpan(); + fixed (char* pCultureName = &MemoryMarshal.GetReference(cultureNameSpan)) + fixed (char* pLocaleName = &MemoryMarshal.GetReference(localeNameSpan)) + { + char* buffer = stackalloc char[LOCALE_INFO_BUFFER_LEN]; + nint exceptionPtr = Interop.JsGlobalization.GetLocaleInfo(pCultureName, cultureNameSpan.Length, pLocaleName, localeNameSpan.Length, buffer, LOCALE_INFO_BUFFER_LEN, out int resultLength); + Helper.MarshalAndThrowIfException(exceptionPtr); + string result = new string(buffer, 0, resultLength); + string[] subresults = result.Split("##"); + if (subresults.Length == 0) + throw new Exception("LocaleInfo recieved from the Browser is in incorrect format."); + if (subresults.Length == 1) + return (subresults[0], ""); // Neutral culture + return (subresults[0], subresults[1]); + } } private string JSGetNativeDisplayName(string localeName, string cultureName) @@ -64,43 +70,82 @@ private string JSGetNativeDisplayName(string localeName, string cultureName) private static unsafe CultureData JSLoadCultureInfoFromBrowser(string localeName, CultureData culture) { - char* buffer = stackalloc char[CULTURE_INFO_BUFFER_LEN]; - int resultLength = Interop.JsGlobalization.GetCultureInfo(localeName, buffer, CULTURE_INFO_BUFFER_LEN, out int exception, out object exResult); - if (exception != 0) - throw new Exception((string)exResult); - string result = new string(buffer, 0, resultLength); - string[] subresults = result.Split("##"); - if (subresults.Length < 4) - throw new Exception("CultureInfo recieved from the Browser is in incorrect format."); - culture._sAM1159 = subresults[0]; - culture._sPM2359 = subresults[1]; - culture._saLongTimes = new string[] { subresults[2] }; - culture._saShortTimes = new string[] { subresults[3] }; + ReadOnlySpan localeNameSpan = localeName.AsSpan(); + fixed (char* pLocaleName = &MemoryMarshal.GetReference(localeNameSpan)) + { + char* buffer = stackalloc char[CULTURE_INFO_BUFFER_LEN]; + nint exceptionPtr = Interop.JsGlobalization.GetCultureInfo(pLocaleName, localeNameSpan.Length, buffer, CULTURE_INFO_BUFFER_LEN, out int resultLength); + Helper.MarshalAndThrowIfException(exceptionPtr); + string result = new string(buffer, 0, resultLength); + string[] subresults = result.Split("##"); + if (subresults.Length < 4) + throw new Exception("CultureInfo recieved from the Browser is in incorrect format."); + culture._sAM1159 = subresults[0]; + culture._sPM2359 = subresults[1]; + culture._saLongTimes = new string[] { subresults[2] }; + culture._saShortTimes = new string[] { subresults[3] }; + } return culture; } private static unsafe int GetFirstDayOfWeek(string localeName) { - int result = Interop.JsGlobalization.GetFirstDayOfWeek(localeName, out int exception, out object ex_result); - if (exception != 0) + ReadOnlySpan localeNameSpan = localeName.AsSpan(); + fixed (char* pLocaleName = &MemoryMarshal.GetReference(localeNameSpan)) { - // Failed, just use 0 - Debug.Fail($"[CultureData.GetFirstDayOfWeek()] failed with {ex_result}"); - return 0; + nint exceptionPtr = Interop.JsGlobalization.GetFirstDayOfWeek(pLocaleName, localeNameSpan.Length, out int result); + if (exceptionPtr != IntPtr.Zero) + { + int success = Helper.MarshalAndThrowIfException( + exceptionPtr, + failOnlyDebug: true, + failureMessage: $"[CultureData.GetFirstDayOfWeek()] failed with"); + // Failed, just use 0 + if (success == -1) + return 0; + } + return result; } - return result; } private static unsafe int GetFirstWeekOfYear(string localeName) { - int result = Interop.JsGlobalization.GetFirstWeekOfYear(localeName, out int exception, out object ex_result); - if (exception != 0) + ReadOnlySpan localeNameSpan = localeName.AsSpan(); + fixed (char* pLocaleName = &MemoryMarshal.GetReference(localeNameSpan)) + { + nint exceptionPtr = Interop.JsGlobalization.GetFirstWeekOfYear(pLocaleName, localeNameSpan.Length, out int result); + if (exceptionPtr != IntPtr.Zero) + { + int success = Helper.MarshalAndThrowIfException( + exceptionPtr, + failOnlyDebug: true, + failureMessage: $"[CultureData.GetFirstWeekOfYear()] failed with"); + // Failed, just use 0 + if (success == -1) + return 0; + } + return result; + } + } + } + + internal static class Helper + { + internal static int MarshalAndThrowIfException(nint exceptionPtr, bool failOnlyDebug = false, string failureMessage = "") + { + if (exceptionPtr != IntPtr.Zero) { - // Failed, just use 0 - Debug.Fail($"[CultureData.GetFirstDayOfWeek()] failed with {ex_result}"); - return 0; + string message = Marshal.PtrToStringUni(exceptionPtr)!; + Marshal.FreeHGlobal(exceptionPtr); + if (failOnlyDebug) + { + Debug.Fail($"{failureMessage} {message}"); + return -1; + } + throw new Exception(message); } - return result; + return 0; } + } } diff --git a/src/libraries/System.Private.CoreLib/src/System/Globalization/TextInfo.WebAssembly.cs b/src/libraries/System.Private.CoreLib/src/System/Globalization/TextInfo.WebAssembly.cs index a2dd2a02c05f18..05e8cc3e1d0495 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Globalization/TextInfo.WebAssembly.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Globalization/TextInfo.WebAssembly.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Diagnostics; +using System.Runtime.InteropServices; namespace System.Globalization { @@ -13,18 +14,14 @@ internal unsafe void JsChangeCase(char* src, int srcLen, char* dstBuffer, int ds Debug.Assert(!GlobalizationMode.UseNls); Debug.Assert(GlobalizationMode.Hybrid); - int exception; - object ex_result; - if (HasEmptyCultureName) + ReadOnlySpan cultureName = _cultureName.AsSpan(); + fixed (char* pCultureName = &MemoryMarshal.GetReference(cultureName)) { - Interop.JsGlobalization.ChangeCaseInvariant(src, srcLen, dstBuffer, dstBufferCapacity, toUpper, out exception, out ex_result); + nint exceptionPtr = HasEmptyCultureName ? + Interop.JsGlobalization.ChangeCaseInvariant(src, srcLen, dstBuffer, dstBufferCapacity, toUpper) : + Interop.JsGlobalization.ChangeCase(pCultureName, cultureName.Length, src, srcLen, dstBuffer, dstBufferCapacity, toUpper); + Helper.MarshalAndThrowIfException(exceptionPtr); } - else - { - Interop.JsGlobalization.ChangeCase(_cultureName, src, srcLen, dstBuffer, dstBufferCapacity, toUpper, out exception, out ex_result); - } - if (exception != 0) - throw new Exception((string)ex_result); } } } diff --git a/src/mono/browser/runtime/corebindings.c b/src/mono/browser/runtime/corebindings.c index a6642a06d69fc8..39b25e5bff333d 100644 --- a/src/mono/browser/runtime/corebindings.c +++ b/src/mono/browser/runtime/corebindings.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #include @@ -58,17 +59,17 @@ extern void mono_wasm_invoke_jsimport_ST (int function_handle, void *args); #endif /* DISABLE_THREADS */ // HybridGlobalization -extern void mono_wasm_change_case_invariant (const uint16_t* src, int32_t srcLength, uint16_t* dst, int32_t dstLength, mono_bool bToUpper, int *is_exception, MonoObject** ex_result); -extern void mono_wasm_change_case (MonoString **culture, const uint16_t* src, int32_t srcLength, uint16_t* dst, int32_t dstLength, mono_bool bToUpper, int *is_exception, MonoObject** ex_result); -extern int mono_wasm_compare_string (MonoString **culture, const uint16_t* str1, int32_t str1Length, const uint16_t* str2, int32_t str2Length, int32_t options, int *is_exception, MonoObject** ex_result); -extern mono_bool mono_wasm_starts_with (MonoString **culture, const uint16_t* str1, int32_t str1Length, const uint16_t* str2, int32_t str2Length, int32_t options, int *is_exception, MonoObject** ex_result); -extern mono_bool mono_wasm_ends_with (MonoString **culture, const uint16_t* str1, int32_t str1Length, const uint16_t* str2, int32_t str2Length, int32_t options, int *is_exception, MonoObject** ex_result); -extern int mono_wasm_index_of (MonoString **culture, const uint16_t* str1, int32_t str1Length, const uint16_t* str2, int32_t str2Length, int32_t options, mono_bool fromBeginning, int *is_exception, MonoObject** ex_result); -extern int mono_wasm_get_calendar_info (MonoString **culture, int32_t calendarId, const uint16_t* result, int32_t resultLength, int *is_exception, MonoObject** ex_result); -extern int mono_wasm_get_locale_info (MonoString **locale, MonoString **culture, const uint16_t* result, int32_t resultLength, int *is_exception, MonoObject** ex_result); -extern int mono_wasm_get_culture_info (MonoString **culture, const uint16_t* result, int32_t resultLength, int *is_exception, MonoObject** ex_result); -extern int mono_wasm_get_first_day_of_week (MonoString **culture, int *is_exception, MonoObject** ex_result); -extern int mono_wasm_get_first_week_of_year (MonoString **culture, int *is_exception, MonoObject** ex_result); +extern char16_t* mono_wasm_change_case_invariant (const uint16_t* src, int32_t srcLength, uint16_t* dst, int32_t dstLength, mono_bool bToUpper); +extern char16_t* mono_wasm_change_case (const uint16_t* culture, int32_t cultureLength, const uint16_t* src, int32_t srcLength, uint16_t* dst, int32_t dstLength, mono_bool bToUpper); +extern char16_t* mono_wasm_compare_string (const uint16_t* culture, int32_t cultureLength, const uint16_t* str1, int32_t str1Length, const uint16_t* str2, int32_t str2Length, int32_t options, int *resultPtr); +extern char16_t* mono_wasm_starts_with (const uint16_t* culture, int32_t cultureLength, const uint16_t* str1, int32_t str1Length, const uint16_t* str2, int32_t str2Length, int32_t options, mono_bool *resultPtr); +extern char16_t* mono_wasm_ends_with (const uint16_t* culture, int32_t cultureLength, const uint16_t* str1, int32_t str1Length, const uint16_t* str2, int32_t str2Length, int32_t options, mono_bool *resultPtr); +extern char16_t* mono_wasm_index_of (const uint16_t* culture, int32_t cultureLength, const uint16_t* str1, int32_t str1Length, const uint16_t* str2, int32_t str2Length, int32_t options, mono_bool fromBeginning, int *resultPtr); +extern char16_t* mono_wasm_get_calendar_info (const uint16_t* culture, int32_t cultureLength, int32_t calendarId, const uint16_t* result, int32_t resultMaxLength, int *resultLength); +extern char16_t* mono_wasm_get_culture_info (const uint16_t* culture, int32_t cultureLength, const uint16_t* result, int32_t resultMaxLength, int *resultLength); +extern char16_t* mono_wasm_get_locale_info (const uint16_t* locale, int32_t localeLength, const uint16_t* culture, int32_t cultureLength, const uint16_t* result, int32_t resultMaxLength, int *resultLength); +extern char16_t* mono_wasm_get_first_day_of_week (const uint16_t* culture, int32_t cultureLength, int *resultPtr); +extern char16_t* mono_wasm_get_first_week_of_year (const uint16_t* culture, int32_t cultureLength, int *resultPtr); void bindings_initialize_internals (void) { diff --git a/src/mono/browser/runtime/hybrid-globalization/calendar.ts b/src/mono/browser/runtime/hybrid-globalization/calendar.ts index d3944f514ce854..2d87d1c085cc04 100644 --- a/src/mono/browser/runtime/hybrid-globalization/calendar.ts +++ b/src/mono/browser/runtime/hybrid-globalization/calendar.ts @@ -2,23 +2,20 @@ // The .NET Foundation licenses this file to you under the MIT license. /* eslint-disable no-inner-declarations */ -import { mono_wasm_new_external_root } from "../roots"; -import { monoStringToString, stringToUTF16 } from "../strings"; -import { MonoObject, MonoObjectRef, MonoString, MonoStringRef } from "../types/internal"; -import { Int32Ptr } from "../types/emscripten"; -import { wrap_error_root, wrap_no_error_root } from "./helpers"; +import { stringToUTF16, stringToUTF16Ptr, utf16ToString } from "../strings"; +import { VoidPtrNull } from "../types/internal"; +import { Int32Ptr, VoidPtr } from "../types/emscripten"; import { INNER_SEPARATOR, OUTER_SEPARATOR, normalizeSpaces } from "./helpers"; +import { setI32 } from "../memory"; const MONTH_CODE = "MMMM"; const YEAR_CODE = "yyyy"; const DAY_CODE = "d"; // this function joins all calendar info with OUTER_SEPARATOR into one string and returns it back to managed code -export function mono_wasm_get_calendar_info (culture: MonoStringRef, calendarId: number, dst: number, dstLength: number, isException: Int32Ptr, exAddress: MonoObjectRef): number { - const cultureRoot = mono_wasm_new_external_root(culture), - exceptionRoot = mono_wasm_new_external_root(exAddress); +export function mono_wasm_get_calendar_info (culture: number, cultureLength: number, calendarId: number, dst: number, dstMaxLength: number, dstLength: Int32Ptr): VoidPtr { try { - const cultureName = monoStringToString(cultureRoot); + const cultureName = utf16ToString(culture, (culture + 2 * cultureLength)); const locale = cultureName ? cultureName : undefined; const calendarInfo = { EnglishName: "", @@ -56,18 +53,14 @@ export function mono_wasm_get_calendar_info (culture: MonoStringRef, calendarId: calendarInfo.AbbreviatedEraNames = eraNames.abbreviatedEraNames; const result = Object.values(calendarInfo).join(OUTER_SEPARATOR); - if (result.length > dstLength) { - throw new Error(`Calendar info exceeds length of ${dstLength}.`); + if (result.length > dstMaxLength) { + throw new Error(`Calendar info exceeds length of ${dstMaxLength}.`); } stringToUTF16(dst, dst + 2 * result.length, result); - wrap_no_error_root(isException, exceptionRoot); - return result.length; + setI32(dstLength, result.length); + return VoidPtrNull; } catch (ex: any) { - wrap_error_root(isException, ex, exceptionRoot); - return -1; - } finally { - cultureRoot.release(); - exceptionRoot.release(); + return stringToUTF16Ptr(ex.toString()); } } diff --git a/src/mono/browser/runtime/hybrid-globalization/change-case.ts b/src/mono/browser/runtime/hybrid-globalization/change-case.ts index 762eacc94c26bc..437aabb42bfcd2 100644 --- a/src/mono/browser/runtime/hybrid-globalization/change-case.ts +++ b/src/mono/browser/runtime/hybrid-globalization/change-case.ts @@ -1,16 +1,13 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -import { mono_wasm_new_external_root } from "../roots"; -import { monoStringToString, utf16ToStringLoop, stringToUTF16 } from "../strings"; -import { MonoObject, MonoObjectRef, MonoString, MonoStringRef } from "../types/internal"; -import { Int32Ptr } from "../types/emscripten"; -import { wrap_error_root, wrap_no_error_root } from "./helpers"; +import { utf16ToStringLoop, stringToUTF16, stringToUTF16Ptr, utf16ToString } from "../strings"; +import { VoidPtrNull } from "../types/internal"; +import { VoidPtr } from "../types/emscripten"; import { localHeapViewU16, setU16_local } from "../memory"; import { isSurrogate } from "./helpers"; -export function mono_wasm_change_case_invariant (src: number, srcLength: number, dst: number, dstLength: number, toUpper: number, is_exception: Int32Ptr, ex_address: MonoObjectRef): void { - const exceptionRoot = mono_wasm_new_external_root(ex_address); +export function mono_wasm_change_case_invariant (src: number, srcLength: number, dst: number, dstLength: number, toUpper: number): VoidPtr { try { const input = utf16ToStringLoop(src, src + 2 * srcLength); const result = toUpper ? input.toUpperCase() : input.toLowerCase(); @@ -18,8 +15,7 @@ export function mono_wasm_change_case_invariant (src: number, srcLength: number, // originally we do not support this expansion if (result.length <= dstLength) { stringToUTF16(dst, dst + 2 * dstLength, result); - wrap_no_error_root(is_exception, exceptionRoot); - return; + return VoidPtrNull; } // workaround to maintain the ICU-like behavior @@ -59,19 +55,15 @@ export function mono_wasm_change_case_invariant (src: number, srcLength: number, } } } - wrap_no_error_root(is_exception, exceptionRoot); + return VoidPtrNull; } catch (ex: any) { - wrap_error_root(is_exception, ex, exceptionRoot); - } finally { - exceptionRoot.release(); + return stringToUTF16Ptr(ex.toString()); } } -export function mono_wasm_change_case (culture: MonoStringRef, src: number, srcLength: number, dst: number, dstLength: number, toUpper: number, is_exception: Int32Ptr, ex_address: MonoObjectRef): void { - const cultureRoot = mono_wasm_new_external_root(culture), - exceptionRoot = mono_wasm_new_external_root(ex_address); +export function mono_wasm_change_case (culture: number, cultureLength: number, src: number, srcLength: number, dst: number, dstLength: number, toUpper: number): VoidPtr { try { - const cultureName = monoStringToString(cultureRoot); + const cultureName = utf16ToString(culture, (culture + 2 * cultureLength)); if (!cultureName) throw new Error("Cannot change case, the culture name is null."); const input = utf16ToStringLoop(src, src + 2 * srcLength); @@ -79,8 +71,7 @@ export function mono_wasm_change_case (culture: MonoStringRef, src: number, srcL if (result.length <= input.length) { stringToUTF16(dst, dst + 2 * dstLength, result); - wrap_no_error_root(is_exception, exceptionRoot); - return; + return VoidPtrNull; } // workaround to maintain the ICU-like behavior const heapI16 = localHeapViewU16(); @@ -119,12 +110,9 @@ export function mono_wasm_change_case (culture: MonoStringRef, src: number, srcL } } } - wrap_no_error_root(is_exception, exceptionRoot); + return VoidPtrNull; } catch (ex: any) { - wrap_error_root(is_exception, ex, exceptionRoot); - } finally { - cultureRoot.release(); - exceptionRoot.release(); + return stringToUTF16Ptr(ex.toString()); } } diff --git a/src/mono/browser/runtime/hybrid-globalization/collations.ts b/src/mono/browser/runtime/hybrid-globalization/collations.ts index 523f63307e278c..b329b39b15d0e1 100644 --- a/src/mono/browser/runtime/hybrid-globalization/collations.ts +++ b/src/mono/browser/runtime/hybrid-globalization/collations.ts @@ -1,113 +1,106 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -import { mono_wasm_new_external_root } from "../roots"; -import { monoStringToString, utf16ToString } from "../strings"; -import { MonoObject, MonoObjectRef, MonoString, MonoStringRef } from "../types/internal"; -import { Int32Ptr } from "../types/emscripten"; -import { wrap_error_root, wrap_no_error_root } from "./helpers"; +import { stringToUTF16Ptr, utf16ToString } from "../strings"; +import { VoidPtrNull } from "../types/internal"; +import { Int32Ptr, VoidPtr } from "../types/emscripten"; import { GraphemeSegmenter } from "./grapheme-segmenter"; +import { setI32 } from "../memory"; const COMPARISON_ERROR = -2; const INDEXING_ERROR = -1; let graphemeSegmenterCached: GraphemeSegmenter | null; -export function mono_wasm_compare_string (culture: MonoStringRef, str1: number, str1Length: number, str2: number, str2Length: number, options: number, is_exception: Int32Ptr, ex_address: MonoObjectRef): number { - const cultureRoot = mono_wasm_new_external_root(culture), - exceptionRoot = mono_wasm_new_external_root(ex_address); +export function mono_wasm_compare_string (culture: number, cultureLength: number, str1: number, str1Length: number, str2: number, str2Length: number, options: number, resultPtr: Int32Ptr): VoidPtr { try { - const cultureName = monoStringToString(cultureRoot); + const cultureName = utf16ToString(culture, (culture + 2 * cultureLength)); const string1 = utf16ToString(str1, (str1 + 2 * str1Length)); const string2 = utf16ToString(str2, (str2 + 2 * str2Length)); const casePicker = (options & 0x1f); const locale = cultureName ? cultureName : undefined; - wrap_no_error_root(is_exception, exceptionRoot); - return compareStrings(string1, string2, locale, casePicker); + const result = compareStrings(string1, string2, locale, casePicker); + setI32(resultPtr, result); + return VoidPtrNull; } catch (ex: any) { - wrap_error_root(is_exception, ex, exceptionRoot); - return COMPARISON_ERROR; - } finally { - cultureRoot.release(); - exceptionRoot.release(); + setI32(resultPtr, COMPARISON_ERROR); + return stringToUTF16Ptr(ex.toString()); } } -export function mono_wasm_starts_with (culture: MonoStringRef, str1: number, str1Length: number, str2: number, str2Length: number, options: number, is_exception: Int32Ptr, ex_address: MonoObjectRef): number { - const cultureRoot = mono_wasm_new_external_root(culture), - exceptionRoot = mono_wasm_new_external_root(ex_address); +export function mono_wasm_starts_with (culture: number, cultureLength: number, str1: number, str1Length: number, str2: number, str2Length: number, options: number, resultPtr: Int32Ptr): VoidPtr { try { - const cultureName = monoStringToString(cultureRoot); + const cultureName = utf16ToString(culture, (culture + 2 * cultureLength)); const prefix = decodeToCleanString(str2, str2Length); // no need to look for an empty string - if (prefix.length == 0) - return 1; // true + if (prefix.length == 0) { + setI32(resultPtr, 1); // true + return VoidPtrNull; + } const source = decodeToCleanString(str1, str1Length); - if (source.length < prefix.length) - return 0; //false + if (source.length < prefix.length) { + setI32(resultPtr, 0); // false + return VoidPtrNull; + } const sourceOfPrefixLength = source.slice(0, prefix.length); const casePicker = (options & 0x1f); const locale = cultureName ? cultureName : undefined; - const result = compareStrings(sourceOfPrefixLength, prefix, locale, casePicker); - wrap_no_error_root(is_exception, exceptionRoot); - return result === 0 ? 1 : 0; // equals ? true : false + const cmpResult = compareStrings(sourceOfPrefixLength, prefix, locale, casePicker); + const result = cmpResult === 0 ? 1 : 0; // equals ? true : false + setI32(resultPtr, result); + return VoidPtrNull; } catch (ex: any) { - wrap_error_root(is_exception, ex, exceptionRoot); - return INDEXING_ERROR; - } finally { - cultureRoot.release(); - exceptionRoot.release(); + setI32(resultPtr, INDEXING_ERROR); + return stringToUTF16Ptr(ex.toString()); } } -export function mono_wasm_ends_with (culture: MonoStringRef, str1: number, str1Length: number, str2: number, str2Length: number, options: number, is_exception: Int32Ptr, ex_address: MonoObjectRef): number { - const cultureRoot = mono_wasm_new_external_root(culture), - exceptionRoot = mono_wasm_new_external_root(ex_address); +export function mono_wasm_ends_with (culture: number, cultureLength: number, str1: number, str1Length: number, str2: number, str2Length: number, options: number, resultPtr: Int32Ptr): VoidPtr { try { - const cultureName = monoStringToString(cultureRoot); + const cultureName = utf16ToString(culture, (culture + 2 * cultureLength)); const suffix = decodeToCleanString(str2, str2Length); - if (suffix.length == 0) - return 1; // true + if (suffix.length == 0) { + setI32(resultPtr, 1); // true + return VoidPtrNull; + } const source = decodeToCleanString(str1, str1Length); const diff = source.length - suffix.length; - if (diff < 0) - return 0; //false + if (diff < 0) { + setI32(resultPtr, 0); // false + return VoidPtrNull; + } const sourceOfSuffixLength = source.slice(diff, source.length); const casePicker = (options & 0x1f); const locale = cultureName ? cultureName : undefined; - const result = compareStrings(sourceOfSuffixLength, suffix, locale, casePicker); - wrap_no_error_root(is_exception, exceptionRoot); - return result === 0 ? 1 : 0; // equals ? true : false + const cmpResult = compareStrings(sourceOfSuffixLength, suffix, locale, casePicker); + const result = cmpResult === 0 ? 1 : 0; // equals ? true : false + setI32(resultPtr, result); + return VoidPtrNull; } catch (ex: any) { - wrap_error_root(is_exception, ex, exceptionRoot); - return INDEXING_ERROR; - } finally { - cultureRoot.release(); - exceptionRoot.release(); + setI32(resultPtr, INDEXING_ERROR); + return stringToUTF16Ptr(ex.toString()); } } -export function mono_wasm_index_of (culture: MonoStringRef, needlePtr: number, needleLength: number, srcPtr: number, srcLength: number, options: number, fromBeginning: number, is_exception: Int32Ptr, ex_address: MonoObjectRef): number { - const cultureRoot = mono_wasm_new_external_root(culture), - exceptionRoot = mono_wasm_new_external_root(ex_address); +export function mono_wasm_index_of (culture: number, cultureLength: number, needlePtr: number, needleLength: number, srcPtr: number, srcLength: number, options: number, fromBeginning: number, resultPtr: Int32Ptr): VoidPtr { try { const needle = utf16ToString(needlePtr, (needlePtr + 2 * needleLength)); // no need to look for an empty string if (cleanString(needle).length == 0) { - wrap_no_error_root(is_exception, exceptionRoot); - return fromBeginning ? 0 : srcLength; + setI32(resultPtr, fromBeginning ? 0 : srcLength); + return VoidPtrNull; } const source = utf16ToString(srcPtr, (srcPtr + 2 * srcLength)); // no need to look in an empty string if (cleanString(source).length == 0) { - wrap_no_error_root(is_exception, exceptionRoot); - return fromBeginning ? 0 : srcLength; + setI32(resultPtr, fromBeginning ? 0 : srcLength); + return VoidPtrNull; } - const cultureName = monoStringToString(cultureRoot); + const cultureName = utf16ToString(culture, (culture + 2 * cultureLength)); const locale = cultureName ? cultureName : undefined; const casePicker = (options & 0x1f); let result = -1; @@ -148,14 +141,11 @@ export function mono_wasm_index_of (culture: MonoStringRef, needlePtr: number, n break; } } - wrap_no_error_root(is_exception, exceptionRoot); - return result; + setI32(resultPtr, result); + return VoidPtrNull; } catch (ex: any) { - wrap_error_root(is_exception, ex, exceptionRoot); - return INDEXING_ERROR; - } finally { - cultureRoot.release(); - exceptionRoot.release(); + setI32(resultPtr, INDEXING_ERROR); + return stringToUTF16Ptr(ex.toString()); } function checkMatchFound (str1: string, str2: string, locale: string | undefined, casePicker: number): boolean { diff --git a/src/mono/browser/runtime/hybrid-globalization/culture-info.ts b/src/mono/browser/runtime/hybrid-globalization/culture-info.ts index 03bebd9ec65ee2..70b36296407bbb 100644 --- a/src/mono/browser/runtime/hybrid-globalization/culture-info.ts +++ b/src/mono/browser/runtime/hybrid-globalization/culture-info.ts @@ -1,18 +1,15 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -import { wrap_error_root, wrap_no_error_root } from "./helpers"; -import { mono_wasm_new_external_root } from "../roots"; -import { monoStringToString, stringToUTF16 } from "../strings"; -import { Int32Ptr } from "../types/emscripten"; -import { MonoObject, MonoObjectRef, MonoString, MonoStringRef } from "../types/internal"; +import { setI32 } from "../memory"; +import { stringToUTF16, stringToUTF16Ptr, utf16ToString } from "../strings"; +import { Int32Ptr, VoidPtr } from "../types/emscripten"; +import { VoidPtrNull } from "../types/internal"; import { OUTER_SEPARATOR, normalizeLocale, normalizeSpaces } from "./helpers"; -export function mono_wasm_get_culture_info (culture: MonoStringRef, dst: number, dstLength: number, isException: Int32Ptr, exAddress: MonoObjectRef): number { - const cultureRoot = mono_wasm_new_external_root(culture), - exceptionRoot = mono_wasm_new_external_root(exAddress); +export function mono_wasm_get_culture_info (culture: number, cultureLength: number, dst: number, dstMaxLength: number, dstLength: Int32Ptr): VoidPtr { try { - const cultureName = monoStringToString(cultureRoot); + const cultureName = utf16ToString(culture, (culture + 2 * cultureLength)); const cultureInfo = { AmDesignator: "", PmDesignator: "", @@ -26,18 +23,15 @@ export function mono_wasm_get_culture_info (culture: MonoStringRef, dst: number, cultureInfo.LongTimePattern = getLongTimePattern(canonicalLocale, designators); cultureInfo.ShortTimePattern = getShortTimePattern(cultureInfo.LongTimePattern); const result = Object.values(cultureInfo).join(OUTER_SEPARATOR); - if (result.length > dstLength) { - throw new Error(`Culture info exceeds length of ${dstLength}.`); + if (result.length > dstMaxLength) { + throw new Error(`Culture info exceeds length of ${dstMaxLength}.`); } stringToUTF16(dst, dst + 2 * result.length, result); - wrap_no_error_root(isException, exceptionRoot); - return result.length; + setI32(dstLength, result.length); + return VoidPtrNull; } catch (ex: any) { - wrap_error_root(isException, ex, exceptionRoot); - return -1; - } finally { - cultureRoot.release(); - exceptionRoot.release(); + setI32(dstLength, -1); + return stringToUTF16Ptr(ex.toString()); } } diff --git a/src/mono/browser/runtime/hybrid-globalization/helpers.ts b/src/mono/browser/runtime/hybrid-globalization/helpers.ts index 74134c4ca3cc1d..0cd2294447226f 100644 --- a/src/mono/browser/runtime/hybrid-globalization/helpers.ts +++ b/src/mono/browser/runtime/hybrid-globalization/helpers.ts @@ -1,12 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -import { normalize_exception } from "../invoke-js"; -import { receiveWorkerHeapViews, setI32_unchecked } from "../memory"; -import { stringToMonoStringRoot } from "../strings"; -import { Int32Ptr } from "../types/emscripten"; -import { MonoObject, WasmRoot } from "../types/internal"; - const SURROGATE_HIGHER_START = "\uD800"; const SURROGATE_HIGHER_END = "\uDBFF"; const SURROGATE_LOWER_START = "\uDC00"; @@ -48,29 +42,3 @@ export function isSurrogate (str: string, startIdx: number): boolean { SURROGATE_LOWER_START <= str[startIdx + 1] && str[startIdx + 1] <= SURROGATE_LOWER_END; } - -function _wrap_error_flag (is_exception: Int32Ptr | null, ex: any): string { - const res = normalize_exception(ex); - if (is_exception) { - receiveWorkerHeapViews(); - setI32_unchecked(is_exception, 1); - } - return res; -} - -export function wrap_error_root (is_exception: Int32Ptr | null, ex: any, result: WasmRoot): void { - const res = _wrap_error_flag(is_exception, ex); - stringToMonoStringRoot(res, result); -} - -// TODO replace it with replace it with UTF16 char*, no GC root needed -// https://github.com/dotnet/runtime/issues/98365 -export function wrap_no_error_root (is_exception: Int32Ptr | null, result?: WasmRoot): void { - if (is_exception) { - receiveWorkerHeapViews(); - setI32_unchecked(is_exception, 0); - } - if (result) { - result.clear(); - } -} diff --git a/src/mono/browser/runtime/hybrid-globalization/locales.ts b/src/mono/browser/runtime/hybrid-globalization/locales.ts index 252dfe1badf9e2..da6a478d1e3931 100644 --- a/src/mono/browser/runtime/hybrid-globalization/locales.ts +++ b/src/mono/browser/runtime/hybrid-globalization/locales.ts @@ -1,27 +1,23 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -import { wrap_error_root, wrap_no_error_root } from "./helpers"; -import { mono_wasm_new_external_root } from "../roots"; -import { monoStringToString, stringToUTF16 } from "../strings"; -import { Int32Ptr } from "../types/emscripten"; -import { MonoObject, MonoObjectRef, MonoString, MonoStringRef } from "../types/internal"; +import { setI32 } from "../memory"; +import { stringToUTF16, stringToUTF16Ptr, utf16ToString } from "../strings"; +import { Int32Ptr, VoidPtr } from "../types/emscripten"; +import { VoidPtrNull } from "../types/internal"; import { OUTER_SEPARATOR, normalizeLocale } from "./helpers"; -export function mono_wasm_get_locale_info (culture: MonoStringRef, locale: MonoStringRef, dst: number, dstLength: number, isException: Int32Ptr, exAddress: MonoObjectRef): number { - const localeRoot = mono_wasm_new_external_root(locale), - cultureRoot = mono_wasm_new_external_root(culture), - exceptionRoot = mono_wasm_new_external_root(exAddress); +export function mono_wasm_get_locale_info (culture: number, cultureLength: number, locale: number, localeLength: number, dst: number, dstMaxLength: number, dstLength: Int32Ptr): VoidPtr { try { - const localeNameOriginal = monoStringToString(localeRoot); + const localeNameOriginal = utf16ToString(locale, (locale + 2 * localeLength)); const localeName = normalizeLocale(localeNameOriginal); if (!localeName && localeNameOriginal) { // handle non-standard or malformed locales by forwarding the locale code stringToUTF16(dst, dst + 2 * localeNameOriginal.length, localeNameOriginal); - wrap_no_error_root(isException, exceptionRoot); - return localeNameOriginal.length; + setI32(dstLength, localeNameOriginal.length); + return VoidPtrNull; } - const cultureNameOriginal = monoStringToString(cultureRoot); + const cultureNameOriginal = utf16ToString(culture, (culture + 2 * cultureLength)); const cultureName = normalizeLocale(cultureNameOriginal); if (!localeName || !cultureName) @@ -49,8 +45,8 @@ export function mono_wasm_get_locale_info (culture: MonoStringRef, locale: MonoS if (error instanceof RangeError && error.message === "invalid_argument" && localeNameOriginal) { // handle non-standard or malformed locales by forwarding the locale code, e.g. "xx-u-xx" stringToUTF16(dst, dst + 2 * localeNameOriginal.length, localeNameOriginal); - wrap_no_error_root(isException, exceptionRoot); - return localeNameOriginal.length; + setI32(dstLength, localeNameOriginal.length); + return VoidPtrNull; } throw error; } @@ -67,54 +63,41 @@ export function mono_wasm_get_locale_info (culture: MonoStringRef, locale: MonoS if (!result) throw new Error(`Locale info for locale=${localeName} is null or empty.`); - if (result.length > dstLength) - throw new Error(`Locale info for locale=${localeName} exceeds length of ${dstLength}.`); + if (result.length > dstMaxLength) + throw new Error(`Locale info for locale=${localeName} exceeds length of ${dstMaxLength}.`); stringToUTF16(dst, dst + 2 * result.length, result); - wrap_no_error_root(isException, exceptionRoot); - return result.length; + setI32(dstLength, result.length); + return VoidPtrNull; } catch (ex: any) { - wrap_error_root(isException, ex, exceptionRoot); - return -1; - } finally { - cultureRoot.release(); - exceptionRoot.release(); + setI32(dstLength, -1); + return stringToUTF16Ptr(ex.toString()); } } -export function mono_wasm_get_first_day_of_week (culture: MonoStringRef, isException: Int32Ptr, exAddress: MonoObjectRef): number { - - const cultureRoot = mono_wasm_new_external_root(culture), - exceptionRoot = mono_wasm_new_external_root(exAddress); +export function mono_wasm_get_first_day_of_week (culture: number, cultureLength: number, resultPtr: Int32Ptr): VoidPtr { try { - const cultureName = monoStringToString(cultureRoot); + const cultureName = utf16ToString(culture, (culture + 2 * cultureLength)); const canonicalLocale = normalizeLocale(cultureName); - wrap_no_error_root(isException, exceptionRoot); - return getFirstDayOfWeek(canonicalLocale); + const result = getFirstDayOfWeek(canonicalLocale); + setI32(resultPtr, result); + return VoidPtrNull; } catch (ex: any) { - wrap_error_root(isException, ex, exceptionRoot); - return -1; - } finally { - cultureRoot.release(); - exceptionRoot.release(); + setI32(resultPtr, -1); + return stringToUTF16Ptr(ex.toString()); } } -export function mono_wasm_get_first_week_of_year (culture: MonoStringRef, isException: Int32Ptr, exAddress: MonoObjectRef): number { - - const cultureRoot = mono_wasm_new_external_root(culture), - exceptionRoot = mono_wasm_new_external_root(exAddress); +export function mono_wasm_get_first_week_of_year (culture: number, cultureLength: number, resultPtr: Int32Ptr): VoidPtr { try { - const cultureName = monoStringToString(cultureRoot); + const cultureName = utf16ToString(culture, (culture + 2 * cultureLength)); const canonicalLocale = normalizeLocale(cultureName); - wrap_no_error_root(isException, exceptionRoot); - return getFirstWeekOfYear(canonicalLocale); + const result = getFirstWeekOfYear(canonicalLocale); + setI32(resultPtr, result); + return VoidPtrNull; } catch (ex: any) { - wrap_error_root(isException, ex, exceptionRoot); - return -1; - } finally { - cultureRoot.release(); - exceptionRoot.release(); + setI32(resultPtr, -1); + return stringToUTF16Ptr(ex.toString()); } } From 7d91bf56ec48329ac3ed65c35fdfa9b6fd81c2d3 Mon Sep 17 00:00:00 2001 From: Stephen Toub Date: Tue, 23 Apr 2024 12:06:53 -0400 Subject: [PATCH 036/161] Fix incorrect suffix search for alternation with RegexOptions.RightToLeft (#101408) * Fix incorrect suffix search for alternation with RegexOptions.RightToLeft Our limited RegexOptions.RightToLeft support for prefix optimizations is mishandling alternations. For RTL, this actually needs to create a suffix, but for alternations, we were actually creating a prefix. As this option is rarely used and it's not worth significant investment in optimizing, the fix is just to disable the handling of alternations for RTL, as the support has been broken since it was introduced in .NET 7. * Fix new tests * Avoid annoying skip message --- .../RegularExpressions/RegexPrefixAnalyzer.cs | 2 +- .../Regex.CompileToAssembly.Tests.cs | 93 +++++++++---------- .../FunctionalTests/Regex.Match.Tests.cs | 5 + .../UnitTests/RegexFindOptimizationsTests.cs | 2 +- 4 files changed, 53 insertions(+), 49 deletions(-) diff --git a/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexPrefixAnalyzer.cs b/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexPrefixAnalyzer.cs index 926a28339162f6..b46af7b1b9d066 100644 --- a/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexPrefixAnalyzer.cs +++ b/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexPrefixAnalyzer.cs @@ -359,7 +359,7 @@ static bool Process(RegexNode node, ref ValueStringBuilder vsb) } // Alternation: find a string that's a shared prefix of all branches - case RegexNodeKind.Alternate: + case RegexNodeKind.Alternate when !rtl: // for RTL we'd need to be matching the suffixes of the alternation cases { int childCount = node.ChildCount(); diff --git a/src/libraries/System.Text.RegularExpressions/tests/FunctionalTests/Regex.CompileToAssembly.Tests.cs b/src/libraries/System.Text.RegularExpressions/tests/FunctionalTests/Regex.CompileToAssembly.Tests.cs index a669f65bd023ed..c1d17ffa6a3ae5 100644 --- a/src/libraries/System.Text.RegularExpressions/tests/FunctionalTests/Regex.CompileToAssembly.Tests.cs +++ b/src/libraries/System.Text.RegularExpressions/tests/FunctionalTests/Regex.CompileToAssembly.Tests.cs @@ -14,63 +14,62 @@ namespace System.Text.RegularExpressions.Tests [SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework)] public class RegexCompileToAssemblyTests : FileCleanupTestBase { - public static bool IsDebug => typeof(Regex).Assembly.GetCustomAttributes(false).OfType().Any(da => da.IsJITTrackingEnabled); - public static bool IsRelease => !IsDebug; - public static bool IsDebugAndRemoteExecutorSupported => IsDebug && RemoteExecutor.IsSupported; - - [ConditionalFact(nameof(IsRelease))] - public void CompileToAssembly_PNSE() + [Fact] + public void CompileToAssembly_SimpleTest() { - Assert.Throws(() => Regex.CompileToAssembly(null, null)); - Assert.Throws(() => Regex.CompileToAssembly(null, null, null)); - Assert.Throws(() => Regex.CompileToAssembly(null, null, null, null)); + bool isDebug = typeof(Regex).Assembly.GetCustomAttributes(false).OfType().Any(da => da.IsJITTrackingEnabled); - Assert.Throws(() => Regex.CompileToAssembly( - [new RegexCompilationInfo("abcd", RegexOptions.None, "abcd", "SomeNamespace", true)], - new AssemblyName("abcd"))); + if (!isDebug) + { + Assert.Throws(() => Regex.CompileToAssembly(null, null)); + Assert.Throws(() => Regex.CompileToAssembly(null, null, null)); + Assert.Throws(() => Regex.CompileToAssembly(null, null, null, null)); - Assert.Throws(() => Regex.CompileToAssembly( - [new RegexCompilationInfo("abcd", RegexOptions.None, "abcd", "SomeNamespace", true)], - new AssemblyName("abcd"), - [new CustomAttributeBuilder(typeof(AssemblyCompanyAttribute).GetConstructor([typeof(string)]), new[] { "TestCompany" })])); + Assert.Throws(() => Regex.CompileToAssembly( + [new RegexCompilationInfo("abcd", RegexOptions.None, "abcd", "SomeNamespace", true)], + new AssemblyName("abcd"))); - Assert.Throws(() => Regex.CompileToAssembly( - [new RegexCompilationInfo("abcd", RegexOptions.None, "abcd", "SomeNamespace", true)], - new AssemblyName("abcd"), - [new CustomAttributeBuilder(typeof(AssemblyCompanyAttribute).GetConstructor([typeof(string)]), new[] { "TestCompany" })], - "resourceFile")); - } + Assert.Throws(() => Regex.CompileToAssembly( + [new RegexCompilationInfo("abcd", RegexOptions.None, "abcd", "SomeNamespace", true)], + new AssemblyName("abcd"), + [new CustomAttributeBuilder(typeof(AssemblyCompanyAttribute).GetConstructor([typeof(string)]), new[] { "TestCompany" })])); - [ConditionalFact(nameof(IsDebugAndRemoteExecutorSupported))] - public void CompileToAssembly_SimpleUseInDebug() - { - RemoteExecutor.Invoke(() => + Assert.Throws(() => Regex.CompileToAssembly( + [new RegexCompilationInfo("abcd", RegexOptions.None, "abcd", "SomeNamespace", true)], + new AssemblyName("abcd"), + [new CustomAttributeBuilder(typeof(AssemblyCompanyAttribute).GetConstructor([typeof(string)]), new[] { "TestCompany" })], + "resourceFile")); + } + else if (RemoteExecutor.IsSupported) { - (RegexCompilationInfo rci, string validInput, string invalidInput)[] regexes = - [ - (new RegexCompilationInfo("abcd", RegexOptions.None, "Type1", "Namespace1", ispublic: true), "123abcd123", "123abed123"), - (new RegexCompilationInfo("(a|b|cde)+", RegexOptions.None, "Type2", "Namespace2.Sub", ispublic: true), "abcde", "cd"), - ]; + RemoteExecutor.Invoke(() => + { + (RegexCompilationInfo rci, string validInput, string invalidInput)[] regexes = + [ + (new RegexCompilationInfo("abcd", RegexOptions.None, "Type1", "Namespace1", ispublic: true), "123abcd123", "123abed123"), + (new RegexCompilationInfo("(a|b|cde)+", RegexOptions.None, "Type2", "Namespace2.Sub", ispublic: true), "abcde", "cd"), + ]; - string assemblyName = Path.GetRandomFileName(); + string assemblyName = Path.GetRandomFileName(); - string cwd = Environment.CurrentDirectory; - Environment.CurrentDirectory = TestDirectory; - try - { - Regex.CompileToAssembly(regexes.Select(r => r.rci).ToArray(), new AssemblyName(assemblyName)); - } - finally - { - Environment.CurrentDirectory = cwd; - } + string cwd = Environment.CurrentDirectory; + Environment.CurrentDirectory = TestDirectory; + try + { + Regex.CompileToAssembly(regexes.Select(r => r.rci).ToArray(), new AssemblyName(assemblyName)); + } + finally + { + Environment.CurrentDirectory = cwd; + } - string assemblyPath = Path.Combine(TestDirectory, assemblyName + ".dll"); - Assert.True(File.Exists(assemblyPath)); + string assemblyPath = Path.Combine(TestDirectory, assemblyName + ".dll"); + Assert.True(File.Exists(assemblyPath)); - // Uncomment to save the assembly to the desktop for inspection: - // File.Copy(assemblyPath, Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory), Path.GetFileName(assemblyPath))); - }).Dispose(); + // Uncomment to save the assembly to the desktop for inspection: + // File.Copy(assemblyPath, Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory), Path.GetFileName(assemblyPath))); + }).Dispose(); + } } } } diff --git a/src/libraries/System.Text.RegularExpressions/tests/FunctionalTests/Regex.Match.Tests.cs b/src/libraries/System.Text.RegularExpressions/tests/FunctionalTests/Regex.Match.Tests.cs index 1b06272fba64ab..d58290174c222f 100644 --- a/src/libraries/System.Text.RegularExpressions/tests/FunctionalTests/Regex.Match.Tests.cs +++ b/src/libraries/System.Text.RegularExpressions/tests/FunctionalTests/Regex.Match.Tests.cs @@ -698,6 +698,11 @@ public static IEnumerable Match_MemberData() yield return (@"(...)(?(1)\w*|\s*)[a1 ]", "zabcaaaaaaa", RegexOptions.RightToLeft, 0, 11, true, "aaaa"); yield return (@"(...)(?(1)\w*|\s*)[a1 ]", "---- ", RegexOptions.RightToLeft, 0, 11, true, "--- "); yield return (@"(aaa)(?(1)aaa|b?)*", "aaaaaa", RegexOptions.None, 0, 6, true, "aaaaaa"); + + yield return (@"AAB|AAC", "AABAACD", RegexOptions.RightToLeft, 0, 6, true, "AAC"); + yield return (@"AAB|AA\d", "AABAACD", RegexOptions.RightToLeft, 0, 6, true, "AAB"); + yield return (@"(AB){3,}", "1234ABABABAB5678", RegexOptions.RightToLeft, 0, 16, true, "ABABABAB"); + yield return (@"(AB){1,3}", "1234ABABABAB5678", RegexOptions.RightToLeft, 0, 16, true, "ABABAB"); } // Character Class Subtraction diff --git a/src/libraries/System.Text.RegularExpressions/tests/UnitTests/RegexFindOptimizationsTests.cs b/src/libraries/System.Text.RegularExpressions/tests/UnitTests/RegexFindOptimizationsTests.cs index c962bc072b6fd7..4c0b02b266142e 100644 --- a/src/libraries/System.Text.RegularExpressions/tests/UnitTests/RegexFindOptimizationsTests.cs +++ b/src/libraries/System.Text.RegularExpressions/tests/UnitTests/RegexFindOptimizationsTests.cs @@ -88,7 +88,6 @@ public void TrailingAnchor(string pattern, int options, int expectedMode, int ex [InlineData(@"(ab){2,4}(de){4,}", 0, (int)FindNextStartingPositionMode.LeadingString_LeftToRight, "abab")] [InlineData(@"(ab){2,4}(de){4,}", (int)RegexOptions.RightToLeft, (int)FindNextStartingPositionMode.LeadingString_RightToLeft, "de")] [InlineData(@"ab|(abc)|(abcd)", 0, (int)FindNextStartingPositionMode.LeadingString_LeftToRight, "ab")] - [InlineData(@"ab|(abc)|(abcd)", (int)RegexOptions.RightToLeft, (int)FindNextStartingPositionMode.LeadingString_RightToLeft, "ab")] [InlineData(@"ab(?=cd)", 0, (int)FindNextStartingPositionMode.LeadingString_LeftToRight, "ab")] [InlineData(@"ab(?=cd)", (int)RegexOptions.RightToLeft, (int)FindNextStartingPositionMode.LeadingString_RightToLeft, "ab")] [InlineData(@"\bab(?=\w)(?!=\d)c\b", 0, (int)FindNextStartingPositionMode.LeadingString_LeftToRight, "abc")] @@ -110,6 +109,7 @@ public void LeadingPrefix(string pattern, int options, int expectedMode, string [InlineData(@"a", (int)RegexOptions.IgnoreCase | (int)RegexOptions.RightToLeft, (int)FindNextStartingPositionMode.LeadingSet_RightToLeft, "Aa")] [InlineData(@"ab|cd|ef|gh", (int)RegexOptions.RightToLeft, (int)FindNextStartingPositionMode.LeadingSet_RightToLeft, "bdfh")] [InlineData(@"\bab(?=\w)(?!=\d)c\b", (int)(RegexOptions.IgnoreCase | RegexOptions.RightToLeft), (int)FindNextStartingPositionMode.LeadingSet_RightToLeft, "Cc")] + [InlineData(@"ab|(abc)|(abcd)", (int)RegexOptions.RightToLeft, (int)FindNextStartingPositionMode.LeadingSet_RightToLeft, "bcd")] public void LeadingSet(string pattern, int options, int expectedMode, string expectedChars) { RegexFindOptimizations opts = ComputeOptimizations(pattern, (RegexOptions)options); From 40bc2d88b6606324f5774cc972d480a1d26084f8 Mon Sep 17 00:00:00 2001 From: Meri Khamoyan <96171496+mkhamoyan@users.noreply.github.com> Date: Tue, 23 Apr 2024 18:35:28 +0200 Subject: [PATCH 037/161] [mono][wasm] Fix function signature mismatch in m2n invoke (#101106) Fix signature mismatch --- src/mono/browser/runtime/runtime.c | 10 ++---- src/mono/mono/metadata/native-library.c | 29 +++++++++++++++++ src/mono/mono/metadata/native-library.h | 3 ++ src/mono/mono/mini/aot-compiler.c | 18 +++++++---- src/mono/mono/mini/mini-llvm.c | 11 +++++-- .../wasm/Wasm.Build.Tests/Common/TestUtils.cs | 4 ++- .../PInvokeTableGeneratorTests.cs | 26 +++++++++++++++ .../UnmanagedCallback.cs | 28 ++++++++++++++++ src/mono/wasm/testassets/native-libs/local.c | 10 ++++++ src/tasks/AotCompilerTask/MonoAOTCompiler.cs | 21 +----------- src/tasks/Common/Utils.cs | 32 +++++++++++++++++++ .../ManagedToNativeGenerator.cs | 27 +--------------- .../WasmAppBuilder/PInvokeTableGenerator.cs | 2 +- 13 files changed, 157 insertions(+), 64 deletions(-) create mode 100644 src/mono/wasm/testassets/Wasm.Buid.Tests.Programs/UnmanagedCallback.cs create mode 100644 src/mono/wasm/testassets/native-libs/local.c diff --git a/src/mono/browser/runtime/runtime.c b/src/mono/browser/runtime/runtime.c index 2132dd9906d597..8ddcdbce138637 100644 --- a/src/mono/browser/runtime/runtime.c +++ b/src/mono/browser/runtime/runtime.c @@ -65,6 +65,7 @@ int mono_wasm_enable_gc = 1; /* Missing from public headers */ +char *mono_fixup_symbol_name (char *key); void mono_icall_table_init (void); void mono_wasm_enable_debugging (int); void mono_ee_interp_init (const char *opts); @@ -213,13 +214,8 @@ get_native_to_interp (MonoMethod *method, void *extra_arg) assert (strlen (name) < 100); snprintf (key, sizeof(key), "%s_%s_%s", name, class_name, method_name); - len = strlen (key); - for (int i = 0; i < len; ++i) { - if (key [i] == '.') - key [i] = '_'; - } - - addr = wasm_dl_get_native_to_interp (key, extra_arg); + char* fixedName = mono_fixup_symbol_name(key); + addr = wasm_dl_get_native_to_interp (fixedName, extra_arg); MONO_EXIT_GC_UNSAFE; return addr; } diff --git a/src/mono/mono/metadata/native-library.c b/src/mono/mono/metadata/native-library.c index f26ab2e9152afa..142c467fdd0af5 100644 --- a/src/mono/mono/metadata/native-library.c +++ b/src/mono/mono/metadata/native-library.c @@ -1222,3 +1222,32 @@ mono_loader_install_pinvoke_override (PInvokeOverrideFn override_fn) { pinvoke_override = override_fn; } + +// Keep synced with FixupSymbolName from src/tasks/Common/Utils.cs +char* mono_fixup_symbol_name (char *key) { + char* fixedName = malloc(256); + int sb_index = 0; + int len = (int)strlen (key); + + for (int i = 0; i < len; ++i) { + unsigned char b = key[i]; + if ((b >= '0' && b <= '9') || + (b >= 'a' && b <= 'z') || + (b >= 'A' && b <= 'Z') || + (b == '_')) { + fixedName[sb_index++] = b; + } + else if (b == '.' || b == '-' || b == '+' || b == '<' || b == '>') { + fixedName[sb_index++] = '_'; + } + else { + // Append the hexadecimal representation of b between underscores + sprintf(&fixedName[sb_index], "_%X_", b); + sb_index += 4; // Move the index after the appended hexadecimal characters + } + } + + // Null-terminate the fixedName string + fixedName[sb_index] = '\0'; + return fixedName; +} diff --git a/src/mono/mono/metadata/native-library.h b/src/mono/mono/metadata/native-library.h index 9108a86ae75460..8a0b0e20b9ec6d 100644 --- a/src/mono/mono/metadata/native-library.h +++ b/src/mono/mono/metadata/native-library.h @@ -35,4 +35,7 @@ mono_lookup_pinvoke_qcall_internal (const char *name); void mono_loader_install_pinvoke_override (PInvokeOverrideFn override_fn); +char * +mono_fixup_symbol_name (char *key); + #endif diff --git a/src/mono/mono/mini/aot-compiler.c b/src/mono/mono/mini/aot-compiler.c index fdd8511f478744..9aa0760231dd19 100644 --- a/src/mono/mono/mini/aot-compiler.c +++ b/src/mono/mono/mini/aot-compiler.c @@ -51,6 +51,7 @@ #include #include #include +#include #include #include #include @@ -12407,7 +12408,6 @@ emit_file_info (MonoAotCompile *acfg) if (acfg->aot_opts.static_link) { char symbol [MAX_SYMBOL_SIZE]; - char *p; /* * Emit a global symbol which can be passed by an embedding app to @@ -12415,14 +12415,17 @@ emit_file_info (MonoAotCompile *acfg) * structure. */ sprintf (symbol, "%smono_aot_module_%s_info", acfg->user_symbol_prefix, acfg->image->assembly->aname.name); - +#ifdef TARGET_WASM + acfg->static_linking_symbol = g_strdup (mono_fixup_symbol_name(symbol)); +#else /* Get rid of characters which cannot occur in symbols */ - p = symbol; + char *p = symbol; for (p = symbol; *p; ++p) { if (!(isalnum (*p) || *p == '_')) *p = '_'; } acfg->static_linking_symbol = g_strdup (symbol); +#endif } if (acfg->llvm) @@ -14860,7 +14863,6 @@ aot_assembly (MonoAssembly *ass, guint32 jit_opts, MonoAotOptions *aot_options) { MonoImage *image = ass->image; MonoAotCompile *acfg; - char *p; int res; TV_DECLARE (atv); TV_DECLARE (btv); @@ -15120,13 +15122,17 @@ aot_assembly (MonoAssembly *ass, guint32 jit_opts, MonoAotOptions *aot_options) acfg->flags = (MonoAotFileFlags)(acfg->flags | MONO_AOT_FILE_FLAG_LLVM_ONLY); acfg->assembly_name_sym = g_strdup (get_assembly_prefix (acfg->image)); - /* Get rid of characters which cannot occur in symbols */ +#ifdef TARGET_WASM + acfg->global_prefix = g_strdup_printf ("mono_aot_%s", g_strdup(mono_fixup_symbol_name (acfg->assembly_name_sym))); +#else + char *p; + /* Get rid of characters which cannot occur in symbols */ for (p = acfg->assembly_name_sym; *p; ++p) { if (!(isalnum (*p) || *p == '_')) *p = '_'; } - acfg->global_prefix = g_strdup_printf ("mono_aot_%s", acfg->assembly_name_sym); +#endif acfg->plt_symbol = g_strdup_printf ("%s_plt", acfg->global_prefix); acfg->got_symbol = g_strdup_printf ("%s_got", acfg->global_prefix); if (acfg->llvm) { diff --git a/src/mono/mono/mini/mini-llvm.c b/src/mono/mono/mini/mini-llvm.c index c8481b41bf9759..63ffbf994657f0 100644 --- a/src/mono/mono/mini/mini-llvm.c +++ b/src/mono/mono/mini/mini-llvm.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -14519,17 +14520,21 @@ emit_aot_file_info (MonoLLVMModule *module) LLVMSetInitializer (info_var, LLVMConstNamedStruct (module->info_var_type, fields, nfields)); if (module->static_link) { - char *s, *p; + char *s; LLVMValueRef var; s = g_strdup_printf ("mono_aot_module_%s_info", module->assembly->aname.name); +#ifdef TARGET_WASM + var = LLVMAddGlobal (module->lmodule, pointer_type (LLVMInt8Type ()), g_strdup (mono_fixup_symbol_name(s))); +#else /* Get rid of characters which cannot occur in symbols */ - p = s; + char *p = s; for (p = s; *p; ++p) { if (!(isalnum (*p) || *p == '_')) - *p = '_'; + *p = '_'; } var = LLVMAddGlobal (module->lmodule, pointer_type (LLVMInt8Type ()), s); +#endif g_free (s); LLVMSetInitializer (var, LLVMConstBitCast (LLVMGetNamedGlobal (module->lmodule, "mono_aot_file_info"), pointer_type (LLVMInt8Type ()))); LLVMSetLinkage (var, LLVMExternalLinkage); diff --git a/src/mono/wasm/Wasm.Build.Tests/Common/TestUtils.cs b/src/mono/wasm/Wasm.Build.Tests/Common/TestUtils.cs index 97aa019d454302..fdf88fecc9ee0f 100644 --- a/src/mono/wasm/Wasm.Build.Tests/Common/TestUtils.cs +++ b/src/mono/wasm/Wasm.Build.Tests/Common/TestUtils.cs @@ -91,7 +91,9 @@ public static void AssertEqual(object expected, object actual, string label) $"[{label}]\n"); } - private static readonly char[] s_charsToReplace = new[] { '.', '-', '+' }; + private static readonly char[] s_charsToReplace = new[] { '.', '-', '+', '<', '>' }; + // Keep synced with FixupSymbolName from src/tasks/Common/Utils.cs + // and with mono_fixup_symbol_name from src/mono/mono/metadata/native-library.c public static string FixupSymbolName(string name) { UTF8Encoding utf8 = new(); diff --git a/src/mono/wasm/Wasm.Build.Tests/PInvokeTableGeneratorTests.cs b/src/mono/wasm/Wasm.Build.Tests/PInvokeTableGeneratorTests.cs index 8c0442a1b0d680..0daa8d0984920e 100644 --- a/src/mono/wasm/Wasm.Build.Tests/PInvokeTableGeneratorTests.cs +++ b/src/mono/wasm/Wasm.Build.Tests/PInvokeTableGeneratorTests.cs @@ -884,5 +884,31 @@ public void EnsureWasmAbiRulesAreFollowedInAOT(BuildArgs buildArgs, RunHost host [BuildAndRun(host: RunHost.Chrome, aot: false)] public void EnsureWasmAbiRulesAreFollowedInInterpreter(BuildArgs buildArgs, RunHost host, string id) => EnsureWasmAbiRulesAreFollowed(buildArgs, host, id); + + [Theory] + [BuildAndRun(host: RunHost.Chrome, aot: false)] + public void UCOWithSpecialCharacters(BuildArgs buildArgs, RunHost host, string id) + { + var extraProperties = "true"; + var extraItems = @""; + + buildArgs = ExpandBuildArgs(buildArgs, + extraItems: extraItems, + extraProperties: extraProperties); + + (string libraryDir, string output) = BuildProject(buildArgs, + id: id, + new BuildProjectOptions( + InitProject: () => + { + File.Copy(Path.Combine(BuildEnvironment.TestAssetsPath, "Wasm.Buid.Tests.Programs", "UnmanagedCallback.cs"), Path.Combine(_projectDir!, "Program.cs")); + File.Copy(Path.Combine(BuildEnvironment.TestAssetsPath, "native-libs", "local.c"), Path.Combine(_projectDir!, "local.c")); + }, + Publish: true, + DotnetWasmFromRuntimePack: false)); + + var runOutput = RunAndTestWasmApp(buildArgs, buildDir: _projectDir, expectedExitCode: 42, host: host, id: id); + Assert.Contains("ManagedFunc returned 42", runOutput); + } } } diff --git a/src/mono/wasm/testassets/Wasm.Buid.Tests.Programs/UnmanagedCallback.cs b/src/mono/wasm/testassets/Wasm.Buid.Tests.Programs/UnmanagedCallback.cs new file mode 100644 index 00000000000000..2157909c3d5fc6 --- /dev/null +++ b/src/mono/wasm/testassets/Wasm.Buid.Tests.Programs/UnmanagedCallback.cs @@ -0,0 +1,28 @@ +using System; +using System.Runtime.InteropServices; + +public unsafe partial class Test +{ + public unsafe static int Main(string[] args) + { + ((IntPtr)(delegate* unmanaged)&Interop.Managed8\u4F60Func).ToString(); + + Console.WriteLine($"main: {args.Length}"); + Interop.UnmanagedFunc(); + return 42; + } +} + +file partial class Interop +{ + [UnmanagedCallersOnly(EntryPoint = "ManagedFunc")] + public static int Managed8\u4F60Func(int number) + { + // called from UnmanagedFunc + Console.WriteLine($"Managed8\u4F60Func({number}) -> 42"); + return 42; + } + + [DllImport("local", EntryPoint = "UnmanagedFunc")] + public static extern void UnmanagedFunc(); // calls ManagedFunc +} diff --git a/src/mono/wasm/testassets/native-libs/local.c b/src/mono/wasm/testassets/native-libs/local.c new file mode 100644 index 00000000000000..4d7a660513c1fb --- /dev/null +++ b/src/mono/wasm/testassets/native-libs/local.c @@ -0,0 +1,10 @@ +#include +int ManagedFunc(int number); + +void UnmanagedFunc() +{ + int ret = 0; + printf("UnmanagedFunc calling ManagedFunc\n"); + ret = ManagedFunc(123); + printf("ManagedFunc returned %d\n", ret); +} \ No newline at end of file diff --git a/src/tasks/AotCompilerTask/MonoAOTCompiler.cs b/src/tasks/AotCompilerTask/MonoAOTCompiler.cs index 09d58b2a9d083d..4e98e9271490b6 100644 --- a/src/tasks/AotCompilerTask/MonoAOTCompiler.cs +++ b/src/tasks/AotCompilerTask/MonoAOTCompiler.cs @@ -1237,26 +1237,7 @@ private string FixupSymbolName(string name) if (_symbolNameFixups.TryGetValue(name, out string? fixedName)) return fixedName; - UTF8Encoding utf8 = new(); - byte[] bytes = utf8.GetBytes(name); - StringBuilder sb = new(); - - foreach (byte b in bytes) - { - if ((b >= (byte)'0' && b <= (byte)'9') || - (b >= (byte)'a' && b <= (byte)'z') || - (b >= (byte)'A' && b <= (byte)'Z') || - (b == (byte)'_')) - { - sb.Append((char)b); - } - else - { - sb.Append('_'); - } - } - - fixedName = sb.ToString(); + fixedName = Utils.FixupSymbolName(name); _symbolNameFixups[name] = fixedName; return fixedName; } diff --git a/src/tasks/Common/Utils.cs b/src/tasks/Common/Utils.cs index eca2ccd9740233..2f2e8b2ce02d1a 100644 --- a/src/tasks/Common/Utils.cs +++ b/src/tasks/Common/Utils.cs @@ -11,6 +11,7 @@ using System.Reflection.Metadata; using System.Security.Cryptography; using System.Text; +using System.Linq; using Microsoft.Build.Framework; using Microsoft.Build.Utilities; @@ -33,6 +34,8 @@ public enum HashEncodingType private static readonly object s_SyncObj = new object(); + private static readonly char[] s_charsToReplace = new[] { '.', '-', '+', '<', '>' }; + public static string GetEmbeddedResource(string file) { using Stream stream = typeof(Utils).Assembly @@ -411,4 +414,33 @@ private static bool IsManagedAssembly(PEReader peReader) return false; } } + + // Keep synced with mono_fixup_symbol_name from src/mono/mono/metadata/native-library.c + public static string FixupSymbolName(string name) + { + UTF8Encoding utf8 = new(); + byte[] bytes = utf8.GetBytes(name); + StringBuilder sb = new(); + + foreach (byte b in bytes) + { + if ((b >= (byte)'0' && b <= (byte)'9') || + (b >= (byte)'a' && b <= (byte)'z') || + (b >= (byte)'A' && b <= (byte)'Z') || + (b == (byte)'_')) + { + sb.Append((char)b); + } + else if (s_charsToReplace.Contains((char)b)) + { + sb.Append('_'); + } + else + { + sb.Append($"_{b:X}_"); + } + } + + return sb.ToString(); + } } diff --git a/src/tasks/WasmAppBuilder/ManagedToNativeGenerator.cs b/src/tasks/WasmAppBuilder/ManagedToNativeGenerator.cs index 3acdcf06ba8a64..db9cf0cef04d87 100644 --- a/src/tasks/WasmAppBuilder/ManagedToNativeGenerator.cs +++ b/src/tasks/WasmAppBuilder/ManagedToNativeGenerator.cs @@ -36,8 +36,6 @@ public class ManagedToNativeGenerator : Task [Output] public string[]? FileWrites { get; private set; } - private static readonly char[] s_charsToReplace = new[] { '.', '-', '+', '<', '>' }; - public override bool Execute() { if (Assemblies!.Length == 0) @@ -108,30 +106,7 @@ string FixupSymbolName(string name) if (_symbolNameFixups.TryGetValue(name, out string? fixedName)) return fixedName; - UTF8Encoding utf8 = new(); - byte[] bytes = utf8.GetBytes(name); - StringBuilder sb = new(); - - foreach (byte b in bytes) - { - if ((b >= (byte)'0' && b <= (byte)'9') || - (b >= (byte)'a' && b <= (byte)'z') || - (b >= (byte)'A' && b <= (byte)'Z') || - (b == (byte)'_')) - { - sb.Append((char)b); - } - else if (s_charsToReplace.Contains((char)b)) - { - sb.Append('_'); - } - else - { - sb.Append($"_{b:X}_"); - } - } - - fixedName = sb.ToString(); + fixedName = Utils.FixupSymbolName(name); _symbolNameFixups[name] = fixedName; return fixedName; } diff --git a/src/tasks/WasmAppBuilder/PInvokeTableGenerator.cs b/src/tasks/WasmAppBuilder/PInvokeTableGenerator.cs index 4a29b47666e94d..7808655b7f6b68 100644 --- a/src/tasks/WasmAppBuilder/PInvokeTableGenerator.cs +++ b/src/tasks/WasmAppBuilder/PInvokeTableGenerator.cs @@ -304,7 +304,7 @@ private string DelegateKey(PInvokeCallback export) // it needs to match the key generated in get_native_to_interp var method = export.Method; string module_symbol = method.DeclaringType!.Module!.Assembly!.GetName()!.Name!; - return $"\"{module_symbol}_{method.DeclaringType.Name}_{method.Name}\"".Replace('.', '_'); + return $"\"{_fixupSymbolName($"{module_symbol}_{method.DeclaringType.Name}_{method.Name}")}\""; } #pragma warning disable SYSLIB1045 // framework doesn't support GeneratedRegexAttribute From f27056529982d9aea44f0a84f24fc0bb0ee52c96 Mon Sep 17 00:00:00 2001 From: Koundinya Veluri Date: Tue, 23 Apr 2024 12:19:41 -0700 Subject: [PATCH 038/161] Fix class construction cycle in Lock on NativeAOT (#100374) When a thread reenters class construction through accessing NativeRuntimeEventSource.Log, Log would return null. Checks on IsFullyInitialized were added to ensure that the normal path would not be taken in that case, to avoid null checks in several places and in different files. That doesn't work when a different thread sees the initialization stage as Complete, as it would try to initialize NativeRuntimeEventSource and run into a class construction cycle. Fixed by removing the IsFullyInitialized checks, introducing a new initialization stage PartiallyCompelte, and not setting the stage to Complete until it has been verified that Log does not return null. When the stage is PartiallyCompelte, a thread would retry the relevant initialization. This again guarantees that there would be at most one attempt at initialization through Lock at any given time, and prevents the class construction cycle. Fixes https://github.com/dotnet/runtime/issues/99663 --- .../src/System/Threading/Lock.NativeAot.cs | 75 +++++++++++-------- 1 file changed, 43 insertions(+), 32 deletions(-) diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Threading/Lock.NativeAot.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Threading/Lock.NativeAot.cs index 7ac43d2257e786..8a1c017a508098 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Threading/Lock.NativeAot.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Threading/Lock.NativeAot.cs @@ -92,18 +92,6 @@ internal void Reenter(uint previousRecursionCount) _recursionCount = previousRecursionCount; } - private static bool IsFullyInitialized - { - get - { - // If NativeRuntimeEventSource is already being class-constructed by this thread earlier in the stack, Log can - // be null. This property is used to avoid going down the wait path in that case to avoid null checks in several - // other places. - Debug.Assert((StaticsInitializationStage)s_staticsInitializationStage == StaticsInitializationStage.Complete); - return NativeRuntimeEventSource.Log != null; - } - } - [MethodImpl(MethodImplOptions.AggressiveInlining)] private TryLockResult LazyInitializeOrEnter() { @@ -113,10 +101,6 @@ private TryLockResult LazyInitializeOrEnter() case StaticsInitializationStage.Complete: if (_spinCount == SpinCountNotInitialized) { - if (!IsFullyInitialized) - { - goto case StaticsInitializationStage.Started; - } _spinCount = s_maxSpinCount; } return TryLockResult.Spin; @@ -137,7 +121,7 @@ private TryLockResult LazyInitializeOrEnter() } stage = (StaticsInitializationStage)Volatile.Read(ref s_staticsInitializationStage); - if (stage == StaticsInitializationStage.Complete && IsFullyInitialized) + if (stage == StaticsInitializationStage.Complete) { goto case StaticsInitializationStage.Complete; } @@ -155,7 +139,9 @@ private TryLockResult LazyInitializeOrEnter() } default: - Debug.Assert(stage == StaticsInitializationStage.NotStarted); + Debug.Assert( + stage == StaticsInitializationStage.NotStarted || + stage == StaticsInitializationStage.PartiallyComplete); if (TryInitializeStatics()) { goto case StaticsInitializationStage.Complete; @@ -169,29 +155,49 @@ private static bool TryInitializeStatics() { // Since Lock is used to synchronize class construction, and some of the statics initialization may involve class // construction, update the stage first to avoid infinite recursion - switch ( - (StaticsInitializationStage) - Interlocked.CompareExchange( - ref s_staticsInitializationStage, - (int)StaticsInitializationStage.Started, - (int)StaticsInitializationStage.NotStarted)) + var oldStage = (StaticsInitializationStage)s_staticsInitializationStage; + while (true) { - case StaticsInitializationStage.Started: - return false; - case StaticsInitializationStage.Complete: + if (oldStage == StaticsInitializationStage.Complete) + { return true; + } + + var stageBeforeUpdate = + (StaticsInitializationStage)Interlocked.CompareExchange( + ref s_staticsInitializationStage, + (int)StaticsInitializationStage.Started, + (int)oldStage); + if (stageBeforeUpdate == StaticsInitializationStage.Started) + { + return false; + } + if (stageBeforeUpdate == oldStage) + { + Debug.Assert( + oldStage == StaticsInitializationStage.NotStarted || + oldStage == StaticsInitializationStage.PartiallyComplete); + break; + } + + oldStage = stageBeforeUpdate; } bool isFullyInitialized; try { - s_isSingleProcessor = Environment.IsSingleProcessor; - s_maxSpinCount = DetermineMaxSpinCount(); - s_minSpinCount = DetermineMinSpinCount(); + if (oldStage == StaticsInitializationStage.NotStarted) + { + // If the stage is PartiallyComplete, these will have already been initialized + s_isSingleProcessor = Environment.IsSingleProcessor; + s_maxSpinCount = DetermineMaxSpinCount(); + s_minSpinCount = DetermineMinSpinCount(); + } // Also initialize some types that are used later to prevent potential class construction cycles. If // NativeRuntimeEventSource is already being class-constructed by this thread earlier in the stack, Log can be - // null. Avoid going down the wait path in that case to avoid null checks in several other places. + // null. Avoid going down the wait path in that case to avoid null checks in several other places. If not fully + // initialized, the stage will also be set to PartiallyComplete to try again. isFullyInitialized = NativeRuntimeEventSource.Log != null; } catch @@ -200,7 +206,11 @@ private static bool TryInitializeStatics() throw; } - Volatile.Write(ref s_staticsInitializationStage, (int)StaticsInitializationStage.Complete); + Volatile.Write( + ref s_staticsInitializationStage, + isFullyInitialized + ? (int)StaticsInitializationStage.Complete + : (int)StaticsInitializationStage.PartiallyComplete); return isFullyInitialized; } @@ -242,6 +252,7 @@ private enum StaticsInitializationStage { NotStarted, Started, + PartiallyComplete, Complete } } From d92ac1f892a7f9c00561db6541671f25f3972eed Mon Sep 17 00:00:00 2001 From: Radek Zikmund <32671551+rzikm@users.noreply.github.com> Date: Tue, 23 Apr 2024 22:14:09 +0200 Subject: [PATCH 039/161] Fix SocketsHttpHandlerTest_HttpClientHandlerTest_Http3.ReadAsStreamAsync_Cancellation data race (#101428) * Fix SocketsHttpHandlerTest_HttpClientHandlerTest_Http3.ReadAsStreamAsync_Cancellation data race * Fix build --- .../tests/System/Net/Http/HttpClientHandlerTest.cs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.cs b/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.cs index 0ffd0d4ae82eda..7c3d3f385d0bd9 100644 --- a/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.cs +++ b/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.cs @@ -6,6 +6,9 @@ using System.Linq; using System.Net.Http.Headers; using System.Net.Sockets; +#if !NETFRAMEWORK +using System.Net.Quic; +#endif using System.Net.Test.Common; using System.Security.Authentication; using System.Security.Cryptography; @@ -1396,6 +1399,12 @@ await server.AcceptConnectionAsync(async connection => await connection.SendResponseAsync(HttpStatusCode.OK, headers: new HttpHeaderData[] { new HttpHeaderData("Transfer-Encoding", "chunked") }, isFinal: false); await connection.SendResponseBodyAsync("1\r\nh\r\n", false); } +#if !NETFRAMEWORK + catch (QuicException ex) when (ex.ApplicationErrorCode == 0x10c /*H3_REQUEST_CANCELLED*/) + { + // The request was cancelled before we sent the body, ignore + } +#endif catch (IOException ex) { // when testing in the browser, we are using the WebSocket for the loopback From 6e866a6ed62c6178efc55e4fe276d3e44190e4f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Strehovsk=C3=BD?= Date: Wed, 24 Apr 2024 06:29:58 +0900 Subject: [PATCH 040/161] Fix running tests with process isolation under naot (#100331) We don't currently run any RequiresProcessIsolation tests under native AOT because we hit the "not an applicable OS" early out here: https://github.com/dotnet/runtime/blob/765ca4e9f2dddca2005ffdb45863b7980247a886/src/tests/Common/CoreCLRTestLibrary/OutOfProcessTest.cs#L75-L79 --- src/tests/Common/CLRTest.Jit.targets | 4 +- .../CoreCLRTestLibrary/OutOfProcessTest.cs | 12 +++-- .../Common/XUnitWrapperGenerator/ITestInfo.cs | 7 ++- .../XUnitWrapperGenerator/OptionsHelper.cs | 3 ++ .../XUnitWrapperGenerator.cs | 2 +- .../XUnitWrapperGenerator.props | 1 + .../Directed/tailcall/mutual_recursion.fsproj | 3 ++ .../Runtime_72845/Runtime_72845.fsproj | 3 ++ .../coreclr/GitHub_22888/test22888.csproj | 3 ++ src/tests/issues.targets | 49 +++++++++++++++++++ 10 files changed, 79 insertions(+), 8 deletions(-) diff --git a/src/tests/Common/CLRTest.Jit.targets b/src/tests/Common/CLRTest.Jit.targets index 6fd00de8977f6a..5c2a0735a414fe 100644 --- a/src/tests/Common/CLRTest.Jit.targets +++ b/src/tests/Common/CLRTest.Jit.targets @@ -140,7 +140,7 @@ IF NOT DEFINED DoLink ( DependsOnTargets="GetDisasmCheckData"> false - true + true $(scriptPath)__jit_disasm.out $(scriptPath)__jit_disasm_list.out @@ -184,7 +184,7 @@ fi DependsOnTargets="GetDisasmCheckData"> false - true + true $(scriptPath)__jit_disasm.out $(scriptPath)__jit_disasm_list.out diff --git a/src/tests/Common/CoreCLRTestLibrary/OutOfProcessTest.cs b/src/tests/Common/CoreCLRTestLibrary/OutOfProcessTest.cs index 0337fa9e624f0d..66937878587ddd 100644 --- a/src/tests/Common/CoreCLRTestLibrary/OutOfProcessTest.cs +++ b/src/tests/Common/CoreCLRTestLibrary/OutOfProcessTest.cs @@ -49,7 +49,7 @@ static OutOfProcessTest() && !OperatingSystem.IsBrowser() && !OperatingSystem.IsOSPlatform("Wasi"); - public static void RunOutOfProcessTest(string assemblyPath) + public static void RunOutOfProcessTest(string assemblyPath, string testPathPrefix) { int ret = -100; string baseDir = AppContext.BaseDirectory; @@ -63,17 +63,23 @@ public static void RunOutOfProcessTest(string assemblyPath) { CoreclrTestWrapperLib wrapper = new CoreclrTestWrapperLib(); + string testScriptPath = assemblyPath; + if (testPathPrefix != null) + testScriptPath = Path.Combine(testPathPrefix, testScriptPath); + if (OperatingSystem.IsWindows()) { - testExecutable = Path.Combine(baseDir, Path.ChangeExtension(assemblyPath, ".cmd")); + testExecutable = Path.Combine(baseDir, Path.ChangeExtension(testScriptPath, ".cmd")); } else { - testExecutable = Path.Combine(baseDir, Path.ChangeExtension(assemblyPath.Replace("\\", "/"), ".sh")); + testExecutable = Path.Combine(baseDir, Path.ChangeExtension(testScriptPath.Replace("\\", "/"), ".sh")); } if (!File.Exists(testExecutable)) { + Console.WriteLine($"Test executable '{testExecutable}' not found, skipping."); + // Skip platform-specific test when running on the excluded platform return; } diff --git a/src/tests/Common/XUnitWrapperGenerator/ITestInfo.cs b/src/tests/Common/XUnitWrapperGenerator/ITestInfo.cs index c4bdef69eb9e91..712c435162aaf3 100644 --- a/src/tests/Common/XUnitWrapperGenerator/ITestInfo.cs +++ b/src/tests/Common/XUnitWrapperGenerator/ITestInfo.cs @@ -336,13 +336,16 @@ public sealed class OutOfProcessTest : ITestInfo private CodeBuilder _executionStatement { get; } private string RelativeAssemblyPath { get; } - public OutOfProcessTest(string displayName, string relativeAssemblyPath) + public OutOfProcessTest(string displayName, string relativeAssemblyPath, string? testBuildMode) { Method = displayName; DisplayNameForFiltering = displayName; TestNameExpression = $"@\"{displayName}\""; RelativeAssemblyPath = relativeAssemblyPath; + // Native AOT tests get generated into a 'native' directory, so we need to get out of that one first to find the test + string testPathPrefix = string.Equals(testBuildMode, "nativeaot", StringComparison.OrdinalIgnoreCase) ? "\"..\"" : "null"; + _executionStatement = new CodeBuilder(); _executionStatement.AppendLine(); _executionStatement.AppendLine("if (TestLibrary.OutOfProcessTest.OutOfProcessTestsSupported)"); @@ -350,7 +353,7 @@ public OutOfProcessTest(string displayName, string relativeAssemblyPath) using (_executionStatement.NewBracesScope()) { _executionStatement.AppendLine($@"TestLibrary.OutOfProcessTest" - + $@".RunOutOfProcessTest(@""{relativeAssemblyPath}"");"); + + $@".RunOutOfProcessTest(@""{relativeAssemblyPath}"", {testPathPrefix});"); } } diff --git a/src/tests/Common/XUnitWrapperGenerator/OptionsHelper.cs b/src/tests/Common/XUnitWrapperGenerator/OptionsHelper.cs index 9b9dd10b23569d..61f4488f0aaa3e 100644 --- a/src/tests/Common/XUnitWrapperGenerator/OptionsHelper.cs +++ b/src/tests/Common/XUnitWrapperGenerator/OptionsHelper.cs @@ -9,6 +9,7 @@ public static class OptionsHelper private const string InMergedTestDirectoryOption = "build_property.InMergedTestDirectory"; private const string IsMergedTestRunnerAssemblyOption = "build_property.IsMergedTestRunnerAssembly"; private const string PriorityOption = "build_property.Priority"; + private const string TestBuildModeOption = "build_property.TestBuildMode"; private const string RuntimeFlavorOption = "build_property.RuntimeFlavor"; private const string IsOutOfProcessTestAssemblyOption = "build_metadata.AdditionalFiles.IsOutOfProcessTestAssembly"; private const string TestFilterOption = "build_property.TestFilter"; @@ -38,6 +39,8 @@ private static bool GetBoolOption(this AnalyzerConfigOptions options, string key internal static string RuntimeFlavor(this AnalyzerConfigOptions options) => options.TryGetValue(RuntimeFlavorOption, out string? flavor) ? flavor : "CoreCLR"; + internal static string? TestBuildMode(this AnalyzerConfigOptions options) => options.TryGetValue(TestBuildModeOption, out string? option) ? option : null; + internal static bool IsOutOfProcessTestAssembly(this AnalyzerConfigOptions options) => options.GetBoolOption(IsOutOfProcessTestAssemblyOption); internal static string? TestFilter(this AnalyzerConfigOptions options) => options.TryGetValue(TestFilterOption, out string? filter) ? filter : null; diff --git a/src/tests/Common/XUnitWrapperGenerator/XUnitWrapperGenerator.cs b/src/tests/Common/XUnitWrapperGenerator/XUnitWrapperGenerator.cs index 06cfdf3022c1b7..bbff22006a4bd0 100644 --- a/src/tests/Common/XUnitWrapperGenerator/XUnitWrapperGenerator.cs +++ b/src/tests/Common/XUnitWrapperGenerator/XUnitWrapperGenerator.cs @@ -56,7 +56,7 @@ public void Initialize(IncrementalGeneratorInitializationContext context) string? testDisplayName = fileOptions.TestDisplayName(); if (assemblyPath is not null && testDisplayName is not null) { - return ImmutableArray.Create(new OutOfProcessTest(testDisplayName, assemblyPath)); + return ImmutableArray.Create(new OutOfProcessTest(testDisplayName, assemblyPath, fileOptions.TestBuildMode())); } } diff --git a/src/tests/Common/XUnitWrapperGenerator/XUnitWrapperGenerator.props b/src/tests/Common/XUnitWrapperGenerator/XUnitWrapperGenerator.props index 067c31f8d6b4d0..fca5c164fba2e1 100644 --- a/src/tests/Common/XUnitWrapperGenerator/XUnitWrapperGenerator.props +++ b/src/tests/Common/XUnitWrapperGenerator/XUnitWrapperGenerator.props @@ -5,6 +5,7 @@ + diff --git a/src/tests/JIT/Directed/tailcall/mutual_recursion.fsproj b/src/tests/JIT/Directed/tailcall/mutual_recursion.fsproj index 83624287a592ec..b6a0995379d76a 100644 --- a/src/tests/JIT/Directed/tailcall/mutual_recursion.fsproj +++ b/src/tests/JIT/Directed/tailcall/mutual_recursion.fsproj @@ -2,6 +2,9 @@ true + + + true True diff --git a/src/tests/JIT/Regression/JitBlue/Runtime_72845/Runtime_72845.fsproj b/src/tests/JIT/Regression/JitBlue/Runtime_72845/Runtime_72845.fsproj index 4ecbaba4ff4301..302b1099bdf8dc 100644 --- a/src/tests/JIT/Regression/JitBlue/Runtime_72845/Runtime_72845.fsproj +++ b/src/tests/JIT/Regression/JitBlue/Runtime_72845/Runtime_72845.fsproj @@ -7,6 +7,9 @@ True $(NetCoreAppToolCurrent) True + + + true diff --git a/src/tests/Regressions/coreclr/GitHub_22888/test22888.csproj b/src/tests/Regressions/coreclr/GitHub_22888/test22888.csproj index f2a1d423be02aa..f74b821627d90b 100644 --- a/src/tests/Regressions/coreclr/GitHub_22888/test22888.csproj +++ b/src/tests/Regressions/coreclr/GitHub_22888/test22888.csproj @@ -3,6 +3,9 @@ true true + + + true diff --git a/src/tests/issues.targets b/src/tests/issues.targets index e5e6cc332a6292..8289fcefb924fb 100644 --- a/src/tests/issues.targets +++ b/src/tests/issues.targets @@ -682,6 +682,15 @@ + + needs triage + + + needs triage + + + https://github.com/dotnet/runtime/issues/91381 + https://github.com/dotnet/runtime/issues/89157 @@ -1151,6 +1160,46 @@ + + + + https://github.com/dotnet/runtime/issues/101284 + + + https://github.com/dotnet/runtime/issues/101284 + + + https://github.com/dotnet/runtime/issues/101284 + + + https://github.com/dotnet/runtime/issues/101284 + + + https://github.com/dotnet/runtime/issues/101284 + + + https://github.com/dotnet/runtime/issues/101284 + + + https://github.com/dotnet/runtime/issues/101363 + + + https://github.com/dotnet/runtime/issues/101363 + + + https://github.com/dotnet/runtime/issues/101363 + + + https://github.com/dotnet/runtime/issues/101363 + + + https://github.com/dotnet/runtime/issues/101363 + + + https://github.com/dotnet/runtime/issues/101364 + + + From 1af8ccd0e7ca5918610c97145fca226ab9329e7e Mon Sep 17 00:00:00 2001 From: Jan Kotas Date: Tue, 23 Apr 2024 16:13:06 -0700 Subject: [PATCH 041/161] Fix comment (#101440) --- src/coreclr/gc/gcpriv.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/coreclr/gc/gcpriv.h b/src/coreclr/gc/gcpriv.h index 6db2e06d04c004..a7199e5d220ac0 100644 --- a/src/coreclr/gc/gcpriv.h +++ b/src/coreclr/gc/gcpriv.h @@ -140,10 +140,10 @@ inline void FATAL_GC_ERROR() // // This means any empty regions can be freely used for any generation. For // Server GC we will balance regions between heaps. -// For now disable regions for StandAlone GC, NativeAOT and MacOS builds +// For now disable regions for standalone GC and macOS builds #if defined (HOST_64BIT) && !defined (BUILD_AS_STANDALONE) && !defined(__APPLE__) #define USE_REGIONS -#endif //HOST_64BIT && BUILD_AS_STANDALONE +#endif //HOST_64BIT && BUILD_AS_STANDALONE && !__APPLE__ //#define SPINLOCK_HISTORY //#define RECORD_LOH_STATE From 8017222b29b64863babf214050ecc80d5f28e323 Mon Sep 17 00:00:00 2001 From: Vladimir Sadov Date: Tue, 23 Apr 2024 16:57:35 -0700 Subject: [PATCH 042/161] Disable UnrollEqualsStartsWith for gcstress. The test takes very long time. (#101455) * Disable UnrollEqualsStartsWith for gcstress. The test takes very long time. * fix comment * added a comment for the reason to exclude --- src/tests/JIT/opt/Vectorization/UnrollEqualsStartsWith.csproj | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/tests/JIT/opt/Vectorization/UnrollEqualsStartsWith.csproj b/src/tests/JIT/opt/Vectorization/UnrollEqualsStartsWith.csproj index c9327d09cb4dc3..87fba405d81ec4 100644 --- a/src/tests/JIT/opt/Vectorization/UnrollEqualsStartsWith.csproj +++ b/src/tests/JIT/opt/Vectorization/UnrollEqualsStartsWith.csproj @@ -1,6 +1,10 @@ True + + true + + true From f55c5a80329644e7ee5cce499fbbb4da2899aabd Mon Sep 17 00:00:00 2001 From: Tanner Gooding Date: Tue, 23 Apr 2024 18:16:58 -0700 Subject: [PATCH 043/161] Expose the `ConvertToIntegerNative` APIs (#100993) * Expose the ConvertToIntegerNative APIs for the floating-point types * Accelerate the ConvertToInteger and related APIs * Applying formatting patch * Fixing some tests for x86 and skipping some tests on Mono --- src/coreclr/jit/compiler.h | 20 +- src/coreclr/jit/emit.h | 4 + src/coreclr/jit/gentree.cpp | 260 +++++++++++++----- src/coreclr/jit/hwintrinsicarm64.cpp | 26 +- src/coreclr/jit/hwintrinsiclistarm64.h | 8 + src/coreclr/jit/hwintrinsiclistxarch.h | 14 +- src/coreclr/jit/hwintrinsicxarch.cpp | 108 ++++++-- src/coreclr/jit/importercalls.cpp | 128 ++++++++- src/coreclr/jit/namedintrinsiclist.h | 2 + src/coreclr/jit/simdashwintrinsic.cpp | 101 +++---- src/coreclr/jit/simdashwintrinsiclistarm64.h | 4 + src/coreclr/jit/simdashwintrinsiclistxarch.h | 4 + .../Common/tests/System/GenericMathHelpers.cs | 6 + .../ref/System.Numerics.Vectors.cs | 6 + .../src/System/Decimal.cs | 8 + .../src/System/Double.cs | 10 + .../System.Private.CoreLib/src/System/Half.cs | 8 + .../src/System/Numerics/IFloatingPoint.cs | 20 ++ .../src/System/Numerics/Vector.cs | 34 ++- .../System/Runtime/InteropServices/NFloat.cs | 8 + .../System/Runtime/Intrinsics/Vector128.cs | 62 ++++- .../System/Runtime/Intrinsics/Vector256.cs | 62 ++++- .../System/Runtime/Intrinsics/Vector512.cs | 62 ++++- .../src/System/Runtime/Intrinsics/Vector64.cs | 38 ++- .../src/System/Single.cs | 10 + .../ref/System.Runtime.InteropServices.cs | 2 + .../ref/System.Runtime.Intrinsics.cs | 24 ++ .../tests/Vectors/Vector128Tests.cs | 104 +++++++ .../tests/Vectors/Vector256Tests.cs | 104 +++++++ .../tests/Vectors/Vector512Tests.cs | 104 +++++++ .../tests/Vectors/Vector64Tests.cs | 73 +++++ .../System.Runtime/ref/System.Runtime.cs | 12 + .../System/DoubleTests.GenericMath.cs | 169 +++++++++++- .../System/SingleTests.GenericMath.cs | 167 +++++++++++ 34 files changed, 1578 insertions(+), 194 deletions(-) diff --git a/src/coreclr/jit/compiler.h b/src/coreclr/jit/compiler.h index 3c19969d0c90d8..5b8a04e868836c 100644 --- a/src/coreclr/jit/compiler.h +++ b/src/coreclr/jit/compiler.h @@ -3188,13 +3188,17 @@ class Compiler CorInfoType simdBaseJitType, unsigned simdSize); -#if defined(TARGET_XARCH) - GenTree* gtNewSimdCvtNode(var_types type, - GenTree* op1, - CorInfoType simdTargetBaseJitType, - CorInfoType simdSourceBaseJitType, - unsigned simdSize); -#endif //TARGET_XARCH + GenTree* gtNewSimdCvtNode(var_types type, + GenTree* op1, + CorInfoType simdTargetBaseJitType, + CorInfoType simdSourceBaseJitType, + unsigned simdSize); + + GenTree* gtNewSimdCvtNativeNode(var_types type, + GenTree* op1, + CorInfoType simdTargetBaseJitType, + CorInfoType simdSourceBaseJitType, + unsigned simdSize); GenTree* gtNewSimdCreateBroadcastNode( var_types type, GenTree* op1, CorInfoType simdBaseJitType, unsigned simdSize); @@ -5928,7 +5932,7 @@ class Compiler void fgReplaceEhfSuccessor(BasicBlock* block, BasicBlock* oldSucc, BasicBlock* newSucc); void fgRemoveEhfSuccessor(BasicBlock* block, const unsigned succIndex); - + void fgRemoveEhfSuccessor(FlowEdge* succEdge); void fgReplaceJumpTarget(BasicBlock* block, BasicBlock* oldTarget, BasicBlock* newTarget); diff --git a/src/coreclr/jit/emit.h b/src/coreclr/jit/emit.h index 40a729dd70fee2..4fb37df5149111 100644 --- a/src/coreclr/jit/emit.h +++ b/src/coreclr/jit/emit.h @@ -4020,6 +4020,8 @@ emitAttr emitter::emitGetBaseMemOpSize(instrDesc* id) const case INS_subss: case INS_ucomiss: case INS_vbroadcastss: + case INS_vcvttss2usi32: + case INS_vcvttss2usi64: case INS_vfmadd132ss: case INS_vfmadd213ss: case INS_vfmadd231ss: @@ -4067,6 +4069,8 @@ emitAttr emitter::emitGetBaseMemOpSize(instrDesc* id) const case INS_subsd: case INS_ucomisd: case INS_vbroadcastsd: + case INS_vcvttsd2usi32: + case INS_vcvttsd2usi64: case INS_vfmadd132sd: case INS_vfmadd213sd: case INS_vfmadd231sd: diff --git a/src/coreclr/jit/gentree.cpp b/src/coreclr/jit/gentree.cpp index 878c02ac1603df..c6d6b78c48ca9e 100644 --- a/src/coreclr/jit/gentree.cpp +++ b/src/coreclr/jit/gentree.cpp @@ -21350,7 +21350,6 @@ GenTree* Compiler::gtNewSimdCeilNode(var_types type, GenTree* op1, CorInfoType s return gtNewSimdHWIntrinsicNode(type, op1, intrinsic, simdBaseJitType, simdSize); } -#if defined(TARGET_XARCH) GenTree* Compiler::gtNewSimdCvtNode(var_types type, GenTree* op1, CorInfoType simdTargetBaseJitType, @@ -21368,12 +21367,128 @@ GenTree* Compiler::gtNewSimdCvtNode(var_types type, assert(varTypeIsIntegral(simdTargetBaseType)); assert(IsBaselineSimdIsaSupportedDebugOnly()); + +#if defined(TARGET_XARCH) assert(IsBaselineVector512IsaSupportedDebugOnly() || ((simdTargetBaseType == TYP_INT) && ((simdSize == 16 && compIsaSupportedDebugOnly(InstructionSet_SSE41)) || (simdSize == 32 && compIsaSupportedDebugOnly(InstructionSet_AVX))))); + GenTree* fixupVal; + + if (IsBaselineVector512IsaSupportedOpportunistically()) + { + /*Generate the control table for VFIXUPIMMSD/SS + - For conversion to unsigned + // QNAN: 0b1000: Saturate to Zero + // SNAN: 0b1000: Saturate to Zero + // ZERO: 0b0000 + // +ONE: 0b0000 + // -INF: 0b1000: Saturate to Zero + // +INF: 0b0000 + // -VAL: 0b1000: Saturate to Zero + // +VAL: 0b0000 + - For conversion to signed + // QNAN: 0b1000: Saturate to Zero + // SNAN: 0b1000: Saturate to Zero + // ZERO: 0b0000 + // +ONE: 0b0000 + // -INF: 0b0000 + // +INF: 0b0000 + // -VAL: 0b0000 + // +VAL: 0b0000 + */ + int32_t iconVal = varTypeIsUnsigned(simdTargetBaseType) ? 0x08080088 : 0x00000088; + GenTree* tblCon = gtNewSimdCreateBroadcastNode(type, gtNewIconNode(iconVal), simdTargetBaseJitType, simdSize); + + // We need op1Clone to run fixup + GenTree* op1Clone = fgMakeMultiUse(&op1); + + // run vfixupimmsd base on table and no flags reporting + fixupVal = gtNewSimdHWIntrinsicNode(type, op1, op1Clone, tblCon, gtNewIconNode(0), NI_AVX512F_Fixup, + simdSourceBaseJitType, simdSize); + } + else + { + // Zero out NaN values from the input. + // mask1 contains the output either 0xFFFFFFFF or 0. + // FixupVal zeros out any NaN values in the input by ANDing input with mask1. + GenTree* op1Clone1 = fgMakeMultiUse(&op1); + GenTree* op1Clone2 = fgMakeMultiUse(&op1); + GenTree* mask1 = gtNewSimdCmpOpNode(GT_EQ, type, op1, op1Clone1, simdSourceBaseJitType, simdSize); + fixupVal = gtNewSimdBinOpNode(GT_AND, type, op1Clone2, mask1, simdSourceBaseJitType, simdSize); + } + + if (varTypeIsSigned(simdTargetBaseType)) + { + GenTree* maxVal; + GenTree* maxValDup; + if (varTypeIsLong(simdTargetBaseType)) + { + int64_t actualMaxVal = INT64_MAX; + maxVal = gtNewDconNode(static_cast(actualMaxVal), simdSourceBaseType); + maxVal = gtNewSimdCreateBroadcastNode(type, maxVal, simdSourceBaseJitType, simdSize); + maxValDup = + gtNewSimdCreateBroadcastNode(type, gtNewLconNode(actualMaxVal), simdTargetBaseJitType, simdSize); + } + else + { + ssize_t actualMaxVal = INT32_MAX; + maxVal = gtNewDconNode(static_cast(actualMaxVal), simdSourceBaseType); + maxVal = gtNewSimdCreateBroadcastNode(type, maxVal, simdSourceBaseJitType, simdSize); + maxValDup = + gtNewSimdCreateBroadcastNode(type, gtNewIconNode(actualMaxVal), simdTargetBaseJitType, simdSize); + } + + // we will be using the input value twice + GenTree* fixupValDup = fgMakeMultiUse(&fixupVal); + + // compare with max value of integer/long + fixupVal = gtNewSimdCmpOpNode(GT_GE, type, fixupVal, maxVal, simdSourceBaseJitType, simdSize); + + // cast it + GenTree* castNode = + gtNewSimdCvtNativeNode(type, fixupValDup, simdTargetBaseJitType, simdSourceBaseJitType, simdSize); + + // use the fixupVal mask with input value and max value to blend + return gtNewSimdCndSelNode(type, fixupVal, maxValDup, castNode, simdTargetBaseJitType, simdSize); + } + else + { + return gtNewSimdCvtNativeNode(type, fixupVal, simdTargetBaseJitType, simdSourceBaseJitType, simdSize); + } +#elif defined(TARGET_ARM64) + return gtNewSimdCvtNativeNode(type, op1, simdTargetBaseJitType, simdSourceBaseJitType, simdSize); +#else +#error Unsupported platform +#endif // !TARGET_XARCH && !TARGET_ARM64 +} + +GenTree* Compiler::gtNewSimdCvtNativeNode(var_types type, + GenTree* op1, + CorInfoType simdTargetBaseJitType, + CorInfoType simdSourceBaseJitType, + unsigned simdSize) +{ + assert(varTypeIsSIMD(type)); + assert(getSIMDTypeForSize(simdSize) == type); + assert(op1 != nullptr); + assert(op1->TypeIs(type)); + + var_types simdSourceBaseType = JitType2PreciseVarType(simdSourceBaseJitType); + var_types simdTargetBaseType = JitType2PreciseVarType(simdTargetBaseJitType); + assert(varTypeIsFloating(simdSourceBaseType)); + assert(varTypeIsIntegral(simdTargetBaseType)); + + assert(IsBaselineSimdIsaSupportedDebugOnly()); + // Generate intrinsic needed for conversion NamedIntrinsic hwIntrinsicID = NI_Illegal; + +#if defined(TARGET_XARCH) + assert(IsBaselineVector512IsaSupportedDebugOnly() || + ((simdTargetBaseType == TYP_INT) && + ((simdSize == 16) || (simdSize == 32 && compIsaSupportedDebugOnly(InstructionSet_AVX))))); + switch (simdSourceBaseJitType) { case CORINFO_TYPE_FLOAT: @@ -21389,21 +21504,25 @@ GenTree* Compiler::gtNewSimdCvtNode(var_types type, hwIntrinsicID = NI_AVX512F_ConvertToVector512Int32WithTruncation; break; } + case 32: { hwIntrinsicID = NI_AVX_ConvertToVector256Int32WithTruncation; break; } + case 16: { hwIntrinsicID = NI_SSE2_ConvertToVector128Int32WithTruncation; break; } + default: unreached(); } break; } + case CORINFO_TYPE_UINT: { switch (simdSize) @@ -21413,26 +21532,31 @@ GenTree* Compiler::gtNewSimdCvtNode(var_types type, hwIntrinsicID = NI_AVX512F_ConvertToVector512UInt32WithTruncation; break; } + case 32: { hwIntrinsicID = NI_AVX512F_VL_ConvertToVector256UInt32WithTruncation; break; } + case 16: { hwIntrinsicID = NI_AVX512F_VL_ConvertToVector128UInt32WithTruncation; break; } + default: unreached(); } break; } + default: unreached(); } break; } + case CORINFO_TYPE_DOUBLE: { switch (simdTargetBaseJitType) @@ -21446,21 +21570,25 @@ GenTree* Compiler::gtNewSimdCvtNode(var_types type, hwIntrinsicID = NI_AVX512DQ_ConvertToVector512Int64WithTruncation; break; } + case 32: { hwIntrinsicID = NI_AVX512DQ_VL_ConvertToVector256Int64WithTruncation; break; } + case 16: { hwIntrinsicID = NI_AVX512DQ_VL_ConvertToVector128Int64WithTruncation; break; } + default: unreached(); } break; } + case CORINFO_TYPE_ULONG: { switch (simdSize) @@ -21470,115 +21598,95 @@ GenTree* Compiler::gtNewSimdCvtNode(var_types type, hwIntrinsicID = NI_AVX512DQ_ConvertToVector512UInt64WithTruncation; break; } + case 32: { hwIntrinsicID = NI_AVX512DQ_VL_ConvertToVector256UInt64WithTruncation; break; } + case 16: { hwIntrinsicID = NI_AVX512DQ_VL_ConvertToVector128UInt64WithTruncation; break; } + default: unreached(); } break; } + default: unreached(); } break; } + default: unreached(); } - assert(hwIntrinsicID != NI_Illegal); - - GenTree* fixupVal; +#elif defined(TARGET_ARM64) + assert((simdSize == 8) || (simdSize == 16)); - if (IsBaselineVector512IsaSupportedOpportunistically()) + switch (simdSourceBaseJitType) { - /*Generate the control table for VFIXUPIMMSD/SS - - For conversion to unsigned - // QNAN: 0b1000: Saturate to Zero - // SNAN: 0b1000: Saturate to Zero - // ZERO: 0b0000 - // +ONE: 0b0000 - // -INF: 0b1000: Saturate to Zero - // +INF: 0b0000 - // -VAL: 0b1000: Saturate to Zero - // +VAL: 0b0000 - - For conversion to signed - // QNAN: 0b1000: Saturate to Zero - // SNAN: 0b1000: Saturate to Zero - // ZERO: 0b0000 - // +ONE: 0b0000 - // -INF: 0b0000 - // +INF: 0b0000 - // -VAL: 0b0000 - // +VAL: 0b0000 - */ - int32_t iconVal = varTypeIsUnsigned(simdTargetBaseType) ? 0x08080088 : 0x00000088; - GenTree* tblCon = gtNewSimdCreateBroadcastNode(type, gtNewIconNode(iconVal), simdTargetBaseJitType, simdSize); - - // We need op1Clone to run fixup - GenTree* op1Clone = fgMakeMultiUse(&op1); + case CORINFO_TYPE_FLOAT: + { + switch (simdTargetBaseJitType) + { + case CORINFO_TYPE_INT: + { + hwIntrinsicID = NI_AdvSimd_ConvertToInt32RoundToZero; + break; + } - // run vfixupimmsd base on table and no flags reporting - fixupVal = gtNewSimdHWIntrinsicNode(type, op1, op1Clone, tblCon, gtNewIconNode(0), NI_AVX512F_Fixup, - simdSourceBaseJitType, simdSize); - } - else - { - // Zero out NaN values from the input. - // mask1 contains the output either 0xFFFFFFFF or 0. - // FixupVal zeros out any NaN values in the input by ANDing input with mask1. - GenTree* op1Clone1 = fgMakeMultiUse(&op1); - GenTree* op1Clone2 = fgMakeMultiUse(&op1); - GenTree* mask1 = gtNewSimdCmpOpNode(GT_EQ, type, op1, op1Clone1, simdSourceBaseJitType, simdSize); - fixupVal = gtNewSimdBinOpNode(GT_AND, type, op1Clone2, mask1, simdSourceBaseJitType, simdSize); - } + case CORINFO_TYPE_UINT: + { + hwIntrinsicID = NI_AdvSimd_ConvertToUInt32RoundToZero; + break; + } - if (varTypeIsSigned(simdTargetBaseType)) - { - GenTree* maxVal; - GenTree* maxValDup; - if (varTypeIsLong(simdTargetBaseType)) - { - int64_t actualMaxVal = INT64_MAX; - maxVal = gtNewDconNode(static_cast(actualMaxVal), simdSourceBaseType); - maxVal = gtNewSimdCreateBroadcastNode(type, maxVal, simdSourceBaseJitType, simdSize); - maxValDup = - gtNewSimdCreateBroadcastNode(type, gtNewLconNode(actualMaxVal), simdTargetBaseJitType, simdSize); - } - else - { - ssize_t actualMaxVal = INT32_MAX; - maxVal = gtNewDconNode(static_cast(actualMaxVal), simdSourceBaseType); - maxVal = gtNewSimdCreateBroadcastNode(type, maxVal, simdSourceBaseJitType, simdSize); - maxValDup = - gtNewSimdCreateBroadcastNode(type, gtNewIconNode(actualMaxVal), simdTargetBaseJitType, simdSize); + default: + unreached(); + } + break; } - // we will be using the input value twice - GenTree* fixupValDup = fgMakeMultiUse(&fixupVal); + case CORINFO_TYPE_DOUBLE: + { + switch (simdTargetBaseJitType) + { + case CORINFO_TYPE_LONG: + { + hwIntrinsicID = (simdSize == 8) ? NI_AdvSimd_Arm64_ConvertToInt64RoundToZeroScalar + : NI_AdvSimd_Arm64_ConvertToInt64RoundToZero; + break; + } - // compare with max value of integer/long - fixupVal = gtNewSimdCmpOpNode(GT_GE, type, fixupVal, maxVal, simdSourceBaseJitType, simdSize); + case CORINFO_TYPE_ULONG: + { + hwIntrinsicID = (simdSize == 8) ? NI_AdvSimd_Arm64_ConvertToUInt64RoundToZeroScalar + : NI_AdvSimd_Arm64_ConvertToUInt64RoundToZero; + break; + } - // cast it - GenTree* castNode = gtNewSimdHWIntrinsicNode(type, fixupValDup, hwIntrinsicID, simdSourceBaseJitType, simdSize); + default: + unreached(); + } + break; + } - // use the fixupVal mask with input value and max value to blend - return gtNewSimdCndSelNode(type, fixupVal, maxValDup, castNode, simdTargetBaseJitType, simdSize); - } - else - { - return gtNewSimdHWIntrinsicNode(type, fixupVal, hwIntrinsicID, simdSourceBaseJitType, simdSize); + default: + unreached(); } +#else +#error Unsupported platform +#endif // !TARGET_XARCH && !TARGET_ARM64 + + assert(hwIntrinsicID != NI_Illegal); + return gtNewSimdHWIntrinsicNode(type, op1, hwIntrinsicID, simdSourceBaseJitType, simdSize); } -#endif // TARGET_XARCH GenTree* Compiler::gtNewSimdCmpOpNode( genTreeOps op, var_types type, GenTree* op1, GenTree* op2, CorInfoType simdBaseJitType, unsigned simdSize) diff --git a/src/coreclr/jit/hwintrinsicarm64.cpp b/src/coreclr/jit/hwintrinsicarm64.cpp index 8e3288f75d7090..98342739cb4e0d 100644 --- a/src/coreclr/jit/hwintrinsicarm64.cpp +++ b/src/coreclr/jit/hwintrinsicarm64.cpp @@ -621,28 +621,28 @@ GenTree* Compiler::impSpecialIntrinsic(NamedIntrinsic intrinsic, } case NI_Vector64_ConvertToInt32: + case NI_Vector64_ConvertToInt32Native: case NI_Vector128_ConvertToInt32: + case NI_Vector128_ConvertToInt32Native: { assert(sig->numArgs == 1); assert(simdBaseType == TYP_FLOAT); - op1 = impSIMDPopStack(); - retNode = - gtNewSimdHWIntrinsicNode(retType, op1, NI_AdvSimd_ConvertToInt32RoundToZero, simdBaseJitType, simdSize); + op1 = impSIMDPopStack(); + retNode = gtNewSimdCvtNativeNode(retType, op1, CORINFO_TYPE_INT, simdBaseJitType, simdSize); break; } case NI_Vector64_ConvertToInt64: + case NI_Vector64_ConvertToInt64Native: case NI_Vector128_ConvertToInt64: + case NI_Vector128_ConvertToInt64Native: { assert(sig->numArgs == 1); assert(simdBaseType == TYP_DOUBLE); - intrinsic = (simdSize == 8) ? NI_AdvSimd_Arm64_ConvertToInt64RoundToZeroScalar - : NI_AdvSimd_Arm64_ConvertToInt64RoundToZero; - op1 = impSIMDPopStack(); - retNode = gtNewSimdHWIntrinsicNode(retType, op1, intrinsic, simdBaseJitType, simdSize); + retNode = gtNewSimdCvtNativeNode(retType, op1, CORINFO_TYPE_LONG, simdBaseJitType, simdSize); break; } @@ -658,28 +658,28 @@ GenTree* Compiler::impSpecialIntrinsic(NamedIntrinsic intrinsic, } case NI_Vector64_ConvertToUInt32: + case NI_Vector64_ConvertToUInt32Native: case NI_Vector128_ConvertToUInt32: + case NI_Vector128_ConvertToUInt32Native: { assert(sig->numArgs == 1); assert(simdBaseType == TYP_FLOAT); op1 = impSIMDPopStack(); - retNode = gtNewSimdHWIntrinsicNode(retType, op1, NI_AdvSimd_ConvertToUInt32RoundToZero, simdBaseJitType, - simdSize); + retNode = gtNewSimdCvtNativeNode(retType, op1, CORINFO_TYPE_UINT, simdBaseJitType, simdSize); break; } case NI_Vector64_ConvertToUInt64: + case NI_Vector64_ConvertToUInt64Native: case NI_Vector128_ConvertToUInt64: + case NI_Vector128_ConvertToUInt64Native: { assert(sig->numArgs == 1); assert(simdBaseType == TYP_DOUBLE); - intrinsic = (simdSize == 8) ? NI_AdvSimd_Arm64_ConvertToUInt64RoundToZeroScalar - : NI_AdvSimd_Arm64_ConvertToUInt64RoundToZero; - op1 = impSIMDPopStack(); - retNode = gtNewSimdHWIntrinsicNode(retType, op1, intrinsic, simdBaseJitType, simdSize); + retNode = gtNewSimdCvtNativeNode(retType, op1, CORINFO_TYPE_ULONG, simdBaseJitType, simdSize); break; } diff --git a/src/coreclr/jit/hwintrinsiclistarm64.h b/src/coreclr/jit/hwintrinsiclistarm64.h index f1a48b2d28127c..06feb2816de5ce 100644 --- a/src/coreclr/jit/hwintrinsiclistarm64.h +++ b/src/coreclr/jit/hwintrinsiclistarm64.h @@ -37,10 +37,14 @@ HARDWARE_INTRINSIC(Vector64, Ceiling, HARDWARE_INTRINSIC(Vector64, ConditionalSelect, 8, 3, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen) HARDWARE_INTRINSIC(Vector64, ConvertToDouble, 8, 1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen|HW_Flag_BaseTypeFromFirstArg) HARDWARE_INTRINSIC(Vector64, ConvertToInt32, 8, 1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen|HW_Flag_BaseTypeFromFirstArg) +HARDWARE_INTRINSIC(Vector64, ConvertToInt32Native, 8, 1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen|HW_Flag_BaseTypeFromFirstArg) HARDWARE_INTRINSIC(Vector64, ConvertToInt64, 8, 1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen|HW_Flag_BaseTypeFromFirstArg) +HARDWARE_INTRINSIC(Vector64, ConvertToInt64Native, 8, 1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen|HW_Flag_BaseTypeFromFirstArg) HARDWARE_INTRINSIC(Vector64, ConvertToSingle, 8, 1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen|HW_Flag_BaseTypeFromFirstArg) HARDWARE_INTRINSIC(Vector64, ConvertToUInt32, 8, 1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen|HW_Flag_BaseTypeFromFirstArg) +HARDWARE_INTRINSIC(Vector64, ConvertToUInt32Native, 8, 1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen|HW_Flag_BaseTypeFromFirstArg) HARDWARE_INTRINSIC(Vector64, ConvertToUInt64, 8, 1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen|HW_Flag_BaseTypeFromFirstArg) +HARDWARE_INTRINSIC(Vector64, ConvertToUInt64Native, 8, 1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen|HW_Flag_BaseTypeFromFirstArg) HARDWARE_INTRINSIC(Vector64, Create, 8, -1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen) HARDWARE_INTRINSIC(Vector64, CreateScalar, 8, -1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen) HARDWARE_INTRINSIC(Vector64, CreateScalarUnsafe, 8, 1, true, {INS_ins, INS_ins, INS_ins, INS_ins, INS_ins, INS_ins, INS_invalid, INS_invalid, INS_fmov, INS_invalid}, HW_Category_SIMD, HW_Flag_SpecialImport|HW_Flag_SpecialCodeGen|HW_Flag_SupportsContainment) @@ -146,10 +150,14 @@ HARDWARE_INTRINSIC(Vector128, Ceiling, HARDWARE_INTRINSIC(Vector128, ConditionalSelect, 16, 3, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen) HARDWARE_INTRINSIC(Vector128, ConvertToDouble, 16, 1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen|HW_Flag_BaseTypeFromFirstArg) HARDWARE_INTRINSIC(Vector128, ConvertToInt32, 16, 1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen|HW_Flag_BaseTypeFromFirstArg) +HARDWARE_INTRINSIC(Vector128, ConvertToInt32Native, 16, 1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen|HW_Flag_BaseTypeFromFirstArg) HARDWARE_INTRINSIC(Vector128, ConvertToInt64, 16, 1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen|HW_Flag_BaseTypeFromFirstArg) +HARDWARE_INTRINSIC(Vector128, ConvertToInt64Native, 16, 1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen|HW_Flag_BaseTypeFromFirstArg) HARDWARE_INTRINSIC(Vector128, ConvertToSingle, 16, 1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen|HW_Flag_BaseTypeFromFirstArg) HARDWARE_INTRINSIC(Vector128, ConvertToUInt32, 16, 1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen|HW_Flag_BaseTypeFromFirstArg) +HARDWARE_INTRINSIC(Vector128, ConvertToUInt32Native, 16, 1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen|HW_Flag_BaseTypeFromFirstArg) HARDWARE_INTRINSIC(Vector128, ConvertToUInt64, 16, 1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen|HW_Flag_BaseTypeFromFirstArg) +HARDWARE_INTRINSIC(Vector128, ConvertToUInt64Native, 16, 1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen|HW_Flag_BaseTypeFromFirstArg) HARDWARE_INTRINSIC(Vector128, Create, 16, -1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen) HARDWARE_INTRINSIC(Vector128, CreateScalar, 16, -1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen) HARDWARE_INTRINSIC(Vector128, CreateScalarUnsafe, 16, 1, true, {INS_ins, INS_ins, INS_ins, INS_ins, INS_ins, INS_ins, INS_ins, INS_ins, INS_fmov, INS_fmov}, HW_Category_SIMD, HW_Flag_SpecialImport|HW_Flag_SpecialCodeGen|HW_Flag_SupportsContainment) diff --git a/src/coreclr/jit/hwintrinsiclistxarch.h b/src/coreclr/jit/hwintrinsiclistxarch.h index 07bc2e4838c88c..d3f7c575a86667 100644 --- a/src/coreclr/jit/hwintrinsiclistxarch.h +++ b/src/coreclr/jit/hwintrinsiclistxarch.h @@ -56,10 +56,14 @@ HARDWARE_INTRINSIC(Vector128, Ceiling, HARDWARE_INTRINSIC(Vector128, ConditionalSelect, 16, 3, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen) HARDWARE_INTRINSIC(Vector128, ConvertToDouble, 16, 1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen|HW_Flag_BaseTypeFromFirstArg) HARDWARE_INTRINSIC(Vector128, ConvertToInt32, 16, 1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen|HW_Flag_BaseTypeFromFirstArg) +HARDWARE_INTRINSIC(Vector128, ConvertToInt32Native, 16, 1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen|HW_Flag_BaseTypeFromFirstArg) HARDWARE_INTRINSIC(Vector128, ConvertToInt64, 16, 1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen|HW_Flag_BaseTypeFromFirstArg) +HARDWARE_INTRINSIC(Vector128, ConvertToInt64Native, 16, 1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen|HW_Flag_BaseTypeFromFirstArg) HARDWARE_INTRINSIC(Vector128, ConvertToSingle, 16, 1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen|HW_Flag_BaseTypeFromFirstArg) HARDWARE_INTRINSIC(Vector128, ConvertToUInt32, 16, 1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen|HW_Flag_BaseTypeFromFirstArg) +HARDWARE_INTRINSIC(Vector128, ConvertToUInt32Native, 16, 1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen|HW_Flag_BaseTypeFromFirstArg) HARDWARE_INTRINSIC(Vector128, ConvertToUInt64, 16, 1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen|HW_Flag_BaseTypeFromFirstArg) +HARDWARE_INTRINSIC(Vector128, ConvertToUInt64Native, 16, 1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen|HW_Flag_BaseTypeFromFirstArg) HARDWARE_INTRINSIC(Vector128, Create, 16, -1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen) HARDWARE_INTRINSIC(Vector128, CreateScalar, 16, 1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen) HARDWARE_INTRINSIC(Vector128, CreateScalarUnsafe, 16, 1, true, {INS_movd, INS_movd, INS_movd, INS_movd, INS_movd, INS_movd, INS_movd, INS_movd, INS_movss, INS_movsd_simd}, HW_Category_SIMDScalar, HW_Flag_SpecialImport|HW_Flag_SpecialCodeGen|HW_Flag_NoRMWSemantics) @@ -162,10 +166,14 @@ HARDWARE_INTRINSIC(Vector256, Ceiling, HARDWARE_INTRINSIC(Vector256, ConditionalSelect, 32, 3, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen|HW_Flag_AvxOnlyCompatible) HARDWARE_INTRINSIC(Vector256, ConvertToDouble, 32, 1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen|HW_Flag_BaseTypeFromFirstArg) HARDWARE_INTRINSIC(Vector256, ConvertToInt32, 32, 1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen|HW_Flag_BaseTypeFromFirstArg|HW_Flag_AvxOnlyCompatible) +HARDWARE_INTRINSIC(Vector256, ConvertToInt32Native, 32, 1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen|HW_Flag_BaseTypeFromFirstArg|HW_Flag_AvxOnlyCompatible) HARDWARE_INTRINSIC(Vector256, ConvertToInt64, 32, 1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen|HW_Flag_BaseTypeFromFirstArg) +HARDWARE_INTRINSIC(Vector256, ConvertToInt64Native, 32, 1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen|HW_Flag_BaseTypeFromFirstArg) HARDWARE_INTRINSIC(Vector256, ConvertToSingle, 32, 1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen|HW_Flag_BaseTypeFromFirstArg|HW_Flag_AvxOnlyCompatible) HARDWARE_INTRINSIC(Vector256, ConvertToUInt32, 32, 1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen|HW_Flag_BaseTypeFromFirstArg) +HARDWARE_INTRINSIC(Vector256, ConvertToUInt32Native, 32, 1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen|HW_Flag_BaseTypeFromFirstArg) HARDWARE_INTRINSIC(Vector256, ConvertToUInt64, 32, 1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen|HW_Flag_BaseTypeFromFirstArg) +HARDWARE_INTRINSIC(Vector256, ConvertToUInt64Native, 32, 1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen|HW_Flag_BaseTypeFromFirstArg) HARDWARE_INTRINSIC(Vector256, Create, 32, -1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen|HW_Flag_AvxOnlyCompatible) HARDWARE_INTRINSIC(Vector256, CreateScalar, 32, -1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen|HW_Flag_AvxOnlyCompatible) HARDWARE_INTRINSIC(Vector256, CreateScalarUnsafe, 32, 1, true, {INS_movd, INS_movd, INS_movd, INS_movd, INS_movd, INS_movd, INS_movd, INS_movd, INS_movss, INS_movsd_simd}, HW_Category_SIMDScalar, HW_Flag_SpecialImport|HW_Flag_SpecialCodeGen|HW_Flag_AvxOnlyCompatible) @@ -274,11 +282,15 @@ HARDWARE_INTRINSIC(Vector512, CreateScalar, HARDWARE_INTRINSIC(Vector512, CreateScalarUnsafe, 64, 1, true, {INS_movd, INS_movd, INS_movd, INS_movd, INS_movd, INS_movd, INS_movd, INS_movd, INS_movss, INS_movsd_simd}, HW_Category_SIMDScalar, HW_Flag_SpecialImport|HW_Flag_SpecialCodeGen) HARDWARE_INTRINSIC(Vector512, CreateSequence, 64, 2, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen) HARDWARE_INTRINSIC(Vector512, ConvertToDouble, 64, 1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen|HW_Flag_BaseTypeFromFirstArg) -HARDWARE_INTRINSIC(Vector512, ConvertToSingle, 64, 1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen|HW_Flag_BaseTypeFromFirstArg) HARDWARE_INTRINSIC(Vector512, ConvertToInt32, 64, 1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen|HW_Flag_BaseTypeFromFirstArg) +HARDWARE_INTRINSIC(Vector512, ConvertToInt32Native, 64, 1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen|HW_Flag_BaseTypeFromFirstArg) HARDWARE_INTRINSIC(Vector512, ConvertToInt64, 64, 1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen|HW_Flag_BaseTypeFromFirstArg) +HARDWARE_INTRINSIC(Vector512, ConvertToInt64Native, 64, 1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen|HW_Flag_BaseTypeFromFirstArg) +HARDWARE_INTRINSIC(Vector512, ConvertToSingle, 64, 1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen|HW_Flag_BaseTypeFromFirstArg) HARDWARE_INTRINSIC(Vector512, ConvertToUInt32, 64, 1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen|HW_Flag_BaseTypeFromFirstArg) +HARDWARE_INTRINSIC(Vector512, ConvertToUInt32Native, 64, 1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen|HW_Flag_BaseTypeFromFirstArg) HARDWARE_INTRINSIC(Vector512, ConvertToUInt64, 64, 1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen|HW_Flag_BaseTypeFromFirstArg) +HARDWARE_INTRINSIC(Vector512, ConvertToUInt64Native, 64, 1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen|HW_Flag_BaseTypeFromFirstArg) HARDWARE_INTRINSIC(Vector512, Divide, 64, 2, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen) HARDWARE_INTRINSIC(Vector512, Equals, 64, 2, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoCodeGen) HARDWARE_INTRINSIC(Vector512, EqualsAll, 64, 2, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoCodeGen) diff --git a/src/coreclr/jit/hwintrinsicxarch.cpp b/src/coreclr/jit/hwintrinsicxarch.cpp index fc3c01e4c31d29..553e1bdf78366a 100644 --- a/src/coreclr/jit/hwintrinsicxarch.cpp +++ b/src/coreclr/jit/hwintrinsicxarch.cpp @@ -1440,58 +1440,59 @@ GenTree* Compiler::impSpecialIntrinsic(NamedIntrinsic intrinsic, break; } - case NI_Vector128_ConvertToInt64: - case NI_Vector256_ConvertToInt64: - case NI_Vector512_ConvertToInt64: + case NI_Vector128_ConvertToInt32: + case NI_Vector256_ConvertToInt32: + case NI_Vector512_ConvertToInt32: { assert(sig->numArgs == 1); - assert(simdBaseType == TYP_DOUBLE); - if (IsBaselineVector512IsaSupportedOpportunistically()) + assert(simdBaseType == TYP_FLOAT); + + if (compOpportunisticallyDependsOn(InstructionSet_SSE41)) { op1 = impSIMDPopStack(); - retNode = gtNewSimdCvtNode(retType, op1, CORINFO_TYPE_LONG, simdBaseJitType, simdSize); + retNode = gtNewSimdCvtNode(retType, op1, CORINFO_TYPE_INT, simdBaseJitType, simdSize); } break; } - case NI_Vector128_ConvertToUInt32: - case NI_Vector256_ConvertToUInt32: - case NI_Vector512_ConvertToUInt32: + case NI_Vector128_ConvertToInt32Native: + case NI_Vector256_ConvertToInt32Native: + case NI_Vector512_ConvertToInt32Native: { assert(sig->numArgs == 1); assert(simdBaseType == TYP_FLOAT); - if (IsBaselineVector512IsaSupportedOpportunistically()) - { - op1 = impSIMDPopStack(); - retNode = gtNewSimdCvtNode(retType, op1, CORINFO_TYPE_UINT, simdBaseJitType, simdSize); - } + + op1 = impSIMDPopStack(); + retNode = gtNewSimdCvtNativeNode(retType, op1, CORINFO_TYPE_INT, simdBaseJitType, simdSize); break; } - case NI_Vector128_ConvertToUInt64: - case NI_Vector256_ConvertToUInt64: - case NI_Vector512_ConvertToUInt64: + case NI_Vector128_ConvertToInt64: + case NI_Vector256_ConvertToInt64: + case NI_Vector512_ConvertToInt64: { assert(sig->numArgs == 1); assert(simdBaseType == TYP_DOUBLE); + if (IsBaselineVector512IsaSupportedOpportunistically()) { op1 = impSIMDPopStack(); - retNode = gtNewSimdCvtNode(retType, op1, CORINFO_TYPE_ULONG, simdBaseJitType, simdSize); + retNode = gtNewSimdCvtNode(retType, op1, CORINFO_TYPE_LONG, simdBaseJitType, simdSize); } break; } - case NI_Vector128_ConvertToInt32: - case NI_Vector256_ConvertToInt32: - case NI_Vector512_ConvertToInt32: + case NI_Vector128_ConvertToInt64Native: + case NI_Vector256_ConvertToInt64Native: + case NI_Vector512_ConvertToInt64Native: { assert(sig->numArgs == 1); - assert(simdBaseType == TYP_FLOAT); - if (compOpportunisticallyDependsOn(InstructionSet_SSE41)) + assert(simdBaseType == TYP_DOUBLE); + + if (IsBaselineVector512IsaSupportedOpportunistically()) { op1 = impSIMDPopStack(); - retNode = gtNewSimdCvtNode(retType, op1, CORINFO_TYPE_INT, simdBaseJitType, simdSize); + retNode = gtNewSimdCvtNativeNode(retType, op1, CORINFO_TYPE_LONG, simdBaseJitType, simdSize); } break; } @@ -1545,6 +1546,65 @@ GenTree* Compiler::impSpecialIntrinsic(NamedIntrinsic intrinsic, break; } + case NI_Vector128_ConvertToUInt32: + case NI_Vector256_ConvertToUInt32: + case NI_Vector512_ConvertToUInt32: + { + assert(sig->numArgs == 1); + assert(simdBaseType == TYP_FLOAT); + + if (IsBaselineVector512IsaSupportedOpportunistically()) + { + op1 = impSIMDPopStack(); + retNode = gtNewSimdCvtNode(retType, op1, CORINFO_TYPE_UINT, simdBaseJitType, simdSize); + } + break; + } + + case NI_Vector128_ConvertToUInt32Native: + case NI_Vector256_ConvertToUInt32Native: + case NI_Vector512_ConvertToUInt32Native: + { + assert(sig->numArgs == 1); + assert(simdBaseType == TYP_FLOAT); + + if (IsBaselineVector512IsaSupportedOpportunistically()) + { + op1 = impSIMDPopStack(); + retNode = gtNewSimdCvtNativeNode(retType, op1, CORINFO_TYPE_UINT, simdBaseJitType, simdSize); + } + break; + } + + case NI_Vector128_ConvertToUInt64: + case NI_Vector256_ConvertToUInt64: + case NI_Vector512_ConvertToUInt64: + { + assert(sig->numArgs == 1); + assert(simdBaseType == TYP_DOUBLE); + if (IsBaselineVector512IsaSupportedOpportunistically()) + { + op1 = impSIMDPopStack(); + retNode = gtNewSimdCvtNode(retType, op1, CORINFO_TYPE_ULONG, simdBaseJitType, simdSize); + } + break; + } + + case NI_Vector128_ConvertToUInt64Native: + case NI_Vector256_ConvertToUInt64Native: + case NI_Vector512_ConvertToUInt64Native: + { + assert(sig->numArgs == 1); + assert(simdBaseType == TYP_DOUBLE); + + if (IsBaselineVector512IsaSupportedOpportunistically()) + { + op1 = impSIMDPopStack(); + retNode = gtNewSimdCvtNativeNode(retType, op1, CORINFO_TYPE_ULONG, simdBaseJitType, simdSize); + } + break; + } + case NI_Vector128_Create: case NI_Vector256_Create: case NI_Vector512_Create: diff --git a/src/coreclr/jit/importercalls.cpp b/src/coreclr/jit/importercalls.cpp index 0ec0d6b9afd3e8..4dc64523217230 100644 --- a/src/coreclr/jit/importercalls.cpp +++ b/src/coreclr/jit/importercalls.cpp @@ -5164,12 +5164,16 @@ GenTree* Compiler::impPrimitiveNamedIntrinsic(NamedIntrinsic intrinsic, assert(sig->sigInst.classInstCount == 0); var_types retType = JITtype2varType(sig->retType); - assert(varTypeIsArithmetic(retType)); + + if (!varTypeIsArithmetic(retType)) + { + assert((intrinsic == NI_PRIMITIVE_ConvertToInteger) || (intrinsic == NI_PRIMITIVE_ConvertToIntegerNative)); + return nullptr; + } NamedIntrinsic hwintrinsic = NI_Illegal; CORINFO_ARG_LIST_HANDLE args = sig->args; - assert((sig->numArgs == 1) || (sig->numArgs == 2)); CORINFO_CLASS_HANDLE op1ClsHnd; @@ -5180,6 +5184,113 @@ GenTree* Compiler::impPrimitiveNamedIntrinsic(NamedIntrinsic intrinsic, switch (intrinsic) { + case NI_PRIMITIVE_ConvertToInteger: + case NI_PRIMITIVE_ConvertToIntegerNative: + { + assert(sig->sigInst.methInstCount == 1); + assert(varTypeIsFloating(baseType)); + + var_types tgtType = JitType2PreciseVarType(sig->retType); + retType = genActualType(retType); + bool uns = varTypeIsUnsigned(tgtType) && !varTypeIsSmall(tgtType); + + GenTree* res = nullptr; + GenTree* op1 = nullptr; + +#if defined(TARGET_XARCH) && defined(FEATURE_HW_INTRINSICS) + if ((intrinsic == NI_PRIMITIVE_ConvertToIntegerNative) && IsBaselineSimdIsaSupported()) + { + NamedIntrinsic hwIntrinsicId = NI_Illegal; + + if (retType == TYP_INT) + { + if (baseType == TYP_FLOAT) + { + if (!uns) + { + hwIntrinsicId = NI_SSE_ConvertToInt32WithTruncation; + } + else if (IsBaselineVector512IsaSupportedOpportunistically()) + { + hwIntrinsicId = NI_AVX512F_ConvertToUInt32WithTruncation; + } + } + else + { + assert(baseType == TYP_DOUBLE); + + if (!uns) + { + hwIntrinsicId = NI_SSE2_ConvertToInt32WithTruncation; + } + else if (IsBaselineVector512IsaSupportedOpportunistically()) + { + hwIntrinsicId = NI_AVX512F_ConvertToUInt32WithTruncation; + } + } + } +#if defined(TARGET_AMD64) + else + { + assert(retType == TYP_LONG); + + if (baseType == TYP_FLOAT) + { + if (!uns) + { + hwIntrinsicId = NI_SSE_X64_ConvertToInt64WithTruncation; + } + else if (IsBaselineVector512IsaSupportedOpportunistically()) + { + hwIntrinsicId = NI_AVX512F_X64_ConvertToUInt64WithTruncation; + } + } + else + { + assert(baseType == TYP_DOUBLE); + + if (!uns) + { + hwIntrinsicId = NI_SSE2_X64_ConvertToInt64WithTruncation; + } + else if (IsBaselineVector512IsaSupportedOpportunistically()) + { + hwIntrinsicId = NI_AVX512F_X64_ConvertToUInt64WithTruncation; + } + } + } +#endif // TARGET_AMD64 + + if (hwIntrinsicId != NI_Illegal) + { + op1 = impPopStack().val; + res = gtNewSimdHWIntrinsicNode(retType, op1, hwIntrinsicId, baseJitType, 16); + + if (varTypeIsSmall(tgtType)) + { + res = gtNewCastNode(TYP_INT, res, /* uns */ false, tgtType); + } + return res; + } + } +#endif // TARGET_XARCH && FEATURE_HW_INTRINSICS + + op1 = impPopStack().val; + + if (varTypeIsSmall(tgtType)) + { + res = gtNewCastNodeL(retType, op1, /* uns */ false, retType); + res = gtFoldExpr(res); + res = gtNewCastNode(TYP_INT, res, /* uns */ false, tgtType); + } + else + { + res = gtNewCastNodeL(retType, op1, /* uns */ false, tgtType); + } + + return gtFoldExpr(res); + } + case NI_PRIMITIVE_Crc32C: { assert(sig->numArgs == 2); @@ -10072,6 +10183,19 @@ NamedIntrinsic Compiler::lookupPrimitiveFloatNamedIntrinsic(CORINFO_METHOD_HANDL { result = NI_System_Math_Ceiling; } + else if (strncmp(methodName, "ConvertToInteger", 16) == 0) + { + methodName += 16; + + if (methodName[0] == '\0') + { + result = NI_PRIMITIVE_ConvertToInteger; + } + else if (strcmp(methodName, "Native") == 0) + { + result = NI_PRIMITIVE_ConvertToIntegerNative; + } + } else if (strncmp(methodName, "Cos", 3) == 0) { methodName += 3; diff --git a/src/coreclr/jit/namedintrinsiclist.h b/src/coreclr/jit/namedintrinsiclist.h index b3eb292677d809..67eec1059e82e8 100644 --- a/src/coreclr/jit/namedintrinsiclist.h +++ b/src/coreclr/jit/namedintrinsiclist.h @@ -227,6 +227,8 @@ enum NamedIntrinsic : unsigned short NI_PRIMITIVE_START, + NI_PRIMITIVE_ConvertToInteger, + NI_PRIMITIVE_ConvertToIntegerNative, NI_PRIMITIVE_Crc32C, NI_PRIMITIVE_LeadingZeroCount, NI_PRIMITIVE_Log2, diff --git a/src/coreclr/jit/simdashwintrinsic.cpp b/src/coreclr/jit/simdashwintrinsic.cpp index 9ffd3b7b011d55..c9b227440d4e5d 100644 --- a/src/coreclr/jit/simdashwintrinsic.cpp +++ b/src/coreclr/jit/simdashwintrinsic.cpp @@ -523,20 +523,23 @@ GenTree* Compiler::impSimdAsHWIntrinsicSpecial(NamedIntrinsic intrinsic, return nullptr; } - case NI_VectorT_ConvertToInt64: - case NI_VectorT_ConvertToUInt32: - case NI_VectorT_ConvertToUInt64: + case NI_VectorT_ConvertToInt32: { - if (IsBaselineVector512IsaSupportedOpportunistically()) + if (compOpportunisticallyDependsOn(InstructionSet_SSE41)) { break; } return nullptr; } - case NI_VectorT_ConvertToInt32: + case NI_VectorT_ConvertToInt64: + case NI_VectorT_ConvertToInt64Native: + case NI_VectorT_ConvertToUInt32: + case NI_VectorT_ConvertToUInt32Native: + case NI_VectorT_ConvertToUInt64: + case NI_VectorT_ConvertToUInt64Native: { - if (compOpportunisticallyDependsOn(InstructionSet_SSE41)) + if (IsBaselineVector512IsaSupportedOpportunistically()) { break; } @@ -1175,34 +1178,6 @@ GenTree* Compiler::impSimdAsHWIntrinsicSpecial(NamedIntrinsic intrinsic, } #if defined(TARGET_XARCH) - - case NI_VectorT_ConvertToInt64: - { - assert(sig->numArgs == 1); - assert(simdBaseType == TYP_DOUBLE); - return gtNewSimdCvtNode(retType, op1, CORINFO_TYPE_LONG, simdBaseJitType, simdSize); - } - - case NI_VectorT_ConvertToUInt32: - { - assert(sig->numArgs == 1); - assert(simdBaseType == TYP_FLOAT); - return gtNewSimdCvtNode(retType, op1, CORINFO_TYPE_UINT, simdBaseJitType, simdSize); - } - - case NI_VectorT_ConvertToUInt64: - { - assert(sig->numArgs == 1); - assert(simdBaseType == TYP_DOUBLE); - return gtNewSimdCvtNode(retType, op1, CORINFO_TYPE_ULONG, simdBaseJitType, simdSize); - } - - case NI_VectorT_ConvertToInt32: - { - assert(simdBaseType == TYP_FLOAT); - return gtNewSimdCvtNode(retType, op1, CORINFO_TYPE_INT, simdBaseJitType, simdSize); - } - case NI_VectorT_ConvertToDouble: { assert(sig->numArgs == 1); @@ -1273,43 +1248,71 @@ GenTree* Compiler::impSimdAsHWIntrinsicSpecial(NamedIntrinsic intrinsic, simdSize); } + case NI_VectorT_ConvertToSingle: + { + assert((simdBaseType == TYP_INT) || (simdBaseType == TYP_UINT)); + return gtNewSimdHWIntrinsicNode(retType, op1, NI_AdvSimd_ConvertToSingle, simdBaseJitType, + simdSize); + } +#else +#error Unsupported platform +#endif // !TARGET_XARCH && !TARGET_ARM64 + case NI_VectorT_ConvertToInt32: { + assert(sig->numArgs == 1); assert(simdBaseType == TYP_FLOAT); - return gtNewSimdHWIntrinsicNode(retType, op1, NI_AdvSimd_ConvertToInt32RoundToZero, simdBaseJitType, - simdSize); + return gtNewSimdCvtNode(retType, op1, CORINFO_TYPE_INT, simdBaseJitType, simdSize); + } + + case NI_VectorT_ConvertToInt32Native: + { + assert(sig->numArgs == 1); + assert(simdBaseType == TYP_FLOAT); + return gtNewSimdCvtNativeNode(retType, op1, CORINFO_TYPE_INT, simdBaseJitType, simdSize); } case NI_VectorT_ConvertToInt64: { + assert(sig->numArgs == 1); assert(simdBaseType == TYP_DOUBLE); - return gtNewSimdHWIntrinsicNode(retType, op1, NI_AdvSimd_Arm64_ConvertToInt64RoundToZero, - simdBaseJitType, simdSize); + return gtNewSimdCvtNode(retType, op1, CORINFO_TYPE_LONG, simdBaseJitType, simdSize); } - case NI_VectorT_ConvertToSingle: + case NI_VectorT_ConvertToInt64Native: { - assert((simdBaseType == TYP_INT) || (simdBaseType == TYP_UINT)); - return gtNewSimdHWIntrinsicNode(retType, op1, NI_AdvSimd_ConvertToSingle, simdBaseJitType, - simdSize); + assert(sig->numArgs == 1); + assert(simdBaseType == TYP_DOUBLE); + return gtNewSimdCvtNativeNode(retType, op1, CORINFO_TYPE_LONG, simdBaseJitType, simdSize); } case NI_VectorT_ConvertToUInt32: { + assert(sig->numArgs == 1); + assert(simdBaseType == TYP_FLOAT); + return gtNewSimdCvtNode(retType, op1, CORINFO_TYPE_UINT, simdBaseJitType, simdSize); + } + + case NI_VectorT_ConvertToUInt32Native: + { + assert(sig->numArgs == 1); assert(simdBaseType == TYP_FLOAT); - return gtNewSimdHWIntrinsicNode(retType, op1, NI_AdvSimd_ConvertToUInt32RoundToZero, - simdBaseJitType, simdSize); + return gtNewSimdCvtNativeNode(retType, op1, CORINFO_TYPE_UINT, simdBaseJitType, simdSize); } case NI_VectorT_ConvertToUInt64: { + assert(sig->numArgs == 1); assert(simdBaseType == TYP_DOUBLE); - return gtNewSimdHWIntrinsicNode(retType, op1, NI_AdvSimd_Arm64_ConvertToUInt64RoundToZero, - simdBaseJitType, simdSize); + return gtNewSimdCvtNode(retType, op1, CORINFO_TYPE_ULONG, simdBaseJitType, simdSize); + } + + case NI_VectorT_ConvertToUInt64Native: + { + assert(sig->numArgs == 1); + assert(simdBaseType == TYP_DOUBLE); + return gtNewSimdCvtNativeNode(retType, op1, CORINFO_TYPE_ULONG, simdBaseJitType, simdSize); } -#else -#error Unsupported platform -#endif // !TARGET_XARCH && !TARGET_ARM64 default: { diff --git a/src/coreclr/jit/simdashwintrinsiclistarm64.h b/src/coreclr/jit/simdashwintrinsiclistarm64.h index cb8d702be5e71f..911306e712409c 100644 --- a/src/coreclr/jit/simdashwintrinsiclistarm64.h +++ b/src/coreclr/jit/simdashwintrinsiclistarm64.h @@ -224,10 +224,14 @@ SIMD_AS_HWINTRINSIC_ID(VectorT, Ceiling, SIMD_AS_HWINTRINSIC_ID(VectorT, ConditionalSelect, 3, {NI_VectorT_ConditionalSelect, NI_VectorT_ConditionalSelect, NI_VectorT_ConditionalSelect, NI_VectorT_ConditionalSelect, NI_VectorT_ConditionalSelect, NI_VectorT_ConditionalSelect, NI_VectorT_ConditionalSelect, NI_VectorT_ConditionalSelect, NI_VectorT_ConditionalSelect, NI_VectorT_ConditionalSelect}, SimdAsHWIntrinsicFlag::None) SIMD_AS_HWINTRINSIC_ID(VectorT, ConvertToDouble, 1, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_VectorT_ConvertToDouble, NI_VectorT_ConvertToDouble, NI_Illegal, NI_Illegal}, SimdAsHWIntrinsicFlag::None) SIMD_AS_HWINTRINSIC_ID(VectorT, ConvertToInt32, 1, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_VectorT_ConvertToInt32, NI_Illegal}, SimdAsHWIntrinsicFlag::None) +SIMD_AS_HWINTRINSIC_ID(VectorT, ConvertToInt32Native, 1, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_VectorT_ConvertToInt32Native, NI_Illegal}, SimdAsHWIntrinsicFlag::None) SIMD_AS_HWINTRINSIC_ID(VectorT, ConvertToInt64, 1, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_VectorT_ConvertToInt64}, SimdAsHWIntrinsicFlag::None) +SIMD_AS_HWINTRINSIC_ID(VectorT, ConvertToInt64Native, 1, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_VectorT_ConvertToInt64Native}, SimdAsHWIntrinsicFlag::None) SIMD_AS_HWINTRINSIC_ID(VectorT, ConvertToSingle, 1, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_VectorT_ConvertToSingle, NI_VectorT_ConvertToSingle, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal}, SimdAsHWIntrinsicFlag::None) SIMD_AS_HWINTRINSIC_ID(VectorT, ConvertToUInt32, 1, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_VectorT_ConvertToUInt32, NI_Illegal}, SimdAsHWIntrinsicFlag::None) +SIMD_AS_HWINTRINSIC_ID(VectorT, ConvertToUInt32Native, 1, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_VectorT_ConvertToUInt32Native, NI_Illegal}, SimdAsHWIntrinsicFlag::None) SIMD_AS_HWINTRINSIC_ID(VectorT, ConvertToUInt64, 1, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_VectorT_ConvertToUInt64}, SimdAsHWIntrinsicFlag::None) +SIMD_AS_HWINTRINSIC_ID(VectorT, ConvertToUInt64Native, 1, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_VectorT_ConvertToUInt64Native}, SimdAsHWIntrinsicFlag::None) SIMD_AS_HWINTRINSIC_NM(VectorT, CreateBroadcast, ".ctor", 2, {NI_VectorT_CreateBroadcast, NI_VectorT_CreateBroadcast, NI_VectorT_CreateBroadcast, NI_VectorT_CreateBroadcast, NI_VectorT_CreateBroadcast, NI_VectorT_CreateBroadcast, NI_VectorT_CreateBroadcast, NI_VectorT_CreateBroadcast, NI_VectorT_CreateBroadcast, NI_VectorT_CreateBroadcast}, SimdAsHWIntrinsicFlag::InstanceMethod | SimdAsHWIntrinsicFlag::SpillSideEffectsOp1) SIMD_AS_HWINTRINSIC_ID(VectorT, CreateSequence, 2, {NI_VectorT_CreateSequence, NI_VectorT_CreateSequence, NI_VectorT_CreateSequence, NI_VectorT_CreateSequence, NI_VectorT_CreateSequence, NI_VectorT_CreateSequence, NI_VectorT_CreateSequence, NI_VectorT_CreateSequence, NI_VectorT_CreateSequence, NI_VectorT_CreateSequence}, SimdAsHWIntrinsicFlag::SpillSideEffectsOp1) SIMD_AS_HWINTRINSIC_ID(VectorT, Divide, 2, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_VectorT_Divide, NI_VectorT_Divide}, SimdAsHWIntrinsicFlag::None) diff --git a/src/coreclr/jit/simdashwintrinsiclistxarch.h b/src/coreclr/jit/simdashwintrinsiclistxarch.h index 5cf07eff0c84ae..dd1d6374bc248f 100644 --- a/src/coreclr/jit/simdashwintrinsiclistxarch.h +++ b/src/coreclr/jit/simdashwintrinsiclistxarch.h @@ -224,10 +224,14 @@ SIMD_AS_HWINTRINSIC_ID(VectorT, Ceiling, SIMD_AS_HWINTRINSIC_ID(VectorT, ConditionalSelect, 3, {NI_VectorT_ConditionalSelect, NI_VectorT_ConditionalSelect, NI_VectorT_ConditionalSelect, NI_VectorT_ConditionalSelect, NI_VectorT_ConditionalSelect, NI_VectorT_ConditionalSelect, NI_VectorT_ConditionalSelect, NI_VectorT_ConditionalSelect, NI_VectorT_ConditionalSelect, NI_VectorT_ConditionalSelect}, SimdAsHWIntrinsicFlag::None) SIMD_AS_HWINTRINSIC_ID(VectorT, ConvertToDouble, 1, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_VectorT_ConvertToDouble, NI_VectorT_ConvertToDouble, NI_Illegal, NI_Illegal}, SimdAsHWIntrinsicFlag::None) SIMD_AS_HWINTRINSIC_ID(VectorT, ConvertToInt32, 1, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_VectorT_ConvertToInt32, NI_Illegal}, SimdAsHWIntrinsicFlag::None) +SIMD_AS_HWINTRINSIC_ID(VectorT, ConvertToInt32Native, 1, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_VectorT_ConvertToInt32Native, NI_Illegal}, SimdAsHWIntrinsicFlag::None) SIMD_AS_HWINTRINSIC_ID(VectorT, ConvertToInt64, 1, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_VectorT_ConvertToInt64}, SimdAsHWIntrinsicFlag::None) +SIMD_AS_HWINTRINSIC_ID(VectorT, ConvertToInt64Native, 1, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_VectorT_ConvertToInt64Native}, SimdAsHWIntrinsicFlag::None) SIMD_AS_HWINTRINSIC_ID(VectorT, ConvertToSingle, 1, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_VectorT_ConvertToSingle, NI_VectorT_ConvertToSingle, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal}, SimdAsHWIntrinsicFlag::None) SIMD_AS_HWINTRINSIC_ID(VectorT, ConvertToUInt32, 1, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_VectorT_ConvertToUInt32, NI_Illegal}, SimdAsHWIntrinsicFlag::None) +SIMD_AS_HWINTRINSIC_ID(VectorT, ConvertToUInt32Native, 1, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_VectorT_ConvertToUInt32Native, NI_Illegal}, SimdAsHWIntrinsicFlag::None) SIMD_AS_HWINTRINSIC_ID(VectorT, ConvertToUInt64, 1, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_VectorT_ConvertToUInt64}, SimdAsHWIntrinsicFlag::None) +SIMD_AS_HWINTRINSIC_ID(VectorT, ConvertToUInt64Native, 1, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_VectorT_ConvertToUInt64Native}, SimdAsHWIntrinsicFlag::None) SIMD_AS_HWINTRINSIC_NM(VectorT, CreateBroadcast, ".ctor", 2, {NI_VectorT_CreateBroadcast, NI_VectorT_CreateBroadcast, NI_VectorT_CreateBroadcast, NI_VectorT_CreateBroadcast, NI_VectorT_CreateBroadcast, NI_VectorT_CreateBroadcast, NI_VectorT_CreateBroadcast, NI_VectorT_CreateBroadcast, NI_VectorT_CreateBroadcast, NI_VectorT_CreateBroadcast}, SimdAsHWIntrinsicFlag::InstanceMethod | SimdAsHWIntrinsicFlag::SpillSideEffectsOp1) SIMD_AS_HWINTRINSIC_ID(VectorT, CreateSequence, 2, {NI_VectorT_CreateSequence, NI_VectorT_CreateSequence, NI_VectorT_CreateSequence, NI_VectorT_CreateSequence, NI_VectorT_CreateSequence, NI_VectorT_CreateSequence, NI_VectorT_CreateSequence, NI_VectorT_CreateSequence, NI_VectorT_CreateSequence, NI_VectorT_CreateSequence}, SimdAsHWIntrinsicFlag::SpillSideEffectsOp1) SIMD_AS_HWINTRINSIC_ID(VectorT, Divide, 2, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_VectorT_Divide, NI_VectorT_Divide}, SimdAsHWIntrinsicFlag::None) diff --git a/src/libraries/Common/tests/System/GenericMathHelpers.cs b/src/libraries/Common/tests/System/GenericMathHelpers.cs index 277580dc5920d8..a02f8a4e162a6e 100644 --- a/src/libraries/Common/tests/System/GenericMathHelpers.cs +++ b/src/libraries/Common/tests/System/GenericMathHelpers.cs @@ -151,6 +151,12 @@ public static class FloatingPointHelper { public static TSelf Ceiling(TSelf x) => TSelf.Ceiling(x); + public static TInteger ConvertToInteger(TSelf x) + where TInteger : IBinaryInteger => TSelf.ConvertToInteger(x); + + public static TInteger ConvertToIntegerNative(TSelf x) + where TInteger : IBinaryInteger => TSelf.ConvertToIntegerNative(x); + public static TSelf Floor(TSelf x) => TSelf.Floor(x); public static TSelf Round(TSelf x) => TSelf.Round(x); diff --git a/src/libraries/System.Numerics.Vectors/ref/System.Numerics.Vectors.cs b/src/libraries/System.Numerics.Vectors/ref/System.Numerics.Vectors.cs index 8bf4cb6c534827..531a379cf06e99 100644 --- a/src/libraries/System.Numerics.Vectors/ref/System.Numerics.Vectors.cs +++ b/src/libraries/System.Numerics.Vectors/ref/System.Numerics.Vectors.cs @@ -235,14 +235,20 @@ public static partial class Vector [System.CLSCompliantAttribute(false)] public static System.Numerics.Vector ConvertToDouble(System.Numerics.Vector value) { throw null; } public static System.Numerics.Vector ConvertToInt32(System.Numerics.Vector value) { throw null; } + public static System.Numerics.Vector ConvertToInt32Native(System.Numerics.Vector value) { throw null; } public static System.Numerics.Vector ConvertToInt64(System.Numerics.Vector value) { throw null; } + public static System.Numerics.Vector ConvertToInt64Native(System.Numerics.Vector value) { throw null; } public static System.Numerics.Vector ConvertToSingle(System.Numerics.Vector value) { throw null; } [System.CLSCompliantAttribute(false)] public static System.Numerics.Vector ConvertToSingle(System.Numerics.Vector value) { throw null; } [System.CLSCompliantAttribute(false)] public static System.Numerics.Vector ConvertToUInt32(System.Numerics.Vector value) { throw null; } [System.CLSCompliantAttribute(false)] + public static System.Numerics.Vector ConvertToUInt32Native(System.Numerics.Vector value) { throw null; } + [System.CLSCompliantAttribute(false)] public static System.Numerics.Vector ConvertToUInt64(System.Numerics.Vector value) { throw null; } + [System.CLSCompliantAttribute(false)] + public static System.Numerics.Vector ConvertToUInt64Native(System.Numerics.Vector value) { throw null; } public static System.Numerics.Vector CreateSequence(T start, T step) { throw null; } public static System.Numerics.Vector Divide(System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } public static System.Numerics.Vector Divide(System.Numerics.Vector left, T right) { throw null; } diff --git a/src/libraries/System.Private.CoreLib/src/System/Decimal.cs b/src/libraries/System.Private.CoreLib/src/System/Decimal.cs index f2d89445f834ba..189e54dcc1ef74 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Decimal.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Decimal.cs @@ -1117,6 +1117,14 @@ object IConvertible.ToType(Type type, IFormatProvider? provider) // IFloatingPoint // + /// + public static TInteger ConvertToInteger(decimal value) + where TInteger : IBinaryInteger => TInteger.CreateSaturating(value); + + /// + public static TInteger ConvertToIntegerNative(decimal value) + where TInteger : IBinaryInteger => TInteger.CreateSaturating(value); + /// int IFloatingPoint.GetExponentByteCount() => sizeof(sbyte); diff --git a/src/libraries/System.Private.CoreLib/src/System/Double.cs b/src/libraries/System.Private.CoreLib/src/System/Double.cs index 71d73546bc1364..04e8269c78f464 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Double.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Double.cs @@ -655,6 +655,16 @@ public static bool IsPow2(double value) [Intrinsic] public static double Ceiling(double x) => Math.Ceiling(x); + /// + [Intrinsic] + public static TInteger ConvertToInteger(double value) + where TInteger : IBinaryInteger => TInteger.CreateSaturating(value); + + /// + [Intrinsic] + public static TInteger ConvertToIntegerNative(double value) + where TInteger : IBinaryInteger => TInteger.CreateSaturating(value); + /// [Intrinsic] public static double Floor(double x) => Math.Floor(x); diff --git a/src/libraries/System.Private.CoreLib/src/System/Half.cs b/src/libraries/System.Private.CoreLib/src/System/Half.cs index adc7df07932f7f..d4459c5162366f 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Half.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Half.cs @@ -1314,6 +1314,14 @@ public static bool IsPow2(Half value) /// public static Half Ceiling(Half x) => (Half)MathF.Ceiling((float)x); + /// + public static TInteger ConvertToInteger(Half value) + where TInteger : IBinaryInteger => TInteger.CreateSaturating(value); + + /// + public static TInteger ConvertToIntegerNative(Half value) + where TInteger : IBinaryInteger => TInteger.CreateSaturating(value); + /// public static Half Floor(Half x) => (Half)MathF.Floor((float)x); diff --git a/src/libraries/System.Private.CoreLib/src/System/Numerics/IFloatingPoint.cs b/src/libraries/System.Private.CoreLib/src/System/Numerics/IFloatingPoint.cs index e36c76007bbdfd..9c92a14f0e75c7 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Numerics/IFloatingPoint.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Numerics/IFloatingPoint.cs @@ -16,6 +16,26 @@ public interface IFloatingPoint /// The ceiling of . static virtual TSelf Ceiling(TSelf x) => TSelf.Round(x, digits: 0, MidpointRounding.ToPositiveInfinity); + /// Converts a value to a specified integer type using saturation on overflow + /// The integer type to which is converted. + /// The value to be converted. + /// An instance of created from . + static virtual TInteger ConvertToInteger(TSelf value) + where TInteger : IBinaryInteger + { + return TInteger.CreateSaturating(value); + } + + /// Converts a value to a specified integer type using platform specific behavior on overflow. + /// The integer type to which is converted. + /// The value to be converted. + /// An instance of created from . + static virtual TInteger ConvertToIntegerNative(TSelf value) + where TInteger : IBinaryInteger + { + return TSelf.ConvertToInteger(value); + } + /// Computes the floor of a value. /// The value whose floor is to be computed. /// The floor of . diff --git a/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector.cs b/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector.cs index 5d8bc58bbe26ee..0e968e6fca8f34 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector.cs @@ -325,7 +325,7 @@ public static Vector ConvertToDouble(Vector value) } } - /// Converts a to a . + /// Converts a to a using saturation on overflow. /// The vector to convert. /// The converted vector. [Intrinsic] @@ -342,7 +342,13 @@ public static Vector ConvertToInt32(Vector value) return result; } - /// Converts a to a . + /// Converts a to a using platform specific behavior on overflow. + /// The vector to convert. + /// The converted vector. + [Intrinsic] + public static Vector ConvertToInt32Native(Vector value) => ConvertToInt32(value); + + /// Converts a to a using saturation on overflow. /// The vector to convert. /// The converted vector. [Intrinsic] @@ -359,6 +365,12 @@ public static Vector ConvertToInt64(Vector value) return result; } + /// Converts a to a using platform specific behavior on overflow. + /// The vector to convert. + /// The converted vector. + [Intrinsic] + public static Vector ConvertToInt64Native(Vector value) => ConvertToInt64(value); + /// Converts a to a . /// The vector to convert. /// The converted vector. @@ -396,7 +408,7 @@ public static Vector ConvertToSingle(Vector value) } } - /// Converts a to a . + /// Converts a to a using saturation on overflow. /// The vector to convert. /// The converted vector. [Intrinsic] @@ -414,7 +426,14 @@ public static Vector ConvertToUInt32(Vector value) return result; } - /// Converts a to a . + /// Converts a to a using platform specific behavior on overflow. + /// The vector to convert. + /// The converted vector. + [Intrinsic] + [CLSCompliant(false)] + public static Vector ConvertToUInt32Native(Vector value) => ConvertToUInt32(value); + + /// Converts a to a using saturation on overflow. /// The vector to convert. /// The converted vector. [Intrinsic] @@ -432,6 +451,13 @@ public static Vector ConvertToUInt64(Vector value) return result; } + /// Converts a to a using platform specific behavior on overflow. + /// The vector to convert. + /// The converted vector. + [Intrinsic] + [CLSCompliant(false)] + public static Vector ConvertToUInt64Native(Vector value) => ConvertToUInt64(value); + /// Creates a new instance where the elements begin at a specified value and which are spaced apart according to another specified value. /// The type of the elements in the vector. /// The value that element 0 will be initialized to. diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/NFloat.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/NFloat.cs index 37c39bbc029a24..b314daec02a93c 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/NFloat.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/NFloat.cs @@ -992,6 +992,14 @@ static NFloat IBinaryNumber.AllBitsSet /// public static NFloat Ceiling(NFloat x) => new NFloat(NativeType.Ceiling(x._value)); + /// + public static TInteger ConvertToInteger(NFloat value) + where TInteger : IBinaryInteger => TInteger.CreateSaturating(value); + + /// + public static TInteger ConvertToIntegerNative(NFloat value) + where TInteger : IBinaryInteger => TInteger.CreateSaturating(value); + /// public static NFloat Floor(NFloat x) => new NFloat(NativeType.Floor(x._value)); diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector128.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector128.cs index 3e24e591a32c12..4080b06c92b77b 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector128.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector128.cs @@ -468,7 +468,7 @@ public static unsafe Vector128 ConvertToDouble(Vector128 vector) } } - /// Converts a to a . + /// Converts a to a using saturation on overflow. /// The vector to convert. /// The converted vector. [Intrinsic] @@ -481,7 +481,20 @@ public static unsafe Vector128 ConvertToInt32(Vector128 vector) ); } - /// Converts a to a . + /// Converts a to a platform specific behavior on overflow. + /// The vector to convert. + /// The converted vector. + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static unsafe Vector128 ConvertToInt32Native(Vector128 vector) + { + return Create( + Vector64.ConvertToInt32Native(vector._lower), + Vector64.ConvertToInt32Native(vector._upper) + ); + } + + /// Converts a to a using saturation on overflow. /// The vector to convert. /// The converted vector. [Intrinsic] @@ -494,6 +507,19 @@ public static unsafe Vector128 ConvertToInt64(Vector128 vector) ); } + /// Converts a to a using platform specific behavior on overflow. + /// The vector to convert. + /// The converted vector. + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static unsafe Vector128 ConvertToInt64Native(Vector128 vector) + { + return Create( + Vector64.ConvertToInt64Native(vector._lower), + Vector64.ConvertToInt64Native(vector._upper) + ); + } + /// Converts a to a . /// The vector to convert. /// The converted vector. @@ -564,7 +590,7 @@ static Vector128 SoftwareFallback(Vector128 vector) } } - /// Converts a to a . + /// Converts a to a using saturation on overflow. /// The vector to convert. /// The converted vector. [Intrinsic] @@ -578,7 +604,21 @@ public static unsafe Vector128 ConvertToUInt32(Vector128 vector) ); } - /// Converts a to a . + /// Converts a to a using platform specific behavior on overflow. + /// The vector to convert. + /// The converted vector. + [Intrinsic] + [CLSCompliant(false)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static unsafe Vector128 ConvertToUInt32Native(Vector128 vector) + { + return Create( + Vector64.ConvertToUInt32Native(vector._lower), + Vector64.ConvertToUInt32Native(vector._upper) + ); + } + + /// Converts a to a using saturation on overflow. /// The vector to convert. /// The converted vector. [Intrinsic] @@ -592,6 +632,20 @@ public static unsafe Vector128 ConvertToUInt64(Vector128 vector) ); } + /// Converts a to a using platform specific behavior on overflow. + /// The vector to convert. + /// The converted vector. + [Intrinsic] + [CLSCompliant(false)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static unsafe Vector128 ConvertToUInt64Native(Vector128 vector) + { + return Create( + Vector64.ConvertToUInt64Native(vector._lower), + Vector64.ConvertToUInt64Native(vector._upper) + ); + } + /// Copies a to a given array. /// The type of the elements in the vector. /// The vector to be copied. diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector256.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector256.cs index 1347a082afab97..4d174eef197544 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector256.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector256.cs @@ -386,7 +386,7 @@ public static Vector256 ConvertToDouble(Vector256 vector) } } - /// Converts a to a . + /// Converts a to a using saturation on overflow. /// The vector to convert. /// The converted vector. [Intrinsic] @@ -399,7 +399,20 @@ public static Vector256 ConvertToInt32(Vector256 vector) ); } - /// Converts a to a . + /// Converts a to a using platform specific behavior on overflow. + /// The vector to convert. + /// The converted vector. + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector256 ConvertToInt32Native(Vector256 vector) + { + return Create( + Vector128.ConvertToInt32Native(vector._lower), + Vector128.ConvertToInt32Native(vector._upper) + ); + } + + /// Converts a to a using saturation on overflow. /// The vector to convert. /// The converted vector. [Intrinsic] @@ -412,6 +425,19 @@ public static Vector256 ConvertToInt64(Vector256 vector) ); } + /// Converts a to a using platform specific behavior on overflow. + /// The vector to convert. + /// The converted vector. + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector256 ConvertToInt64Native(Vector256 vector) + { + return Create( + Vector128.ConvertToInt64Native(vector._lower), + Vector128.ConvertToInt64Native(vector._upper) + ); + } + /// Converts a to a . /// The vector to convert. /// The converted vector. @@ -472,7 +498,7 @@ public static Vector256 ConvertToSingle(Vector256 vector) } } - /// Converts a to a . + /// Converts a to a using saturation on overflow. /// The vector to convert. /// The converted vector. [Intrinsic] @@ -486,7 +512,21 @@ public static Vector256 ConvertToUInt32(Vector256 vector) ); } - /// Converts a to a . + /// Converts a to a using platform specific behavior on overflow. + /// The vector to convert. + /// The converted vector. + [Intrinsic] + [CLSCompliant(false)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector256 ConvertToUInt32Native(Vector256 vector) + { + return Create( + Vector128.ConvertToUInt32Native(vector._lower), + Vector128.ConvertToUInt32Native(vector._upper) + ); + } + + /// Converts a to a using saturation on overflow. /// The vector to convert. /// The converted vector. [Intrinsic] @@ -500,6 +540,20 @@ public static Vector256 ConvertToUInt64(Vector256 vector) ); } + /// Converts a to a using platform specific behavior on overflow. + /// The vector to convert. + /// The converted vector. + [Intrinsic] + [CLSCompliant(false)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector256 ConvertToUInt64Native(Vector256 vector) + { + return Create( + Vector128.ConvertToUInt64Native(vector._lower), + Vector128.ConvertToUInt64Native(vector._upper) + ); + } + /// Copies a to a given array. /// The type of the elements in the vector. /// The vector to be copied. diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector512.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector512.cs index edb84585a987de..d63f12afb64d9c 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector512.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector512.cs @@ -348,7 +348,7 @@ public static Vector512 ConvertToDouble(Vector512 vector) ); } - /// Converts a to a . + /// Converts a to a using saturation on overflow. /// The vector to convert. /// The converted vector. [Intrinsic] @@ -361,7 +361,20 @@ public static Vector512 ConvertToInt32(Vector512 vector) ); } - /// Converts a to a . + /// Converts a to a using platform specific behavior on overflow. + /// The vector to convert. + /// The converted vector. + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector512 ConvertToInt32Native(Vector512 vector) + { + return Create( + Vector256.ConvertToInt32Native(vector._lower), + Vector256.ConvertToInt32Native(vector._upper) + ); + } + + /// Converts a to a using saturation on overflow. /// The vector to convert. /// The converted vector. [Intrinsic] @@ -374,6 +387,19 @@ public static Vector512 ConvertToInt64(Vector512 vector) ); } + /// Converts a to a using platform specific behavior on overflow. + /// The vector to convert. + /// The converted vector. + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector512 ConvertToInt64Native(Vector512 vector) + { + return Create( + Vector256.ConvertToInt64Native(vector._lower), + Vector256.ConvertToInt64Native(vector._upper) + ); + } + /// Converts a to a . /// The vector to convert. /// The converted vector. @@ -401,7 +427,7 @@ public static Vector512 ConvertToSingle(Vector512 vector) ); } - /// Converts a to a . + /// Converts a to a using saturation on overflow. /// The vector to convert. /// The converted vector. [Intrinsic] @@ -415,7 +441,21 @@ public static Vector512 ConvertToUInt32(Vector512 vector) ); } - /// Converts a to a . + /// Converts a to a using platform specific behavior on overflow. + /// The vector to convert. + /// The converted vector. + [Intrinsic] + [CLSCompliant(false)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector512 ConvertToUInt32Native(Vector512 vector) + { + return Create( + Vector256.ConvertToUInt32Native(vector._lower), + Vector256.ConvertToUInt32Native(vector._upper) + ); + } + + /// Converts a to a using saturation on overflow. /// The vector to convert. /// The converted vector. [Intrinsic] @@ -429,6 +469,20 @@ public static Vector512 ConvertToUInt64(Vector512 vector) ); } + /// Converts a to a using platform specific behavior on overflow. + /// The vector to convert. + /// The converted vector. + [Intrinsic] + [CLSCompliant(false)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector512 ConvertToUInt64Native(Vector512 vector) + { + return Create( + Vector256.ConvertToUInt64Native(vector._lower), + Vector256.ConvertToUInt64Native(vector._upper) + ); + } + /// Copies a to a given array. /// The type of the elements in the vector. /// The vector to be copied. diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector64.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector64.cs index 50e9f697c94f44..04c5e0672a9d1b 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector64.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector64.cs @@ -339,7 +339,7 @@ public static unsafe Vector64 ConvertToDouble(Vector64 vector) return result; } - /// Converts a to a . + /// Converts a to a using saturation on overflow. /// The vector to convert. /// The converted vector. [Intrinsic] @@ -357,7 +357,14 @@ public static unsafe Vector64 ConvertToInt32(Vector64 vector) return result; } - /// Converts a to a . + /// Converts a to a using platform specific behavior on overflow. + /// The vector to convert. + /// The converted vector. + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static unsafe Vector64 ConvertToInt32Native(Vector64 vector) => ConvertToInt32(vector); + + /// Converts a to a using saturation on overflow. /// The vector to convert. /// The converted vector. [Intrinsic] @@ -375,6 +382,13 @@ public static unsafe Vector64 ConvertToInt64(Vector64 vector) return result; } + /// Converts a to a using platform specific behavior on overflow. + /// The vector to convert. + /// The converted vector. + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static unsafe Vector64 ConvertToInt64Native(Vector64 vector) => ConvertToInt64(vector); + /// Converts a to a . /// The vector to convert. /// The converted vector. @@ -412,7 +426,7 @@ public static unsafe Vector64 ConvertToSingle(Vector64 vector) return result; } - /// Converts a to a . + /// Converts a to a using saturation on overflow. /// The vector to convert. /// The converted vector. [Intrinsic] @@ -431,7 +445,15 @@ public static unsafe Vector64 ConvertToUInt32(Vector64 vector) return result; } - /// Converts a to a . + /// Converts a to a using platform specific behavior on overflow. + /// The vector to convert. + /// The converted vector. + [Intrinsic] + [CLSCompliant(false)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static unsafe Vector64 ConvertToUInt32Native(Vector64 vector) => ConvertToUInt32(vector); + + /// Converts a to a using saturation on overflow. /// The vector to convert. /// The converted vector. [Intrinsic] @@ -450,6 +472,14 @@ public static unsafe Vector64 ConvertToUInt64(Vector64 vector) return result; } + /// Converts a to a using platform specific behavior on overflow. + /// The vector to convert. + /// The converted vector. + [Intrinsic] + [CLSCompliant(false)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static unsafe Vector64 ConvertToUInt64Native(Vector64 vector) => ConvertToUInt64(vector); + /// Copies a to a given array. /// The type of the elements in the vector. /// The vector to be copied. diff --git a/src/libraries/System.Private.CoreLib/src/System/Single.cs b/src/libraries/System.Private.CoreLib/src/System/Single.cs index 9cc7c6b56c0adf..8a8a38aa2c0b48 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Single.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Single.cs @@ -650,6 +650,16 @@ public static bool IsPow2(float value) [Intrinsic] public static float Ceiling(float x) => MathF.Ceiling(x); + /// + [Intrinsic] + public static TInteger ConvertToInteger(float value) + where TInteger : IBinaryInteger => TInteger.CreateSaturating(value); + + /// + [Intrinsic] + public static TInteger ConvertToIntegerNative(float value) + where TInteger : IBinaryInteger => TInteger.CreateSaturating(value); + /// [Intrinsic] public static float Floor(float x) => MathF.Floor(x); diff --git a/src/libraries/System.Runtime.InteropServices/ref/System.Runtime.InteropServices.cs b/src/libraries/System.Runtime.InteropServices/ref/System.Runtime.InteropServices.cs index c0fe858d94c608..3b718d224417c7 100644 --- a/src/libraries/System.Runtime.InteropServices/ref/System.Runtime.InteropServices.cs +++ b/src/libraries/System.Runtime.InteropServices/ref/System.Runtime.InteropServices.cs @@ -1341,6 +1341,8 @@ public static void Free(void* ptr) { } public static System.Runtime.InteropServices.NFloat Clamp(System.Runtime.InteropServices.NFloat value, System.Runtime.InteropServices.NFloat min, System.Runtime.InteropServices.NFloat max) { throw null; } public int CompareTo(object? obj) { throw null; } public int CompareTo(System.Runtime.InteropServices.NFloat other) { throw null; } + public static TInteger ConvertToInteger(System.Runtime.InteropServices.NFloat value) where TInteger : System.Numerics.IBinaryInteger { throw null; } + public static TInteger ConvertToIntegerNative(System.Runtime.InteropServices.NFloat value) where TInteger : System.Numerics.IBinaryInteger { throw null; } public static System.Runtime.InteropServices.NFloat CopySign(System.Runtime.InteropServices.NFloat value, System.Runtime.InteropServices.NFloat sign) { throw null; } public static System.Runtime.InteropServices.NFloat Cos(System.Runtime.InteropServices.NFloat x) { throw null; } public static System.Runtime.InteropServices.NFloat Cosh(System.Runtime.InteropServices.NFloat x) { throw null; } diff --git a/src/libraries/System.Runtime.Intrinsics/ref/System.Runtime.Intrinsics.cs b/src/libraries/System.Runtime.Intrinsics/ref/System.Runtime.Intrinsics.cs index c34725ba0bae50..bd7871cdf99065 100644 --- a/src/libraries/System.Runtime.Intrinsics/ref/System.Runtime.Intrinsics.cs +++ b/src/libraries/System.Runtime.Intrinsics/ref/System.Runtime.Intrinsics.cs @@ -49,14 +49,20 @@ public static partial class Vector128 [System.CLSCompliantAttribute(false)] public static System.Runtime.Intrinsics.Vector128 ConvertToDouble(System.Runtime.Intrinsics.Vector128 vector) { throw null; } public static System.Runtime.Intrinsics.Vector128 ConvertToInt32(System.Runtime.Intrinsics.Vector128 vector) { throw null; } + public static System.Runtime.Intrinsics.Vector128 ConvertToInt32Native(System.Runtime.Intrinsics.Vector128 vector) { throw null; } public static System.Runtime.Intrinsics.Vector128 ConvertToInt64(System.Runtime.Intrinsics.Vector128 vector) { throw null; } + public static System.Runtime.Intrinsics.Vector128 ConvertToInt64Native(System.Runtime.Intrinsics.Vector128 vector) { throw null; } public static System.Runtime.Intrinsics.Vector128 ConvertToSingle(System.Runtime.Intrinsics.Vector128 vector) { throw null; } [System.CLSCompliantAttribute(false)] public static System.Runtime.Intrinsics.Vector128 ConvertToSingle(System.Runtime.Intrinsics.Vector128 vector) { throw null; } [System.CLSCompliantAttribute(false)] public static System.Runtime.Intrinsics.Vector128 ConvertToUInt32(System.Runtime.Intrinsics.Vector128 vector) { throw null; } [System.CLSCompliantAttribute(false)] + public static System.Runtime.Intrinsics.Vector128 ConvertToUInt32Native(System.Runtime.Intrinsics.Vector128 vector) { throw null; } + [System.CLSCompliantAttribute(false)] public static System.Runtime.Intrinsics.Vector128 ConvertToUInt64(System.Runtime.Intrinsics.Vector128 vector) { throw null; } + [System.CLSCompliantAttribute(false)] + public static System.Runtime.Intrinsics.Vector128 ConvertToUInt64Native(System.Runtime.Intrinsics.Vector128 vector) { throw null; } public static void CopyTo(this System.Runtime.Intrinsics.Vector128 vector, System.Span destination) { } public static void CopyTo(this System.Runtime.Intrinsics.Vector128 vector, T[] destination) { } public static void CopyTo(this System.Runtime.Intrinsics.Vector128 vector, T[] destination, int startIndex) { } @@ -384,14 +390,20 @@ public static partial class Vector256 [System.CLSCompliantAttribute(false)] public static System.Runtime.Intrinsics.Vector256 ConvertToDouble(System.Runtime.Intrinsics.Vector256 vector) { throw null; } public static System.Runtime.Intrinsics.Vector256 ConvertToInt32(System.Runtime.Intrinsics.Vector256 vector) { throw null; } + public static System.Runtime.Intrinsics.Vector256 ConvertToInt32Native(System.Runtime.Intrinsics.Vector256 vector) { throw null; } public static System.Runtime.Intrinsics.Vector256 ConvertToInt64(System.Runtime.Intrinsics.Vector256 vector) { throw null; } + public static System.Runtime.Intrinsics.Vector256 ConvertToInt64Native(System.Runtime.Intrinsics.Vector256 vector) { throw null; } public static System.Runtime.Intrinsics.Vector256 ConvertToSingle(System.Runtime.Intrinsics.Vector256 vector) { throw null; } [System.CLSCompliantAttribute(false)] public static System.Runtime.Intrinsics.Vector256 ConvertToSingle(System.Runtime.Intrinsics.Vector256 vector) { throw null; } [System.CLSCompliantAttribute(false)] public static System.Runtime.Intrinsics.Vector256 ConvertToUInt32(System.Runtime.Intrinsics.Vector256 vector) { throw null; } [System.CLSCompliantAttribute(false)] + public static System.Runtime.Intrinsics.Vector256 ConvertToUInt32Native(System.Runtime.Intrinsics.Vector256 vector) { throw null; } + [System.CLSCompliantAttribute(false)] public static System.Runtime.Intrinsics.Vector256 ConvertToUInt64(System.Runtime.Intrinsics.Vector256 vector) { throw null; } + [System.CLSCompliantAttribute(false)] + public static System.Runtime.Intrinsics.Vector256 ConvertToUInt64Native(System.Runtime.Intrinsics.Vector256 vector) { throw null; } public static void CopyTo(this System.Runtime.Intrinsics.Vector256 vector, System.Span destination) { } public static void CopyTo(this System.Runtime.Intrinsics.Vector256 vector, T[] destination) { } public static void CopyTo(this System.Runtime.Intrinsics.Vector256 vector, T[] destination, int startIndex) { } @@ -719,14 +731,20 @@ public static partial class Vector512 [System.CLSCompliantAttribute(false)] public static System.Runtime.Intrinsics.Vector512 ConvertToDouble(System.Runtime.Intrinsics.Vector512 vector) { throw null; } public static System.Runtime.Intrinsics.Vector512 ConvertToInt32(System.Runtime.Intrinsics.Vector512 vector) { throw null; } + public static System.Runtime.Intrinsics.Vector512 ConvertToInt32Native(System.Runtime.Intrinsics.Vector512 vector) { throw null; } public static System.Runtime.Intrinsics.Vector512 ConvertToInt64(System.Runtime.Intrinsics.Vector512 vector) { throw null; } + public static System.Runtime.Intrinsics.Vector512 ConvertToInt64Native(System.Runtime.Intrinsics.Vector512 vector) { throw null; } public static System.Runtime.Intrinsics.Vector512 ConvertToSingle(System.Runtime.Intrinsics.Vector512 vector) { throw null; } [System.CLSCompliantAttribute(false)] public static System.Runtime.Intrinsics.Vector512 ConvertToSingle(System.Runtime.Intrinsics.Vector512 vector) { throw null; } [System.CLSCompliantAttribute(false)] public static System.Runtime.Intrinsics.Vector512 ConvertToUInt32(System.Runtime.Intrinsics.Vector512 vector) { throw null; } [System.CLSCompliantAttribute(false)] + public static System.Runtime.Intrinsics.Vector512 ConvertToUInt32Native(System.Runtime.Intrinsics.Vector512 vector) { throw null; } + [System.CLSCompliantAttribute(false)] public static System.Runtime.Intrinsics.Vector512 ConvertToUInt64(System.Runtime.Intrinsics.Vector512 vector) { throw null; } + [System.CLSCompliantAttribute(false)] + public static System.Runtime.Intrinsics.Vector512 ConvertToUInt64Native(System.Runtime.Intrinsics.Vector512 vector) { throw null; } public static void CopyTo(this System.Runtime.Intrinsics.Vector512 vector, System.Span destination) { } public static void CopyTo(this System.Runtime.Intrinsics.Vector512 vector, T[] destination) { } public static void CopyTo(this System.Runtime.Intrinsics.Vector512 vector, T[] destination, int startIndex) { } @@ -1050,14 +1068,20 @@ public static partial class Vector64 [System.CLSCompliantAttribute(false)] public static System.Runtime.Intrinsics.Vector64 ConvertToDouble(System.Runtime.Intrinsics.Vector64 vector) { throw null; } public static System.Runtime.Intrinsics.Vector64 ConvertToInt32(System.Runtime.Intrinsics.Vector64 vector) { throw null; } + public static System.Runtime.Intrinsics.Vector64 ConvertToInt32Native(System.Runtime.Intrinsics.Vector64 vector) { throw null; } public static System.Runtime.Intrinsics.Vector64 ConvertToInt64(System.Runtime.Intrinsics.Vector64 vector) { throw null; } + public static System.Runtime.Intrinsics.Vector64 ConvertToInt64Native(System.Runtime.Intrinsics.Vector64 vector) { throw null; } public static System.Runtime.Intrinsics.Vector64 ConvertToSingle(System.Runtime.Intrinsics.Vector64 vector) { throw null; } [System.CLSCompliantAttribute(false)] public static System.Runtime.Intrinsics.Vector64 ConvertToSingle(System.Runtime.Intrinsics.Vector64 vector) { throw null; } [System.CLSCompliantAttribute(false)] public static System.Runtime.Intrinsics.Vector64 ConvertToUInt32(System.Runtime.Intrinsics.Vector64 vector) { throw null; } [System.CLSCompliantAttribute(false)] + public static System.Runtime.Intrinsics.Vector64 ConvertToUInt32Native(System.Runtime.Intrinsics.Vector64 vector) { throw null; } + [System.CLSCompliantAttribute(false)] public static System.Runtime.Intrinsics.Vector64 ConvertToUInt64(System.Runtime.Intrinsics.Vector64 vector) { throw null; } + [System.CLSCompliantAttribute(false)] + public static System.Runtime.Intrinsics.Vector64 ConvertToUInt64Native(System.Runtime.Intrinsics.Vector64 vector) { throw null; } public static void CopyTo(this System.Runtime.Intrinsics.Vector64 vector, System.Span destination) { } public static void CopyTo(this System.Runtime.Intrinsics.Vector64 vector, T[] destination) { } public static void CopyTo(this System.Runtime.Intrinsics.Vector64 vector, T[] destination, int startIndex) { } diff --git a/src/libraries/System.Runtime.Intrinsics/tests/Vectors/Vector128Tests.cs b/src/libraries/System.Runtime.Intrinsics/tests/Vectors/Vector128Tests.cs index 0ebed660f33689..95cf6d16b66171 100644 --- a/src/libraries/System.Runtime.Intrinsics/tests/Vectors/Vector128Tests.cs +++ b/src/libraries/System.Runtime.Intrinsics/tests/Vectors/Vector128Tests.cs @@ -5,6 +5,7 @@ using System.Numerics; using System.Reflection; using System.Runtime.InteropServices; +using System.Runtime.Intrinsics.X86; using Xunit; namespace System.Runtime.Intrinsics.Tests.Vectors @@ -4872,5 +4873,108 @@ public void Log2SingleTest(float value, float expectedResult, float variance) Vector128 actualResult = Vector128.Log2(Vector128.Create(value)); AssertEqual(Vector128.Create(expectedResult), actualResult, Vector128.Create(variance)); } + + [Fact] + [SkipOnMono("https://github.com/dotnet/runtime/issues/100368")] + public void ConvertToInt32Test() + { + Assert.Equal(Vector128.Create(int.MinValue), Vector128.ConvertToInt32(Vector128.Create(float.MinValue))); + Assert.Equal(Vector128.Create(2), Vector128.ConvertToInt32(Vector128.Create(2.6f))); + Assert.Equal(Vector128.Create(int.MaxValue), Vector128.ConvertToInt32(Vector128.Create(float.MaxValue))); + } + + [Fact] + [SkipOnMono("https://github.com/dotnet/runtime/issues/100368")] + public void ConvertToInt32NativeTest() + { + if (Vector128.IsHardwareAccelerated && Sse2.IsSupported) + { + Assert.Equal(Vector128.Create(int.MinValue), Vector128.ConvertToInt32Native(Vector128.Create(float.MaxValue))); + } + else + { + Assert.Equal(Vector128.Create(int.MaxValue), Vector128.ConvertToInt32Native(Vector128.Create(float.MaxValue))); + } + Assert.Equal(Vector128.Create(int.MinValue), Vector128.ConvertToInt32Native(Vector128.Create(float.MinValue))); + Assert.Equal(Vector128.Create(2), Vector128.ConvertToInt32Native(Vector128.Create(2.6f))); + } + + [Fact] + [SkipOnMono("https://github.com/dotnet/runtime/issues/100368")] + public void ConvertToInt64Test() + { + Assert.Equal(Vector128.Create(long.MinValue), Vector128.ConvertToInt64(Vector128.Create(double.MinValue))); + Assert.Equal(Vector128.Create(2L), Vector128.ConvertToInt64(Vector128.Create(2.6))); + Assert.Equal(Vector128.Create(long.MaxValue), Vector128.ConvertToInt64(Vector128.Create(double.MaxValue))); + } + + [Fact] + [SkipOnMono("https://github.com/dotnet/runtime/issues/100368")] + public void ConvertToInt64NativeTest() + { + if (Vector128.IsHardwareAccelerated && Avx512DQ.VL.IsSupported) + { + Assert.Equal(Vector128.Create(long.MinValue), Vector128.ConvertToInt64Native(Vector128.Create(double.MaxValue))); + } + else + { + Assert.Equal(Vector128.Create(long.MaxValue), Vector128.ConvertToInt64Native(Vector128.Create(double.MaxValue))); + } + + Assert.Equal(Vector128.Create(long.MinValue), Vector128.ConvertToInt64Native(Vector128.Create(double.MinValue))); + Assert.Equal(Vector128.Create(2L), Vector128.ConvertToInt64Native(Vector128.Create(2.6))); + } + + [Fact] + [SkipOnMono("https://github.com/dotnet/runtime/issues/100368")] + public void ConvertToUInt32Test() + { + Assert.Equal(Vector128.Create(uint.MinValue), Vector128.ConvertToUInt32(Vector128.Create(float.MinValue))); + Assert.Equal(Vector128.Create(2u), Vector128.ConvertToUInt32(Vector128.Create(2.6f))); + Assert.Equal(Vector128.Create(uint.MaxValue), Vector128.ConvertToUInt32(Vector128.Create(float.MaxValue))); + } + + [Fact] + [SkipOnMono("https://github.com/dotnet/runtime/issues/100368")] + public void ConvertToUInt32NativeTest() + { + if (Vector128.IsHardwareAccelerated && Avx512F.VL.IsSupported) + { + Assert.Equal(Vector128.Create(uint.MaxValue), Vector128.ConvertToUInt32Native(Vector128.Create(float.MinValue))); + } + else + { + Assert.Equal(Vector128.Create(uint.MinValue), Vector128.ConvertToUInt32Native(Vector128.Create(float.MinValue))); + } + + Assert.Equal(Vector128.Create(2u), Vector128.ConvertToUInt32Native(Vector128.Create(2.6f))); + Assert.Equal(Vector128.Create(uint.MaxValue), Vector128.ConvertToUInt32Native(Vector128.Create(float.MaxValue))); + } + + [Fact] + [SkipOnMono("https://github.com/dotnet/runtime/issues/100368")] + public void ConvertToUInt64Test() + { + Assert.Equal(Vector128.Create(ulong.MinValue), Vector128.ConvertToUInt64(Vector128.Create(double.MinValue))); + Assert.Equal(Vector128.Create(2UL), Vector128.ConvertToUInt64(Vector128.Create(2.6))); + Assert.Equal(Vector128.Create(ulong.MaxValue), Vector128.ConvertToUInt64(Vector128.Create(double.MaxValue))); + } + + [Fact] + [SkipOnMono("https://github.com/dotnet/runtime/issues/100368")] + public void ConvertToUInt64NativeTest() + { + if (Vector128.IsHardwareAccelerated && Avx512DQ.VL.IsSupported) + { + Assert.Equal(Vector128.Create(ulong.MaxValue), Vector128.ConvertToUInt64Native(Vector128.Create(double.MinValue))); + } + else + { + Assert.Equal(Vector128.Create(ulong.MinValue), Vector128.ConvertToUInt64Native(Vector128.Create(double.MinValue))); + } + + Assert.Equal(Vector128.Create(2UL), Vector128.ConvertToUInt64Native(Vector128.Create(2.6))); + Assert.Equal(Vector128.Create(ulong.MaxValue), Vector128.ConvertToUInt64Native(Vector128.Create(double.MaxValue))); + } } } diff --git a/src/libraries/System.Runtime.Intrinsics/tests/Vectors/Vector256Tests.cs b/src/libraries/System.Runtime.Intrinsics/tests/Vectors/Vector256Tests.cs index d658ca08b17b32..a5559d43c81505 100644 --- a/src/libraries/System.Runtime.Intrinsics/tests/Vectors/Vector256Tests.cs +++ b/src/libraries/System.Runtime.Intrinsics/tests/Vectors/Vector256Tests.cs @@ -4,6 +4,7 @@ using System.Numerics; using System.Reflection; using System.Runtime.InteropServices; +using System.Runtime.Intrinsics.X86; using Xunit; namespace System.Runtime.Intrinsics.Tests.Vectors @@ -5887,5 +5888,108 @@ public void Log2SingleTest(float value, float expectedResult, float variance) Vector256 actualResult = Vector256.Log2(Vector256.Create(value)); AssertEqual(Vector256.Create(expectedResult), actualResult, Vector256.Create(variance)); } + + [Fact] + [SkipOnMono("https://github.com/dotnet/runtime/issues/100368")] + public void ConvertToInt32Test() + { + Assert.Equal(Vector256.Create(int.MinValue), Vector256.ConvertToInt32(Vector256.Create(float.MinValue))); + Assert.Equal(Vector256.Create(2), Vector256.ConvertToInt32(Vector256.Create(2.6f))); + Assert.Equal(Vector256.Create(int.MaxValue), Vector256.ConvertToInt32(Vector256.Create(float.MaxValue))); + } + + [Fact] + [SkipOnMono("https://github.com/dotnet/runtime/issues/100368")] + public void ConvertToInt32NativeTest() + { + if (Vector128.IsHardwareAccelerated && Sse2.IsSupported) + { + Assert.Equal(Vector256.Create(int.MinValue), Vector256.ConvertToInt32Native(Vector256.Create(float.MaxValue))); + } + else + { + Assert.Equal(Vector256.Create(int.MaxValue), Vector256.ConvertToInt32Native(Vector256.Create(float.MaxValue))); + } + Assert.Equal(Vector256.Create(int.MinValue), Vector256.ConvertToInt32Native(Vector256.Create(float.MinValue))); + Assert.Equal(Vector256.Create(2), Vector256.ConvertToInt32Native(Vector256.Create(2.6f))); + } + + [Fact] + [SkipOnMono("https://github.com/dotnet/runtime/issues/100368")] + public void ConvertToInt64Test() + { + Assert.Equal(Vector256.Create(long.MinValue), Vector256.ConvertToInt64(Vector256.Create(double.MinValue))); + Assert.Equal(Vector256.Create(2L), Vector256.ConvertToInt64(Vector256.Create(2.6))); + Assert.Equal(Vector256.Create(long.MaxValue), Vector256.ConvertToInt64(Vector256.Create(double.MaxValue))); + } + + [Fact] + [SkipOnMono("https://github.com/dotnet/runtime/issues/100368")] + public void ConvertToInt64NativeTest() + { + if (Vector128.IsHardwareAccelerated && Avx512DQ.VL.IsSupported) + { + Assert.Equal(Vector256.Create(long.MinValue), Vector256.ConvertToInt64Native(Vector256.Create(double.MaxValue))); + } + else + { + Assert.Equal(Vector256.Create(long.MaxValue), Vector256.ConvertToInt64Native(Vector256.Create(double.MaxValue))); + } + + Assert.Equal(Vector256.Create(long.MinValue), Vector256.ConvertToInt64Native(Vector256.Create(double.MinValue))); + Assert.Equal(Vector256.Create(2L), Vector256.ConvertToInt64Native(Vector256.Create(2.6))); + } + + [Fact] + [SkipOnMono("https://github.com/dotnet/runtime/issues/100368")] + public void ConvertToUInt32Test() + { + Assert.Equal(Vector256.Create(uint.MinValue), Vector256.ConvertToUInt32(Vector256.Create(float.MinValue))); + Assert.Equal(Vector256.Create(2u), Vector256.ConvertToUInt32(Vector256.Create(2.6f))); + Assert.Equal(Vector256.Create(uint.MaxValue), Vector256.ConvertToUInt32(Vector256.Create(float.MaxValue))); + } + + [Fact] + [SkipOnMono("https://github.com/dotnet/runtime/issues/100368")] + public void ConvertToUInt32NativeTest() + { + if (Vector128.IsHardwareAccelerated && Avx512F.VL.IsSupported) + { + Assert.Equal(Vector256.Create(uint.MaxValue), Vector256.ConvertToUInt32Native(Vector256.Create(float.MinValue))); + } + else + { + Assert.Equal(Vector256.Create(uint.MinValue), Vector256.ConvertToUInt32Native(Vector256.Create(float.MinValue))); + } + + Assert.Equal(Vector256.Create(2u), Vector256.ConvertToUInt32Native(Vector256.Create(2.6f))); + Assert.Equal(Vector256.Create(uint.MaxValue), Vector256.ConvertToUInt32Native(Vector256.Create(float.MaxValue))); + } + + [Fact] + [SkipOnMono("https://github.com/dotnet/runtime/issues/100368")] + public void ConvertToUInt64Test() + { + Assert.Equal(Vector256.Create(ulong.MinValue), Vector256.ConvertToUInt64(Vector256.Create(double.MinValue))); + Assert.Equal(Vector256.Create(2UL), Vector256.ConvertToUInt64(Vector256.Create(2.6))); + Assert.Equal(Vector256.Create(ulong.MaxValue), Vector256.ConvertToUInt64(Vector256.Create(double.MaxValue))); + } + + [Fact] + [SkipOnMono("https://github.com/dotnet/runtime/issues/100368")] + public void ConvertToUInt64NativeTest() + { + if (Vector128.IsHardwareAccelerated && Avx512DQ.VL.IsSupported) + { + Assert.Equal(Vector256.Create(ulong.MaxValue), Vector256.ConvertToUInt64Native(Vector256.Create(double.MinValue))); + } + else + { + Assert.Equal(Vector256.Create(ulong.MinValue), Vector256.ConvertToUInt64Native(Vector256.Create(double.MinValue))); + } + + Assert.Equal(Vector256.Create(2UL), Vector256.ConvertToUInt64Native(Vector256.Create(2.6))); + Assert.Equal(Vector256.Create(ulong.MaxValue), Vector256.ConvertToUInt64Native(Vector256.Create(double.MaxValue))); + } } } diff --git a/src/libraries/System.Runtime.Intrinsics/tests/Vectors/Vector512Tests.cs b/src/libraries/System.Runtime.Intrinsics/tests/Vectors/Vector512Tests.cs index 4b4f9e2d4692aa..c01f88facbf574 100644 --- a/src/libraries/System.Runtime.Intrinsics/tests/Vectors/Vector512Tests.cs +++ b/src/libraries/System.Runtime.Intrinsics/tests/Vectors/Vector512Tests.cs @@ -4,6 +4,7 @@ using System.Numerics; using System.Reflection; using System.Runtime.InteropServices; +using System.Runtime.Intrinsics.X86; using Xunit; namespace System.Runtime.Intrinsics.Tests.Vectors @@ -5320,5 +5321,108 @@ public void Log2SingleTest(float value, float expectedResult, float variance) Vector512 actualResult = Vector512.Log2(Vector512.Create(value)); AssertEqual(Vector512.Create(expectedResult), actualResult, Vector512.Create(variance)); } + + [Fact] + [SkipOnMono("https://github.com/dotnet/runtime/issues/100368")] + public void ConvertToInt32Test() + { + Assert.Equal(Vector512.Create(int.MinValue), Vector512.ConvertToInt32(Vector512.Create(float.MinValue))); + Assert.Equal(Vector512.Create(2), Vector512.ConvertToInt32(Vector512.Create(2.6f))); + Assert.Equal(Vector512.Create(int.MaxValue), Vector512.ConvertToInt32(Vector512.Create(float.MaxValue))); + } + + [Fact] + [SkipOnMono("https://github.com/dotnet/runtime/issues/100368")] + public void ConvertToInt32NativeTest() + { + if (Vector128.IsHardwareAccelerated && Sse2.IsSupported) + { + Assert.Equal(Vector512.Create(int.MinValue), Vector512.ConvertToInt32Native(Vector512.Create(float.MaxValue))); + } + else + { + Assert.Equal(Vector512.Create(int.MaxValue), Vector512.ConvertToInt32Native(Vector512.Create(float.MaxValue))); + } + Assert.Equal(Vector512.Create(int.MinValue), Vector512.ConvertToInt32Native(Vector512.Create(float.MinValue))); + Assert.Equal(Vector512.Create(2), Vector512.ConvertToInt32Native(Vector512.Create(2.6f))); + } + + [Fact] + [SkipOnMono("https://github.com/dotnet/runtime/issues/100368")] + public void ConvertToInt64Test() + { + Assert.Equal(Vector512.Create(long.MinValue), Vector512.ConvertToInt64(Vector512.Create(double.MinValue))); + Assert.Equal(Vector512.Create(2L), Vector512.ConvertToInt64(Vector512.Create(2.6))); + Assert.Equal(Vector512.Create(long.MaxValue), Vector512.ConvertToInt64(Vector512.Create(double.MaxValue))); + } + + [Fact] + [SkipOnMono("https://github.com/dotnet/runtime/issues/100368")] + public void ConvertToInt64NativeTest() + { + if (Vector128.IsHardwareAccelerated && Avx512DQ.VL.IsSupported) + { + Assert.Equal(Vector512.Create(long.MinValue), Vector512.ConvertToInt64Native(Vector512.Create(double.MaxValue))); + } + else + { + Assert.Equal(Vector512.Create(long.MaxValue), Vector512.ConvertToInt64Native(Vector512.Create(double.MaxValue))); + } + + Assert.Equal(Vector512.Create(long.MinValue), Vector512.ConvertToInt64Native(Vector512.Create(double.MinValue))); + Assert.Equal(Vector512.Create(2L), Vector512.ConvertToInt64Native(Vector512.Create(2.6))); + } + + [Fact] + [SkipOnMono("https://github.com/dotnet/runtime/issues/100368")] + public void ConvertToUInt32Test() + { + Assert.Equal(Vector512.Create(uint.MinValue), Vector512.ConvertToUInt32(Vector512.Create(float.MinValue))); + Assert.Equal(Vector512.Create(2u), Vector512.ConvertToUInt32(Vector512.Create(2.6f))); + Assert.Equal(Vector512.Create(uint.MaxValue), Vector512.ConvertToUInt32(Vector512.Create(float.MaxValue))); + } + + [Fact] + [SkipOnMono("https://github.com/dotnet/runtime/issues/100368")] + public void ConvertToUInt32NativeTest() + { + if (Vector128.IsHardwareAccelerated && Avx512F.VL.IsSupported) + { + Assert.Equal(Vector512.Create(uint.MaxValue), Vector512.ConvertToUInt32Native(Vector512.Create(float.MinValue))); + } + else + { + Assert.Equal(Vector512.Create(uint.MinValue), Vector512.ConvertToUInt32Native(Vector512.Create(float.MinValue))); + } + + Assert.Equal(Vector512.Create(2u), Vector512.ConvertToUInt32Native(Vector512.Create(2.6f))); + Assert.Equal(Vector512.Create(uint.MaxValue), Vector512.ConvertToUInt32Native(Vector512.Create(float.MaxValue))); + } + + [Fact] + [SkipOnMono("https://github.com/dotnet/runtime/issues/100368")] + public void ConvertToUInt64Test() + { + Assert.Equal(Vector512.Create(ulong.MinValue), Vector512.ConvertToUInt64(Vector512.Create(double.MinValue))); + Assert.Equal(Vector512.Create(2UL), Vector512.ConvertToUInt64(Vector512.Create(2.6))); + Assert.Equal(Vector512.Create(ulong.MaxValue), Vector512.ConvertToUInt64(Vector512.Create(double.MaxValue))); + } + + [Fact] + [SkipOnMono("https://github.com/dotnet/runtime/issues/100368")] + public void ConvertToUInt64NativeTest() + { + if (Vector128.IsHardwareAccelerated && Avx512DQ.VL.IsSupported) + { + Assert.Equal(Vector512.Create(ulong.MaxValue), Vector512.ConvertToUInt64Native(Vector512.Create(double.MinValue))); + } + else + { + Assert.Equal(Vector512.Create(ulong.MinValue), Vector512.ConvertToUInt64Native(Vector512.Create(double.MinValue))); + } + + Assert.Equal(Vector512.Create(2UL), Vector512.ConvertToUInt64Native(Vector512.Create(2.6))); + Assert.Equal(Vector512.Create(ulong.MaxValue), Vector512.ConvertToUInt64Native(Vector512.Create(double.MaxValue))); + } } } diff --git a/src/libraries/System.Runtime.Intrinsics/tests/Vectors/Vector64Tests.cs b/src/libraries/System.Runtime.Intrinsics/tests/Vectors/Vector64Tests.cs index 69f37520ad735a..3c2d8064681fe1 100644 --- a/src/libraries/System.Runtime.Intrinsics/tests/Vectors/Vector64Tests.cs +++ b/src/libraries/System.Runtime.Intrinsics/tests/Vectors/Vector64Tests.cs @@ -4,6 +4,7 @@ using System.Numerics; using System.Reflection; using System.Runtime.InteropServices; +using System.Runtime.Intrinsics.X86; using Xunit; namespace System.Runtime.Intrinsics.Tests.Vectors @@ -4287,5 +4288,77 @@ public void Log2SingleTest(float value, float expectedResult, float variance) Vector64 actualResult = Vector64.Log2(Vector64.Create(value)); AssertEqual(Vector64.Create(expectedResult), actualResult, Vector64.Create(variance)); } + + [Fact] + [SkipOnMono("https://github.com/dotnet/runtime/issues/100368")] + public void ConvertToInt32Test() + { + Assert.Equal(Vector64.Create(int.MinValue), Vector64.ConvertToInt32(Vector64.Create(float.MinValue))); + Assert.Equal(Vector64.Create(2), Vector64.ConvertToInt32(Vector64.Create(2.6f))); + Assert.Equal(Vector64.Create(int.MaxValue), Vector64.ConvertToInt32(Vector64.Create(float.MaxValue))); + } + + [Fact] + [SkipOnMono("https://github.com/dotnet/runtime/issues/100368")] + public void ConvertToInt32NativeTest() + { + Assert.Equal(Vector64.Create(int.MinValue), Vector64.ConvertToInt32Native(Vector64.Create(float.MinValue))); + Assert.Equal(Vector64.Create(2), Vector64.ConvertToInt32Native(Vector64.Create(2.6f))); + Assert.Equal(Vector64.Create(int.MaxValue), Vector64.ConvertToInt32Native(Vector64.Create(float.MaxValue))); + } + + [Fact] + [SkipOnMono("https://github.com/dotnet/runtime/issues/100368")] + public void ConvertToInt64Test() + { + Assert.Equal(Vector64.Create(long.MinValue), Vector64.ConvertToInt64(Vector64.Create(double.MinValue))); + Assert.Equal(Vector64.Create(2L), Vector64.ConvertToInt64(Vector64.Create(2.6))); + Assert.Equal(Vector64.Create(long.MaxValue), Vector64.ConvertToInt64(Vector64.Create(double.MaxValue))); + } + + [Fact] + [SkipOnMono("https://github.com/dotnet/runtime/issues/100368")] + public void ConvertToInt64NativeTest() + { + Assert.Equal(Vector64.Create(long.MinValue), Vector64.ConvertToInt64Native(Vector64.Create(double.MinValue))); + Assert.Equal(Vector64.Create(2L), Vector64.ConvertToInt64Native(Vector64.Create(2.6))); + Assert.Equal(Vector64.Create(long.MaxValue), Vector64.ConvertToInt64Native(Vector64.Create(double.MaxValue))); + } + + [Fact] + [SkipOnMono("https://github.com/dotnet/runtime/issues/100368")] + public void ConvertToUInt32Test() + { + Assert.Equal(Vector64.Create(uint.MinValue), Vector64.ConvertToUInt32(Vector64.Create(float.MinValue))); + Assert.Equal(Vector64.Create(2u), Vector64.ConvertToUInt32(Vector64.Create(2.6f))); + Assert.Equal(Vector64.Create(uint.MaxValue), Vector64.ConvertToUInt32(Vector64.Create(float.MaxValue))); + } + + [Fact] + [SkipOnMono("https://github.com/dotnet/runtime/issues/100368")] + public void ConvertToUInt32NativeTest() + { + Assert.Equal(Vector64.Create(uint.MinValue), Vector64.ConvertToUInt32Native(Vector64.Create(float.MinValue))); + Assert.Equal(Vector64.Create(2u), Vector64.ConvertToUInt32Native(Vector64.Create(2.6f))); + Assert.Equal(Vector64.Create(uint.MaxValue), Vector64.ConvertToUInt32Native(Vector64.Create(float.MaxValue))); + } + + [Fact] + [SkipOnMono("https://github.com/dotnet/runtime/issues/100368")] + public void ConvertToUInt64Test() + { + Assert.Equal(Vector64.Create(ulong.MinValue), Vector64.ConvertToUInt64(Vector64.Create(double.MinValue))); + Assert.Equal(Vector64.Create(2UL), Vector64.ConvertToUInt64(Vector64.Create(2.6))); + Assert.Equal(Vector64.Create(ulong.MaxValue), Vector64.ConvertToUInt64(Vector64.Create(double.MaxValue))); + } + + [Fact] + [SkipOnMono("https://github.com/dotnet/runtime/issues/100368")] + public void ConvertToUInt64NativeTest() + { + Assert.Equal(Vector64.Create(ulong.MinValue), Vector64.ConvertToUInt64Native(Vector64.Create(double.MinValue))); + Assert.Equal(Vector64.Create(2UL), Vector64.ConvertToUInt64Native(Vector64.Create(2.6))); + Assert.Equal(Vector64.Create(ulong.MaxValue), Vector64.ConvertToUInt64Native(Vector64.Create(double.MaxValue))); + } } } diff --git a/src/libraries/System.Runtime/ref/System.Runtime.cs b/src/libraries/System.Runtime/ref/System.Runtime.cs index 14575b820c33ab..a3f2a4b07e2f48 100644 --- a/src/libraries/System.Runtime/ref/System.Runtime.cs +++ b/src/libraries/System.Runtime/ref/System.Runtime.cs @@ -4,6 +4,8 @@ // Changes to this file must follow the https://aka.ms/api-review process. // ------------------------------------------------------------------------------ +using System.Numerics; + namespace Microsoft.Win32.SafeHandles { public abstract partial class CriticalHandleMinusOneIsInvalid : System.Runtime.InteropServices.CriticalHandle @@ -1985,6 +1987,8 @@ public void GetObjectData(System.Runtime.Serialization.SerializationInfo info, S public static int Compare(decimal d1, decimal d2) { throw null; } public int CompareTo(decimal value) { throw null; } public int CompareTo(object? value) { throw null; } + public static TInteger ConvertToInteger(decimal value) where TInteger : System.Numerics.IBinaryInteger { throw null; } + public static TInteger ConvertToIntegerNative(decimal value) where TInteger : System.Numerics.IBinaryInteger { throw null; } public static decimal CopySign(decimal value, decimal sign) { throw null; } public static decimal CreateChecked(TOther value) where TOther : System.Numerics.INumberBase { throw null; } public static decimal CreateSaturating(TOther value) where TOther : System.Numerics.INumberBase { throw null; } @@ -2259,6 +2263,8 @@ public DivideByZeroException(string? message, System.Exception? innerException) public static double Clamp(double value, double min, double max) { throw null; } public int CompareTo(double value) { throw null; } public int CompareTo(object? value) { throw null; } + public static TInteger ConvertToInteger(double value) where TInteger : System.Numerics.IBinaryInteger { throw null; } + public static TInteger ConvertToIntegerNative(double value) where TInteger : System.Numerics.IBinaryInteger { throw null; } public static double CopySign(double value, double sign) { throw null; } public static double Cos(double x) { throw null; } public static double Cosh(double x) { throw null; } @@ -2881,6 +2887,8 @@ public enum GCNotificationStatus public static System.Half Clamp(System.Half value, System.Half min, System.Half max) { throw null; } public int CompareTo(System.Half other) { throw null; } public int CompareTo(object? obj) { throw null; } + public static TInteger ConvertToInteger(System.Half value) where TInteger : System.Numerics.IBinaryInteger { throw null; } + public static TInteger ConvertToIntegerNative(System.Half value) where TInteger : System.Numerics.IBinaryInteger { throw null; } public static System.Half CopySign(System.Half value, System.Half sign) { throw null; } public static System.Half Cos(System.Half x) { throw null; } public static System.Half Cosh(System.Half x) { throw null; } @@ -4998,6 +5006,8 @@ public SerializableAttribute() { } public static float Clamp(float value, float min, float max) { throw null; } public int CompareTo(object? value) { throw null; } public int CompareTo(float value) { throw null; } + public static TInteger ConvertToInteger(float value) where TInteger : System.Numerics.IBinaryInteger { throw null; } + public static TInteger ConvertToIntegerNative(float value) where TInteger : System.Numerics.IBinaryInteger { throw null; } public static float CopySign(float value, float sign) { throw null; } public static float Cos(float x) { throw null; } public static float Cosh(float x) { throw null; } @@ -10809,6 +10819,8 @@ public partial interface IFloatingPointIeee754 : System.IComparable, Syst public partial interface IFloatingPoint : System.IComparable, System.IComparable, System.IEquatable, System.IFormattable, System.IParsable, System.ISpanFormattable, System.ISpanParsable, System.Numerics.IAdditionOperators, System.Numerics.IAdditiveIdentity, System.Numerics.IComparisonOperators, System.Numerics.IDecrementOperators, System.Numerics.IDivisionOperators, System.Numerics.IEqualityOperators, System.Numerics.IFloatingPointConstants, System.Numerics.IIncrementOperators, System.Numerics.IModulusOperators, System.Numerics.IMultiplicativeIdentity, System.Numerics.IMultiplyOperators, System.Numerics.INumber, System.Numerics.INumberBase, System.Numerics.ISignedNumber, System.Numerics.ISubtractionOperators, System.Numerics.IUnaryNegationOperators, System.Numerics.IUnaryPlusOperators where TSelf : System.Numerics.IFloatingPoint? { static virtual TSelf Ceiling(TSelf x) { throw null; } + static virtual TInteger ConvertToInteger(TSelf value) where TInteger : System.Numerics.IBinaryInteger { throw null; } + static virtual TInteger ConvertToIntegerNative(TSelf value) where TInteger : System.Numerics.IBinaryInteger { throw null; } static virtual TSelf Floor(TSelf x) { throw null; } int GetExponentByteCount(); int GetExponentShortestBitLength(); diff --git a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/DoubleTests.GenericMath.cs b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/DoubleTests.GenericMath.cs index 05e71be7b325c2..d829eb1199d4d7 100644 --- a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/DoubleTests.GenericMath.cs +++ b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/DoubleTests.GenericMath.cs @@ -3,6 +3,7 @@ using System.Globalization; using System.Runtime.InteropServices; +using System.Runtime.Intrinsics.X86; using Xunit; namespace System.Tests @@ -356,6 +357,172 @@ public static void op_InequalityTest() // IFloatingPoint // + [Fact] + [SkipOnMono("https://github.com/dotnet/runtime/issues/100368")] + public static void ConvertToIntegerTest() + { + // Signed Values + + Assert.Equal(0, FloatingPointHelper.ConvertToInteger(double.MinValue)); + Assert.Equal(int.MinValue, FloatingPointHelper.ConvertToInteger(double.MinValue)); + Assert.Equal(long.MinValue, FloatingPointHelper.ConvertToInteger(double.MinValue)); + Assert.Equal(Int128.MinValue, FloatingPointHelper.ConvertToInteger(double.MinValue)); + Assert.Equal(nint.MinValue, FloatingPointHelper.ConvertToInteger(double.MinValue)); + Assert.Equal(0, FloatingPointHelper.ConvertToInteger(double.MinValue)); + + Assert.Equal(2, FloatingPointHelper.ConvertToInteger(2.6)); + Assert.Equal(2, FloatingPointHelper.ConvertToInteger(2.6)); + Assert.Equal(2, FloatingPointHelper.ConvertToInteger(2.6)); + Assert.Equal(2, FloatingPointHelper.ConvertToInteger(2.6)); + Assert.Equal(2, FloatingPointHelper.ConvertToInteger(2.6)); + Assert.Equal(2, FloatingPointHelper.ConvertToInteger(2.6)); + + Assert.Equal(-1, FloatingPointHelper.ConvertToInteger(double.MaxValue)); + Assert.Equal(int.MaxValue, FloatingPointHelper.ConvertToInteger(double.MaxValue)); + Assert.Equal(long.MaxValue, FloatingPointHelper.ConvertToInteger(double.MaxValue)); + Assert.Equal(Int128.MaxValue, FloatingPointHelper.ConvertToInteger(double.MaxValue)); + Assert.Equal(nint.MaxValue, FloatingPointHelper.ConvertToInteger(double.MaxValue)); + Assert.Equal(-1, FloatingPointHelper.ConvertToInteger(double.MaxValue)); + + // Unsigned Values + + Assert.Equal(byte.MinValue, FloatingPointHelper.ConvertToInteger(double.MinValue)); + Assert.Equal(ushort.MinValue, FloatingPointHelper.ConvertToInteger(double.MinValue)); + Assert.Equal(uint.MinValue, FloatingPointHelper.ConvertToInteger(double.MinValue)); + Assert.Equal(ulong.MinValue, FloatingPointHelper.ConvertToInteger(double.MinValue)); + Assert.Equal(UInt128.MinValue, FloatingPointHelper.ConvertToInteger(double.MinValue)); + Assert.Equal(nuint.MinValue, FloatingPointHelper.ConvertToInteger(double.MinValue)); + + Assert.Equal(2u, FloatingPointHelper.ConvertToInteger(2.6)); + Assert.Equal(2u, FloatingPointHelper.ConvertToInteger(2.6)); + Assert.Equal(2u, FloatingPointHelper.ConvertToInteger(2.6)); + Assert.Equal(2u, FloatingPointHelper.ConvertToInteger(2.6)); + Assert.Equal(2u, FloatingPointHelper.ConvertToInteger(2.6)); + Assert.Equal(2u, FloatingPointHelper.ConvertToInteger(2.6)); + + Assert.Equal(byte.MaxValue, FloatingPointHelper.ConvertToInteger(double.MaxValue)); + Assert.Equal(ushort.MaxValue, FloatingPointHelper.ConvertToInteger(double.MaxValue)); + Assert.Equal(uint.MaxValue, FloatingPointHelper.ConvertToInteger(double.MaxValue)); + Assert.Equal(ulong.MaxValue, FloatingPointHelper.ConvertToInteger(double.MaxValue)); + Assert.Equal(UInt128.MaxValue, FloatingPointHelper.ConvertToInteger(double.MaxValue)); + Assert.Equal(nuint.MaxValue, FloatingPointHelper.ConvertToInteger(double.MaxValue)); + } + + [Fact] + [SkipOnMono("https://github.com/dotnet/runtime/issues/100368")] + public static void ConvertToIntegerNativeTest() + { + // Signed Values + + Assert.Equal(0, FloatingPointHelper.ConvertToIntegerNative(double.MinValue)); + Assert.Equal(int.MinValue, FloatingPointHelper.ConvertToIntegerNative(double.MinValue)); + Assert.Equal(long.MinValue, FloatingPointHelper.ConvertToIntegerNative(double.MinValue)); + Assert.Equal(Int128.MinValue, FloatingPointHelper.ConvertToIntegerNative(double.MinValue)); + Assert.Equal(nint.MinValue, FloatingPointHelper.ConvertToIntegerNative(double.MinValue)); + Assert.Equal(0, FloatingPointHelper.ConvertToIntegerNative(double.MinValue)); + + Assert.Equal(2, FloatingPointHelper.ConvertToIntegerNative(2.6)); + Assert.Equal(2, FloatingPointHelper.ConvertToIntegerNative(2.6)); + Assert.Equal(2, FloatingPointHelper.ConvertToIntegerNative(2.6)); + Assert.Equal(2, FloatingPointHelper.ConvertToIntegerNative(2.6)); + Assert.Equal(2, FloatingPointHelper.ConvertToIntegerNative(2.6)); + Assert.Equal(2, FloatingPointHelper.ConvertToIntegerNative(2.6)); + + if (Sse2.IsSupported) + { + // On Xarch: + // * Conversion to int is natively supported and returns 0x8000_0000 + // * Conversion to long is natively supported on 64-bit and returns 0x8000_0000_0000_0000 + + Assert.Equal(0, FloatingPointHelper.ConvertToIntegerNative(double.MaxValue)); + Assert.Equal(int.MinValue, FloatingPointHelper.ConvertToIntegerNative(double.MaxValue)); + Assert.Equal(nint.MinValue, FloatingPointHelper.ConvertToIntegerNative(double.MaxValue)); + Assert.Equal(0, FloatingPointHelper.ConvertToIntegerNative(double.MaxValue)); + + if (Environment.Is64BitProcess) + { + Assert.Equal(long.MinValue, FloatingPointHelper.ConvertToIntegerNative(double.MaxValue)); + } + else + { + Assert.Equal(long.MaxValue, FloatingPointHelper.ConvertToIntegerNative(double.MaxValue)); + } + } + else + { + Assert.Equal(-1, FloatingPointHelper.ConvertToIntegerNative(double.MaxValue)); + Assert.Equal(int.MaxValue, FloatingPointHelper.ConvertToIntegerNative(double.MaxValue)); + Assert.Equal(long.MaxValue, FloatingPointHelper.ConvertToIntegerNative(double.MaxValue)); + Assert.Equal(nint.MaxValue, FloatingPointHelper.ConvertToIntegerNative(double.MaxValue)); + Assert.Equal(-1, FloatingPointHelper.ConvertToIntegerNative(double.MaxValue)); + } + Assert.Equal(Int128.MaxValue, FloatingPointHelper.ConvertToIntegerNative(double.MaxValue)); + + // Unsigned Values + + if (Sse2.IsSupported) + { + // On Xarch: + // * Conversion to uint is natively supported w/ Avx512 and returns 0xFFFF_FFFF + // * Conversion to ulong is natively supported on 64-bit w/ Avx512 and returns 0xFFFF_FFFF_FFFF_FFFF + + if (Avx512F.IsSupported) + { + Assert.Equal(uint.MaxValue, FloatingPointHelper.ConvertToIntegerNative(double.MinValue)); + Assert.Equal(nuint.MaxValue, FloatingPointHelper.ConvertToIntegerNative(double.MinValue)); + } + else + { + Assert.Equal(uint.MinValue, FloatingPointHelper.ConvertToIntegerNative(double.MinValue)); + Assert.Equal(nuint.MinValue, FloatingPointHelper.ConvertToIntegerNative(double.MinValue)); + } + + if (Environment.Is64BitProcess && Avx512F.IsSupported) + { + Assert.Equal(ulong.MaxValue, FloatingPointHelper.ConvertToIntegerNative(double.MinValue)); + } + else + { + Assert.Equal(ulong.MinValue, FloatingPointHelper.ConvertToIntegerNative(double.MinValue)); + } + } + else + { + Assert.Equal(uint.MinValue, FloatingPointHelper.ConvertToIntegerNative(double.MinValue)); + Assert.Equal(ulong.MinValue, FloatingPointHelper.ConvertToIntegerNative(double.MinValue)); + Assert.Equal(nuint.MinValue, FloatingPointHelper.ConvertToIntegerNative(double.MinValue)); + } + Assert.Equal(byte.MinValue, FloatingPointHelper.ConvertToIntegerNative(double.MinValue)); + Assert.Equal(ushort.MinValue, FloatingPointHelper.ConvertToIntegerNative(double.MinValue)); + Assert.Equal(UInt128.MinValue, FloatingPointHelper.ConvertToIntegerNative(double.MinValue)); + + Assert.Equal(2u, FloatingPointHelper.ConvertToIntegerNative(2.6)); + Assert.Equal(2u, FloatingPointHelper.ConvertToIntegerNative(2.6)); + Assert.Equal(2u, FloatingPointHelper.ConvertToIntegerNative(2.6)); + Assert.Equal(2u, FloatingPointHelper.ConvertToIntegerNative(2.6)); + Assert.Equal(2u, FloatingPointHelper.ConvertToIntegerNative(2.6)); + Assert.Equal(2u, FloatingPointHelper.ConvertToIntegerNative(2.6)); + + if (Sse2.IsSupported) + { + // On Xarch: + // * Conversion to uint is natively supported w/ Avx512 and returns 0xFFFF_FFFF + // * Conversion to ulong is natively supported on 64-bit w/ Avx512 and returns 0xFFFF_FFFF_FFFF_FFFF + + Assert.Equal(byte.MinValue, FloatingPointHelper.ConvertToIntegerNative(double.MaxValue)); + Assert.Equal(ushort.MinValue, FloatingPointHelper.ConvertToIntegerNative(double.MaxValue)); + } + else + { + Assert.Equal(byte.MaxValue, FloatingPointHelper.ConvertToIntegerNative(double.MaxValue)); + Assert.Equal(ushort.MaxValue, FloatingPointHelper.ConvertToIntegerNative(double.MaxValue)); + } + Assert.Equal(uint.MaxValue, FloatingPointHelper.ConvertToIntegerNative(double.MaxValue)); + Assert.Equal(ulong.MaxValue, FloatingPointHelper.ConvertToIntegerNative(double.MaxValue)); + Assert.Equal(UInt128.MaxValue, FloatingPointHelper.ConvertToIntegerNative(double.MaxValue)); + Assert.Equal(nuint.MaxValue, FloatingPointHelper.ConvertToIntegerNative(double.MaxValue)); + } + [Fact] public static void GetExponentByteCountTest() { @@ -1055,7 +1222,7 @@ public static void CreateCheckedFromDecimalTest() AssertBitwiseEqual(-0.0, NumberBaseHelper.CreateChecked(-0.0m)); AssertBitwiseEqual(+0.0, NumberBaseHelper.CreateChecked(+0.0m)); AssertBitwiseEqual(+1.0, NumberBaseHelper.CreateChecked(+1.0m)); - AssertBitwiseEqual(+79228162514264337593543950335.0, NumberBaseHelper.CreateChecked(decimal.MaxValue)); + AssertBitwiseEqual(+79228162514264337593543950335.0, NumberBaseHelper.CreateChecked(decimal.MaxValue)); } [Fact] diff --git a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/SingleTests.GenericMath.cs b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/SingleTests.GenericMath.cs index a6637de7f7e2a3..21a4ba2cd77a11 100644 --- a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/SingleTests.GenericMath.cs +++ b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/SingleTests.GenericMath.cs @@ -3,6 +3,7 @@ using System.Globalization; using System.Runtime.InteropServices; +using System.Runtime.Intrinsics.X86; using Xunit; namespace System.Tests @@ -356,6 +357,172 @@ public static void op_InequalityTest() // IFloatingPoint // + [Fact] + [SkipOnMono("https://github.com/dotnet/runtime/issues/100368")] + public static void ConvertToIntegerTest() + { + // Signed Values + + Assert.Equal(0, FloatingPointHelper.ConvertToInteger(float.MinValue)); + Assert.Equal(int.MinValue, FloatingPointHelper.ConvertToInteger(float.MinValue)); + Assert.Equal(long.MinValue, FloatingPointHelper.ConvertToInteger(float.MinValue)); + Assert.Equal(Int128.MinValue, FloatingPointHelper.ConvertToInteger(float.MinValue)); + Assert.Equal(nint.MinValue, FloatingPointHelper.ConvertToInteger(float.MinValue)); + Assert.Equal(0, FloatingPointHelper.ConvertToInteger(float.MinValue)); + + Assert.Equal(2, FloatingPointHelper.ConvertToInteger(2.6f)); + Assert.Equal(2, FloatingPointHelper.ConvertToInteger(2.6f)); + Assert.Equal(2, FloatingPointHelper.ConvertToInteger(2.6f)); + Assert.Equal(2, FloatingPointHelper.ConvertToInteger(2.6f)); + Assert.Equal(2, FloatingPointHelper.ConvertToInteger(2.6f)); + Assert.Equal(2, FloatingPointHelper.ConvertToInteger(2.6f)); + + Assert.Equal(-1, FloatingPointHelper.ConvertToInteger(float.MaxValue)); + Assert.Equal(int.MaxValue, FloatingPointHelper.ConvertToInteger(float.MaxValue)); + Assert.Equal(long.MaxValue, FloatingPointHelper.ConvertToInteger(float.MaxValue)); + Assert.Equal(Int128.MaxValue, FloatingPointHelper.ConvertToInteger(float.MaxValue)); + Assert.Equal(nint.MaxValue, FloatingPointHelper.ConvertToInteger(float.MaxValue)); + Assert.Equal(-1, FloatingPointHelper.ConvertToInteger(float.MaxValue)); + + // Unsigned Values + + Assert.Equal(byte.MinValue, FloatingPointHelper.ConvertToInteger(float.MinValue)); + Assert.Equal(ushort.MinValue, FloatingPointHelper.ConvertToInteger(float.MinValue)); + Assert.Equal(uint.MinValue, FloatingPointHelper.ConvertToInteger(float.MinValue)); + Assert.Equal(ulong.MinValue, FloatingPointHelper.ConvertToInteger(float.MinValue)); + Assert.Equal(UInt128.MinValue, FloatingPointHelper.ConvertToInteger(float.MinValue)); + Assert.Equal(nuint.MinValue, FloatingPointHelper.ConvertToInteger(float.MinValue)); + + Assert.Equal(2u, FloatingPointHelper.ConvertToInteger(2.6f)); + Assert.Equal(2u, FloatingPointHelper.ConvertToInteger(2.6f)); + Assert.Equal(2u, FloatingPointHelper.ConvertToInteger(2.6f)); + Assert.Equal(2u, FloatingPointHelper.ConvertToInteger(2.6f)); + Assert.Equal(2u, FloatingPointHelper.ConvertToInteger(2.6f)); + Assert.Equal(2u, FloatingPointHelper.ConvertToInteger(2.6f)); + + Assert.Equal(byte.MaxValue, FloatingPointHelper.ConvertToInteger(float.MaxValue)); + Assert.Equal(ushort.MaxValue, FloatingPointHelper.ConvertToInteger(float.MaxValue)); + Assert.Equal(uint.MaxValue, FloatingPointHelper.ConvertToInteger(float.MaxValue)); + Assert.Equal(ulong.MaxValue, FloatingPointHelper.ConvertToInteger(float.MaxValue)); + Assert.Equal(new UInt128(0xFFFF_FF00_0000_0000, 0x0000_0000_0000_0000), FloatingPointHelper.ConvertToInteger(float.MaxValue)); + Assert.Equal(nuint.MaxValue, FloatingPointHelper.ConvertToInteger(float.MaxValue)); + } + + [Fact] + [SkipOnMono("https://github.com/dotnet/runtime/issues/100368")] + public static void ConvertToIntegerNativeTest() + { + // Signed Values + + Assert.Equal(0, FloatingPointHelper.ConvertToIntegerNative(float.MinValue)); + Assert.Equal(int.MinValue, FloatingPointHelper.ConvertToIntegerNative(float.MinValue)); + Assert.Equal(long.MinValue, FloatingPointHelper.ConvertToIntegerNative(float.MinValue)); + Assert.Equal(Int128.MinValue, FloatingPointHelper.ConvertToIntegerNative(float.MinValue)); + Assert.Equal(nint.MinValue, FloatingPointHelper.ConvertToIntegerNative(float.MinValue)); + Assert.Equal(0, FloatingPointHelper.ConvertToIntegerNative(float.MinValue)); + + Assert.Equal(2, FloatingPointHelper.ConvertToIntegerNative(2.6f)); + Assert.Equal(2, FloatingPointHelper.ConvertToIntegerNative(2.6f)); + Assert.Equal(2, FloatingPointHelper.ConvertToIntegerNative(2.6f)); + Assert.Equal(2, FloatingPointHelper.ConvertToIntegerNative(2.6f)); + Assert.Equal(2, FloatingPointHelper.ConvertToIntegerNative(2.6f)); + Assert.Equal(2, FloatingPointHelper.ConvertToIntegerNative(2.6f)); + + if (Sse2.IsSupported) + { + // On Xarch: + // * Conversion to int is natively supported and returns 0x8000_0000 + // * Conversion to long is natively supported on 64-bit and returns 0x8000_0000_0000_0000 + + Assert.Equal(0, FloatingPointHelper.ConvertToIntegerNative(float.MaxValue)); + Assert.Equal(int.MinValue, FloatingPointHelper.ConvertToIntegerNative(float.MaxValue)); + Assert.Equal(nint.MinValue, FloatingPointHelper.ConvertToIntegerNative(float.MaxValue)); + Assert.Equal(0, FloatingPointHelper.ConvertToIntegerNative(float.MaxValue)); + + if (Environment.Is64BitProcess) + { + Assert.Equal(long.MinValue, FloatingPointHelper.ConvertToIntegerNative(float.MaxValue)); + } + else + { + Assert.Equal(long.MaxValue, FloatingPointHelper.ConvertToIntegerNative(float.MaxValue)); + } + } + else + { + Assert.Equal(-1, FloatingPointHelper.ConvertToIntegerNative(float.MaxValue)); + Assert.Equal(int.MaxValue, FloatingPointHelper.ConvertToIntegerNative(float.MaxValue)); + Assert.Equal(long.MaxValue, FloatingPointHelper.ConvertToIntegerNative(float.MaxValue)); + Assert.Equal(nint.MaxValue, FloatingPointHelper.ConvertToIntegerNative(float.MaxValue)); + Assert.Equal(-1, FloatingPointHelper.ConvertToIntegerNative(float.MaxValue)); + } + Assert.Equal(Int128.MaxValue, FloatingPointHelper.ConvertToIntegerNative(float.MaxValue)); + + // Unsigned Values + + if (Sse2.IsSupported) + { + // On Xarch: + // * Conversion to uint is natively supported w/ Avx512 and returns 0xFFFF_FFFF + // * Conversion to ulong is natively supported on 64-bit w/ Avx512 and returns 0xFFFF_FFFF_FFFF_FFFF + + if (Avx512F.IsSupported) + { + Assert.Equal(uint.MaxValue, FloatingPointHelper.ConvertToIntegerNative(float.MinValue)); + Assert.Equal(nuint.MaxValue, FloatingPointHelper.ConvertToIntegerNative(float.MinValue)); + } + else + { + Assert.Equal(uint.MinValue, FloatingPointHelper.ConvertToIntegerNative(float.MinValue)); + Assert.Equal(nuint.MinValue, FloatingPointHelper.ConvertToIntegerNative(float.MinValue)); + } + + if (Environment.Is64BitProcess && Avx512F.IsSupported) + { + Assert.Equal(ulong.MaxValue, FloatingPointHelper.ConvertToIntegerNative(float.MinValue)); + } + else + { + Assert.Equal(ulong.MinValue, FloatingPointHelper.ConvertToIntegerNative(float.MinValue)); + } + } + else + { + Assert.Equal(uint.MinValue, FloatingPointHelper.ConvertToIntegerNative(float.MinValue)); + Assert.Equal(ulong.MinValue, FloatingPointHelper.ConvertToIntegerNative(float.MinValue)); + Assert.Equal(nuint.MinValue, FloatingPointHelper.ConvertToIntegerNative(float.MinValue)); + } + Assert.Equal(byte.MinValue, FloatingPointHelper.ConvertToIntegerNative(float.MinValue)); + Assert.Equal(ushort.MinValue, FloatingPointHelper.ConvertToIntegerNative(float.MinValue)); + Assert.Equal(UInt128.MinValue, FloatingPointHelper.ConvertToIntegerNative(float.MinValue)); + + Assert.Equal(2u, FloatingPointHelper.ConvertToIntegerNative(2.6f)); + Assert.Equal(2u, FloatingPointHelper.ConvertToIntegerNative(2.6f)); + Assert.Equal(2u, FloatingPointHelper.ConvertToIntegerNative(2.6f)); + Assert.Equal(2u, FloatingPointHelper.ConvertToIntegerNative(2.6f)); + Assert.Equal(2u, FloatingPointHelper.ConvertToIntegerNative(2.6f)); + Assert.Equal(2u, FloatingPointHelper.ConvertToIntegerNative(2.6f)); + + if (Sse2.IsSupported) + { + // On Xarch: + // * Conversion to uint is natively supported w/ Avx512 and returns 0xFFFF_FFFF + // * Conversion to ulong is natively supported on 64-bit w/ Avx512 and returns 0xFFFF_FFFF_FFFF_FFFF + + Assert.Equal(byte.MinValue, FloatingPointHelper.ConvertToIntegerNative(float.MaxValue)); + Assert.Equal(ushort.MinValue, FloatingPointHelper.ConvertToIntegerNative(float.MaxValue)); + } + else + { + Assert.Equal(byte.MaxValue, FloatingPointHelper.ConvertToIntegerNative(float.MaxValue)); + Assert.Equal(ushort.MaxValue, FloatingPointHelper.ConvertToIntegerNative(float.MaxValue)); + } + Assert.Equal(uint.MaxValue, FloatingPointHelper.ConvertToIntegerNative(float.MaxValue)); + Assert.Equal(ulong.MaxValue, FloatingPointHelper.ConvertToIntegerNative(float.MaxValue)); + Assert.Equal(new UInt128(0xFFFF_FF00_0000_0000, 0x0000_0000_0000_0000), FloatingPointHelper.ConvertToIntegerNative(float.MaxValue)); + Assert.Equal(nuint.MaxValue, FloatingPointHelper.ConvertToIntegerNative(float.MaxValue)); + } + [Fact] public static void GetExponentByteCountTest() { From a2bd5830ce09cd81d834afd5571bc6c9e5ad879b Mon Sep 17 00:00:00 2001 From: Tyler Brinkley Date: Tue, 23 Apr 2024 20:17:07 -0500 Subject: [PATCH 044/161] Make mutable generic collection interfaces implement read-only collection interfaces (#95830) * Make mutable generic collection interfaces implement read-only collection interfaces * More updates * Fix build * Update refs * Add DIM's to ref also * fixes * Try to fix arrays * Moved dim's to the end of the interfaces. Made the tests support .NET Framework 4.8. * Small fix * Small fix * Fix build * Fix * Cleanup * Incorporate #96672 * Check the correct inheritanceDepth in vm/array.cpp --------- Co-authored-by: Eirik Tsarpalis Co-authored-by: Tanner Gooding --- .../src/System/Array.CoreCLR.cs | 2 +- src/coreclr/vm/array.cpp | 19 +- .../System/Collections/CollectionAsserts.cs | 152 +++++++++++++++ .../Collections/ICollection.Generic.Tests.cs | 43 +++-- .../Collections/IDictionary.Generic.Tests.cs | 180 +++++++++++++++--- .../System/Collections/IList.Generic.Tests.cs | 75 ++++---- .../System/Collections/ISet.Generic.Tests.cs | 53 +++--- .../Generic/CollectionExtensionsTests.cs | 12 ++ .../System/Collections/Generic/ICollection.cs | 6 +- .../System/Collections/Generic/IDictionary.cs | 22 ++- .../src/System/Collections/Generic/IList.cs | 6 +- .../src/System/Collections/Generic/ISet.cs | 35 +++- .../System.Runtime/ref/System.Runtime.cs | 49 +++-- 13 files changed, 490 insertions(+), 164 deletions(-) diff --git a/src/coreclr/System.Private.CoreLib/src/System/Array.CoreCLR.cs b/src/coreclr/System.Private.CoreLib/src/System/Array.CoreCLR.cs index de7b3021c458fe..74e07398481681 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Array.CoreCLR.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Array.CoreCLR.cs @@ -694,7 +694,7 @@ public ArrayInitializeCache(RuntimeType arrayType) // it for type and executes it. // // The "T" will reflect the interface used to invoke the method. The actual runtime "this" will be - // array that is castable to "T[]" (i.e. for primitivs and valuetypes, it will be exactly + // array that is castable to "T[]" (i.e. for primitives and valuetypes, it will be exactly // "T[]" - for orefs, it may be a "U[]" where U derives from T.) //---------------------------------------------------------------------------------------- internal sealed class SZArrayHelper diff --git a/src/coreclr/vm/array.cpp b/src/coreclr/vm/array.cpp index ffb6e6def99ce0..e1e2b31e4df647 100644 --- a/src/coreclr/vm/array.cpp +++ b/src/coreclr/vm/array.cpp @@ -1210,29 +1210,14 @@ MethodDesc* GetActualImplementationForArrayGenericIListOrIReadOnlyListMethod(Met } CONTRACTL_END - int slot = pItfcMeth->GetSlot(); - - // We need to pick the right starting method depending on the depth of the inheritance chain - static const BinderMethodID startingMethod[] = { - METHOD__SZARRAYHELPER__GETENUMERATOR, // First method of IEnumerable`1 - METHOD__SZARRAYHELPER__GET_COUNT, // First method of ICollection`1/IReadOnlyCollection`1 - METHOD__SZARRAYHELPER__GET_ITEM // First method of IList`1/IReadOnlyList`1 - }; - // Subtract one for the non-generic IEnumerable that the generic enumerable inherits from unsigned int inheritanceDepth = pItfcMeth->GetMethodTable()->GetNumInterfaces() - 1; - PREFIX_ASSUME(0 <= inheritanceDepth && inheritanceDepth < ARRAY_SIZE(startingMethod)); - - MethodDesc *pGenericImplementor = CoreLibBinder::GetMethod((BinderMethodID)(startingMethod[inheritanceDepth] + slot)); - // The most common reason for this assert is that the order of the SZArrayHelper methods in - // corelib.h does not match the order they are implemented on the generic interfaces. - _ASSERTE(pGenericImplementor == MemberLoader::FindMethodByName(g_pSZArrayHelperClass, pItfcMeth->GetName())); + MethodDesc *pGenericImplementor = MemberLoader::FindMethodByName(g_pSZArrayHelperClass, pItfcMeth->GetName()); // OPTIMIZATION: For any method other than GetEnumerator(), we can safely substitute // "Object" for reference-type theT's. This causes fewer methods to be instantiated. - if (startingMethod[inheritanceDepth] != METHOD__SZARRAYHELPER__GETENUMERATOR && - !theT.IsValueType()) + if (inheritanceDepth != 0 && !theT.IsValueType()) { theT = TypeHandle(g_pObjectClass); } diff --git a/src/libraries/Common/tests/System/Collections/CollectionAsserts.cs b/src/libraries/Common/tests/System/Collections/CollectionAsserts.cs index 2de26be1737fdc..1e76d40ebb411f 100644 --- a/src/libraries/Common/tests/System/Collections/CollectionAsserts.cs +++ b/src/libraries/Common/tests/System/Collections/CollectionAsserts.cs @@ -1,6 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System; using System.Collections.Generic; using System.Linq; using Xunit; @@ -9,6 +10,151 @@ namespace System.Collections.Tests { internal static class CollectionAsserts { + public static void HasCount(ICollection collection, int count) + { + Assert.Equal(count, collection.Count); +#if !NETFRAMEWORK + IReadOnlyCollection readOnlyCollection = collection; + Assert.Equal(count, readOnlyCollection.Count); +#endif + } + + public static void EqualAt(IList list, int index, T expected) + { + Assert.Equal(expected, list[index]); +#if !NETFRAMEWORK + IReadOnlyList readOnlyList = list; + Assert.Equal(expected, readOnlyList[index]); +#endif + } + + public static void NotEqualAt(IList list, int index, T expected) + { + Assert.NotEqual(expected, list[index]); +#if !NETFRAMEWORK + IReadOnlyList readOnlyList = list; + Assert.NotEqual(expected, readOnlyList[index]); +#endif + } + + public static void ThrowsElementAt(IList list, int index, Type exceptionType) + { + Assert.Throws(exceptionType, () => list[index]); +#if !NETFRAMEWORK + IReadOnlyList readOnlyList = list; + Assert.Throws(exceptionType, () => readOnlyList[index]); +#endif + } + + public static void ElementAtSucceeds(IList list, int index) + { + T result = list[index]; +#if !NETFRAMEWORK + IReadOnlyList readOnlyList = list; + Assert.Equal(result, readOnlyList[index]); +#endif + } + + public static void EqualAt(IDictionary dictionary, TKey key, TValue expected) + { + Assert.Equal(expected, dictionary[key]); +#if !NETFRAMEWORK + IReadOnlyDictionary readOnlyDictionary = dictionary; + Assert.Equal(expected, readOnlyDictionary[key]); +#endif + } + + public static void ContainsKey(IDictionary dictionary, TKey key, bool expected) + { + Assert.Equal(expected, dictionary.ContainsKey(key)); +#if !NETFRAMEWORK + IReadOnlyDictionary readOnlyDictionary = dictionary; + Assert.Equal(expected, readOnlyDictionary.ContainsKey(key)); +#endif + } + + public static void TryGetValue(IDictionary dictionary, TKey key, bool expected, TValue expectedValue = default) + { + Assert.Equal(expected, dictionary.TryGetValue(key, out TValue value)); + if (expected) + { + Assert.Equal(expectedValue, value); + } +#if !NETFRAMEWORK + IReadOnlyDictionary readOnlyDictionary = dictionary; + Assert.Equal(expected, readOnlyDictionary.TryGetValue(key, out value)); + if (expected) + { + Assert.Equal(expectedValue, value); + } +#endif + } + + public static void Contains(ISet set, T expected) + { + Assert.True(set.Contains(expected)); +#if !NETFRAMEWORK + ICollection collection = set; + Assert.True(collection.Contains(expected)); + IReadOnlySet readOnlySet = set; + Assert.True(readOnlySet.Contains(expected)); +#endif + } + + public static void IsProperSubsetOf(ISet set, IEnumerable enumerable, bool expected) + { + Assert.Equal(expected, set.IsProperSubsetOf(enumerable)); +#if !NETFRAMEWORK + IReadOnlySet readOnlySet = set; + Assert.Equal(expected, readOnlySet.IsProperSubsetOf(enumerable)); +#endif + } + + public static void IsProperSupersetOf(ISet set, IEnumerable enumerable, bool expected) + { + Assert.Equal(expected, set.IsProperSupersetOf(enumerable)); +#if !NETFRAMEWORK + IReadOnlySet readOnlySet = set; + Assert.Equal(expected, readOnlySet.IsProperSupersetOf(enumerable)); +#endif + } + + public static void IsSubsetOf(ISet set, IEnumerable enumerable, bool expected) + { + Assert.Equal(expected, set.IsSubsetOf(enumerable)); +#if !NETFRAMEWORK + IReadOnlySet readOnlySet = set; + Assert.Equal(expected, readOnlySet.IsSubsetOf(enumerable)); +#endif + } + + public static void IsSupersetOf(ISet set, IEnumerable enumerable, bool expected) + { + Assert.Equal(expected, set.IsSupersetOf(enumerable)); +#if !NETFRAMEWORK + IReadOnlySet readOnlySet = set; + Assert.Equal(expected, readOnlySet.IsSupersetOf(enumerable)); +#endif + } + + public static void Overlaps(ISet set, IEnumerable enumerable, bool expected) + { + Assert.Equal(expected, set.Overlaps(enumerable)); +#if !NETFRAMEWORK + IReadOnlySet readOnlySet = set; + Assert.Equal(expected, readOnlySet.Overlaps(enumerable)); +#endif + } + + public static void SetEquals(ISet set, IEnumerable enumerable, bool expected) + { + Assert.Equal(expected, set.SetEquals(enumerable)); +#if !NETFRAMEWORK + IReadOnlySet readOnlySet = set; + Assert.Equal(expected, readOnlySet.SetEquals(enumerable)); +#endif + } + public static void Equal(ICollection expected, ICollection actual) { Assert.Equal(expected == null, actual == null); @@ -43,6 +189,12 @@ public static void Equal(ICollection expected, ICollection actual) return; } Assert.Equal(expected.Count, actual.Count); +#if !NETFRAMEWORK + IReadOnlyCollection readOnlyExpected = expected; + Assert.Equal(expected.Count, readOnlyExpected.Count); + IReadOnlyCollection readOnlyActual = actual; + Assert.Equal(actual.Count, readOnlyActual.Count); +#endif IEnumerator e = expected.GetEnumerator(); IEnumerator a = actual.GetEnumerator(); while (e.MoveNext()) diff --git a/src/libraries/Common/tests/System/Collections/ICollection.Generic.Tests.cs b/src/libraries/Common/tests/System/Collections/ICollection.Generic.Tests.cs index a94a9308b99ab4..8ae72dea074ab0 100644 --- a/src/libraries/Common/tests/System/Collections/ICollection.Generic.Tests.cs +++ b/src/libraries/Common/tests/System/Collections/ICollection.Generic.Tests.cs @@ -130,7 +130,7 @@ public void ICollection_Generic_IsReadOnly_Validity(int count) public void ICollection_Generic_Count_Validity(int count) { ICollection collection = GenericICollectionFactory(count); - Assert.Equal(count, collection.Count); + CollectionAsserts.HasCount(collection, count); } #endregion @@ -145,7 +145,7 @@ public virtual void ICollection_Generic_Add_DefaultValue(int count) { ICollection collection = GenericICollectionFactory(count); collection.Add(default(T)); - Assert.Equal(count + 1, collection.Count); + CollectionAsserts.HasCount(collection, count + 1); } } @@ -161,7 +161,7 @@ public void ICollection_Generic_Add_InvalidValueToMiddleOfCollection(int count) collection.Add(invalidValue); for (int i = 0; i < count; i++) collection.Add(CreateT(i)); - Assert.Equal(count * 2, collection.Count); + CollectionAsserts.HasCount(collection, count * 2); }); } } @@ -178,7 +178,7 @@ public void ICollection_Generic_Add_InvalidValueToBeginningOfCollection(int coun collection.Add(invalidValue); for (int i = 0; i < count; i++) collection.Add(CreateT(i)); - Assert.Equal(count, collection.Count); + CollectionAsserts.HasCount(collection, count); }); } } @@ -192,8 +192,9 @@ public void ICollection_Generic_Add_InvalidValueToEndOfCollection(int count) Assert.All(InvalidValues, invalidValue => { ICollection collection = GenericICollectionFactory(count); + collection.Add(invalidValue); - Assert.Equal(count, collection.Count); + CollectionAsserts.HasCount(collection, count); }); } } @@ -208,7 +209,7 @@ public void ICollection_Generic_Add_DuplicateValue(int count) T duplicateValue = CreateT(700); collection.Add(duplicateValue); collection.Add(duplicateValue); - Assert.Equal(count + 2, collection.Count); + CollectionAsserts.HasCount(collection, count + 2); } } @@ -221,7 +222,7 @@ public void ICollection_Generic_Add_AfterCallingClear(int count) ICollection collection = GenericICollectionFactory(count); collection.Clear(); AddToCollection(collection, 5); - Assert.Equal(5, collection.Count); + CollectionAsserts.HasCount(collection, 5); } } @@ -261,7 +262,7 @@ public void ICollection_Generic_Add_AfterRemovingAllItems(int count) for (int i = 0; i < count; i++) collection.Remove(collection.ElementAt(0)); collection.Add(CreateT(254)); - Assert.Equal(1, collection.Count); + CollectionAsserts.HasCount(collection, 1); } } @@ -273,7 +274,7 @@ public void ICollection_Generic_Add_ToReadOnlyCollection(int count) { ICollection collection = GenericICollectionFactory(count); Assert.Throws(() => collection.Add(CreateT(0))); - Assert.Equal(count, collection.Count); + CollectionAsserts.HasCount(collection, count); } } @@ -306,12 +307,12 @@ public void ICollection_Generic_Clear(int count) if (IsReadOnly || AddRemoveClear_ThrowsNotSupported) { Assert.Throws(() => collection.Clear()); - Assert.Equal(count, collection.Count); + CollectionAsserts.HasCount(collection, count); } else { collection.Clear(); - Assert.Equal(0, collection.Count); + CollectionAsserts.HasCount(collection, 0); } } @@ -325,14 +326,14 @@ public void ICollection_Generic_Clear_Repeatedly(int count) Assert.Throws(() => collection.Clear()); Assert.Throws(() => collection.Clear()); Assert.Throws(() => collection.Clear()); - Assert.Equal(count, collection.Count); + CollectionAsserts.HasCount(collection, count); } else { collection.Clear(); collection.Clear(); collection.Clear(); - Assert.Equal(0, collection.Count); + CollectionAsserts.HasCount(collection, 0); } } @@ -434,7 +435,7 @@ public void ICollection_Generic_Contains_ValidValueThatExistsTwiceInTheCollectio T item = CreateT(12); collection.Add(item); collection.Add(item); - Assert.Equal(count + 2, collection.Count); + CollectionAsserts.HasCount(collection, count + 2); } } @@ -567,7 +568,7 @@ public void ICollection_Generic_Remove_DefaultValueNotContainedInCollection(int count--; } Assert.False(collection.Remove(value)); - Assert.Equal(count, collection.Count); + CollectionAsserts.HasCount(collection, count); } } @@ -583,7 +584,7 @@ public void ICollection_Generic_Remove_NonDefaultValueNotContainedInCollection(i while (collection.Contains(value) || Enumerable.Contains(InvalidValues, value)) value = CreateT(seed++); Assert.False(collection.Remove(value)); - Assert.Equal(count, collection.Count); + CollectionAsserts.HasCount(collection, count); } } @@ -602,7 +603,7 @@ public virtual void ICollection_Generic_Remove_DefaultValueContainedInCollection count++; } Assert.True(collection.Remove(value)); - Assert.Equal(count - 1, collection.Count); + CollectionAsserts.HasCount(collection, count - 1); } } @@ -621,7 +622,7 @@ public void ICollection_Generic_Remove_NonDefaultValueContainedInCollection(int count++; } Assert.True(collection.Remove(value)); - Assert.Equal(count - 1, collection.Count); + CollectionAsserts.HasCount(collection, count - 1); } } @@ -639,7 +640,7 @@ public void ICollection_Generic_Remove_ValueThatExistsTwiceInCollection(int coun count += 2; Assert.True(collection.Remove(value)); Assert.True(collection.Contains(value)); - Assert.Equal(count - 1, collection.Count); + CollectionAsserts.HasCount(collection, count - 1); } } @@ -654,7 +655,7 @@ public void ICollection_Generic_Remove_EveryValue(int count) { Assert.True(collection.Remove(value)); }); - Assert.Empty(collection); + CollectionAsserts.HasCount(collection, 0); } } @@ -667,7 +668,7 @@ public void ICollection_Generic_Remove_InvalidValue_ThrowsArgumentException(int { Assert.Throws(() => collection.Remove(value)); }); - Assert.Equal(count, collection.Count); + CollectionAsserts.HasCount(collection, count); } [Theory] diff --git a/src/libraries/Common/tests/System/Collections/IDictionary.Generic.Tests.cs b/src/libraries/Common/tests/System/Collections/IDictionary.Generic.Tests.cs index df92ab206f6686..e6311ec89b4fc1 100644 --- a/src/libraries/Common/tests/System/Collections/IDictionary.Generic.Tests.cs +++ b/src/libraries/Common/tests/System/Collections/IDictionary.Generic.Tests.cs @@ -266,12 +266,16 @@ public void IDictionary_Generic_ItemGet_DefaultKey(int count) if (!DefaultValueAllowed) { Assert.Throws(() => dictionary[default(TKey)]); +#if !NETFRAMEWORK + IReadOnlyDictionary readOnlyDictionary = dictionary; + Assert.Throws(() => readOnlyDictionary[default(TKey)]); +#endif } else { TValue value = CreateTValue(3452); dictionary[default(TKey)] = value; - Assert.Equal(value, dictionary[default(TKey)]); + CollectionAsserts.EqualAt(dictionary, default(TKey), value); } } } @@ -283,6 +287,10 @@ public void IDictionary_Generic_ItemGet_MissingNonDefaultKey_ThrowsKeyNotFoundEx IDictionary dictionary = GenericIDictionaryFactory(count); TKey missingKey = GetNewKey(dictionary); Assert.Throws(() => dictionary[missingKey]); +#if !NETFRAMEWORK + IReadOnlyDictionary readOnlyDictionary = dictionary; + Assert.Throws(() => readOnlyDictionary[missingKey]); +#endif } [Theory] @@ -296,6 +304,10 @@ public void IDictionary_Generic_ItemGet_MissingDefaultKey_ThrowsKeyNotFoundExcep while (dictionary.ContainsKey(missingKey)) dictionary.Remove(missingKey); Assert.Throws(() => dictionary[missingKey]); +#if !NETFRAMEWORK + IReadOnlyDictionary readOnlyDictionary = dictionary; + Assert.Throws(() => readOnlyDictionary[missingKey]); +#endif } } @@ -306,7 +318,7 @@ public void IDictionary_Generic_ItemGet_PresentKeyReturnsCorrectValue(int count) IDictionary dictionary = GenericIDictionaryFactory(count); foreach (KeyValuePair pair in dictionary) { - Assert.Equal(pair.Value, dictionary[pair.Key]); + CollectionAsserts.EqualAt(dictionary, pair.Key, pair.Value); } } @@ -329,7 +341,7 @@ public void IDictionary_Generic_ItemSet_DefaultKey(int count) { TValue value = CreateTValue(3452); dictionary[default(TKey)] = value; - Assert.Equal(value, dictionary[default(TKey)]); + CollectionAsserts.EqualAt(dictionary, default(TKey), value); } } } @@ -355,7 +367,7 @@ public void IDictionary_Generic_ItemSet_AddsNewValueWhenNotPresent(int count) IDictionary dictionary = GenericIDictionaryFactory(count); TKey missingKey = GetNewKey(dictionary); dictionary[missingKey] = CreateTValue(543); - Assert.Equal(count + 1, dictionary.Count); + CollectionAsserts.HasCount(dictionary, count + 1); } } @@ -370,8 +382,8 @@ public void IDictionary_Generic_ItemSet_ReplacesExistingValueWhenPresent(int cou dictionary.Add(existingKey, CreateTValue(5342)); TValue newValue = CreateTValue(1234); dictionary[existingKey] = newValue; - Assert.Equal(count + 1, dictionary.Count); - Assert.Equal(newValue, dictionary[existingKey]); + CollectionAsserts.HasCount(dictionary, count + 1); + CollectionAsserts.EqualAt(dictionary, existingKey, newValue); } } @@ -386,6 +398,10 @@ public void IDictionary_Generic_Keys_ContainsAllCorrectKeys(int count) IDictionary dictionary = GenericIDictionaryFactory(count); IEnumerable expected = dictionary.Select((pair) => pair.Key); Assert.True(expected.SequenceEqual(dictionary.Keys)); +#if !NETFRAMEWORK + IReadOnlyDictionary readOnlyDictionary = dictionary; + Assert.True(expected.SequenceEqual(readOnlyDictionary.Keys)); +#endif } [Theory] @@ -396,6 +412,10 @@ public void IDictionary_Generic_Keys_ModifyingTheDictionaryUpdatesTheCollection( { IDictionary dictionary = GenericIDictionaryFactory(count); ICollection keys = dictionary.Keys; +#if !NETFRAMEWORK + IReadOnlyDictionary readOnlyDictionary = dictionary; + IEnumerable readOnlyKeys = readOnlyDictionary.Keys; +#endif int previousCount = keys.Count; if (count > 0) Assert.NotEmpty(keys); @@ -403,10 +423,16 @@ public void IDictionary_Generic_Keys_ModifyingTheDictionaryUpdatesTheCollection( if (IDictionary_Generic_Keys_Values_ModifyingTheDictionaryUpdatesTheCollection) { Assert.Empty(keys); +#if !NETFRAMEWORK + Assert.Empty(readOnlyKeys); +#endif } else { Assert.Equal(previousCount, keys.Count); +#if !NETFRAMEWORK + Assert.Equal(previousCount, readOnlyKeys.Count()); +#endif } } } @@ -420,11 +446,20 @@ public void IDictionary_Generic_Keys_Enumeration_ParentDictionaryModifiedInvalid IDictionary dictionary = GenericIDictionaryFactory(count); ICollection keys = dictionary.Keys; IEnumerator keysEnum = keys.GetEnumerator(); +#if !NETFRAMEWORK + IReadOnlyDictionary readOnlyDictionary = dictionary; + IEnumerable readOnlyKeys = readOnlyDictionary.Keys; + IEnumerator readOnlyKeysEnum = readOnlyKeys.GetEnumerator(); +#endif dictionary.Add(GetNewKey(dictionary), CreateTValue(3432)); if (count == 0 ? Enumerator_Empty_ModifiedDuringEnumeration_ThrowsInvalidOperationException : IDictionary_Generic_Keys_Values_Enumeration_ThrowsInvalidOperation_WhenParentModified) { Assert.Throws(() => keysEnum.MoveNext()); Assert.Throws(() => keysEnum.Reset()); +#if !NETFRAMEWORK + Assert.Throws(() => readOnlyKeysEnum.MoveNext()); + Assert.Throws(() => readOnlyKeysEnum.Reset()); +#endif } else { @@ -433,6 +468,13 @@ public void IDictionary_Generic_Keys_Enumeration_ParentDictionaryModifiedInvalid _ = keysEnum.Current; } keysEnum.Reset(); +#if !NETFRAMEWORK + if (readOnlyKeysEnum.MoveNext()) + { + _ = readOnlyKeysEnum.Current; + } + readOnlyKeysEnum.Reset(); +#endif } } } @@ -456,10 +498,25 @@ public void IDictionary_Generic_Keys_Enumeration_Reset(int count) IDictionary dictionary = GenericIDictionaryFactory(count); ICollection keys = dictionary.Keys; IEnumerator enumerator = keys.GetEnumerator(); +#if !NETFRAMEWORK + IReadOnlyDictionary readOnlyDictionary = dictionary; + IEnumerable readOnlyKeys = readOnlyDictionary.Keys; + IEnumerator readOnlyEnumerator = readOnlyKeys.GetEnumerator(); +#endif if (IDictionary_Generic_Keys_Values_Enumeration_ResetImplemented) + { enumerator.Reset(); +#if !NETFRAMEWORK + readOnlyEnumerator.Reset(); +#endif + } else + { Assert.Throws(() => enumerator.Reset()); +#if !NETFRAMEWORK + Assert.Throws(() => readOnlyEnumerator.Reset()); +#endif + } } #endregion @@ -473,6 +530,10 @@ public void IDictionary_Generic_Values_ContainsAllCorrectValues(int count) IDictionary dictionary = GenericIDictionaryFactory(count); IEnumerable expected = dictionary.Select((pair) => pair.Value); Assert.True(expected.SequenceEqual(dictionary.Values)); +#if !NETFRAMEWORK + IReadOnlyDictionary readOnlyDictionary = dictionary; + Assert.True(expected.SequenceEqual(readOnlyDictionary.Values)); +#endif } [Theory] @@ -491,6 +552,10 @@ public void IDictionary_Generic_Values_IncludeDuplicatesMultipleTimes(int count) dictionary.Add(missingKey, pair.Value); } Assert.Equal(count * 2, dictionary.Values.Count); +#if !NETFRAMEWORK + IReadOnlyDictionary readOnlyDictionary = dictionary; + Assert.Equal(count * 2, readOnlyDictionary.Values.Count()); +#endif } } @@ -500,9 +565,18 @@ public void IDictionary_Generic_Values_ModifyingTheDictionaryUpdatesTheCollectio { IDictionary dictionary = GenericIDictionaryFactory(count); ICollection values = dictionary.Values; +#if !NETFRAMEWORK + IReadOnlyDictionary readOnlyDictionary = dictionary; + IEnumerable readOnlyValues = readOnlyDictionary.Values; +#endif int previousCount = values.Count; if (count > 0) + { Assert.NotEmpty(values); +#if !NETFRAMEWORK + Assert.NotEmpty(readOnlyValues); +#endif + } if (!IsReadOnly) { @@ -510,10 +584,16 @@ public void IDictionary_Generic_Values_ModifyingTheDictionaryUpdatesTheCollectio if (IDictionary_Generic_Keys_Values_ModifyingTheDictionaryUpdatesTheCollection) { Assert.Empty(values); +#if !NETFRAMEWORK + Assert.Empty(readOnlyValues); +#endif } else { Assert.Equal(previousCount, values.Count); +#if !NETFRAMEWORK + Assert.Equal(previousCount, readOnlyValues.Count()); +#endif } } } @@ -527,11 +607,20 @@ public void IDictionary_Generic_Values_Enumeration_ParentDictionaryModifiedInval IDictionary dictionary = GenericIDictionaryFactory(count); ICollection values = dictionary.Values; IEnumerator valuesEnum = values.GetEnumerator(); +#if !NETFRAMEWORK + IReadOnlyDictionary readOnlyDictionary = dictionary; + IEnumerable readOnlyValues = readOnlyDictionary.Values; + IEnumerator readOnlyValuesEnum = readOnlyValues.GetEnumerator(); +#endif dictionary.Add(GetNewKey(dictionary), CreateTValue(3432)); if (count == 0 ? Enumerator_Empty_ModifiedDuringEnumeration_ThrowsInvalidOperationException : IDictionary_Generic_Keys_Values_Enumeration_ThrowsInvalidOperation_WhenParentModified) { Assert.Throws(() => valuesEnum.MoveNext()); Assert.Throws(() => valuesEnum.Reset()); +#if !NETFRAMEWORK + Assert.Throws(() => readOnlyValuesEnum.MoveNext()); + Assert.Throws(() => readOnlyValuesEnum.Reset()); +#endif } else { @@ -540,6 +629,13 @@ public void IDictionary_Generic_Values_Enumeration_ParentDictionaryModifiedInval _ = valuesEnum.Current; } valuesEnum.Reset(); +#if !NETFRAMEWORK + if (readOnlyValuesEnum.MoveNext()) + { + _ = readOnlyValuesEnum.Current; + } + readOnlyValuesEnum.Reset(); +#endif } } } @@ -563,10 +659,25 @@ public void IDictionary_Generic_Values_Enumeration_Reset(int count) IDictionary dictionary = GenericIDictionaryFactory(count); ICollection values = dictionary.Values; IEnumerator enumerator = values.GetEnumerator(); +#if !NETFRAMEWORK + IReadOnlyDictionary readOnlyDictionary = dictionary; + IEnumerable readOnlyValues = readOnlyDictionary.Values; + IEnumerator readOnlyEnumerator = readOnlyValues.GetEnumerator(); +#endif if (IDictionary_Generic_Keys_Values_Enumeration_ResetImplemented) + { enumerator.Reset(); +#if !NETFRAMEWORK + readOnlyEnumerator.Reset(); +#endif + } else + { Assert.Throws(() => enumerator.Reset()); +#if !NETFRAMEWORK + Assert.Throws(() => readOnlyEnumerator.Reset()); +#endif + } } #endregion @@ -594,8 +705,8 @@ public void IDictionary_Generic_Add_DefaultKey_DefaultValue(int count) if (DefaultValueAllowed && !IsReadOnly) { dictionary.Add(missingKey, value); - Assert.Equal(count + 1, dictionary.Count); - Assert.Equal(value, dictionary[missingKey]); + CollectionAsserts.HasCount(dictionary, count + 1); + CollectionAsserts.EqualAt(dictionary, missingKey, value); } else if (!IsReadOnly) { @@ -613,8 +724,8 @@ public void IDictionary_Generic_Add_DefaultKey_NonDefaultValue(int count) if (DefaultValueAllowed && !IsReadOnly) { dictionary.Add(missingKey, value); - Assert.Equal(count + 1, dictionary.Count); - Assert.Equal(value, dictionary[missingKey]); + CollectionAsserts.HasCount(dictionary, count + 1); + CollectionAsserts.EqualAt(dictionary, missingKey, value); } else if (!IsReadOnly) { @@ -632,8 +743,8 @@ public void IDictionary_Generic_Add_NonDefaultKey_DefaultValue(int count) TKey missingKey = GetNewKey(dictionary); TValue value = default(TValue); dictionary.Add(missingKey, value); - Assert.Equal(count + 1, dictionary.Count); - Assert.Equal(value, dictionary[missingKey]); + CollectionAsserts.HasCount(dictionary, count + 1); + CollectionAsserts.EqualAt(dictionary, missingKey, value); } } @@ -647,8 +758,8 @@ public void IDictionary_Generic_Add_NonDefaultKey_NonDefaultValue(int count) TKey missingKey = GetNewKey(dictionary); TValue value = CreateTValue(1342); dictionary.Add(missingKey, value); - Assert.Equal(count + 1, dictionary.Count); - Assert.Equal(value, dictionary[missingKey]); + CollectionAsserts.HasCount(dictionary, count + 1); + CollectionAsserts.EqualAt(dictionary, missingKey, value); } } @@ -666,6 +777,10 @@ public void IDictionary_Generic_Add_DuplicateValue(int count) dictionary.Add(GetNewKey(dictionary), duplicate); dictionary.Add(GetNewKey(dictionary), duplicate); Assert.Equal(2, dictionary.Values.Count((value) => value.Equals(duplicate))); +#if !NETFRAMEWORK + IReadOnlyDictionary readOnlyDictionary = dictionary; + Assert.Equal(2, readOnlyDictionary.Values.Count((value) => value.Equals(duplicate))); +#endif } } @@ -692,7 +807,7 @@ public void IDictionary_Generic_Add_DistinctValuesWithHashCollisions(int count) if (dictionary != null) { AddToCollection(dictionary, count); - Assert.Equal(count, dictionary.Count); + CollectionAsserts.HasCount(dictionary, count); } } } @@ -709,7 +824,7 @@ public void IDictionary_Generic_ContainsKey_ValidKeyNotContainedInDictionary(int { IDictionary dictionary = GenericIDictionaryFactory(count); TKey missingKey = GetNewKey(dictionary); - Assert.False(dictionary.ContainsKey(missingKey)); + CollectionAsserts.ContainsKey(dictionary, missingKey, false); } } @@ -722,7 +837,7 @@ public void IDictionary_Generic_ContainsKey_ValidKeyContainedInDictionary(int co IDictionary dictionary = GenericIDictionaryFactory(count); TKey missingKey = GetNewKey(dictionary); dictionary.Add(missingKey, CreateTValue(34251)); - Assert.True(dictionary.ContainsKey(missingKey)); + CollectionAsserts.ContainsKey(dictionary, missingKey, true); } } @@ -739,13 +854,17 @@ public void IDictionary_Generic_ContainsKey_DefaultKeyNotContainedInDictionary(i TKey missingKey = default(TKey); while (dictionary.ContainsKey(missingKey)) dictionary.Remove(missingKey); - Assert.False(dictionary.ContainsKey(missingKey)); + CollectionAsserts.ContainsKey(dictionary, missingKey, false); } } else { // throws ArgumentNullException Assert.Throws(() => dictionary.ContainsKey(default(TKey))); +#if !NETFRAMEWORK + IReadOnlyDictionary readOnlyDictionary = dictionary; + Assert.Throws(() => readOnlyDictionary.ContainsKey(default(TKey))); +#endif } } @@ -759,7 +878,7 @@ public void IDictionary_Generic_ContainsKey_DefaultKeyContainedInDictionary(int TKey missingKey = default(TKey); if (!dictionary.ContainsKey(missingKey)) dictionary.Add(missingKey, CreateTValue(5341)); - Assert.True(dictionary.ContainsKey(missingKey)); + CollectionAsserts.ContainsKey(dictionary, missingKey, true); } } @@ -789,7 +908,7 @@ public void IDictionary_Generic_RemoveKey_EveryKey(int count) { Assert.True(dictionary.Remove(key)); }); - Assert.Empty(dictionary); + CollectionAsserts.HasCount(dictionary, 0); } } @@ -802,7 +921,7 @@ public void IDictionary_Generic_RemoveKey_ValidKeyNotContainedInDictionary(int c IDictionary dictionary = GenericIDictionaryFactory(count); TKey missingKey = GetNewKey(dictionary); Assert.False(dictionary.Remove(missingKey)); - Assert.Equal(count, dictionary.Count); + CollectionAsserts.HasCount(dictionary, count); } } @@ -816,7 +935,7 @@ public void IDictionary_Generic_RemoveKey_ValidKeyContainedInDictionary(int coun TKey missingKey = GetNewKey(dictionary); dictionary.Add(missingKey, CreateTValue(34251)); Assert.True(dictionary.Remove(missingKey)); - Assert.Equal(count, dictionary.Count); + CollectionAsserts.HasCount(dictionary, count); } } @@ -909,8 +1028,7 @@ public void IDictionary_Generic_TryGetValue_ValidKeyNotContainedInDictionary(int IDictionary dictionary = GenericIDictionaryFactory(count); TKey missingKey = GetNewKey(dictionary); TValue value = CreateTValue(5123); - TValue outValue; - Assert.False(dictionary.TryGetValue(missingKey, out outValue)); + CollectionAsserts.TryGetValue(dictionary, missingKey, false); } [Theory] @@ -922,10 +1040,8 @@ public void IDictionary_Generic_TryGetValue_ValidKeyContainedInDictionary(int co IDictionary dictionary = GenericIDictionaryFactory(count); TKey missingKey = GetNewKey(dictionary); TValue value = CreateTValue(5123); - TValue outValue; dictionary.TryAdd(missingKey, value); - Assert.True(dictionary.TryGetValue(missingKey, out outValue)); - Assert.Equal(value, outValue); + CollectionAsserts.TryGetValue(dictionary, missingKey, true, value); } } @@ -942,12 +1058,16 @@ public void IDictionary_Generic_TryGetValue_DefaultKeyNotContainedInDictionary(i TKey missingKey = default(TKey); while (dictionary.ContainsKey(missingKey)) dictionary.Remove(missingKey); - Assert.False(dictionary.TryGetValue(missingKey, out outValue)); + CollectionAsserts.TryGetValue(dictionary, missingKey, false); } } else { Assert.Throws(() => dictionary.TryGetValue(default(TKey), out outValue)); +#if !NETFRAMEWORK + IReadOnlyDictionary readOnlyDictionary = dictionary; + Assert.Throws(() => readOnlyDictionary.TryGetValue(default(TKey), out outValue)); +#endif } } @@ -960,10 +1080,8 @@ public void IDictionary_Generic_TryGetValue_DefaultKeyContainedInDictionary(int IDictionary dictionary = GenericIDictionaryFactory(count); TKey missingKey = default(TKey); TValue value = CreateTValue(5123); - TValue outValue; dictionary.TryAdd(missingKey, value); - Assert.True(dictionary.TryGetValue(missingKey, out outValue)); - Assert.Equal(value, outValue); + CollectionAsserts.TryGetValue(dictionary, missingKey, true, value); } } diff --git a/src/libraries/Common/tests/System/Collections/IList.Generic.Tests.cs b/src/libraries/Common/tests/System/Collections/IList.Generic.Tests.cs index 44f67e0ca24f83..6d66f143f18d65 100644 --- a/src/libraries/Common/tests/System/Collections/IList.Generic.Tests.cs +++ b/src/libraries/Common/tests/System/Collections/IList.Generic.Tests.cs @@ -103,8 +103,8 @@ protected override IEnumerable GetModifyEnumerables(ModifyOper public void IList_Generic_ItemGet_NegativeIndex_ThrowsException(int count) { IList list = GenericIListFactory(count); - Assert.Throws(IList_Generic_Item_InvalidIndex_ThrowType, () => list[-1]); - Assert.Throws(IList_Generic_Item_InvalidIndex_ThrowType, () => list[int.MinValue]); + CollectionAsserts.ThrowsElementAt(list, -1, IList_Generic_Item_InvalidIndex_ThrowType); + CollectionAsserts.ThrowsElementAt(list, int.MinValue, IList_Generic_Item_InvalidIndex_ThrowType); } [Theory] @@ -112,8 +112,8 @@ public void IList_Generic_ItemGet_NegativeIndex_ThrowsException(int count) public void IList_Generic_ItemGet_IndexGreaterThanListCount_ThrowsException(int count) { IList list = GenericIListFactory(count); - Assert.Throws(IList_Generic_Item_InvalidIndex_ThrowType, () => list[count]); - Assert.Throws(IList_Generic_Item_InvalidIndex_ThrowType, () => list[count + 1]); + CollectionAsserts.ThrowsElementAt(list, count, IList_Generic_Item_InvalidIndex_ThrowType); + CollectionAsserts.ThrowsElementAt(list, count + 1, IList_Generic_Item_InvalidIndex_ThrowType); } [Theory] @@ -121,8 +121,7 @@ public void IList_Generic_ItemGet_IndexGreaterThanListCount_ThrowsException(int public void IList_Generic_ItemGet_ValidGetWithinListBounds(int count) { IList list = GenericIListFactory(count); - T result; - Assert.All(Enumerable.Range(0, count), index => result = list[index]); + Assert.All(Enumerable.Range(0, count), index => CollectionAsserts.ElementAtSucceeds(list, index)); } #endregion @@ -139,7 +138,7 @@ public void IList_Generic_ItemSet_NegativeIndex_ThrowsException(int count) T validAdd = CreateT(0); Assert.Throws(IList_Generic_Item_InvalidIndex_ThrowType, () => list[-1] = validAdd); Assert.Throws(IList_Generic_Item_InvalidIndex_ThrowType, () => list[int.MinValue] = validAdd); - Assert.Equal(count, list.Count); + CollectionAsserts.HasCount(list, count); } } @@ -153,7 +152,7 @@ public void IList_Generic_ItemSet_IndexGreaterThanListCount_ThrowsException(int T validAdd = CreateT(0); Assert.Throws(IList_Generic_Item_InvalidIndex_ThrowType, () => list[count] = validAdd); Assert.Throws(IList_Generic_Item_InvalidIndex_ThrowType, () => list[count + 1] = validAdd); - Assert.Equal(count, list.Count); + CollectionAsserts.HasCount(list, count); } } @@ -166,7 +165,7 @@ public void IList_Generic_ItemSet_OnReadOnlyList(int count) IList list = GenericIListFactory(count); T before = list[count / 2]; Assert.Throws(() => list[count / 2] = CreateT(321432)); - Assert.Equal(before, list[count / 2]); + CollectionAsserts.EqualAt(list, count / 2, before); } } @@ -179,7 +178,7 @@ public void IList_Generic_ItemSet_FirstItemToNonDefaultValue(int count) IList list = GenericIListFactory(count); T value = CreateT(123452); list[0] = value; - Assert.Equal(value, list[0]); + CollectionAsserts.EqualAt(list, 0, value); } } @@ -193,12 +192,12 @@ public void IList_Generic_ItemSet_FirstItemToDefaultValue(int count) if (DefaultValueAllowed) { list[0] = default(T); - Assert.Equal(default(T), list[0]); + CollectionAsserts.EqualAt(list, 0, default(T)); } else { Assert.Throws(() => list[0] = default(T)); - Assert.NotEqual(default(T), list[0]); + CollectionAsserts.NotEqualAt(list, 0, default(T)); } } } @@ -213,7 +212,7 @@ public void IList_Generic_ItemSet_LastItemToNonDefaultValue(int count) T value = CreateT(123452); int lastIndex = count > 0 ? count - 1 : 0; list[lastIndex] = value; - Assert.Equal(value, list[lastIndex]); + CollectionAsserts.EqualAt(list, lastIndex, value); } } @@ -228,12 +227,12 @@ public void IList_Generic_ItemSet_LastItemToDefaultValue(int count) if (DefaultValueAllowed) { list[lastIndex] = default(T); - Assert.Equal(default(T), list[lastIndex]); + CollectionAsserts.EqualAt(list, lastIndex, default(T)); } else { Assert.Throws(() => list[lastIndex] = default(T)); - Assert.NotEqual(default(T), list[lastIndex]); + CollectionAsserts.NotEqualAt(list, lastIndex, default(T)); } } } @@ -248,8 +247,8 @@ public void IList_Generic_ItemSet_DuplicateValues(int count) T value = CreateT(123452); list[0] = value; list[1] = value; - Assert.Equal(value, list[0]); - Assert.Equal(value, list[1]); + CollectionAsserts.EqualAt(list, 0, value); + CollectionAsserts.EqualAt(list, 1, value); } } @@ -396,7 +395,7 @@ public void IList_Generic_Insert_NegativeIndex_ThrowsArgumentOutOfRangeException T validAdd = CreateT(0); Assert.Throws(() => list.Insert(-1, validAdd)); Assert.Throws(() => list.Insert(int.MinValue, validAdd)); - Assert.Equal(count, list.Count); + CollectionAsserts.HasCount(list, count); } } @@ -409,8 +408,8 @@ public void IList_Generic_Insert_IndexGreaterThanListCount_Appends(int count) IList list = GenericIListFactory(count); T validAdd = CreateT(12350); list.Insert(count, validAdd); - Assert.Equal(count + 1, list.Count); - Assert.Equal(validAdd, list[count]); + CollectionAsserts.HasCount(list, count + 1); + CollectionAsserts.EqualAt(list, count, validAdd); } } @@ -422,7 +421,7 @@ public void IList_Generic_Insert_ToReadOnlyList(int count) { IList list = GenericIListFactory(count); Assert.Throws(() => list.Insert(count / 2, CreateT(321432))); - Assert.Equal(count, list.Count); + CollectionAsserts.HasCount(list, count); } } @@ -435,8 +434,8 @@ public void IList_Generic_Insert_FirstItemToNonDefaultValue(int count) IList list = GenericIListFactory(count); T value = CreateT(123452); list.Insert(0, value); - Assert.Equal(value, list[0]); - Assert.Equal(count + 1, list.Count); + CollectionAsserts.EqualAt(list, 0, value); + CollectionAsserts.HasCount(list, count + 1); } } @@ -449,8 +448,8 @@ public void IList_Generic_Insert_FirstItemToDefaultValue(int count) IList list = GenericIListFactory(count); T value = default(T); list.Insert(0, value); - Assert.Equal(value, list[0]); - Assert.Equal(count + 1, list.Count); + CollectionAsserts.EqualAt(list, 0, value); + CollectionAsserts.HasCount(list, count + 1); } } @@ -464,8 +463,8 @@ public void IList_Generic_Insert_LastItemToNonDefaultValue(int count) T value = CreateT(123452); int lastIndex = count > 0 ? count - 1 : 0; list.Insert(lastIndex, value); - Assert.Equal(value, list[lastIndex]); - Assert.Equal(count + 1, list.Count); + CollectionAsserts.EqualAt(list, lastIndex, value); + CollectionAsserts.HasCount(list, count + 1); } } @@ -479,8 +478,8 @@ public void IList_Generic_Insert_LastItemToDefaultValue(int count) T value = default(T); int lastIndex = count > 0 ? count - 1 : 0; list.Insert(lastIndex, value); - Assert.Equal(value, list[lastIndex]); - Assert.Equal(count + 1, list.Count); + CollectionAsserts.EqualAt(list, lastIndex, value); + CollectionAsserts.HasCount(list, count + 1); } } @@ -500,9 +499,9 @@ public void IList_Generic_Insert_DuplicateValues(int count) { list.Insert(0, value); list.Insert(1, value); - Assert.Equal(value, list[0]); - Assert.Equal(value, list[1]); - Assert.Equal(count + 2, list.Count); + CollectionAsserts.EqualAt(list, 0, value); + CollectionAsserts.EqualAt(list, 1, value); + CollectionAsserts.HasCount(list, count + 2); } } } @@ -535,7 +534,7 @@ public void IList_Generic_RemoveAt_NegativeIndex_ThrowsArgumentOutOfRangeExcepti T validAdd = CreateT(0); Assert.Throws(() => list.RemoveAt(-1)); Assert.Throws(() => list.RemoveAt(int.MinValue)); - Assert.Equal(count, list.Count); + CollectionAsserts.HasCount(list, count); } } @@ -549,7 +548,7 @@ public void IList_Generic_RemoveAt_IndexGreaterThanListCount_ThrowsArgumentOutOf T validAdd = CreateT(0); Assert.Throws(() => list.RemoveAt(count)); Assert.Throws(() => list.RemoveAt(count + 1)); - Assert.Equal(count, list.Count); + CollectionAsserts.HasCount(list, count); } } @@ -561,7 +560,7 @@ public void IList_Generic_RemoveAt_OnReadOnlyList(int count) { IList list = GenericIListFactory(count); Assert.Throws(() => list.RemoveAt(count / 2)); - Assert.Equal(count, list.Count); + CollectionAsserts.HasCount(list, count); } } @@ -572,11 +571,11 @@ public void IList_Generic_RemoveAt_AllValidIndices(int count) if (!IsReadOnly && !AddRemoveClear_ThrowsNotSupported) { IList list = GenericIListFactory(count); - Assert.Equal(count, list.Count); + CollectionAsserts.HasCount(list, count); Assert.All(Enumerable.Range(0, count).Reverse(), index => { list.RemoveAt(index); - Assert.Equal(index, list.Count); + CollectionAsserts.HasCount(list, index); }); } } @@ -591,7 +590,7 @@ public void IList_Generic_RemoveAt_ZeroMultipleTimes(int count) Assert.All(Enumerable.Range(0, count), index => { list.RemoveAt(0); - Assert.Equal(count - index - 1, list.Count); + CollectionAsserts.HasCount(list, count - index - 1); }); } } diff --git a/src/libraries/Common/tests/System/Collections/ISet.Generic.Tests.cs b/src/libraries/Common/tests/System/Collections/ISet.Generic.Tests.cs index 303001e8bd1443..350faab6f44cb7 100644 --- a/src/libraries/Common/tests/System/Collections/ISet.Generic.Tests.cs +++ b/src/libraries/Common/tests/System/Collections/ISet.Generic.Tests.cs @@ -84,8 +84,8 @@ public void ICollection_Generic_Add_ReturnValue(int count) Assert.True(set.Add(newValue)); if (!DuplicateValuesAllowed) Assert.False(set.Add(newValue)); - Assert.Equal(count + 1, set.Count); - Assert.True(set.Contains(newValue)); + CollectionAsserts.HasCount(set, count + 1); + CollectionAsserts.Contains(set, newValue); } } @@ -104,7 +104,7 @@ public void ICollection_Generic_Add_DuplicateValue_DoesNothing(int count) duplicateValue = CreateT(seed++); collection.Add(duplicateValue); collection.Add(duplicateValue); - Assert.Equal(count + 1, collection.Count); + CollectionAsserts.HasCount(collection, count + 1); } } } @@ -118,7 +118,7 @@ private void Validate_ExceptWith(ISet set, IEnumerable enumerable) if (set.Count == 0 || enumerable == set) { set.ExceptWith(enumerable); - Assert.Equal(0, set.Count); + CollectionAsserts.HasCount(set, 0); } else { @@ -126,7 +126,7 @@ private void Validate_ExceptWith(ISet set, IEnumerable enumerable) foreach (T element in enumerable) expected.Remove(element); set.ExceptWith(enumerable); - Assert.Equal(expected.Count, set.Count); + CollectionAsserts.HasCount(set, expected.Count); Assert.True(expected.SetEquals(set)); } } @@ -136,7 +136,7 @@ private void Validate_IntersectWith(ISet set, IEnumerable enumerable) if (set.Count == 0 || Enumerable.Count(enumerable) == 0) { set.IntersectWith(enumerable); - Assert.Equal(0, set.Count); + CollectionAsserts.HasCount(set, 0); } else if (set == enumerable) { @@ -152,7 +152,7 @@ private void Validate_IntersectWith(ISet set, IEnumerable enumerable) if (enumerable.Contains(value, comparer)) expected.Add(value); set.IntersectWith(enumerable); - Assert.Equal(expected.Count, set.Count); + CollectionAsserts.HasCount(set, expected.Count); Assert.True(expected.SetEquals(set)); } } @@ -178,7 +178,7 @@ private void Validate_IsProperSubsetOf(ISet set, IEnumerable enumerable) break; } } - Assert.Equal(!setContainsValueNotInEnumerable && enumerableContainsValueNotInSet, set.IsProperSubsetOf(enumerable)); + CollectionAsserts.IsProperSubsetOf(set, enumerable, !setContainsValueNotInEnumerable && enumerableContainsValueNotInSet); } private void Validate_IsProperSupersetOf(ISet set, IEnumerable enumerable) @@ -203,7 +203,7 @@ private void Validate_IsProperSupersetOf(ISet set, IEnumerable enumerable) } } isProperSuperset = isProperSuperset && setContainsElementsNotInEnumerable; - Assert.Equal(isProperSuperset, set.IsProperSupersetOf(enumerable)); + CollectionAsserts.IsProperSupersetOf(set, enumerable, isProperSuperset); } private void Validate_IsSubsetOf(ISet set, IEnumerable enumerable) @@ -212,10 +212,10 @@ private void Validate_IsSubsetOf(ISet set, IEnumerable enumerable) foreach (T value in set) if (!enumerable.Contains(value, comparer)) { - Assert.False(set.IsSubsetOf(enumerable)); + CollectionAsserts.IsSubsetOf(set, enumerable, false); return; } - Assert.True(set.IsSubsetOf(enumerable)); + CollectionAsserts.IsSubsetOf(set, enumerable, true); } private void Validate_IsSupersetOf(ISet set, IEnumerable enumerable) @@ -224,10 +224,10 @@ private void Validate_IsSupersetOf(ISet set, IEnumerable enumerable) foreach (T value in enumerable) if (!set.Contains(value, comparer)) { - Assert.False(set.IsSupersetOf(enumerable)); + CollectionAsserts.IsSupersetOf(set, enumerable, false); return; } - Assert.True(set.IsSupersetOf(enumerable)); + CollectionAsserts.IsSupersetOf(set, enumerable, true); } private void Validate_Overlaps(ISet set, IEnumerable enumerable) @@ -237,11 +237,11 @@ private void Validate_Overlaps(ISet set, IEnumerable enumerable) { if (set.Contains(value, comparer)) { - Assert.True(set.Overlaps(enumerable)); + CollectionAsserts.Overlaps(set, enumerable, true); return; } } - Assert.False(set.Overlaps(enumerable)); + CollectionAsserts.Overlaps(set, enumerable, false); } private void Validate_SetEquals(ISet set, IEnumerable enumerable) @@ -251,7 +251,7 @@ private void Validate_SetEquals(ISet set, IEnumerable enumerable) { if (!enumerable.Contains(value, comparer)) { - Assert.False(set.SetEquals(enumerable)); + CollectionAsserts.SetEquals(set, enumerable, false); return; } } @@ -259,11 +259,11 @@ private void Validate_SetEquals(ISet set, IEnumerable enumerable) { if (!set.Contains(value, comparer)) { - Assert.False(set.SetEquals(enumerable)); + CollectionAsserts.SetEquals(set, enumerable, false); return; } } - Assert.True(set.SetEquals(enumerable)); + CollectionAsserts.SetEquals(set, enumerable, true); } private void Validate_SymmetricExceptWith(ISet set, IEnumerable enumerable) @@ -277,7 +277,7 @@ private void Validate_SymmetricExceptWith(ISet set, IEnumerable enumerable if (!enumerable.Contains(element, comparer)) expected.Add(element); set.SymmetricExceptWith(enumerable); - Assert.Equal(expected.Count, set.Count); + CollectionAsserts.HasCount(set, expected.Count); Assert.True(expected.SetEquals(set)); } @@ -289,7 +289,7 @@ private void Validate_UnionWith(ISet set, IEnumerable enumerable) if (!set.Contains(element, comparer)) expected.Add(element); set.UnionWith(enumerable); - Assert.Equal(expected.Count, set.Count); + CollectionAsserts.HasCount(set, expected.Count); Assert.True(expected.SetEquals(set)); } @@ -308,6 +308,15 @@ public void ISet_Generic_NullEnumerableArgument(int count) Assert.Throws(() => set.IsSupersetOf(null)); Assert.Throws(() => set.Overlaps(null)); Assert.Throws(() => set.SetEquals(null)); +#if !NETFRAMEWORK + IReadOnlySet readOnlySet = set; + Assert.Throws(() => readOnlySet.IsProperSubsetOf(null)); + Assert.Throws(() => readOnlySet.IsProperSupersetOf(null)); + Assert.Throws(() => readOnlySet.IsSubsetOf(null)); + Assert.Throws(() => readOnlySet.IsSupersetOf(null)); + Assert.Throws(() => readOnlySet.Overlaps(null)); + Assert.Throws(() => readOnlySet.SetEquals(null)); +#endif if (!IsReadOnly) { Assert.Throws(() => set.ExceptWith(null)); @@ -502,7 +511,7 @@ public void ISet_Generic_Overlaps_Itself(int setLength) public void ISet_Generic_SetEquals_Itself(int setLength) { ISet set = GenericISetFactory(setLength); - Assert.True(set.SetEquals(set)); + CollectionAsserts.SetEquals(set, set, true); } [Theory] @@ -660,7 +669,7 @@ public void ISet_Generic_SymmetricExceptWith_AfterRemovingElements(EnumerableTyp if (!enumerable.Contains(element, comparer)) expected.Add(element); set.SymmetricExceptWith(enumerable); - Assert.Equal(expected.Count, set.Count); + CollectionAsserts.HasCount(set, expected.Count); Assert.True(expected.SetEquals(set)); } } diff --git a/src/libraries/System.Collections/tests/Generic/CollectionExtensionsTests.cs b/src/libraries/System.Collections/tests/Generic/CollectionExtensionsTests.cs index 213d9d6faca996..6a5b458232fc5c 100644 --- a/src/libraries/System.Collections/tests/Generic/CollectionExtensionsTests.cs +++ b/src/libraries/System.Collections/tests/Generic/CollectionExtensionsTests.cs @@ -61,6 +61,10 @@ public void TryAdd_KeyDoesntExistInIDictionary_ReturnsTrue() IDictionary dictionary = new SortedDictionary(); Assert.True(dictionary.TryAdd("key", "value")); Assert.Equal("value", dictionary["key"]); +#if !NETFRAMEWORK + IReadOnlyDictionary readOnlyDictionary = dictionary; + Assert.Equal("value", readOnlyDictionary["key"]); +#endif } [Fact] @@ -69,6 +73,10 @@ public void TryAdd_KeyExistsInIDictionary_ReturnsFalse() IDictionary dictionary = new SortedDictionary() { ["key"] = "value" }; Assert.False(dictionary.TryAdd("key", "value2")); Assert.Equal("value", dictionary["key"]); +#if !NETFRAMEWORK + IReadOnlyDictionary readOnlyDictionary = dictionary; + Assert.Equal("value", readOnlyDictionary["key"]); +#endif } [Fact] @@ -96,6 +104,10 @@ public void Remove_KeyExistsInIDictionary_ReturnsTrue() Assert.True(dictionary.Remove("key", out var value)); Assert.Equal("value", value); Assert.Throws(() => dictionary["key"]); +#if !NETFRAMEWORK + IReadOnlyDictionary readOnlyDictionary = dictionary; + Assert.Throws(() => readOnlyDictionary["key"]); +#endif } [Fact] diff --git a/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/ICollection.cs b/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/ICollection.cs index 1c1095f8a5cf75..24cf81efb2b440 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/ICollection.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/ICollection.cs @@ -9,9 +9,9 @@ namespace System.Collections.Generic { // Base interface for all collections, defining enumerators, size, and // synchronization methods. - public interface ICollection : IEnumerable + public interface ICollection : IReadOnlyCollection { - int Count + new int Count { #if MONO [DynamicDependency(nameof(Array.InternalArray__ICollection_get_Count), typeof(Array))] @@ -53,5 +53,7 @@ bool IsReadOnly [DynamicDependency(nameof(Array.InternalArray__ICollection_Remove) + "``1", typeof(Array))] #endif bool Remove(T item); + + int IReadOnlyCollection.Count => Count; } } diff --git a/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/IDictionary.cs b/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/IDictionary.cs index 56a03106c205b6..7e3e30d8db0929 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/IDictionary.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/IDictionary.cs @@ -9,32 +9,32 @@ namespace System.Collections.Generic // Keys can be any non-null object. Values can be any object. // You can look up a value in an IDictionary via the default indexed // property, Items. - public interface IDictionary : ICollection> + public interface IDictionary : ICollection>, IReadOnlyDictionary { // Interfaces are not serializable // The Item property provides methods to read and edit entries // in the Dictionary. - TValue this[TKey key] + new TValue this[TKey key] { get; set; } // Returns a collections of the keys in this dictionary. - ICollection Keys + new ICollection Keys { get; } // Returns a collections of the values in this dictionary. - ICollection Values + new ICollection Values { get; } // Returns whether this dictionary contains a particular key. // - bool ContainsKey(TKey key); + new bool ContainsKey(TKey key); // Adds a key-value pair to the dictionary. // @@ -44,6 +44,16 @@ ICollection Values // bool Remove(TKey key); - bool TryGetValue(TKey key, [MaybeNullWhen(false)] out TValue value); + new bool TryGetValue(TKey key, [MaybeNullWhen(false)] out TValue value); + + TValue IReadOnlyDictionary.this[TKey key] => this[key]; + + IEnumerable IReadOnlyDictionary.Keys => Keys; + + IEnumerable IReadOnlyDictionary.Values => Values; + + bool IReadOnlyDictionary.ContainsKey(TKey key) => ContainsKey(key); + + bool IReadOnlyDictionary.TryGetValue(TKey key, [MaybeNullWhen(false)] out TValue value) => TryGetValue(key, out value); } } diff --git a/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/IList.cs b/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/IList.cs index f45ae823daf650..ec8098c3ff7ea1 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/IList.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/IList.cs @@ -10,10 +10,10 @@ namespace System.Collections.Generic // An IList is an ordered collection of objects. The exact ordering // is up to the implementation of the list, ranging from a sorted // order to insertion order. - public interface IList : ICollection + public interface IList : ICollection, IReadOnlyList { // The Item property provides methods to read and edit entries in the List. - T this[int index] + new T this[int index] { #if MONO [DynamicDependency(nameof(Array.InternalArray__get_Item) + "``1", typeof(Array))] @@ -46,5 +46,7 @@ T this[int index] [DynamicDependency(nameof(Array.InternalArray__RemoveAt), typeof(Array))] #endif void RemoveAt(int index); + + T IReadOnlyList.this[int index] => this[index]; } } diff --git a/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/ISet.cs b/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/ISet.cs index cee05d198cda07..ce2e8e7c5f4ff1 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/ISet.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/ISet.cs @@ -8,7 +8,7 @@ namespace System.Collections.Generic /// by some comparer. It also supports basic set operations such as Union, Intersection, /// Complement and Exclusive Complement. /// - public interface ISet : ICollection + public interface ISet : ICollection, IReadOnlySet { //Add ITEM to the set, return true if added, false if duplicate new bool Add(T item); @@ -26,21 +26,42 @@ public interface ISet : ICollection void SymmetricExceptWith(IEnumerable other); //Check if this set is a subset of other - bool IsSubsetOf(IEnumerable other); + new bool IsSubsetOf(IEnumerable other); //Check if this set is a superset of other - bool IsSupersetOf(IEnumerable other); + new bool IsSupersetOf(IEnumerable other); //Check if this set is a subset of other, but not the same as it - bool IsProperSupersetOf(IEnumerable other); + new bool IsProperSupersetOf(IEnumerable other); //Check if this set is a superset of other, but not the same as it - bool IsProperSubsetOf(IEnumerable other); + new bool IsProperSubsetOf(IEnumerable other); //Check if this set has any elements in common with other - bool Overlaps(IEnumerable other); + new bool Overlaps(IEnumerable other); //Check if this set contains the same and only the same elements as other - bool SetEquals(IEnumerable other); + new bool SetEquals(IEnumerable other); + + /// + /// Determines if the set contains a specific item + /// + /// The item to check if the set contains. + /// if found; otherwise . + new bool Contains(T item) => ((ICollection)this).Contains(item); + + bool IReadOnlySet.IsSubsetOf(IEnumerable other) => IsSubsetOf(other); + + bool IReadOnlySet.IsSupersetOf(IEnumerable other) => IsSupersetOf(other); + + bool IReadOnlySet.IsProperSupersetOf(IEnumerable other) => IsProperSupersetOf(other); + + bool IReadOnlySet.IsProperSubsetOf(IEnumerable other) => IsProperSubsetOf(other); + + bool IReadOnlySet.Overlaps(IEnumerable other) => Overlaps(other); + + bool IReadOnlySet.SetEquals(IEnumerable other) => SetEquals(other); + + bool IReadOnlySet.Contains(T value) => ((ICollection)this).Contains(value); } } diff --git a/src/libraries/System.Runtime/ref/System.Runtime.cs b/src/libraries/System.Runtime/ref/System.Runtime.cs index a3f2a4b07e2f48..c2f175247dc9b6 100644 --- a/src/libraries/System.Runtime/ref/System.Runtime.cs +++ b/src/libraries/System.Runtime/ref/System.Runtime.cs @@ -7803,29 +7803,35 @@ public partial interface IAsyncEnumerator : System.IAsyncDisposable T Current { get; } System.Threading.Tasks.ValueTask MoveNextAsync(); } - public partial interface ICollection : System.Collections.Generic.IEnumerable, System.Collections.IEnumerable + public partial interface ICollection : System.Collections.Generic.IEnumerable, System.Collections.IEnumerable, System.Collections.Generic.IReadOnlyCollection { - int Count { get; } + new int Count { get; } bool IsReadOnly { get; } void Add(T item); void Clear(); bool Contains(T item); void CopyTo(T[] array, int arrayIndex); bool Remove(T item); + int System.Collections.Generic.IReadOnlyCollection.Count => Count; } public partial interface IComparer { int Compare(T? x, T? y); } - public partial interface IDictionary : System.Collections.Generic.ICollection>, System.Collections.Generic.IEnumerable>, System.Collections.IEnumerable + public partial interface IDictionary : System.Collections.Generic.ICollection>, System.Collections.Generic.IEnumerable>, System.Collections.IEnumerable, System.Collections.Generic.IReadOnlyDictionary, System.Collections.Generic.IReadOnlyCollection> { - TValue this[TKey key] { get; set; } - System.Collections.Generic.ICollection Keys { get; } - System.Collections.Generic.ICollection Values { get; } + new TValue this[TKey key] { get; set; } + new System.Collections.Generic.ICollection Keys { get; } + new System.Collections.Generic.ICollection Values { get; } void Add(TKey key, TValue value); - bool ContainsKey(TKey key); + new bool ContainsKey(TKey key); bool Remove(TKey key); - bool TryGetValue(TKey key, [System.Diagnostics.CodeAnalysis.MaybeNullWhenAttribute(false)] out TValue value); + new bool TryGetValue(TKey key, [System.Diagnostics.CodeAnalysis.MaybeNullWhenAttribute(false)] out TValue value); + TValue System.Collections.Generic.IReadOnlyDictionary.this[TKey key] => this[key]; + System.Collections.Generic.IEnumerable System.Collections.Generic.IReadOnlyDictionary.Keys => Keys; + System.Collections.Generic.IEnumerable System.Collections.Generic.IReadOnlyDictionary.Values => Values; + bool System.Collections.Generic.IReadOnlyDictionary.ContainsKey(TKey key) => ContainsKey(key); + bool System.Collections.Generic.IReadOnlyDictionary.TryGetValue(TKey key, [System.Diagnostics.CodeAnalysis.MaybeNullWhenAttribute(false)] out TValue value) => TryGetValue(key, out value); } public partial interface IEnumerable : System.Collections.IEnumerable { @@ -7840,12 +7846,13 @@ public partial interface IEqualityComparer bool Equals(T? x, T? y); int GetHashCode([System.Diagnostics.CodeAnalysis.DisallowNullAttribute] T obj); } - public partial interface IList : System.Collections.Generic.ICollection, System.Collections.Generic.IEnumerable, System.Collections.IEnumerable + public partial interface IList : System.Collections.Generic.ICollection, System.Collections.Generic.IEnumerable, System.Collections.IEnumerable, System.Collections.Generic.IReadOnlyList, System.Collections.Generic.IReadOnlyCollection { - T this[int index] { get; set; } + new T this[int index] { get; set; } int IndexOf(T item); void Insert(int index, T item); void RemoveAt(int index); + T System.Collections.Generic.IReadOnlyList.this[int index] => this[index]; } public partial interface IReadOnlyCollection : System.Collections.Generic.IEnumerable, System.Collections.IEnumerable { @@ -7873,19 +7880,27 @@ public partial interface IReadOnlySet : System.Collections.Generic.IEnumerabl bool Overlaps(System.Collections.Generic.IEnumerable other); bool SetEquals(System.Collections.Generic.IEnumerable other); } - public partial interface ISet : System.Collections.Generic.ICollection, System.Collections.Generic.IEnumerable, System.Collections.IEnumerable + public partial interface ISet : System.Collections.Generic.ICollection, System.Collections.Generic.IEnumerable, System.Collections.IEnumerable, System.Collections.Generic.IReadOnlySet, System.Collections.Generic.IReadOnlyCollection { new bool Add(T item); void ExceptWith(System.Collections.Generic.IEnumerable other); void IntersectWith(System.Collections.Generic.IEnumerable other); - bool IsProperSubsetOf(System.Collections.Generic.IEnumerable other); - bool IsProperSupersetOf(System.Collections.Generic.IEnumerable other); - bool IsSubsetOf(System.Collections.Generic.IEnumerable other); - bool IsSupersetOf(System.Collections.Generic.IEnumerable other); - bool Overlaps(System.Collections.Generic.IEnumerable other); - bool SetEquals(System.Collections.Generic.IEnumerable other); + new bool IsProperSubsetOf(System.Collections.Generic.IEnumerable other); + new bool IsProperSupersetOf(System.Collections.Generic.IEnumerable other); + new bool IsSubsetOf(System.Collections.Generic.IEnumerable other); + new bool IsSupersetOf(System.Collections.Generic.IEnumerable other); + new bool Overlaps(System.Collections.Generic.IEnumerable other); + new bool SetEquals(System.Collections.Generic.IEnumerable other); void SymmetricExceptWith(System.Collections.Generic.IEnumerable other); void UnionWith(System.Collections.Generic.IEnumerable other); + new bool Contains(T item) => ((ICollection)this).Contains(item); + bool System.Collections.Generic.IReadOnlySet.Contains(T item) => ((ICollection)this).Contains(item); + bool System.Collections.Generic.IReadOnlySet.IsProperSubsetOf(System.Collections.Generic.IEnumerable other) => IsProperSubsetOf(other); + bool System.Collections.Generic.IReadOnlySet.IsProperSupersetOf(System.Collections.Generic.IEnumerable other) => IsProperSupersetOf(other); + bool System.Collections.Generic.IReadOnlySet.IsSubsetOf(System.Collections.Generic.IEnumerable other) => IsSubsetOf(other); + bool System.Collections.Generic.IReadOnlySet.IsSupersetOf(System.Collections.Generic.IEnumerable other) => IsSupersetOf(other); + bool System.Collections.Generic.IReadOnlySet.Overlaps(System.Collections.Generic.IEnumerable other) => Overlaps(other); + bool System.Collections.Generic.IReadOnlySet.SetEquals(System.Collections.Generic.IEnumerable other) => SetEquals(other); } public partial class KeyNotFoundException : System.SystemException { From 3e18c03f644b15060be2ac35d1f3b8cc2895bd32 Mon Sep 17 00:00:00 2001 From: Aaron Robinson Date: Tue, 23 Apr 2024 19:14:50 -0700 Subject: [PATCH 045/161] Simplify managed MetadataImport creation (#101353) * Simplify managed MetadataImport creation Consolidate the create mechanism for the managed MetadataImport type. This also removes some Helper Method Frame usage. * Always get the latest metadataimport instance. The field on the managed object can become stale during HotReload or EnC scenarios. --------- Co-authored-by: Jan Kotas --- .../src/System/Reflection/MdImport.cs | 15 ++++---- .../Reflection/RuntimeCustomAttributeData.cs | 35 ++++++++++++------- .../src/System/Reflection/RuntimeModule.cs | 4 +-- .../System/Reflection/RuntimeParameterInfo.cs | 21 +++++++---- .../System/Reflection/RuntimePropertyInfo.cs | 7 ++-- .../src/System/RuntimeHandles.cs | 25 +++---------- .../src/System/RuntimeType.CoreCLR.cs | 25 ++++++++----- src/coreclr/vm/domainassembly.cpp | 8 ++--- src/coreclr/vm/ecalllist.h | 3 +- src/coreclr/vm/managedmdimport.cpp | 10 ++++++ src/coreclr/vm/managedmdimport.hpp | 1 + src/coreclr/vm/runtimehandles.cpp | 29 --------------- src/coreclr/vm/runtimehandles.h | 10 +----- 13 files changed, 91 insertions(+), 102 deletions(-) diff --git a/src/coreclr/System.Private.CoreLib/src/System/Reflection/MdImport.cs b/src/coreclr/System.Private.CoreLib/src/System/Reflection/MdImport.cs index febf1a5055568f..6f74dde91fe7e0 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Reflection/MdImport.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/MdImport.cs @@ -205,9 +205,6 @@ internal readonly partial struct MetadataImport #pragma warning restore CA1067 { private readonly IntPtr m_metadataImport2; - private readonly object? m_keepalive; - - internal static MetadataImport EmptyImport => new MetadataImport(IntPtr.Zero, null); #region Override methods from Object public override int GetHashCode() @@ -304,10 +301,16 @@ internal static unsafe MarshalAsAttribute GetMarshalAs(ConstArray nativeType, Ru #endregion #region Constructor - internal MetadataImport(IntPtr metadataImport2, object? keepalive) + [MethodImpl(MethodImplOptions.InternalCall)] + private static extern unsafe IntPtr GetMetadataImport(RuntimeModule module); + + internal MetadataImport(RuntimeModule module) { - m_metadataImport2 = metadataImport2; - m_keepalive = keepalive; + ArgumentNullException.ThrowIfNull(module); + + // The MetadataImport instance needs to be acquired in this manner + // since the instance can be replaced during HotReload and EnC scenarios. + m_metadataImport2 = GetMetadataImport(module); } #endregion diff --git a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeCustomAttributeData.cs b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeCustomAttributeData.cs index fd33d68fb0758e..38663e57cde246 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeCustomAttributeData.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeCustomAttributeData.cs @@ -215,6 +215,7 @@ internal static CustomAttributeRecord[] GetCustomAttributeRecords(RuntimeModule scope.GetCustomAttributeProps(tkCustomAttributeTokens[i], out records[i].tkCtor.Value, out records[i].blob); } + GC.KeepAlive(module); return records; } @@ -250,13 +251,13 @@ internal static CustomAttributeTypedArgument Filter(IList a private RuntimeCustomAttributeData(RuntimeModule scope, MetadataToken caCtorToken, in ConstArray blob) { m_scope = scope; - m_ctor = (RuntimeConstructorInfo)RuntimeType.GetMethodBase(scope, caCtorToken)!; + m_ctor = (RuntimeConstructorInfo)RuntimeType.GetMethodBase(m_scope, caCtorToken)!; if (m_ctor!.DeclaringType!.IsGenericType) { - MetadataImport metadataScope = scope.MetadataImport; - Type attributeType = scope.ResolveType(metadataScope.GetParentToken(caCtorToken), null, null)!; - m_ctor = (RuntimeConstructorInfo)scope.ResolveMethod(caCtorToken, attributeType.GenericTypeArguments, null)!.MethodHandle.GetMethodInfo(); + MetadataImport metadataScope = m_scope.MetadataImport; + Type attributeType = m_scope.ResolveType(metadataScope.GetParentToken(caCtorToken), null, null)!; + m_ctor = (RuntimeConstructorInfo)m_scope.ResolveMethod(caCtorToken, attributeType.GenericTypeArguments, null)!.MethodHandle.GetMethodInfo(); } ReadOnlySpan parameters = m_ctor.GetParametersAsSpan(); @@ -1466,6 +1467,7 @@ private static bool IsCustomAttributeDefined( } } } + GC.KeepAlive(decoratedModule); return false; } @@ -1615,6 +1617,7 @@ private static void AddCustomAttributes( attributes.Add(attribute); } + GC.KeepAlive(decoratedModule); } [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:RequiresUnreferencedCode", @@ -2194,10 +2197,11 @@ internal static bool IsDefined(RuntimeFieldInfo field, RuntimeType? caType) if ((method.Attributes & MethodAttributes.PinvokeImpl) == 0) return null; - MetadataImport scope = ModuleHandle.GetMetadataImport(method.Module.ModuleHandle.GetRuntimeModule()); + RuntimeModule module = method.Module.ModuleHandle.GetRuntimeModule(); + MetadataImport scope = module.MetadataImport; int token = method.MetadataToken; - scope.GetPInvokeMap(token, out PInvokeAttributes flags, out string entryPoint, out string dllName); + GC.KeepAlive(module); CharSet charSet = CharSet.None; @@ -2252,7 +2256,7 @@ internal static bool IsDefined(RuntimeFieldInfo field, RuntimeType? caType) private static MarshalAsAttribute? GetMarshalAsCustomAttribute(int token, RuntimeModule scope) { - ConstArray nativeType = ModuleHandle.GetMetadataImport(scope).GetFieldMarshal(token); + ConstArray nativeType = scope.MetadataImport.GetFieldMarshal(token); if (nativeType.Length == 0) return null; @@ -2262,10 +2266,15 @@ internal static bool IsDefined(RuntimeFieldInfo field, RuntimeType? caType) private static FieldOffsetAttribute? GetFieldOffsetCustomAttribute(RuntimeFieldInfo field) { - if (field.DeclaringType is not null && - field.GetRuntimeModule().MetadataImport.GetFieldOffset(field.DeclaringType.MetadataToken, field.MetadataToken, out int fieldOffset)) - return new FieldOffsetAttribute(fieldOffset); - + if (field.DeclaringType is not null) + { + RuntimeModule module = field.GetRuntimeModule(); + if (module.MetadataImport.GetFieldOffset(field.DeclaringType.MetadataToken, field.MetadataToken, out int fieldOffset)) + { + return new FieldOffsetAttribute(fieldOffset); + } + GC.KeepAlive(module); + } return null; } @@ -2291,7 +2300,9 @@ internal static bool IsDefined(RuntimeFieldInfo field, RuntimeType? caType) case TypeAttributes.UnicodeClass: charSet = CharSet.Unicode; break; default: Debug.Fail("Unreachable code"); break; } - type.GetRuntimeModule().MetadataImport.GetClassLayout(type.MetadataToken, out int pack, out int size); + RuntimeModule module = type.GetRuntimeModule(); + module.MetadataImport.GetClassLayout(type.MetadataToken, out int pack, out int size); + GC.KeepAlive(module); StructLayoutAttribute attribute = new StructLayoutAttribute(layoutKind); diff --git a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeModule.cs b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeModule.cs index 8e7e4a05c73dde..4e9a4dffeb209a 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeModule.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeModule.cs @@ -202,7 +202,7 @@ public override byte[] ResolveSignature(int metadataToken) if (declaringType.IsGenericType || declaringType.IsArray) { - int tkDeclaringType = ModuleHandle.GetMetadataImport(this).GetParentToken(metadataToken); + int tkDeclaringType = MetadataImport.GetParentToken(metadataToken); declaringType = (RuntimeType)ResolveType(tkDeclaringType, genericTypeArguments, genericMethodArguments); } @@ -353,7 +353,7 @@ public override void GetPEKind(out PortableExecutableKinds peKind, out ImageFile #region Internal Members internal RuntimeType RuntimeType => m_runtimeType ??= ModuleHandle.GetModuleType(this); - internal MetadataImport MetadataImport => ModuleHandle.GetMetadataImport(this); + internal MetadataImport MetadataImport => new MetadataImport(this); #endregion #region ICustomAttributeProvider Members diff --git a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeParameterInfo.cs b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeParameterInfo.cs index 5af77b790f49c3..24dd89c2113172 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeParameterInfo.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeParameterInfo.cs @@ -29,6 +29,11 @@ internal static ParameterInfo GetReturnParameter(IRuntimeMethodInfo method, Memb private static ParameterInfo[] GetParameters( IRuntimeMethodInfo methodHandle, MemberInfo member, Signature sig, out ParameterInfo? returnParameter, bool fetchReturnParameter) { + // The lifetime rules for MetadataImport expect these two objects to be the same instance. + // See the lifetime of MetadataImport, acquired through IRuntimeMethodInfo, but extended + // through the MemberInfo instance. + Debug.Assert(ReferenceEquals(methodHandle, member)); + returnParameter = null; int sigArgCount = sig.Arguments.Length; ParameterInfo[] args = @@ -43,7 +48,7 @@ private static ParameterInfo[] GetParameters( // are generated on the fly by the runtime. if (!MdToken.IsNullToken(tkMethodDef)) { - MetadataImport scope = RuntimeTypeHandle.GetMetadataImport(RuntimeMethodHandle.GetDeclaringType(methodHandle)); + MetadataImport scope = RuntimeMethodHandle.GetDeclaringType(methodHandle).GetRuntimeModule().MetadataImport; scope.EnumParams(tkMethodDef, out MetadataEnumResult tkParamDefs); @@ -73,7 +78,7 @@ private static ParameterInfo[] GetParameters( } else if (!fetchReturnParameter && position >= 0) { - // position beyong sigArgCount? + // position beyond sigArgCount? if (position >= sigArgCount) throw new BadImageFormatException(SR.BadImageFormat_ParameterSignatureMismatch); @@ -86,7 +91,7 @@ private static ParameterInfo[] GetParameters( // Fill in empty ParameterInfos for those without tokens if (fetchReturnParameter) { - returnParameter ??= new RuntimeParameterInfo(sig, MetadataImport.EmptyImport, 0, -1, (ParameterAttributes)0, member); + returnParameter ??= new RuntimeParameterInfo(sig, default, 0, -1, (ParameterAttributes)0, member); } else { @@ -97,7 +102,7 @@ private static ParameterInfo[] GetParameters( if (args[i] != null) continue; - args[i] = new RuntimeParameterInfo(sig, MetadataImport.EmptyImport, 0, i, (ParameterAttributes)0, member); + args[i] = new RuntimeParameterInfo(sig, default, 0, i, (ParameterAttributes)0, member); } } } @@ -165,7 +170,7 @@ private RuntimeParameterInfo(RuntimeParameterInfo accessor, MemberInfo member) PositionImpl = accessor.Position; AttrsImpl = accessor.Attributes; - // Strictly speeking, property's don't contain parameter tokens + // Strictly speaking, properties don't contain parameter tokens // However we need this to make ca's work... oh well... m_tkParamDef = MdToken.IsNullToken(accessor.MetadataToken) ? (int)MetadataTokenType.ParamDef : accessor.MetadataToken; m_scope = accessor.m_scope; @@ -176,7 +181,7 @@ private RuntimeParameterInfo( int position, ParameterAttributes attributes, MemberInfo member) { Debug.Assert(member != null); - Debug.Assert(MdToken.IsNullToken(tkParamDef) == scope.Equals(MetadataImport.EmptyImport)); + Debug.Assert(MdToken.IsNullToken(tkParamDef) == scope.Equals((MetadataImport)default)); Debug.Assert(MdToken.IsNullToken(tkParamDef) || MdToken.IsTokenOfType(tkParamDef, MetadataTokenType.ParamDef)); PositionImpl = position; @@ -201,7 +206,7 @@ internal RuntimeParameterInfo(MethodInfo owner, string? name, Type parameterType PositionImpl = position; AttrsImpl = ParameterAttributes.None; m_tkParamDef = (int)MetadataTokenType.ParamDef; - m_scope = MetadataImport.EmptyImport; + m_scope = default; } #endregion @@ -239,6 +244,7 @@ public override string? Name if (!MdToken.IsNullToken(m_tkParamDef)) { string name = m_scope.GetName(m_tkParamDef).ToString(); + GC.KeepAlive(this); NameImpl = name; } @@ -339,6 +345,7 @@ private bool TryGetDefaultValueInternal(bool raw, out object? defaultValue) #region Look for a default value in metadata // This will return DBNull.Value if no constant value is defined on m_tkParamDef in the metadata. defaultValue = MdConstant.GetValue(m_scope, m_tkParamDef, ParameterType.TypeHandle, raw); + GC.KeepAlive(this); // If default value is not specified in metadata, look for it in custom attributes if (defaultValue == DBNull.Value) diff --git a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimePropertyInfo.cs b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimePropertyInfo.cs index 933e05d0bf7854..d49ac821e684d9 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimePropertyInfo.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimePropertyInfo.cs @@ -35,7 +35,8 @@ internal RuntimePropertyInfo( Debug.Assert(reflectedTypeCache != null); Debug.Assert(!reflectedTypeCache.IsGlobal); - MetadataImport scope = declaredType.GetRuntimeModule().MetadataImport; + RuntimeModule module = declaredType.GetRuntimeModule(); + MetadataImport scope = module.MetadataImport; m_token = tkProperty; m_reflectedTypeCache = reflectedTypeCache; @@ -47,6 +48,7 @@ internal RuntimePropertyInfo( out _, out _, out _, out m_getterMethod, out m_setterMethod, out m_otherMethod, out isPrivate, out m_bindingFlags); + GC.KeepAlive(module); } #endregion @@ -65,9 +67,9 @@ internal Signature Signature { if (m_signature == null) { - GetRuntimeModule().MetadataImport.GetPropertyProps( m_token, out _, out _, out ConstArray sig); + GC.KeepAlive(this); m_signature = new Signature(sig.Signature.ToPointer(), sig.Length, m_declaringType); } @@ -210,6 +212,7 @@ public override Type[] GetOptionalCustomModifiers() internal object GetConstantValue(bool raw) { object? defaultValue = MdConstant.GetValue(GetRuntimeModule().MetadataImport, m_token, PropertyType.TypeHandle, raw); + GC.KeepAlive(this); if (defaultValue == DBNull.Value) // Arg_EnumLitValueNotFound -> "Literal value was not found." diff --git a/src/coreclr/System.Private.CoreLib/src/System/RuntimeHandles.cs b/src/coreclr/System.Private.CoreLib/src/System/RuntimeHandles.cs index 001a9fcdfee6a8..380981993451e9 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/RuntimeHandles.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/RuntimeHandles.cs @@ -650,14 +650,6 @@ internal static bool SatisfiesConstraints(RuntimeType paramType, RuntimeType[]? } } - [MethodImpl(MethodImplOptions.InternalCall)] - private static extern IntPtr _GetMetadataImport(RuntimeType type); - - internal static MetadataImport GetMetadataImport(RuntimeType type) - { - return new MetadataImport(_GetMetadataImport(type), type); - } - [LibraryImport(RuntimeHelpers.QCall, EntryPoint = "RuntimeTypeHandle_RegisterCollectibleTypeDependency")] private static partial void RegisterCollectibleTypeDependency(QCallTypeHandle type, QCallAssembly assembly); @@ -1247,8 +1239,6 @@ internal ModuleHandle(RuntimeModule module) } #endregion - #region Internal FCalls - internal RuntimeModule GetRuntimeModule() { return m_ptr; @@ -1278,6 +1268,7 @@ public bool Equals(ModuleHandle handle) public static bool operator !=(ModuleHandle left, ModuleHandle right) => !left.Equals(right); + #region Internal FCalls [MethodImpl(MethodImplOptions.InternalCall)] internal static extern IRuntimeMethodInfo GetDynamicMethod(Reflection.Emit.DynamicMethod method, RuntimeModule module, string name, byte[] sig, Resolver resolver); @@ -1336,7 +1327,7 @@ public RuntimeTypeHandle ResolveTypeHandle(int typeToken, RuntimeTypeHandle[]? t } catch (Exception) { - if (!GetMetadataImport(module).IsValidToken(typeToken)) + if (!module.MetadataImport.IsValidToken(typeToken)) throw new ArgumentOutOfRangeException(nameof(typeToken), SR.Format(SR.Argument_InvalidToken, typeToken, new ModuleHandle(module))); throw; @@ -1389,7 +1380,7 @@ internal static RuntimeMethodHandleInternal ResolveMethodHandleInternal(RuntimeM } catch (Exception) { - if (!GetMetadataImport(module).IsValidToken(methodToken)) + if (!module.MetadataImport.IsValidToken(methodToken)) throw new ArgumentOutOfRangeException(nameof(methodToken), SR.Format(SR.Argument_InvalidToken, methodToken, new ModuleHandle(module))); throw; @@ -1442,7 +1433,7 @@ public RuntimeFieldHandle ResolveFieldHandle(int fieldToken, RuntimeTypeHandle[] } catch (Exception) { - if (!GetMetadataImport(module).IsValidToken(fieldToken)) + if (!module.MetadataImport.IsValidToken(fieldToken)) throw new ArgumentOutOfRangeException(nameof(fieldToken), SR.Format(SR.Argument_InvalidToken, fieldToken, new ModuleHandle(module))); throw; @@ -1485,14 +1476,6 @@ internal static void GetPEKind(RuntimeModule module, out PortableExecutableKinds internal static extern int GetMDStreamVersion(RuntimeModule module); public int MDStreamVersion => GetMDStreamVersion(GetRuntimeModule()); - - [MethodImpl(MethodImplOptions.InternalCall)] - private static extern IntPtr _GetMetadataImport(RuntimeModule module); - - internal static MetadataImport GetMetadataImport(RuntimeModule module) - { - return new MetadataImport(_GetMetadataImport(module), module); - } #endregion } diff --git a/src/coreclr/System.Private.CoreLib/src/System/RuntimeType.CoreCLR.cs b/src/coreclr/System.Private.CoreLib/src/System/RuntimeType.CoreCLR.cs index 56ff2e26850ccc..c6ea76fde9b85f 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/RuntimeType.CoreCLR.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/RuntimeType.CoreCLR.cs @@ -932,7 +932,8 @@ private void PopulateLiteralFields(Filter filter, RuntimeType declaringType, ref if (MdToken.IsNullToken(tkDeclaringType)) return; - MetadataImport scope = RuntimeTypeHandle.GetMetadataImport(declaringType); + RuntimeModule module = declaringType.GetRuntimeModule(); + MetadataImport scope = module.MetadataImport; scope.EnumFields(tkDeclaringType, out MetadataEnumResult tkFields); @@ -976,6 +977,7 @@ private void PopulateLiteralFields(Filter filter, RuntimeType declaringType, ref list.Add(runtimeFieldInfo); } } + GC.KeepAlive(module); } private void AddSpecialInterface( @@ -1102,7 +1104,7 @@ private RuntimeType[] PopulateNestedClasses(Filter filter) ListBuilder list = default; ModuleHandle moduleHandle = new ModuleHandle(RuntimeTypeHandle.GetModule(declaringType)); - MetadataImport scope = ModuleHandle.GetMetadataImport(moduleHandle.GetRuntimeModule()); + MetadataImport scope = moduleHandle.GetRuntimeModule().MetadataImport; scope.EnumNestedTypes(tkEnclosingType, out MetadataEnumResult tkNestedClasses); @@ -1174,7 +1176,8 @@ private void PopulateEvents( if (MdToken.IsNullToken(tkDeclaringType)) return; - MetadataImport scope = RuntimeTypeHandle.GetMetadataImport(declaringType); + RuntimeModule module = declaringType.GetRuntimeModule(); + MetadataImport scope = module.MetadataImport; scope.EnumEvents(tkDeclaringType, out MetadataEnumResult tkEvents); @@ -1220,6 +1223,7 @@ private void PopulateEvents( list.Add(eventInfo); } + GC.KeepAlive(module); } private RuntimePropertyInfo[] PopulateProperties(Filter filter) @@ -1286,7 +1290,8 @@ private void PopulateProperties( if (MdToken.IsNullToken(tkDeclaringType)) return; - MetadataImport scope = RuntimeTypeHandle.GetMetadataImport(declaringType); + RuntimeModule module = declaringType.GetRuntimeModule(); + MetadataImport scope = module.MetadataImport; scope.EnumProperties(tkDeclaringType, out MetadataEnumResult tkProperties); @@ -1304,7 +1309,7 @@ private void PopulateProperties( if (filter.RequiresStringComparison()) { - MdUtf8String name = declaringType.GetRuntimeModule().MetadataImport.GetName(tkProperty); + MdUtf8String name = scope.GetName(tkProperty); if (!filter.Match(name)) continue; @@ -1399,6 +1404,7 @@ private void PopulateProperties( list.Add(propertyInfo); } + GC.KeepAlive(module); } #endregion @@ -1571,7 +1577,9 @@ internal Type[] FunctionPointerReturnAndParameterTypes while (type.IsNested) type = type.DeclaringType!; - m_namespace = RuntimeTypeHandle.GetMetadataImport((RuntimeType)type).GetNamespace(type.MetadataToken).ToString(); + RuntimeModule module = ((RuntimeType)type).GetRuntimeModule(); + m_namespace = module.MetadataImport.GetNamespace(type.MetadataToken).ToString(); + GC.KeepAlive(module); } return m_namespace; @@ -3499,8 +3507,9 @@ public override GenericParameterAttributes GenericParameterAttributes if (!IsGenericParameter) throw new InvalidOperationException(SR.Arg_NotGenericParameter); - - RuntimeTypeHandle.GetMetadataImport(this).GetGenericParamProps(MetadataToken, out GenericParameterAttributes attributes); + RuntimeModule module = GetRuntimeModule(); + module.MetadataImport.GetGenericParamProps(MetadataToken, out GenericParameterAttributes attributes); + GC.KeepAlive(module); return attributes; } diff --git a/src/coreclr/vm/domainassembly.cpp b/src/coreclr/vm/domainassembly.cpp index 0e86d312ae88a3..ead21d61193433 100644 --- a/src/coreclr/vm/domainassembly.cpp +++ b/src/coreclr/vm/domainassembly.cpp @@ -344,14 +344,14 @@ OBJECTREF DomainAssembly::GetExposedModuleObject() { REFLECTMODULEBASEREF refClass = NULL; - // Will be TRUE only if LoaderAllocator managed object was already collected and therefore we should + // Will be true only if LoaderAllocator managed object was already collected and therefore we should // return NULL - BOOL fIsLoaderAllocatorCollected = FALSE; + bool fIsLoaderAllocatorCollected = false; GCPROTECT_BEGIN(refClass); refClass = (REFLECTMODULEBASEREF) AllocateObject(CoreLibBinder::GetClass(CLASS__MODULE)); - refClass->SetModule(m_pModule); + refClass->SetModule(GetModule()); // Attach the reference to the assembly to keep the LoaderAllocator for this collectible type // alive as long as a reference to the module is kept alive. @@ -360,7 +360,7 @@ OBJECTREF DomainAssembly::GetExposedModuleObject() OBJECTREF refAssembly = GetModule()->GetAssembly()->GetExposedObject(); if ((refAssembly == NULL) && GetModule()->GetAssembly()->IsCollectible()) { - fIsLoaderAllocatorCollected = TRUE; + fIsLoaderAllocatorCollected = true; } refClass->SetAssembly(refAssembly); } diff --git a/src/coreclr/vm/ecalllist.h b/src/coreclr/vm/ecalllist.h index 5406bc85c7a1c3..98a38b8603419c 100644 --- a/src/coreclr/vm/ecalllist.h +++ b/src/coreclr/vm/ecalllist.h @@ -137,7 +137,6 @@ FCFuncStart(gCOMTypeHandleFuncs) FCFuncElement("GetFields", RuntimeTypeHandle::GetFields) FCFuncElement("GetInterfaces", RuntimeTypeHandle::GetInterfaces) FCFuncElement("GetAttributes", RuntimeTypeHandle::GetAttributes) - FCFuncElement("_GetMetadataImport", RuntimeTypeHandle::GetMetadataImport) FCFuncElement("GetNumVirtuals", RuntimeTypeHandle::GetNumVirtuals) FCFuncElement("GetNumVirtualsAndStaticVirtuals", RuntimeTypeHandle::GetNumVirtualsAndStaticVirtuals) FCFuncElement("CanCastTo", RuntimeTypeHandle::CanCastTo) @@ -156,6 +155,7 @@ FCFuncStart(gCOMTypeHandleFuncs) FCFuncEnd() FCFuncStart(gMetaDataImport) + FCFuncElement("GetMetadataImport", MetaDataImport::GetMetadataImport) FCFuncElement("GetDefaultValue", MetaDataImport::GetDefaultValue) FCFuncElement("GetName", MetaDataImport::GetName) FCFuncElement("GetUserString", MetaDataImport::GetUserString) @@ -236,7 +236,6 @@ FCFuncEnd() FCFuncStart(gCOMModuleHandleFuncs) FCFuncElement("GetToken", ModuleHandle::GetToken) FCFuncElement("GetDynamicMethod", ModuleHandle::GetDynamicMethod) - FCFuncElement("_GetMetadataImport", ModuleHandle::GetMetadataImport) FCFuncElement("GetMDStreamVersion", ModuleHandle::GetMDStreamVersion) FCFuncEnd() diff --git a/src/coreclr/vm/managedmdimport.cpp b/src/coreclr/vm/managedmdimport.cpp index 200a330df62c67..8ab00a85f5320c 100644 --- a/src/coreclr/vm/managedmdimport.cpp +++ b/src/coreclr/vm/managedmdimport.cpp @@ -67,6 +67,16 @@ FCIMPL11(FC_BOOL_RET, MetaDataImport::GetMarshalAs, } FCIMPLEND +FCIMPL1(IMDInternalImport*, MetaDataImport::GetMetadataImport, ReflectModuleBaseObject * pModuleUNSAFE) +{ + FCALL_CONTRACT; + + REFLECTMODULEBASEREF refModule = (REFLECTMODULEBASEREF)ObjectToOBJECTREF(pModuleUNSAFE); + Module *pModule = refModule->GetModule(); + return pModule->GetMDImport(); +} +FCIMPLEND + FCIMPL6(HRESULT, MetaDataImport::GetDefaultValue, IMDInternalImport* pScope, mdToken tk, INT64* pDefaultValue, LPCWSTR* pStringValue, INT32* pLength, INT32* pCorElementType) { FCALL_CONTRACT; diff --git a/src/coreclr/vm/managedmdimport.hpp b/src/coreclr/vm/managedmdimport.hpp index 817c5fa426a4c5..4db05291d6fd0b 100644 --- a/src/coreclr/vm/managedmdimport.hpp +++ b/src/coreclr/vm/managedmdimport.hpp @@ -27,6 +27,7 @@ typedef struct class MetaDataImport { public: + static FCDECL1(IMDInternalImport*, GetMetadataImport, ReflectModuleBaseObject* pModuleUNSAFE); static FCDECL2(HRESULT, GetScopeProps, IMDInternalImport* pScope, GUID* pmvid); static FCDECL3(HRESULT, GetMemberRefProps, IMDInternalImport* pScope, mdMemberRef mr, ConstArray* ppvSigBlob); diff --git a/src/coreclr/vm/runtimehandles.cpp b/src/coreclr/vm/runtimehandles.cpp index 4598f4d1e49a4b..c660763f11577b 100644 --- a/src/coreclr/vm/runtimehandles.cpp +++ b/src/coreclr/vm/runtimehandles.cpp @@ -1488,21 +1488,6 @@ FCIMPL1(FC_BOOL_RET, RuntimeTypeHandle::ContainsGenericVariables, PTR_ReflectCla } FCIMPLEND -FCIMPL1(IMDInternalImport*, RuntimeTypeHandle::GetMetadataImport, ReflectClassBaseObject * pTypeUNSAFE) -{ - FCALL_CONTRACT; - - REFLECTCLASSBASEREF refType = (REFLECTCLASSBASEREF)ObjectToOBJECTREF(pTypeUNSAFE); - - if (refType == NULL) - FCThrowRes(kArgumentNullException, W("Arg_InvalidHandle")); - - Module *pModule = refType->GetType().GetModule(); - - return pModule->GetMDImport(); -} -FCIMPLEND - extern "C" void* QCALLTYPE RuntimeTypeHandle_AllocateTypeAssociatedMemory(QCall::TypeHandle type, uint32_t size) { QCALL_CONTRACT; @@ -2790,20 +2775,6 @@ FCIMPL1(INT32, ModuleHandle::GetToken, ReflectModuleBaseObject * pModuleUNSAFE) } FCIMPLEND -FCIMPL1(IMDInternalImport*, ModuleHandle::GetMetadataImport, ReflectModuleBaseObject * pModuleUNSAFE) -{ - FCALL_CONTRACT; - - REFLECTMODULEBASEREF refModule = (REFLECTMODULEBASEREF)ObjectToOBJECTREF(pModuleUNSAFE); - - if (refModule == NULL) - FCThrowRes(kArgumentNullException, W("Arg_InvalidHandle")); - - Module *pModule = refModule->GetModule(); - return pModule->GetMDImport(); -} -FCIMPLEND - extern "C" void QCALLTYPE ModuleHandle_ResolveType(QCall::ModuleHandle pModule, INT32 tkType, TypeHandle *typeArgs, INT32 typeArgsCount, TypeHandle *methodArgs, INT32 methodArgsCount, QCall::ObjectHandleOnStack retType) { QCALL_CONTRACT; diff --git a/src/coreclr/vm/runtimehandles.h b/src/coreclr/vm/runtimehandles.h index 6b0d995977c654..56bb2df245f9f7 100644 --- a/src/coreclr/vm/runtimehandles.h +++ b/src/coreclr/vm/runtimehandles.h @@ -163,8 +163,6 @@ class RuntimeTypeHandle { static FCDECL1(MethodDesc *, GetFirstIntroducedMethod, ReflectClassBaseObject* pType); static FCDECL1(void, GetNextIntroducedMethod, MethodDesc **ppMethod); - static FCDECL1(IMDInternalImport*, GetMetadataImport, ReflectClassBaseObject * pModuleUNSAFE); - // Helper methods not called by managed code static void ValidateTypeAbleToBeInstantiated(TypeHandle typeHandle, bool fGetUninitializedObject); @@ -316,13 +314,7 @@ class ModuleHandle { public: static FCDECL5(ReflectMethodObject*, GetDynamicMethod, ReflectMethodObject *pMethodUNSAFE, ReflectModuleBaseObject *pModuleUNSAFE, StringObject *name, U1Array *sig, Object *resolver); static FCDECL1(INT32, GetToken, ReflectModuleBaseObject *pModuleUNSAFE); - - static - FCDECL1(IMDInternalImport*, GetMetadataImport, ReflectModuleBaseObject * pModuleUNSAFE); - - static - FCDECL1(INT32, GetMDStreamVersion, ReflectModuleBaseObject * pModuleUNSAFE); - + static FCDECL1(INT32, GetMDStreamVersion, ReflectModuleBaseObject * pModuleUNSAFE); }; extern "C" void QCALLTYPE ModuleHandle_GetModuleType(QCall::ModuleHandle pModule, QCall::ObjectHandleOnStack retType); From 33092b8097464a17a021224476ff121fedc4a8fd Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Tue, 23 Apr 2024 21:29:47 -0500 Subject: [PATCH 046/161] Update dependencies from https://github.com/dotnet/emsdk build 20240422.2 (#101425) Microsoft.SourceBuild.Intermediate.emsdk , Microsoft.NET.Runtime.Emscripten.3.1.34.Python.win-x64 , Microsoft.NET.Workload.Emscripten.Current.Manifest-9.0.100.Transport From Version 9.0.0-preview.4.24215.3 -> To Version 9.0.0-preview.4.24222.2 Co-authored-by: dotnet-maestro[bot] --- eng/Version.Details.xml | 12 ++++++------ eng/Versions.props | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index d3abb581e0f162..3473e1d653c37e 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -12,9 +12,9 @@ https://github.com/dotnet/wcf 7f504aabb1988e9a093c1e74d8040bd52feb2f01 - + https://github.com/dotnet/emsdk - 19c9523f5c2dd091b49959700723af795d6ad2b4 + 9d28301f6a5f512db14f242f7403a4bfbcbcc8a4 https://github.com/dotnet/llvm-project @@ -68,14 +68,14 @@ 861f49c137941b9722a43e5993ccac7716c8528c - + https://github.com/dotnet/emsdk - 19c9523f5c2dd091b49959700723af795d6ad2b4 + 9d28301f6a5f512db14f242f7403a4bfbcbcc8a4 - + https://github.com/dotnet/emsdk - 19c9523f5c2dd091b49959700723af795d6ad2b4 + 9d28301f6a5f512db14f242f7403a4bfbcbcc8a4 diff --git a/eng/Versions.props b/eng/Versions.props index 95e1a7403b2580..5e732a3a2e1871 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -235,9 +235,9 @@ Note: when the name is updated, make sure to update dependency name in eng/pipelines/common/xplat-setup.yml like - DarcDependenciesChanged.Microsoft_NET_Workload_Emscripten_Current_Manifest-9_0_100_Transport --> - 9.0.0-preview.4.24215.3 + 9.0.0-preview.4.24222.2 $(MicrosoftNETWorkloadEmscriptenCurrentManifest90100TransportVersion) - 9.0.0-preview.4.24215.3 + 9.0.0-preview.4.24222.2 1.1.87-gba258badda 1.0.0-v3.14.0.5722 From 9aaf6027cae3fe92e5d5903adaddfd1b0dbdb1fa Mon Sep 17 00:00:00 2001 From: Austin Wise Date: Tue, 23 Apr 2024 20:51:46 -0700 Subject: [PATCH 047/161] [mono] Fix condition for disabling extra checks in verify_class_overrides (#101445) `ENABLE_CHECKED_BUILD` is defined to mean "Enable additional checks" and is enabled in checked and debug builds. Therefore this performance optimization should be enabled when `ENABLE_CHECKED_BUILD` is *not* defined. Ref: #101312 --- src/mono/mono/metadata/class-setup-vtable.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/mono/mono/metadata/class-setup-vtable.c b/src/mono/mono/metadata/class-setup-vtable.c index 62afa76dde5b74..b2f13d72dfc47c 100644 --- a/src/mono/mono/metadata/class-setup-vtable.c +++ b/src/mono/mono/metadata/class-setup-vtable.c @@ -773,9 +773,7 @@ mono_method_get_method_definition (MonoMethod *method) static gboolean verify_class_overrides (MonoClass *klass, MonoMethod **overrides, int onum) { - // on windows and arm, we define NDEBUG for release builds - // on browser and wasi, we define DEBUG for debug builds -#ifdef ENABLE_CHECKED_BUILD +#ifndef ENABLE_CHECKED_BUILD if (klass->image == mono_defaults.corlib) return TRUE; #endif From bc9fc5a774d96f95abe0ea5c90fac48b38ed2e67 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Strehovsk=C3=BD?= Date: Wed, 24 Apr 2024 17:16:43 +0900 Subject: [PATCH 048/161] Run System.Net.Http trimming tests with AOT (#101416) --- .../tests/TrimmingTests/System.Net.Http.TrimmingTests.proj | 2 ++ src/libraries/tests.proj | 1 - 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/libraries/System.Net.Http/tests/TrimmingTests/System.Net.Http.TrimmingTests.proj b/src/libraries/System.Net.Http/tests/TrimmingTests/System.Net.Http.TrimmingTests.proj index ca55774a5ac45d..ea8bfeffaa4bbb 100644 --- a/src/libraries/System.Net.Http/tests/TrimmingTests/System.Net.Http.TrimmingTests.proj +++ b/src/libraries/System.Net.Http/tests/TrimmingTests/System.Net.Http.TrimmingTests.proj @@ -5,6 +5,8 @@ browser-wasm + + true diff --git a/src/libraries/tests.proj b/src/libraries/tests.proj index 5d1b0a0c7fb4fe..6610727190fb34 100644 --- a/src/libraries/tests.proj +++ b/src/libraries/tests.proj @@ -650,7 +650,6 @@ - From 3027ff1de78eca5319f1f3239c12817a5d7c7063 Mon Sep 17 00:00:00 2001 From: Adeel Mujahid <3840695+am11@users.noreply.github.com> Date: Wed, 24 Apr 2024 14:09:12 +0300 Subject: [PATCH 049/161] Fix a compiler error on alpine-arm64 (#101206) --- src/coreclr/jit/optimizebools.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coreclr/jit/optimizebools.cpp b/src/coreclr/jit/optimizebools.cpp index 0524fc5d2022c6..f915cf7c349481 100644 --- a/src/coreclr/jit/optimizebools.cpp +++ b/src/coreclr/jit/optimizebools.cpp @@ -1248,7 +1248,7 @@ void OptBoolsDsc::optOptimizeBoolsUpdateTrees() optReturnBlock = true; } - assert(m_cmpOp != NULL && m_c1 != nullptr && m_c2 != nullptr); + assert(m_cmpOp != GT_NONE && m_c1 != nullptr && m_c2 != nullptr); GenTree* cmpOp1 = m_foldOp == GT_NONE ? m_c1 : m_comp->gtNewOperNode(m_foldOp, m_foldType, m_c1, m_c2); if (m_testInfo1.isBool && m_testInfo2.isBool) From 33e3f0c746c38e10b701932d14230830647dddc6 Mon Sep 17 00:00:00 2001 From: Andzej Korovacki Date: Wed, 24 Apr 2024 14:15:14 +0300 Subject: [PATCH 050/161] Change all Cookie localized DateTime logic with Universal alternative (#100489) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Change all localized DateTime logic with Universal alternative * tests adjusted * comment updated according to changes * Update src/libraries/System.Net.Primitives/tests/FunctionalTests/CookieTest.cs Co-authored-by: Radek Zikmund <32671551+rzikm@users.noreply.github.com> * Code review comment fix --------- Co-authored-by: Radek Zikmund <32671551+rzikm@users.noreply.github.com> Co-authored-by: Marie Píchová <11718369+ManickaP@users.noreply.github.com> --- src/libraries/Common/src/System/Net/CookieParser.cs | 2 +- .../System.Net.Primitives/src/System/Net/Cookie.cs | 8 ++++---- .../tests/FunctionalTests/CookieTest.cs | 10 ++++++---- 3 files changed, 11 insertions(+), 9 deletions(-) diff --git a/src/libraries/Common/src/System/Net/CookieParser.cs b/src/libraries/Common/src/System/Net/CookieParser.cs index bd6b262b5b4f54..9148b479a1f113 100644 --- a/src/libraries/Common/src/System/Net/CookieParser.cs +++ b/src/libraries/Common/src/System/Net/CookieParser.cs @@ -665,7 +665,7 @@ private static FieldInfo IsQuotedVersionField expiresSet = true; if (int.TryParse(CheckQuoted(_tokenizer.Value), out int parsed)) { - cookie!.Expires = DateTime.Now.AddSeconds(parsed); + cookie!.Expires = DateTime.UtcNow.AddSeconds(parsed); } else { diff --git a/src/libraries/System.Net.Primitives/src/System/Net/Cookie.cs b/src/libraries/System.Net.Primitives/src/System/Net/Cookie.cs index 8e21138d1b58f5..b25a5df1db2d1c 100644 --- a/src/libraries/System.Net.Primitives/src/System/Net/Cookie.cs +++ b/src/libraries/System.Net.Primitives/src/System/Net/Cookie.cs @@ -63,7 +63,7 @@ public sealed class Cookie private bool m_secure; // Do not rename (binary serialization) [System.Runtime.Serialization.OptionalField] private bool m_httpOnly = false; // Do not rename (binary serialization) - private DateTime m_timeStamp = DateTime.Now; // Do not rename (binary serialization) + private DateTime m_timeStamp = DateTime.UtcNow; // Do not rename (binary serialization) private string m_value = string.Empty; // Do not rename (binary serialization) private int m_version; // Do not rename (binary serialization) @@ -199,13 +199,13 @@ public bool Expired { get { - return (m_expires != DateTime.MinValue) && (m_expires.ToLocalTime() <= DateTime.Now); + return (m_expires != DateTime.MinValue) && (m_expires.ToUniversalTime() <= DateTime.UtcNow); } set { if (value) { - m_expires = DateTime.Now; + m_expires = DateTime.UtcNow; } } } @@ -801,7 +801,7 @@ internal void ToString(StringBuilder sb) } if (Expires != DateTime.MinValue) { - int seconds = (int)(Expires.ToLocalTime() - DateTime.Now).TotalSeconds; + int seconds = (int)(Expires.ToUniversalTime() - DateTime.UtcNow).TotalSeconds; if (seconds < 0) { // This means that the cookie has already expired. Set Max-Age to 0 diff --git a/src/libraries/System.Net.Primitives/tests/FunctionalTests/CookieTest.cs b/src/libraries/System.Net.Primitives/tests/FunctionalTests/CookieTest.cs index 1ba710d4f46e86..11fa3ba37026ee 100644 --- a/src/libraries/System.Net.Primitives/tests/FunctionalTests/CookieTest.cs +++ b/src/libraries/System.Net.Primitives/tests/FunctionalTests/CookieTest.cs @@ -116,10 +116,10 @@ public static void Expired_GetSet_Success() Cookie c = new Cookie(); Assert.False(c.Expired); - c.Expires = DateTime.Now.AddDays(-1); + c.Expires = DateTime.UtcNow.AddDays(-1); Assert.True(c.Expired); - c.Expires = DateTime.Now.AddDays(1); + c.Expires = DateTime.UtcNow.AddDays(1); Assert.False(c.Expired); c.Expired = true; @@ -135,7 +135,7 @@ public static void Expires_GetSet_Success() Cookie c = new Cookie(); Assert.Equal(c.Expires, DateTime.MinValue); - DateTime dt = DateTime.Now; + DateTime dt = DateTime.UtcNow; c.Expires = dt; Assert.Equal(dt, c.Expires); } @@ -226,7 +226,9 @@ public static void Secure_GetSet_Success() [Fact] public static void Timestamp_GetSet_Success() { - DateTime dt = new DateTime(DateTime.Now.Year, DateTime.Now.Month, DateTime.Now.Day, DateTime.Now.Hour, DateTime.Now.Minute, 0); //DateTime.Now changes as the test runs + //DateTime.UtcNow changes as the test runs + DateTime dt = DateTime.UtcNow; + dt = new DateTime(dt.Year, dt.Month, dt.Day, dt.Hour, dt.Minute, 0); Cookie c = new Cookie(); Assert.True(c.TimeStamp >= dt); } From e01db175827165aa9b056d3127ce2bcc40a311f9 Mon Sep 17 00:00:00 2001 From: Radek Zikmund <32671551+rzikm@users.noreply.github.com> Date: Wed, 24 Apr 2024 13:30:55 +0200 Subject: [PATCH 051/161] Disable frequently failing tests (#101439) --- .../Net/Http/HttpClientHandlerTest.Cookies.cs | 9 +++- .../System/Net/Http/HttpClientHandlerTest.cs | 49 ++++++++++--------- .../HttpClientHandlerTest.AltSvc.cs | 9 +++- .../HttpClientHandlerTest.Headers.cs | 9 +++- 4 files changed, 50 insertions(+), 26 deletions(-) diff --git a/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.Cookies.cs b/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.Cookies.cs index b2f03bfbc930e5..714cec7bae3d56 100644 --- a/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.Cookies.cs +++ b/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.Cookies.cs @@ -216,10 +216,15 @@ private string GetCookieValue(HttpRequestData request) return cookieHeaderValue; } - [Fact] + [ConditionalFact] [SkipOnPlatform(TestPlatforms.Browser, "CookieContainer is not supported on Browser")] public async Task GetAsync_SetCookieContainerAndCookieHeader_BothCookiesSent() { + if (UseVersion == HttpVersion30) + { + throw new SkipTestException("https://github.com/dotnet/runtime/issues/101377"); + } + await LoopbackServerFactory.CreateServerAsync(async (server, url) => { HttpClientHandler handler = CreateHttpClientHandler(); @@ -313,7 +318,7 @@ await LoopbackServerFactory.CreateClientAndServerAsync(async url => using (HttpClient client = CreateHttpClient(handler)) { client.DefaultRequestHeaders.ConnectionClose = true; // to avoid issues with connection pooling - await client.GetAsync(url1); + await client.GetAsync(url1); } }, async server => diff --git a/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.cs b/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.cs index 7c3d3f385d0bd9..0e6faffa6d1622 100644 --- a/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.cs +++ b/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.cs @@ -270,7 +270,7 @@ await LoopbackServer.CreateClientAndServerAsync(async proxyUri => public static IEnumerable SecureAndNonSecure_IPBasedUri_MemberData() => from address in new[] { IPAddress.Loopback, IPAddress.IPv6Loopback } from useSsl in BoolValues - // we could not create SslStream in browser, [ActiveIssue("https://github.com/dotnet/runtime/issues/37669", TestPlatforms.Browser)] + // we could not create SslStream in browser, [ActiveIssue("https://github.com/dotnet/runtime/issues/37669", TestPlatforms.Browser)] where PlatformDetection.IsNotBrowser || !useSsl select new object[] { address, useSsl }; @@ -880,8 +880,8 @@ await LoopbackServer.CreateClientAndServerAsync(async url => "\r\n" + "5\r\n" + "hello" + // missing \r\n terminator - //"5\r\n" + - //"world" + // missing \r\n terminator + //"5\r\n" + + //"world" + // missing \r\n terminator "0\r\n" + "\r\n")); } @@ -985,7 +985,7 @@ await connection.WriteStringAsync( }); } - [Theory] + [ConditionalTheory] [InlineData(true, true, true)] [InlineData(true, true, false)] [InlineData(true, false, false)] @@ -995,6 +995,11 @@ await connection.WriteStringAsync( [ActiveIssue("https://github.com/dotnet/runtime/issues/65429", typeof(PlatformDetection), nameof(PlatformDetection.IsNodeJS))] public async Task ReadAsStreamAsync_HandlerProducesWellBehavedResponseStream(bool? chunked, bool enableWasmStreaming, bool slowChunks) { + if (UseVersion == HttpVersion30) + { + throw new SkipTestException("https://github.com/dotnet/runtime/issues/91757"); + } + if (IsWinHttpHandler && UseVersion >= HttpVersion20.Value) { return; @@ -1094,7 +1099,7 @@ await LoopbackServerFactory.CreateClientAndServerAsync(async uri => if (PlatformDetection.IsBrowser) { #if !NETFRAMEWORK - if(slowChunks) + if (slowChunks) { Assert.Equal(1, await responseStream.ReadAsync(new Memory(buffer2))); Assert.Equal((byte)'h', buffer2[0]); @@ -1204,7 +1209,7 @@ await server.AcceptConnectionAsync(async connection => { case true: await connection.SendResponseAsync(HttpStatusCode.OK, headers: new HttpHeaderData[] { new HttpHeaderData("Transfer-Encoding", "chunked") }, isFinal: false); - if(PlatformDetection.IsBrowser && slowChunks) + if (PlatformDetection.IsBrowser && slowChunks) { await connection.SendResponseBodyAsync("1\r\nh\r\n", false); await tcs.Task; @@ -1219,12 +1224,12 @@ await server.AcceptConnectionAsync(async connection => break; case false: - await connection.SendResponseAsync(HttpStatusCode.OK, headers: new HttpHeaderData[] { new HttpHeaderData("Content-Length", "11")}, content: "hello world"); + await connection.SendResponseAsync(HttpStatusCode.OK, headers: new HttpHeaderData[] { new HttpHeaderData("Content-Length", "11") }, content: "hello world"); break; case null: // This inject Content-Length header with null value to hint Loopback code to not include one automatically. - await connection.SendResponseAsync(HttpStatusCode.OK, headers: new HttpHeaderData[] { new HttpHeaderData("Content-Length", null)}, isFinal: false); + await connection.SendResponseAsync(HttpStatusCode.OK, headers: new HttpHeaderData[] { new HttpHeaderData("Content-Length", null) }, isFinal: false); await connection.SendResponseBodyAsync("hello world"); break; } @@ -1459,10 +1464,10 @@ await LoopbackServerFactory.CreateServerAsync(async (server3, url3) => Task serverTask3 = server3.AcceptConnectionAsync(async connection3 => { await connection3.ReadRequestDataAsync(); - await connection3.SendResponseAsync(HttpStatusCode.OK, new HttpHeaderData[] { new HttpHeaderData("Content-Length", "20") }, isFinal : false); - await connection3.SendResponseBodyAsync("1234567890", isFinal : false); + await connection3.SendResponseAsync(HttpStatusCode.OK, new HttpHeaderData[] { new HttpHeaderData("Content-Length", "20") }, isFinal: false); + await connection3.SendResponseBodyAsync("1234567890", isFinal: false); await unblockServers.Task; - await connection3.SendResponseBodyAsync("1234567890", isFinal : true); + await connection3.SendResponseBodyAsync("1234567890", isFinal: true); }); // Make three requests @@ -1536,7 +1541,7 @@ public async Task GetAsync_UnicodeHostName_SuccessStatusCodeInResponse() } } -#region Post Methods Tests + #region Post Methods Tests [Fact] [SkipOnPlatform(TestPlatforms.Browser, "ExpectContinue not supported on Browser")] @@ -1580,13 +1585,13 @@ await server.AcceptConnectionAsync(async connection => public static IEnumerable Interim1xxStatusCode() { - yield return new object[] { (HttpStatusCode) 100 }; // 100 Continue. + yield return new object[] { (HttpStatusCode)100 }; // 100 Continue. // 101 SwitchingProtocols will be treated as a final status code. - yield return new object[] { (HttpStatusCode) 102 }; // 102 Processing. - yield return new object[] { (HttpStatusCode) 103 }; // 103 EarlyHints. - yield return new object[] { (HttpStatusCode) 150 }; - yield return new object[] { (HttpStatusCode) 180 }; - yield return new object[] { (HttpStatusCode) 199 }; + yield return new object[] { (HttpStatusCode)102 }; // 102 Processing. + yield return new object[] { (HttpStatusCode)103 }; // 103 EarlyHints. + yield return new object[] { (HttpStatusCode)150 }; + yield return new object[] { (HttpStatusCode)180 }; + yield return new object[] { (HttpStatusCode)199 }; } [Theory] @@ -1647,7 +1652,7 @@ await server.AcceptConnectionAsync(async connection => new HttpHeaderData("Content-type", "text/xml"), new HttpHeaderData("Set-Cookie", SetCookieIgnored1)}, isFinal: false); - await connection.SendResponseAsync(responseStatusCode, headers: new HttpHeaderData[] { + await connection.SendResponseAsync(responseStatusCode, headers: new HttpHeaderData[] { new HttpHeaderData("Cookie", "ignore_cookie=choco2"), new HttpHeaderData("Content-type", "text/plain"), new HttpHeaderData("Set-Cookie", SetCookieIgnored2)}, isFinal: false); @@ -1751,7 +1756,7 @@ await server.AcceptConnectionAsync(async connection => { await connection.ReadRequestDataAsync(readBody: false); // Send multiple 100-Continue responses. - for (int count = 0 ; count < 4; count++) + for (int count = 0; count < 4; count++) { await connection.SendResponseAsync(HttpStatusCode.Continue, isFinal: false); } @@ -1855,7 +1860,7 @@ await server.AcceptConnectionAsync(async connection => { await connection.ReadRequestDataAsync(readBody: false); - await connection.SendResponseAsync(HttpStatusCode.OK, headers: new HttpHeaderData[] {new HttpHeaderData("Content-Length", $"{ResponseString.Length}")}, isFinal : false); + await connection.SendResponseAsync(HttpStatusCode.OK, headers: new HttpHeaderData[] { new HttpHeaderData("Content-Length", $"{ResponseString.Length}") }, isFinal: false); byte[] body = await connection.ReadRequestBodyAsync(); Assert.Equal(RequestString, Encoding.ASCII.GetString(body)); @@ -2136,7 +2141,7 @@ await LoopbackServerFactory.CreateServerAsync(async (server, rootUrl) => } }); } -#endregion + #endregion [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowserDomSupported))] public async Task GetAsync_InvalidUrl_ExpectedExceptionThrown() diff --git a/src/libraries/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.AltSvc.cs b/src/libraries/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.AltSvc.cs index f71efde6631058..d20b0f2635dcab 100644 --- a/src/libraries/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.AltSvc.cs +++ b/src/libraries/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.AltSvc.cs @@ -8,6 +8,8 @@ using System.Net.Test.Common; using System.Net.Quic; +using Microsoft.DotNet.XUnitExtensions; + namespace System.Net.Http.Functional.Tests { public abstract class HttpClientHandler_AltSvc_Test : HttpClientHandlerTestBase @@ -71,9 +73,14 @@ public async Task AltSvc_Header_Upgrade_Success(Version fromVersion, bool overri { HttpVersion.Version20, false } }; - [Fact] + [ConditionalFact] public async Task AltSvc_ConnectionFrame_UpgradeFrom20_Success() { + if (UseVersion == HttpVersion30) + { + throw new SkipTestException("https://github.com/dotnet/runtime/issues/101376"); + } + using Http2LoopbackServer firstServer = Http2LoopbackServer.CreateServer(); using Http3LoopbackServer secondServer = CreateHttp3LoopbackServer(); using HttpClient client = CreateHttpClient(HttpVersion.Version20); diff --git a/src/libraries/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.Headers.cs b/src/libraries/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.Headers.cs index 663e3e3a4e1483..4807d9de7842cd 100644 --- a/src/libraries/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.Headers.cs +++ b/src/libraries/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.Headers.cs @@ -13,6 +13,8 @@ using Xunit; using Xunit.Abstractions; +using Microsoft.DotNet.XUnitExtensions; + namespace System.Net.Http.Functional.Tests { using Configuration = System.Net.Test.Common.Configuration; @@ -283,12 +285,17 @@ await LoopbackServerFactory.CreateClientAndServerAsync(async uri => }); } - [Theory] + [ConditionalTheory] [InlineData("Thu, 01 Dec 1994 16:00:00 GMT", true)] [InlineData("-1", false)] [InlineData("0", false)] public async Task SendAsync_Expires_Success(string value, bool isValid) { + if (UseVersion == HttpVersion30) + { + throw new SkipTestException("https://github.com/dotnet/runtime/issues/91757"); + } + await LoopbackServerFactory.CreateClientAndServerAsync(async uri => { using (HttpClient client = CreateHttpClient()) From e58be4792208e1cda48620901e6c7822262809e5 Mon Sep 17 00:00:00 2001 From: Radek Zikmund <32671551+rzikm@users.noreply.github.com> Date: Wed, 24 Apr 2024 13:33:23 +0200 Subject: [PATCH 052/161] Fix ReadAsStreamAsync_HandlerProducesWellBehavedResponseStream for Http3 (#101447) --- .../Common/tests/System/Net/Http/Http3LoopbackConnection.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/libraries/Common/tests/System/Net/Http/Http3LoopbackConnection.cs b/src/libraries/Common/tests/System/Net/Http/Http3LoopbackConnection.cs index 9d6fef5fb3a720..5635b753a5f6cf 100644 --- a/src/libraries/Common/tests/System/Net/Http/Http3LoopbackConnection.cs +++ b/src/libraries/Common/tests/System/Net/Http/Http3LoopbackConnection.cs @@ -198,7 +198,6 @@ public async Task DisposeCurrentStream() await _currentStream.DisposeAsync().ConfigureAwait(false); _openStreams.Remove((int)_currentStreamId); _currentStream = null; - _currentStreamId = -4; } public override async Task ReadRequestBodyAsync() From 0549076be34a047c712033372f29d4b0c11fffae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Fi=C5=A1era?= Date: Wed, 24 Apr 2024 14:34:11 +0200 Subject: [PATCH 053/161] [browser] More meaningful code in browser template (#101287) --- .../scenarios/BuildWasmAppsJobsList.txt | 2 +- .../Templates/WasmTemplateTests.cs | 78 +++++++++++++------ .../InterpPgoTests.cs | 50 +++--------- .../templates/templates/browser/Program.cs | 51 ++++++++++-- .../templates/browser/wwwroot/index.html | 9 ++- .../templates/browser/wwwroot/main.js | 23 +++--- .../WasmBasicTestApp/App/InterpPgoTest.cs | 21 +++++ .../WasmBasicTestApp/App/wwwroot/main.js | 23 +++++- 8 files changed, 177 insertions(+), 80 deletions(-) rename src/mono/wasm/Wasm.Build.Tests/{Templates => TestAppScenarios}/InterpPgoTests.cs (65%) create mode 100644 src/mono/wasm/testassets/WasmBasicTestApp/App/InterpPgoTest.cs diff --git a/eng/testing/scenarios/BuildWasmAppsJobsList.txt b/eng/testing/scenarios/BuildWasmAppsJobsList.txt index 6afea6cb3e2237..11bfdab2c7414e 100644 --- a/eng/testing/scenarios/BuildWasmAppsJobsList.txt +++ b/eng/testing/scenarios/BuildWasmAppsJobsList.txt @@ -3,7 +3,7 @@ Wasm.Build.NativeRebuild.Tests.NoopNativeRebuildTest Wasm.Build.NativeRebuild.Tests.OptimizationFlagChangeTests Wasm.Build.NativeRebuild.Tests.ReferenceNewAssemblyRebuildTest Wasm.Build.NativeRebuild.Tests.SimpleSourceChangeRebuildTest -Wasm.Build.Templates.Tests.InterpPgoTests +Wasm.Build.Tests.TestAppScenarios.InterpPgoTests Wasm.Build.Templates.Tests.NativeBuildTests Wasm.Build.Tests.Blazor.AppsettingsTests Wasm.Build.Tests.Blazor.BuildPublishTests diff --git a/src/mono/wasm/Wasm.Build.Tests/Templates/WasmTemplateTests.cs b/src/mono/wasm/Wasm.Build.Tests/Templates/WasmTemplateTests.cs index d3e2e506b477a4..b1927711236c8c 100644 --- a/src/mono/wasm/Wasm.Build.Tests/Templates/WasmTemplateTests.cs +++ b/src/mono/wasm/Wasm.Build.Tests/Templates/WasmTemplateTests.cs @@ -20,7 +20,25 @@ public WasmTemplateTests(ITestOutputHelper output, SharedBuildPerTestClassFixtur { } - private void UpdateProgramCS() + private string StringReplaceWithAssert(string oldContent, string oldValue, string newValue) + { + string newContent = oldContent.Replace(oldValue, newValue); + if (oldValue != newValue && oldContent == newContent) + throw new XunitException($"Replacing '{oldValue}' with '{newValue}' did not change the content '{oldContent}'"); + + return newContent; + } + + private void UpdateBrowserProgramCs() + { + var path = Path.Combine(_projectDir!, "Program.cs"); + string text = File.ReadAllText(path); + text = StringReplaceWithAssert(text, "while(true)", $"int i = 0;{Environment.NewLine}while(i++ < 10)"); + text = StringReplaceWithAssert(text, "partial class StopwatchSample", $"return 42;{Environment.NewLine}partial class StopwatchSample"); + File.WriteAllText(path, text); + } + + private void UpdateConsoleProgramCs() { string programText = """ Console.WriteLine("Hello, Console!"); @@ -30,25 +48,36 @@ private void UpdateProgramCS() """; var path = Path.Combine(_projectDir!, "Program.cs"); string text = File.ReadAllText(path); - text = text.Replace(@"Console.WriteLine(""Hello, Console!"");", programText); - text = text.Replace("return 0;", "return 42;"); + text = StringReplaceWithAssert(text, @"Console.WriteLine(""Hello, Console!"");", programText); + text = StringReplaceWithAssert(text, "return 0;", "return 42;"); File.WriteAllText(path, text); } private void UpdateBrowserMainJs(string targetFramework, string runtimeAssetsRelativePath = DefaultRuntimeAssetsRelativePath) { - base.UpdateBrowserMainJs((mainJsContent) => { - // .withExitOnUnhandledError() is available only only >net7.0 - mainJsContent = mainJsContent.Replace(".create()", + base.UpdateBrowserMainJs( + (mainJsContent) => + { + // .withExitOnUnhandledError() is available only only >net7.0 + mainJsContent = StringReplaceWithAssert( + mainJsContent, + ".create()", (targetFramework == "net8.0" || targetFramework == "net9.0") ? ".withConsoleForwarding().withElementOnExit().withExitCodeLogging().withExitOnUnhandledError().create()" - : ".withConsoleForwarding().withElementOnExit().withExitCodeLogging().create()"); + : ".withConsoleForwarding().withElementOnExit().withExitCodeLogging().create()" + ); - mainJsContent = mainJsContent.Replace("runMain()", "dotnet.run()"); - mainJsContent = mainJsContent.Replace("from './_framework/dotnet.js'", $"from '{runtimeAssetsRelativePath}dotnet.js'"); + // dotnet.run() is already used in <= net8.0 + if (targetFramework != "net8.0") + mainJsContent = StringReplaceWithAssert(mainJsContent, "runMain()", "dotnet.run()"); - return mainJsContent; - }, targetFramework, runtimeAssetsRelativePath); + mainJsContent = StringReplaceWithAssert(mainJsContent, "from './_framework/dotnet.js'", $"from '{runtimeAssetsRelativePath}dotnet.js'"); + + return mainJsContent; + }, + targetFramework, + runtimeAssetsRelativePath + ); } private void UpdateConsoleMainJs() @@ -56,8 +85,7 @@ private void UpdateConsoleMainJs() string mainJsPath = Path.Combine(_projectDir!, "main.mjs"); string mainJsContent = File.ReadAllText(mainJsPath); - mainJsContent = mainJsContent - .Replace(".create()", ".withConsoleForwarding().create()"); + mainJsContent = StringReplaceWithAssert(mainJsContent, ".create()", ".withConsoleForwarding().create()"); File.WriteAllText(mainJsPath, mainJsContent); } @@ -73,8 +101,7 @@ private void UpdateMainJsEnvironmentVariables(params (string key, string value)[ js.Append($".withEnvironmentVariable(\"{variable.key}\", \"{variable.value}\")"); } - mainJsContent = mainJsContent - .Replace(".create()", js.ToString() + ".create()"); + mainJsContent = StringReplaceWithAssert(mainJsContent, ".create()", js.ToString() + ".create()"); File.WriteAllText(mainJsPath, mainJsContent); } @@ -88,6 +115,7 @@ public void BrowserBuildThenPublish(string config) string projectFile = CreateWasmTemplateProject(id, "wasmbrowser"); string projectName = Path.GetFileNameWithoutExtension(projectFile); + UpdateBrowserProgramCs(); UpdateBrowserMainJs(DefaultTargetFramework); var buildArgs = new BuildArgs(projectName, config, false, id, null); @@ -96,10 +124,10 @@ public void BrowserBuildThenPublish(string config) atTheEnd: """ - - <_LinkedOutFile Include="$(IntermediateOutputPath)\linked\*.dll" /> - - + + <_LinkedOutFile Include="$(IntermediateOutputPath)\linked\*.dll" /> + + """ ); @@ -212,7 +240,7 @@ private void ConsoleBuildAndRun(string config, bool relinking, string extraNewAr string projectFile = CreateWasmTemplateProject(id, "wasmconsole", extraNewArgs, addFrameworkArg: addFrameworkArg); string projectName = Path.GetFileNameWithoutExtension(projectFile); - UpdateProgramCS(); + UpdateConsoleProgramCs(); UpdateConsoleMainJs(); if (relinking) AddItemsPropertiesToProject(projectFile, "true"); @@ -277,6 +305,7 @@ private async Task BrowserRunTwiceWithAndThenWithoutBuildAsync(string config, st string id = $"browser_{config}_{GetRandomId()}"; string projectFile = CreateWasmTemplateProject(id, "wasmbrowser"); + UpdateBrowserProgramCs(); UpdateBrowserMainJs(DefaultTargetFramework); if (!string.IsNullOrEmpty(extraProperties)) @@ -310,7 +339,7 @@ private Task ConsoleRunWithAndThenWithoutBuildAsync(string config, string extraP string id = $"console_{config}_{GetRandomId()}"; string projectFile = CreateWasmTemplateProject(id, "wasmconsole"); - UpdateProgramCS(); + UpdateConsoleProgramCs(); UpdateConsoleMainJs(); if (!string.IsNullOrEmpty(extraProperties)) @@ -374,7 +403,7 @@ public void ConsolePublishAndRun(string config, bool aot, bool relinking) string projectFile = CreateWasmTemplateProject(id, "wasmconsole"); string projectName = Path.GetFileNameWithoutExtension(projectFile); - UpdateProgramCS(); + UpdateConsoleProgramCs(); UpdateConsoleMainJs(); if (aot) @@ -436,6 +465,9 @@ public async Task BrowserBuildAndRun(string extraNewArgs, string targetFramework string id = $"browser_{config}_{GetRandomId()}"; CreateWasmTemplateProject(id, "wasmbrowser", extraNewArgs, addFrameworkArg: extraNewArgs.Length == 0); + if (targetFramework != "net8.0") + UpdateBrowserProgramCs(); + UpdateBrowserMainJs(targetFramework, runtimeAssetsRelativePath); new DotNetCommand(s_buildEnv, _testOutput) @@ -518,7 +550,7 @@ public void Test_WasmStripILAfterAOT(string stripILAfterAOT, bool expectILStripp string projectDirectory = Path.GetDirectoryName(projectFile)!; bool aot = true; - UpdateProgramCS(); + UpdateConsoleProgramCs(); UpdateConsoleMainJs(); string extraProperties = "true"; diff --git a/src/mono/wasm/Wasm.Build.Tests/Templates/InterpPgoTests.cs b/src/mono/wasm/Wasm.Build.Tests/TestAppScenarios/InterpPgoTests.cs similarity index 65% rename from src/mono/wasm/Wasm.Build.Tests/Templates/InterpPgoTests.cs rename to src/mono/wasm/Wasm.Build.Tests/TestAppScenarios/InterpPgoTests.cs index 4fe88ee8daca3d..24e052f96d3fb4 100644 --- a/src/mono/wasm/Wasm.Build.Tests/Templates/InterpPgoTests.cs +++ b/src/mono/wasm/Wasm.Build.Tests/TestAppScenarios/InterpPgoTests.cs @@ -13,9 +13,9 @@ #nullable enable -namespace Wasm.Build.Templates.Tests; +namespace Wasm.Build.Tests.TestAppScenarios; -public class InterpPgoTests : WasmTemplateTestBase +public class InterpPgoTests : AppTestBase { public InterpPgoTests(ITestOutputHelper output, SharedBuildPerTestClassFixture buildContext) : base(output, buildContext) @@ -32,41 +32,11 @@ public async Task FirstRunGeneratesTableAndSecondRunLoadsIt(string config) // Invoking it too many times makes the test meaningfully slower. const int iterationCount = 70; - string id = $"browser_{config}_{GetRandomId()}"; _testOutput.WriteLine("/// Creating project"); - string projectFile = CreateWasmTemplateProject(id, "wasmbrowser", extraProperties: "0"); - - _testOutput.WriteLine("/// Updating JS"); - UpdateBrowserMainJs((js) => { - // We need to capture INTERNAL so we can explicitly save the PGO table - js = js.Replace( - "const { setModuleImports, getAssemblyExports, getConfig, runMain } = await dotnet", - "const { setModuleImports, getAssemblyExports, getConfig, runMain, INTERNAL } = await dotnet" - ); - // Enable interpreter PGO + interpreter PGO logging + console output capturing - js = js.Replace( - ".create()", - ".withConsoleForwarding().withElementOnExit().withExitCodeLogging().withExitOnUnhandledError().withRuntimeOptions(['--interp-pgo-logging']).withInterpreterPgo(true).create()" - ); - js = js.Replace("runMain()", "dotnet.run()"); - // Call Greeting in a loop to exercise enough code to cause something to tier, - // then call INTERNAL.interp_pgo_save_data() to save the interp PGO table - js = js.Replace( - "const text = exports.MyClass.Greeting();", - "console.log(`WASM debug level ${getConfig().debugLevel}`);\n" + - "let text = '';\n" + - $"for (let i = 0; i < {iterationCount}; i++) {{ text = exports.MyClass.Greeting(); }};\n" + - "await INTERNAL.interp_pgo_save_data();" - ); - return js; - }, DefaultTargetFramework); + CopyTestAsset("WasmBasicTestApp", "InterpPgoTest", "App"); _testOutput.WriteLine("/// Building"); - - new DotNetCommand(s_buildEnv, _testOutput) - .WithWorkingDirectory(_projectDir!) - .Execute($"build -c {config} -bl:{Path.Combine(s_buildEnv.LogRootPath, $"{id}.binlog")}") - .EnsureSuccessful(); + BuildProject(config, extraArgs: "-p:WasmDebugLevel=0"); _testOutput.WriteLine("/// Starting server"); @@ -75,7 +45,11 @@ public async Task FirstRunGeneratesTableAndSecondRunLoadsIt(string config) using var runCommand = new RunCommand(s_buildEnv, _testOutput) .WithWorkingDirectory(_projectDir!); await using var runner = new BrowserRunner(_testOutput); - var url = await runner.StartServerAndGetUrlAsync(runCommand, $"run --no-silent -c {config} --no-build --project \"{projectFile}\" --forward-console"); + var url = await runner.StartServerAndGetUrlAsync(runCommand, $"run --no-silent -c {config} --no-build --project \"{_projectDir!}\" --forward-console"); + url = $"{url}?test=InterpPgoTest&iterationCount={iterationCount}"; + + _testOutput.WriteLine($"/// Spawning browser at URL {url}"); + IBrowser browser = await runner.SpawnBrowserAsync(url); IBrowserContext context = await browser.NewContextAsync(); @@ -83,11 +57,11 @@ public async Task FirstRunGeneratesTableAndSecondRunLoadsIt(string config) { _testOutput.WriteLine("/// First run"); var page = await runner.RunAsync(context, url); - await runner.WaitForExitMessageAsync(TimeSpan.FromSeconds(30)); + await runner.WaitForExitMessageAsync(TimeSpan.FromSeconds(6 * 30)); lock (runner.OutputLines) output = string.Join(Environment.NewLine, runner.OutputLines); - Assert.Contains("Hello, Browser!", output); + Assert.Contains("Hello, World!", output); // Verify that no PGO table was located in cache Assert.Contains("Failed to load interp_pgo table", output); // Verify that the table was saved after the app ran @@ -107,7 +81,7 @@ public async Task FirstRunGeneratesTableAndSecondRunLoadsIt(string config) lock (runner.OutputLines) output = string.Join(Environment.NewLine, runner.OutputLines); - Assert.Contains("Hello, Browser!", output); + Assert.Contains("Hello, World!", output); // Verify that table data was loaded from cache // if this breaks, it could be caused by change in config which affects the config hash and the cache storage hash key Assert.Contains(" bytes of interp_pgo data (table size == ", output); diff --git a/src/mono/wasm/templates/templates/browser/Program.cs b/src/mono/wasm/templates/templates/browser/Program.cs index ecf115b0e71284..a9726e67fd6aca 100644 --- a/src/mono/wasm/templates/templates/browser/Program.cs +++ b/src/mono/wasm/templates/templates/browser/Program.cs @@ -1,18 +1,55 @@ using System; +using System.Diagnostics; using System.Runtime.InteropServices.JavaScript; +using System.Threading.Tasks; Console.WriteLine("Hello, Browser!"); -public partial class MyClass +if (args.Length == 1 && args[0] == "start") + StopwatchSample.Start(); + +while(true) +{ + StopwatchSample.Render(); + await Task.Delay(1000); +} + +partial class StopwatchSample { + private static Stopwatch stopwatch = new(); + + public static void Start() => stopwatch.Start(); + public static void Render() => SetInnerText("#time", stopwatch.Elapsed.ToString(@"mm\:ss")); + + [JSImport("dom.setInnerText", "main.js")] + internal static partial void SetInnerText(string selector, string content); + [JSExport] - internal static string Greeting() + internal static bool Toggle() { - var text = $"Hello, World! Greetings from {GetHRef()}"; - Console.WriteLine(text); - return text; + if (stopwatch.IsRunning) + { + stopwatch.Stop(); + return false; + } + else + { + stopwatch.Start(); + return true; + } } - [JSImport("window.location.href", "main.js")] - internal static partial string GetHRef(); + [JSExport] + internal static void Reset() + { + if (stopwatch.IsRunning) + stopwatch.Restart(); + else + stopwatch.Reset(); + + Render(); + } + + [JSExport] + internal static bool IsRunning() => stopwatch.IsRunning; } diff --git a/src/mono/wasm/templates/templates/browser/wwwroot/index.html b/src/mono/wasm/templates/templates/browser/wwwroot/index.html index 417803bf38d934..287d8b5319216a 100644 --- a/src/mono/wasm/templates/templates/browser/wwwroot/index.html +++ b/src/mono/wasm/templates/templates/browser/wwwroot/index.html @@ -11,7 +11,14 @@ - +

Stopwatch

+

+ Time elapsed in .NET is loading... +

+

+ + +

diff --git a/src/mono/wasm/templates/templates/browser/wwwroot/main.js b/src/mono/wasm/templates/templates/browser/wwwroot/main.js index afcf21e4e6510d..82c86ed196b4ef 100644 --- a/src/mono/wasm/templates/templates/browser/wwwroot/main.js +++ b/src/mono/wasm/templates/templates/browser/wwwroot/main.js @@ -4,24 +4,29 @@ import { dotnet } from './_framework/dotnet.js' const { setModuleImports, getAssemblyExports, getConfig, runMain } = await dotnet - .withDiagnosticTracing(false) - .withApplicationArgumentsFromQuery() + .withApplicationArguments("start") .create(); setModuleImports('main.js', { - window: { - location: { - href: () => globalThis.window.location.href - } + dom: { + setInnerText: (selector, time) => document.querySelector(selector).innerText = time } }); const config = getConfig(); const exports = await getAssemblyExports(config.mainAssemblyName); -const text = exports.MyClass.Greeting(); -console.log(text); -document.getElementById('out').innerHTML = text; +document.getElementById('reset').addEventListener('click', e => { + exports.StopwatchSample.Reset(); + e.preventDefault(); +}); + +const pauseButton = document.getElementById('pause'); +pauseButton.addEventListener('click', e => { + const isRunning = exports.StopwatchSample.Toggle(); + pauseButton.innerText = isRunning ? 'Pause' : 'Start'; + e.preventDefault(); +}); // run the C# Main() method and keep the runtime process running and executing further API calls await runMain(); \ No newline at end of file diff --git a/src/mono/wasm/testassets/WasmBasicTestApp/App/InterpPgoTest.cs b/src/mono/wasm/testassets/WasmBasicTestApp/App/InterpPgoTest.cs new file mode 100644 index 00000000000000..6d093133b3771c --- /dev/null +++ b/src/mono/wasm/testassets/WasmBasicTestApp/App/InterpPgoTest.cs @@ -0,0 +1,21 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.IO; +using System.Text.Json; +using System.Runtime.InteropServices.JavaScript; + +public partial class InterpPgoTest +{ + [JSImport("window.location.href", "main.js")] + internal static partial string GetHRef(); + + [JSExport] + internal static string Greeting() + { + var text = $"Hello, World! Greetings from {GetHRef()}"; + Console.WriteLine(text); + return text; + } +} diff --git a/src/mono/wasm/testassets/WasmBasicTestApp/App/wwwroot/main.js b/src/mono/wasm/testassets/WasmBasicTestApp/App/wwwroot/main.js index 5aeeb024096d56..7df0706d568193 100644 --- a/src/mono/wasm/testassets/WasmBasicTestApp/App/wwwroot/main.js +++ b/src/mono/wasm/testassets/WasmBasicTestApp/App/wwwroot/main.js @@ -78,9 +78,15 @@ switch (testCase) { }, }); break; + case "InterpPgoTest": + dotnet + .withConsoleForwarding() + .withRuntimeOptions(['--interp-pgo-logging']) + .withInterpreterPgo(true); + break; } -const { getAssemblyExports, getConfig, INTERNAL } = await dotnet.create(); +const { setModuleImports, getAssemblyExports, getConfig, INTERNAL } = await dotnet.create(); const config = getConfig(); const exports = await getAssemblyExports(config.mainAssemblyName); const assemblyExtension = config.resources.assembly['System.Private.CoreLib.wasm'] !== undefined ? ".wasm" : ".dll"; @@ -116,6 +122,21 @@ try { testOutput("WasmDebugLevel: " + config.debugLevel); exit(0); break; + case "InterpPgoTest": + setModuleImports('main.js', { + window: { + location: { + href: () => globalThis.window.location.href + } + } + }); + const iterationCount = params.get("iterationCount") ?? 70; + for (let i = 0; i < iterationCount; i++) { + exports.InterpPgoTest.Greeting(); + }; + await INTERNAL.interp_pgo_save_data(); + exit(0); + break; default: console.error(`Unknown test case: ${testCase}`); exit(3); From 7e29a451396466bb4a8e5abb9ebfdd444cd2e8a1 Mon Sep 17 00:00:00 2001 From: Vlad Brezae Date: Wed, 24 Apr 2024 16:19:26 +0300 Subject: [PATCH 054/161] Disable System.Text.Json.Tests suite on interp with debug runtime (#101483) Interpreter gets very slow on debug builds and this suite can also timeout. --- .../tests/System.Text.Json.Tests/AssemblyInfo.cs | 7 +++++++ .../System.Text.Json.Tests/System.Text.Json.Tests.csproj | 1 + 2 files changed, 8 insertions(+) create mode 100644 src/libraries/System.Text.Json/tests/System.Text.Json.Tests/AssemblyInfo.cs diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/AssemblyInfo.cs b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/AssemblyInfo.cs new file mode 100644 index 00000000000000..68af8051230a6d --- /dev/null +++ b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/AssemblyInfo.cs @@ -0,0 +1,7 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using Xunit; + +[assembly: ActiveIssue("Interpreter with debug runtime can be very slow", typeof(PlatformDetection), nameof(PlatformDetection.IsMonoInterpreter), nameof(PlatformDetection.IsDebugRuntime))] diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/System.Text.Json.Tests.csproj b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/System.Text.Json.Tests.csproj index cada80f5cee613..1e3c083791c653 100644 --- a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/System.Text.Json.Tests.csproj +++ b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/System.Text.Json.Tests.csproj @@ -31,6 +31,7 @@ + From 56ee7c5950b55529c2b5618d8f9b796d1b425813 Mon Sep 17 00:00:00 2001 From: Radek Zikmund <32671551+rzikm@users.noreply.github.com> Date: Wed, 24 Apr 2024 16:13:16 +0200 Subject: [PATCH 055/161] Fix deadlock in TestUtilities.TestEventListener (#101493) --- .../tests/TestUtilities/TestEventListener.cs | 38 ++++++++++++------- 1 file changed, 24 insertions(+), 14 deletions(-) diff --git a/src/libraries/Common/tests/TestUtilities/TestEventListener.cs b/src/libraries/Common/tests/TestUtilities/TestEventListener.cs index bd7b633ba6f822..3c33bdb633e36b 100644 --- a/src/libraries/Common/tests/TestUtilities/TestEventListener.cs +++ b/src/libraries/Common/tests/TestUtilities/TestEventListener.cs @@ -55,34 +55,44 @@ public TestEventListener(ITestOutputHelper output, params string[] sourceNames) public TestEventListener(Action writeFunc, params string[] sourceNames) { + List eventSources = _eventSources; + lock (this) { _writeFunc = writeFunc; _sourceNames = new HashSet(sourceNames); - foreach (EventSource eventSource in _eventSources) + _eventSources = null; + } + + // eventSources were populated in the base ctor and are now owned by this thread, enable them now. + foreach (EventSource eventSource in eventSources) + { + if (_sourceNames.Contains(eventSource.Name)) { - OnEventSourceCreated(eventSource); + EnableEvents(eventSource, EventLevel.LogAlways); } - _eventSources = null; } } protected override void OnEventSourceCreated(EventSource eventSource) { - lock (this) + // We're likely called from base ctor, if so, just save the event source for later initialization. + if (_sourceNames is null) { - // We're called from base ctor, just save the event source for later initialization. - if (_sourceNames is null) + lock (this) { - _eventSources.Add(eventSource); - return; + if (_sourceNames is null) + { + _eventSources.Add(eventSource); + return; + } } + } - // Second pass called from our ctor, allow logging for specified source names. - if (_sourceNames.Contains(eventSource.Name)) - { - EnableEvents(eventSource, EventLevel.LogAlways); - } + // Second pass called after our ctor, allow logging for specified source names. + if (_sourceNames.Contains(eventSource.Name)) + { + EnableEvents(eventSource, EventLevel.LogAlways); } } @@ -102,7 +112,7 @@ protected override void OnEventWritten(EventWrittenEventArgs eventData) } try { - _writeFunc(sb.ToString()); + _writeFunc?.Invoke(sb.ToString()); } catch { } } From 36e01f7193be4718624c89323e29db7f931d9f41 Mon Sep 17 00:00:00 2001 From: Radek Zikmund <32671551+rzikm@users.noreply.github.com> Date: Wed, 24 Apr 2024 17:03:11 +0200 Subject: [PATCH 056/161] Add more logging to HTTP3 and QUIC code (#101449) * Add more logging to QuicConnection and QuicStream * Fix ptr format * wip * Add more http3 logging * fixup! Add more http3 logging * Code review feedback --- .../SocketsHttpHandler/Http3Connection.cs | 13 +++++++++ .../Net/Quic/Internal/MsQuicExtensions.cs | 27 ++++++++++++++++-- .../src/System/Net/Quic/QuicConnection.cs | 28 +++++++++++++++++++ .../src/System/Net/Quic/QuicListener.cs | 11 ++++++++ .../src/System/Net/Quic/QuicStream.cs | 11 ++++++++ 5 files changed, 87 insertions(+), 3 deletions(-) diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Http3Connection.cs b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Http3Connection.cs index a4e8efeca6412e..75b9d9b1f8a964 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Http3Connection.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Http3Connection.cs @@ -300,6 +300,11 @@ internal Exception Abort(Exception abortException) private void OnServerGoAway(long firstRejectedStreamId) { + if (NetEventSource.Log.IsEnabled()) + { + Trace($"GOAWAY received. First rejected stream ID = {firstRejectedStreamId}"); + } + // Stop sending requests to this connection. _pool.InvalidateHttp3Connection(this); @@ -649,6 +654,10 @@ private async Task ProcessServerControlStreamAsync(QuicStream stream, ArrayBuffe case Http3FrameType.ReservedHttp2Ping: case Http3FrameType.ReservedHttp2WindowUpdate: case Http3FrameType.ReservedHttp2Continuation: + if (NetEventSource.Log.IsEnabled()) + { + Trace($"Received reserved frame: {frameType}"); + } throw HttpProtocolException.CreateHttp3ConnectionException(Http3ErrorCode.UnexpectedFrame); case Http3FrameType.PushPromise: case Http3FrameType.CancelPush: @@ -663,6 +672,10 @@ private async Task ProcessServerControlStreamAsync(QuicStream stream, ArrayBuffe } if (!shuttingDown) { + if (NetEventSource.Log.IsEnabled()) + { + Trace($"Control stream closed by the server."); + } throw HttpProtocolException.CreateHttp3ConnectionException(Http3ErrorCode.ClosedCriticalStream); } return; diff --git a/src/libraries/System.Net.Quic/src/System/Net/Quic/Internal/MsQuicExtensions.cs b/src/libraries/System.Net.Quic/src/System/Net/Quic/Internal/MsQuicExtensions.cs index 5c079f65287415..cfc5a09a37171c 100644 --- a/src/libraries/System.Net.Quic/src/System/Net/Quic/Internal/MsQuicExtensions.cs +++ b/src/libraries/System.Net.Quic/src/System/Net/Quic/Internal/MsQuicExtensions.cs @@ -1,6 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System; using System.Net.Quic; namespace Microsoft.Quic; @@ -17,7 +18,7 @@ public override string ToString() => Type switch { QUIC_LISTENER_EVENT_TYPE.NEW_CONNECTION - => $"{{ {nameof(NEW_CONNECTION.Info)} = {{ {nameof(QUIC_NEW_CONNECTION_INFO.QuicVersion)} = {NEW_CONNECTION.Info->QuicVersion}, {nameof(QUIC_NEW_CONNECTION_INFO.LocalAddress)} = {MsQuicHelpers.QuicAddrToIPEndPoint(NEW_CONNECTION.Info->LocalAddress)}, {nameof(QUIC_NEW_CONNECTION_INFO.RemoteAddress)} = {MsQuicHelpers.QuicAddrToIPEndPoint(NEW_CONNECTION.Info->RemoteAddress)} }} }}", + => $"{{ {nameof(NEW_CONNECTION.Info)} = {{ {nameof(QUIC_NEW_CONNECTION_INFO.QuicVersion)} = {NEW_CONNECTION.Info->QuicVersion}, {nameof(QUIC_NEW_CONNECTION_INFO.LocalAddress)} = {MsQuicHelpers.QuicAddrToIPEndPoint(NEW_CONNECTION.Info->LocalAddress)}, {nameof(QUIC_NEW_CONNECTION_INFO.RemoteAddress)} = {MsQuicHelpers.QuicAddrToIPEndPoint(NEW_CONNECTION.Info->RemoteAddress)} }}, {nameof(NEW_CONNECTION.Connection)} = 0x{(IntPtr)NEW_CONNECTION.Connection:X11} }}", _ => string.Empty }; } @@ -40,9 +41,29 @@ public override string ToString() QUIC_CONNECTION_EVENT_TYPE.PEER_ADDRESS_CHANGED => $"{{ {nameof(PEER_ADDRESS_CHANGED.Address)} = {MsQuicHelpers.QuicAddrToIPEndPoint(PEER_ADDRESS_CHANGED.Address)} }}", QUIC_CONNECTION_EVENT_TYPE.PEER_STREAM_STARTED - => $"{{ {nameof(PEER_STREAM_STARTED.Flags)} = {PEER_STREAM_STARTED.Flags} }}", + => $"{{ {nameof(PEER_STREAM_STARTED.Stream)} = 0x{(IntPtr)PEER_STREAM_STARTED.Stream:X11} {nameof(PEER_STREAM_STARTED.Flags)} = {PEER_STREAM_STARTED.Flags} }}", + QUIC_CONNECTION_EVENT_TYPE.STREAMS_AVAILABLE + => $"{{ {nameof(STREAMS_AVAILABLE.BidirectionalCount)} = {STREAMS_AVAILABLE.BidirectionalCount}, {nameof(STREAMS_AVAILABLE.UnidirectionalCount)} = {STREAMS_AVAILABLE.UnidirectionalCount} }}", + QUIC_CONNECTION_EVENT_TYPE.PEER_NEEDS_STREAMS + => $"{{ {nameof(PEER_NEEDS_STREAMS.Bidirectional)} = {PEER_NEEDS_STREAMS.Bidirectional} }}", + QUIC_CONNECTION_EVENT_TYPE.IDEAL_PROCESSOR_CHANGED + => $"{{ {nameof(IDEAL_PROCESSOR_CHANGED.IdealProcessor)} = {IDEAL_PROCESSOR_CHANGED.IdealProcessor}, {nameof(IDEAL_PROCESSOR_CHANGED.PartitionIndex)} = {IDEAL_PROCESSOR_CHANGED.PartitionIndex} }}", + QUIC_CONNECTION_EVENT_TYPE.DATAGRAM_STATE_CHANGED + => $"{{ {nameof(DATAGRAM_STATE_CHANGED.SendEnabled)} = {DATAGRAM_STATE_CHANGED.SendEnabled}, {nameof(DATAGRAM_STATE_CHANGED.MaxSendLength)} = {DATAGRAM_STATE_CHANGED.MaxSendLength} }}", + QUIC_CONNECTION_EVENT_TYPE.DATAGRAM_RECEIVED + => $"{{ {nameof(DATAGRAM_RECEIVED.Flags)} = {DATAGRAM_RECEIVED.Flags} }}", + QUIC_CONNECTION_EVENT_TYPE.DATAGRAM_SEND_STATE_CHANGED + => $"{{ {nameof(DATAGRAM_SEND_STATE_CHANGED.ClientContext)} = 0x{(IntPtr)DATAGRAM_SEND_STATE_CHANGED.ClientContext:X11}, {nameof(DATAGRAM_SEND_STATE_CHANGED.State)} = {DATAGRAM_SEND_STATE_CHANGED.State} }}", + QUIC_CONNECTION_EVENT_TYPE.RESUMED + => $"{{ {nameof(RESUMED.ResumptionStateLength)} = {RESUMED.ResumptionStateLength} }}", + QUIC_CONNECTION_EVENT_TYPE.RESUMPTION_TICKET_RECEIVED + => $"{{ {nameof(RESUMPTION_TICKET_RECEIVED.ResumptionTicketLength)} = {RESUMPTION_TICKET_RECEIVED.ResumptionTicketLength} }}", QUIC_CONNECTION_EVENT_TYPE.PEER_CERTIFICATE_RECEIVED - => $"{{ {nameof(PEER_CERTIFICATE_RECEIVED.DeferredStatus)} = {PEER_CERTIFICATE_RECEIVED.DeferredStatus}, {nameof(PEER_CERTIFICATE_RECEIVED.DeferredErrorFlags)} = {PEER_CERTIFICATE_RECEIVED.DeferredErrorFlags} }}", + => $"{{ {nameof(PEER_CERTIFICATE_RECEIVED.DeferredStatus)} = {PEER_CERTIFICATE_RECEIVED.DeferredStatus}, {nameof(PEER_CERTIFICATE_RECEIVED.DeferredErrorFlags)} = {PEER_CERTIFICATE_RECEIVED.DeferredErrorFlags}, {nameof(PEER_CERTIFICATE_RECEIVED.Certificate)} = 0x{(IntPtr)PEER_CERTIFICATE_RECEIVED.Certificate:X11} }}", + QUIC_CONNECTION_EVENT_TYPE.RELIABLE_RESET_NEGOTIATED + => $"{{ {nameof(RELIABLE_RESET_NEGOTIATED.IsNegotiated)} = {RELIABLE_RESET_NEGOTIATED.IsNegotiated} }}", + QUIC_CONNECTION_EVENT_TYPE.ONE_WAY_DELAY_NEGOTIATED + => $"{{ {nameof(ONE_WAY_DELAY_NEGOTIATED.SendNegotiated)} = {ONE_WAY_DELAY_NEGOTIATED.SendNegotiated}, {nameof(ONE_WAY_DELAY_NEGOTIATED.ReceiveNegotiated)} = {ONE_WAY_DELAY_NEGOTIATED.ReceiveNegotiated} }}", _ => string.Empty }; } diff --git a/src/libraries/System.Net.Quic/src/System/Net/Quic/QuicConnection.cs b/src/libraries/System.Net.Quic/src/System/Net/Quic/QuicConnection.cs index 315352d2797bb4..e568eeb6f97b7a 100644 --- a/src/libraries/System.Net.Quic/src/System/Net/Quic/QuicConnection.cs +++ b/src/libraries/System.Net.Quic/src/System/Net/Quic/QuicConnection.cs @@ -252,6 +252,11 @@ private unsafe QuicConnection() throw; } + if (NetEventSource.Log.IsEnabled()) + { + NetEventSource.Info(this, $"{this} New outbound connection."); + } + _tlsSecret = MsQuicTlsSecret.Create(_handle); } @@ -411,6 +416,12 @@ public async ValueTask OpenOutboundStreamAsync(QuicStreamType type, try { stream = new QuicStream(_handle, type, _defaultStreamErrorCode); + + if (NetEventSource.Log.IsEnabled()) + { + NetEventSource.Info(this, $"{this} New outbound {type} stream {stream}."); + } + await stream.StartAsync(cancellationToken).ConfigureAwait(false); } catch @@ -482,6 +493,11 @@ public ValueTask CloseAsync(long errorCode, CancellationToken cancellationToken if (_shutdownTcs.TryGetValueTask(out ValueTask valueTask, this, cancellationToken)) { + if (NetEventSource.Log.IsEnabled()) + { + NetEventSource.Info(this, $"{this} Closing connection, Error code = {errorCode}"); + } + unsafe { MsQuicApi.Api.ConnectionShutdown( @@ -551,6 +567,13 @@ private unsafe int HandleEventPeerAddressChanged(ref PEER_ADDRESS_CHANGED_DATA d private unsafe int HandleEventPeerStreamStarted(ref PEER_STREAM_STARTED_DATA data) { QuicStream stream = new QuicStream(_handle, data.Stream, data.Flags, _defaultStreamErrorCode); + + if (NetEventSource.Log.IsEnabled()) + { + QuicStreamType type = data.Flags.HasFlag(QUIC_STREAM_OPEN_FLAGS.UNIDIRECTIONAL) ? QuicStreamType.Unidirectional : QuicStreamType.Bidirectional; + NetEventSource.Info(this, $"{this} New inbound {type} stream {stream}, Id = {stream.Id}."); + } + if (!_acceptQueue.Writer.TryWrite(stream)) { if (NetEventSource.Log.IsEnabled()) @@ -648,6 +671,11 @@ public async ValueTask DisposeAsync() return; } + if (NetEventSource.Log.IsEnabled()) + { + NetEventSource.Info(this, $"{this} Disposing."); + } + // Check if the connection has been shut down and if not, shut it down. if (_shutdownTcs.TryGetValueTask(out ValueTask valueTask, this)) { diff --git a/src/libraries/System.Net.Quic/src/System/Net/Quic/QuicListener.cs b/src/libraries/System.Net.Quic/src/System/Net/Quic/QuicListener.cs index 88ea309054a7db..249f7571519131 100644 --- a/src/libraries/System.Net.Quic/src/System/Net/Quic/QuicListener.cs +++ b/src/libraries/System.Net.Quic/src/System/Net/Quic/QuicListener.cs @@ -335,6 +335,12 @@ private unsafe int HandleEventNewConnection(ref NEW_CONNECTION_DATA data) } QuicConnection connection = new QuicConnection(data.Connection, data.Info); + + if (NetEventSource.Log.IsEnabled()) + { + NetEventSource.Info(this, $"{this} New inbound connection {connection}."); + } + SslClientHelloInfo clientHello = new SslClientHelloInfo(data.Info->ServerNameLength > 0 ? Marshal.PtrToStringUTF8((IntPtr)data.Info->ServerName, data.Info->ServerNameLength) : "", SslProtocols.Tls13); // Kicks off the rest of the handshake in the background, the process itself will enqueue the result in the accept queue. @@ -404,6 +410,11 @@ public async ValueTask DisposeAsync() return; } + if (NetEventSource.Log.IsEnabled()) + { + NetEventSource.Info(this, $"{this} Disposing."); + } + // Check if the listener has been shut down and if not, shut it down. if (_shutdownTcs.TryInitialize(out ValueTask valueTask, this)) { diff --git a/src/libraries/System.Net.Quic/src/System/Net/Quic/QuicStream.cs b/src/libraries/System.Net.Quic/src/System/Net/Quic/QuicStream.cs index 06515f3310bf7f..6af0f5c5c099f3 100644 --- a/src/libraries/System.Net.Quic/src/System/Net/Quic/QuicStream.cs +++ b/src/libraries/System.Net.Quic/src/System/Net/Quic/QuicStream.cs @@ -225,6 +225,7 @@ internal unsafe QuicStream(MsQuicContextSafeHandle connectionHandle, QUIC_HANDLE } _id = (long)GetMsQuicParameter(_handle, QUIC_PARAM_STREAM_ID); _type = flags.HasFlag(QUIC_STREAM_OPEN_FLAGS.UNIDIRECTIONAL) ? QuicStreamType.Unidirectional : QuicStreamType.Bidirectional; + _startedTcs.TrySetResult(); } @@ -325,6 +326,11 @@ public override async ValueTask ReadAsync(Memory buffer, Cancellation } } + if (NetEventSource.Log.IsEnabled()) + { + NetEventSource.Info(this, $"{this} Stream read '{totalCopied}' bytes."); + } + return totalCopied; } @@ -690,6 +696,11 @@ public override async ValueTask DisposeAsync() return; } + if (NetEventSource.Log.IsEnabled()) + { + NetEventSource.Info(this, $"{this} Disposing."); + } + // If the stream wasn't started successfully, gracelessly abort it. if (!_startedTcs.IsCompletedSuccessfully) { From 5fe1a569099272cbe3cec4972c52e5531223b58e Mon Sep 17 00:00:00 2001 From: SwapnilGaikwad Date: Wed, 24 Apr 2024 16:07:10 +0100 Subject: [PATCH 057/161] Fix checks to accommodate register wraparounds in multi-reg ops (#101430) Fixes issue #101070 --- src/coreclr/jit/codegen.h | 10 ++++++++++ src/coreclr/jit/hwintrinsiccodegenarm64.cpp | 8 ++++---- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/src/coreclr/jit/codegen.h b/src/coreclr/jit/codegen.h index f5e0dc857a7d4c..441db5f6b50d47 100644 --- a/src/coreclr/jit/codegen.h +++ b/src/coreclr/jit/codegen.h @@ -101,6 +101,16 @@ class CodeGen final : public CodeGenInterface } } +#if defined(TARGET_ARM64) + regNumber getNextSIMDRegWithWraparound(regNumber reg) + { + regNumber nextReg = REG_NEXT(reg); + + // Wraparound if necessary, REG_V0 comes next after REG_V31. + return (nextReg > REG_V31) ? REG_V0 : nextReg; + } +#endif // defined(TARGET_ARM64) + static GenTreeIndir indirForm(var_types type, GenTree* base); static GenTreeStoreInd storeIndirForm(var_types type, GenTree* base, GenTree* data); diff --git a/src/coreclr/jit/hwintrinsiccodegenarm64.cpp b/src/coreclr/jit/hwintrinsiccodegenarm64.cpp index 9a3a98e087a274..01914951576bfa 100644 --- a/src/coreclr/jit/hwintrinsiccodegenarm64.cpp +++ b/src/coreclr/jit/hwintrinsiccodegenarm64.cpp @@ -833,7 +833,7 @@ void CodeGen::genHWIntrinsic(GenTreeHWIntrinsic* node) GenTree* argNode = use.GetNode(); assert(argReg == argNode->GetRegNum()); - argReg = REG_NEXT(argReg); + argReg = getNextSIMDRegWithWraparound(argReg); } assert((ins == INS_st2 && regCount == 2) || (ins == INS_st3 && regCount == 3) || (ins == INS_st4 && regCount == 4)); @@ -883,7 +883,7 @@ void CodeGen::genHWIntrinsic(GenTreeHWIntrinsic* node) GenTree* argNode = use.GetNode(); assert(argReg == argNode->GetRegNum()); - argReg = REG_NEXT(argReg); + argReg = getNextSIMDRegWithWraparound(argReg); } assert((ins == INS_st1_2regs && regCount == 2) || (ins == INS_st2 && regCount == 2) || (ins == INS_st1_3regs && regCount == 3) || (ins == INS_st3 && regCount == 3) || @@ -1186,7 +1186,7 @@ void CodeGen::genHWIntrinsic(GenTreeHWIntrinsic* node) GenTree* argNode = use.GetNode(); assert(argReg == argNode->GetRegNum()); - argReg = REG_NEXT(argReg); + argReg = getNextSIMDRegWithWraparound(argReg); #endif } } @@ -1241,7 +1241,7 @@ void CodeGen::genHWIntrinsic(GenTreeHWIntrinsic* node) assert(argReg == argNode->GetRegNum()); // and they should not interfere with targetReg assert(targetReg != argReg); - argReg = REG_NEXT(argReg); + argReg = getNextSIMDRegWithWraparound(argReg); #endif } } From b5ee98696f9e858a953289131c8d9e66bbde50d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Jare=C5=A1?= Date: Wed, 24 Apr 2024 19:26:42 +0200 Subject: [PATCH 058/161] Disable terminal logger experience for dotnet test in manual tests. (#100333) --- src/libraries/System.Console/tests/ManualTests/Readme.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/libraries/System.Console/tests/ManualTests/Readme.md b/src/libraries/System.Console/tests/ManualTests/Readme.md index 6c56bce87840a7..4cd91a362a94d7 100644 --- a/src/libraries/System.Console/tests/ManualTests/Readme.md +++ b/src/libraries/System.Console/tests/ManualTests/Readme.md @@ -6,7 +6,8 @@ To run the suite, follow these steps: 1. Build the CLR and libraries. 2. Using a terminal, navigate to the current folder. 3. Enable manual testing by defining the `MANUAL_TESTS` environment variable (e.g. on bash `export MANUAL_TESTS=true`). -4. Run `dotnet test` and follow the instructions in the command prompt. +4. Disable terminal logger output for dotnet test by setting `MSBUILDENSURESTDOUTFORTASKPROCESSES=1` environment variable. (e.g. on bash `export MSBUILDENSURESTDOUTFORTASKPROCESSES=1`). +5. Run `dotnet test` and follow the instructions in the command prompt. ## Instructions for Windows testers From 1a93a9d0fc121a98f63345754cabe0f4427e37d2 Mon Sep 17 00:00:00 2001 From: Adam Sitnik Date: Wed, 24 Apr 2024 19:58:46 +0200 Subject: [PATCH 059/161] TypeName parsing API (#100094) Co-authored-by: Jan Kotas --- .../Reflection/TypeNameParser.CoreCLR.cs | 91 ++- .../src/System/Type.CoreCLR.cs | 1 - .../System/Reflection/RuntimeAssemblyName.cs | 23 +- .../Reflection/TypeNameParser.NativeAot.cs | 69 +- .../CustomAttributeTypeNameParser.cs | 29 +- .../ILVerification/ILVerification.projitems | 35 +- .../Dataflow/TypeNameParser.Dataflow.cs | 46 +- .../ILCompiler.Compiler.csproj | 4 +- .../ILCompiler.TypeSystem.csproj | 29 +- .../Reflection/AssemblyNameFormatter.cs | 12 +- .../System/Reflection/AssemblyNameParser.cs | 506 ++++++++++++ .../Reflection/Metadata/AssemblyNameInfo.cs | 219 +++++ .../System/Reflection/Metadata/TypeName.cs | 398 ++++++++++ .../Reflection/Metadata/TypeNameParser.cs | 260 ++++++ .../Metadata/TypeNameParserHelpers.cs | 383 +++++++++ .../Metadata/TypeNameParserOptions.cs | 41 + .../Reflection/TypeNameParser.Helpers.cs | 192 +++++ .../src/System/Reflection/TypeNameParser.cs | 701 ---------------- ...alueStringBuilder.AppendSpanFormattable.cs | 2 + .../System.Private.CoreLib.Shared.projitems | 27 +- .../UnconditionalSuppressMessageAttribute.cs | 2 + .../System/Reflection/AssemblyNameParser.cs | 438 ---------- .../ref/System.Reflection.Metadata.cs | 43 + .../src/Resources/Strings.resx | 21 + .../src/System.Reflection.Metadata.csproj | 11 + .../tests/Metadata/AssemblyNameInfoTests.cs | 105 +++ .../Metadata/TypeNameParserHelpersTests.cs | 173 ++++ .../tests/Metadata/TypeNameParserSamples.cs | 255 ++++++ .../tests/Metadata/TypeNameTests.cs | 748 ++++++++++++++++++ .../System.Reflection.Metadata.Tests.csproj | 6 + .../System/Reflection/TypeNameParser.Mono.cs | 29 +- 31 files changed, 3599 insertions(+), 1300 deletions(-) rename src/libraries/{System.Private.CoreLib => Common}/src/System/Reflection/AssemblyNameFormatter.cs (92%) create mode 100644 src/libraries/Common/src/System/Reflection/AssemblyNameParser.cs create mode 100644 src/libraries/Common/src/System/Reflection/Metadata/AssemblyNameInfo.cs create mode 100644 src/libraries/Common/src/System/Reflection/Metadata/TypeName.cs create mode 100644 src/libraries/Common/src/System/Reflection/Metadata/TypeNameParser.cs create mode 100644 src/libraries/Common/src/System/Reflection/Metadata/TypeNameParserHelpers.cs create mode 100644 src/libraries/Common/src/System/Reflection/Metadata/TypeNameParserOptions.cs create mode 100644 src/libraries/Common/src/System/Reflection/TypeNameParser.Helpers.cs delete mode 100644 src/libraries/Common/src/System/Reflection/TypeNameParser.cs delete mode 100644 src/libraries/System.Private.CoreLib/src/System/Reflection/AssemblyNameParser.cs create mode 100644 src/libraries/System.Reflection.Metadata/tests/Metadata/AssemblyNameInfoTests.cs create mode 100644 src/libraries/System.Reflection.Metadata/tests/Metadata/TypeNameParserHelpersTests.cs create mode 100644 src/libraries/System.Reflection.Metadata/tests/Metadata/TypeNameParserSamples.cs create mode 100644 src/libraries/System.Reflection.Metadata/tests/Metadata/TypeNameTests.cs diff --git a/src/coreclr/System.Private.CoreLib/src/System/Reflection/TypeNameParser.CoreCLR.cs b/src/coreclr/System.Private.CoreLib/src/System/Reflection/TypeNameParser.CoreCLR.cs index 2af4bb792d4588..35fa0b5718e387 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Reflection/TypeNameParser.CoreCLR.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/TypeNameParser.CoreCLR.cs @@ -4,11 +4,9 @@ using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.IO; -using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Loader; -using System.Text; using System.Threading; namespace System.Reflection @@ -57,7 +55,13 @@ internal partial struct TypeNameParser return null; } - return new TypeNameParser(typeName) + Metadata.TypeName? parsed = Metadata.TypeNameParser.Parse(typeName, throwOnError: throwOnError); + if (parsed is null) + { + return null; + } + + return new TypeNameParser() { _assemblyResolver = assemblyResolver, _typeResolver = typeResolver, @@ -65,7 +69,7 @@ internal partial struct TypeNameParser _ignoreCase = ignoreCase, _extensibleParser = extensibleParser, _requestingAssembly = requestingAssembly - }.Parse(); + }.Resolve(parsed); } [RequiresUnreferencedCode("The type might be removed")] @@ -75,13 +79,24 @@ internal partial struct TypeNameParser bool ignoreCase, Assembly topLevelAssembly) { - return new TypeNameParser(typeName) + Metadata.TypeName? parsed = Metadata.TypeNameParser.Parse(typeName, throwOnError); + + if (parsed is null) + { + return null; + } + else if (topLevelAssembly is not null && parsed.AssemblyName is not null) + { + return throwOnError ? throw new ArgumentException(SR.Argument_AssemblyGetTypeCannotSpecifyAssembly) : null; + } + + return new TypeNameParser() { _throwOnError = throwOnError, _ignoreCase = ignoreCase, _topLevelAssembly = topLevelAssembly, _requestingAssembly = topLevelAssembly - }.Parse(); + }.Resolve(parsed); } // Resolve type name referenced by a custom attribute metadata. @@ -95,12 +110,13 @@ internal static RuntimeType GetTypeReferencedByCustomAttribute(string typeName, RuntimeAssembly requestingAssembly = scope.GetRuntimeAssembly(); - RuntimeType? type = (RuntimeType?)new TypeNameParser(typeName) + Metadata.TypeName parsed = Metadata.TypeName.Parse(typeName); + RuntimeType? type = (RuntimeType?)new TypeNameParser() { _throwOnError = true, _suppressContextualReflectionContext = true, _requestingAssembly = requestingAssembly - }.Parse(); + }.Resolve(parsed); Debug.Assert(type != null); @@ -124,13 +140,19 @@ internal static RuntimeType GetTypeReferencedByCustomAttribute(string typeName, return null; } - RuntimeType? type = (RuntimeType?)new TypeNameParser(typeName) + Metadata.TypeName? parsed = Metadata.TypeNameParser.Parse(typeName, throwOnError); + if (parsed is null) + { + return null; + } + + RuntimeType? type = (RuntimeType?)new TypeNameParser() { _requestingAssembly = requestingAssembly, _throwOnError = throwOnError, _suppressContextualReflectionContext = true, _requireAssemblyQualifiedName = requireAssemblyQualifiedName, - }.Parse(); + }.Resolve(parsed); if (type != null) RuntimeTypeHandle.RegisterCollectibleTypeDependency(type, requestingAssembly); @@ -138,23 +160,12 @@ internal static RuntimeType GetTypeReferencedByCustomAttribute(string typeName, return type; } - private bool CheckTopLevelAssemblyQualifiedName() - { - if (_topLevelAssembly is not null) - { - if (_throwOnError) - throw new ArgumentException(SR.Argument_AssemblyGetTypeCannotSpecifyAssembly); - return false; - } - return true; - } - - private Assembly? ResolveAssembly(string assemblyName) + private Assembly? ResolveAssembly(AssemblyName assemblyName) { Assembly? assembly; if (_assemblyResolver is not null) { - assembly = _assemblyResolver(new AssemblyName(assemblyName)); + assembly = _assemblyResolver(assemblyName); if (assembly is null && _throwOnError) { throw new FileNotFoundException(SR.Format(SR.FileNotFound_ResolveAssembly, assemblyName)); @@ -162,7 +173,7 @@ private bool CheckTopLevelAssemblyQualifiedName() } else { - assembly = RuntimeAssembly.InternalLoad(new AssemblyName(assemblyName), ref Unsafe.NullRef(), + assembly = RuntimeAssembly.InternalLoad(assemblyName, ref Unsafe.NullRef(), _suppressContextualReflectionContext ? null : AssemblyLoadContext.CurrentContextualReflectionContext, requestingAssembly: (RuntimeAssembly?)_requestingAssembly, throwOnFileNotFound: _throwOnError); } @@ -173,13 +184,14 @@ private bool CheckTopLevelAssemblyQualifiedName() Justification = "TypeNameParser.GetType is marked as RequiresUnreferencedCode.")] [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2075:UnrecognizedReflectionPattern", Justification = "TypeNameParser.GetType is marked as RequiresUnreferencedCode.")] - private Type? GetType(string typeName, ReadOnlySpan nestedTypeNames, string? assemblyNameIfAny) + private Type? GetType(string escapedTypeName, // For nested types, it's Name. For other types it's FullName + ReadOnlySpan nestedTypeNames, Metadata.TypeName parsedName) { Assembly? assembly; - if (assemblyNameIfAny is not null) + if (parsedName.AssemblyName is not null) { - assembly = ResolveAssembly(assemblyNameIfAny); + assembly = ResolveAssembly(parsedName.AssemblyName.ToAssemblyName()); if (assembly is null) return null; } @@ -193,8 +205,6 @@ private bool CheckTopLevelAssemblyQualifiedName() // Resolve the top level type. if (_typeResolver is not null) { - string escapedTypeName = EscapeTypeName(typeName); - type = _typeResolver(assembly, escapedTypeName, _ignoreCase); if (type is null) @@ -216,28 +226,29 @@ private bool CheckTopLevelAssemblyQualifiedName() { if (_throwOnError) { - throw new TypeLoadException(SR.Format(SR.TypeLoad_ResolveType, EscapeTypeName(typeName))); + throw new TypeLoadException(SR.Format(SR.TypeLoad_ResolveType, escapedTypeName)); } return null; } - return GetTypeFromDefaultAssemblies(typeName, nestedTypeNames); + return GetTypeFromDefaultAssemblies(UnescapeTypeName(escapedTypeName), nestedTypeNames, parsedName); } if (assembly is RuntimeAssembly runtimeAssembly) { + string unescapedTypeName = UnescapeTypeName(escapedTypeName); // Compat: Non-extensible parser allows ambiguous matches with ignore case lookup if (!_extensibleParser || !_ignoreCase) { - return runtimeAssembly.GetTypeCore(typeName, nestedTypeNames, throwOnError: _throwOnError, ignoreCase: _ignoreCase); + return runtimeAssembly.GetTypeCore(unescapedTypeName, nestedTypeNames, throwOnError: _throwOnError, ignoreCase: _ignoreCase); } - type = runtimeAssembly.GetTypeCore(typeName, default, throwOnError: _throwOnError, ignoreCase: _ignoreCase); + type = runtimeAssembly.GetTypeCore(unescapedTypeName, default, throwOnError: _throwOnError, ignoreCase: _ignoreCase); } else { // This is a third-party Assembly object. Emulate GetTypeCore() by calling the public GetType() // method. This is wasteful because it'll probably reparse a type string that we've already parsed // but it can't be helped. - type = assembly.GetType(EscapeTypeName(typeName), throwOnError: _throwOnError, ignoreCase: _ignoreCase); + type = assembly.GetType(escapedTypeName, throwOnError: _throwOnError, ignoreCase: _ignoreCase); } if (type is null) @@ -257,7 +268,7 @@ private bool CheckTopLevelAssemblyQualifiedName() if (_throwOnError) { throw new TypeLoadException(SR.Format(SR.TypeLoad_ResolveNestedType, - nestedTypeNames[i], (i > 0) ? nestedTypeNames[i - 1] : typeName)); + nestedTypeNames[i], (i > 0) ? nestedTypeNames[i - 1] : escapedTypeName)); } return null; } @@ -266,12 +277,12 @@ private bool CheckTopLevelAssemblyQualifiedName() return type; } - private Type? GetTypeFromDefaultAssemblies(string typeName, ReadOnlySpan nestedTypeNames) + private Type? GetTypeFromDefaultAssemblies(string typeName, ReadOnlySpan nestedTypeNames, Metadata.TypeName parsedName) { RuntimeAssembly? requestingAssembly = (RuntimeAssembly?)_requestingAssembly; if (requestingAssembly is not null) { - Type? type = ((RuntimeAssembly)requestingAssembly).GetTypeCore(typeName, nestedTypeNames, throwOnError: false, ignoreCase: _ignoreCase); + Type? type = requestingAssembly.GetTypeCore(typeName, nestedTypeNames, throwOnError: false, ignoreCase: _ignoreCase); if (type is not null) return type; } @@ -279,12 +290,12 @@ private bool CheckTopLevelAssemblyQualifiedName() RuntimeAssembly coreLib = (RuntimeAssembly)typeof(object).Assembly; if (requestingAssembly != coreLib) { - Type? type = ((RuntimeAssembly)coreLib).GetTypeCore(typeName, nestedTypeNames, throwOnError: false, ignoreCase: _ignoreCase); + Type? type = coreLib.GetTypeCore(typeName, nestedTypeNames, throwOnError: false, ignoreCase: _ignoreCase); if (type is not null) return type; } - RuntimeAssembly? resolvedAssembly = AssemblyLoadContext.OnTypeResolve(requestingAssembly, EscapeTypeName(typeName, nestedTypeNames)); + RuntimeAssembly? resolvedAssembly = AssemblyLoadContext.OnTypeResolve(requestingAssembly, parsedName.FullName); if (resolvedAssembly is not null) { Type? type = resolvedAssembly.GetTypeCore(typeName, nestedTypeNames, throwOnError: false, ignoreCase: _ignoreCase); @@ -293,7 +304,7 @@ private bool CheckTopLevelAssemblyQualifiedName() } if (_throwOnError) - throw new TypeLoadException(SR.Format(SR.TypeLoad_ResolveTypeFromAssembly, EscapeTypeName(typeName), (requestingAssembly ?? coreLib).FullName)); + throw new TypeLoadException(SR.Format(SR.TypeLoad_ResolveTypeFromAssembly, parsedName.FullName, (requestingAssembly ?? coreLib).FullName)); return null; } diff --git a/src/coreclr/System.Private.CoreLib/src/System/Type.CoreCLR.cs b/src/coreclr/System.Private.CoreLib/src/System/Type.CoreCLR.cs index 03a92b709eb1a5..81caecb09c99aa 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Type.CoreCLR.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Type.CoreCLR.cs @@ -4,7 +4,6 @@ using System.Diagnostics.CodeAnalysis; using System.Reflection; using System.Runtime.CompilerServices; -using System.Runtime.Versioning; using System.Security; using StackCrawlMark = System.Threading.StackCrawlMark; diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/RuntimeAssemblyName.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/RuntimeAssemblyName.cs index ee76c4a5e302dd..5e855eb58565d6 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/RuntimeAssemblyName.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/RuntimeAssemblyName.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Diagnostics; +using System.Reflection.Metadata; namespace System.Reflection { @@ -129,6 +130,11 @@ public AssemblyName ToAssemblyName() return assemblyName; } + internal static RuntimeAssemblyName FromAssemblyNameInfo(AssemblyNameInfo source) + { + return new(source.Name, source.Version, source.CultureName, source._flags, source.PublicKeyOrToken); + } + // // Copies a RuntimeAssemblyName into a freshly allocated AssemblyName with no data aliasing to any other object. // @@ -142,10 +148,10 @@ public void CopyToAssemblyName(AssemblyName blank) // Our "Flags" contain both the classic flags and the ProcessorArchitecture + ContentType bits. The public AssemblyName has separate properties for // these. The setters for these properties quietly mask out any bits intended for the other one, so we needn't do that ourselves.. - blank.Flags = ExtractAssemblyNameFlags(this.Flags); - blank.ContentType = ExtractAssemblyContentType(this.Flags); + blank.Flags = AssemblyNameInfo.ExtractAssemblyNameFlags(this.Flags); + blank.ContentType = AssemblyNameInfo.ExtractAssemblyContentType(this.Flags); #pragma warning disable SYSLIB0037 // AssemblyName.ProcessorArchitecture is obsolete - blank.ProcessorArchitecture = ExtractProcessorArchitecture(this.Flags); + blank.ProcessorArchitecture = AssemblyNameInfo.ExtractProcessorArchitecture(this.Flags); #pragma warning restore SYSLIB0037 if (this.PublicKeyOrToken != null) @@ -168,17 +174,8 @@ public string FullName get { byte[]? pkt = (0 != (Flags & AssemblyNameFlags.PublicKey)) ? AssemblyNameHelpers.ComputePublicKeyToken(PublicKeyOrToken) : PublicKeyOrToken; - return AssemblyNameFormatter.ComputeDisplayName(Name, Version, CultureName, pkt, ExtractAssemblyNameFlags(Flags), ExtractAssemblyContentType(Flags)); + return AssemblyNameFormatter.ComputeDisplayName(Name, Version, CultureName, pkt, AssemblyNameInfo.ExtractAssemblyNameFlags(Flags), AssemblyNameInfo.ExtractAssemblyContentType(Flags)); } } - - private static AssemblyNameFlags ExtractAssemblyNameFlags(AssemblyNameFlags combinedFlags) - => combinedFlags & unchecked((AssemblyNameFlags)0xFFFFF10F); - - private static AssemblyContentType ExtractAssemblyContentType(AssemblyNameFlags flags) - => (AssemblyContentType)((((int)flags) >> 9) & 0x7); - - private static ProcessorArchitecture ExtractProcessorArchitecture(AssemblyNameFlags flags) - => (ProcessorArchitecture)((((int)flags) >> 4) & 0x7); } } diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/TypeNameParser.NativeAot.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/TypeNameParser.NativeAot.cs index e370cb4eed0a83..2149003ddcfb4c 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/TypeNameParser.NativeAot.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/TypeNameParser.NativeAot.cs @@ -1,8 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Collections.Generic; -using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.IO; using System.Reflection.Runtime.Assemblies; @@ -53,7 +51,13 @@ internal partial struct TypeNameParser return null; } - return new TypeNameParser(typeName) + Metadata.TypeName? parsed = Metadata.TypeNameParser.Parse(typeName, throwOnError); + if (parsed is null) + { + return null; + } + + return new TypeNameParser() { _assemblyResolver = assemblyResolver, _typeResolver = typeResolver, @@ -61,7 +65,7 @@ internal partial struct TypeNameParser _ignoreCase = ignoreCase, _extensibleParser = extensibleParser, _defaultAssemblyName = defaultAssemblyName - }.Parse(); + }.Resolve(parsed); } internal static Type? GetType( @@ -70,35 +74,35 @@ internal partial struct TypeNameParser bool ignoreCase, Assembly topLevelAssembly) { - return new TypeNameParser(typeName) + Metadata.TypeName? parsed = Metadata.TypeNameParser.Parse(typeName, throwOnError); + + if (parsed is null) + { + return null; + } + else if (topLevelAssembly is not null && parsed.AssemblyName is not null) + { + return throwOnError ? throw new ArgumentException(SR.Argument_AssemblyGetTypeCannotSpecifyAssembly) : null; + } + + return new TypeNameParser() { _throwOnError = throwOnError, _ignoreCase = ignoreCase, _topLevelAssembly = topLevelAssembly, - }.Parse(); + }.Resolve(parsed); } - private bool CheckTopLevelAssemblyQualifiedName() - { - if (_topLevelAssembly is not null) - { - if (_throwOnError) - throw new ArgumentException(SR.Argument_AssemblyGetTypeCannotSpecifyAssembly); - return false; - } - return true; - } - - private Assembly? ResolveAssembly(string assemblyName) + private Assembly? ResolveAssembly(Metadata.AssemblyNameInfo assemblyName) { Assembly? assembly; if (_assemblyResolver is not null) { - assembly = _assemblyResolver(new AssemblyName(assemblyName)); + assembly = _assemblyResolver(assemblyName.ToAssemblyName()); } else { - assembly = RuntimeAssemblyInfo.GetRuntimeAssemblyIfExists(RuntimeAssemblyName.Parse(assemblyName)); + assembly = RuntimeAssemblyInfo.GetRuntimeAssemblyIfExists(RuntimeAssemblyName.FromAssemblyNameInfo(assemblyName)); } if (assembly is null && _throwOnError) @@ -113,13 +117,13 @@ private bool CheckTopLevelAssemblyQualifiedName() Justification = "GetType APIs are marked as RequiresUnreferencedCode.")] [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2075:UnrecognizedReflectionPattern", Justification = "GetType APIs are marked as RequiresUnreferencedCode.")] - private Type? GetType(string typeName, ReadOnlySpan nestedTypeNames, string? assemblyNameIfAny) + private Type? GetType(string escapedTypeName, ReadOnlySpan nestedTypeNames, Metadata.TypeName parsedName) { Assembly? assembly; - if (assemblyNameIfAny is not null) + if (parsedName.AssemblyName is not null) { - assembly = ResolveAssembly(assemblyNameIfAny); + assembly = ResolveAssembly(parsedName.AssemblyName); if (assembly is null) return null; } @@ -133,8 +137,6 @@ private bool CheckTopLevelAssemblyQualifiedName() // Resolve the top level type. if (_typeResolver is not null) { - string escapedTypeName = EscapeTypeName(typeName); - type = _typeResolver(assembly, escapedTypeName, _ignoreCase); if (type is null) @@ -154,14 +156,14 @@ private bool CheckTopLevelAssemblyQualifiedName() { if (assembly is RuntimeAssemblyInfo runtimeAssembly) { - type = runtimeAssembly.GetTypeCore(typeName, throwOnError: _throwOnError, ignoreCase: _ignoreCase); + type = runtimeAssembly.GetTypeCore(UnescapeTypeName(escapedTypeName), throwOnError: _throwOnError, ignoreCase: _ignoreCase); } else { // This is a third-party Assembly object. We can emulate GetTypeCore() by calling the public GetType() // method. This is wasteful because it'll probably reparse a type string that we've already parsed // but it can't be helped. - type = assembly.GetType(EscapeTypeName(typeName), throwOnError: _throwOnError, ignoreCase: _ignoreCase); + type = assembly.GetType(escapedTypeName, throwOnError: _throwOnError, ignoreCase: _ignoreCase); } if (type is null) @@ -169,13 +171,15 @@ private bool CheckTopLevelAssemblyQualifiedName() } else { + string? unescapedTypeName = UnescapeTypeName(escapedTypeName); + RuntimeAssemblyInfo? defaultAssembly = null; if (_defaultAssemblyName != null) { defaultAssembly = RuntimeAssemblyInfo.GetRuntimeAssemblyIfExists(RuntimeAssemblyName.Parse(_defaultAssemblyName)); if (defaultAssembly != null) { - type = defaultAssembly.GetTypeCore(typeName, throwOnError: false, ignoreCase: _ignoreCase); + type = defaultAssembly.GetTypeCore(unescapedTypeName, throwOnError: false, ignoreCase: _ignoreCase); } } @@ -185,7 +189,7 @@ private bool CheckTopLevelAssemblyQualifiedName() coreLib = (RuntimeAssemblyInfo)typeof(object).Assembly; if (coreLib != assembly) { - type = coreLib.GetTypeCore(typeName, throwOnError: false, ignoreCase: _ignoreCase); + type = coreLib.GetTypeCore(unescapedTypeName, throwOnError: false, ignoreCase: _ignoreCase); } } @@ -193,7 +197,7 @@ private bool CheckTopLevelAssemblyQualifiedName() { if (_throwOnError) { - throw Helpers.CreateTypeLoadException(typeName, (defaultAssembly ?? coreLib).FullName); + throw Helpers.CreateTypeLoadException(unescapedTypeName, (defaultAssembly ?? coreLib).FullName); } return null; } @@ -214,10 +218,9 @@ private bool CheckTopLevelAssemblyQualifiedName() if (type is null && _ignoreCase && !_extensibleParser) { // Return the first name that matches. Which one gets returned on a multiple match is an implementation detail. - string lowerName = nestedTypeNames[i].ToLowerInvariant(); foreach (Type nt in declaringType.GetNestedTypes(BindingFlags.NonPublic | BindingFlags.Public)) { - if (nt.Name.ToLowerInvariant() == lowerName) + if (nt.Name.Equals(nestedTypeNames[i], StringComparison.InvariantCultureIgnoreCase)) { type = nt; break; @@ -230,7 +233,7 @@ private bool CheckTopLevelAssemblyQualifiedName() if (_throwOnError) { throw new TypeLoadException(SR.Format(SR.TypeLoad_ResolveNestedType, - nestedTypeNames[i], (i > 0) ? nestedTypeNames[i - 1] : typeName)); + nestedTypeNames[i], (i > 0) ? nestedTypeNames[i - 1] : escapedTypeName)); } return null; } diff --git a/src/coreclr/tools/Common/TypeSystem/Common/Utilities/CustomAttributeTypeNameParser.cs b/src/coreclr/tools/Common/TypeSystem/Common/Utilities/CustomAttributeTypeNameParser.cs index a52a68f0028a48..72779375f4697a 100644 --- a/src/coreclr/tools/Common/TypeSystem/Common/Utilities/CustomAttributeTypeNameParser.cs +++ b/src/coreclr/tools/Common/TypeSystem/Common/Utilities/CustomAttributeTypeNameParser.cs @@ -2,8 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; -using System.Collections.Generic; -using System.Text; +using System.Reflection.Metadata; using Internal.TypeSystem; @@ -37,12 +36,17 @@ internal partial struct TypeNameParser public static TypeDesc ResolveType(ModuleDesc module, string name, bool throwIfNotFound, Func canonResolver) { - return new TypeNameParser(name.AsSpan()) + if (!TypeName.TryParse(name.AsSpan(), out TypeName parsed)) + { + ThrowHelper.ThrowTypeLoadException(name, module); + } + + return new TypeNameParser() { _module = module, _throwIfNotFound = throwIfNotFound, _canonResolver = canonResolver - }.Parse()?.Value; + }.Resolve(parsed)?.Value; } private sealed class Type @@ -64,12 +68,10 @@ public Type MakeGenericType(Type[] typeArguments) } } - private static bool CheckTopLevelAssemblyQualifiedName() => true; - - private Type GetType(string typeName, ReadOnlySpan nestedTypeNames, string assemblyNameIfAny) + private Type GetType(string typeName, ReadOnlySpan nestedTypeNames, TypeName parsedName) { - ModuleDesc module = (assemblyNameIfAny == null) ? _module : - _module.Context.ResolveAssembly(new AssemblyName(assemblyNameIfAny), throwIfNotFound: _throwIfNotFound); + ModuleDesc module = (parsedName.AssemblyName == null) ? _module : + _module.Context.ResolveAssembly(parsedName.AssemblyName.ToAssemblyName(), throwIfNotFound: _throwIfNotFound); if (_canonResolver != null && nestedTypeNames.IsEmpty) { @@ -86,7 +88,7 @@ private Type GetType(string typeName, ReadOnlySpan nestedTypeNames, stri } // If it didn't resolve and wasn't assembly-qualified, we also try core library - if (assemblyNameIfAny == null) + if (parsedName.AssemblyName == null) { Type type = GetTypeCore(module.Context.SystemModule, typeName, nestedTypeNames); if (type != null) @@ -94,7 +96,7 @@ private Type GetType(string typeName, ReadOnlySpan nestedTypeNames, stri } if (_throwIfNotFound) - ThrowHelper.ThrowTypeLoadException(EscapeTypeName(typeName, nestedTypeNames), module); + ThrowHelper.ThrowTypeLoadException(parsedName.FullName, module); return null; } @@ -115,10 +117,5 @@ private static Type GetTypeCore(ModuleDesc module, string typeName, ReadOnlySpan return new Type(type); } - - private void ParseError() - { - ThrowHelper.ThrowTypeLoadException(_input.ToString(), _module); - } } } diff --git a/src/coreclr/tools/ILVerification/ILVerification.projitems b/src/coreclr/tools/ILVerification/ILVerification.projitems index 81ce9f65d1139a..3b2c30ddef1f18 100644 --- a/src/coreclr/tools/ILVerification/ILVerification.projitems +++ b/src/coreclr/tools/ILVerification/ILVerification.projitems @@ -66,12 +66,45 @@ Utilities\CustomAttributeTypeNameParser.cs - + + Utilities\HexConverter.cs + + + Utilities\AssemblyNameFormatter.cs + + + Utilities\AssemblyNameParser.cs + + + Utilities\Metadata\AssemblyNameInfo.cs + + + Utilities\TypeName.cs + + + Utilities\TypeNameParserOptions.cs + + Utilities\TypeNameParser.cs + + Utilities\TypeNameParserHelpers.cs + + + System\Diagnostics\CodeAnalysis\UnconditionalSuppressMessageAttribute.cs + + + System\Diagnostics\CodeAnalysis\NullableAttributes.cs + + + Utilities\CustomAttributeTypeNameParser.Helpers + Utilities\ValueStringBuilder.cs + + Utilities\ValueStringBuilder.AppendSpanFormattable.cs + Utilities\LockFreeReaderHashtable.cs diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/TypeNameParser.Dataflow.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/TypeNameParser.Dataflow.cs index 90b63f39c9f026..5b0cfdb12b4445 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/TypeNameParser.Dataflow.cs +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/TypeNameParser.Dataflow.cs @@ -2,10 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Collections.Generic; -using System.Diagnostics; -using System.IO; -using System.Reflection; - +using System.Reflection.Metadata; using Internal.TypeSystem; namespace System.Reflection @@ -20,14 +17,20 @@ internal partial struct TypeNameParser public static TypeDesc ResolveType(string name, ModuleDesc callingModule, TypeSystemContext context, List referencedModules, out bool typeWasNotFoundInAssemblyNorBaseLibrary) { - var parser = new TypeNameParser(name) + if (!TypeName.TryParse(name, out TypeName parsed)) + { + typeWasNotFoundInAssemblyNorBaseLibrary = false; + return null; + } + + var parser = new TypeNameParser() { _context = context, _callingModule = callingModule, _referencedModules = referencedModules }; - TypeDesc result = parser.Parse()?.Value; + TypeDesc result = parser.Resolve(parsed)?.Value; typeWasNotFoundInAssemblyNorBaseLibrary = parser._typeWasNotFoundInAssemblyNorBaseLibrary; return result; @@ -52,16 +55,13 @@ public Type MakeGenericType(Type[] typeArguments) } } - private static bool CheckTopLevelAssemblyQualifiedName() => true; - - private Type GetType(string typeName, ReadOnlySpan nestedTypeNames, string assemblyNameIfAny) + private Type GetType(string typeName, ReadOnlySpan nestedTypeNames, TypeName parsedName) { ModuleDesc module; - if (assemblyNameIfAny != null) + if (parsedName.AssemblyName != null) { - module = (TryParseAssemblyName(assemblyNameIfAny) is AssemblyName an) ? - _context.ResolveAssembly(an, throwIfNotFound: false) : null; + module = _context.ResolveAssembly(parsedName.AssemblyName.ToAssemblyName(), throwIfNotFound: false); } else { @@ -79,7 +79,7 @@ private Type GetType(string typeName, ReadOnlySpan nestedTypeNames, stri } // If it didn't resolve and wasn't assembly-qualified, we also try core library - if (assemblyNameIfAny == null) + if (parsedName.AssemblyName == null) { Type type = GetTypeCore(_context.SystemModule, typeName, nestedTypeNames); if (type != null) @@ -94,22 +94,6 @@ private Type GetType(string typeName, ReadOnlySpan nestedTypeNames, stri return null; } - private static AssemblyName TryParseAssemblyName(string assemblyName) - { - try - { - return new AssemblyName(assemblyName); - } - catch (FileLoadException) - { - return null; - } - catch (ArgumentException) - { - return null; - } - } - private static Type GetTypeCore(ModuleDesc module, string typeName, ReadOnlySpan nestedTypeNames) { (string typeNamespace, string name) = SplitFullTypeName(typeName); @@ -127,9 +111,5 @@ private static Type GetTypeCore(ModuleDesc module, string typeName, ReadOnlySpan return new Type(type); } - - private static void ParseError() - { - } } } diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/ILCompiler.Compiler.csproj b/src/coreclr/tools/aot/ILCompiler.Compiler/ILCompiler.Compiler.csproj index 37c8c2108d9172..a895dbe1726fa3 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/ILCompiler.Compiler.csproj +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/ILCompiler.Compiler.csproj @@ -397,8 +397,8 @@ - - Compiler\Dataflow\TypeNameParser.cs + + Compiler\Dataflow\TypeNameParser.Helpers.cs Utilities\ValueStringBuilder.cs diff --git a/src/coreclr/tools/aot/ILCompiler.TypeSystem/ILCompiler.TypeSystem.csproj b/src/coreclr/tools/aot/ILCompiler.TypeSystem/ILCompiler.TypeSystem.csproj index c46d5fecbfb76c..23afa3780b1abc 100644 --- a/src/coreclr/tools/aot/ILCompiler.TypeSystem/ILCompiler.TypeSystem.csproj +++ b/src/coreclr/tools/aot/ILCompiler.TypeSystem/ILCompiler.TypeSystem.csproj @@ -198,12 +198,39 @@ Utilities\CustomAttributeTypeNameParser.cs - + + Utilities\HexConverter.cs + + + Utilities\AssemblyNameFormatter.cs + + + Utilities\AssemblyNameParser.cs + + + Utilities\AssemblyNameInfo.cs + + + Utilities\TypeName.cs + + Utilities\TypeNameParser.cs + + Utilities\TypeNameParserHelpers.cs + + + Utilities\TypeNameParserOptions.cs + + + Utilities\CustomAttributeTypeNameParser.Helpers + Utilities\ValueStringBuilder.cs + + Utilities\ValueStringBuilder.AppendSpanFormattable.cs + Utilities\GCPointerMap.Algorithm.cs diff --git a/src/libraries/System.Private.CoreLib/src/System/Reflection/AssemblyNameFormatter.cs b/src/libraries/Common/src/System/Reflection/AssemblyNameFormatter.cs similarity index 92% rename from src/libraries/System.Private.CoreLib/src/System/Reflection/AssemblyNameFormatter.cs rename to src/libraries/Common/src/System/Reflection/AssemblyNameFormatter.cs index c1a810db507557..9d5eeebc85a6d0 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Reflection/AssemblyNameFormatter.cs +++ b/src/libraries/Common/src/System/Reflection/AssemblyNameFormatter.cs @@ -6,6 +6,8 @@ using System.Globalization; using System.Text; +#nullable enable + namespace System.Reflection { internal static class AssemblyNameFormatter @@ -91,7 +93,8 @@ private static void AppendQuoted(this ref ValueStringBuilder vsb, string s) // App-compat: You can use double or single quotes to quote a name, and Fusion (or rather the IdentityAuthority) picks one // by some algorithm. Rather than guess at it, we use double quotes consistently. - if (s != s.Trim() || s.Contains('\"') || s.Contains('\'')) + ReadOnlySpan span = s.AsSpan(); + if (s.Length != span.Trim().Length || span.IndexOfAny('\"', '\'') >= 0) needsQuoting = true; if (needsQuoting) @@ -125,5 +128,12 @@ private static void AppendQuoted(this ref ValueStringBuilder vsb, string s) if (needsQuoting) vsb.Append(quoteChar); } + +#if !NETCOREAPP + private static void AppendSpanFormattable(this ref ValueStringBuilder vsb, ushort value) + { + vsb.Append(value.ToString()); + } +#endif } } diff --git a/src/libraries/Common/src/System/Reflection/AssemblyNameParser.cs b/src/libraries/Common/src/System/Reflection/AssemblyNameParser.cs new file mode 100644 index 00000000000000..bfd91d781a4ecc --- /dev/null +++ b/src/libraries/Common/src/System/Reflection/AssemblyNameParser.cs @@ -0,0 +1,506 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.Globalization; +using System.IO; +using System.Runtime.CompilerServices; +using System.Text; + +#nullable enable + +namespace System.Reflection +{ + /// + /// Parses an assembly name. + /// + internal ref partial struct AssemblyNameParser + { + public readonly struct AssemblyNameParts + { + public AssemblyNameParts(string name, Version? version, string? cultureName, AssemblyNameFlags flags, byte[]? publicKeyOrToken) + { + _name = name; + _version = version; + _cultureName = cultureName; + _flags = flags; + _publicKeyOrToken = publicKeyOrToken; + } + + public readonly string _name; + public readonly Version? _version; + public readonly string? _cultureName; + public readonly AssemblyNameFlags _flags; + public readonly byte[]? _publicKeyOrToken; + } + + /// + /// Token categories for the lexer. + /// + private enum Token + { + Equals = 1, + Comma = 2, + String = 3, + End = 4, + } + + private enum AttributeKind + { + Version = 1, + Culture = 2, + PublicKeyOrToken = 4, + ProcessorArchitecture = 8, + Retargetable = 16, + ContentType = 32 + } + + private readonly ReadOnlySpan _input; + private int _index; + + private AssemblyNameParser(ReadOnlySpan input) + { +#if SYSTEM_PRIVATE_CORELIB + if (input.Length == 0) + throw new ArgumentException(SR.Format_StringZeroLength); +#else + Debug.Assert(input.Length > 0); +#endif + + _input = input; + _index = 0; + } + +#if SYSTEM_PRIVATE_CORELIB + public static AssemblyNameParts Parse(string name) => Parse(name.AsSpan()); + + public static AssemblyNameParts Parse(ReadOnlySpan name) + { + AssemblyNameParser parser = new(name); + AssemblyNameParts result = default; + if (parser.TryParse(ref result)) + { + return result; + } + throw new FileLoadException(SR.InvalidAssemblyName, name.ToString()); + } +#endif + + internal static bool TryParse(ReadOnlySpan name, ref AssemblyNameParts parts) + { + AssemblyNameParser parser = new(name); + return parser.TryParse(ref parts); + } + + private static bool TryRecordNewSeen(scoped ref AttributeKind seenAttributes, AttributeKind newAttribute) + { + if ((seenAttributes & newAttribute) != 0) + { + return false; + } + seenAttributes |= newAttribute; + return true; + } + + private bool TryParse(ref AssemblyNameParts result) + { + // Name must come first. + if (!TryGetNextToken(out string name, out Token token) || token != Token.String || string.IsNullOrEmpty(name)) + return false; + + Version? version = null; + string? cultureName = null; + byte[]? pkt = null; + AssemblyNameFlags flags = 0; + + AttributeKind alreadySeen = default; + if (!TryGetNextToken(out _, out token)) + return false; + + while (token != Token.End) + { + if (token != Token.Comma) + return false; + + if (!TryGetNextToken(out string attributeName, out token) || token != Token.String) + return false; + + if (!TryGetNextToken(out _, out token) || token != Token.Equals) + return false; + + if (!TryGetNextToken(out string attributeValue, out token) || token != Token.String) + return false; + + if (attributeName == string.Empty) + return false; + + if (IsAttribute(attributeName, "Version")) + { + if (!TryRecordNewSeen(ref alreadySeen, AttributeKind.Version)) + { + return false; + } + if (!TryParseVersion(attributeValue, ref version)) + { + return false; + } + } + else if (IsAttribute(attributeName, "Culture")) + { + if (!TryRecordNewSeen(ref alreadySeen, AttributeKind.Culture)) + { + return false; + } + if (!TryParseCulture(attributeValue, out cultureName)) + { + return false; + } + } + else if (IsAttribute(attributeName, "PublicKeyToken")) + { + if (!TryRecordNewSeen(ref alreadySeen, AttributeKind.PublicKeyOrToken)) + { + return false; + } + if (!TryParsePKT(attributeValue, isToken: true, out pkt)) + { + return false; + } + } + else if (IsAttribute(attributeName, "PublicKey")) + { + if (!TryRecordNewSeen(ref alreadySeen, AttributeKind.PublicKeyOrToken)) + { + return false; + } + if (!TryParsePKT(attributeValue, isToken: false, out pkt)) + { + return false; + } + flags |= AssemblyNameFlags.PublicKey; + } + else if (IsAttribute(attributeName, "ProcessorArchitecture")) + { + if (!TryRecordNewSeen(ref alreadySeen, AttributeKind.ProcessorArchitecture)) + { + return false; + } + if (!TryParseProcessorArchitecture(attributeValue, out ProcessorArchitecture arch)) + { + return false; + } + flags |= (AssemblyNameFlags)(((int)arch) << 4); + } + else if (IsAttribute(attributeName, "Retargetable")) + { + if (!TryRecordNewSeen(ref alreadySeen, AttributeKind.Retargetable)) + { + return false; + } + + if (attributeValue.Equals("Yes", StringComparison.OrdinalIgnoreCase)) + { + flags |= AssemblyNameFlags.Retargetable; + } + else if (attributeValue.Equals("No", StringComparison.OrdinalIgnoreCase)) + { + // nothing to do + } + else + { + return false; + } + } + else if (IsAttribute(attributeName, "ContentType")) + { + if (!TryRecordNewSeen(ref alreadySeen, AttributeKind.ContentType)) + { + return false; + } + + if (attributeValue.Equals("WindowsRuntime", StringComparison.OrdinalIgnoreCase)) + { + flags |= (AssemblyNameFlags)(((int)AssemblyContentType.WindowsRuntime) << 9); + } + else + { + return false; + } + } + else + { + // Desktop compat: If we got here, the attribute name is unknown to us. Ignore it. + } + + if (!TryGetNextToken(out _, out token)) + { + return false; + } + } + + result = new AssemblyNameParts(name, version, cultureName, flags, pkt); + return true; + } + + private static bool IsAttribute(string candidate, string attributeKind) + => candidate.Equals(attributeKind, StringComparison.OrdinalIgnoreCase); + + private static bool TryParseVersion(string attributeValue, ref Version? version) + { +#if NET8_0_OR_GREATER + ReadOnlySpan attributeValueSpan = attributeValue; + Span parts = stackalloc Range[5]; + parts = parts.Slice(0, attributeValueSpan.Split(parts, '.')); +#else + string[] parts = attributeValue.Split('.'); +#endif + if (parts.Length is < 2 or > 4) + { + return false; + } + + Span versionNumbers = stackalloc ushort[4] { ushort.MaxValue, ushort.MaxValue, ushort.MaxValue, ushort.MaxValue }; + for (int i = 0; i < parts.Length; i++) + { + if (!ushort.TryParse( +#if NET8_0_OR_GREATER + attributeValueSpan[parts[i]], +#else + parts[i], +#endif + NumberStyles.None, NumberFormatInfo.InvariantInfo, out versionNumbers[i])) + { + return false; + } + } + + if (versionNumbers[0] == ushort.MaxValue || + versionNumbers[1] == ushort.MaxValue) + { + return false; + } + + version = + versionNumbers[2] == ushort.MaxValue ? new Version(versionNumbers[0], versionNumbers[1]) : + versionNumbers[3] == ushort.MaxValue ? new Version(versionNumbers[0], versionNumbers[1], versionNumbers[2]) : + new Version(versionNumbers[0], versionNumbers[1], versionNumbers[2], versionNumbers[3]); + + return true; + } + + private static bool TryParseCulture(string attributeValue, out string? result) + { + if (attributeValue.Equals("Neutral", StringComparison.OrdinalIgnoreCase)) + { + result = ""; + return true; + } + + result = attributeValue; + return true; + } + + private static bool TryParsePKT(string attributeValue, bool isToken, out byte[]? result) + { + if (attributeValue.Equals("null", StringComparison.OrdinalIgnoreCase) || attributeValue == string.Empty) + { + result = Array.Empty(); + return true; + } + + if (attributeValue.Length % 2 != 0 || (isToken && attributeValue.Length != 8 * 2)) + { + result = null; + return false; + } + + byte[] pkt = new byte[attributeValue.Length / 2]; + if (!HexConverter.TryDecodeFromUtf16(attributeValue.AsSpan(), pkt, out int _)) + { + result = null; + return false; + } + + result = pkt; + return true; + } + + private static bool TryParseProcessorArchitecture(string attributeValue, out ProcessorArchitecture result) + { + result = attributeValue switch + { + _ when attributeValue.Equals("msil", StringComparison.OrdinalIgnoreCase) => ProcessorArchitecture.MSIL, + _ when attributeValue.Equals("x86", StringComparison.OrdinalIgnoreCase) => ProcessorArchitecture.X86, + _ when attributeValue.Equals("ia64", StringComparison.OrdinalIgnoreCase) => ProcessorArchitecture.IA64, + _ when attributeValue.Equals("amd64", StringComparison.OrdinalIgnoreCase) => ProcessorArchitecture.Amd64, + _ when attributeValue.Equals("arm", StringComparison.OrdinalIgnoreCase) => ProcessorArchitecture.Arm, + _ when attributeValue.Equals("msil", StringComparison.OrdinalIgnoreCase) => ProcessorArchitecture.MSIL, + _ => ProcessorArchitecture.None + }; + return result != ProcessorArchitecture.None; + } + + private static bool IsWhiteSpace(char ch) + => ch is '\n' or '\r' or ' ' or '\t'; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private bool TryGetNextChar(out char ch) + { + if (_index < _input.Length) + { + ch = _input[_index++]; + if (ch == '\0') + { + return false; + } + } + else + { + ch = '\0'; + } + + return true; + } + + // + // Return the next token in assembly name. If the result is Token.String, + // sets "tokenString" to the tokenized string. + // + private bool TryGetNextToken(out string tokenString, out Token token) + { + tokenString = string.Empty; + char c; + + while (true) + { + if (!TryGetNextChar(out c)) + { + token = default; + return false; + } + + switch (c) + { + case ',': + { + token = Token.Comma; + return true; + } + case '=': + { + token = Token.Equals; + return true; + } + case '\0': + { + token = Token.End; + return true; + } + } + + if (!IsWhiteSpace(c)) + { + break; + } + } + + using ValueStringBuilder sb = new ValueStringBuilder(stackalloc char[64]); + + char quoteChar = '\0'; + if (c is '\'' or '\"') + { + quoteChar = c; + if (!TryGetNextChar(out c)) + { + token = default; + return false; + } + } + + for (; ; ) + { + if (c == 0) + { + if (quoteChar != 0) + { + // EOS and unclosed quotes is an error + token = default; + return false; + } + // Reached end of input and therefore of string + break; + } + + if (quoteChar != 0 && c == quoteChar) + break; // Terminate: Found closing quote of quoted string. + + if (quoteChar == 0 && (c is ',' or '=')) + { + _index--; + break; // Terminate: Found start of a new ',' or '=' token. + } + + if (quoteChar == 0 && (c is '\'' or '\"')) + { + token = default; + return false; + } + + if (c is '\\') + { + if (!TryGetNextChar(out c)) + { + token = default; + return false; + } + + switch (c) + { + case '\\': + case ',': + case '=': + case '\'': + case '"': + sb.Append(c); + break; + case 't': + sb.Append('\t'); + break; + case 'r': + sb.Append('\r'); + break; + case 'n': + sb.Append('\n'); + break; + default: + token = default; + return false; + } + } + else + { + sb.Append(c); + } + + if (!TryGetNextChar(out c)) + { + token = default; + return false; + } + } + + + int length = sb.Length; + if (quoteChar == 0) + { + while (length > 0 && IsWhiteSpace(sb[length - 1])) + length--; + } + + tokenString = sb.AsSpan(0, length).ToString(); + token = Token.String; + return true; + } + } +} diff --git a/src/libraries/Common/src/System/Reflection/Metadata/AssemblyNameInfo.cs b/src/libraries/Common/src/System/Reflection/Metadata/AssemblyNameInfo.cs new file mode 100644 index 00000000000000..ee586e3b57a8c0 --- /dev/null +++ b/src/libraries/Common/src/System/Reflection/Metadata/AssemblyNameInfo.cs @@ -0,0 +1,219 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +#nullable enable + +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.Text; + +#if !SYSTEM_PRIVATE_CORELIB +using System.Collections.Immutable; +using System.Linq; +#endif + +namespace System.Reflection.Metadata +{ + /// + /// Describes an assembly. + /// + /// + /// It's a more lightweight, immutable version of that does not pre-allocate instances. + /// + [DebuggerDisplay("{FullName}")] +#if SYSTEM_PRIVATE_CORELIB + internal +#else + public +#endif + sealed class AssemblyNameInfo + { + internal readonly AssemblyNameFlags _flags; + private string? _fullName; + +#if !SYSTEM_PRIVATE_CORELIB + /// + /// Initializes a new instance of the AssemblyNameInfo class. + /// + /// The simple name of the assembly. + /// The version of the assembly. + /// The name of the culture associated with the assembly. + /// The attributes of the assembly. + /// The public key or its token. Set to when it's public key. + /// is null. + public AssemblyNameInfo(string name, Version? version = null, string? cultureName = null, AssemblyNameFlags flags = AssemblyNameFlags.None, ImmutableArray publicKeyOrToken = default) + { + Name = name ?? throw new ArgumentNullException(nameof(name)); + Version = version; + CultureName = cultureName; + _flags = flags; + PublicKeyOrToken = publicKeyOrToken; + } +#endif + + internal AssemblyNameInfo(AssemblyNameParser.AssemblyNameParts parts) + { + Name = parts._name; + Version = parts._version; + CultureName = parts._cultureName; + _flags = parts._flags; +#if SYSTEM_PRIVATE_CORELIB + PublicKeyOrToken = parts._publicKeyOrToken; +#else + PublicKeyOrToken = parts._publicKeyOrToken is null ? default : parts._publicKeyOrToken.Length == 0 + ? ImmutableArray.Empty + #if NET8_0_OR_GREATER + : Runtime.InteropServices.ImmutableCollectionsMarshal.AsImmutableArray(parts._publicKeyOrToken); + #else + : ImmutableArray.Create(parts._publicKeyOrToken); + #endif +#endif + } + + /// + /// Gets the simple name of the assembly. + /// + public string Name { get; } + + /// + /// Gets the version of the assembly. + /// + public Version? Version { get; } + + /// + /// Gets the name of the culture associated with the assembly. + /// + public string? CultureName { get; } + + /// + /// Gets the attributes of the assembly. + /// + public AssemblyNameFlags Flags => _flags; + + /// + /// Gets the public key or the public key token of the assembly. + /// + /// Check for flag to see whether it's public key or its token. +#if SYSTEM_PRIVATE_CORELIB + public byte[]? PublicKeyOrToken { get; } +#else + public ImmutableArray PublicKeyOrToken { get; } +#endif + + /// + /// Gets the full name of the assembly, also known as the display name. + /// + /// In contrary to it does not validate public key token neither computes it based on the provided public key. + public string FullName + { + get + { + if (_fullName is null) + { + byte[]? publicKeyToken = ((Flags & AssemblyNameFlags.PublicKey) != 0) ? null : +#if SYSTEM_PRIVATE_CORELIB + PublicKeyOrToken; +#elif NET8_0_OR_GREATER + !PublicKeyOrToken.IsDefault ? Runtime.InteropServices.ImmutableCollectionsMarshal.AsArray(PublicKeyOrToken) : null; +#else + !PublicKeyOrToken.IsDefault ? PublicKeyOrToken.ToArray() : null; +#endif + _fullName = AssemblyNameFormatter.ComputeDisplayName(Name, Version, CultureName, publicKeyToken, + ExtractAssemblyNameFlags(_flags), ExtractAssemblyContentType(_flags)); + } + + return _fullName; + } + } + + /// + /// Initializes a new instance of the class based on the stored information. + /// + public AssemblyName ToAssemblyName() + { + AssemblyName assemblyName = new(); + assemblyName.Name = Name; + assemblyName.CultureName = CultureName; + assemblyName.Version = Version; + assemblyName.Flags = Flags; + assemblyName.ContentType = ExtractAssemblyContentType(_flags); +#pragma warning disable SYSLIB0037 // Type or member is obsolete + assemblyName.ProcessorArchitecture = ExtractProcessorArchitecture(_flags); +#pragma warning restore SYSLIB0037 // Type or member is obsolete + +#if SYSTEM_PRIVATE_CORELIB + if (PublicKeyOrToken is not null) + { + if ((Flags & AssemblyNameFlags.PublicKey) != 0) + { + assemblyName.SetPublicKey(PublicKeyOrToken); + } + else + { + assemblyName.SetPublicKeyToken(PublicKeyOrToken); + } + } +#else + if (!PublicKeyOrToken.IsDefault) + { +#pragma warning disable RS0030 // TypeSystem does not allow System.Linq, but we need to use System.Linq.ImmutableArrayExtensions.ToArray + // A copy of the array needs to be created, as AssemblyName allows for the mutation of provided array. + if ((Flags & AssemblyNameFlags.PublicKey) != 0) + { + assemblyName.SetPublicKey(PublicKeyOrToken.ToArray()); + } + else + { + assemblyName.SetPublicKeyToken(PublicKeyOrToken.ToArray()); + } +#pragma warning restore RS0030 + } +#endif + + return assemblyName; + } + + /// + /// Parses a span of characters into a assembly name. + /// + /// A span containing the characters representing the assembly name to parse. + /// Parsed type name. + /// Provided assembly name was invalid. + public static AssemblyNameInfo Parse(ReadOnlySpan assemblyName) + => TryParse(assemblyName, out AssemblyNameInfo? result) + ? result! +#if SYSTEM_REFLECTION_METADATA || SYSTEM_PRIVATE_CORELIB + : throw new ArgumentException(SR.InvalidAssemblyName, nameof(assemblyName)); +#else // tools that reference this file as a link + : throw new ArgumentException("The given assembly name was invalid.", nameof(assemblyName)); +#endif + + /// + /// Tries to parse a span of characters into an assembly name. + /// + /// A span containing the characters representing the assembly name to parse. + /// Contains the result when parsing succeeds. + /// true if assembly name was converted successfully, otherwise, false. + public static bool TryParse(ReadOnlySpan assemblyName, [NotNullWhen(true)] out AssemblyNameInfo? result) + { + AssemblyNameParser.AssemblyNameParts parts = default; + if (AssemblyNameParser.TryParse(assemblyName, ref parts)) + { + result = new(parts); + return true; + } + + result = null; + return false; + } + + internal static AssemblyNameFlags ExtractAssemblyNameFlags(AssemblyNameFlags combinedFlags) + => combinedFlags & unchecked((AssemblyNameFlags)0xFFFFF10F); + + internal static AssemblyContentType ExtractAssemblyContentType(AssemblyNameFlags flags) + => (AssemblyContentType)((((int)flags) >> 9) & 0x7); + + internal static ProcessorArchitecture ExtractProcessorArchitecture(AssemblyNameFlags flags) + => (ProcessorArchitecture)((((int)flags) >> 4) & 0x7); + } +} diff --git a/src/libraries/Common/src/System/Reflection/Metadata/TypeName.cs b/src/libraries/Common/src/System/Reflection/Metadata/TypeName.cs new file mode 100644 index 00000000000000..2fac2f8ffd74db --- /dev/null +++ b/src/libraries/Common/src/System/Reflection/Metadata/TypeName.cs @@ -0,0 +1,398 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +#nullable enable + +using System.Collections.Generic; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.Runtime.InteropServices; +using System.Text; + +#if !SYSTEM_PRIVATE_CORELIB +using System.Collections.Immutable; +#endif + +namespace System.Reflection.Metadata +{ + [DebuggerDisplay("{AssemblyQualifiedName}")] +#if SYSTEM_PRIVATE_CORELIB + internal +#else + public +#endif + sealed class TypeName + { + /// + /// Positive value is array rank. + /// Negative value is modifier encoded using constants defined in . + /// + private readonly sbyte _rankOrModifier; + /// + /// To avoid the need of allocating a string for all declaring types (example: A+B+C+D+E+F+G), + /// length of the name is stored and the fullName passed in ctor represents the full name of the nested type. + /// So when the name is needed, a substring is being performed. + /// + private readonly int _nestedNameLength; + private readonly TypeName? _elementOrGenericType; + private readonly TypeName? _declaringType; +#if SYSTEM_PRIVATE_CORELIB + private readonly List? _genericArguments; +#else + private readonly ImmutableArray _genericArguments; +#endif + private string? _name, _fullName, _assemblyQualifiedName; + + internal TypeName(string? fullName, + AssemblyNameInfo? assemblyName, + TypeName? elementOrGenericType = default, + TypeName? declaringType = default, +#if SYSTEM_PRIVATE_CORELIB + List? genericTypeArguments = default, +#else + ImmutableArray.Builder? genericTypeArguments = default, +#endif + sbyte rankOrModifier = default, + int nestedNameLength = -1) + { + _fullName = fullName; + AssemblyName = assemblyName; + _rankOrModifier = rankOrModifier; + _elementOrGenericType = elementOrGenericType; + _declaringType = declaringType; + _nestedNameLength = nestedNameLength; + +#if SYSTEM_PRIVATE_CORELIB + _genericArguments = genericTypeArguments; +#else + _genericArguments = genericTypeArguments is null + ? ImmutableArray.Empty + : genericTypeArguments.Count == genericTypeArguments.Capacity ? genericTypeArguments.MoveToImmutable() : genericTypeArguments.ToImmutableArray(); +#endif + } + + /// + /// The assembly-qualified name of the type; e.g., "System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089". + /// + /// + /// If returns null, simply returns . + /// + public string AssemblyQualifiedName + => _assemblyQualifiedName ??= AssemblyName is null ? FullName : $"{FullName}, {AssemblyName.FullName}"; + + /// + /// Returns assembly name which contains this type, or null if this was not + /// created from a fully-qualified name. + /// + public AssemblyNameInfo? AssemblyName { get; } + + /// + /// If this type is a nested type (see ), gets + /// the declaring type. If this type is not a nested type, throws. + /// + /// + /// For example, given "Namespace.Declaring+Nested", unwraps the outermost type and returns "Namespace.Declaring". + /// + /// The current type is not a nested type. + public TypeName DeclaringType + { + get + { + if (_declaringType is null) + { + TypeNameParserHelpers.ThrowInvalidOperation_NotNestedType(); + } + + return _declaringType; + } + } + + /// + /// The full name of this type, including namespace, but without the assembly name; e.g., "System.Int32". + /// Nested types are represented with a '+'; e.g., "MyNamespace.MyType+NestedType". + /// + /// + /// For constructed generic types, the type arguments will be listed using their fully qualified + /// names. For example, given "List<int>", the property will return + /// "System.Collections.Generic.List`1[[System.Int32, mscorlib, ...]]". + /// For open generic types, the convention is to use a backtick ("`") followed by + /// the arity of the generic type. For example, given "Dictionary<,>", the + /// property will return "System.Collections.Generic.Dictionary`2". Given "Dictionary<,>.Enumerator", + /// the property will return "System.Collections.Generic.Dictionary`2+Enumerator". + /// See ECMA-335, Sec. I.10.7.2 (Type names and arity encoding) for more information. + /// + public string FullName + { + get + { + if (_fullName is null) + { + if (IsConstructedGenericType) + { + _fullName = TypeNameParserHelpers.GetGenericTypeFullName(GetGenericTypeDefinition().FullName.AsSpan(), +#if SYSTEM_PRIVATE_CORELIB + CollectionsMarshal.AsSpan(_genericArguments)); +#else + _genericArguments.AsSpan()); +#endif + } + else if (IsArray || IsPointer || IsByRef) + { + ValueStringBuilder builder = new(stackalloc char[128]); + builder.Append(GetElementType().FullName); + _fullName = TypeNameParserHelpers.GetRankOrModifierStringRepresentation(_rankOrModifier, ref builder); + } + else + { + Debug.Fail("Pre-allocated full name should have been provided in the ctor"); + } + } + else if (_nestedNameLength > 0 && _fullName.Length > _nestedNameLength) // Declaring types + { + // Stored fullName represents the full name of the nested type. + // Example: Namespace.Declaring+Nested + _fullName = _fullName.Substring(0, _nestedNameLength); + } + + return _fullName!; + } + } + + /// + /// Returns true if this type represents any kind of array, regardless of the array's + /// rank or its bounds. + /// + public bool IsArray => _rankOrModifier == TypeNameParserHelpers.SZArray || _rankOrModifier > 0; + + /// + /// Returns true if this type represents a constructed generic type (e.g., "List<int>"). + /// + /// + /// Returns false for open generic types (e.g., "Dictionary<,>"). + /// + public bool IsConstructedGenericType => +#if SYSTEM_PRIVATE_CORELIB + _genericArguments is not null; +#else + _genericArguments.Length > 0; +#endif + + /// + /// Returns true if this is a "plain" type; that is, not an array, not a pointer, not a reference, and + /// not a constructed generic type. Examples of elemental types are "System.Int32", + /// "System.Uri", and "YourNamespace.YourClass". + /// + /// + /// This property returning true doesn't mean that the type is a primitive like string + /// or int; it just means that there's no underlying type. + /// This property will return true for generic type definitions (e.g., "Dictionary<,>"). + /// This is because determining whether a type truly is a generic type requires loading the type + /// and performing a runtime check. + /// + public bool IsSimple => _elementOrGenericType is null; + + /// + /// Returns true if this is a managed pointer type (e.g., "ref int"). + /// Managed pointer types are sometimes called byref types () + /// + public bool IsByRef => _rankOrModifier == TypeNameParserHelpers.ByRef; + + /// + /// Returns true if this is a nested type (e.g., "Namespace.Declaring+Nested"). + /// For nested types returns their declaring type. + /// + public bool IsNested => _declaringType is not null; + + /// + /// Returns true if this type represents a single-dimensional, zero-indexed array (e.g., "int[]"). + /// + public bool IsSZArray => _rankOrModifier == TypeNameParserHelpers.SZArray; + + /// + /// Returns true if this type represents an unmanaged pointer (e.g., "int*" or "void*"). + /// Unmanaged pointer types are often just called pointers () + /// + public bool IsPointer => _rankOrModifier == TypeNameParserHelpers.Pointer; + + /// + /// Returns true if this type represents a variable-bound array; that is, an array of rank greater + /// than 1 (e.g., "int[,]") or a single-dimensional array which isn't necessarily zero-indexed. + /// + public bool IsVariableBoundArrayType => _rankOrModifier >= 1; + + /// + /// The name of this type, without the namespace and the assembly name; e.g., "Int32". + /// Nested types are represented without a '+'; e.g., "MyNamespace.MyType+NestedType" is just "NestedType". + /// + public string Name + { + get + { + if (_name is null) + { + if (IsConstructedGenericType) + { + _name = TypeNameParserHelpers.GetName(GetGenericTypeDefinition().FullName.AsSpan()).ToString(); + } + else if (IsPointer || IsByRef || IsArray) + { + ValueStringBuilder builder = new(stackalloc char[64]); + builder.Append(GetElementType().Name); + _name = TypeNameParserHelpers.GetRankOrModifierStringRepresentation(_rankOrModifier, ref builder); + } + else if (_nestedNameLength > 0 && _fullName is not null) + { + _name = TypeNameParserHelpers.GetName(_fullName.AsSpan(0, _nestedNameLength)).ToString(); + } + else + { + _name = TypeNameParserHelpers.GetName(FullName.AsSpan()).ToString(); + } + } + + return _name; + } + } + + /// + /// Represents the total number of instances that are used to describe + /// this instance, including any generic arguments or underlying types. + /// + /// + /// This value is computed every time this method gets called, it's not cached. + /// There's not really a parallel concept to this in reflection. Think of it + /// as the total number of instances that would be created if + /// you were to totally deconstruct this instance and visit each intermediate + /// that occurs as part of deconstruction. + /// "int" and "Person" each have complexities of 1 because they're standalone types. + /// "int[]" has a node count of 2 because to fully inspect it involves inspecting the + /// array type itself, plus unwrapping the underlying type ("int") and inspecting that. + /// + /// "Dictionary<string, List<int[][]>>" has node count 8 because fully visiting it + /// involves inspecting 8 instances total: + /// + /// Dictionary<string, List<int[][]>> (the original type) + /// Dictionary`2 (the generic type definition) + /// string (a type argument of Dictionary) + /// List<int[][]> (a type argument of Dictionary) + /// List`1 (the generic type definition) + /// int[][] (a type argument of List) + /// int[] (the underlying type of int[][]) + /// int (the underlying type of int[]) + /// + /// + /// + public int GetNodeCount() + { + int result = 1; + + if (IsNested) + { + result += DeclaringType.GetNodeCount(); + } + else if (IsConstructedGenericType) + { + result++; + } + else if (IsArray || IsPointer || IsByRef) + { + result += GetElementType().GetNodeCount(); + } + + foreach (TypeName genericArgument in GetGenericArguments()) + { + result += genericArgument.GetNodeCount(); + } + + return result; + } + + /// + /// The TypeName of the object encompassed or referred to by the current array, pointer, or reference type. + /// + /// + /// For example, given "int[][]", unwraps the outermost array and returns "int[]". + /// + /// The current type is not an array, pointer or reference. + public TypeName GetElementType() + { + if (!(IsArray || IsPointer || IsByRef)) + { + TypeNameParserHelpers.ThrowInvalidOperation_NoElement(); + } + + return _elementOrGenericType!; + } + + /// + /// Returns a TypeName object that represents a generic type name definition from which the current generic type name can be constructed. + /// + /// + /// Given "Dictionary<string, int>", returns the generic type definition "Dictionary<,>". + /// + /// The current type is not a generic type. + public TypeName GetGenericTypeDefinition() + { + if (!IsConstructedGenericType) + { + TypeNameParserHelpers.ThrowInvalidOperation_NotGenericType(); + } + + return _elementOrGenericType!; + } + + /// + /// Parses a span of characters into a type name. + /// + /// A span containing the characters representing the type name to parse. + /// An object that describes optional parameters to use. + /// Parsed type name. + /// Provided type name was invalid. + /// Parsing has exceeded the limit set by . + public static TypeName Parse(ReadOnlySpan typeName, TypeNameParseOptions? options = default) + => TypeNameParser.Parse(typeName, throwOnError: true, options)!; + + /// + /// Tries to parse a span of characters into a type name. + /// + /// A span containing the characters representing the type name to parse. + /// An object that describes optional parameters to use. + /// Contains the result when parsing succeeds. + /// true if type name was converted successfully, otherwise, false. + public static bool TryParse(ReadOnlySpan typeName, [NotNullWhen(true)] out TypeName? result, TypeNameParseOptions? options = default) + { + result = TypeNameParser.Parse(typeName, throwOnError: false, options); + return result is not null; + } + + /// + /// Gets the number of dimensions in an array. + /// + /// An integer that contains the number of dimensions in the current type. + /// The current type is not an array. + public int GetArrayRank() + { + if (!(_rankOrModifier == TypeNameParserHelpers.SZArray || _rankOrModifier > 0)) + { + TypeNameParserHelpers.ThrowInvalidOperation_HasToBeArrayClass(); + } + + return _rankOrModifier == TypeNameParserHelpers.SZArray ? 1 : _rankOrModifier; + } + + /// + /// If this represents a constructed generic type, returns an array + /// of all the generic arguments. Otherwise it returns an empty array. + /// + /// + /// For example, given "Dictionary<string, int>", returns a 2-element array containing + /// string and int. + /// + public +#if SYSTEM_PRIVATE_CORELIB + IReadOnlyList GetGenericArguments() => _genericArguments is null ? Array.Empty() : _genericArguments; +#else + ImmutableArray GetGenericArguments() => _genericArguments; +#endif + } +} diff --git a/src/libraries/Common/src/System/Reflection/Metadata/TypeNameParser.cs b/src/libraries/Common/src/System/Reflection/Metadata/TypeNameParser.cs new file mode 100644 index 00000000000000..7c75f3ee844d6d --- /dev/null +++ b/src/libraries/Common/src/System/Reflection/Metadata/TypeNameParser.cs @@ -0,0 +1,260 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Collections.Generic; +using System.Diagnostics; + +#if !SYSTEM_PRIVATE_CORELIB +using System.Collections.Immutable; +#endif + +using static System.Reflection.Metadata.TypeNameParserHelpers; + +#nullable enable + +namespace System.Reflection.Metadata +{ + [DebuggerDisplay("{_inputString}")] + internal ref struct TypeNameParser + { + private static readonly TypeNameParseOptions _defaults = new(); + private readonly bool _throwOnError; + private readonly TypeNameParseOptions _parseOptions; + private ReadOnlySpan _inputString; + + private TypeNameParser(ReadOnlySpan name, bool throwOnError, TypeNameParseOptions? options) : this() + { + _inputString = name; + _throwOnError = throwOnError; + _parseOptions = options ?? _defaults; + } + + internal static TypeName? Parse(ReadOnlySpan typeName, bool throwOnError, TypeNameParseOptions? options = default) + { + ReadOnlySpan trimmedName = typeName.TrimStart(); // whitespaces at beginning are always OK + if (trimmedName.IsEmpty) + { + if (throwOnError) + { + ThrowArgumentException_InvalidTypeName(errorIndex: 0); // whitespace input needs to report the error index as 0 + } + + return null; + } + + int recursiveDepth = 0; + TypeNameParser parser = new(trimmedName, throwOnError, options); + TypeName? parsedName = parser.ParseNextTypeName(allowFullyQualifiedName: true, ref recursiveDepth); + + if (parsedName is null || !parser._inputString.IsEmpty) // unconsumed input == error + { + if (throwOnError) + { + if (recursiveDepth >= parser._parseOptions.MaxNodes) + { + ThrowInvalidOperation_MaxNodesExceeded(parser._parseOptions.MaxNodes); + } + + int errorIndex = typeName.Length - parser._inputString.Length; + ThrowArgumentException_InvalidTypeName(errorIndex); + } + + return null; + } + + return parsedName; + } + + // this method should return null instead of throwing, so the caller can get errorIndex and include it in error msg + private TypeName? ParseNextTypeName(bool allowFullyQualifiedName, ref int recursiveDepth) + { + if (!TryDive(ref recursiveDepth)) + { + return null; + } + + List? nestedNameLengths = null; + if (!TryGetTypeNameInfo(ref _inputString, ref nestedNameLengths, out int fullTypeNameLength)) + { + return null; + } + + ReadOnlySpan fullTypeName = _inputString.Slice(0, fullTypeNameLength); + _inputString = _inputString.Slice(fullTypeNameLength); + + // Don't allocate now, as it may be an open generic type like "Name`1" +#if SYSTEM_PRIVATE_CORELIB + List? genericArgs = null; +#else + ImmutableArray.Builder? genericArgs = null; +#endif + + // Are there any captured generic args? We'll look for "[[" and "[". + // There are no spaces allowed before the first '[', but spaces are allowed + // after that. The check slices _inputString, so we'll capture it into + // a local so we can restore it later if needed. + ReadOnlySpan capturedBeforeProcessing = _inputString; + if (IsBeginningOfGenericArgs(ref _inputString, out bool doubleBrackets)) + { + ParseAnotherGenericArg: + + // Namespace.Type`2[[GenericArgument1, AssemblyName1],[GenericArgument2, AssemblyName2]] - double square bracket syntax allows for fully qualified type names + // Namespace.Type`2[GenericArgument1,GenericArgument2] - single square bracket syntax is legal only for non-fully qualified type names + // Namespace.Type`2[[GenericArgument1, AssemblyName1], GenericArgument2] - mixed mode + // Namespace.Type`2[GenericArgument1, [GenericArgument2, AssemblyName2]] - mixed mode + TypeName? genericArg = ParseNextTypeName(allowFullyQualifiedName: doubleBrackets, ref recursiveDepth); + if (genericArg is null) // parsing failed + { + return null; + } + + // For [[, there had better be a ']' after the type name. + if (doubleBrackets && !TryStripFirstCharAndTrailingSpaces(ref _inputString, ']')) + { + return null; + } + + if (genericArgs is null) + { +#if SYSTEM_PRIVATE_CORELIB + genericArgs = new List(2); +#else + genericArgs = ImmutableArray.CreateBuilder(2); +#endif + } + genericArgs.Add(genericArg); + + // Is there a ',[' indicating fully qualified generic type arg? + // Is there a ',' indicating non-fully qualified generic type arg? + if (TryStripFirstCharAndTrailingSpaces(ref _inputString, ',')) + { + doubleBrackets = TryStripFirstCharAndTrailingSpaces(ref _inputString, '['); + + goto ParseAnotherGenericArg; + } + + // The only other allowable character is ']', indicating the end of + // the generic type arg list. + if (!TryStripFirstCharAndTrailingSpaces(ref _inputString, ']')) + { + return null; + } + } + + // If there was an error stripping the generic args, back up to + // before we started processing them, and let the decorator + // parser try handling it. + if (genericArgs is null) + { + _inputString = capturedBeforeProcessing; + } + + int previousDecorator = default; + // capture the current state so we can reprocess it again once we know the AssemblyName + capturedBeforeProcessing = _inputString; + // iterate over the decorators to ensure there are no illegal combinations + while (TryParseNextDecorator(ref _inputString, out int parsedDecorator)) + { + if (!TryDive(ref recursiveDepth)) + { + return null; + } + + // Currently it's illegal for managed reference to be followed by any other decorator, + // but this is a runtime-specific behavior and the parser is not enforcing that rule. + previousDecorator = parsedDecorator; + } + + AssemblyNameInfo? assemblyName = null; + if (allowFullyQualifiedName && !TryParseAssemblyName(ref assemblyName)) + { +#if SYSTEM_PRIVATE_CORELIB + // backward compat: throw FileLoadException for non-empty invalid strings + if (_throwOnError || !_inputString.TrimStart().StartsWith(",")) + { + throw new IO.FileLoadException(SR.InvalidAssemblyName, _inputString.ToString()); + } +#else + return null; +#endif + } + + // No matter what was parsed, the full name string is allocated only once. + // In case of generic, nested, array, pointer and byref types the full name is allocated + // when needed for the first time . + string fullName = fullTypeName.ToString(); + + TypeName? declaringType = GetDeclaringType(fullName, nestedNameLengths, assemblyName); + TypeName result = new(fullName, assemblyName, declaringType: declaringType); + if (genericArgs is not null) + { + result = new(fullName: null, assemblyName, elementOrGenericType: result, declaringType, genericArgs); + } + + if (previousDecorator != default) // some decorators were recognized + { + while (TryParseNextDecorator(ref capturedBeforeProcessing, out int parsedModifier)) + { + result = new(fullName: null, assemblyName, elementOrGenericType: result, rankOrModifier: (sbyte)parsedModifier); + } + } + + return result; + } + + /// false means the input was invalid and parsing has failed. Empty input is valid and returns true. + private bool TryParseAssemblyName(ref AssemblyNameInfo? assemblyName) + { + ReadOnlySpan capturedBeforeProcessing = _inputString; + if (TryStripFirstCharAndTrailingSpaces(ref _inputString, ',')) + { + if (_inputString.IsEmpty) + { + _inputString = capturedBeforeProcessing; // restore the state + return false; + } + + ReadOnlySpan candidate = GetAssemblyNameCandidate(_inputString); + if (!AssemblyNameInfo.TryParse(candidate, out assemblyName)) + { + return false; + } + + _inputString = _inputString.Slice(candidate.Length); + return true; + } + + return true; + } + + private static TypeName? GetDeclaringType(string fullTypeName, List? nestedNameLengths, AssemblyNameInfo? assemblyName) + { + if (nestedNameLengths is null) + { + return null; + } + + TypeName? declaringType = null; + int nameOffset = 0; + foreach (int nestedNameLength in nestedNameLengths) + { + Debug.Assert(nestedNameLength > 0, "TryGetTypeNameInfo should return error on zero lengths"); + int fullNameLength = nameOffset + nestedNameLength; + declaringType = new(fullTypeName, assemblyName, declaringType: declaringType, nestedNameLength: fullNameLength); + nameOffset += nestedNameLength + 1; // include the '+' that was skipped in name + } + + return declaringType; + } + + private bool TryDive(ref int depth) + { + if (depth >= _parseOptions.MaxNodes) + { + return false; + } + depth++; + return true; + } + } +} diff --git a/src/libraries/Common/src/System/Reflection/Metadata/TypeNameParserHelpers.cs b/src/libraries/Common/src/System/Reflection/Metadata/TypeNameParserHelpers.cs new file mode 100644 index 00000000000000..3783f56c73d4b7 --- /dev/null +++ b/src/libraries/Common/src/System/Reflection/Metadata/TypeNameParserHelpers.cs @@ -0,0 +1,383 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Buffers; +using System.Collections.Generic; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.Text; + +#nullable enable + +namespace System.Reflection.Metadata +{ + internal static class TypeNameParserHelpers + { + internal const sbyte SZArray = -1; + internal const sbyte Pointer = -2; + internal const sbyte ByRef = -3; + private const char EscapeCharacter = '\\'; +#if NET8_0_OR_GREATER + private static readonly SearchValues s_endOfFullTypeNameDelimitersSearchValues = SearchValues.Create("[]&*,+\\"); +#endif + + internal static string GetGenericTypeFullName(ReadOnlySpan fullTypeName, ReadOnlySpan genericArgs) + { + Debug.Assert(genericArgs.Length > 0); + + ValueStringBuilder result = new(stackalloc char[128]); + result.Append(fullTypeName); + + result.Append('['); + foreach (TypeName genericArg in genericArgs) + { + result.Append('['); + result.Append(genericArg.AssemblyQualifiedName); + result.Append(']'); + result.Append(','); + } + result[result.Length - 1] = ']'; // replace ',' with ']' + + return result.ToString(); + } + + /// Positive length or negative value for invalid name + internal static int GetFullTypeNameLength(ReadOnlySpan input, out bool isNestedType) + { + isNestedType = false; + + // NET 6+ guarantees that MemoryExtensions.IndexOfAny has worst-case complexity + // O(m * i) if a match is found, or O(m * n) if a match is not found, where: + // i := index of match position + // m := number of needles + // n := length of search space (haystack) + // + // Downlevel versions of .NET do not make this guarantee, instead having a + // worst-case complexity of O(m * n) even if a match occurs at the beginning of + // the search space. Since we're running this in a loop over untrusted user + // input, that makes the total loop complexity potentially O(m * n^2), where + // 'n' is adversary-controlled. To avoid DoS issues here, we'll loop manually. + +#if NET8_0_OR_GREATER + int offset = input.IndexOfAny(s_endOfFullTypeNameDelimitersSearchValues); + if (offset < 0) + { + return input.Length; // no type name end chars were found, the whole input is the type name + } + + if (input[offset] == EscapeCharacter) // this is very rare (IL Emit or pure IL) + { + offset = GetUnescapedOffset(input, startOffset: offset); // this is slower, but very rare so acceptable + } +#else + int offset = GetUnescapedOffset(input, startOffset: 0); +#endif + isNestedType = offset > 0 && offset < input.Length && input[offset] == '+'; + return offset; + + static int GetUnescapedOffset(ReadOnlySpan input, int startOffset) + { + int offset = startOffset; + for (; offset < input.Length; offset++) + { + char c = input[offset]; + if (c == EscapeCharacter) + { + offset++; // skip the escaped char + + if (offset == input.Length || // invalid name that ends with escape character + !NeedsEscaping(input[offset])) // invalid name, escapes a char that does not need escaping + { + return -1; + } + } + else if (NeedsEscaping(c)) + { + break; + } + } + return offset; + } + + static bool NeedsEscaping(char c) => c is '[' or ']' or '&' or '*' or ',' or '+' or EscapeCharacter; + } + + internal static ReadOnlySpan GetName(ReadOnlySpan fullName) + { + int offset = fullName.LastIndexOfAny('.', '+'); + + if (offset > 0 && fullName[offset - 1] == EscapeCharacter) // this should be very rare (IL Emit & pure IL) + { + offset = GetUnescapedOffset(fullName, startIndex: offset); + } + + return offset < 0 ? fullName : fullName.Slice(offset + 1); + + static int GetUnescapedOffset(ReadOnlySpan fullName, int startIndex) + { + int offset = startIndex; + for (; offset >= 0; offset--) + { + if (fullName[offset] is '.' or '+') + { + if (offset == 0 || fullName[offset - 1] != EscapeCharacter) + { + break; + } + offset--; // skip the escaping character + } + } + return offset; + } + } + + // this method handles escaping of the ] just to let the AssemblyNameParser fail for the right input + internal static ReadOnlySpan GetAssemblyNameCandidate(ReadOnlySpan input) + { + // The only delimiter which can terminate an assembly name is ']'. + // Otherwise EOL serves as the terminator. + int offset = input.IndexOf(']'); + + if (offset > 0 && input[offset - 1] == EscapeCharacter) // this should be very rare (IL Emit & pure IL) + { + offset = GetUnescapedOffset(input, startIndex: offset); + } + + return offset < 0 ? input : input.Slice(0, offset); + + static int GetUnescapedOffset(ReadOnlySpan input, int startIndex) + { + int offset = startIndex; + for (; offset < input.Length; offset++) + { + if (input[offset] is ']') + { + if (input[offset - 1] != EscapeCharacter) + { + break; + } + } + } + return offset; + } + } + + internal static string GetRankOrModifierStringRepresentation(int rankOrModifier, ref ValueStringBuilder builder) + { + if (rankOrModifier == ByRef) + { + builder.Append('&'); + } + else if (rankOrModifier == Pointer) + { + builder.Append('*'); + } + else if (rankOrModifier == SZArray) + { + builder.Append("[]"); + } + else if (rankOrModifier == 1) + { + builder.Append("[*]"); + } + else + { + Debug.Assert(rankOrModifier >= 2); + + builder.Append('['); + builder.Append(',', rankOrModifier - 1); + builder.Append(']'); + } + + return builder.ToString(); + } + + /// + /// Are there any captured generic args? We'll look for "[[" and "[" that is not followed by "]", "*" and ",". + /// + internal static bool IsBeginningOfGenericArgs(ref ReadOnlySpan span, out bool doubleBrackets) + { + doubleBrackets = false; + + if (!span.IsEmpty && span[0] == '[') + { + // There are no spaces allowed before the first '[', but spaces are allowed after that. + ReadOnlySpan trimmed = span.Slice(1).TrimStart(); + if (!trimmed.IsEmpty) + { + if (trimmed[0] == '[') + { + doubleBrackets = true; + span = trimmed.Slice(1).TrimStart(); + return true; + } + if (!(trimmed[0] is ',' or '*' or ']')) // [] or [*] or [,] or [,,,, ...] + { + span = trimmed; + return true; + } + } + } + + return false; + } + + internal static bool TryGetTypeNameInfo(ref ReadOnlySpan input, ref List? nestedNameLengths, out int totalLength) + { + bool isNestedType; + totalLength = 0; + do + { + int length = GetFullTypeNameLength(input.Slice(totalLength), out isNestedType); + if (length <= 0) + { + // invalid type names: + // -1: invalid escaping + // 0: pair of unescaped "++" characters + return false; + } + +#if SYSTEM_PRIVATE_CORELIB + // Compat: Ignore leading '.' for type names without namespace. .NET Framework historically ignored leading '.' here. It is likely + // that code out there depends on this behavior. For example, type names formed by concatenating namespace and name, without checking for + // empty namespace (bug), are going to have superfluous leading '.'. + // This behavior means that types that start with '.' are not round-trippable via type name. + if (length > 1 && input[0] == '.' && input.Slice(0, length).LastIndexOf('.') == 0) + { + input = input.Slice(1); + length--; + } +#endif + if (isNestedType) + { + (nestedNameLengths ??= new()).Add(length); + totalLength += 1; // skip the '+' sign in next search + } + totalLength += length; + } while (isNestedType); + + return true; + } + + internal static bool TryParseNextDecorator(ref ReadOnlySpan input, out int rankOrModifier) + { + // Then try pulling a single decorator. + // Whitespace cannot precede the decorator, but it can follow the decorator. + + ReadOnlySpan originalInput = input; // so we can restore on 'false' return + + if (TryStripFirstCharAndTrailingSpaces(ref input, '*')) + { + rankOrModifier = Pointer; + return true; + } + + if (TryStripFirstCharAndTrailingSpaces(ref input, '&')) + { + rankOrModifier = ByRef; + return true; + } + + if (TryStripFirstCharAndTrailingSpaces(ref input, '[')) + { + // SZArray := [] + // MDArray := [*] or [,] or [,,,, ...] + + int rank = 1; + bool hasSeenAsterisk = false; + + ReadNextArrayToken: + + if (TryStripFirstCharAndTrailingSpaces(ref input, ']')) + { + // End of array marker + rankOrModifier = rank == 1 && !hasSeenAsterisk ? SZArray : rank; + return true; + } + + if (!hasSeenAsterisk) + { + if (rank == 1 && TryStripFirstCharAndTrailingSpaces(ref input, '*')) + { + // [*] + hasSeenAsterisk = true; + goto ReadNextArrayToken; + } + else if (TryStripFirstCharAndTrailingSpaces(ref input, ',')) + { + // [,,, ...] + checked { rank++; } + goto ReadNextArrayToken; + } + } + + // Don't know what this token is. + // Fall through to 'return false' statement. + } + + input = originalInput; // ensure 'ref input' not mutated + rankOrModifier = 0; + return false; + } + + internal static bool TryStripFirstCharAndTrailingSpaces(ref ReadOnlySpan span, char value) + { + if (!span.IsEmpty && span[0] == value) + { + span = span.Slice(1).TrimStart(); + return true; + } + return false; + } + + [DoesNotReturn] + internal static void ThrowInvalidOperation_MaxNodesExceeded(int limit) => throw +#if SYSTEM_REFLECTION_METADATA + new InvalidOperationException(SR.Format(SR.InvalidOperation_MaxNodesExceeded, limit)); +#else // corelib and tools that reference this file as a link + new InvalidOperationException(); +#endif + + [DoesNotReturn] + internal static void ThrowArgumentException_InvalidTypeName(int errorIndex) => throw +#if SYSTEM_PRIVATE_CORELIB + new ArgumentException(SR.Arg_ArgumentException, $"typeName@{errorIndex}"); +#elif SYSTEM_REFLECTION_METADATA + new ArgumentException(SR.Argument_InvalidTypeName, $"typeName@{errorIndex}"); +#else // tools that reference this file as a link + new ArgumentException(); +#endif + + [DoesNotReturn] + internal static void ThrowInvalidOperation_NotGenericType() => throw +#if SYSTEM_REFLECTION_METADATA || SYSTEM_PRIVATE_CORELIB + new InvalidOperationException(SR.InvalidOperation_NotGenericType); +#else // tools that reference this file as a link + new InvalidOperationException(); +#endif + + [DoesNotReturn] + internal static void ThrowInvalidOperation_NotNestedType() => throw +#if SYSTEM_REFLECTION_METADATA + new InvalidOperationException(SR.InvalidOperation_NotNestedType); +#else // corelib and tools that reference this file as a link + new InvalidOperationException(); +#endif + + [DoesNotReturn] + internal static void ThrowInvalidOperation_NoElement() => throw +#if SYSTEM_REFLECTION_METADATA + new InvalidOperationException(SR.InvalidOperation_NoElement); +#else // corelib and tools that reference this file as a link + new InvalidOperationException(); +#endif + + [DoesNotReturn] + internal static void ThrowInvalidOperation_HasToBeArrayClass() => throw +#if SYSTEM_REFLECTION_METADATA || SYSTEM_PRIVATE_CORELIB + new InvalidOperationException(SR.Argument_HasToBeArrayClass); +#else // tools that reference this file as a link + new InvalidOperationException(); +#endif + } +} diff --git a/src/libraries/Common/src/System/Reflection/Metadata/TypeNameParserOptions.cs b/src/libraries/Common/src/System/Reflection/Metadata/TypeNameParserOptions.cs new file mode 100644 index 00000000000000..66350c9a44cac7 --- /dev/null +++ b/src/libraries/Common/src/System/Reflection/Metadata/TypeNameParserOptions.cs @@ -0,0 +1,41 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace System.Reflection.Metadata +{ +#if SYSTEM_PRIVATE_CORELIB + internal +#else + public +#endif + sealed class TypeNameParseOptions + { + private int _maxNodes = +#if SYSTEM_PRIVATE_CORELIB + int.MaxValue; // CoreLib has never introduced any limits +#else + 20; +#endif + + /// + /// Limits the maximum value of node count that parser can handle. + /// + public int MaxNodes + { + get => _maxNodes; + set + { +#if NET8_0_OR_GREATER + ArgumentOutOfRangeException.ThrowIfLessThanOrEqual(value, 0, nameof(value)); +#else + if (value <= 0) + { + throw new ArgumentOutOfRangeException(paramName: nameof(value)); + } +#endif + + _maxNodes = value; + } + } + } +} diff --git a/src/libraries/Common/src/System/Reflection/TypeNameParser.Helpers.cs b/src/libraries/Common/src/System/Reflection/TypeNameParser.Helpers.cs new file mode 100644 index 00000000000000..bcb2125d3f4ea3 --- /dev/null +++ b/src/libraries/Common/src/System/Reflection/TypeNameParser.Helpers.cs @@ -0,0 +1,192 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.Reflection.Metadata; +using System.Text; + +#nullable enable + +namespace System.Reflection +{ + internal partial struct TypeNameParser + { +#if !MONO // Mono never needs unescaped names + private const char EscapeCharacter = '\\'; + + /// + /// Removes escape characters from the string (if there were any found). + /// + private static string UnescapeTypeName(string name) + { + int indexOfEscapeCharacter = name.IndexOf(EscapeCharacter); + if (indexOfEscapeCharacter < 0) + { + return name; + } + + return Unescape(name, indexOfEscapeCharacter); + + static string Unescape(string name, int indexOfEscapeCharacter) + { + // this code path is executed very rarely (IL Emit or pure IL with chars not allowed in C# or F#) + var sb = new ValueStringBuilder(stackalloc char[64]); + sb.EnsureCapacity(name.Length); + sb.Append(name.AsSpan(0, indexOfEscapeCharacter)); + + for (int i = indexOfEscapeCharacter; i < name.Length;) + { + char c = name[i++]; + + if (c != EscapeCharacter) + { + sb.Append(c); + } + else if (i < name.Length && name[i] == EscapeCharacter) // escaped escape character ;) + { + sb.Append(c); + // Consume the escaped escape character, it's important for edge cases + // like escaped escape character followed by another escaped char (example: "\\\\\\+") + i++; + } + } + + return sb.ToString(); + } + } +#endif + + private static (string typeNamespace, string name) SplitFullTypeName(string typeName) + { + string typeNamespace, name; + + // Matches algorithm from ns::FindSep in src\coreclr\utilcode\namespaceutil.cpp + // This could result in the type name beginning with a '.' character. + int separator = typeName.LastIndexOf('.'); + if (separator <= 0) + { + typeNamespace = ""; + name = typeName; + } + else + { + if (typeName[separator - 1] == '.') + separator--; + typeNamespace = typeName.Substring(0, separator); + name = typeName.Substring(separator + 1); + } + + return (typeNamespace, name); + } + + [UnconditionalSuppressMessage("ReflectionAnalysis", "IL3050:RequiresDynamicCode", + Justification = "Used to implement resolving types from strings.")] + private Type? Resolve(TypeName typeName) + { + if (typeName.IsNested) + { + TypeName? current = typeName; + int nestingDepth = 0; + while (current is not null && current.IsNested) + { + nestingDepth++; + current = current.DeclaringType; + } + + // We're performing real type resolution, it is assumed that the caller has already validated the correctness + // of this TypeName object against their own policies, so there is no need for this method to perform any further checks. + string[] nestedTypeNames = new string[nestingDepth]; + current = typeName; + while (current is not null && current.IsNested) + { +#if MONO + nestedTypeNames[--nestingDepth] = current.Name; +#else // CLR, NativeAOT and tools require unescaped nested type names + nestedTypeNames[--nestingDepth] = UnescapeTypeName(current.Name); +#endif + current = current.DeclaringType; + } +#if SYSTEM_PRIVATE_CORELIB + string nonNestedParentName = current!.FullName; +#else // the tools require unescaped names + string nonNestedParentName = UnescapeTypeName(current!.FullName); +#endif + Type? type = GetType(nonNestedParentName, nestedTypeNames, typeName); + return type is null || !typeName.IsConstructedGenericType ? type : MakeGenericType(type, typeName); + } + else if (typeName.IsConstructedGenericType) + { + Type? type = Resolve(typeName.GetGenericTypeDefinition()); + return type is null ? null : MakeGenericType(type, typeName); + } + else if (typeName.IsArray || typeName.IsPointer || typeName.IsByRef) + { + Type? type = Resolve(typeName.GetElementType()); + if (type is null) + { + return null; + } + + if (typeName.IsByRef) + { + return type.MakeByRefType(); + } + else if (typeName.IsPointer) + { + return type.MakePointerType(); + } + else if (typeName.IsSZArray) + { + return type.MakeArrayType(); + } + else + { + Debug.Assert(typeName.IsVariableBoundArrayType); + + return type.MakeArrayType(rank: typeName.GetArrayRank()); + } + } + else + { + Debug.Assert(typeName.IsSimple); + + Type? type = GetType( +#if SYSTEM_PRIVATE_CORELIB + typeName.FullName, +#else // the tools require unescaped names + UnescapeTypeName(typeName.FullName), +#endif + nestedTypeNames: ReadOnlySpan.Empty, typeName); + + return type; + } + } + + [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2055:UnrecognizedReflectionPattern", + Justification = "Used to implement resolving types from strings.")] + [UnconditionalSuppressMessage("ReflectionAnalysis", "IL3050:RequiresDynamicCode", + Justification = "Used to implement resolving types from strings.")] + private Type? MakeGenericType(Type type, TypeName typeName) + { + var genericArgs = typeName.GetGenericArguments(); +#if SYSTEM_PRIVATE_CORELIB + int size = genericArgs.Count; +#else + int size = genericArgs.Length; +#endif + Type[] genericTypes = new Type[size]; + for (int i = 0; i < size; i++) + { + Type? genericArg = Resolve(genericArgs[i]); + if (genericArg is null) + { + return null; + } + genericTypes[i] = genericArg; + } + + return type.MakeGenericType(genericTypes); + } + } +} diff --git a/src/libraries/Common/src/System/Reflection/TypeNameParser.cs b/src/libraries/Common/src/System/Reflection/TypeNameParser.cs deleted file mode 100644 index 0b69e4e18aaae4..00000000000000 --- a/src/libraries/Common/src/System/Reflection/TypeNameParser.cs +++ /dev/null @@ -1,701 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System.Diagnostics; -using System.Diagnostics.CodeAnalysis; -using System.Runtime.InteropServices; -using System.Text; - -#nullable enable - -namespace System.Reflection -{ - // - // Parser for type names passed to GetType() apis. - // - [StructLayout(LayoutKind.Auto)] - internal ref partial struct TypeNameParser - { - private ReadOnlySpan _input; - private int _index; - private int _errorIndex; // Position for error reporting - - private TypeNameParser(ReadOnlySpan name) - { - _input = name; - _errorIndex = _index = 0; - } - - // - // Parses a type name. The type name may be optionally postpended with a "," followed by a legal assembly name. - // - private Type? Parse() - { - TypeName? typeName = ParseNonQualifiedTypeName(); - if (typeName is null) - return null; - - string? assemblyName = null; - - TokenType token = GetNextToken(); - if (token != TokenType.End) - { - if (token != TokenType.Comma) - { - ParseError(); - return null; - } - - if (!CheckTopLevelAssemblyQualifiedName()) - return null; - - assemblyName = GetNextAssemblyName(); - if (assemblyName is null) - return null; - Debug.Assert(Peek == TokenType.End); - } - - return typeName.ResolveType(ref this, assemblyName); - } - - // - // Parses a type name without any assembly name qualification. - // - private TypeName? ParseNonQualifiedTypeName() - { - // Parse the named type or constructed generic type part first. - TypeName? typeName = ParseNamedOrConstructedGenericTypeName(); - if (typeName is null) - return null; - - // Iterate through any "has-element" qualifiers ([], &, *). - while (true) - { - TokenType token = Peek; - if (token == TokenType.End) - break; - if (token == TokenType.Asterisk) - { - Skip(); - typeName = new ModifierTypeName(typeName, ModifierTypeName.Pointer); - } - else if (token == TokenType.Ampersand) - { - Skip(); - typeName = new ModifierTypeName(typeName, ModifierTypeName.ByRef); - } - else if (token == TokenType.OpenSqBracket) - { - Skip(); - token = GetNextToken(); - if (token == TokenType.Asterisk) - { - typeName = new ModifierTypeName(typeName, 1); - token = GetNextToken(); - } - else - { - int rank = 1; - while (token == TokenType.Comma) - { - token = GetNextToken(); - rank++; - } - if (rank == 1) - typeName = new ModifierTypeName(typeName, ModifierTypeName.Array); - else - typeName = new ModifierTypeName(typeName, rank); - } - if (token != TokenType.CloseSqBracket) - { - ParseError(); - return null; - } - } - else - { - break; - } - } - return typeName; - } - - // - // Foo or Foo+Inner or Foo[String] or Foo+Inner[String] - // - private TypeName? ParseNamedOrConstructedGenericTypeName() - { - TypeName? namedType = ParseNamedTypeName(); - if (namedType is null) - return null; - - // Because "[" is used both for generic arguments and array indexes, we must peek two characters deep. - if (!(Peek is TokenType.OpenSqBracket && (PeekSecond is TokenType.Other or TokenType.OpenSqBracket))) - return namedType; - - Skip(); - - TypeName[] typeArguments = new TypeName[2]; - int typeArgumentsCount = 0; - while (true) - { - TypeName? typeArgument = ParseGenericTypeArgument(); - if (typeArgument is null) - return null; - if (typeArgumentsCount >= typeArguments.Length) - Array.Resize(ref typeArguments, 2 * typeArgumentsCount); - typeArguments[typeArgumentsCount++] = typeArgument; - TokenType token = GetNextToken(); - if (token == TokenType.CloseSqBracket) - break; - if (token != TokenType.Comma) - { - ParseError(); - return null; - } - } - - return new GenericTypeName(namedType, typeArguments, typeArgumentsCount); - } - - // - // Foo or Foo+Inner - // - private TypeName? ParseNamedTypeName() - { - string? fullName = GetNextIdentifier(); - if (fullName is null) - return null; - - fullName = ApplyLeadingDotCompatQuirk(fullName); - - if (Peek == TokenType.Plus) - { - string[] nestedNames = new string[1]; - int nestedNamesCount = 0; - - do - { - Skip(); - - string? nestedName = GetNextIdentifier(); - if (nestedName is null) - return null; - - nestedName = ApplyLeadingDotCompatQuirk(nestedName); - - if (nestedNamesCount >= nestedNames.Length) - Array.Resize(ref nestedNames, 2 * nestedNamesCount); - nestedNames[nestedNamesCount++] = nestedName; - } - while (Peek == TokenType.Plus); - - return new NestedNamespaceTypeName(fullName, nestedNames, nestedNamesCount); - } - else - { - return new NamespaceTypeName(fullName); - } - - // Compat: Ignore leading '.' for type names without namespace. .NET Framework historically ignored leading '.' here. It is likely - // that code out there depends on this behavior. For example, type names formed by concatenating namespace and name, without checking for - // empty namespace (bug), are going to have superfluous leading '.'. - // This behavior means that types that start with '.' are not round-trippable via type name. - static string ApplyLeadingDotCompatQuirk(string typeName) - { -#if NETCOREAPP - return (typeName.StartsWith('.') && !typeName.AsSpan(1).Contains('.')) ? typeName.Substring(1) : typeName; -#else - return ((typeName.Length > 0) && (typeName[0] == '.') && typeName.LastIndexOf('.') == 0) ? typeName.Substring(1) : typeName; -#endif - } - } - - // - // Parse a generic argument. In particular, generic arguments can take the special form [,]. - // - private TypeName? ParseGenericTypeArgument() - { - TokenType token = GetNextToken(); - if (token == TokenType.Other) - { - return ParseNonQualifiedTypeName(); - } - if (token != TokenType.OpenSqBracket) - { - ParseError(); - return null; - } - string? assemblyName = null; - TypeName? typeName = ParseNonQualifiedTypeName(); - if (typeName is null) - return null; - - token = GetNextToken(); - if (token == TokenType.Comma) - { - assemblyName = GetNextEmbeddedAssemblyName(); - token = GetNextToken(); - } - if (token != TokenType.CloseSqBracket) - { - ParseError(); - return null; - } - - return (assemblyName != null) ? new AssemblyQualifiedTypeName(typeName, assemblyName) : typeName; - } - - // - // String tokenizer for type names passed to the GetType() APIs. - // - - private TokenType Peek - { - get - { - SkipWhiteSpace(); - char c = (_index < _input.Length) ? _input[_index] : '\0'; - return CharToToken(c); - } - } - - private TokenType PeekSecond - { - get - { - SkipWhiteSpace(); - int index = _index + 1; - while (index < _input.Length && char.IsWhiteSpace(_input[index])) - index++; - char c = (index < _input.Length) ? _input[index] : '\0'; - return CharToToken(c); - } - } - - private void Skip() - { - SkipWhiteSpace(); - if (_index < _input.Length) - _index++; - } - - // Return the next token and skip index past it unless already at end of string - // or the token is not a reserved token. - private TokenType GetNextToken() - { - _errorIndex = _index; - - TokenType tokenType = Peek; - if (tokenType == TokenType.End || tokenType == TokenType.Other) - return tokenType; - Skip(); - return tokenType; - } - - // - // Lex the next segment as part of a type name. (Do not use for assembly names.) - // - // Note that unescaped "."'s do NOT terminate the identifier, but unescaped "+"'s do. - // - // Terminated by the first non-escaped reserved character ('[', ']', '+', '&', '*' or ',') - // - private string? GetNextIdentifier() - { - SkipWhiteSpace(); - - ValueStringBuilder sb = new ValueStringBuilder(stackalloc char[64]); - - int src = _index; - while (true) - { - if (src >= _input.Length) - break; - char c = _input[src]; - TokenType token = CharToToken(c); - if (token != TokenType.Other) - break; - src++; - if (c == '\\') // Check for escaped character - { - // Update error location - _errorIndex = src - 1; - - c = (src < _input.Length) ? _input[src++] : '\0'; - - if (!NeedsEscapingInTypeName(c)) - { - // If we got here, a backslash was used to escape a character that is not legal to escape inside a type name. - ParseError(); - return null; - } - } - sb.Append(c); - } - _index = src; - - if (sb.Length == 0) - { - // The identifier has to be non-empty - _errorIndex = src; - ParseError(); - return null; - } - - return sb.ToString(); - } - - // - // Lex the next segment as the assembly name at the end of an assembly-qualified type name. (Do not use for - // assembly names embedded inside generic type arguments.) - // - private string? GetNextAssemblyName() - { - if (!StartAssemblyName()) - return null; - - string assemblyName = _input.Slice(_index).ToString(); - _index = _input.Length; - return assemblyName; - } - - // - // Lex the next segment as an assembly name embedded inside a generic argument type. - // - // Terminated by an unescaped ']'. - // - private string? GetNextEmbeddedAssemblyName() - { - if (!StartAssemblyName()) - return null; - - ValueStringBuilder sb = new ValueStringBuilder(stackalloc char[64]); - - int src = _index; - while (true) - { - if (src >= _input.Length) - { - ParseError(); - return null; - } - char c = _input[src]; - if (c == ']') - break; - src++; - - // Backslash can be used to escape a ']' - any other backslash character is left alone (along with the backslash) - // for the AssemblyName parser to handle. - if (c == '\\' && (src < _input.Length) && _input[src] == ']') - { - c = _input[src++]; - } - sb.Append(c); - } - _index = src; - - if (sb.Length == 0) - { - // The assembly name has to be non-empty - _errorIndex = src; - ParseError(); - return null; - } - - return sb.ToString(); - } - - private bool StartAssemblyName() - { - // Compat: Treat invalid starting token of assembly name as type name parsing error instead of assembly name parsing error. This only affects - // exception returned by the parser. - if (Peek is TokenType.End or TokenType.Comma) - { - ParseError(); - return false; - } - return true; - } - - // - // Classify a character as a TokenType. (Fortunately, all tokens in type name strings other than identifiers are single-character tokens.) - // - private static TokenType CharToToken(char c) - { - return c switch - { - '\0' => TokenType.End, - '[' => TokenType.OpenSqBracket, - ']' => TokenType.CloseSqBracket, - ',' => TokenType.Comma, - '+' => TokenType.Plus, - '*' => TokenType.Asterisk, - '&' => TokenType.Ampersand, - _ => TokenType.Other, - }; - } - - // - // The type name parser has a strange attitude towards whitespace. It throws away whitespace between punctuation tokens and whitespace - // preceding identifiers or assembly names (and this cannot be escaped away). But whitespace between the end of an identifier - // and the punctuation that ends it is *not* ignored. - // - // In other words, GetType(" Foo") searches for "Foo" but GetType("Foo ") searches for "Foo ". - // - // Whitespace between the end of an assembly name and the punction mark that ends it is also not ignored by this parser, - // but this is irrelevant since the assembly name is then turned over to AssemblyName for parsing, which *does* ignore trailing whitespace. - // - private void SkipWhiteSpace() - { - while (_index < _input.Length && char.IsWhiteSpace(_input[_index])) - _index++; - } - - private enum TokenType - { - End = 0, //At end of string - OpenSqBracket = 1, //'[' - CloseSqBracket = 2, //']' - Comma = 3, //',' - Plus = 4, //'+' - Asterisk = 5, //'*' - Ampersand = 6, //'&' - Other = 7, //Type identifier, AssemblyName or embedded AssemblyName. - } - - // - // The TypeName class is the base class for a family of types that represent the nodes in a parse tree for - // assembly-qualified type names. - // - private abstract class TypeName - { - /// - /// Helper for the Type.GetType() family of APIs. "containingAssemblyIsAny" is the assembly to search for (as determined - /// by a qualifying assembly string in the original type string passed to Type.GetType(). If null, it means the type stream - /// didn't specify an assembly name. How to respond to that is up to the type resolver delegate in getTypeOptions - this class - /// is just a middleman. - /// - public abstract Type? ResolveType(ref TypeNameParser parser, string? containingAssemblyIfAny); - } - - // - // Represents a parse of a type name qualified by an assembly name. - // - private sealed class AssemblyQualifiedTypeName : TypeName - { - private readonly string _assemblyName; - private readonly TypeName _nonQualifiedTypeName; - - public AssemblyQualifiedTypeName(TypeName nonQualifiedTypeName, string assemblyName) - { - _nonQualifiedTypeName = nonQualifiedTypeName; - _assemblyName = assemblyName; - } - - public override Type? ResolveType(ref TypeNameParser parser, string? containingAssemblyIfAny) - { - return _nonQualifiedTypeName.ResolveType(ref parser, _assemblyName); - } - } - - // - // Non-nested named type. The full name is the namespace-qualified name. For example, the FullName for - // System.Collections.Generic.IList<> is "System.Collections.Generic.IList`1". - // - private sealed partial class NamespaceTypeName : TypeName - { - private readonly string _fullName; - public NamespaceTypeName(string fullName) - { - _fullName = fullName; - } - - public override Type? ResolveType(ref TypeNameParser parser, string? containingAssemblyIfAny) - { - return parser.GetType(_fullName, default, containingAssemblyIfAny); - } - } - - // - // Nested type name. - // - private sealed partial class NestedNamespaceTypeName : TypeName - { - private readonly string _fullName; - private readonly string[] _nestedNames; - private readonly int _nestedNamesCount; - - public NestedNamespaceTypeName(string fullName, string[] nestedNames, int nestedNamesCount) - { - _fullName = fullName; - _nestedNames = nestedNames; - _nestedNamesCount = nestedNamesCount; - } - - public override Type? ResolveType(ref TypeNameParser parser, string? containingAssemblyIfAny) - { - return parser.GetType(_fullName, _nestedNames.AsSpan(0, _nestedNamesCount), containingAssemblyIfAny); - } - } - - // - // Array, byref or pointer type name. - // - private sealed class ModifierTypeName : TypeName - { - private readonly TypeName _elementTypeName; - - // Positive value is multi-dimensional array rank. - // Negative value is modifier encoded using constants below. - private readonly int _rankOrModifier; - - public const int Array = -1; - public const int Pointer = -2; - public const int ByRef = -3; - - public ModifierTypeName(TypeName elementTypeName, int rankOrModifier) - { - _elementTypeName = elementTypeName; - _rankOrModifier = rankOrModifier; - } - -#if NETCOREAPP - [UnconditionalSuppressMessage("AotAnalysis", "IL3050:AotUnfriendlyApi", - Justification = "Used to implement resolving types from strings.")] -#endif - public override Type? ResolveType(ref TypeNameParser parser, string? containingAssemblyIfAny) - { - Type? elementType = _elementTypeName.ResolveType(ref parser, containingAssemblyIfAny); - if (elementType is null) - return null; - - return _rankOrModifier switch - { - Array => elementType.MakeArrayType(), - Pointer => elementType.MakePointerType(), - ByRef => elementType.MakeByRefType(), - _ => elementType.MakeArrayType(_rankOrModifier) - }; - } - } - - // - // Constructed generic type name. - // - private sealed class GenericTypeName : TypeName - { - private readonly TypeName _typeDefinition; - private readonly TypeName[] _typeArguments; - private readonly int _typeArgumentsCount; - - public GenericTypeName(TypeName genericTypeDefinition, TypeName[] typeArguments, int typeArgumentsCount) - { - _typeDefinition = genericTypeDefinition; - _typeArguments = typeArguments; - _typeArgumentsCount = typeArgumentsCount; - } - -#if NETCOREAPP - [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2055:UnrecognizedReflectionPattern", - Justification = "Used to implement resolving types from strings.")] - [UnconditionalSuppressMessage("AotAnalysis", "IL3050:AotUnfriendlyApi", - Justification = "Used to implement resolving types from strings.")] -#endif - public override Type? ResolveType(ref TypeNameParser parser, string? containingAssemblyIfAny) - { - Type? typeDefinition = _typeDefinition.ResolveType(ref parser, containingAssemblyIfAny); - if (typeDefinition is null) - return null; - - Type[] arguments = new Type[_typeArgumentsCount]; - for (int i = 0; i < arguments.Length; i++) - { - Type? typeArgument = _typeArguments[i].ResolveType(ref parser, null); - if (typeArgument is null) - return null; - arguments[i] = typeArgument; - } - - return typeDefinition.MakeGenericType(arguments); - } - } - - // - // Type name escaping helpers - // - -#if NETCOREAPP - private static ReadOnlySpan CharsToEscape => "\\[]+*&,"; - - private static bool NeedsEscapingInTypeName(char c) - => CharsToEscape.Contains(c); -#else - private static char[] CharsToEscape { get; } = "\\[]+*&,".ToCharArray(); - - private static bool NeedsEscapingInTypeName(char c) - => Array.IndexOf(CharsToEscape, c) >= 0; -#endif - - private static string EscapeTypeName(string name) - { - if (name.AsSpan().IndexOfAny(CharsToEscape) < 0) - return name; - - var sb = new ValueStringBuilder(stackalloc char[64]); - foreach (char c in name) - { - if (NeedsEscapingInTypeName(c)) - sb.Append('\\'); - sb.Append(c); - } - - return sb.ToString(); - } - - private static string EscapeTypeName(string typeName, ReadOnlySpan nestedTypeNames) - { - string fullName = EscapeTypeName(typeName); - if (nestedTypeNames.Length > 0) - { - var sb = new StringBuilder(fullName); - for (int i = 0; i < nestedTypeNames.Length; i++) - { - sb.Append('+'); - sb.Append(EscapeTypeName(nestedTypeNames[i])); - } - fullName = sb.ToString(); - } - return fullName; - } - - private static (string typeNamespace, string name) SplitFullTypeName(string typeName) - { - string typeNamespace, name; - - // Matches algorithm from ns::FindSep in src\coreclr\utilcode\namespaceutil.cpp - int separator = typeName.LastIndexOf('.'); - if (separator <= 0) - { - typeNamespace = ""; - name = typeName; - } - else - { - if (typeName[separator - 1] == '.') - separator--; - typeNamespace = typeName.Substring(0, separator); - name = typeName.Substring(separator + 1); - } - - return (typeNamespace, name); - } - -#if SYSTEM_PRIVATE_CORELIB - private void ParseError() - { - if (_throwOnError) - throw new ArgumentException(SR.Arg_ArgumentException, $"typeName@{_errorIndex}"); - } -#endif - } -} diff --git a/src/libraries/Common/src/System/Text/ValueStringBuilder.AppendSpanFormattable.cs b/src/libraries/Common/src/System/Text/ValueStringBuilder.AppendSpanFormattable.cs index 04e9fcbdb55240..3e9cf2c56d3ea6 100644 --- a/src/libraries/Common/src/System/Text/ValueStringBuilder.AppendSpanFormattable.cs +++ b/src/libraries/Common/src/System/Text/ValueStringBuilder.AppendSpanFormattable.cs @@ -1,6 +1,8 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +#nullable enable + namespace System.Text { internal ref partial struct ValueStringBuilder diff --git a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems index b9f4be64bc9a74..4dd47c701586ca 100644 --- a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems +++ b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems @@ -649,9 +649,7 @@ - - @@ -1473,8 +1471,29 @@ Common\System\IO\PathInternal.CaseSensitivity.cs - - Common\System\Reflection\TypeNameParser.cs + + Common\System\Reflection\TypeNameParser.Helpers + + + Common\System\Reflection\AssemblyNameParser.cs + + + Common\System\Reflection\AssemblyNameFormatter.cs + + + Common\System\Reflection\Metadata\AssemblyNameInfo.cs + + + Common\System\Reflection\Metadata\TypeName.cs + + + Common\System\Reflection\Metadata\TypeNameParser.cs + + + Common\System\Reflection\Metadata\TypeNameParserHelpers.cs + + + Common\System\Reflection\Metadata\TypeNameParserOptions.cs Common\System\Runtime\Versioning\NonVersionableAttribute.cs diff --git a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/CodeAnalysis/UnconditionalSuppressMessageAttribute.cs b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/CodeAnalysis/UnconditionalSuppressMessageAttribute.cs index 2d82ed0c0e7f50..5ee6c949bc97e5 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/CodeAnalysis/UnconditionalSuppressMessageAttribute.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/CodeAnalysis/UnconditionalSuppressMessageAttribute.cs @@ -1,6 +1,8 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +#nullable enable + namespace System.Diagnostics.CodeAnalysis { /// diff --git a/src/libraries/System.Private.CoreLib/src/System/Reflection/AssemblyNameParser.cs b/src/libraries/System.Private.CoreLib/src/System/Reflection/AssemblyNameParser.cs deleted file mode 100644 index dbaaefd4d8c9dd..00000000000000 --- a/src/libraries/System.Private.CoreLib/src/System/Reflection/AssemblyNameParser.cs +++ /dev/null @@ -1,438 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System.Diagnostics; -using System.Diagnostics.CodeAnalysis; -using System.Globalization; -using System.IO; -using System.Runtime.CompilerServices; -using System.Text; - -namespace System.Reflection -{ - // - // Parses an assembly name. - // - internal ref struct AssemblyNameParser - { - public readonly struct AssemblyNameParts - { - public AssemblyNameParts(string name, Version? version, string? cultureName, AssemblyNameFlags flags, byte[]? publicKeyOrToken) - { - _name = name; - _version = version; - _cultureName = cultureName; - _flags = flags; - _publicKeyOrToken = publicKeyOrToken; - } - - public readonly string _name; - public readonly Version? _version; - public readonly string? _cultureName; - public readonly AssemblyNameFlags _flags; - public readonly byte[]? _publicKeyOrToken; - } - - // Token categories for the lexer. - private enum Token - { - Equals = 1, - Comma = 2, - String = 3, - End = 4, - } - - private enum AttributeKind - { - Version = 1, - Culture = 2, - PublicKeyOrToken = 4, - ProcessorArchitecture = 8, - Retargetable = 16, - ContentType = 32 - } - - private readonly ReadOnlySpan _input; - private int _index; - - private AssemblyNameParser(ReadOnlySpan input) - { - if (input.Length == 0) - throw new ArgumentException(SR.Format_StringZeroLength); - - _input = input; - _index = 0; - } - - public static AssemblyNameParts Parse(string name) - { - return new AssemblyNameParser(name).Parse(); - } - - public static AssemblyNameParts Parse(ReadOnlySpan name) - { - return new AssemblyNameParser(name).Parse(); - } - - private void RecordNewSeenOrThrow(scoped ref AttributeKind seenAttributes, AttributeKind newAttribute) - { - if ((seenAttributes & newAttribute) != 0) - { - ThrowInvalidAssemblyName(); - } - seenAttributes |= newAttribute; - } - - private AssemblyNameParts Parse() - { - // Name must come first. - Token token = GetNextToken(out string name); - if (token != Token.String) - ThrowInvalidAssemblyName(); - - if (string.IsNullOrEmpty(name)) - ThrowInvalidAssemblyName(); - - Version? version = null; - string? cultureName = null; - byte[]? pkt = null; - AssemblyNameFlags flags = 0; - - AttributeKind alreadySeen = default; - token = GetNextToken(); - while (token != Token.End) - { - if (token != Token.Comma) - ThrowInvalidAssemblyName(); - - token = GetNextToken(out string attributeName); - if (token != Token.String) - ThrowInvalidAssemblyName(); - - token = GetNextToken(); - if (token != Token.Equals) - ThrowInvalidAssemblyName(); - - token = GetNextToken(out string attributeValue); - if (token != Token.String) - ThrowInvalidAssemblyName(); - - if (attributeName == string.Empty) - ThrowInvalidAssemblyName(); - - if (attributeName.Equals("Version", StringComparison.OrdinalIgnoreCase)) - { - RecordNewSeenOrThrow(ref alreadySeen, AttributeKind.Version); - version = ParseVersion(attributeValue); - } - - if (attributeName.Equals("Culture", StringComparison.OrdinalIgnoreCase)) - { - RecordNewSeenOrThrow(ref alreadySeen, AttributeKind.Culture); - cultureName = ParseCulture(attributeValue); - } - - if (attributeName.Equals("PublicKey", StringComparison.OrdinalIgnoreCase)) - { - RecordNewSeenOrThrow(ref alreadySeen, AttributeKind.PublicKeyOrToken); - pkt = ParsePKT(attributeValue, isToken: false); - flags |= AssemblyNameFlags.PublicKey; - } - - if (attributeName.Equals("PublicKeyToken", StringComparison.OrdinalIgnoreCase)) - { - RecordNewSeenOrThrow(ref alreadySeen, AttributeKind.PublicKeyOrToken); - pkt = ParsePKT(attributeValue, isToken: true); - } - - if (attributeName.Equals("ProcessorArchitecture", StringComparison.OrdinalIgnoreCase)) - { - RecordNewSeenOrThrow(ref alreadySeen, AttributeKind.ProcessorArchitecture); - flags |= (AssemblyNameFlags)(((int)ParseProcessorArchitecture(attributeValue)) << 4); - } - - if (attributeName.Equals("Retargetable", StringComparison.OrdinalIgnoreCase)) - { - RecordNewSeenOrThrow(ref alreadySeen, AttributeKind.Retargetable); - if (attributeValue.Equals("Yes", StringComparison.OrdinalIgnoreCase)) - { - flags |= AssemblyNameFlags.Retargetable; - } - else if (attributeValue.Equals("No", StringComparison.OrdinalIgnoreCase)) - { - // nothing to do - } - else - { - ThrowInvalidAssemblyName(); - } - } - - if (attributeName.Equals("ContentType", StringComparison.OrdinalIgnoreCase)) - { - RecordNewSeenOrThrow(ref alreadySeen, AttributeKind.ContentType); - if (attributeValue.Equals("WindowsRuntime", StringComparison.OrdinalIgnoreCase)) - { - flags |= (AssemblyNameFlags)(((int)AssemblyContentType.WindowsRuntime) << 9); - } - else - { - ThrowInvalidAssemblyName(); - } - } - - // Desktop compat: If we got here, the attribute name is unknown to us. Ignore it. - token = GetNextToken(); - } - - return new AssemblyNameParts(name, version, cultureName, flags, pkt); - } - - private Version ParseVersion(string attributeValue) - { - ReadOnlySpan attributeValueSpan = attributeValue; - Span parts = stackalloc Range[5]; - parts = parts.Slice(0, attributeValueSpan.Split(parts, '.')); - if (parts.Length is < 2 or > 4) - { - ThrowInvalidAssemblyName(); - } - - Span versionNumbers = stackalloc ushort[4]; - for (int i = 0; i < versionNumbers.Length; i++) - { - if ((uint)i >= (uint)parts.Length) - { - versionNumbers[i] = ushort.MaxValue; - break; - } - - if (!ushort.TryParse(attributeValueSpan[parts[i]], NumberStyles.None, NumberFormatInfo.InvariantInfo, out versionNumbers[i])) - { - ThrowInvalidAssemblyName(); - } - } - - if (versionNumbers[0] == ushort.MaxValue || - versionNumbers[1] == ushort.MaxValue) - { - ThrowInvalidAssemblyName(); - } - - return - versionNumbers[2] == ushort.MaxValue ? new Version(versionNumbers[0], versionNumbers[1]) : - versionNumbers[3] == ushort.MaxValue ? new Version(versionNumbers[0], versionNumbers[1], versionNumbers[2]) : - new Version(versionNumbers[0], versionNumbers[1], versionNumbers[2], versionNumbers[3]); - } - - private static string ParseCulture(string attributeValue) - { - if (attributeValue.Equals("Neutral", StringComparison.OrdinalIgnoreCase)) - { - return ""; - } - - return attributeValue; - } - - private byte[] ParsePKT(string attributeValue, bool isToken) - { - if (attributeValue.Equals("null", StringComparison.OrdinalIgnoreCase) || attributeValue == string.Empty) - return Array.Empty(); - - if (isToken && attributeValue.Length != 8 * 2) - ThrowInvalidAssemblyName(); - - byte[] pkt = new byte[attributeValue.Length / 2]; - int srcIndex = 0; - for (int i = 0; i < pkt.Length; i++) - { - char hi = attributeValue[srcIndex++]; - char lo = attributeValue[srcIndex++]; - pkt[i] = (byte)((ParseHexNybble(hi) << 4) | ParseHexNybble(lo)); - } - return pkt; - } - - private ProcessorArchitecture ParseProcessorArchitecture(string attributeValue) - { - if (attributeValue.Equals("msil", StringComparison.OrdinalIgnoreCase)) - return ProcessorArchitecture.MSIL; - if (attributeValue.Equals("x86", StringComparison.OrdinalIgnoreCase)) - return ProcessorArchitecture.X86; - if (attributeValue.Equals("ia64", StringComparison.OrdinalIgnoreCase)) - return ProcessorArchitecture.IA64; - if (attributeValue.Equals("amd64", StringComparison.OrdinalIgnoreCase)) - return ProcessorArchitecture.Amd64; - if (attributeValue.Equals("arm", StringComparison.OrdinalIgnoreCase)) - return ProcessorArchitecture.Arm; - ThrowInvalidAssemblyName(); - return default; // unreachable - } - - private byte ParseHexNybble(char c) - { - int value = HexConverter.FromChar(c); - if (value == 0xFF) - { - ThrowInvalidAssemblyName(); - } - return (byte)value; - } - - // - // Return the next token in assembly name. If you expect the result to be Token.String, - // use GetNext(out String) instead. - // - private Token GetNextToken() - { - return GetNextToken(out _); - } - - private static bool IsWhiteSpace(char ch) - { - switch (ch) - { - case '\n': - case '\r': - case ' ': - case '\t': - return true; - default: - return false; - } - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private char GetNextChar() - { - char ch; - if (_index < _input.Length) - { - ch = _input[_index++]; - if (ch == '\0') - { - ThrowInvalidAssemblyName(); - } - } - else - { - ch = '\0'; - } - - return ch; - } - - // - // Return the next token in assembly name. If the result is Token.String, - // sets "tokenString" to the tokenized string. - // - private Token GetNextToken(out string tokenString) - { - tokenString = string.Empty; - char c; - - while (true) - { - c = GetNextChar(); - switch (c) - { - case ',': - return Token.Comma; - case '=': - return Token.Equals; - case '\0': - return Token.End; - } - - if (!IsWhiteSpace(c)) - { - break; - } - } - - ValueStringBuilder sb = new ValueStringBuilder(stackalloc char[64]); - - char quoteChar = '\0'; - if (c == '\'' || c == '\"') - { - quoteChar = c; - c = GetNextChar(); - } - - for (; ; ) - { - if (c == 0) - { - if (quoteChar != 0) - { - // EOS and unclosed quotes is an error - ThrowInvalidAssemblyName(); - } - // Reached end of input and therefore of string - break; - } - - if (quoteChar != 0 && c == quoteChar) - break; // Terminate: Found closing quote of quoted string. - - if (quoteChar == 0 && (c == ',' || c == '=')) - { - _index--; - break; // Terminate: Found start of a new ',' or '=' token. - } - - if (quoteChar == 0 && (c == '\'' || c == '\"')) - ThrowInvalidAssemblyName(); - - if (c == '\\') - { - c = GetNextChar(); - - switch (c) - { - case '\\': - case ',': - case '=': - case '\'': - case '"': - sb.Append(c); - break; - case 't': - sb.Append('\t'); - break; - case 'r': - sb.Append('\r'); - break; - case 'n': - sb.Append('\n'); - break; - default: - ThrowInvalidAssemblyName(); - break; //unreachable - } - } - else - { - sb.Append(c); - } - - c = GetNextChar(); - } - - - if (quoteChar == 0) - { - while (sb.Length > 0 && IsWhiteSpace(sb[sb.Length - 1])) - sb.Length--; - } - - tokenString = sb.ToString(); - return Token.String; - } - - [DoesNotReturn] - private void ThrowInvalidAssemblyName() - => throw new FileLoadException(SR.InvalidAssemblyName, _input.ToString()); - } -} diff --git a/src/libraries/System.Reflection.Metadata/ref/System.Reflection.Metadata.cs b/src/libraries/System.Reflection.Metadata/ref/System.Reflection.Metadata.cs index d656738565288c..6eaf4ea70e61ee 100644 --- a/src/libraries/System.Reflection.Metadata/ref/System.Reflection.Metadata.cs +++ b/src/libraries/System.Reflection.Metadata/ref/System.Reflection.Metadata.cs @@ -2408,6 +2408,49 @@ public readonly partial struct TypeLayout public int PackingSize { get { throw null; } } public int Size { get { throw null; } } } + public sealed partial class AssemblyNameInfo + { + public AssemblyNameInfo(string name, System.Version? version = null, string? cultureName = null, System.Reflection.AssemblyNameFlags flags = AssemblyNameFlags.None, + Collections.Immutable.ImmutableArray publicKeyOrToken = default) { } + public string Name { get { throw null; } } + public string? CultureName { get { throw null; } } + public string FullName { get { throw null; } } + public System.Version? Version { get { throw null; } } + public System.Reflection.AssemblyNameFlags Flags { get { throw null; } } + public System.Collections.Immutable.ImmutableArray PublicKeyOrToken { get { throw null; } } + public static System.Reflection.Metadata.AssemblyNameInfo Parse(System.ReadOnlySpan assemblyName) { throw null; } + public static bool TryParse(System.ReadOnlySpan assemblyName, [System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] out System.Reflection.Metadata.AssemblyNameInfo? result) { throw null; } + public System.Reflection.AssemblyName ToAssemblyName() { throw null; } + } + public sealed partial class TypeName + { + internal TypeName() { } + public string AssemblyQualifiedName { get { throw null; } } + public AssemblyNameInfo? AssemblyName { get { throw null; } } + public System.Reflection.Metadata.TypeName? DeclaringType { get { throw null; } } + public string FullName { get { throw null; } } + public bool IsArray { get { throw null; } } + public bool IsByRef { get { throw null; } } + public bool IsConstructedGenericType { get { throw null; } } + public bool IsNested { get { throw null; } } + public bool IsPointer { get { throw null; } } + public bool IsSimple { get { throw null; } } + public bool IsSZArray { get { throw null; } } + public bool IsVariableBoundArrayType { get { throw null; } } + public string Name { get { throw null; } } + public static System.Reflection.Metadata.TypeName Parse(System.ReadOnlySpan typeName, System.Reflection.Metadata.TypeNameParseOptions? options = null) { throw null; } + public static bool TryParse(System.ReadOnlySpan typeName, [System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] out System.Reflection.Metadata.TypeName? result, System.Reflection.Metadata.TypeNameParseOptions? options = null) { throw null; } + public int GetArrayRank() { throw null; } + public System.Collections.Immutable.ImmutableArray GetGenericArguments() { throw null; } + public System.Reflection.Metadata.TypeName GetGenericTypeDefinition() { throw null; } + public System.Reflection.Metadata.TypeName GetElementType() { throw null; } + public int GetNodeCount() { throw null; } + } + public sealed partial class TypeNameParseOptions + { + public TypeNameParseOptions() { } + public int MaxNodes { get { throw null; } set { } } + } public readonly partial struct TypeReference { private readonly object _dummy; diff --git a/src/libraries/System.Reflection.Metadata/src/Resources/Strings.resx b/src/libraries/System.Reflection.Metadata/src/Resources/Strings.resx index c035a3efee098f..963e4d0af9f8a3 100644 --- a/src/libraries/System.Reflection.Metadata/src/Resources/Strings.resx +++ b/src/libraries/System.Reflection.Metadata/src/Resources/Strings.resx @@ -411,4 +411,25 @@ The SwitchInstructionEncoder.Branch method was invoked too many times. + + The name of the type is invalid. + + + Maximum node count of {0} exceeded. + + + Must be an array type. + + + This operation is only valid on generic types. + + + This operation is only valid on nested types. + + + This operation is only valid on arrays, pointers and references. + + + The given assembly name was invalid. + \ No newline at end of file diff --git a/src/libraries/System.Reflection.Metadata/src/System.Reflection.Metadata.csproj b/src/libraries/System.Reflection.Metadata/src/System.Reflection.Metadata.csproj index e713d6210651f9..266d4c6f55fddd 100644 --- a/src/libraries/System.Reflection.Metadata/src/System.Reflection.Metadata.csproj +++ b/src/libraries/System.Reflection.Metadata/src/System.Reflection.Metadata.csproj @@ -16,6 +16,7 @@ The System.Reflection.Metadata library is built-in as part of the shared framewo $(DefineConstants);FEATURE_CER + $(DefineConstants);SYSTEM_REFLECTION_METADATA @@ -250,7 +251,17 @@ The System.Reflection.Metadata library is built-in as part of the shared framewo + + + + + + + + + + diff --git a/src/libraries/System.Reflection.Metadata/tests/Metadata/AssemblyNameInfoTests.cs b/src/libraries/System.Reflection.Metadata/tests/Metadata/AssemblyNameInfoTests.cs new file mode 100644 index 00000000000000..230e051ab045cb --- /dev/null +++ b/src/libraries/System.Reflection.Metadata/tests/Metadata/AssemblyNameInfoTests.cs @@ -0,0 +1,105 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using Xunit; + +namespace System.Reflection.Metadata.Tests.Metadata +{ + public class AssemblyNameInfoTests + { + [Theory] + [InlineData("MyAssemblyName, Version=1.0.0.0, PublicKeyToken=b77a5c561934e089")] + public void WithPublicTokenKey(string fullName) + { + AssemblyName assemblyName = new AssemblyName(fullName); + + AssemblyNameInfo assemblyNameInfo = AssemblyNameInfo.Parse(fullName.AsSpan()); + + Assert.Equal(fullName, assemblyName.FullName); + Assert.Equal(fullName, assemblyNameInfo.FullName); + + Roundtrip(assemblyName); + } + + [Fact] + public void NoPublicKeyOrToken() + { + AssemblyName source = new AssemblyName(); + source.Name = "test"; + source.Version = new Version(1, 2, 3, 4); + source.CultureName = "en-US"; + + Roundtrip(source); + } + + [Theory] + [InlineData(ProcessorArchitecture.MSIL)] + [InlineData(ProcessorArchitecture.X86)] + [InlineData(ProcessorArchitecture.IA64)] + [InlineData(ProcessorArchitecture.Amd64)] + [InlineData(ProcessorArchitecture.Arm)] + public void ProcessorArchitectureIsPropagated(ProcessorArchitecture architecture) + { + string input = $"Abc, ProcessorArchitecture={architecture}"; + AssemblyNameInfo assemblyNameInfo = AssemblyNameInfo.Parse(input.AsSpan()); + + AssemblyName assemblyName = assemblyNameInfo.ToAssemblyName(); + + Assert.Equal(architecture, assemblyName.ProcessorArchitecture); + Assert.Equal(AssemblyContentType.Default, assemblyName.ContentType); + // By design (desktop compat) AssemblyName.FullName and ToString() do not include ProcessorArchitecture. + Assert.Equal(assemblyName.FullName, assemblyNameInfo.FullName); + Assert.DoesNotContain("ProcessorArchitecture", assemblyNameInfo.FullName); + } + + [Fact] + public void AssemblyContentTypeIsPropagated() + { + const string input = "Abc, ContentType=WindowsRuntime"; + AssemblyNameInfo assemblyNameInfo = AssemblyNameInfo.Parse(input.AsSpan()); + + AssemblyName assemblyName = assemblyNameInfo.ToAssemblyName(); + + Assert.Equal(AssemblyContentType.WindowsRuntime, assemblyName.ContentType); + Assert.Equal(ProcessorArchitecture.None, assemblyName.ProcessorArchitecture); + Assert.Equal(input, assemblyNameInfo.FullName); + Assert.Equal(assemblyName.FullName, assemblyNameInfo.FullName); + } + + [Fact] + public void RetargetableIsPropagated() + { + const string input = "Abc, Retargetable=Yes"; + AssemblyNameInfo assemblyNameInfo = AssemblyNameInfo.Parse(input.AsSpan()); + Assert.True((assemblyNameInfo.Flags & AssemblyNameFlags.Retargetable) != 0); + + AssemblyName assemblyName = assemblyNameInfo.ToAssemblyName(); + + Assert.True((assemblyName.Flags & AssemblyNameFlags.Retargetable) != 0); + Assert.Equal(AssemblyContentType.Default, assemblyName.ContentType); + Assert.Equal(ProcessorArchitecture.None, assemblyName.ProcessorArchitecture); + Assert.Equal(input, assemblyNameInfo.FullName); + Assert.Equal(assemblyName.FullName, assemblyNameInfo.FullName); + } + + [Fact] + public void EscapedSquareBracketIsNotAllowedInTheName() + => Assert.False(AssemblyNameInfo.TryParse("Esc\\[aped".AsSpan(), out _)); + + static void Roundtrip(AssemblyName source) + { + AssemblyNameInfo parsed = AssemblyNameInfo.Parse(source.FullName.AsSpan()); + Assert.Equal(source.Name, parsed.Name); + Assert.Equal(source.Version, parsed.Version); + Assert.Equal(source.CultureName, parsed.CultureName); + Assert.Equal(source.FullName, parsed.FullName); + + AssemblyName fromParsed = parsed.ToAssemblyName(); + Assert.Equal(source.Name, fromParsed.Name); + Assert.Equal(source.Version, fromParsed.Version); + Assert.Equal(source.CultureName, fromParsed.CultureName); + Assert.Equal(source.FullName, fromParsed.FullName); + Assert.Equal(source.GetPublicKeyToken(), fromParsed.GetPublicKeyToken()); + } + } +} diff --git a/src/libraries/System.Reflection.Metadata/tests/Metadata/TypeNameParserHelpersTests.cs b/src/libraries/System.Reflection.Metadata/tests/Metadata/TypeNameParserHelpersTests.cs new file mode 100644 index 00000000000000..b9d23a2be15244 --- /dev/null +++ b/src/libraries/System.Reflection.Metadata/tests/Metadata/TypeNameParserHelpersTests.cs @@ -0,0 +1,173 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Linq; +using System.Text; +using Xunit; + +namespace System.Reflection.Metadata.Tests +{ + public class TypeNameParserHelpersTests + { + [Theory] + [InlineData("A[]", 1, false)] + [InlineData("AB[a,b]", 2, false)] + [InlineData("AB[[a, b],[c,d]]", 2, false)] + [InlineData("12]]", 2, false)] + [InlineData("ABC&", 3, false)] + [InlineData("ABCD*", 4, false)] + [InlineData("ABCDE,otherType]]", 5, false)] + [InlineData("Containing+Nested", 10, true)] + [InlineData("NoSpecial.Characters", 20, false)] + [InlineData("Requires\\+Escaping", 18, false)] + [InlineData("Requires\\[Escaping+Nested", 18, true)] + [InlineData("Worst\\[\\]\\&\\*\\,\\+Case", 21, false)] + [InlineData("EscapingSthThatShouldNotBeEscaped\\A", -1 , false)] + [InlineData("EndsWithEscaping\\", -1, false)] + public void GetFullTypeNameLengthReturnsExpectedValue(string input, int expected, bool expectedIsNested) + { + Assert.Equal(expected, TypeNameParserHelpers.GetFullTypeNameLength(input.AsSpan(), out bool isNested)); + Assert.Equal(expectedIsNested, isNested); + + string withNamespace = $"Namespace1.Namespace2.Namespace3.{input}"; + int expectedWithNamespace = expected < 0 ? expected : expected + withNamespace.Length - input.Length; + Assert.Equal(expectedWithNamespace, TypeNameParserHelpers.GetFullTypeNameLength(withNamespace.AsSpan(), out isNested)); + Assert.Equal(expectedIsNested, isNested); + } + + [Theory] + [InlineData("JustTypeName", "JustTypeName")] + [InlineData("Namespace.TypeName", "TypeName")] + [InlineData("Namespace1.Namespace2.TypeName", "TypeName")] + [InlineData("Namespace.NotNamespace\\.TypeName", "NotNamespace\\.TypeName")] + [InlineData("Namespace1.Namespace2.Containing+Nested", "Nested")] + [InlineData("Namespace1.Namespace2.Not\\+Nested", "Not\\+Nested")] + [InlineData("NotNamespace1\\.NotNamespace2\\.TypeName", "NotNamespace1\\.NotNamespace2\\.TypeName")] + [InlineData("NotNamespace1\\.NotNamespace2\\.Not\\+Nested", "NotNamespace1\\.NotNamespace2\\.Not\\+Nested")] + public void GetNameReturnsJustName(string fullName, string expected) + => Assert.Equal(expected, TypeNameParserHelpers.GetName(fullName.AsSpan()).ToString()); + + [Theory] + [InlineData("simple", "simple")] + [InlineData("simple]", "simple")] + [InlineData("esc\\]aped", "esc\\]aped")] + [InlineData("esc\\]aped]", "esc\\]aped")] + public void GetAssemblyNameCandidateReturnsExpectedValue(string input, string expected) + => Assert.Equal(expected, TypeNameParserHelpers.GetAssemblyNameCandidate(input.AsSpan()).ToString()); + + [Theory] + [InlineData(TypeNameParserHelpers.SZArray, "[]")] + [InlineData(TypeNameParserHelpers.Pointer, "*")] + [InlineData(TypeNameParserHelpers.ByRef, "&")] + [InlineData(1, "[*]")] + [InlineData(2, "[,]")] + [InlineData(3, "[,,]")] + [InlineData(4, "[,,,]")] + public void AppendRankOrModifierStringRepresentationAppendsExpectedString(int input, string expected) + { + ValueStringBuilder builder = new ValueStringBuilder(initialCapacity: 10); + Assert.Equal(expected, TypeNameParserHelpers.GetRankOrModifierStringRepresentation(input, ref builder)); + } + + [Theory] + [InlineData(typeof(List))] + [InlineData(typeof(int?))] + [InlineData(typeof(List))] + [InlineData(typeof(Dictionary))] + [InlineData(typeof(ValueTuple))] + [InlineData(typeof(ValueTuple))] + public void GetGenericTypeFullNameReturnsSameStringAsTypeAPI(Type genericType) + { + TypeName openGenericTypeName = TypeName.Parse(genericType.GetGenericTypeDefinition().FullName.AsSpan()); + ReadOnlySpan genericArgNames = genericType.GetGenericArguments().Select(arg => TypeName.Parse(arg.AssemblyQualifiedName.AsSpan())).ToArray(); + + Assert.Equal(genericType.FullName, TypeNameParserHelpers.GetGenericTypeFullName(openGenericTypeName.FullName.AsSpan(), genericArgNames)); + } + + [Theory] + [InlineData("", false, false, "")] + [InlineData("[", false, false, "[")] // too little to be able to tell + [InlineData("[[", true, true, "")] + [InlineData("[[A],[B]]", true, true, "A],[B]]")] + [InlineData("[ [ A],[B]]", true, true, "A],[B]]")] + [InlineData("[\t[\t \r\nA],[B]]", true, true, "A],[B]]")] // whitespaces other than ' ' + [InlineData("[A,B]", true, false, "A,B]")] + [InlineData("[ A,B]", true, false, "A,B]")] + [InlineData("[]", false, false, "[]")] + [InlineData("[*]", false, false, "[*]")] + [InlineData("[,]", false, false, "[,]")] + [InlineData("[,,]", false, false, "[,,]")] + public void IsBeginningOfGenericAgsHandlesAllCasesProperly(string input, bool expectedResult, bool expectedDoubleBrackets, string expectedConsumedInput) + { + ReadOnlySpan inputSpan = input.AsSpan(); + + Assert.Equal(expectedResult, TypeNameParserHelpers.IsBeginningOfGenericArgs(ref inputSpan, out bool doubleBrackets)); + Assert.Equal(expectedDoubleBrackets, doubleBrackets); + Assert.Equal(expectedConsumedInput, inputSpan.ToString()); + } + + [Theory] + [InlineData("A.B.C", true, null, 5)] + [InlineData("A.B.C\\", false, null, 0)] // invalid type name: ends with escape character + [InlineData("A.B.C\\DoeNotNeedEscaping", false, null, 0)] // invalid type name: escapes non-special character + [InlineData("A.B+C", true, new int[] { 3 }, 5)] + [InlineData("A.B++C", false, null, 0)] // invalid type name: two following, unescaped + + [InlineData("A.B`1", true, null, 5)] + [InlineData("A+B`1+C1`2+DD2`3+E", true, new int[] { 1, 3, 4, 5 }, 18)] + [InlineData("Integer`2147483646+NoOverflow`1", true, new int[] { 18 }, 31)] + [InlineData("Integer`2147483647+Overflow`1", true, new int[] { 18 }, 29)] + public void TryGetTypeNameInfoGetsAllTheInfo(string input, bool expectedResult, int[] expectedNestedNameLengths, int expectedTotalLength) + { + List? nestedNameLengths = null; + ReadOnlySpan span = input.AsSpan(); + bool result = TypeNameParserHelpers.TryGetTypeNameInfo(ref span, ref nestedNameLengths, out int totalLength); + + Assert.Equal(expectedResult, result); + + if (expectedResult) + { + Assert.Equal(expectedNestedNameLengths, nestedNameLengths?.ToArray()); + Assert.Equal(expectedTotalLength, totalLength); + } + } + + [Theory] + [InlineData("*", true, TypeNameParserHelpers.Pointer, "")] + [InlineData(" *", false, default(int), " *")] // Whitespace cannot precede the decorator + [InlineData("* *", true, TypeNameParserHelpers.Pointer, "*")] // but it can follow the decorator. + [InlineData("&", true, TypeNameParserHelpers.ByRef, "")] + [InlineData("\t&", false, default(int), "\t&")] + [InlineData("&\t\r\n[]", true, TypeNameParserHelpers.ByRef, "[]")] + [InlineData("[]", true, TypeNameParserHelpers.SZArray, "")] + [InlineData("\r\n[]", false, default(int), "\r\n[]")] + [InlineData("[] []", true, TypeNameParserHelpers.SZArray, "[]")] + [InlineData("[,]", true, 2, "")] + [InlineData(" [,,,]", false, default(int), " [,,,]")] + [InlineData("[,,,,] *[]", true, 5, "*[]")] + public void TryParseNextDecoratorParsesTheDecoratorAndConsumesFollowingWhitespaces( + string input, bool expectedResult, int expectedModifier, string expectedConsumedInput) + { + ReadOnlySpan inputSpan = input.AsSpan(); + + Assert.Equal(expectedResult, TypeNameParserHelpers.TryParseNextDecorator(ref inputSpan, out int parsedModifier)); + Assert.Equal(expectedModifier, parsedModifier); + Assert.Equal(expectedConsumedInput, inputSpan.ToString()); + } + + [Theory] + [InlineData(" , ", ',', false, " , ")] // it can not start with a whitespace + [InlineData("AB", ',', false, "AB")] // does not start with given character + [InlineData(", ", ',', true, "")] // trimming + [InlineData(",[AB]", ',', true, "[AB]")] // nothing to trim + public void TryStripFirstCharAndTrailingSpacesWorksAsExpected( + string input, char argument, bool expectedResult, string expectedConsumedInput) + { + ReadOnlySpan inputSpan = input.AsSpan(); + + Assert.Equal(expectedResult, TypeNameParserHelpers.TryStripFirstCharAndTrailingSpaces(ref inputSpan, argument)); + Assert.Equal(expectedConsumedInput, inputSpan.ToString()); + } + } +} diff --git a/src/libraries/System.Reflection.Metadata/tests/Metadata/TypeNameParserSamples.cs b/src/libraries/System.Reflection.Metadata/tests/Metadata/TypeNameParserSamples.cs new file mode 100644 index 00000000000000..0c48cdc2641d97 --- /dev/null +++ b/src/libraries/System.Reflection.Metadata/tests/Metadata/TypeNameParserSamples.cs @@ -0,0 +1,255 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Runtime.Serialization; +using System.Runtime.Serialization.Formatters.Binary; +using Xunit; + +namespace System.Reflection.Metadata.Tests +{ + public class TypeNameParserSamples + { + internal sealed class SampleSerializationBinder : SerializationBinder + { + private static TypeNameParseOptions _options; + + // we could use Frozen collections here ;) + private readonly static Dictionary _alwaysAllowed = new() + { + { typeof(string).FullName, typeof(string) }, + { typeof(int).FullName, typeof(int) }, + { typeof(uint).FullName, typeof(uint) }, + { typeof(long).FullName, typeof(long) }, + { typeof(ulong).FullName, typeof(ulong) }, + { typeof(double).FullName, typeof(double) }, + { typeof(float).FullName, typeof(float) }, + { typeof(bool).FullName, typeof(bool) }, + { typeof(short).FullName, typeof(short) }, + { typeof(ushort).FullName, typeof(ushort) }, + { typeof(byte).FullName, typeof(byte) }, + { typeof(char).FullName, typeof(char) }, + { typeof(DateTime).FullName, typeof(DateTime) }, + { typeof(TimeSpan).FullName, typeof(TimeSpan) }, + { typeof(Guid).FullName, typeof(Guid) }, + { typeof(Uri).FullName, typeof(Uri) }, + { typeof(DateTimeOffset).FullName, typeof(DateTimeOffset) }, + { typeof(Version).FullName, typeof(Version) }, + { typeof(Nullable).FullName, typeof(Nullable) }, // Nullable is generic! + }; + + private readonly Dictionary? _userDefined; + + public SampleSerializationBinder(Type[]? allowedTypes = null) + => _userDefined = allowedTypes?.ToDictionary(type => type.FullName); + + public override Type? BindToType(string assemblyName, string typeName) + { + // Fast path for common primitive type names and user-defined type names + // that use the same syntax and casing as System.Type.FullName API. + if (TryGetTypeFromFullName(typeName, out Type type)) + { + return type; + } + + _options ??= new TypeNameParseOptions() // there is no need for lazy initialization, I just wanted to have everything important in one method + { + // To prevent from unbounded recursion, we set the max depth for parser options. + // By ensuring that the max depth limit is enforced, we can safely use recursion in + // GetTypeFromParsedTypeName to get arrays of arrays and generics of generics. + MaxNodes = 10 + }; + + if (!TypeName.TryParse(typeName.AsSpan(), out TypeName parsed, _options)) + { + // we can throw any exception, log the information etc + throw new InvalidOperationException($"Invalid type name: '{typeName}'"); + } + + if (parsed.AssemblyName is not null) + { + // The attackers may create such a payload, + // where "typeName" passed to BindToType contains the assembly name + // and "assemblyName" passed to this method contains something else + // (some garbage or a different assembly name). Example: + // typeName: System.Int32, MyHackyDll.dll + // assemblyName: mscorlib.dll + throw new InvalidOperationException($"Type name '{typeName}' contained assembly name."); + } + + return GetTypeFromParsedTypeName(parsed); + } + + private Type? GetTypeFromParsedTypeName(TypeName parsed) + { + if (TryGetTypeFromFullName(parsed.FullName, out Type type)) + { + return type; + } + else if (parsed.IsArray) + { + TypeName arrayElementTypeName = parsed.GetElementType(); + Type arrayElementType = GetTypeFromParsedTypeName(arrayElementTypeName); // recursive call allows for creating arrays of arrays etc + + return parsed.IsSZArray + ? arrayElementType.MakeArrayType() + : arrayElementType.MakeArrayType(parsed.GetArrayRank()); + } + else if (parsed.IsConstructedGenericType) + { + TypeName genericTypeDefinitionName = parsed.GetGenericTypeDefinition(); + Type genericTypeDefinition = GetTypeFromParsedTypeName(genericTypeDefinitionName); + Debug.Assert(genericTypeDefinition.IsGenericTypeDefinition); + + ImmutableArray genericArgs = parsed.GetGenericArguments(); + Type[] typeArguments = new Type[genericArgs.Length]; + for (int i = 0; i < genericArgs.Length; i++) + { + typeArguments[i] = GetTypeFromParsedTypeName(genericArgs[i]); // recursive call allows for generics of generics like "List" + } + return genericTypeDefinition.MakeGenericType(typeArguments); + } + + throw new ArgumentException($"{parsed.FullName} is not on the allow list."); + } + + private bool TryGetTypeFromFullName(string fullName, out Type? type) + => _alwaysAllowed.TryGetValue(fullName, out type) + || (_userDefined is not null && _userDefined.TryGetValue(fullName, out type)); + } + + [Serializable] + public class CustomUserDefinedType + { + public int Integer { get; set; } + public string Text { get; set; } + public List ListOfDates { get; set; } + public CustomUserDefinedType[] ArrayOfCustomUserDefinedTypes { get; set; } + } + + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsBinaryFormatterSupported))] + public void CanDeserializeCustomUserDefinedType() + { + CustomUserDefinedType parent = new() + { + Integer = 1, + Text = "parent", + ListOfDates = new List() + { + DateTime.Parse("02/06/2024") + }, + ArrayOfCustomUserDefinedTypes = new [] + { + new CustomUserDefinedType() + { + Integer = 2, + Text = "child" + } + } + }; + SampleSerializationBinder binder = new( + allowedTypes: + [ + typeof(CustomUserDefinedType), + typeof(List<>) // using List would require using type forwarding info in dictionary + ]); + + CustomUserDefinedType deserialized = SerializeDeserialize(parent, binder); + + Assert.Equal(parent.Integer, deserialized.Integer); + Assert.Equal(parent.Text, deserialized.Text); + Assert.Equal(parent.ListOfDates.Count, deserialized.ListOfDates.Count); + for (int i = 0; i < deserialized.ListOfDates.Count; i++) + { + Assert.Equal(parent.ListOfDates[i], deserialized.ListOfDates[i]); + } + Assert.Equal(parent.ArrayOfCustomUserDefinedTypes.Length, deserialized.ArrayOfCustomUserDefinedTypes.Length); + for (int i = 0; i < deserialized.ArrayOfCustomUserDefinedTypes.Length; i++) + { + Assert.Equal(parent.ArrayOfCustomUserDefinedTypes[i].Integer, deserialized.ArrayOfCustomUserDefinedTypes[i].Integer); + Assert.Equal(parent.ArrayOfCustomUserDefinedTypes[i].Text, deserialized.ArrayOfCustomUserDefinedTypes[i].Text); + } + } + + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsBinaryFormatterSupported))] + public void CanDeserializeDictionaryUsingNonPublicComparerType() + { + Dictionary dictionary = new(StringComparer.CurrentCulture) + { + { "test", 1 } + }; + SampleSerializationBinder binder = new( + allowedTypes: + [ + typeof(Dictionary<,>), // this could be Dictionary to be more strict + StringComparer.CurrentCulture.GetType(), // this type is not public, this is all this test is about + typeof(Globalization.CompareOptions), + typeof(Globalization.CompareInfo), + typeof(KeyValuePair<,>), // this could be KeyValuePair to be more strict + ]); + + Dictionary deserialized = SerializeDeserialize(dictionary, binder); + + Assert.Equal(dictionary, deserialized); + } + + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsBinaryFormatterSupported))] + public void CanDeserializeArraysOfArrays() + { + int[][] arrayOfArrays = new int[10][]; + for (int i = 0; i < arrayOfArrays.Length; i++) + { + arrayOfArrays[i] = Enumerable.Repeat(i, 10).ToArray(); + } + + SampleSerializationBinder binder = new(); + int[][] deserialized = SerializeDeserialize(arrayOfArrays, binder); + + Assert.Equal(arrayOfArrays.Length, deserialized.Length); + for (int i = 0; i < arrayOfArrays.Length; i++) + { + Assert.Equal(arrayOfArrays[i], deserialized[i]); + } + } + + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsBinaryFormatterSupported))] + public void CanDeserializeListOfListOfInt() + { + List> listOfListOfInts = new(10); + for (int i = 0; i < listOfListOfInts.Count; i++) + { + listOfListOfInts[i] = Enumerable.Repeat(i, 10).ToList(); + } + + SampleSerializationBinder binder = new(allowedTypes: + [ + typeof(List<>) + ]); + List> deserialized = SerializeDeserialize(listOfListOfInts, binder); + + Assert.Equal(listOfListOfInts.Count, deserialized.Count); + for (int i = 0; i < listOfListOfInts.Count; i++) + { + Assert.Equal(listOfListOfInts[i], deserialized[i]); + } + } + + static T SerializeDeserialize(T instance, SerializationBinder binder) + { + using MemoryStream bfStream = new(); + BinaryFormatter bf = new() + { + Binder = binder + }; + + bf.Serialize(bfStream, instance); + bfStream.Position = 0; + + return (T)bf.Deserialize(bfStream); + } + } +} diff --git a/src/libraries/System.Reflection.Metadata/tests/Metadata/TypeNameTests.cs b/src/libraries/System.Reflection.Metadata/tests/Metadata/TypeNameTests.cs new file mode 100644 index 00000000000000..53f8e43821bc61 --- /dev/null +++ b/src/libraries/System.Reflection.Metadata/tests/Metadata/TypeNameTests.cs @@ -0,0 +1,748 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using System.Reflection.Emit; +using Xunit; + +namespace System.Reflection.Metadata.Tests +{ + public class TypeNameTests + { + [Theory] + [InlineData(" System.Int32", "System.Int32", "Int32")] + [InlineData(" MyNamespace.MyType+NestedType", "MyNamespace.MyType+NestedType", "NestedType")] + public void SpacesAtTheBeginningAreOK(string input, string expectedFullName, string expectedName) + { + TypeName parsed = TypeName.Parse(input.AsSpan()); + + Assert.Equal(expectedName, parsed.Name); + Assert.Equal(expectedFullName, parsed.FullName); + Assert.Equal(expectedFullName, parsed.AssemblyQualifiedName); + } + + [Fact] + public void LeadingDotIsNotConsumedForFullTypeNamesWithoutNamespace() + { + // This is true only for the public API. + // The internal CoreLib implementation consumes the leading dot for backward compat. + TypeName parsed = TypeName.Parse(".NoNamespace".AsSpan()); + + Assert.Equal("NoNamespace", parsed.Name); + Assert.Equal(".NoNamespace", parsed.FullName); + Assert.Equal(".NoNamespace", parsed.AssemblyQualifiedName); + } + + [Theory] + [InlineData("")] + [InlineData(" ")] + [InlineData(" ")] + public void EmptyStringsAreNotAllowed(string input) + { + Assert.Throws(() => TypeName.Parse(input.AsSpan())); + + Assert.False(TypeName.TryParse(input.AsSpan(), out _)); + } + + [Theory] + [InlineData("Namespace.Containing++Nested")] // a pair of '++' + [InlineData("TypeNameFollowedBySome[] unconsumedCharacters")] + [InlineData("MissingAssemblyName, ")] + [InlineData("ExtraComma, ,")] + [InlineData("ExtraComma, , System.Runtime")] + [InlineData("UsingGenericSyntaxButNotProvidingGenericArgs[[]]")] + [InlineData("ExtraCommaAfterFirstGenericArg`1[[type1, assembly1],]")] + [InlineData("MissingClosingSquareBrackets`1[[type1, assembly1")] // missing ]] + [InlineData("MissingClosingSquareBracket`1[[type1, assembly1]")] // missing ] + [InlineData("MissingClosingSquareBracketsMixedMode`2[[type1, assembly1], type2")] // missing ] + [InlineData("MissingClosingSquareBrackets`2[[type1, assembly1], [type2, assembly2")] // missing ] + [InlineData("MissingClosingSquareBracketsMixedMode`2[type1, [type2, assembly2")] // missing ]] + [InlineData("MissingClosingSquareBracketsMixedMode`2[type1, [type2, assembly2]")] // missing ] + [InlineData("EscapeCharacterAtTheEnd\\")] + [InlineData("EscapeNonSpecialChar\\a")] + [InlineData("EscapeNonSpecialChar\\0")] + [InlineData("DoubleNestingChar++Bla")] + public void InvalidTypeNamesAreNotAllowed(string input) + { + Assert.Throws(() => TypeName.Parse(input.AsSpan())); + + Assert.False(TypeName.TryParse(input.AsSpan(), out _)); + } + + [Theory] + [InlineData("System.Int32&&")] // by-ref to by-ref is currently not supported by CLR + [InlineData("System.Int32[,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,]")] // more than max array rank (32) + public void ParserIsNotEnforcingRuntimeSpecificRules(string input) + { + Assert.True(TypeName.TryParse(input.AsSpan(), out _)); + + if (PlatformDetection.IsNotMonoRuntime) // https://github.com/dotnet/runtime/issues/45033 + { +#if NETCOREAPP + Assert.Throws(() => Type.GetType(input)); +#endif + } + } + + [Theory] + [InlineData("Namespace.Kość", "Namespace.Kość")] + public void UnicodeCharactersAreAllowedByDefault(string input, string expectedFullName) + => Assert.Equal(expectedFullName, TypeName.Parse(input.AsSpan()).FullName); + + [Theory] + [InlineData(typeof(int))] + [InlineData(typeof(Dictionary))] + [InlineData(typeof(int[][]))] + [InlineData(typeof(Assert))] // xUnit assembly + [InlineData(typeof(TypeNameTests))] // test assembly + [InlineData(typeof(NestedGeneric_0.NestedGeneric_1.NestedGeneric_2.NestedNonGeneric_3))] + public void TypeNameCanContainAssemblyName(Type type) + { + AssemblyName expectedAssemblyName = new(type.Assembly.FullName); + + Verify(type, expectedAssemblyName, TypeName.Parse(type.AssemblyQualifiedName.AsSpan())); + + static void Verify(Type type, AssemblyName expectedAssemblyName, TypeName parsed) + { + Assert.Equal(type.AssemblyQualifiedName, parsed.AssemblyQualifiedName); + Assert.Equal(type.FullName, parsed.FullName); + Assert.Equal(type.Name, parsed.Name); + + AssemblyNameInfo parsedAssemblyName = parsed.AssemblyName; + Assert.NotNull(parsedAssemblyName); + + Assert.Equal(expectedAssemblyName.Name, parsedAssemblyName.Name); + Assert.Equal(expectedAssemblyName.Version, parsedAssemblyName.Version); + Assert.Equal(expectedAssemblyName.CultureName, parsedAssemblyName.CultureName); + Assert.Equal(expectedAssemblyName.FullName, parsedAssemblyName.FullName); + + Assert.Equal(default, parsedAssemblyName.Flags); + } + } + + [Theory] + [InlineData(10, "*")] // pointer to pointer + [InlineData(10, "[]")] // array of arrays + [InlineData(100, "*")] + [InlineData(100, "[]")] + public void MaxNodesIsRespected_TooManyDecorators(int maxDepth, string decorator) + { + TypeNameParseOptions options = new() + { + MaxNodes = maxDepth + }; + + string notTooMany = $"System.Int32{string.Join("", Enumerable.Repeat(decorator, maxDepth - 1))}"; + string tooMany = $"System.Int32{string.Join("", Enumerable.Repeat(decorator, maxDepth))}"; + + Assert.Throws(() => TypeName.Parse(tooMany.AsSpan(), options)); + Assert.False(TypeName.TryParse(tooMany.AsSpan(), out _, options)); + + TypeName parsed = TypeName.Parse(notTooMany.AsSpan(), options); + ValidateElementType(maxDepth, parsed, decorator); + + Assert.True(TypeName.TryParse(notTooMany.AsSpan(), out parsed, options)); + ValidateElementType(maxDepth, parsed, decorator); + + static void ValidateElementType(int maxDepth, TypeName parsed, string decorator) + { + for (int i = 0; i < maxDepth - 1; i++) + { + Assert.Equal(decorator == "*", parsed.IsPointer); + Assert.Equal(decorator == "[]", parsed.IsSZArray); + Assert.False(parsed.IsConstructedGenericType); + + parsed = parsed.GetElementType(); + } + } + } + + [Theory] + [InlineData(10)] + [InlineData(100)] + public void MaxNodesIsRespected_TooDeepGenerics(int maxDepth) + { + TypeNameParseOptions options = new() + { + MaxNodes = maxDepth + }; + + string tooDeep = GetName(maxDepth); + string notTooDeep = GetName(maxDepth - 1); + + Assert.Throws(() => TypeName.Parse(tooDeep.AsSpan(), options)); + Assert.False(TypeName.TryParse(tooDeep.AsSpan(), out _, options)); + + TypeName parsed = TypeName.Parse(notTooDeep.AsSpan(), options); + Validate(maxDepth, parsed); + + Assert.True(TypeName.TryParse(notTooDeep.AsSpan(), out parsed, options)); + Validate(maxDepth, parsed); + + static string GetName(int depth) + { + // MakeGenericType is not used here, as it crashes for larger depths + string coreLibName = typeof(object).Assembly.FullName; + string fullName = typeof(int).AssemblyQualifiedName!; + for (int i = 0; i < depth; i++) + { + fullName = $"System.Collections.Generic.List`1[[{fullName}]], {coreLibName}"; + } + return fullName; + } + + static void Validate(int maxDepth, TypeName parsed) + { + for (int i = 0; i < maxDepth - 1; i++) + { + Assert.True(parsed.IsConstructedGenericType); + parsed = parsed.GetGenericArguments()[0]; + } + } + } + + [Theory] + [InlineData(10)] + [InlineData(100)] + public void MaxNodesIsRespected_TooManyGenericArguments(int maxDepth) + { + TypeNameParseOptions options = new() + { + MaxNodes = maxDepth + }; + + string tooMany = GetName(maxDepth); + string notTooMany = GetName(maxDepth - 1); + + Assert.Throws(() => TypeName.Parse(tooMany.AsSpan(), options)); + Assert.False(TypeName.TryParse(tooMany.AsSpan(), out _, options)); + + TypeName parsed = TypeName.Parse(notTooMany.AsSpan(), options); + Validate(parsed, maxDepth); + + Assert.True(TypeName.TryParse(notTooMany.AsSpan(), out parsed, options)); + Validate(parsed, maxDepth); + + static string GetName(int depth) + => $"Some.GenericType`{depth}[{string.Join(",", Enumerable.Repeat("System.Int32", depth))}]"; + + static void Validate(TypeName parsed, int maxDepth) + { + Assert.True(parsed.IsConstructedGenericType); + ImmutableArray genericArgs = parsed.GetGenericArguments(); + Assert.Equal(maxDepth - 1, genericArgs.Length); + Assert.All(genericArgs, arg => Assert.False(arg.IsConstructedGenericType)); + } + } + + public static IEnumerable GenericArgumentsAreSupported_Arguments() + { + yield return new object[] + { + "Generic`1[[A]]", + "Generic`1", + "Generic`1[[A]]", + new string[] { "A" }, + null + }; + yield return new object[] + { + "Generic`1[A]", + "Generic`1", + "Generic`1[[A]]", + new string[] { "A" }, + null + }; + yield return new object[] + { + "Generic`3[[A],[B],[C]]", + "Generic`3", + "Generic`3[[A],[B],[C]]", + new string[] { "A", "B", "C" }, + null + }; + yield return new object[] + { + "Generic`3[A,B,C]", + "Generic`3", + "Generic`3[[A],[B],[C]]", + new string[] { "A", "B", "C" }, + null + }; + yield return new object[] + { + "Generic`1[[System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]", + "Generic`1", + "Generic`1[[System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]", + new string[] { "System.Int32" }, + new AssemblyName[] { new AssemblyName("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089") } + }; + yield return new object[] + { + "Generic`2[[System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.Boolean, mscorlib, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]", + "Generic`2", + "Generic`2[[System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.Boolean, mscorlib, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]", + new string[] { "System.Int32", "System.Boolean" }, + new AssemblyName[] + { + new AssemblyName("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"), + new AssemblyName("mscorlib, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089") + } + }; + yield return new object[] + { + "Generic`2[[System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089], System.Boolean]", + "Generic`2", + "Generic`2[[System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.Boolean]]", + new string[] { "System.Int32", "System.Boolean" }, + new AssemblyName[] + { + new AssemblyName("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"), + null + } + }; + yield return new object[] + { + "Generic`2[System.Boolean, [System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]", + "Generic`2", + "Generic`2[[System.Boolean],[System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]", + new string[] { "System.Boolean", "System.Int32" }, + new AssemblyName[] + { + null, + new AssemblyName("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089") + } + }; + yield return new object[] + { + "Generic`3[[System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089], System.Boolean, [System.Byte, other, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]", + "Generic`3", + "Generic`3[[System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.Boolean],[System.Byte, other, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]", + new string[] { "System.Int32", "System.Boolean", "System.Byte" }, + new AssemblyName[] + { + new AssemblyName("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"), + null, + new AssemblyName("other, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089") + } + }; + yield return new object[] + { + "Generic`3[System.Boolean, [System.Byte, other, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089], System.Int32]", + "Generic`3", + "Generic`3[[System.Boolean],[System.Byte, other, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.Int32]]", + new string[] { "System.Boolean", "System.Byte", "System.Int32" }, + new AssemblyName[] + { + null, + new AssemblyName("other, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"), + null + } + }; + } + + [Theory] + [MemberData(nameof(GenericArgumentsAreSupported_Arguments))] + public void GenericArgumentsAreSupported(string input, string name, string fullName, string[] genericTypesFullNames, AssemblyName[]? assemblyNames) + { + TypeName parsed = TypeName.Parse(input.AsSpan()); + + Assert.Equal(name, parsed.Name); + Assert.Equal(fullName, parsed.FullName); + Assert.True(parsed.IsConstructedGenericType); + Assert.NotNull(parsed.GetGenericTypeDefinition()); + Assert.False(parsed.IsSimple); + + ImmutableArray typeNames = parsed.GetGenericArguments(); + for (int i = 0; i < genericTypesFullNames.Length; i++) + { + TypeName genericArg = typeNames[i]; + Assert.Equal(genericTypesFullNames[i], genericArg.FullName); + Assert.True(genericArg.IsSimple); + Assert.False(genericArg.IsConstructedGenericType); + Assert.Throws(genericArg.GetGenericTypeDefinition); + + if (assemblyNames is not null) + { + if (assemblyNames[i] is null) + { + Assert.Null(genericArg.AssemblyName); + } + else + { + Assert.Equal(assemblyNames[i].FullName, genericArg.AssemblyName.FullName); + Assert.Equal(assemblyNames[i].Name, genericArg.AssemblyName.Name); + } + } + } + } + + public static IEnumerable DecoratorsAreSupported_Arguments() + { + yield return new object[] + { + "TypeName*", "TypeName", false, false, -1, false, true + }; + yield return new object[] + { + "TypeName&", "TypeName", false, false, -1, true, false + }; + yield return new object[] + { + "TypeName[]", "TypeName", true, true, 1, false, false + }; + yield return new object[] + { + "TypeName[*]", "TypeName", true, false, 1, false, false + }; + yield return new object[] + { + "TypeName[,,,]", "TypeName", true, false, 4, false, false + }; + } + + [Theory] + [MemberData(nameof(DecoratorsAreSupported_Arguments))] + public void DecoratorsAreSupported(string input, string typeNameWithoutDecorators, bool isArray, bool isSzArray, int arrayRank, bool isByRef, bool isPointer) + { + TypeName parsed = TypeName.Parse(input.AsSpan()); + + Assert.Equal(input, parsed.FullName); + Assert.Equal(isArray, parsed.IsArray); + Assert.Equal(isSzArray, parsed.IsSZArray); + if (isArray) + { + Assert.Equal(arrayRank, parsed.GetArrayRank()); + } + else + { + Assert.Throws(() => parsed.GetArrayRank()); + } + Assert.Equal(isByRef, parsed.IsByRef); + Assert.Equal(isPointer, parsed.IsPointer); + Assert.False(parsed.IsSimple); + + TypeName elementType = parsed.GetElementType(); + Assert.NotNull(elementType); + Assert.Equal(typeNameWithoutDecorators, elementType.FullName); + Assert.True(elementType.IsSimple); + Assert.False(elementType.IsArray); + Assert.False(elementType.IsSZArray); + Assert.False(elementType.IsByRef); + Assert.False(elementType.IsPointer); + Assert.Throws(elementType.GetElementType); + } + + public static IEnumerable GetAdditionalConstructedTypeData() + { + yield return new object[] { typeof(Dictionary[,], List>[]), 16 }; + + // "Dictionary[,], List>[]" breaks down to complexity 16 like so: + // + // 01: Dictionary[,], List>[] + // 02: `- Dictionary[,], List> + // 03: +- Dictionary`2 + // 04: +- List[,] + // 05: | `- List + // 06: | +- List`1 + // 07: | `- int[] + // 08: | `- int + // 09: `- List + // 10: +- List`1 + // 11: `- int?[][][,] + // 12: `- int?[][] + // 13: `- int?[] + // 14: `- int? + // 15: +- Nullable`1 + // 16: `- int + + yield return new object[] { typeof(int[]).MakePointerType().MakeByRefType(), 4 }; // int[]*& + yield return new object[] { typeof(long).MakeArrayType(31), 2 }; // long[,,,,,,,...] + yield return new object[] { typeof(long).Assembly.GetType("System.Int64[*]"), 2 }; // long[*] + } + + [Theory] + [InlineData(typeof(TypeName), 1)] + [InlineData(typeof(TypeNameTests), 1)] + [InlineData(typeof(object), 1)] + [InlineData(typeof(Assert), 1)] // xunit + [InlineData(typeof(int[]), 2)] + [InlineData(typeof(int[,][]), 3)] + [InlineData(typeof(Nullable<>), 1)] // open generic type treated as elemental + [InlineData(typeof(NestedNonGeneric_0), 2)] // declaring and nested + [InlineData(typeof(NestedGeneric_0), 3)] // declaring, nested and generic arg + [InlineData(typeof(NestedNonGeneric_0.NestedNonGeneric_1), 3)] // declaring, nested 0 and nested 1 + // TypeNameTests+NestedGeneric_0`1+NestedGeneric_1`2[[Int32],[String],[Boolean]] (simplified for brevity) + [InlineData(typeof(NestedGeneric_0.NestedGeneric_1), 6)] // declaring, nested 0 and nested 1 and 3 generic args + [MemberData(nameof(GetAdditionalConstructedTypeData))] + public void GetNodeCountReturnsExpectedValue(Type type, int expected) + { + TypeName parsed = TypeName.Parse(type.AssemblyQualifiedName.AsSpan()); + + Assert.Equal(expected, parsed.GetNodeCount()); + + Assert.Equal(type.Name, parsed.Name); + Assert.Equal(type.FullName, parsed.FullName); + Assert.Equal(type.AssemblyQualifiedName, parsed.AssemblyQualifiedName); + } + + [Fact] + public void IsSimpleReturnsTrueForNestedNonGenericTypes() + { + Assert.True(TypeName.Parse("Containing+Nested".AsSpan()).IsSimple); + Assert.False(TypeName.Parse(typeof(NestedGeneric_0).FullName.AsSpan()).IsSimple); + } + + [Fact] + public void DeclaringTypeThrowsForNonNestedTypes() + { + TypeName nested = TypeName.Parse("Containing+Nested".AsSpan()); + Assert.True(nested.IsNested); + Assert.Equal("Containing", nested.DeclaringType.Name); + + TypeName notNested = TypeName.Parse("NotNested".AsSpan()); + Assert.False(notNested.IsNested); + Assert.Throws(() => notNested.DeclaringType); + } + + [Theory] + [InlineData("SingleDimensionNonZeroIndexed[*]", true)] + [InlineData("SingleDimensionZeroIndexed[]", false)] + [InlineData("MultiDimensional[,,,,,,]", true)] + public void IsVariableBoundArrayTypeReturnsTrueForNonSZArrays(string typeName, bool expected) + { + TypeName parsed = TypeName.Parse(typeName.AsSpan()); + + Assert.True(parsed.IsArray); + Assert.Equal(expected, parsed.IsVariableBoundArrayType); + Assert.NotEqual(expected, parsed.IsSZArray); + Assert.InRange(parsed.GetArrayRank(), 1, 32); + } + + public static IEnumerable GetTypesThatRequireEscaping() + { + if (PlatformDetection.IsReflectionEmitSupported + && !PlatformDetection.IsMonoRuntime) // Mono does not escape Type.Name + { + AssemblyBuilder assembly = AssemblyBuilder.DefineDynamicAssembly(new AssemblyName("TypesThatRequireEscaping"), AssemblyBuilderAccess.Run); + ModuleBuilder module = assembly.DefineDynamicModule("TypesThatRequireEscapingModule"); + + yield return new object[] { module.DefineType("TypeNameWith+ThatIsNotNestedType").CreateType() }; + yield return new object[] { module.DefineType("TypeNameWith\\TheEscapingCharacter").CreateType() }; + yield return new object[] { module.DefineType("TypeNameWith&Ampersand").CreateType() }; + yield return new object[] { module.DefineType("TypeNameWith*Asterisk").CreateType() }; + yield return new object[] { module.DefineType("TypeNameWith[OpeningSquareBracket").CreateType() }; + yield return new object[] { module.DefineType("TypeNameWith]ClosingSquareBracket").CreateType() }; + yield return new object[] { module.DefineType("TypeNameWith[]BothSquareBrackets").CreateType() }; + yield return new object[] { module.DefineType("TypeNameWith[[]]NestedSquareBrackets").CreateType() }; + yield return new object[] { module.DefineType("TypeNameWith,Comma").CreateType() }; + yield return new object[] { module.DefineType("TypeNameWith\\[]+*&,AllSpecialCharacters").CreateType() }; + + TypeBuilder containingType = module.DefineType("ContainingTypeWithA+Plus"); + _ = containingType.CreateType(); // containing type must exist! + yield return new object[] { containingType.DefineNestedType("NoSpecialCharacters").CreateType() }; + yield return new object[] { containingType.DefineNestedType("Contains+Plus").CreateType() }; + } + } + + [Theory] + [InlineData(typeof(List))] + [InlineData(typeof(List>))] + [InlineData(typeof(Dictionary))] + [InlineData(typeof(Dictionary>))] + [InlineData(typeof(NestedGeneric_0.NestedGeneric_1))] + [InlineData(typeof(NestedGeneric_0.NestedGeneric_1.NestedGeneric_2))] + [InlineData(typeof(NestedGeneric_0.NestedGeneric_1.NestedGeneric_2.NestedNonGeneric_3))] + [MemberData(nameof(GetTypesThatRequireEscaping))] + public void ParsedNamesMatchSystemTypeNames(Type type) + { + TypeName parsed = TypeName.Parse(type.AssemblyQualifiedName.AsSpan()); + + Assert.Equal(type.Name, parsed.Name); + Assert.Equal(type.FullName, parsed.FullName); + Assert.Equal(type.AssemblyQualifiedName, parsed.AssemblyQualifiedName); + + if (type.IsGenericType) + { + Type genericType = type.GetGenericTypeDefinition(); + TypeName genericTypeName = parsed.GetGenericTypeDefinition(); + Assert.Equal(genericType.Name, genericTypeName.Name); + Assert.Equal(genericType.FullName, genericTypeName.FullName); + Assert.Equal(genericType.AssemblyQualifiedName, genericTypeName.AssemblyQualifiedName); + } + } + + [Theory] + [InlineData("Name`2[[int], [bool]]", "Name`2")] // match + [InlineData("Name`1[[int], [bool]]", "Name`1")] // less than expected + [InlineData("Name`3[[int], [bool]]", "Name`3")] // more than expected + [InlineData("Name[[int], [bool]]", "Name")] // no backtick at all! + public void TheNumberAfterBacktickDoesNotEnforceGenericArgCount(string input, string expectedName) + { + TypeName parsed = TypeName.Parse(input.AsSpan()); + + Assert.True(parsed.IsConstructedGenericType); + Assert.Equal(expectedName, parsed.Name); + Assert.Equal($"{expectedName}[[int],[bool]]", parsed.FullName); + Assert.Equal("int", parsed.GetGenericArguments()[0].Name); + Assert.Equal("bool", parsed.GetGenericArguments()[1].Name); + } + + [Theory] + [InlineData(typeof(int))] + [InlineData(typeof(int?))] + [InlineData(typeof(int[]))] + [InlineData(typeof(int[,]))] + [InlineData(typeof(int[,,,]))] + [InlineData(typeof(List))] + [InlineData(typeof(List>))] + [InlineData(typeof(Dictionary))] + [InlineData(typeof(Dictionary>))] + [InlineData(typeof(NestedNonGeneric_0))] + [InlineData(typeof(NestedNonGeneric_0.NestedNonGeneric_1))] + [InlineData(typeof(NestedGeneric_0))] + [InlineData(typeof(NestedGeneric_0.NestedGeneric_1))] + [InlineData(typeof(NestedGeneric_0.NestedGeneric_1.NestedGeneric_2))] + [InlineData(typeof(NestedGeneric_0.NestedGeneric_1.NestedGeneric_2.NestedNonGeneric_3))] + public void CanImplementGetTypeUsingPublicAPIs_Roundtrip(Type type) + { + Test(type); + Test(type.MakePointerType()); + Test(type.MakePointerType().MakePointerType()); + Test(type.MakeByRefType()); + + if (!type.IsArray) + { + Test(type.MakeArrayType()); // [] + Test(type.MakeArrayType(1)); // [*] + Test(type.MakeArrayType(2)); // [,] + } + + static void Test(Type type) + { + TypeName parsed = TypeName.Parse(type.AssemblyQualifiedName.AsSpan()); + + // ensure that Name, FullName and AssemblyQualifiedName match reflection APIs!! + Assert.Equal(type.Name, parsed.Name); + Assert.Equal(type.FullName, parsed.FullName); + Assert.Equal(type.AssemblyQualifiedName, parsed.AssemblyQualifiedName); + // now load load the type from name + Verify(type, parsed, ignoreCase: false); +#if NETCOREAPP // something weird is going on here + // load using lowercase name + Verify(type, TypeName.Parse(type.AssemblyQualifiedName.ToLower().AsSpan()), ignoreCase: true); + // load using uppercase name + Verify(type, TypeName.Parse(type.AssemblyQualifiedName.ToUpper().AsSpan()), ignoreCase: true); +#endif + + static void Verify(Type type, TypeName typeName, bool ignoreCase) + { + Type afterRoundtrip = GetType(typeName, throwOnError: true, ignoreCase: ignoreCase); + + Assert.NotNull(afterRoundtrip); + Assert.Equal(type, afterRoundtrip); + } + } + +#if NET8_0_OR_GREATER + [RequiresUnreferencedCode("The type might be removed")] + [RequiresDynamicCode("Required by MakeArrayType")] +#else +#pragma warning disable IL2055, IL2057, IL2075, IL2096 +#endif + static Type? GetType(TypeName typeName, bool throwOnError = true, bool ignoreCase = false) + { + if (typeName.IsNested) + { + BindingFlags flagsCopiedFromClr = BindingFlags.NonPublic | BindingFlags.Public; + if (ignoreCase) + { + flagsCopiedFromClr |= BindingFlags.IgnoreCase; + } + return Make(GetType(typeName.DeclaringType, throwOnError, ignoreCase)?.GetNestedType(typeName.Name, flagsCopiedFromClr)); + } + else if (typeName.IsConstructedGenericType) + { + return Make(GetType(typeName.GetGenericTypeDefinition(), throwOnError, ignoreCase)); + } + else if(typeName.IsArray || typeName.IsPointer || typeName.IsByRef) + { + return Make(GetType(typeName.GetElementType(), throwOnError, ignoreCase)); + } + else + { + Assert.True(typeName.IsSimple); + + AssemblyName? assemblyName = typeName.AssemblyName.ToAssemblyName(); + Type? type = assemblyName is null + ? Type.GetType(typeName.FullName, throwOnError, ignoreCase) + : Assembly.Load(assemblyName).GetType(typeName.FullName, throwOnError, ignoreCase); + + return Make(type); + } + + Type? Make(Type? type) + { + if (type is null || typeName.IsSimple) + { + return type; + } + else if (typeName.IsConstructedGenericType) + { + ImmutableArray genericArgs = typeName.GetGenericArguments(); + Type[] genericTypes = new Type[genericArgs.Length]; + for (int i = 0; i < genericArgs.Length; i++) + { + Type? genericArg = GetType(genericArgs[i], throwOnError, ignoreCase); + if (genericArg is null) + { + return null; + } + genericTypes[i] = genericArg; + } + + return type.MakeGenericType(genericTypes); + } + else if (typeName.IsByRef) + { + return type.MakeByRefType(); + } + else if (typeName.IsPointer) + { + return type.MakePointerType(); + } + else if (typeName.IsSZArray) + { + return type.MakeArrayType(); + } + else + { + Assert.True(typeName.IsVariableBoundArrayType); + + return type.MakeArrayType(rank: typeName.GetArrayRank()); + } + } + } +#pragma warning restore IL2055, IL2057, IL2075, IL2096 + } + + public class NestedNonGeneric_0 + { + public class NestedNonGeneric_1 { } + } + + public class NestedGeneric_0 + { + public class NestedGeneric_1 + { + public class NestedGeneric_2 + { + public class NestedNonGeneric_3 { } + } + } + } + } +} diff --git a/src/libraries/System.Reflection.Metadata/tests/System.Reflection.Metadata.Tests.csproj b/src/libraries/System.Reflection.Metadata/tests/System.Reflection.Metadata.Tests.csproj index fa48b37d26ab82..f739ac0789ff81 100644 --- a/src/libraries/System.Reflection.Metadata/tests/System.Reflection.Metadata.Tests.csproj +++ b/src/libraries/System.Reflection.Metadata/tests/System.Reflection.Metadata.Tests.csproj @@ -25,6 +25,9 @@ Link="Common\Microsoft\Win32\SafeHandles\SafeLibraryHandle.cs" /> + + @@ -36,6 +39,9 @@ + + + diff --git a/src/mono/System.Private.CoreLib/src/System/Reflection/TypeNameParser.Mono.cs b/src/mono/System.Private.CoreLib/src/System/Reflection/TypeNameParser.Mono.cs index 3622b4e27626ac..22a7361d9814e0 100644 --- a/src/mono/System.Private.CoreLib/src/System/Reflection/TypeNameParser.Mono.cs +++ b/src/mono/System.Private.CoreLib/src/System/Reflection/TypeNameParser.Mono.cs @@ -39,32 +39,31 @@ internal unsafe ref partial struct TypeNameParser return null; } - return new TypeNameParser(typeName) + Metadata.TypeName? parsed = Metadata.TypeNameParser.Parse(typeName, throwOnError: throwOnError); + if (parsed is null) + { + return null; + } + + return new TypeNameParser() { _assemblyResolver = assemblyResolver, _typeResolver = typeResolver, _throwOnError = throwOnError, _ignoreCase = ignoreCase, _stackMark = Unsafe.AsPointer(ref stackMark) - }.Parse(); + }.Resolve(parsed); } - private static bool CheckTopLevelAssemblyQualifiedName() + private Assembly? ResolveAssembly(AssemblyName name) { - return true; - } - - private Assembly? ResolveAssembly(string assemblyName) - { - var name = new AssemblyName(assemblyName); - Assembly? assembly; if (_assemblyResolver is not null) { assembly = _assemblyResolver(name); if (assembly is null && _throwOnError) { - throw new FileNotFoundException(SR.Format(SR.FileNotFound_ResolveAssembly, assemblyName)); + throw new FileNotFoundException(SR.Format(SR.FileNotFound_ResolveAssembly, name.FullName)); } } else @@ -96,13 +95,11 @@ private static bool CheckTopLevelAssemblyQualifiedName() Justification = "TypeNameParser.GetType is marked as RequiresUnreferencedCode.")] [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:RequiresUnreferencedCode", Justification = "TypeNameParser.GetType is marked as RequiresUnreferencedCode.")] - private Type? GetType(string typeName, ReadOnlySpan nestedTypeNames, string? assemblyNameIfAny) + private Type? GetType(string escapedTypeName, ReadOnlySpan nestedTypeNames, Metadata.TypeName parsedName) { - Assembly? assembly = (assemblyNameIfAny is not null) ? ResolveAssembly(assemblyNameIfAny) : null; + Assembly? assembly = (parsedName.AssemblyName is not null) ? ResolveAssembly(parsedName.AssemblyName.ToAssemblyName()) : null; // Both the external type resolver and the default type resolvers expect escaped type names - string escapedTypeName = EscapeTypeName(typeName); - Type? type; // Resolve the top level type. @@ -153,7 +150,7 @@ private static bool CheckTopLevelAssemblyQualifiedName() if (_throwOnError) { throw new TypeLoadException(SR.Format(SR.TypeLoad_ResolveNestedType, - nestedTypeNames[i], (i > 0) ? nestedTypeNames[i - 1] : typeName)); + nestedTypeNames[i], (i > 0) ? nestedTypeNames[i - 1] : escapedTypeName)); } return null; } From dd24e9c3ebaf6cda91fc281657878b75428f178c Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Wed, 24 Apr 2024 11:05:14 -0700 Subject: [PATCH 060/161] Arm64/Sve: Predicated Abs, Predicated/UnPredicated Add, Conditional Select (#100743) * JIT ARM64-SVE: Add Sve.Abs() and Sve.Add() Change-Id: Ie8cfe828595da9a87adbc0857c0c44c0ce12f5b2 * Fix sve scaling in enitIns_R_S/S_R * Revert "Fix sve scaling in enitIns_R_S/S_R" This reverts commit e9fa735738e900bed3c92848aa9ca5ac1f84fbde. * Fix sve scaling in enitIns_R_S/S_R * Restore testing * Use NaturalScale_helper for vector load/stores * wip * Add ConditionalSelect() APIs * Handle ConditionalSelect in JIT * Add test coverage * Update the test cases * jit format * fix merge conflicts * Make predicated/unpredicated work with ConditionalSelect Still some handling around RMW is needed, but this basically works * Misc. changes * jit format * jit format * Handle all the conditions correctly * jit format * fix some spacing * Removed the assert * fix the largest vector size to 64 to fix #100366 * review feedback * wip * Add SVE feature detection for Windows * fix the check for invalid alignment * Revert "Add SVE feature detection for Windows" This reverts commit ed7c781be36f68c95b2acfcaefb88facea954015. * Handle case where Abs() is wrapped in another conditionalSelect * jit format * fix the size comparison * HW_Flag_MaskedPredicatedOnlyOperation * Revert the change in emitarm64.cpp around INS_sve_ldr_mask/INS_sve_str_mask * Fix the condition for lowering * address review feedback for movprfx * Move the special handling of Vector<>.Zero from lowerer to importer * Rename IsEmbeddedMaskedOperation/IsOptionalEmbeddedMaskedOperation * Add more test coverage for conditionalSelect * Rename test method name * Add more test coverage for conditionalSelect:Abs * jit format * Add logging on test methods * Add the missing movprfx for abs * Add few more scenarios where falseVal is zero * Make sure LoadVector is marked as explicit needing mask * revisit the codegen logic * Remove commented code and add some other comments * jit format --------- Co-authored-by: Alan Hayward --- src/coreclr/jit/codegenlinear.cpp | 2 - src/coreclr/jit/compiler.h | 1 + src/coreclr/jit/emitloongarch64.h | 2 +- src/coreclr/jit/emitriscv64.h | 2 +- src/coreclr/jit/gentree.cpp | 14 +- src/coreclr/jit/gentree.h | 12 +- src/coreclr/jit/hwintrinsic.cpp | 60 ++- src/coreclr/jit/hwintrinsic.h | 29 +- src/coreclr/jit/hwintrinsicarm64.cpp | 20 +- src/coreclr/jit/hwintrinsiccodegenarm64.cpp | 123 ++++- src/coreclr/jit/hwintrinsiclistarm64sve.h | 9 +- src/coreclr/jit/liveness.cpp | 4 +- src/coreclr/jit/lowerarmarch.cpp | 67 +++ src/coreclr/jit/lowerxarch.cpp | 4 +- src/coreclr/jit/lsrabuild.cpp | 10 + src/coreclr/jit/ssabuilder.cpp | 14 +- .../Arm/Sve.PlatformNotSupported.cs | 177 +++++++ .../src/System/Runtime/Intrinsics/Arm/Sve.cs | 234 ++++++++++ .../ref/System.Runtime.Intrinsics.cs | 29 +- .../GenerateHWIntrinsicTests_Arm.cs | 63 ++- .../Arm/Shared/SveConditionalSelect.template | 362 +++++++++++++++ .../Arm/Shared/SveLoadMaskedUnOpTest.template | 4 +- .../Shared/_SveBinaryOpTestTemplate.template | 435 ++++++++++++++++++ .../Shared/_SveUnaryOpTestTemplate.template | 391 ++++++++++++++++ 24 files changed, 1994 insertions(+), 74 deletions(-) create mode 100644 src/tests/JIT/HardwareIntrinsics/Arm/Shared/SveConditionalSelect.template create mode 100644 src/tests/JIT/HardwareIntrinsics/Arm/Shared/_SveBinaryOpTestTemplate.template create mode 100644 src/tests/JIT/HardwareIntrinsics/Arm/Shared/_SveUnaryOpTestTemplate.template diff --git a/src/coreclr/jit/codegenlinear.cpp b/src/coreclr/jit/codegenlinear.cpp index 145c074b8fc681..d099fe192fc38a 100644 --- a/src/coreclr/jit/codegenlinear.cpp +++ b/src/coreclr/jit/codegenlinear.cpp @@ -1648,7 +1648,6 @@ void CodeGen::genConsumeRegs(GenTree* tree) // Update the life of the lcl var. genUpdateLife(tree); } -#ifdef TARGET_XARCH #ifdef FEATURE_HW_INTRINSICS else if (tree->OperIs(GT_HWINTRINSIC)) { @@ -1656,7 +1655,6 @@ void CodeGen::genConsumeRegs(GenTree* tree) genConsumeMultiOpOperands(hwintrinsic); } #endif // FEATURE_HW_INTRINSICS -#endif // TARGET_XARCH else if (tree->OperIs(GT_BITCAST, GT_NEG, GT_CAST, GT_LSH, GT_RSH, GT_RSZ, GT_ROR, GT_BSWAP, GT_BSWAP16)) { genConsumeRegs(tree->gtGetOp1()); diff --git a/src/coreclr/jit/compiler.h b/src/coreclr/jit/compiler.h index 5b8a04e868836c..7949058066494d 100644 --- a/src/coreclr/jit/compiler.h +++ b/src/coreclr/jit/compiler.h @@ -3477,6 +3477,7 @@ class Compiler #if defined(TARGET_ARM64) GenTree* gtNewSimdConvertVectorToMaskNode(var_types type, GenTree* node, CorInfoType simdBaseJitType, unsigned simdSize); GenTree* gtNewSimdConvertMaskToVectorNode(GenTreeHWIntrinsic* node, var_types type); + GenTree* gtNewSimdAllTrueMaskNode(CorInfoType simdBaseJitType, unsigned simdSize); #endif //------------------------------------------------------------------------ diff --git a/src/coreclr/jit/emitloongarch64.h b/src/coreclr/jit/emitloongarch64.h index 135f9cf4006735..afaca5b2ba04b8 100644 --- a/src/coreclr/jit/emitloongarch64.h +++ b/src/coreclr/jit/emitloongarch64.h @@ -333,7 +333,7 @@ enum EmitCallType EC_FUNC_TOKEN, // Direct call to a helper/static/nonvirtual/global method // EC_FUNC_TOKEN_INDIR, // Indirect call to a helper/static/nonvirtual/global method - // EC_FUNC_ADDR, // Direct call to an absolute address + // EC_FUNC_ADDR, // Direct call to an absolute address EC_INDIR_R, // Indirect call via register diff --git a/src/coreclr/jit/emitriscv64.h b/src/coreclr/jit/emitriscv64.h index 07e603a70afb7c..262f44c9ac4bbd 100644 --- a/src/coreclr/jit/emitriscv64.h +++ b/src/coreclr/jit/emitriscv64.h @@ -310,7 +310,7 @@ enum EmitCallType EC_FUNC_TOKEN, // Direct call to a helper/static/nonvirtual/global method // EC_FUNC_TOKEN_INDIR, // Indirect call to a helper/static/nonvirtual/global method - // EC_FUNC_ADDR, // Direct call to an absolute address + // EC_FUNC_ADDR, // Direct call to an absolute address // EC_FUNC_VIRTUAL, // Call to a virtual method (using the vtable) EC_INDIR_R, // Indirect call via register diff --git a/src/coreclr/jit/gentree.cpp b/src/coreclr/jit/gentree.cpp index c6d6b78c48ca9e..85ce90e94e001d 100644 --- a/src/coreclr/jit/gentree.cpp +++ b/src/coreclr/jit/gentree.cpp @@ -18012,7 +18012,7 @@ bool GenTree::canBeContained() const } else if (OperIsHWIntrinsic() && !isContainableHWIntrinsic()) { - return isEvexEmbeddedMaskingCompatibleHWIntrinsic(); + return isEmbeddedMaskingCompatibleHWIntrinsic(); } return true; @@ -19909,24 +19909,26 @@ bool GenTree::isEvexCompatibleHWIntrinsic() const } //------------------------------------------------------------------------ -// isEvexEmbeddedMaskingCompatibleHWIntrinsic: Checks if the intrinsic is compatible +// isEmbeddedMaskingCompatibleHWIntrinsic : Checks if the intrinsic is compatible // with the EVEX embedded masking form for its intended lowering instruction. // // Return Value: // true if the intrisic node lowering instruction has an EVEX embedded masking // -bool GenTree::isEvexEmbeddedMaskingCompatibleHWIntrinsic() const +bool GenTree::isEmbeddedMaskingCompatibleHWIntrinsic() const { -#if defined(TARGET_XARCH) if (OperIsHWIntrinsic()) { +#if defined(TARGET_XARCH) // TODO-AVX512F-CQ: Expand this to the full set of APIs and make it table driven // using IsEmbMaskingCompatible. For now, however, limit it to some explicit ids // for prototyping purposes. return (AsHWIntrinsic()->GetHWIntrinsicId() == NI_AVX512F_Add); +#elif defined(TARGET_ARM64) + return HWIntrinsicInfo::IsEmbeddedMaskedOperation(AsHWIntrinsic()->GetHWIntrinsicId()) || + HWIntrinsicInfo::IsOptionalEmbeddedMaskedOperation(AsHWIntrinsic()->GetHWIntrinsicId()); +#endif } -#endif // TARGET_XARCH - return false; } diff --git a/src/coreclr/jit/gentree.h b/src/coreclr/jit/gentree.h index c6369121809520..079174f67e939b 100644 --- a/src/coreclr/jit/gentree.h +++ b/src/coreclr/jit/gentree.h @@ -557,9 +557,9 @@ enum GenTreeFlags : unsigned int GTF_MDARRLOWERBOUND_NONFAULTING = 0x20000000, // GT_MDARR_LOWER_BOUND -- An MD array lower bound operation that cannot fault. Same as GT_IND_NONFAULTING. -#if defined(TARGET_XARCH) && defined(FEATURE_HW_INTRINSICS) +#ifdef FEATURE_HW_INTRINSICS GTF_HW_EM_OP = 0x10000000, // GT_HWINTRINSIC -- node is used as an operand to an embedded mask -#endif // TARGET_XARCH && FEATURE_HW_INTRINSICS +#endif // FEATURE_HW_INTRINSICS }; inline constexpr GenTreeFlags operator ~(GenTreeFlags a) @@ -1465,7 +1465,7 @@ struct GenTree bool isContainableHWIntrinsic() const; bool isRMWHWIntrinsic(Compiler* comp); bool isEvexCompatibleHWIntrinsic() const; - bool isEvexEmbeddedMaskingCompatibleHWIntrinsic() const; + bool isEmbeddedMaskingCompatibleHWIntrinsic() const; #else bool isCommutativeHWIntrinsic() const { @@ -1487,7 +1487,7 @@ struct GenTree return false; } - bool isEvexEmbeddedMaskingCompatibleHWIntrinsic() const + bool isEmbeddedMaskingCompatibleHWIntrinsic() const { return false; } @@ -2226,7 +2226,7 @@ struct GenTree gtFlags &= ~GTF_ICON_HDL_MASK; } -#if defined(TARGET_XARCH) && defined(FEATURE_HW_INTRINSICS) +#ifdef FEATURE_HW_INTRINSICS bool IsEmbMaskOp() { @@ -2240,7 +2240,7 @@ struct GenTree gtFlags |= GTF_HW_EM_OP; } -#endif // TARGET_XARCH && FEATURE_HW_INTRINSICS +#endif // FEATURE_HW_INTRINSICS static bool HandleKindDataIsInvariant(GenTreeFlags flags); diff --git a/src/coreclr/jit/hwintrinsic.cpp b/src/coreclr/jit/hwintrinsic.cpp index 53970ef4a7460b..402cae99b3f631 100644 --- a/src/coreclr/jit/hwintrinsic.cpp +++ b/src/coreclr/jit/hwintrinsic.cpp @@ -1396,6 +1396,36 @@ GenTree* Compiler::impHWIntrinsic(NamedIntrinsic intrinsic, GenTree* op3 = nullptr; GenTree* op4 = nullptr; + switch (numArgs) + { + case 4: + op4 = getArgForHWIntrinsic(sigReader.GetOp4Type(), sigReader.op4ClsHnd); + op4 = addRangeCheckIfNeeded(intrinsic, op4, mustExpand, immLowerBound, immUpperBound); + op3 = getArgForHWIntrinsic(sigReader.GetOp3Type(), sigReader.op3ClsHnd); + op2 = getArgForHWIntrinsic(sigReader.GetOp2Type(), sigReader.op2ClsHnd); + op1 = getArgForHWIntrinsic(sigReader.GetOp1Type(), sigReader.op1ClsHnd); + break; + + case 3: + op3 = getArgForHWIntrinsic(sigReader.GetOp3Type(), sigReader.op3ClsHnd); + op2 = getArgForHWIntrinsic(sigReader.GetOp2Type(), sigReader.op2ClsHnd); + op1 = getArgForHWIntrinsic(sigReader.GetOp1Type(), sigReader.op1ClsHnd); + break; + + case 2: + op2 = getArgForHWIntrinsic(sigReader.GetOp2Type(), sigReader.op2ClsHnd); + op2 = addRangeCheckIfNeeded(intrinsic, op2, mustExpand, immLowerBound, immUpperBound); + op1 = getArgForHWIntrinsic(sigReader.GetOp1Type(), sigReader.op1ClsHnd); + break; + + case 1: + op1 = getArgForHWIntrinsic(sigReader.GetOp1Type(), sigReader.op1ClsHnd); + break; + + default: + break; + } + switch (numArgs) { case 0: @@ -1407,8 +1437,6 @@ GenTree* Compiler::impHWIntrinsic(NamedIntrinsic intrinsic, case 1: { - op1 = getArgForHWIntrinsic(sigReader.GetOp1Type(), sigReader.op1ClsHnd); - if ((category == HW_Category_MemoryLoad) && op1->OperIs(GT_CAST)) { // Although the API specifies a pointer, if what we have is a BYREF, that's what @@ -1467,10 +1495,6 @@ GenTree* Compiler::impHWIntrinsic(NamedIntrinsic intrinsic, case 2: { - op2 = getArgForHWIntrinsic(sigReader.GetOp2Type(), sigReader.op2ClsHnd); - op2 = addRangeCheckIfNeeded(intrinsic, op2, mustExpand, immLowerBound, immUpperBound); - op1 = getArgForHWIntrinsic(sigReader.GetOp1Type(), sigReader.op1ClsHnd); - retNode = isScalar ? gtNewScalarHWIntrinsicNode(nodeRetType, op1, op2, intrinsic) : gtNewSimdHWIntrinsicNode(nodeRetType, op1, op2, intrinsic, simdBaseJitType, simdSize); @@ -1524,10 +1548,6 @@ GenTree* Compiler::impHWIntrinsic(NamedIntrinsic intrinsic, case 3: { - op3 = getArgForHWIntrinsic(sigReader.GetOp3Type(), sigReader.op3ClsHnd); - op2 = getArgForHWIntrinsic(sigReader.GetOp2Type(), sigReader.op2ClsHnd); - op1 = getArgForHWIntrinsic(sigReader.GetOp1Type(), sigReader.op1ClsHnd); - #ifdef TARGET_ARM64 if (intrinsic == NI_AdvSimd_LoadAndInsertScalar) { @@ -1569,12 +1589,6 @@ GenTree* Compiler::impHWIntrinsic(NamedIntrinsic intrinsic, case 4: { - op4 = getArgForHWIntrinsic(sigReader.GetOp4Type(), sigReader.op4ClsHnd); - op4 = addRangeCheckIfNeeded(intrinsic, op4, mustExpand, immLowerBound, immUpperBound); - op3 = getArgForHWIntrinsic(sigReader.GetOp3Type(), sigReader.op3ClsHnd); - op2 = getArgForHWIntrinsic(sigReader.GetOp2Type(), sigReader.op2ClsHnd); - op1 = getArgForHWIntrinsic(sigReader.GetOp1Type(), sigReader.op1ClsHnd); - assert(!isScalar); retNode = gtNewSimdHWIntrinsicNode(nodeRetType, op1, op2, op3, op4, intrinsic, simdBaseJitType, simdSize); @@ -1591,10 +1605,22 @@ GenTree* Compiler::impHWIntrinsic(NamedIntrinsic intrinsic, } #if defined(TARGET_ARM64) - if (HWIntrinsicInfo::IsMaskedOperation(intrinsic)) + if (HWIntrinsicInfo::IsExplicitMaskedOperation(intrinsic)) { assert(numArgs > 0); GenTree* op1 = retNode->AsHWIntrinsic()->Op(1); + if (intrinsic == NI_Sve_ConditionalSelect) + { + if (op1->IsVectorAllBitsSet()) + { + return retNode->AsHWIntrinsic()->Op(2); + } + else if (op1->IsVectorZero()) + { + return retNode->AsHWIntrinsic()->Op(3); + } + } + if (!varTypeIsMask(op1)) { // Op1 input is a vector. HWInstrinsic requires a mask. diff --git a/src/coreclr/jit/hwintrinsic.h b/src/coreclr/jit/hwintrinsic.h index 5ca302e126f32a..e7bd08d5cb33dc 100644 --- a/src/coreclr/jit/hwintrinsic.h +++ b/src/coreclr/jit/hwintrinsic.h @@ -186,11 +186,18 @@ enum HWIntrinsicFlag : unsigned int HW_Flag_ReturnsPerElementMask = 0x10000, // The intrinsic uses a mask in arg1 to select elements present in the result - HW_Flag_MaskedOperation = 0x20000, + HW_Flag_ExplicitMaskedOperation = 0x20000, // The intrinsic uses a mask in arg1 to select elements present in the result, and must use a low register. HW_Flag_LowMaskedOperation = 0x40000, + // The intrinsic can optionally use a mask in arg1 to select elements present in the result, which is not present in + // the API call + HW_Flag_OptionalEmbeddedMaskedOperation = 0x80000, + + // The intrinsic uses a mask in arg1 to select elements present in the result, which is not present in the API call + HW_Flag_EmbeddedMaskedOperation = 0x100000, + #else #error Unsupported platform #endif @@ -872,7 +879,7 @@ struct HWIntrinsicInfo static bool IsMaskedOperation(NamedIntrinsic id) { const HWIntrinsicFlag flags = lookupFlags(id); - return ((flags & HW_Flag_MaskedOperation) != 0) || IsLowMaskedOperation(id); + return IsLowMaskedOperation(id) || IsOptionalEmbeddedMaskedOperation(id) || IsExplicitMaskedOperation(id); } static bool IsLowMaskedOperation(NamedIntrinsic id) @@ -881,6 +888,24 @@ struct HWIntrinsicInfo return (flags & HW_Flag_LowMaskedOperation) != 0; } + static bool IsOptionalEmbeddedMaskedOperation(NamedIntrinsic id) + { + const HWIntrinsicFlag flags = lookupFlags(id); + return (flags & HW_Flag_OptionalEmbeddedMaskedOperation) != 0; + } + + static bool IsEmbeddedMaskedOperation(NamedIntrinsic id) + { + const HWIntrinsicFlag flags = lookupFlags(id); + return (flags & HW_Flag_EmbeddedMaskedOperation) != 0; + } + + static bool IsExplicitMaskedOperation(NamedIntrinsic id) + { + const HWIntrinsicFlag flags = lookupFlags(id); + return (flags & HW_Flag_ExplicitMaskedOperation) != 0; + } + #endif // TARGET_ARM64 static bool HasSpecialSideEffect(NamedIntrinsic id) diff --git a/src/coreclr/jit/hwintrinsicarm64.cpp b/src/coreclr/jit/hwintrinsicarm64.cpp index 98342739cb4e0d..07018824458a0b 100644 --- a/src/coreclr/jit/hwintrinsicarm64.cpp +++ b/src/coreclr/jit/hwintrinsicarm64.cpp @@ -2222,9 +2222,8 @@ GenTree* Compiler::gtNewSimdConvertVectorToMaskNode(var_types type, assert(varTypeIsSIMD(node)); // ConvertVectorToMask uses cmpne which requires an embedded mask. - GenTree* embeddedMask = gtNewSimdHWIntrinsicNode(TYP_MASK, NI_Sve_CreateTrueMaskAll, simdBaseJitType, simdSize); - return gtNewSimdHWIntrinsicNode(TYP_MASK, embeddedMask, node, NI_Sve_ConvertVectorToMask, simdBaseJitType, - simdSize); + GenTree* trueMask = gtNewSimdAllTrueMaskNode(simdBaseJitType, simdSize); + return gtNewSimdHWIntrinsicNode(TYP_MASK, trueMask, node, NI_Sve_ConvertVectorToMask, simdBaseJitType, simdSize); } //------------------------------------------------------------------------ @@ -2246,4 +2245,19 @@ GenTree* Compiler::gtNewSimdConvertMaskToVectorNode(GenTreeHWIntrinsic* node, va node->GetSimdSize()); } +//------------------------------------------------------------------------ +// gtNewSimdEmbeddedMaskNode: Create an embedded mask +// +// Arguments: +// simdBaseJitType -- the base jit type of the nodes being masked +// simdSize -- the simd size of the nodes being masked +// +// Return Value: +// The mask +// +GenTree* Compiler::gtNewSimdAllTrueMaskNode(CorInfoType simdBaseJitType, unsigned simdSize) +{ + return gtNewSimdHWIntrinsicNode(TYP_MASK, NI_Sve_CreateTrueMaskAll, simdBaseJitType, simdSize); +} + #endif // FEATURE_HW_INTRINSICS diff --git a/src/coreclr/jit/hwintrinsiccodegenarm64.cpp b/src/coreclr/jit/hwintrinsiccodegenarm64.cpp index 01914951576bfa..0355b4285d486b 100644 --- a/src/coreclr/jit/hwintrinsiccodegenarm64.cpp +++ b/src/coreclr/jit/hwintrinsiccodegenarm64.cpp @@ -401,6 +401,100 @@ void CodeGen::genHWIntrinsic(GenTreeHWIntrinsic* node) unreached(); } } + else if (intrin.numOperands >= 2 && intrin.op2->IsEmbMaskOp()) + { + // Handle case where op2 is operation that needs embedded mask + GenTree* op2 = intrin.op2; + assert(intrin.id == NI_Sve_ConditionalSelect); + assert(op2->isContained()); + assert(op2->OperIsHWIntrinsic()); + + // Get the registers and intrinsics that needs embedded mask + const HWIntrinsic intrinEmbMask(op2->AsHWIntrinsic()); + instruction insEmbMask = HWIntrinsicInfo::lookupIns(intrinEmbMask.id, intrinEmbMask.baseType); + const bool instrIsRMW = op2->isRMWHWIntrinsic(compiler); + + regNumber maskReg = op1Reg; + regNumber embMaskOp1Reg = REG_NA; + regNumber embMaskOp2Reg = REG_NA; + regNumber falseReg = op3Reg; + + switch (intrinEmbMask.numOperands) + { + case 2: + assert(intrinEmbMask.op2 != nullptr); + embMaskOp2Reg = intrinEmbMask.op2->GetRegNum(); + FALLTHROUGH; + + case 1: + assert(intrinEmbMask.op1 != nullptr); + embMaskOp1Reg = intrinEmbMask.op1->GetRegNum(); + break; + + default: + unreached(); + } + + switch (intrinEmbMask.numOperands) + { + case 1: + assert(!instrIsRMW); + if (targetReg != falseReg) + { + GetEmitter()->emitIns_R_R(INS_sve_movprfx, EA_SCALABLE, targetReg, falseReg); + } + GetEmitter()->emitIns_R_R_R(insEmbMask, emitSize, targetReg, maskReg, embMaskOp1Reg, opt); + break; + + case 2: + + assert(instrIsRMW); + + if (intrin.op3->IsVectorZero()) + { + // If `falseReg` is zero, then move the first operand of `intrinEmbMask` in the + // destination using /Z. + GetEmitter()->emitIns_R_R_R(INS_sve_movprfx, emitSize, targetReg, maskReg, embMaskOp1Reg, opt); + + // Finally, perform the actual "predicated" operation so that `targetReg` is the first operand + // and `embMaskOp2Reg` is the second operand. + GetEmitter()->emitIns_R_R_R(insEmbMask, emitSize, targetReg, maskReg, embMaskOp2Reg, opt); + } + else if (targetReg != falseReg) + { + // If `targetReg` and `falseReg` are not same, then we need to move it to `targetReg` first + // so the `insEmbMask` operation can be merged on top of it. + + if (falseReg != embMaskOp1Reg) + { + // None of targetReg, embMaskOp1Reg and falseReg are same. In such case, use the + // "unpredicated" version of the instruction and then use "sel" to select the active lanes. + + GetEmitter()->emitIns_R_R_R(insEmbMask, emitSize, targetReg, embMaskOp1Reg, embMaskOp2Reg, + opt, INS_SCALABLE_OPTS_UNPREDICATED); + GetEmitter()->emitIns_R_R_R_R(INS_sve_sel, emitSize, targetReg, maskReg, targetReg, + falseReg, opt, INS_SCALABLE_OPTS_UNPREDICATED); + break; + } + else if (targetReg != embMaskOp1Reg) + { + // embMaskOp1Reg is same as `falseReg`, but not same as `targetReg`. Move the + // `embMaskOp1Reg` i.e. `falseReg` in `targetReg`, using "unpredicated movprfx", so the + // subsequent `insEmbMask` operation can be merged on top of it. + GetEmitter()->emitIns_R_R(INS_sve_movprfx, EA_SCALABLE, targetReg, falseReg, opt); + } + + // Finally, perform the actual "predicated" operation so that `targetReg` is the first operand + // and `embMaskOp2Reg` is the second operand. + GetEmitter()->emitIns_R_R_R(insEmbMask, emitSize, targetReg, maskReg, embMaskOp2Reg, opt); + } + + break; + + default: + unreached(); + } + } else { assert(!hasImmediateOperand); @@ -419,6 +513,14 @@ void CodeGen::genHWIntrinsic(GenTreeHWIntrinsic* node) { GetEmitter()->emitIns_R_R(ins, emitSize, targetReg, op1Reg, opt); } + else if (HWIntrinsicInfo::IsScalable(intrin.id)) + { + assert(!node->IsEmbMaskOp()); + // This generates an unpredicated version + // Predicated should be taken care above `intrin.op2->IsEmbMaskOp()` + GetEmitter()->emitIns_R_R_R(ins, emitSize, targetReg, op1Reg, op2Reg, opt, + INS_SCALABLE_OPTS_UNPREDICATED); + } else if (isRMW) { if (targetReg != op1Reg) @@ -437,17 +539,24 @@ void CodeGen::genHWIntrinsic(GenTreeHWIntrinsic* node) break; case 3: - assert(isRMW); - if (targetReg != op1Reg) + if (isRMW) { - assert(targetReg != op2Reg); - assert(targetReg != op3Reg); + if (targetReg != op1Reg) + { + assert(targetReg != op2Reg); + assert(targetReg != op3Reg); - GetEmitter()->emitIns_Mov(INS_mov, emitTypeSize(node), targetReg, op1Reg, /* canSkip */ true); + GetEmitter()->emitIns_Mov(INS_mov, emitTypeSize(node), targetReg, op1Reg, + /* canSkip */ true); + } + GetEmitter()->emitIns_R_R_R(ins, emitSize, targetReg, op2Reg, op3Reg, opt); + } + else + { + GetEmitter()->emitIns_R_R_R_R(ins, emitSize, targetReg, op1Reg, op2Reg, op3Reg, opt, + INS_SCALABLE_OPTS_UNPREDICATED); } - GetEmitter()->emitIns_R_R_R(ins, emitSize, targetReg, op2Reg, op3Reg, opt); break; - default: unreached(); } diff --git a/src/coreclr/jit/hwintrinsiclistarm64sve.h b/src/coreclr/jit/hwintrinsiclistarm64sve.h index ac110c2a0e1b5b..14b880c8e570e4 100644 --- a/src/coreclr/jit/hwintrinsiclistarm64sve.h +++ b/src/coreclr/jit/hwintrinsiclistarm64sve.h @@ -17,6 +17,9 @@ // SVE Intrinsics // Sve +HARDWARE_INTRINSIC(Sve, Abs, -1, -1, false, {INS_sve_abs, INS_invalid, INS_sve_abs, INS_invalid, INS_sve_abs, INS_invalid, INS_sve_abs, INS_invalid, INS_sve_fabs, INS_sve_fabs}, HW_Category_SIMD, HW_Flag_Scalable|HW_Flag_EmbeddedMaskedOperation) +HARDWARE_INTRINSIC(Sve, Add, -1, -1, false, {INS_sve_add, INS_sve_add, INS_sve_add, INS_sve_add, INS_sve_add, INS_sve_add, INS_sve_add, INS_sve_add, INS_sve_fadd, INS_sve_fadd}, HW_Category_SIMD, HW_Flag_Scalable|HW_Flag_OptionalEmbeddedMaskedOperation|HW_Flag_HasRMWSemantics|HW_Flag_LowMaskedOperation) +HARDWARE_INTRINSIC(Sve, ConditionalSelect, -1, 3, true, {INS_sve_sel, INS_sve_sel, INS_sve_sel, INS_sve_sel, INS_sve_sel, INS_sve_sel, INS_sve_sel, INS_sve_sel, INS_sve_sel, INS_sve_sel}, HW_Category_SIMD, HW_Flag_Scalable|HW_Flag_ExplicitMaskedOperation|HW_Flag_SupportsContainment) HARDWARE_INTRINSIC(Sve, CreateTrueMaskByte, -1, 1, false, {INS_invalid, INS_sve_ptrue, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_EnumPattern, HW_Flag_Scalable|HW_Flag_HasImmediateOperand|HW_Flag_ReturnsPerElementMask) HARDWARE_INTRINSIC(Sve, CreateTrueMaskDouble, -1, 1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sve_ptrue}, HW_Category_EnumPattern, HW_Flag_Scalable|HW_Flag_HasImmediateOperand|HW_Flag_ReturnsPerElementMask) HARDWARE_INTRINSIC(Sve, CreateTrueMaskInt16, -1, 1, false, {INS_invalid, INS_invalid, INS_sve_ptrue, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_EnumPattern, HW_Flag_Scalable|HW_Flag_HasImmediateOperand|HW_Flag_ReturnsPerElementMask) @@ -28,7 +31,7 @@ HARDWARE_INTRINSIC(Sve, CreateTrueMaskUInt16, HARDWARE_INTRINSIC(Sve, CreateTrueMaskUInt32, -1, 1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sve_ptrue, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_EnumPattern, HW_Flag_Scalable|HW_Flag_HasImmediateOperand|HW_Flag_ReturnsPerElementMask) HARDWARE_INTRINSIC(Sve, CreateTrueMaskUInt64, -1, 1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sve_ptrue, INS_invalid, INS_invalid}, HW_Category_EnumPattern, HW_Flag_Scalable|HW_Flag_HasImmediateOperand|HW_Flag_ReturnsPerElementMask) -HARDWARE_INTRINSIC(Sve, LoadVector, -1, 2, true, {INS_sve_ld1b, INS_sve_ld1b, INS_sve_ld1h, INS_sve_ld1h, INS_sve_ld1w, INS_sve_ld1w, INS_sve_ld1d, INS_sve_ld1d, INS_sve_ld1w, INS_sve_ld1d}, HW_Category_MemoryLoad, HW_Flag_Scalable|HW_Flag_LowMaskedOperation) +HARDWARE_INTRINSIC(Sve, LoadVector, -1, 2, true, {INS_sve_ld1b, INS_sve_ld1b, INS_sve_ld1h, INS_sve_ld1h, INS_sve_ld1w, INS_sve_ld1w, INS_sve_ld1d, INS_sve_ld1d, INS_sve_ld1w, INS_sve_ld1d}, HW_Category_MemoryLoad, HW_Flag_Scalable|HW_Flag_ExplicitMaskedOperation|HW_Flag_LowMaskedOperation) @@ -38,11 +41,11 @@ HARDWARE_INTRINSIC(Sve, LoadVector, // *************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************** // Special intrinsics that are generated during importing or lowering -HARDWARE_INTRINSIC(Sve, ConvertMaskToVector, -1, 1, true, {INS_sve_mov, INS_sve_mov, INS_sve_mov, INS_sve_mov, INS_sve_mov, INS_sve_mov, INS_sve_mov, INS_sve_mov, INS_sve_mov, INS_sve_mov}, HW_Category_Helper, HW_Flag_Scalable|HW_Flag_MaskedOperation) +HARDWARE_INTRINSIC(Sve, ConvertMaskToVector, -1, 1, true, {INS_sve_mov, INS_sve_mov, INS_sve_mov, INS_sve_mov, INS_sve_mov, INS_sve_mov, INS_sve_mov, INS_sve_mov, INS_sve_mov, INS_sve_mov}, HW_Category_Helper, HW_Flag_Scalable|HW_Flag_ExplicitMaskedOperation) HARDWARE_INTRINSIC(Sve, ConvertVectorToMask, -1, 2, true, {INS_sve_cmpne, INS_sve_cmpne, INS_sve_cmpne, INS_sve_cmpne, INS_sve_cmpne, INS_sve_cmpne, INS_sve_cmpne, INS_sve_cmpne, INS_sve_cmpne, INS_sve_cmpne}, HW_Category_Helper, HW_Flag_Scalable|HW_Flag_ReturnsPerElementMask|HW_Flag_LowMaskedOperation) - HARDWARE_INTRINSIC(Sve, CreateTrueMaskAll, -1, -1, false, {INS_sve_ptrue, INS_sve_ptrue, INS_sve_ptrue, INS_sve_ptrue, INS_sve_ptrue, INS_sve_ptrue, INS_sve_ptrue, INS_sve_ptrue, INS_sve_ptrue, INS_sve_ptrue}, HW_Category_Helper, HW_Flag_Scalable|HW_Flag_ReturnsPerElementMask) + #endif // FEATURE_HW_INTRINSIC #undef HARDWARE_INTRINSIC diff --git a/src/coreclr/jit/liveness.cpp b/src/coreclr/jit/liveness.cpp index 521e9891334339..ef3fedf5b31d32 100644 --- a/src/coreclr/jit/liveness.cpp +++ b/src/coreclr/jit/liveness.cpp @@ -1762,8 +1762,8 @@ void Compiler::fgComputeLifeLIR(VARSET_TP& life, BasicBlock* block, VARSET_VALAR operand->SetUnusedValue(); } - // Special-case PUTARG_STK: since this operator is not considered a value, DCE will not remove - // these nodes. + // Special-case PUTARG_STK: since this operator is not considered a value, DCE will not + // remove these nodes. if (operand->OperIs(GT_PUTARG_STK)) { operand->AsPutArgStk()->gtOp1->SetUnusedValue(); diff --git a/src/coreclr/jit/lowerarmarch.cpp b/src/coreclr/jit/lowerarmarch.cpp index cbdc886ee2802b..7ea9a90d62343e 100644 --- a/src/coreclr/jit/lowerarmarch.cpp +++ b/src/coreclr/jit/lowerarmarch.cpp @@ -1280,6 +1280,34 @@ GenTree* Lowering::LowerHWIntrinsic(GenTreeHWIntrinsic* node) break; } + if (HWIntrinsicInfo::IsEmbeddedMaskedOperation(intrinsicId)) + { + LIR::Use use; + if (BlockRange().TryGetUse(node, &use)) + { + GenTree* user = use.User(); + // Wrap the intrinsic in ConditionalSelect only if it is not already inside another ConditionalSelect + if (!user->OperIsHWIntrinsic() || (user->AsHWIntrinsic()->GetHWIntrinsicId() != NI_Sve_ConditionalSelect)) + { + CorInfoType simdBaseJitType = node->GetSimdBaseJitType(); + unsigned simdSize = node->GetSimdSize(); + var_types simdType = Compiler::getSIMDTypeForSize(simdSize); + GenTree* trueMask = comp->gtNewSimdAllTrueMaskNode(simdBaseJitType, simdSize); + GenTree* trueVal = node; + GenTree* falseVal = comp->gtNewZeroConNode(simdType); + + GenTreeHWIntrinsic* condSelNode = + comp->gtNewSimdHWIntrinsicNode(simdType, trueMask, trueVal, falseVal, NI_Sve_ConditionalSelect, + simdBaseJitType, simdSize); + + BlockRange().InsertBefore(node, trueMask); + BlockRange().InsertBefore(node, falseVal); + BlockRange().InsertAfter(node, condSelNode); + use.ReplaceWith(condSelNode); + } + } + } + ContainCheckHWIntrinsic(node); return node->gtNext; } @@ -3275,6 +3303,45 @@ void Lowering::ContainCheckHWIntrinsic(GenTreeHWIntrinsic* node) } break; + case NI_Sve_ConditionalSelect: + { + assert(intrin.numOperands == 3); + GenTree* op1 = intrin.op1; + GenTree* op2 = intrin.op2; + GenTree* op3 = intrin.op3; + + // Handle op1 + if (op1->IsVectorZero()) + { + // When we are merging with zero, we can specialize + // and avoid instantiating the vector constant. + MakeSrcContained(node, op1); + } + + // Handle op2 + if (op2->OperIsHWIntrinsic()) + { + uint32_t maskSize = genTypeSize(node->GetSimdBaseType()); + uint32_t operSize = genTypeSize(op2->AsHWIntrinsic()->GetSimdBaseType()); + + if ((maskSize == operSize) && IsInvariantInRange(op2, node)) + { + MakeSrcContained(node, op2); + op2->MakeEmbMaskOp(); + } + } + + // Handle op3 + if (op3->IsVectorZero()) + { + // When we are merging with zero, we can specialize + // and avoid instantiating the vector constant. + MakeSrcContained(node, op3); + } + + break; + } + default: unreached(); } diff --git a/src/coreclr/jit/lowerxarch.cpp b/src/coreclr/jit/lowerxarch.cpp index 5a9b12ca4aa274..0e18c5685066fc 100644 --- a/src/coreclr/jit/lowerxarch.cpp +++ b/src/coreclr/jit/lowerxarch.cpp @@ -2970,7 +2970,7 @@ GenTree* Lowering::LowerHWIntrinsicCndSel(GenTreeHWIntrinsic* node) } //---------------------------------------------------------------------------------------------- -// Lowering::LowerHWIntrinsicCndSel: Lowers an AVX512 TernaryLogic call +// Lowering::LowerHWIntrinsicTernaryLogic: Lowers an AVX512 TernaryLogic call // // Arguments: // node - The hardware intrinsic node. @@ -10137,7 +10137,7 @@ void Lowering::ContainCheckHWIntrinsic(GenTreeHWIntrinsic* node) // contained and not a memory operand and know to invoke the special handling // so that the embedded masking can work as expected. - if (op2->isEvexEmbeddedMaskingCompatibleHWIntrinsic()) + if (op2->isEmbeddedMaskingCompatibleHWIntrinsic()) { uint32_t maskSize = genTypeSize(simdBaseType); uint32_t operSize = genTypeSize(op2->AsHWIntrinsic()->GetSimdBaseType()); diff --git a/src/coreclr/jit/lsrabuild.cpp b/src/coreclr/jit/lsrabuild.cpp index 3ee0f88ee2214f..37fa4320cc6918 100644 --- a/src/coreclr/jit/lsrabuild.cpp +++ b/src/coreclr/jit/lsrabuild.cpp @@ -3489,6 +3489,16 @@ int LinearScan::BuildOperandUses(GenTree* node, regMaskTP candidates) if (numArgs != 1) { +#ifdef TARGET_ARM64 + if (HWIntrinsicInfo::IsScalable(hwintrinsic->GetHWIntrinsicId())) + { + for (size_t argNum = 1; argNum <= numArgs; argNum++) + { + BuildOperandUses(hwintrinsic->Op(argNum), candidates); + } + return (int)numArgs; + } +#endif assert(numArgs == 2); assert(hwintrinsic->Op(2)->isContained()); assert(hwintrinsic->Op(2)->IsCnsIntOrI()); diff --git a/src/coreclr/jit/ssabuilder.cpp b/src/coreclr/jit/ssabuilder.cpp index caba13f3536abc..0a5229e32b8b7c 100644 --- a/src/coreclr/jit/ssabuilder.cpp +++ b/src/coreclr/jit/ssabuilder.cpp @@ -965,8 +965,8 @@ void SsaBuilder::AddPhiArgsToSuccessors(BasicBlock* block) // Walk the statements for phi nodes. for (Statement* const stmt : succ->Statements()) { - // A prefix of the statements of the block are phi definition nodes. If we complete processing - // that prefix, exit. + // A prefix of the statements of the block are phi definition nodes. If we complete + // processing that prefix, exit. if (!stmt->IsPhiDefnStmt()) { break; @@ -988,8 +988,9 @@ void SsaBuilder::AddPhiArgsToSuccessors(BasicBlock* block) { if ((memoryKind == GcHeap) && m_pCompiler->byrefStatesMatchGcHeapStates) { - // We've already propagated the "out" number to the phi shared with ByrefExposed, - // but still need to update bbMemorySsaPhiFunc to be in sync between GcHeap and ByrefExposed. + // We've already propagated the "out" number to the phi shared with + // ByrefExposed, but still need to update bbMemorySsaPhiFunc to be in sync + // between GcHeap and ByrefExposed. assert(memoryKind > ByrefExposed); assert(block->bbMemorySsaNumOut[memoryKind] == block->bbMemorySsaNumOut[ByrefExposed]); assert((succ->bbMemorySsaPhiFunc[ByrefExposed] == succMemoryPhi) || @@ -1009,8 +1010,9 @@ void SsaBuilder::AddPhiArgsToSuccessors(BasicBlock* block) BasicBlock::MemoryPhiArg* curArg = succMemoryPhi; unsigned ssaNum = block->bbMemorySsaNumOut[memoryKind]; bool found = false; - // This is a quadratic algorithm. We might need to consider some switch over to a hash table - // representation for the arguments of a phi node, to make this linear. + // This is a quadratic algorithm. We might need to consider some switch over + // to a hash table representation for the arguments of a phi node, to make this + // linear. while (curArg != nullptr) { if (curArg->m_ssaNum == ssaNum) diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Arm/Sve.PlatformNotSupported.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Arm/Sve.PlatformNotSupported.cs index fbd5ee65ca748f..8d56e32fc863ca 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Arm/Sve.PlatformNotSupported.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Arm/Sve.PlatformNotSupported.cs @@ -31,6 +31,125 @@ internal Arm64() { } public static new bool IsSupported { [Intrinsic] get { return false; } } } + + /// Abs : Absolute value + + /// + /// svint8_t svabs[_s8]_m(svint8_t inactive, svbool_t pg, svint8_t op) + /// svint8_t svabs[_s8]_x(svbool_t pg, svint8_t op) + /// svint8_t svabs[_s8]_z(svbool_t pg, svint8_t op) + /// + public static unsafe Vector Abs(Vector value) { throw new PlatformNotSupportedException(); } + + /// + /// svint16_t svabs[_s16]_m(svint16_t inactive, svbool_t pg, svint16_t op) + /// svint16_t svabs[_s16]_x(svbool_t pg, svint16_t op) + /// svint16_t svabs[_s16]_z(svbool_t pg, svint16_t op) + /// + public static unsafe Vector Abs(Vector value) { throw new PlatformNotSupportedException(); } + + /// + /// svint32_t svabs[_s32]_m(svint32_t inactive, svbool_t pg, svint32_t op) + /// svint32_t svabs[_s32]_x(svbool_t pg, svint32_t op) + /// svint32_t svabs[_s32]_z(svbool_t pg, svint32_t op) + /// + public static unsafe Vector Abs(Vector value) { throw new PlatformNotSupportedException(); } + + /// + /// svint64_t svabs[_s64]_m(svint64_t inactive, svbool_t pg, svint64_t op) + /// svint64_t svabs[_s64]_x(svbool_t pg, svint64_t op) + /// svint64_t svabs[_s64]_z(svbool_t pg, svint64_t op) + /// + public static unsafe Vector Abs(Vector value) { throw new PlatformNotSupportedException(); } + + /// + /// svfloat32_t svabs[_f32]_m(svfloat32_t inactive, svbool_t pg, svfloat32_t op) + /// svfloat32_t svabs[_f32]_x(svbool_t pg, svfloat32_t op) + /// svfloat32_t svabs[_f32]_z(svbool_t pg, svfloat32_t op) + /// + public static unsafe Vector Abs(Vector value) { throw new PlatformNotSupportedException(); } + + /// + /// svfloat64_t svabs[_f64]_m(svfloat64_t inactive, svbool_t pg, svfloat64_t op) + /// svfloat64_t svabs[_f64]_x(svbool_t pg, svfloat64_t op) + /// svfloat64_t svabs[_f64]_z(svbool_t pg, svfloat64_t op) + /// + public static unsafe Vector Abs(Vector value) { throw new PlatformNotSupportedException(); } + + + /// Add : Add + + /// + /// svint8_t svadd[_s8]_m(svbool_t pg, svint8_t op1, svint8_t op2) + /// svint8_t svadd[_s8]_x(svbool_t pg, svint8_t op1, svint8_t op2) + /// svint8_t svadd[_s8]_z(svbool_t pg, svint8_t op1, svint8_t op2) + /// + public static unsafe Vector Add(Vector left, Vector right) { throw new PlatformNotSupportedException(); } + + /// + /// svint16_t svadd[_s16]_m(svbool_t pg, svint16_t op1, svint16_t op2) + /// svint16_t svadd[_s16]_x(svbool_t pg, svint16_t op1, svint16_t op2) + /// svint16_t svadd[_s16]_z(svbool_t pg, svint16_t op1, svint16_t op2) + /// + public static unsafe Vector Add(Vector left, Vector right) { throw new PlatformNotSupportedException(); } + + /// + /// svint32_t svadd[_s32]_m(svbool_t pg, svint32_t op1, svint32_t op2) + /// svint32_t svadd[_s32]_x(svbool_t pg, svint32_t op1, svint32_t op2) + /// svint32_t svadd[_s32]_z(svbool_t pg, svint32_t op1, svint32_t op2) + /// + public static unsafe Vector Add(Vector left, Vector right) { throw new PlatformNotSupportedException(); } + + /// + /// svint64_t svadd[_s64]_m(svbool_t pg, svint64_t op1, svint64_t op2) + /// svint64_t svadd[_s64]_x(svbool_t pg, svint64_t op1, svint64_t op2) + /// svint64_t svadd[_s64]_z(svbool_t pg, svint64_t op1, svint64_t op2) + /// + public static unsafe Vector Add(Vector left, Vector right) { throw new PlatformNotSupportedException(); } + + /// + /// svuint8_t svadd[_u8]_m(svbool_t pg, svuint8_t op1, svuint8_t op2) + /// svuint8_t svadd[_u8]_x(svbool_t pg, svuint8_t op1, svuint8_t op2) + /// svuint8_t svadd[_u8]_z(svbool_t pg, svuint8_t op1, svuint8_t op2) + /// + public static unsafe Vector Add(Vector left, Vector right) { throw new PlatformNotSupportedException(); } + + /// + /// svuint16_t svadd[_u16]_m(svbool_t pg, svuint16_t op1, svuint16_t op2) + /// svuint16_t svadd[_u16]_x(svbool_t pg, svuint16_t op1, svuint16_t op2) + /// svuint16_t svadd[_u16]_z(svbool_t pg, svuint16_t op1, svuint16_t op2) + /// + public static unsafe Vector Add(Vector left, Vector right) { throw new PlatformNotSupportedException(); } + + /// + /// svuint32_t svadd[_u32]_m(svbool_t pg, svuint32_t op1, svuint32_t op2) + /// svuint32_t svadd[_u32]_x(svbool_t pg, svuint32_t op1, svuint32_t op2) + /// svuint32_t svadd[_u32]_z(svbool_t pg, svuint32_t op1, svuint32_t op2) + /// + public static unsafe Vector Add(Vector left, Vector right) { throw new PlatformNotSupportedException(); } + + /// + /// svuint64_t svadd[_u64]_m(svbool_t pg, svuint64_t op1, svuint64_t op2) + /// svuint64_t svadd[_u64]_x(svbool_t pg, svuint64_t op1, svuint64_t op2) + /// svuint64_t svadd[_u64]_z(svbool_t pg, svuint64_t op1, svuint64_t op2) + /// + public static unsafe Vector Add(Vector left, Vector right) { throw new PlatformNotSupportedException(); } + + /// + /// svfloat32_t svadd[_f32]_m(svbool_t pg, svfloat32_t op1, svfloat32_t op2) + /// svfloat32_t svadd[_f32]_x(svbool_t pg, svfloat32_t op1, svfloat32_t op2) + /// svfloat32_t svadd[_f32]_z(svbool_t pg, svfloat32_t op1, svfloat32_t op2) + /// + public static unsafe Vector Add(Vector left, Vector right) { throw new PlatformNotSupportedException(); } + + /// + /// svfloat64_t svadd[_f64]_m(svbool_t pg, svfloat64_t op1, svfloat64_t op2) + /// svfloat64_t svadd[_f64]_x(svbool_t pg, svfloat64_t op1, svfloat64_t op2) + /// svfloat64_t svadd[_f64]_z(svbool_t pg, svfloat64_t op1, svfloat64_t op2) + /// + public static unsafe Vector Add(Vector left, Vector right) { throw new PlatformNotSupportedException(); } + + /// CreateTrueMaskByte : Set predicate elements to true /// @@ -120,7 +239,65 @@ internal Arm64() { } /// public static unsafe Vector CreateTrueMaskUInt64([ConstantExpected] SveMaskPattern pattern = SveMaskPattern.All) { throw new PlatformNotSupportedException(); } + /// ConditionalSelect : Conditionally select elements + + /// + /// svint8_t svsel[_s8](svbool_t pg, svint8_t op1, svint8_t op2) + /// svbool_t svsel[_b](svbool_t pg, svbool_t op1, svbool_t op2) + /// + public static unsafe Vector ConditionalSelect(Vector mask, Vector left, Vector right) { throw new PlatformNotSupportedException(); } + + /// + /// svint16_t svsel[_s16](svbool_t pg, svint16_t op1, svint16_t op2) + /// svbool_t svsel[_b](svbool_t pg, svbool_t op1, svbool_t op2) + /// + public static unsafe Vector ConditionalSelect(Vector mask, Vector left, Vector right) { throw new PlatformNotSupportedException(); } + + /// + /// svint32_t svsel[_s32](svbool_t pg, svint32_t op1, svint32_t op2) + /// svbool_t svsel[_b](svbool_t pg, svbool_t op1, svbool_t op2) + /// + public static unsafe Vector ConditionalSelect(Vector mask, Vector left, Vector right) { throw new PlatformNotSupportedException(); } + /// + /// svint64_t svsel[_s64](svbool_t pg, svint64_t op1, svint64_t op2) + /// svbool_t svsel[_b](svbool_t pg, svbool_t op1, svbool_t op2) + /// + public static unsafe Vector ConditionalSelect(Vector mask, Vector left, Vector right) { throw new PlatformNotSupportedException(); } + + /// + /// svuint8_t svsel[_u8](svbool_t pg, svuint8_t op1, svuint8_t op2) + /// svbool_t svsel[_b](svbool_t pg, svbool_t op1, svbool_t op2) + /// + public static unsafe Vector ConditionalSelect(Vector mask, Vector left, Vector right) { throw new PlatformNotSupportedException(); } + + /// + /// svuint16_t svsel[_u16](svbool_t pg, svuint16_t op1, svuint16_t op2) + /// svbool_t svsel[_b](svbool_t pg, svbool_t op1, svbool_t op2) + /// + public static unsafe Vector ConditionalSelect(Vector mask, Vector left, Vector right) { throw new PlatformNotSupportedException(); } + + /// + /// svuint32_t svsel[_u32](svbool_t pg, svuint32_t op1, svuint32_t op2) + /// svbool_t svsel[_b](svbool_t pg, svbool_t op1, svbool_t op2) + /// + public static unsafe Vector ConditionalSelect(Vector mask, Vector left, Vector right) { throw new PlatformNotSupportedException(); } + + /// + /// svuint64_t svsel[_u64](svbool_t pg, svuint64_t op1, svuint64_t op2) + /// svbool_t svsel[_b](svbool_t pg, svbool_t op1, svbool_t op2) + /// + public static unsafe Vector ConditionalSelect(Vector mask, Vector left, Vector right) { throw new PlatformNotSupportedException(); } + + /// + /// svfloat32_t svsel[_f32](svbool_t pg, svfloat32_t op1, svfloat32_t op2) + /// + public static unsafe Vector ConditionalSelect(Vector mask, Vector left, Vector right) { throw new PlatformNotSupportedException(); } + + /// + /// svfloat64_t svsel[_f64](svbool_t pg, svfloat64_t op1, svfloat64_t op2) + /// + public static unsafe Vector ConditionalSelect(Vector mask, Vector left, Vector right) { throw new PlatformNotSupportedException(); } /// LoadVector : Unextended load diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Arm/Sve.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Arm/Sve.cs index 6ba2a2c67bc8a7..a13957916f49a7 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Arm/Sve.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Arm/Sve.cs @@ -29,6 +29,154 @@ internal Arm64() { } } + /// Abs : Absolute value + + /// + /// svint8_t svabs[_s8]_m(svint8_t inactive, svbool_t pg, svint8_t op) + /// ABS Ztied.B, Pg/M, Zop.B + /// MOVPRFX Zresult, Zinactive; ABS Zresult.B, Pg/M, Zop.B + /// svint8_t svabs[_s8]_x(svbool_t pg, svint8_t op) + /// ABS Ztied.B, Pg/M, Ztied.B + /// MOVPRFX Zresult, Zop; ABS Zresult.B, Pg/M, Zop.B + /// svint8_t svabs[_s8]_z(svbool_t pg, svint8_t op) + /// MOVPRFX Zresult.B, Pg/Z, Zop.B; ABS Zresult.B, Pg/M, Zop.B + /// + public static unsafe Vector Abs(Vector value) => Abs(value); + + /// + /// svint16_t svabs[_s16]_m(svint16_t inactive, svbool_t pg, svint16_t op) + /// ABS Ztied.H, Pg/M, Zop.H + /// MOVPRFX Zresult, Zinactive; ABS Zresult.H, Pg/M, Zop.H + /// svint16_t svabs[_s16]_x(svbool_t pg, svint16_t op) + /// ABS Ztied.H, Pg/M, Ztied.H + /// MOVPRFX Zresult, Zop; ABS Zresult.H, Pg/M, Zop.H + /// svint16_t svabs[_s16]_z(svbool_t pg, svint16_t op) + /// MOVPRFX Zresult.H, Pg/Z, Zop.H; ABS Zresult.H, Pg/M, Zop.H + /// + public static unsafe Vector Abs(Vector value) => Abs(value); + + /// + /// svint32_t svabs[_s32]_m(svint32_t inactive, svbool_t pg, svint32_t op) + /// ABS Ztied.S, Pg/M, Zop.S + /// MOVPRFX Zresult, Zinactive; ABS Zresult.S, Pg/M, Zop.S + /// svint32_t svabs[_s32]_x(svbool_t pg, svint32_t op) + /// ABS Ztied.S, Pg/M, Ztied.S + /// MOVPRFX Zresult, Zop; ABS Zresult.S, Pg/M, Zop.S + /// svint32_t svabs[_s32]_z(svbool_t pg, svint32_t op) + /// MOVPRFX Zresult.S, Pg/Z, Zop.S; ABS Zresult.S, Pg/M, Zop.S + /// + public static unsafe Vector Abs(Vector value) => Abs(value); + + /// + /// svint64_t svabs[_s64]_m(svint64_t inactive, svbool_t pg, svint64_t op) + /// ABS Ztied.D, Pg/M, Zop.D + /// MOVPRFX Zresult, Zinactive; ABS Zresult.D, Pg/M, Zop.D + /// svint64_t svabs[_s64]_x(svbool_t pg, svint64_t op) + /// ABS Ztied.D, Pg/M, Ztied.D + /// MOVPRFX Zresult, Zop; ABS Zresult.D, Pg/M, Zop.D + /// svint64_t svabs[_s64]_z(svbool_t pg, svint64_t op) + /// MOVPRFX Zresult.D, Pg/Z, Zop.D; ABS Zresult.D, Pg/M, Zop.D + /// + public static unsafe Vector Abs(Vector value) => Abs(value); + + /// + /// svfloat32_t svabs[_f32]_m(svfloat32_t inactive, svbool_t pg, svfloat32_t op) + /// FABS Ztied.S, Pg/M, Zop.S + /// MOVPRFX Zresult, Zinactive; FABS Zresult.S, Pg/M, Zop.S + /// svfloat32_t svabs[_f32]_x(svbool_t pg, svfloat32_t op) + /// FABS Ztied.S, Pg/M, Ztied.S + /// MOVPRFX Zresult, Zop; FABS Zresult.S, Pg/M, Zop.S + /// svfloat32_t svabs[_f32]_z(svbool_t pg, svfloat32_t op) + /// MOVPRFX Zresult.S, Pg/Z, Zop.S; FABS Zresult.S, Pg/M, Zop.S + /// + public static unsafe Vector Abs(Vector value) => Abs(value); + + /// + /// svfloat64_t svabs[_f64]_m(svfloat64_t inactive, svbool_t pg, svfloat64_t op) + /// FABS Ztied.D, Pg/M, Zop.D + /// MOVPRFX Zresult, Zinactive; FABS Zresult.D, Pg/M, Zop.D + /// svfloat64_t svabs[_f64]_x(svbool_t pg, svfloat64_t op) + /// FABS Ztied.D, Pg/M, Ztied.D + /// MOVPRFX Zresult, Zop; FABS Zresult.D, Pg/M, Zop.D + /// svfloat64_t svabs[_f64]_z(svbool_t pg, svfloat64_t op) + /// MOVPRFX Zresult.D, Pg/Z, Zop.D; FABS Zresult.D, Pg/M, Zop.D + /// + public static unsafe Vector Abs(Vector value) => Abs(value); + + + /// Add : Add + + /// + /// svint8_t svadd[_s8]_m(svbool_t pg, svint8_t op1, svint8_t op2) + /// svint8_t svadd[_s8]_x(svbool_t pg, svint8_t op1, svint8_t op2) + /// svint8_t svadd[_s8]_z(svbool_t pg, svint8_t op1, svint8_t op2) + /// + public static unsafe Vector Add(Vector left, Vector right) => Add(left, right); + + /// + /// svint16_t svadd[_s16]_m(svbool_t pg, svint16_t op1, svint16_t op2) + /// svint16_t svadd[_s16]_x(svbool_t pg, svint16_t op1, svint16_t op2) + /// svint16_t svadd[_s16]_z(svbool_t pg, svint16_t op1, svint16_t op2) + /// + public static unsafe Vector Add(Vector left, Vector right) => Add(left, right); + + /// + /// svint32_t svadd[_s32]_m(svbool_t pg, svint32_t op1, svint32_t op2) + /// svint32_t svadd[_s32]_x(svbool_t pg, svint32_t op1, svint32_t op2) + /// svint32_t svadd[_s32]_z(svbool_t pg, svint32_t op1, svint32_t op2) + /// + public static unsafe Vector Add(Vector left, Vector right) => Add(left, right); + + /// + /// svint64_t svadd[_s64]_m(svbool_t pg, svint64_t op1, svint64_t op2) + /// svint64_t svadd[_s64]_x(svbool_t pg, svint64_t op1, svint64_t op2) + /// svint64_t svadd[_s64]_z(svbool_t pg, svint64_t op1, svint64_t op2) + /// + public static unsafe Vector Add(Vector left, Vector right) => Add(left, right); + + /// + /// svuint8_t svadd[_u8]_m(svbool_t pg, svuint8_t op1, svuint8_t op2) + /// svuint8_t svadd[_u8]_x(svbool_t pg, svuint8_t op1, svuint8_t op2) + /// svuint8_t svadd[_u8]_z(svbool_t pg, svuint8_t op1, svuint8_t op2) + /// + public static unsafe Vector Add(Vector left, Vector right) => Add(left, right); + + /// + /// svuint16_t svadd[_u16]_m(svbool_t pg, svuint16_t op1, svuint16_t op2) + /// svuint16_t svadd[_u16]_x(svbool_t pg, svuint16_t op1, svuint16_t op2) + /// svuint16_t svadd[_u16]_z(svbool_t pg, svuint16_t op1, svuint16_t op2) + /// + public static unsafe Vector Add(Vector left, Vector right) => Add(left, right); + + /// + /// svuint32_t svadd[_u32]_m(svbool_t pg, svuint32_t op1, svuint32_t op2) + /// svuint32_t svadd[_u32]_x(svbool_t pg, svuint32_t op1, svuint32_t op2) + /// svuint32_t svadd[_u32]_z(svbool_t pg, svuint32_t op1, svuint32_t op2) + /// + public static unsafe Vector Add(Vector left, Vector right) => Add(left, right); + + /// + /// svuint64_t svadd[_u64]_m(svbool_t pg, svuint64_t op1, svuint64_t op2) + /// svuint64_t svadd[_u64]_x(svbool_t pg, svuint64_t op1, svuint64_t op2) + /// svuint64_t svadd[_u64]_z(svbool_t pg, svuint64_t op1, svuint64_t op2) + /// + public static unsafe Vector Add(Vector left, Vector right) => Add(left, right); + + /// + /// svfloat32_t svadd[_f32]_m(svbool_t pg, svfloat32_t op1, svfloat32_t op2) + /// svfloat32_t svadd[_f32]_x(svbool_t pg, svfloat32_t op1, svfloat32_t op2) + /// svfloat32_t svadd[_f32]_z(svbool_t pg, svfloat32_t op1, svfloat32_t op2) + /// + public static unsafe Vector Add(Vector left, Vector right) => Add(left, right); + + /// + /// svfloat64_t svadd[_f64]_m(svbool_t pg, svfloat64_t op1, svfloat64_t op2) + /// svfloat64_t svadd[_f64]_x(svbool_t pg, svfloat64_t op1, svfloat64_t op2) + /// svfloat64_t svadd[_f64]_z(svbool_t pg, svfloat64_t op1, svfloat64_t op2) + /// + public static unsafe Vector Add(Vector left, Vector right) => Add(left, right); + + /// CreateTrueMaskByte : Set predicate elements to true /// @@ -118,7 +266,93 @@ internal Arm64() { } /// public static unsafe Vector CreateTrueMaskUInt64([ConstantExpected] SveMaskPattern pattern = SveMaskPattern.All) => CreateTrueMaskUInt64(pattern); + /// ConditionalSelect : Conditionally select elements + + /// + /// svint8_t svsel[_s8](svbool_t pg, svint8_t op1, svint8_t op2) + /// SEL Zresult.B, Pg, Zop1.B, Zop2.B + /// svbool_t svsel[_b](svbool_t pg, svbool_t op1, svbool_t op2) + /// SEL Presult.B, Pg, Pop1.B, Pop2.B + /// + /// + public static unsafe Vector ConditionalSelect(Vector mask, Vector left, Vector right) => ConditionalSelect(mask, left, right); + + /// + /// svint16_t svsel[_s16](svbool_t pg, svint16_t op1, svint16_t op2) + /// SEL Zresult.H, Pg, Zop1.H, Zop2.H + /// svbool_t svsel[_b](svbool_t pg, svbool_t op1, svbool_t op2) + /// SEL Presult.B, Pg, Pop1.B, Pop2.B + /// + /// + public static unsafe Vector ConditionalSelect(Vector mask, Vector left, Vector right) => ConditionalSelect(mask, left, right); + + /// + /// svint32_t svsel[_s32](svbool_t pg, svint32_t op1, svint32_t op2) + /// SEL Zresult.S, Pg, Zop1.S, Zop2.S + /// svbool_t svsel[_b](svbool_t pg, svbool_t op1, svbool_t op2) + /// SEL Presult.B, Pg, Pop1.B, Pop2.B + /// + /// + public static unsafe Vector ConditionalSelect(Vector mask, Vector left, Vector right) => ConditionalSelect(mask, left, right); + + /// + /// svint64_t svsel[_s64](svbool_t pg, svint64_t op1, svint64_t op2) + /// SEL Zresult.D, Pg, Zop1.D, Zop2.D + /// svbool_t svsel[_b](svbool_t pg, svbool_t op1, svbool_t op2) + /// SEL Presult.B, Pg, Pop1.B, Pop2.B + /// + /// + public static unsafe Vector ConditionalSelect(Vector mask, Vector left, Vector right) => ConditionalSelect(mask, left, right); + + /// + /// svuint8_t svsel[_u8](svbool_t pg, svuint8_t op1, svuint8_t op2) + /// SEL Zresult.B, Pg, Zop1.B, Zop2.B + /// svbool_t svsel[_b](svbool_t pg, svbool_t op1, svbool_t op2) + /// SEL Presult.B, Pg, Pop1.B, Pop2.B + /// + /// + public static unsafe Vector ConditionalSelect(Vector mask, Vector left, Vector right) => ConditionalSelect(mask, left, right); + + /// + /// svuint16_t svsel[_u16](svbool_t pg, svuint16_t op1, svuint16_t op2) + /// SEL Zresult.H, Pg, Zop1.H, Zop2.H + /// svbool_t svsel[_b](svbool_t pg, svbool_t op1, svbool_t op2) + /// SEL Presult.B, Pg, Pop1.B, Pop2.B + /// + /// + public static unsafe Vector ConditionalSelect(Vector mask, Vector left, Vector right) => ConditionalSelect(mask, left, right); + + /// + /// svuint32_t svsel[_u32](svbool_t pg, svuint32_t op1, svuint32_t op2) + /// SEL Zresult.S, Pg, Zop1.S, Zop2.S + /// svbool_t svsel[_b](svbool_t pg, svbool_t op1, svbool_t op2) + /// SEL Presult.B, Pg, Pop1.B, Pop2.B + /// + /// + public static unsafe Vector ConditionalSelect(Vector mask, Vector left, Vector right) => ConditionalSelect(mask, left, right); + + /// + /// svuint64_t svsel[_u64](svbool_t pg, svuint64_t op1, svuint64_t op2) + /// SEL Zresult.D, Pg, Zop1.D, Zop2.D + /// svbool_t svsel[_b](svbool_t pg, svbool_t op1, svbool_t op2) + /// SEL Presult.B, Pg, Pop1.B, Pop2.B + /// + /// + public static unsafe Vector ConditionalSelect(Vector mask, Vector left, Vector right) => ConditionalSelect(mask, left, right); + /// + /// svfloat32_t svsel[_f32](svbool_t pg, svfloat32_t op1, svfloat32_t op2) + /// SEL Zresult.S, Pg, Zop1.S, Zop2.S + /// + /// + public static unsafe Vector ConditionalSelect(Vector mask, Vector left, Vector right) => ConditionalSelect(mask, left, right); + + /// + /// svfloat64_t svsel[_f64](svbool_t pg, svfloat64_t op1, svfloat64_t op2) + /// SEL Zresult.D, Pg, Zop1.D, Zop2.D + /// + /// + public static unsafe Vector ConditionalSelect(Vector mask, Vector left, Vector right) => ConditionalSelect(mask, left, right); /// LoadVector : Unextended load diff --git a/src/libraries/System.Runtime.Intrinsics/ref/System.Runtime.Intrinsics.cs b/src/libraries/System.Runtime.Intrinsics/ref/System.Runtime.Intrinsics.cs index bd7871cdf99065..3980308ca0d20e 100644 --- a/src/libraries/System.Runtime.Intrinsics/ref/System.Runtime.Intrinsics.cs +++ b/src/libraries/System.Runtime.Intrinsics/ref/System.Runtime.Intrinsics.cs @@ -4171,7 +4171,22 @@ internal Sve() { } internal Arm64() { } public static new bool IsSupported { get { throw null; } } } - + public static System.Numerics.Vector Abs(System.Numerics.Vector value) { throw null; } + public static System.Numerics.Vector Abs(System.Numerics.Vector value) { throw null; } + public static System.Numerics.Vector Abs(System.Numerics.Vector value) { throw null; } + public static System.Numerics.Vector Abs(System.Numerics.Vector value) { throw null; } + public static System.Numerics.Vector Abs(System.Numerics.Vector value) { throw null; } + public static System.Numerics.Vector Abs(System.Numerics.Vector value) { throw null; } + public static System.Numerics.Vector Add(System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } + public static System.Numerics.Vector Add(System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } + public static System.Numerics.Vector Add(System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } + public static System.Numerics.Vector Add(System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } + public static System.Numerics.Vector Add(System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } + public static System.Numerics.Vector Add(System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } + public static System.Numerics.Vector Add(System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } + public static System.Numerics.Vector Add(System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } + public static System.Numerics.Vector Add(System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } + public static System.Numerics.Vector Add(System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } public static System.Numerics.Vector CreateTrueMaskByte([ConstantExpected] SveMaskPattern pattern = SveMaskPattern.All) { throw null; } public static System.Numerics.Vector CreateTrueMaskDouble([ConstantExpected] SveMaskPattern pattern = SveMaskPattern.All) { throw null; } public static System.Numerics.Vector CreateTrueMaskInt16([ConstantExpected] SveMaskPattern pattern = SveMaskPattern.All) { throw null; } @@ -4182,7 +4197,16 @@ internal Arm64() { } public static System.Numerics.Vector CreateTrueMaskUInt16([ConstantExpected] SveMaskPattern pattern = SveMaskPattern.All) { throw null; } public static System.Numerics.Vector CreateTrueMaskUInt32([ConstantExpected] SveMaskPattern pattern = SveMaskPattern.All) { throw null; } public static System.Numerics.Vector CreateTrueMaskUInt64([ConstantExpected] SveMaskPattern pattern = SveMaskPattern.All) { throw null; } - + public static System.Numerics.Vector ConditionalSelect(System.Numerics.Vector mask, System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } + public static System.Numerics.Vector ConditionalSelect(System.Numerics.Vector mask, System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } + public static System.Numerics.Vector ConditionalSelect(System.Numerics.Vector mask, System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } + public static System.Numerics.Vector ConditionalSelect(System.Numerics.Vector mask, System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } + public static System.Numerics.Vector ConditionalSelect(System.Numerics.Vector mask, System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } + public static System.Numerics.Vector ConditionalSelect(System.Numerics.Vector mask, System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } + public static System.Numerics.Vector ConditionalSelect(System.Numerics.Vector mask, System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } + public static System.Numerics.Vector ConditionalSelect(System.Numerics.Vector mask, System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } + public static System.Numerics.Vector ConditionalSelect(System.Numerics.Vector mask, System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } + public static System.Numerics.Vector ConditionalSelect(System.Numerics.Vector mask, System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } public static unsafe System.Numerics.Vector LoadVector(System.Numerics.Vector mask, sbyte* address) { throw null; } public static unsafe System.Numerics.Vector LoadVector(System.Numerics.Vector mask, short* address) { throw null; } public static unsafe System.Numerics.Vector LoadVector(System.Numerics.Vector mask, int* address) { throw null; } @@ -4193,7 +4217,6 @@ internal Arm64() { } public static unsafe System.Numerics.Vector LoadVector(System.Numerics.Vector mask, ulong* address) { throw null; } public static unsafe System.Numerics.Vector LoadVector(System.Numerics.Vector mask, float* address) { throw null; } public static unsafe System.Numerics.Vector LoadVector(System.Numerics.Vector mask, double* address) { throw null; } - } public enum SveMaskPattern : byte diff --git a/src/tests/Common/GenerateHWIntrinsicTests/GenerateHWIntrinsicTests_Arm.cs b/src/tests/Common/GenerateHWIntrinsicTests/GenerateHWIntrinsicTests_Arm.cs index b5f42595ca77e3..a2ebacb1ce8b8c 100644 --- a/src/tests/Common/GenerateHWIntrinsicTests/GenerateHWIntrinsicTests_Arm.cs +++ b/src/tests/Common/GenerateHWIntrinsicTests/GenerateHWIntrinsicTests_Arm.cs @@ -47,6 +47,16 @@ } }"; +const string SimpleVecOpTest_ValidationLogicForCndSel = @"for (var i = 0; i < RetElementCount; i++) + { + {Op1BaseType} iterResult = (mask[i] != 0) ? {GetIterResult} : falseVal[i]; + if (iterResult != result[i]) + { + succeeded = false; + break; + } + }"; + const string VecPairBinOpTest_ValidationLogic = @" int index = 0; int half = RetElementCount / 2; @@ -107,7 +117,9 @@ ("_TernaryOpTestTemplate.template", "SimpleTernOpTest.template", new Dictionary { ["TemplateName"] = "Simple", ["TemplateValidationLogic"] = SimpleOpTest_ValidationLogic }), ("_UnaryOpTestTemplate.template", "SecureHashUnOpTest.template", new Dictionary { ["TemplateName"] = "SecureHash", ["TemplateValidationLogic"] = SecureHashOpTest_ValidationLogic }), ("_BinaryOpTestTemplate.template", "SecureHashBinOpTest.template", new Dictionary { ["TemplateName"] = "SecureHash", ["TemplateValidationLogic"] = SecureHashOpTest_ValidationLogic }), - ("_TernaryOpTestTemplate.template", "SecureHashTernOpTest.template", new Dictionary { ["TemplateName"] = "SecureHash", ["TemplateValidationLogic"] = SecureHashOpTest_ValidationLogic }) + ("_TernaryOpTestTemplate.template", "SecureHashTernOpTest.template", new Dictionary { ["TemplateName"] = "SecureHash", ["TemplateValidationLogic"] = SecureHashOpTest_ValidationLogic }), + ("_SveUnaryOpTestTemplate.template", "SveSimpleVecOpTest.template", new Dictionary { ["TemplateName"] = "Simple", ["TemplateValidationLogic"] = SimpleVecOpTest_ValidationLogic, ["TemplateValidationLogicForCndSel"] = SimpleVecOpTest_ValidationLogicForCndSel }), + ("_SveBinaryOpTestTemplate.template", "SveVecBinOpTest.template", new Dictionary { ["TemplateName"] = "Simple", ["TemplateValidationLogic"] = SimpleVecOpTest_ValidationLogic, ["TemplateValidationLogicForCndSel"] = SimpleVecOpTest_ValidationLogicForCndSel }), }; (string templateFileName, Dictionary templateData)[] AdvSimdInputs = new [] @@ -2878,16 +2890,45 @@ (string templateFileName, Dictionary templateData)[] SveInputs = new [] { - ("SveLoadMaskedUnOpTest.template", new Dictionary { ["TestName"] = "SveLoadVector_float", ["Isa"] = "Sve", ["Method"] = "LoadVector", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Single", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), - ("SveLoadMaskedUnOpTest.template", new Dictionary { ["TestName"] = "SveLoadVector_double", ["Isa"] = "Sve", ["Method"] = "LoadVector", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Double", ["Op2BaseType"] = "Double", ["LargestVectorSize"] = "8", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), - ("SveLoadMaskedUnOpTest.template", new Dictionary { ["TestName"] = "SveLoadVector_sbyte", ["Isa"] = "Sve", ["Method"] = "LoadVector", ["RetVectorType"] = "Vector", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "SByte", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "8", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), - ("SveLoadMaskedUnOpTest.template", new Dictionary { ["TestName"] = "SveLoadVector_short", ["Isa"] = "Sve", ["Method"] = "LoadVector", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Int16", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "8", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), - ("SveLoadMaskedUnOpTest.template", new Dictionary { ["TestName"] = "SveLoadVector_int", ["Isa"] = "Sve", ["Method"] = "LoadVector", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Int32", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "8", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), - ("SveLoadMaskedUnOpTest.template", new Dictionary { ["TestName"] = "SveLoadVector_long", ["Isa"] = "Sve", ["Method"] = "LoadVector", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Int64", ["Op2BaseType"] = "Int64", ["LargestVectorSize"] = "8", ["NextValueOp2"] = "TestLibrary.Generator.GetInt64()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), - ("SveLoadMaskedUnOpTest.template", new Dictionary { ["TestName"] = "SveLoadVector_byte", ["Isa"] = "Sve", ["Method"] = "LoadVector", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Byte", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "8", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), - ("SveLoadMaskedUnOpTest.template", new Dictionary { ["TestName"] = "SveLoadVector_ushort", ["Isa"] = "Sve", ["Method"] = "LoadVector", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt16", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "8", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), - ("SveLoadMaskedUnOpTest.template", new Dictionary { ["TestName"] = "SveLoadVector_uint", ["Isa"] = "Sve", ["Method"] = "LoadVector", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt32", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "8", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), - ("SveLoadMaskedUnOpTest.template", new Dictionary { ["TestName"] = "SveLoadVector_ulong", ["Isa"] = "Sve", ["Method"] = "LoadVector", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt64", ["Op2BaseType"] = "UInt64", ["LargestVectorSize"] = "8", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt64()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), + ("SveSimpleVecOpTest.template", new Dictionary { ["TestName"] = "Sve_Abs_float", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "Abs", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Single", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "-TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "Helpers.Abs(firstOp[i]) != result[i]", ["GetIterResult"] = "Helpers.Abs(leftOp[i])"}), + ("SveSimpleVecOpTest.template", new Dictionary { ["TestName"] = "Sve_Abs_double", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "Abs", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Double", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "-TestLibrary.Generator.GetDouble()", ["ValidateIterResult"] = "Helpers.Abs(firstOp[i]) != result[i]", ["GetIterResult"] = "Helpers.Abs(leftOp[i])"}), + ("SveSimpleVecOpTest.template", new Dictionary { ["TestName"] = "Sve_Abs_sbyte", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "Abs", ["RetVectorType"] = "Vector", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "SByte", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "(sbyte)-TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.Abs(firstOp[i]) != result[i]", ["GetIterResult"] = "(sbyte)Helpers.Abs(leftOp[i])"}), + ("SveSimpleVecOpTest.template", new Dictionary { ["TestName"] = "Sve_Abs_short", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "Abs", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Int16", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "(short)-TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.Abs(firstOp[i]) != result[i]", ["GetIterResult"] = "(short)Helpers.Abs(leftOp[i])"}), + ("SveSimpleVecOpTest.template", new Dictionary { ["TestName"] = "Sve_Abs_int", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "Abs", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Int32", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "-TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.Abs(firstOp[i]) != result[i]", ["GetIterResult"] = "(int)Helpers.Abs(leftOp[i])"}), + ("SveSimpleVecOpTest.template", new Dictionary { ["TestName"] = "Sve_Abs_long", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "Abs", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Int64", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "-TestLibrary.Generator.GetInt64()", ["ValidateIterResult"] = "(long)Helpers.Abs(firstOp[i]) != (long)result[i]", ["GetIterResult"] = "(long)Helpers.Abs(leftOp[i])"}), + + ("SveVecBinOpTest.template", new Dictionary { ["TestName"] = "Sve_Add_float", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "Add", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "Helpers.Add(left[i], right[i]) != result[i]", ["GetIterResult"] = "Helpers.Add(left[i], right[i])"}), + ("SveVecBinOpTest.template", new Dictionary { ["TestName"] = "Sve_Add_double", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "Add", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "Double", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["ValidateIterResult"] = "Helpers.Add(left[i], right[i]) != result[i]", ["GetIterResult"] = "Helpers.Add(left[i], right[i])"}), + ("SveVecBinOpTest.template", new Dictionary { ["TestName"] = "Sve_Add_sbyte", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "Add", ["RetVectorType"] = "Vector", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "(sbyte)TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.Add(left[i], right[i]) != result[i]", ["GetIterResult"] = "Helpers.Add(left[i], right[i])"}), + ("SveVecBinOpTest.template", new Dictionary { ["TestName"] = "Sve_Add_short", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "Add", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "(short)TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.Add(left[i], right[i]) != result[i]", ["GetIterResult"] = "Helpers.Add(left[i], right[i])"}), + ("SveVecBinOpTest.template", new Dictionary { ["TestName"] = "Sve_Add_int", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "Add", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.Add(left[i], right[i]) != result[i]", ["GetIterResult"] = "Helpers.Add(left[i], right[i])"}), + ("SveVecBinOpTest.template", new Dictionary { ["TestName"] = "Sve_Add_long", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "Add", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Int64", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "Int64", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt64()", ["ValidateIterResult"] = "Helpers.Add(left[i], right[i]) != result[i]", ["GetIterResult"] = "Helpers.Add(left[i], right[i])"}), + ("SveVecBinOpTest.template", new Dictionary { ["TestName"] = "Sve_Add_byte", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "Add", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "(byte)TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "Helpers.Add(left[i], right[i]) != result[i]", ["GetIterResult"] = "Helpers.Add(left[i], right[i])"}), + ("SveVecBinOpTest.template", new Dictionary { ["TestName"] = "Sve_Add_ushort", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "Add", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "Helpers.Add(left[i], right[i]) != result[i]", ["GetIterResult"] = "Helpers.Add(left[i], right[i])"}), + ("SveVecBinOpTest.template", new Dictionary { ["TestName"] = "Sve_Add_uint", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "Add", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "Helpers.Add(left[i], right[i]) != result[i]", ["GetIterResult"] = "Helpers.Add(left[i], right[i])"}), + ("SveVecBinOpTest.template", new Dictionary { ["TestName"] = "Sve_Add_ulong", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "Add", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt64", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "UInt64", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt64()", ["ValidateIterResult"] = "Helpers.Add(left[i], right[i]) != result[i]", ["GetIterResult"] = "Helpers.Add(left[i], right[i])"}), + + ("SveConditionalSelect.template", new Dictionary { ["TestName"] = "Sve_ConditionalSelect_float", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "ConditionalSelect", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "Single", ["Op3VectorType"] = "Vector", ["Op3BaseType"] = "Single", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp3"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "(firstOp[i] != 0 ? (result[i] != secondOp[i]) : (result[i] != thirdOp[i]))",}), + ("SveConditionalSelect.template", new Dictionary { ["TestName"] = "Sve_ConditionalSelect_double", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "ConditionalSelect", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "Double", ["Op3VectorType"] = "Vector", ["Op3BaseType"] = "Double", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp3"] = "TestLibrary.Generator.GetDouble()", ["ValidateIterResult"] = "(firstOp[i] != 0 ? (result[i] != secondOp[i]) : (result[i] != thirdOp[i]))",}), + ("SveConditionalSelect.template", new Dictionary { ["TestName"] = "Sve_ConditionalSelect_sbyte", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "ConditionalSelect", ["RetVectorType"] = "Vector", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "SByte", ["Op3VectorType"] = "Vector", ["Op3BaseType"] = "SByte", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp3"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "(firstOp[i] != 0 ? (result[i] != secondOp[i]) : (result[i] != thirdOp[i]))",}), + ("SveConditionalSelect.template", new Dictionary { ["TestName"] = "Sve_ConditionalSelect_short", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "ConditionalSelect", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "Int16", ["Op3VectorType"] = "Vector", ["Op3BaseType"] = "Int16", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp3"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "(firstOp[i] != 0 ? (result[i] != secondOp[i]) : (result[i] != thirdOp[i]))",}), + ("SveConditionalSelect.template", new Dictionary { ["TestName"] = "Sve_ConditionalSelect_int", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "ConditionalSelect", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "Int32", ["Op3VectorType"] = "Vector", ["Op3BaseType"] = "Int32", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp3"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "(firstOp[i] != 0 ? (result[i] != secondOp[i]) : (result[i] != thirdOp[i]))",}), + ("SveConditionalSelect.template", new Dictionary { ["TestName"] = "Sve_ConditionalSelect_long", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "ConditionalSelect", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Int64", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "Int64", ["Op3VectorType"] = "Vector", ["Op3BaseType"] = "Int64", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt64()", ["NextValueOp3"] = "TestLibrary.Generator.GetInt64()", ["ValidateIterResult"] = "(firstOp[i] != 0 ? (result[i] != secondOp[i]) : (result[i] != thirdOp[i]))",}), + ("SveConditionalSelect.template", new Dictionary { ["TestName"] = "Sve_ConditionalSelect_byte", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "ConditionalSelect", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "Byte", ["Op3VectorType"] = "Vector", ["Op3BaseType"] = "Byte", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["NextValueOp3"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "(firstOp[i] != 0 ? (result[i] != secondOp[i]) : (result[i] != thirdOp[i]))",}), + ("SveConditionalSelect.template", new Dictionary { ["TestName"] = "Sve_ConditionalSelect_ushort", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "ConditionalSelect", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "UInt16", ["Op3VectorType"] = "Vector", ["Op3BaseType"] = "UInt16", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp3"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "(firstOp[i] != 0 ? (result[i] != secondOp[i]) : (result[i] != thirdOp[i]))",}), + ("SveConditionalSelect.template", new Dictionary { ["TestName"] = "Sve_ConditionalSelect_uint", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "ConditionalSelect", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "UInt32", ["Op3VectorType"] = "Vector", ["Op3BaseType"] = "UInt32", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp3"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "(firstOp[i] != 0 ? (result[i] != secondOp[i]) : (result[i] != thirdOp[i]))",}), + ("SveConditionalSelect.template", new Dictionary { ["TestName"] = "Sve_ConditionalSelect_ulong", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "ConditionalSelect", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt64", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "UInt64", ["Op3VectorType"] = "Vector", ["Op3BaseType"] = "UInt64", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt64()", ["NextValueOp3"] = "TestLibrary.Generator.GetUInt64()", ["ValidateIterResult"] = "(firstOp[i] != 0 ? (result[i] != secondOp[i]) : (result[i] != thirdOp[i]))",}), + + ("SveLoadMaskedUnOpTest.template", new Dictionary { ["TestName"] = "SveLoadVector_float", ["Isa"] = "Sve", ["Method"] = "LoadVector", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Single", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "64", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), + ("SveLoadMaskedUnOpTest.template", new Dictionary { ["TestName"] = "SveLoadVector_double", ["Isa"] = "Sve", ["Method"] = "LoadVector", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Double", ["Op2BaseType"] = "Double", ["LargestVectorSize"] = "64", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), + ("SveLoadMaskedUnOpTest.template", new Dictionary { ["TestName"] = "SveLoadVector_sbyte", ["Isa"] = "Sve", ["Method"] = "LoadVector", ["RetVectorType"] = "Vector", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "SByte", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "64", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), + ("SveLoadMaskedUnOpTest.template", new Dictionary { ["TestName"] = "SveLoadVector_short", ["Isa"] = "Sve", ["Method"] = "LoadVector", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Int16", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "64", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), + ("SveLoadMaskedUnOpTest.template", new Dictionary { ["TestName"] = "SveLoadVector_int", ["Isa"] = "Sve", ["Method"] = "LoadVector", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Int32", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "64", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), + ("SveLoadMaskedUnOpTest.template", new Dictionary { ["TestName"] = "SveLoadVector_long", ["Isa"] = "Sve", ["Method"] = "LoadVector", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Int64", ["Op2BaseType"] = "Int64", ["LargestVectorSize"] = "64", ["NextValueOp2"] = "TestLibrary.Generator.GetInt64()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), + ("SveLoadMaskedUnOpTest.template", new Dictionary { ["TestName"] = "SveLoadVector_byte", ["Isa"] = "Sve", ["Method"] = "LoadVector", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Byte", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "64", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), + ("SveLoadMaskedUnOpTest.template", new Dictionary { ["TestName"] = "SveLoadVector_ushort", ["Isa"] = "Sve", ["Method"] = "LoadVector", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt16", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "64", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), + ("SveLoadMaskedUnOpTest.template", new Dictionary { ["TestName"] = "SveLoadVector_uint", ["Isa"] = "Sve", ["Method"] = "LoadVector", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt32", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "64", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), + ("SveLoadMaskedUnOpTest.template", new Dictionary { ["TestName"] = "SveLoadVector_ulong", ["Isa"] = "Sve", ["Method"] = "LoadVector", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt64", ["Op2BaseType"] = "UInt64", ["LargestVectorSize"] = "64", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt64()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), }; diff --git a/src/tests/JIT/HardwareIntrinsics/Arm/Shared/SveConditionalSelect.template b/src/tests/JIT/HardwareIntrinsics/Arm/Shared/SveConditionalSelect.template new file mode 100644 index 00000000000000..963fa1713eec3b --- /dev/null +++ b/src/tests/JIT/HardwareIntrinsics/Arm/Shared/SveConditionalSelect.template @@ -0,0 +1,362 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; +using System.Numerics; +using Xunit; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + [Fact] + public static void {TestName}() + { + var test = new TernaryOpTest__{TestName}(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if ({LoadIsa}.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class TernaryOpTest__{TestName} + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] inArray3; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle inHandle3; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable({Op1BaseType}[] inArray1, {Op2BaseType}[] inArray2, {Op3BaseType}[] inArray3, {RetBaseType}[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf<{Op1BaseType}>(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf<{Op2BaseType}>(); + int sizeOfinArray3 = inArray3.Length * Unsafe.SizeOf<{Op3BaseType}>(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf<{RetBaseType}>(); + if ((alignment != 64 && alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfinArray3 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException($"Invalid value of alignment: {alignment}, sizeOfinArray1: {sizeOfinArray1}, sizeOfinArray2: {sizeOfinArray2}, sizeOfinArray3: {sizeOfinArray3}, sizeOfoutArray: {sizeOfoutArray}"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.inArray3 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.inHandle3 = GCHandle.Alloc(this.inArray3, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As<{Op1BaseType}, byte>(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As<{Op2BaseType}, byte>(ref inArray2[0]), (uint)sizeOfinArray2); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray3Ptr), ref Unsafe.As<{Op3BaseType}, byte>(ref inArray3[0]), (uint)sizeOfinArray3); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray3Ptr => Align((byte*)(inHandle3.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + inHandle3.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public {Op1VectorType}<{Op1BaseType}> _fld1; + public {Op2VectorType}<{Op2BaseType}> _fld2; + public {Op3VectorType}<{Op3BaseType}> _fld3; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = {NextValueOp1}; } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<{Op1VectorType}<{Op1BaseType}>, byte>(ref testStruct._fld1), ref Unsafe.As<{Op1BaseType}, byte>(ref _data1[0]), (uint)Unsafe.SizeOf<{Op1VectorType}<{Op1BaseType}>>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = {NextValueOp2}; } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<{Op2VectorType}<{Op2BaseType}>, byte>(ref testStruct._fld2), ref Unsafe.As<{Op2BaseType}, byte>(ref _data2[0]), (uint)Unsafe.SizeOf<{Op2VectorType}<{Op2BaseType}>>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = {NextValueOp3}; } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<{Op3VectorType}<{Op3BaseType}>, byte>(ref testStruct._fld3), ref Unsafe.As<{Op3BaseType}, byte>(ref _data3[0]), (uint)Unsafe.SizeOf<{Op3VectorType}<{Op3BaseType}>>()); + + return testStruct; + } + + public void RunStructFldScenario(TernaryOpTest__{TestName} testClass) + { + var result = {Isa}.{Method}(_fld1, _fld2, _fld3); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, _fld3, testClass._dataTable.outArrayPtr); + } + } + + private static readonly int LargestVectorSize = {LargestVectorSize}; + + private static readonly int Op1ElementCount = Unsafe.SizeOf<{Op1VectorType}<{Op1BaseType}>>() / sizeof({Op1BaseType}); + private static readonly int Op2ElementCount = Unsafe.SizeOf<{Op2VectorType}<{Op2BaseType}>>() / sizeof({Op2BaseType}); + private static readonly int Op3ElementCount = Unsafe.SizeOf<{Op3VectorType}<{Op3BaseType}>>() / sizeof({Op3BaseType}); + private static readonly int RetElementCount = Unsafe.SizeOf<{RetVectorType}<{RetBaseType}>>() / sizeof({RetBaseType}); + + private static {Op1BaseType}[] _data1 = new {Op1BaseType}[Op1ElementCount]; + private static {Op2BaseType}[] _data2 = new {Op2BaseType}[Op2ElementCount]; + private static {Op3BaseType}[] _data3 = new {Op3BaseType}[Op3ElementCount]; + + private {Op1VectorType}<{Op1BaseType}> _fld1; + private {Op2VectorType}<{Op2BaseType}> _fld2; + private {Op3VectorType}<{Op3BaseType}> _fld3; + + private DataTable _dataTable; + + public TernaryOpTest__{TestName}() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = {NextValueOp1}; } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<{Op1VectorType}<{Op1BaseType}>, byte>(ref _fld1), ref Unsafe.As<{Op1BaseType}, byte>(ref _data1[0]), (uint)Unsafe.SizeOf<{Op1VectorType}<{Op1BaseType}>>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = {NextValueOp2}; } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<{Op2VectorType}<{Op2BaseType}>, byte>(ref _fld2), ref Unsafe.As<{Op2BaseType}, byte>(ref _data2[0]), (uint)Unsafe.SizeOf<{Op2VectorType}<{Op2BaseType}>>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = {NextValueOp3}; } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<{Op3VectorType}<{Op3BaseType}>, byte>(ref _fld3), ref Unsafe.As<{Op3BaseType}, byte>(ref _data3[0]), (uint)Unsafe.SizeOf<{Op3VectorType}<{Op3BaseType}>>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = {NextValueOp1}; } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = {NextValueOp2}; } + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = {NextValueOp3}; } + _dataTable = new DataTable(_data1, _data2, _data3, new {RetBaseType}[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => {Isa}.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = {Isa}.{Method}( + Unsafe.Read<{Op1VectorType}<{Op1BaseType}>>(_dataTable.inArray1Ptr), + Unsafe.Read<{Op2VectorType}<{Op2BaseType}>>(_dataTable.inArray2Ptr), + Unsafe.Read<{Op3VectorType}<{Op3BaseType}>>(_dataTable.inArray3Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + //TODO-SVE: Once register allocation exists for predicates, move loadMask into DataTable + {Op1VectorType}<{Op1BaseType}> loadMask = Sve.CreateTrueMask{RetBaseType}(SveMaskPattern.All); + + var result = {Isa}.{Method}( + {LoadIsa}.Load{Op1VectorType}(loadMask, ({Op1BaseType}*)(_dataTable.inArray1Ptr)), + {LoadIsa}.Load{Op2VectorType}(loadMask, ({Op2BaseType}*)(_dataTable.inArray2Ptr)), + {LoadIsa}.Load{Op3VectorType}(loadMask, ({Op3BaseType}*)(_dataTable.inArray3Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof({Isa}).GetMethod(nameof({Isa}.{Method}), new Type[] { typeof({Op1VectorType}<{Op1BaseType}>), typeof({Op2VectorType}<{Op2BaseType}>), typeof({Op3VectorType}<{Op3BaseType}>) }) + .Invoke(null, new object[] { + Unsafe.Read<{Op1VectorType}<{Op1BaseType}>>(_dataTable.inArray1Ptr), + Unsafe.Read<{Op2VectorType}<{Op2BaseType}>>(_dataTable.inArray2Ptr), + Unsafe.Read<{Op3VectorType}<{Op3BaseType}>>(_dataTable.inArray3Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, ({RetVectorType}<{RetBaseType}>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read<{Op1VectorType}<{Op1BaseType}>>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read<{Op2VectorType}<{Op2BaseType}>>(_dataTable.inArray2Ptr); + var op3 = Unsafe.Read<{Op3VectorType}<{Op3BaseType}>>(_dataTable.inArray3Ptr); + var result = {Isa}.{Method}(op1, op2, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, op3, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = {Isa}.{Method}(_fld1, _fld2, _fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _fld3, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = {Isa}.{Method}(test._fld1, test._fld2, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult({Op1VectorType}<{Op1BaseType}> op1, {Op2VectorType}<{Op2BaseType}> op2, {Op3VectorType}<{Op3BaseType}> op3, void* result, [CallerMemberName] string method = "") + { + {Op1BaseType}[] inArray1 = new {Op1BaseType}[Op1ElementCount]; + {Op2BaseType}[] inArray2 = new {Op2BaseType}[Op2ElementCount]; + {Op3BaseType}[] inArray3 = new {Op3BaseType}[Op3ElementCount]; + {RetBaseType}[] outArray = new {RetBaseType}[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As<{Op1BaseType}, byte>(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As<{Op2BaseType}, byte>(ref inArray2[0]), op2); + Unsafe.WriteUnaligned(ref Unsafe.As<{Op3BaseType}, byte>(ref inArray3[0]), op3); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<{RetBaseType}, byte>(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf<{RetVectorType}<{RetBaseType}>>()); + + ValidateResult(inArray1, inArray2, inArray3, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* op3, void* result, [CallerMemberName] string method = "") + { + {Op1BaseType}[] inArray1 = new {Op1BaseType}[Op1ElementCount]; + {Op2BaseType}[] inArray2 = new {Op2BaseType}[Op2ElementCount]; + {Op3BaseType}[] inArray3 = new {Op3BaseType}[Op3ElementCount]; + {RetBaseType}[] outArray = new {RetBaseType}[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As<{Op1BaseType}, byte>(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf<{Op1VectorType}<{Op1BaseType}>>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<{Op2BaseType}, byte>(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf<{Op2VectorType}<{Op2BaseType}>>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<{Op3BaseType}, byte>(ref inArray3[0]), ref Unsafe.AsRef(op3), (uint)Unsafe.SizeOf<{Op3VectorType}<{Op3BaseType}>>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<{RetBaseType}, byte>(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf<{RetVectorType}<{RetBaseType}>>()); + + ValidateResult(inArray1, inArray2, inArray3, outArray, method); + } + + private void ValidateResult({Op1BaseType}[] firstOp, {Op2BaseType}[] secondOp, {Op3BaseType}[] thirdOp, {RetBaseType}[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if ({ValidateIterResult}) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof({Isa})}.{nameof({Isa}.{Method})}<{RetBaseType}>({Op1VectorType}<{Op1BaseType}>, {Op2VectorType}<{Op2BaseType}>, {Op3VectorType}<{Op3BaseType}>): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($"secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" thirdOp: ({string.Join(", ", thirdOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/tests/JIT/HardwareIntrinsics/Arm/Shared/SveLoadMaskedUnOpTest.template b/src/tests/JIT/HardwareIntrinsics/Arm/Shared/SveLoadMaskedUnOpTest.template index 09aaf2f442e136..d5a62e5cda1cf6 100644 --- a/src/tests/JIT/HardwareIntrinsics/Arm/Shared/SveLoadMaskedUnOpTest.template +++ b/src/tests/JIT/HardwareIntrinsics/Arm/Shared/SveLoadMaskedUnOpTest.template @@ -64,9 +64,9 @@ namespace JIT.HardwareIntrinsics.Arm { int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf<{Op2BaseType}>(); int sizeOfoutArray = outArray.Length * Unsafe.SizeOf<{RetBaseType}>(); - if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfoutArray) + if ((alignment != 64 && alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfoutArray) { - throw new ArgumentException("Invalid value of alignment"); + throw new ArgumentException($"Invalid value of alignment: {alignment}, sizeOfinArray1: {sizeOfinArray1}, sizeOfoutArray: {sizeOfoutArray}"); } this.inArray1 = new byte[alignment * 2]; diff --git a/src/tests/JIT/HardwareIntrinsics/Arm/Shared/_SveBinaryOpTestTemplate.template b/src/tests/JIT/HardwareIntrinsics/Arm/Shared/_SveBinaryOpTestTemplate.template new file mode 100644 index 00000000000000..bd15acab428a09 --- /dev/null +++ b/src/tests/JIT/HardwareIntrinsics/Arm/Shared/_SveBinaryOpTestTemplate.template @@ -0,0 +1,435 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Numerics; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; +using Xunit; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + [Fact] + public static void {TestName}() + { + var test = new {TemplateName}BinaryOpTest__{TestName}(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if ({LoadIsa}.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + // Validates executing the test inside conditional, with op1 as falseValue + test.ConditionalSelect_Op1(); + + // Validates executing the test inside conditional, with op2 as falseValue + test.ConditionalSelect_Op2(); + + // Validates executing the test inside conditional, with op3 as falseValue + test.ConditionalSelect_FalseOp(); + + // Validates executing the test inside conditional, with op3 as zero + test.ConditionalSelect_ZeroOp(); + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class {TemplateName}BinaryOpTest__{TestName} + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable({Op1BaseType}[] inArray1, {Op2BaseType}[] inArray2, {RetBaseType}[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf<{Op1BaseType}>(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf<{Op2BaseType}>(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf<{RetBaseType}>(); + if ((alignment != 64 && alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException($"Invalid value of alignment: {alignment}, sizeOfinArray1: {sizeOfinArray1}, sizeOfinArray2: {sizeOfinArray2}, sizeOfoutArray: {sizeOfoutArray}"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As<{Op1BaseType}, byte>(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As<{Op2BaseType}, byte>(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public {Op1VectorType}<{Op1BaseType}> _fld1; + public {Op2VectorType}<{Op2BaseType}> _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = {NextValueOp1}; } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<{Op1VectorType}<{Op1BaseType}>, byte>(ref testStruct._fld1), ref Unsafe.As<{Op1BaseType}, byte>(ref _data1[0]), (uint)Unsafe.SizeOf<{Op1VectorType}<{Op1BaseType}>>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = {NextValueOp2}; } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<{Op2VectorType}<{Op2BaseType}>, byte>(ref testStruct._fld2), ref Unsafe.As<{Op2BaseType}, byte>(ref _data2[0]), (uint)Unsafe.SizeOf<{Op2VectorType}<{Op2BaseType}>>()); + + return testStruct; + } + + public void RunStructFldScenario({TemplateName}BinaryOpTest__{TestName} testClass) + { + var result = {Isa}.{Method}(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + + private static readonly int LargestVectorSize = {LargestVectorSize}; + + private static readonly int Op1ElementCount = Unsafe.SizeOf<{Op1VectorType}<{Op1BaseType}>>() / sizeof({Op1BaseType}); + private static readonly int Op2ElementCount = Unsafe.SizeOf<{Op2VectorType}<{Op2BaseType}>>() / sizeof({Op2BaseType}); + private static readonly int RetElementCount = Unsafe.SizeOf<{RetVectorType}<{RetBaseType}>>() / sizeof({RetBaseType}); + + private static {Op1BaseType}[] _maskData = new {Op1BaseType}[Op1ElementCount]; + private static {Op1BaseType}[] _data1 = new {Op1BaseType}[Op1ElementCount]; + private static {Op2BaseType}[] _data2 = new {Op2BaseType}[Op2ElementCount]; + + private {Op1VectorType}<{Op1BaseType}> _mask; + private {Op1VectorType}<{Op1BaseType}> _fld1; + private {Op2VectorType}<{Op2BaseType}> _fld2; + private {Op2VectorType}<{Op2BaseType}> _falseFld; + + private DataTable _dataTable; + + public {TemplateName}BinaryOpTest__{TestName}() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _maskData[i] = ({Op1BaseType})({NextValueOp1} % 2); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<{Op1VectorType}<{Op1BaseType}>, byte>(ref _mask), ref Unsafe.As<{Op1BaseType}, byte>(ref _maskData[0]), (uint)Unsafe.SizeOf<{Op1VectorType}<{Op1BaseType}>>()); + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = {NextValueOp1}; } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<{Op1VectorType}<{Op1BaseType}>, byte>(ref _fld1), ref Unsafe.As<{Op1BaseType}, byte>(ref _data1[0]), (uint)Unsafe.SizeOf<{Op1VectorType}<{Op1BaseType}>>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = {NextValueOp2}; } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<{Op2VectorType}<{Op2BaseType}>, byte>(ref _fld2), ref Unsafe.As<{Op2BaseType}, byte>(ref _data2[0]), (uint)Unsafe.SizeOf<{Op2VectorType}<{Op2BaseType}>>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<{Op2VectorType}<{Op2BaseType}>, byte>(ref _falseFld), ref Unsafe.As<{Op2BaseType}, byte>(ref _data2[0]), (uint)Unsafe.SizeOf<{Op2VectorType}<{Op2BaseType}>>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = {NextValueOp1}; } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = {NextValueOp2}; } + _dataTable = new DataTable(_data1, _data2, new {RetBaseType}[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => {Isa}.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = {Isa}.{Method}( + Unsafe.Read<{Op1VectorType}<{Op1BaseType}>>(_dataTable.inArray1Ptr), + Unsafe.Read<{Op2VectorType}<{Op2BaseType}>>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + {Op1VectorType}<{Op1BaseType}> loadMask = Sve.CreateTrueMask{RetBaseType}(SveMaskPattern.All); + + var result = {Isa}.{Method}( + {LoadIsa}.Load{Op1VectorType}(loadMask, ({Op1BaseType}*)(_dataTable.inArray1Ptr)), + {LoadIsa}.Load{Op2VectorType}(loadMask, ({Op2BaseType}*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof({Isa}).GetMethod(nameof({Isa}.{Method}), new Type[] { typeof({Op1VectorType}<{Op1BaseType}>), typeof({Op2VectorType}<{Op2BaseType}>) }) + .Invoke(null, new object[] { + Unsafe.Read<{Op1VectorType}<{Op1BaseType}>>(_dataTable.inArray1Ptr), + Unsafe.Read<{Op2VectorType}<{Op2BaseType}>>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, ({RetVectorType}<{RetBaseType}>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read<{Op1VectorType}<{Op1BaseType}>>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read<{Op2VectorType}<{Op2BaseType}>>(_dataTable.inArray2Ptr); + var result = {Isa}.{Method}(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = {Isa}.{Method}(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = {Isa}.{Method}(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void ConditionalSelect_Op1() + { + TestLibrary.TestFramework.BeginScenario("ConditionalSelect_Op1_mask"); + ConditionalSelectScenario(_mask, _fld1, _fld2, _fld1); + + TestLibrary.TestFramework.BeginScenario("ConditionalSelect_Op1_zero"); + ConditionalSelectScenario({Op1VectorType}<{Op1BaseType}>.Zero, _fld1, _fld2, _fld1); + + TestLibrary.TestFramework.BeginScenario("ConditionalSelect_Op1_all"); + ConditionalSelectScenario({Op1VectorType}<{Op1BaseType}>.AllBitsSet, _fld1, _fld2, _fld1); + } + + public void ConditionalSelect_Op2() + { + TestLibrary.TestFramework.BeginScenario("ConditionalSelect_Op2_mask"); + ConditionalSelectScenario(_mask, _fld1, _fld2, _fld2); + + TestLibrary.TestFramework.BeginScenario("ConditionalSelect_Op2_zero"); + ConditionalSelectScenario({Op1VectorType}<{Op1BaseType}>.Zero, _fld1, _fld2, _fld2); + + TestLibrary.TestFramework.BeginScenario("ConditionalSelect_Op2_all"); + ConditionalSelectScenario({Op1VectorType}<{Op1BaseType}>.AllBitsSet, _fld1, _fld2, _fld2); + } + + public void ConditionalSelect_FalseOp() + { + TestLibrary.TestFramework.BeginScenario("ConditionalSelect_FalseOp_mask"); + ConditionalSelectScenario(_mask, _fld1, _fld2, _falseFld); + + TestLibrary.TestFramework.BeginScenario("ConditionalSelect_FalseOp_zero"); + ConditionalSelectScenario({Op1VectorType}<{Op1BaseType}>.Zero, _fld1, _fld2, _falseFld); + + TestLibrary.TestFramework.BeginScenario("ConditionalSelect_FalseOp_all"); + ConditionalSelectScenario({Op1VectorType}<{Op1BaseType}>.AllBitsSet, _fld1, _fld2, _falseFld); + } + + public void ConditionalSelect_ZeroOp() + { + TestLibrary.TestFramework.BeginScenario("ConditionalSelect_ZeroOp_mask"); + ConditionalSelectScenario(_mask, _fld1, _fld2, {Op1VectorType}<{Op1BaseType}>.Zero); + + TestLibrary.TestFramework.BeginScenario("ConditionalSelect_ZeroOp_zero"); + ConditionalSelectScenario({Op1VectorType}<{Op1BaseType}>.Zero, _fld1, _fld2, {Op1VectorType}<{Op1BaseType}>.Zero); + + TestLibrary.TestFramework.BeginScenario("ConditionalSelect_ZeroOp_all"); + ConditionalSelectScenario({Op1VectorType}<{Op1BaseType}>.AllBitsSet, _fld1, _fld2, {Op1VectorType}<{Op1BaseType}>.Zero); + } + + [method: MethodImpl(MethodImplOptions.AggressiveInlining)] + private void ConditionalSelectScenario({Op1VectorType}<{Op1BaseType}> mask, {Op1VectorType}<{Op1BaseType}> op1, {Op1VectorType}<{Op1BaseType}> op2, {Op1VectorType}<{Op1BaseType}> falseOp) + { + var result = Sve.ConditionalSelect(mask, {Isa}.{Method}(op1, op2), falseOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateConditionalSelectResult(mask, op1, op2, falseOp, _dataTable.outArrayPtr); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateConditionalSelectResult({Op1VectorType}<{Op1BaseType}> maskOp, {Op1VectorType}<{Op1BaseType}> leftOp, {Op1VectorType}<{Op1BaseType}> rightOp, {Op1VectorType}<{Op1BaseType}> falseOp, void* output, [CallerMemberName] string method = "") + { + {Op1BaseType}[] mask = new {Op1BaseType}[Op1ElementCount]; + {Op1BaseType}[] left = new {Op1BaseType}[Op1ElementCount]; + {Op1BaseType}[] right = new {Op1BaseType}[Op1ElementCount]; + {Op1BaseType}[] falseVal = new {Op1BaseType}[Op1ElementCount]; + {RetBaseType}[] result = new {RetBaseType}[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As<{Op1BaseType}, byte>(ref mask[0]), maskOp); + Unsafe.WriteUnaligned(ref Unsafe.As<{Op1BaseType}, byte>(ref left[0]), leftOp); + Unsafe.WriteUnaligned(ref Unsafe.As<{Op1BaseType}, byte>(ref right[0]), rightOp); + Unsafe.WriteUnaligned(ref Unsafe.As<{Op1BaseType}, byte>(ref falseVal[0]), falseOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<{RetBaseType}, byte>(ref result[0]), ref Unsafe.AsRef(output), (uint)Unsafe.SizeOf<{RetVectorType}<{RetBaseType}>>()); + + bool succeeded = true; + + {TemplateValidationLogicForCndSel} + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof({Isa})}.{nameof({Isa}.{Method})}<{RetBaseType}>({Op1VectorType}<{Op1BaseType}>, {Op2VectorType}<{Op2BaseType}>): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" mask: ({string.Join(", ", mask)})"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" falseOp: ({string.Join(", ", falseVal)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + + private void ValidateResult({Op1VectorType}<{Op1BaseType}> op1, {Op2VectorType}<{Op2BaseType}> op2, void* result, [CallerMemberName] string method = "") + { + {Op1BaseType}[] inArray1 = new {Op1BaseType}[Op1ElementCount]; + {Op2BaseType}[] inArray2 = new {Op2BaseType}[Op2ElementCount]; + {RetBaseType}[] outArray = new {RetBaseType}[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As<{Op1BaseType}, byte>(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As<{Op2BaseType}, byte>(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<{RetBaseType}, byte>(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf<{RetVectorType}<{RetBaseType}>>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + {Op1BaseType}[] inArray1 = new {Op1BaseType}[Op1ElementCount]; + {Op2BaseType}[] inArray2 = new {Op2BaseType}[Op2ElementCount]; + {RetBaseType}[] outArray = new {RetBaseType}[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As<{Op1BaseType}, byte>(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf<{Op1VectorType}<{Op1BaseType}>>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<{Op2BaseType}, byte>(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf<{Op2VectorType}<{Op2BaseType}>>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<{RetBaseType}, byte>(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf<{RetVectorType}<{RetBaseType}>>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult({Op1BaseType}[] left, {Op2BaseType}[] right, {RetBaseType}[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + {TemplateValidationLogic} + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof({Isa})}.{nameof({Isa}.{Method})}<{RetBaseType}>({Op1VectorType}<{Op1BaseType}>, {Op2VectorType}<{Op2BaseType}>): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/tests/JIT/HardwareIntrinsics/Arm/Shared/_SveUnaryOpTestTemplate.template b/src/tests/JIT/HardwareIntrinsics/Arm/Shared/_SveUnaryOpTestTemplate.template new file mode 100644 index 00000000000000..557442de4cf0be --- /dev/null +++ b/src/tests/JIT/HardwareIntrinsics/Arm/Shared/_SveUnaryOpTestTemplate.template @@ -0,0 +1,391 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Numerics; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; +using Xunit; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + [Fact] + public static void {TestName}() + { + var test = new {TemplateName}UnaryOpTest__{TestName}(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if ({LoadIsa}.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + // Validates executing the test inside conditional, with op1 as falseValue + test.ConditionalSelect_Op1(); + + // Validates executing the test inside conditional, with op3 as falseValue + test.ConditionalSelect_FalseOp(); + + // Validates executing the test inside conditional, with op3 as zero + test.ConditionalSelect_ZeroOp(); + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class {TemplateName}UnaryOpTest__{TestName} + { + private struct DataTable + { + private byte[] inArray1; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable({Op1BaseType}[] inArray1, {RetBaseType}[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf<{Op1BaseType}>(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf<{RetBaseType}>(); + if ((alignment != 64 && alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException($"Invalid value of alignment: {alignment}, sizeOfinArray1: {sizeOfinArray1}, sizeOfoutArray: {sizeOfoutArray}"); + } + + this.inArray1 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As<{Op1BaseType}, byte>(ref inArray1[0]), (uint)sizeOfinArray1); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public {Op1VectorType}<{Op1BaseType}> _fld1; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = {NextValueOp1}; } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<{Op1VectorType}<{Op1BaseType}>, byte>(ref testStruct._fld1), ref Unsafe.As<{Op1BaseType}, byte>(ref _data1[0]), (uint)Unsafe.SizeOf<{Op1VectorType}<{Op1BaseType}>>()); + + return testStruct; + } + + public void RunStructFldScenario({TemplateName}UnaryOpTest__{TestName} testClass) + { + var result = {Isa}.{Method}(_fld1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, testClass._dataTable.outArrayPtr); + } + } + + private static readonly int LargestVectorSize = {LargestVectorSize}; + + private static readonly int Op1ElementCount = Unsafe.SizeOf<{Op1VectorType}<{Op1BaseType}>>() / sizeof({Op1BaseType}); + private static readonly int RetElementCount = Unsafe.SizeOf<{RetVectorType}<{RetBaseType}>>() / sizeof({RetBaseType}); + + private static {Op1BaseType}[] _maskData = new {Op1BaseType}[Op1ElementCount]; + private static {Op1BaseType}[] _data1 = new {Op1BaseType}[Op1ElementCount]; + + private {Op1VectorType}<{Op1BaseType}> _mask; + private {Op1VectorType}<{Op1BaseType}> _fld1; + private {Op1VectorType}<{Op1BaseType}> _falseFld; + + private DataTable _dataTable; + + public {TemplateName}UnaryOpTest__{TestName}() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _maskData[i] = ({Op1BaseType})({NextValueOp1} % 2); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<{Op1VectorType}<{Op1BaseType}>, byte>(ref _mask), ref Unsafe.As<{Op1BaseType}, byte>(ref _maskData[0]), (uint)Unsafe.SizeOf<{Op1VectorType}<{Op1BaseType}>>()); + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = {NextValueOp1}; } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<{Op1VectorType}<{Op1BaseType}>, byte>(ref _fld1), ref Unsafe.As<{Op1BaseType}, byte>(ref _data1[0]), (uint)Unsafe.SizeOf<{Op1VectorType}<{Op1BaseType}>>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<{Op1VectorType}<{Op1BaseType}>, byte>(ref _falseFld), ref Unsafe.As<{Op1BaseType}, byte>(ref _data1[0]), (uint)Unsafe.SizeOf<{Op1VectorType}<{Op1BaseType}>>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = {NextValueOp1}; } + _dataTable = new DataTable(_data1, new {RetBaseType}[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => {Isa}.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = {Isa}.{Method}( + Unsafe.Read<{Op1VectorType}<{Op1BaseType}>>(_dataTable.inArray1Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + {Op1VectorType}<{Op1BaseType}> loadMask = Sve.CreateTrueMask{RetBaseType}(SveMaskPattern.All); + + var result = {Isa}.{Method}( + {LoadIsa}.Load{Op1VectorType}(loadMask, ({Op1BaseType}*)(_dataTable.inArray1Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof({Isa}).GetMethod(nameof({Isa}.{Method}), new Type[] { typeof({Op1VectorType}<{Op1BaseType}>) }) + .Invoke(null, new object[] { + Unsafe.Read<{Op1VectorType}<{Op1BaseType}>>(_dataTable.inArray1Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, ({RetVectorType}<{RetBaseType}>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read<{Op1VectorType}<{Op1BaseType}>>(_dataTable.inArray1Ptr); + var result = {Isa}.{Method}(op1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = {Isa}.{Method}(_fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = {Isa}.{Method}(test._fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void ConditionalSelect_Op1() + { + TestLibrary.TestFramework.BeginScenario("ConditionalSelect_Op1_mask"); + ConditionalSelectScenario(_mask, _fld1, _fld1); + + TestLibrary.TestFramework.BeginScenario("ConditionalSelect_Op1_zero"); + ConditionalSelectScenario({Op1VectorType}<{Op1BaseType}>.Zero, _fld1, _fld1); + + TestLibrary.TestFramework.BeginScenario("ConditionalSelect_Op1_all"); + ConditionalSelectScenario({Op1VectorType}<{Op1BaseType}>.AllBitsSet, _fld1, _fld1); + } + + public void ConditionalSelect_FalseOp() + { + TestLibrary.TestFramework.BeginScenario(nameof(ConditionalSelect_FalseOp)); + ConditionalSelectScenario(_mask, _fld1, _falseFld); + + TestLibrary.TestFramework.BeginScenario("ConditionalSelect_FalseOp_zero"); + ConditionalSelectScenario({Op1VectorType}<{Op1BaseType}>.Zero, _fld1, _falseFld); + + TestLibrary.TestFramework.BeginScenario("ConditionalSelect_FalseOp_all"); + ConditionalSelectScenario({Op1VectorType}<{Op1BaseType}>.AllBitsSet, _fld1, _falseFld); + } + + public void ConditionalSelect_ZeroOp() + { + TestLibrary.TestFramework.BeginScenario(nameof(ConditionalSelect_ZeroOp)); + ConditionalSelectScenario(_mask, _fld1, {Op1VectorType}<{Op1BaseType}>.Zero); + + TestLibrary.TestFramework.BeginScenario("ConditionalSelect_ZeroOp_zero"); + ConditionalSelectScenario({Op1VectorType}<{Op1BaseType}>.Zero, _fld1, {Op1VectorType}<{Op1BaseType}>.Zero); + + TestLibrary.TestFramework.BeginScenario("ConditionalSelect_ZeroOp_all"); + ConditionalSelectScenario({Op1VectorType}<{Op1BaseType}>.AllBitsSet, _fld1, {Op1VectorType}<{Op1BaseType}>.Zero); + } + + [method: MethodImpl(MethodImplOptions.AggressiveInlining)] + private void ConditionalSelectScenario({Op1VectorType}<{Op1BaseType}> mask, {Op1VectorType}<{Op1BaseType}> op1, {Op1VectorType}<{Op1BaseType}> falseOp) + { + var result = Sve.ConditionalSelect(mask, {Isa}.{Method}(op1), falseOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateConditionalSelectResult(mask, op1, falseOp, _dataTable.outArrayPtr); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateConditionalSelectResult({Op1VectorType}<{Op1BaseType}> maskOp, {Op1VectorType}<{Op1BaseType}> leftOp, {Op1VectorType}<{Op1BaseType}> falseOp, void* output, [CallerMemberName] string method = "") + { + {Op1BaseType}[] mask = new {Op1BaseType}[Op1ElementCount]; + {Op1BaseType}[] left = new {Op1BaseType}[Op1ElementCount]; + {Op1BaseType}[] falseVal = new {Op1BaseType}[Op1ElementCount]; + {RetBaseType}[] result = new {RetBaseType}[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As<{Op1BaseType}, byte>(ref mask[0]), maskOp); + Unsafe.WriteUnaligned(ref Unsafe.As<{Op1BaseType}, byte>(ref left[0]), leftOp); + Unsafe.WriteUnaligned(ref Unsafe.As<{Op1BaseType}, byte>(ref falseVal[0]), falseOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<{RetBaseType}, byte>(ref result[0]), ref Unsafe.AsRef(output), (uint)Unsafe.SizeOf<{RetVectorType}<{RetBaseType}>>()); + + bool succeeded = true; + + {TemplateValidationLogicForCndSel} + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof({Isa})}.{nameof({Isa}.{Method})}<{RetBaseType}>({Op1VectorType}<{Op1BaseType}>, {Op1VectorType}<{Op1BaseType}>): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" mask: ({string.Join(", ", mask)})"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" falseOp: ({string.Join(", ", falseVal)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + + private void ValidateResult({Op1VectorType}<{Op1BaseType}> op1, void* result, [CallerMemberName] string method = "") + { + {Op1BaseType}[] inArray1 = new {Op1BaseType}[Op1ElementCount]; + {RetBaseType}[] outArray = new {RetBaseType}[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As<{Op1BaseType}, byte>(ref inArray1[0]), op1); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<{RetBaseType}, byte>(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf<{RetVectorType}<{RetBaseType}>>()); + + ValidateResult(inArray1, outArray, method); + } + + private void ValidateResult(void* op1, void* result, [CallerMemberName] string method = "") + { + {Op1BaseType}[] inArray1 = new {Op1BaseType}[Op1ElementCount]; + {RetBaseType}[] outArray = new {RetBaseType}[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As<{Op1BaseType}, byte>(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf<{Op1VectorType}<{Op1BaseType}>>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<{RetBaseType}, byte>(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf<{RetVectorType}<{RetBaseType}>>()); + + ValidateResult(inArray1, outArray, method); + } + + private void ValidateResult({Op1BaseType}[] firstOp, {RetBaseType}[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + {TemplateValidationLogic} + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof({Isa})}.{nameof({Isa}.{Method})}<{RetBaseType}>({Op1VectorType}<{Op1BaseType}>): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} From 8f1e68aba0bf904a50d581eadbe657fe6fb39986 Mon Sep 17 00:00:00 2001 From: Jeremy Koritzinsky Date: Wed, 24 Apr 2024 12:02:06 -0700 Subject: [PATCH 061/161] Refresh our "dev-innerloop" pipeline jobs (#101304) --- eng/pipelines/common/platform-matrix.yml | 19 +++++ .../templates/pipeline-with-resources.yml | 3 + eng/pipelines/global-build.yml | 73 ++++--------------- 3 files changed, 37 insertions(+), 58 deletions(-) diff --git a/eng/pipelines/common/platform-matrix.yml b/eng/pipelines/common/platform-matrix.yml index cb3c8b2d0a65e2..2dc00a29da5d35 100644 --- a/eng/pipelines/common/platform-matrix.yml +++ b/eng/pipelines/common/platform-matrix.yml @@ -294,6 +294,25 @@ jobs: helixQueueGroup: ${{ parameters.helixQueueGroup }} ${{ insert }}: ${{ parameters.jobParameters }} +- ${{ if containsValue(parameters.platforms, 'linux_musl_x64_dev_innerloop') }}: + - template: xplat-setup.yml + parameters: + jobTemplate: ${{ parameters.jobTemplate }} + helixQueuesTemplate: ${{ parameters.helixQueuesTemplate }} + variables: ${{ parameters.variables }} + osGroup: linux + osSubgroup: _musl + archType: x64 + targetRid: linux-musl-x64 + platform: linux_musl_x64 + shouldContinueOnError: ${{ parameters.shouldContinueOnError }} + container: linux_musl_x64_dev_innerloop + jobParameters: + runtimeFlavor: ${{ parameters.runtimeFlavor }} + buildConfig: ${{ parameters.buildConfig }} + helixQueueGroup: ${{ parameters.helixQueueGroup }} + ${{ insert }}: ${{ parameters.jobParameters }} + # GCC Linux x64 Build - ${{ if containsValue(parameters.platforms, 'gcc_linux_x64') }}: diff --git a/eng/pipelines/common/templates/pipeline-with-resources.yml b/eng/pipelines/common/templates/pipeline-with-resources.yml index e5e821f60fbc0e..3c9fc538c4845b 100644 --- a/eng/pipelines/common/templates/pipeline-with-resources.yml +++ b/eng/pipelines/common/templates/pipeline-with-resources.yml @@ -68,6 +68,9 @@ extends: linux_x64_dev_innerloop: image: mcr.microsoft.com/dotnet-buildtools/prereqs:ubuntu-22.04 + linux_musl_x64_dev_innerloop: + image: mcr.microsoft.com/dotnet-buildtools/prereqs:alpine-3.19-WithNode + # We use a CentOS Stream 8 image here to test building from source on CentOS Stream 8. SourceBuild_centos_x64: image: mcr.microsoft.com/dotnet-buildtools/prereqs:centos-stream8 diff --git a/eng/pipelines/global-build.yml b/eng/pipelines/global-build.yml index 2e70a2448cd9d3..d7302fe253b6b9 100644 --- a/eng/pipelines/global-build.yml +++ b/eng/pipelines/global-build.yml @@ -1,6 +1,6 @@ -# The purpose of this pipeline is to exercise local developer workflow in the consolidated -# runtime repo. In particular, it is supposed to run the root "build" script just like any -# normal developer normally would and monitor regressions w.r.t. this fundamental scenario. +# The purpose of this pipeline is to exercise various developer workflows in the repo. +# Primarily, it is meant to cover local (non-cross) build scenarios and +# source-build scenarios that commonly cause build breaks. trigger: none @@ -41,28 +41,6 @@ extends: - stage: Build jobs: - # - # Build with Release config and Debug runtimeConfiguration - # - - template: /eng/pipelines/common/platform-matrix.yml - parameters: - jobTemplate: /eng/pipelines/common/global-build-job.yml - buildConfig: release - platforms: - - windows_x86 - - osx_x64 - - osx_arm64 - jobParameters: - testGroup: innerloop - nameSuffix: Runtime_Debug - buildArgs: -c release -runtimeConfiguration debug - timeoutInMinutes: 120 - condition: - or( - eq(stageDependencies.EvaluatePaths.evaluate_paths.outputs['SetPathVars_coreclr.containsChange'], true), - eq(stageDependencies.EvaluatePaths.evaluate_paths.outputs['SetPathVars_non_mono_and_wasm.containsChange'], true), - eq(variables['isRollingBuild'], true)) - # # Build with Release config and runtimeConfiguration with MSBuild generator # @@ -83,26 +61,6 @@ extends: eq(stageDependencies.EvaluatePaths.evaluate_paths.outputs['SetPathVars_non_mono_and_wasm.containsChange'], true), eq(variables['isRollingBuild'], true)) - # - # Build with Debug config and Release runtimeConfiguration - # - - template: /eng/pipelines/common/platform-matrix.yml - parameters: - jobTemplate: /eng/pipelines/common/global-build-job.yml - buildConfig: debug - platforms: - - linux_x64_dev_innerloop - jobParameters: - testGroup: innerloop - nameSuffix: Runtime_Release - buildArgs: -c debug -runtimeConfiguration release - timeoutInMinutes: 120 - condition: - or( - eq(stageDependencies.EvaluatePaths.evaluate_paths.outputs['SetPathVars_coreclr.containsChange'], true), - eq(stageDependencies.EvaluatePaths.evaluate_paths.outputs['SetPathVars_non_mono_and_wasm.containsChange'], true), - eq(variables['isRollingBuild'], true)) - # # Build with RuntimeFlavor only. This exercise code paths where only RuntimeFlavor is # specified. Catches cases where we depend on Configuration also being specified @@ -124,38 +82,37 @@ extends: eq(variables['isRollingBuild'], true)) # - # Build Mono + Libraries. This exercises the code path where we build libraries without - # first building CoreCLR + # Build Libraries AllConfigurations. This exercises the code path where we build libraries for all + # configurations on a non Windows operating system. # - template: /eng/pipelines/common/platform-matrix.yml parameters: jobTemplate: /eng/pipelines/common/global-build-job.yml buildConfig: debug platforms: - - windows_x64 + - linux_x64_dev_innerloop jobParameters: - testGroup: innerloop - nameSuffix: Mono_Libraries - buildArgs: -subset mono+libs /p:RuntimeFlavor=Mono + nameSuffix: Libraries_AllConfigurations + buildArgs: -subset libs -allconfigurations timeoutInMinutes: 120 condition: or( - eq(stageDependencies.EvaluatePaths.evaluate_paths.outputs['SetPathVars_non_wasm.containsChange'], true), + eq(stageDependencies.EvaluatePaths.evaluate_paths.outputs['SetPathVars_non_mono_and_wasm.containsChange'], true), eq(variables['isRollingBuild'], true)) # - # Build Libraries AllConfigurations. This exercises the code path where we build libraries for all - # configurations on a non Windows operating system. + # Build native assets on Alpine. This exercises more modern musl libc changes that have a tendendy to break source-build. + # We don't add this as a source-build job as the repo source-build infrastructure isn't set up to run on alpine effectively. # - template: /eng/pipelines/common/platform-matrix.yml parameters: jobTemplate: /eng/pipelines/common/global-build-job.yml - buildConfig: debug + buildConfig: release platforms: - - linux_x64_dev_innerloop + - linux_musl_x64_dev_innerloop jobParameters: - nameSuffix: Libraries_AllConfigurations - buildArgs: -subset libs -allconfigurations + nameSuffix: Musl_Validation + buildArgs: -subset clr.native+libs.native+host.native -c $(_BuildConfig) timeoutInMinutes: 120 condition: or( From ce0ae49e71201a029be97638eb48074359ea76ae Mon Sep 17 00:00:00 2001 From: Koundinya Veluri Date: Wed, 24 Apr 2024 12:27:34 -0700 Subject: [PATCH 062/161] Add managed blocking info for lock and monitor waits (#101192) * Add managed blocking info for lock and monitor waits - Added a managed `ThreadBlockingInfo` struct that is similar to CoreCLR's `DebugBlockingItem` - Updated `Lock`, `Condition`, and `Monitor` to record the info - The `LockOwnerOSThreadId` and `LockOwnerManagedThreadId` properties can be used by debuggers to determine which thread owns a lock that the current thread is waiting on - In CoreCLR, `Monitor` records the info using the `Monitor` object kinds. In NativeAOT, `Lock` and `Condition` are used for `Monitor` waits, so the object kinds would be `Lock/Condition`. For now, Mono's `Monitor` does not record this info. --- .../src/System/Threading/Condition.cs | 4 + .../src/System/Threading/Lock.NativeAot.cs | 6 + src/coreclr/vm/appdomain.cpp | 7 + src/coreclr/vm/corelib.h | 4 + src/coreclr/vm/syncblk.cpp | 17 +- src/coreclr/vm/syncblk.h | 6 + src/coreclr/vm/threaddebugblockinginfo.cpp | 43 +++- src/coreclr/vm/threaddebugblockinginfo.h | 24 ++- .../System.Private.CoreLib.Shared.projitems | 3 +- .../src/System/Threading/Lock.NonNativeAot.cs | 6 + .../src/System/Threading/Lock.cs | 2 + .../System/Threading/ThreadBlockingInfo.cs | 194 ++++++++++++++++++ 12 files changed, 303 insertions(+), 13 deletions(-) create mode 100644 src/libraries/System.Private.CoreLib/src/System/Threading/ThreadBlockingInfo.cs diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Threading/Condition.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Threading/Condition.cs index ba8aba61a0a1b3..2321c5bafe14b7 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Threading/Condition.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Threading/Condition.cs @@ -32,6 +32,8 @@ private static Waiter GetWaiterForCurrentThread() private Waiter? _waitersHead; private Waiter? _waitersTail; + internal Lock AssociatedLock => _lock; + private unsafe void AssertIsInList(Waiter waiter) { Debug.Assert(_waitersHead != null && _waitersTail != null); @@ -106,6 +108,8 @@ public unsafe bool Wait(int millisecondsTimeout, object? associatedObjectForMoni if (!_lock.IsHeldByCurrentThread) throw new SynchronizationLockException(); + using ThreadBlockingInfo.Scope threadBlockingScope = new(this, millisecondsTimeout); + Waiter waiter = GetWaiterForCurrentThread(); AddWaiter(waiter); diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Threading/Lock.NativeAot.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Threading/Lock.NativeAot.cs index 8a1c017a508098..9ed8dafac4c1b8 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Threading/Lock.NativeAot.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Threading/Lock.NativeAot.cs @@ -24,6 +24,12 @@ public sealed partial class Lock /// public Lock() => _spinCount = SpinCountNotInitialized; +#pragma warning disable CA1822 // can be marked as static - varies between runtimes + internal ulong OwningOSThreadId => 0; +#pragma warning restore CA1822 + + internal int OwningManagedThreadId => (int)_owningThreadId; + [MethodImpl(MethodImplOptions.AggressiveInlining)] internal bool TryEnterOneShot(int currentManagedThreadId) { diff --git a/src/coreclr/vm/appdomain.cpp b/src/coreclr/vm/appdomain.cpp index 59a4783648e2a7..54d395c1d2e353 100644 --- a/src/coreclr/vm/appdomain.cpp +++ b/src/coreclr/vm/appdomain.cpp @@ -1158,6 +1158,13 @@ void SystemDomain::Init() // Finish loading CoreLib now. m_pSystemAssembly->GetDomainAssembly()->EnsureActive(); + + // Set AwareLock's offset of the holding OS thread ID field into ThreadBlockingInfo's static field. That can be used + // when doing managed debugging to get the OS ID of the thread holding the lock. The offset is currently not zero, and + // zero is used in managed code to determine if the static variable has been initialized. + _ASSERTE(AwareLock::GetOffsetOfHoldingOSThreadId() != 0); + CoreLibBinder::GetField(FIELD__THREAD_BLOCKING_INFO__OFFSET_OF_LOCK_OWNER_OS_THREAD_ID) + ->SetStaticValue32(AwareLock::GetOffsetOfHoldingOSThreadId()); } #ifdef _DEBUG diff --git a/src/coreclr/vm/corelib.h b/src/coreclr/vm/corelib.h index 65a187d19216f7..d5af8bdb3cb64e 100644 --- a/src/coreclr/vm/corelib.h +++ b/src/coreclr/vm/corelib.h @@ -583,6 +583,10 @@ END_ILLINK_FEATURE_SWITCH() DEFINE_CLASS(MONITOR, Threading, Monitor) DEFINE_METHOD(MONITOR, ENTER, Enter, SM_Obj_RetVoid) +DEFINE_CLASS(THREAD_BLOCKING_INFO, Threading, ThreadBlockingInfo) +DEFINE_FIELD(THREAD_BLOCKING_INFO, OFFSET_OF_LOCK_OWNER_OS_THREAD_ID, s_monitorObjectOffsetOfLockOwnerOSThreadId) +DEFINE_FIELD(THREAD_BLOCKING_INFO, FIRST, t_first) + DEFINE_CLASS(PARAMETER, Reflection, ParameterInfo) DEFINE_CLASS(PARAMETER_MODIFIER, Reflection, ParameterModifier) diff --git a/src/coreclr/vm/syncblk.cpp b/src/coreclr/vm/syncblk.cpp index 48ede10b35fef0..606137ee8eba75 100644 --- a/src/coreclr/vm/syncblk.cpp +++ b/src/coreclr/vm/syncblk.cpp @@ -2851,15 +2851,9 @@ BOOL SyncBlock::Wait(INT32 timeOut) _ASSERTE ((SyncBlock*)((DWORD_PTR)walk->m_Next->m_WaitSB & ~1)== this); - PendingSync syncState(walk); - - OBJECTREF obj = m_Monitor.GetOwningObject(); - syncState.m_Object = OBJECTREFToObject(obj); - - m_Monitor.IncrementTransientPrecious(); - // While we are in this frame the thread is considered blocked on the - // event of the monitor lock according to the debugger + // event of the monitor lock according to the debugger. DebugBlockingItemHolder + // can trigger a GC, so set it up before accessing the owning object. DebugBlockingItem blockingMonitorInfo; blockingMonitorInfo.dwTimeout = timeOut; blockingMonitorInfo.pMonitor = &m_Monitor; @@ -2867,6 +2861,13 @@ BOOL SyncBlock::Wait(INT32 timeOut) blockingMonitorInfo.type = DebugBlock_MonitorEvent; DebugBlockingItemHolder holder(pCurThread, &blockingMonitorInfo); + PendingSync syncState(walk); + + OBJECTREF obj = m_Monitor.GetOwningObject(); + syncState.m_Object = OBJECTREFToObject(obj); + + m_Monitor.IncrementTransientPrecious(); + GCPROTECT_BEGIN(obj); { GCX_PREEMP(); diff --git a/src/coreclr/vm/syncblk.h b/src/coreclr/vm/syncblk.h index 2ddec753159759..029ee9337d7aab 100644 --- a/src/coreclr/vm/syncblk.h +++ b/src/coreclr/vm/syncblk.h @@ -602,6 +602,12 @@ class AwareLock LIMITED_METHOD_CONTRACT; return m_HoldingThread; } + + static int GetOffsetOfHoldingOSThreadId() + { + LIMITED_METHOD_CONTRACT; + return (int)offsetof(AwareLock, m_HoldingOSThreadId); + } }; #ifdef FEATURE_COMINTEROP diff --git a/src/coreclr/vm/threaddebugblockinginfo.cpp b/src/coreclr/vm/threaddebugblockinginfo.cpp index 8767091566891a..8f4f3831b3518e 100644 --- a/src/coreclr/vm/threaddebugblockinginfo.cpp +++ b/src/coreclr/vm/threaddebugblockinginfo.cpp @@ -72,9 +72,37 @@ VOID ThreadDebugBlockingInfo::VisitBlockingItems(DebugBlockingItemVisitor visito // Holder constructor pushes a blocking item on the blocking info stack #ifndef DACCESS_COMPILE DebugBlockingItemHolder::DebugBlockingItemHolder(Thread *pThread, DebugBlockingItem *pItem) : -m_pThread(pThread) + m_pThread(pThread), m_ppFirstBlockingInfo(nullptr) { - LIMITED_METHOD_CONTRACT; + CONTRACTL + { + THROWS; + GC_TRIGGERS; + MODE_COOPERATIVE; + } + CONTRACTL_END; + + // Try to get the address of the thread-local slot for the managed ThreadBlockingInfo.t_first + EX_TRY + { + FieldDesc *pFD = CoreLibBinder::GetField(FIELD__THREAD_BLOCKING_INFO__FIRST); + m_ppFirstBlockingInfo = (ThreadBlockingInfo **)Thread::GetStaticFieldAddress(pFD); + } + EX_CATCH + { + } + EX_END_CATCH(RethrowTerminalExceptions); + + if (m_ppFirstBlockingInfo != nullptr) + { + // Push info for the managed ThreadBlockingInfo + m_blockingInfo.objectPtr = pItem->pMonitor; + m_blockingInfo.objectKind = (ThreadBlockingInfo::ObjectKind)pItem->type; + m_blockingInfo.timeoutMs = (INT32)pItem->dwTimeout; + m_blockingInfo.next = *m_ppFirstBlockingInfo; + *m_ppFirstBlockingInfo = &m_blockingInfo; + } + pThread->DebugBlockingInfo.PushBlockingItem(pItem); } #endif //DACCESS_COMPILE @@ -84,6 +112,17 @@ m_pThread(pThread) DebugBlockingItemHolder::~DebugBlockingItemHolder() { LIMITED_METHOD_CONTRACT; + m_pThread->DebugBlockingInfo.PopBlockingItem(); + + if (m_ppFirstBlockingInfo != nullptr) + { + // Pop info for the managed ThreadBlockingInfo + _ASSERTE( + m_ppFirstBlockingInfo == + (void *)m_pThread->GetStaticFieldAddrNoCreate(CoreLibBinder::GetField(FIELD__THREAD_BLOCKING_INFO__FIRST))); + _ASSERTE(*m_ppFirstBlockingInfo == &m_blockingInfo); + *m_ppFirstBlockingInfo = m_blockingInfo.next; + } } #endif //DACCESS_COMPILE diff --git a/src/coreclr/vm/threaddebugblockinginfo.h b/src/coreclr/vm/threaddebugblockinginfo.h index 9a2815b3a0c78e..c0d035dd88f01b 100644 --- a/src/coreclr/vm/threaddebugblockinginfo.h +++ b/src/coreclr/vm/threaddebugblockinginfo.h @@ -14,8 +14,8 @@ // Different ways thread can block that the debugger will expose enum DebugBlockingItemType { - DebugBlock_MonitorCriticalSection, - DebugBlock_MonitorEvent, + DebugBlock_MonitorCriticalSection, // maps to ThreadBlockingInfo.ObjectKind.MonitorLock below and in managed code + DebugBlock_MonitorEvent, // maps to ThreadBlockingInfo.ObjectKind.MonitorWait below and in managed code }; typedef DPTR(struct DebugBlockingItem) PTR_DebugBlockingItem; @@ -65,15 +65,35 @@ class ThreadDebugBlockingInfo }; #ifndef DACCESS_COMPILE + +// This is the equivalent of the managed ThreadBlockingInfo (see ThreadBlockingInfo.cs), which is used for tracking blocking +// info from the managed side, similarly to DebugBlockingItem +struct ThreadBlockingInfo +{ + enum class ObjectKind : INT32 + { + MonitorLock, // maps to DebugBlockingItemType::DebugBlock_MonitorCriticalSection + MonitorWait // maps to DebugBlockingItemType::DebugBlock_MonitorEvent + }; + + void *objectPtr; + ObjectKind objectKind; + INT32 timeoutMs; + ThreadBlockingInfo *next; +}; + class DebugBlockingItemHolder { private: Thread *m_pThread; + ThreadBlockingInfo **m_ppFirstBlockingInfo; + ThreadBlockingInfo m_blockingInfo; public: DebugBlockingItemHolder(Thread *pThread, DebugBlockingItem *pItem); ~DebugBlockingItemHolder(); }; + #endif //!DACCESS_COMPILE #endif // __ThreadBlockingInfo__ diff --git a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems index 4dd47c701586ca..fccffa63fa159e 100644 --- a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems +++ b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems @@ -1265,6 +1265,7 @@ + @@ -2786,4 +2787,4 @@ - \ No newline at end of file + diff --git a/src/libraries/System.Private.CoreLib/src/System/Threading/Lock.NonNativeAot.cs b/src/libraries/System.Private.CoreLib/src/System/Threading/Lock.NonNativeAot.cs index 9386b7ed174601..8a05f1e7fddc70 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Threading/Lock.NonNativeAot.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Threading/Lock.NonNativeAot.cs @@ -16,6 +16,12 @@ public sealed partial class Lock ///
public Lock() => _spinCount = s_maxSpinCount; + internal ulong OwningOSThreadId => _owningThreadId; + +#pragma warning disable CA1822 // can be marked as static - varies between runtimes + internal int OwningManagedThreadId => 0; +#pragma warning restore CA1822 + private static TryLockResult LazyInitializeOrEnter() => TryLockResult.Spin; private static bool IsSingleProcessor => Environment.IsSingleProcessor; diff --git a/src/libraries/System.Private.CoreLib/src/System/Threading/Lock.cs b/src/libraries/System.Private.CoreLib/src/System/Threading/Lock.cs index b7961869eac5d2..8658ab6caafb11 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Threading/Lock.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Threading/Lock.cs @@ -477,6 +477,8 @@ private ThreadId TryEnterSlow(int timeoutMs, ThreadId currentThreadId) waitStartTimeTicks = Stopwatch.GetTimestamp(); } + using ThreadBlockingInfo.Scope threadBlockingScope = new(this, timeoutMs); + bool acquiredLock = false; int waitStartTimeMs = timeoutMs < 0 ? 0 : Environment.TickCount; int remainingTimeoutMs = timeoutMs; diff --git a/src/libraries/System.Private.CoreLib/src/System/Threading/ThreadBlockingInfo.cs b/src/libraries/System.Private.CoreLib/src/System/Threading/ThreadBlockingInfo.cs new file mode 100644 index 00000000000000..6deed17e8f5dc5 --- /dev/null +++ b/src/libraries/System.Private.CoreLib/src/System/Threading/ThreadBlockingInfo.cs @@ -0,0 +1,194 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Diagnostics; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace System.Threading +{ + // Tracks some kinds of blocking on the thread, like waiting on locks where it may be useful to know when debugging which + // thread owns the lock. + // + // Notes: + // - The type, some fields, and some other members may be used by debuggers (noted specifically below), so take care when + // renaming them + // - There is a native version of this struct in CoreCLR, used by Monitor to fold in its blocking info here. The struct is + // blittable with sequential layout to support that. + // + // Debuggers may use this info by evaluating expressions to enumerate the blocking infos for a thread. For example: + // - Evaluate "System.Threading.ThreadBlockingInfo.t_first" to obtain the first pointer to a blocking info for the current + // thread + // - While there is a non-null pointer to a blocking info: + // - Evaluate "(*(System.Threading.ThreadBlockingInfo*)ptr).fieldOrProperty", where "ptr" is the blocking info pointer + // value, to get the field and relevant property getter values below + // - Use the _objectKind field value to determine what kind of blocking is occurring + // - Get the LockOwnerOSThreadId and LockOwnerManagedThreadId property getter values. If the blocking is waiting for a + // lock and the lock is currently owned by a thread, one of these properties will return a nonzero value that can be + // used to identify the lock owner thread. + // - Use the _next field value to obtain the next pointer to a blocking info for the thread + [StructLayout(LayoutKind.Sequential)] + internal unsafe struct ThreadBlockingInfo + { +#if CORECLR + // In CoreCLR, for the Monitor object kinds, the object ptr will be a pointer to a native AwareLock object. This + // relative offset indicates the location of the field holding the lock owner OS thread ID (the field is of type + // size_t), and is used to get that info by the LockOwnerOSThreadId property. The offset is not zero currently, so zero + // is used to determine if the static field has been initialized. + // + // This mechanism is used instead of using an FCall in the property getter such that the property can be more easily + // evaluated by a debugger. + private static int s_monitorObjectOffsetOfLockOwnerOSThreadId; +#endif + + // Points to the first (most recent) blocking info for the thread. The _next field points to the next-most-recent + // blocking info for the thread, or null if there are no more. Blocking can be reentrant in some cases, such as on UI + // threads where reentrant waits are used, or if a SynchronizationContext wait override is set. + [ThreadStatic] + private static ThreadBlockingInfo* t_first; // may be used by debuggers + + // This pointer can be used to obtain the object relevant to the blocking. For native object kinds, it points to the + // native object (for Monitor object kinds in CoreCLR, it points to a native AwareLock object). For managed object + // kinds, it points to a stack location containing the managed object reference. + private void* _objectPtr; // may be used by debuggers + + // Indicates the type of object relevant to the blocking + private ObjectKind _objectKind; // may be used by debuggers + + // The timeout in milliseconds for the wait, -1 for infinite timeout + private int _timeoutMs; // may be used by debuggers + + // Points to the next-most-recent blocking info for the thread + private ThreadBlockingInfo* _next; // may be used by debuggers + + private void Push(void* objectPtr, ObjectKind objectKind, int timeoutMs) + { + Debug.Assert(objectPtr != null); + + _objectPtr = objectPtr; + _objectKind = objectKind; + _timeoutMs = timeoutMs; + _next = t_first; + t_first = (ThreadBlockingInfo*)Unsafe.AsPointer(ref this); + } + + private void Pop() + { + Debug.Assert(_objectPtr != null); + Debug.Assert(t_first != null); + Debug.Assert(t_first->_next == _next); + + t_first = _next; + _objectPtr = null; + } + + // If the blocking is associated with a lock of some kind that has thread affinity and tracks the owner's OS thread ID, + // returns the OS thread ID of the thread that currently owns the lock. Otherwise, returns 0. A return value of 0 may + // indicate that the associated lock is currently not owned by a thread, or that the information could not be + // determined. + // + // Calls to native helpers are avoided in the property getter such that it can be more easily evaluated by a debugger. + public ulong LockOwnerOSThreadId // the getter may be used by debuggers + { + get + { + Debug.Assert(_objectPtr != null); + + switch (_objectKind) + { + case ObjectKind.MonitorLock: + case ObjectKind.MonitorWait: + // The Monitor object kinds are only used by CoreCLR, and only the OS thread ID is reported +#if CORECLR + if (s_monitorObjectOffsetOfLockOwnerOSThreadId != 0) + { + return *(nuint*)((nint)_objectPtr + s_monitorObjectOffsetOfLockOwnerOSThreadId); + } +#endif + return 0; + + case ObjectKind.Lock: + return ((Lock)Unsafe.AsRef(_objectPtr)).OwningOSThreadId; + + default: + Debug.Assert(_objectKind == ObjectKind.Condition); +#if NATIVEAOT + return ((Condition)Unsafe.AsRef(_objectPtr)).AssociatedLock.OwningOSThreadId; +#else + return 0; +#endif + } + } + } + + // If the blocking is associated with a lock of some kind that has thread affinity and tracks the owner's managed thread + // ID, returns the managed thread ID of the thread that currently owns the lock. Otherwise, returns 0. A return value of + // 0 may indicate that the associated lock is currently not owned by a thread, or that the information could not be + // determined. + // + // Calls to native helpers are avoided in the property getter such that it can be more easily evaluated by a debugger. + public int LockOwnerManagedThreadId // the getter may be used by debuggers + { + get + { + Debug.Assert(_objectPtr != null); + + switch (_objectKind) + { + case ObjectKind.MonitorLock: + case ObjectKind.MonitorWait: + // The Monitor object kinds are only used by CoreCLR, and only the OS thread ID is reported + return 0; + + case ObjectKind.Lock: + return ((Lock)Unsafe.AsRef(_objectPtr)).OwningManagedThreadId; + + default: + Debug.Assert(_objectKind == ObjectKind.Condition); +#if NATIVEAOT + return ((Condition)Unsafe.AsRef(_objectPtr)).AssociatedLock.OwningManagedThreadId; +#else + return 0; +#endif + } + } + } + + public unsafe ref struct Scope + { + private object? _object; + private ThreadBlockingInfo _blockingInfo; + +#pragma warning disable CS9216 // casting Lock to object + public Scope(Lock lockObj, int timeoutMs) : this(lockObj, ObjectKind.Lock, timeoutMs) { } +#pragma warning restore CS9216 + +#if NATIVEAOT + public Scope(Condition condition, int timeoutMs) : this(condition, ObjectKind.Condition, timeoutMs) { } +#endif + + private Scope(object obj, ObjectKind objectKind, int timeoutMs) + { + _object = obj; + _blockingInfo.Push(Unsafe.AsPointer(ref _object), objectKind, timeoutMs); + } + + public void Dispose() + { + if (_object is not null) + { + _blockingInfo.Pop(); + _object = null; + } + } + } + + public enum ObjectKind // may be used by debuggers + { + MonitorLock, // maps to DebugBlockingItemType::DebugBlock_MonitorCriticalSection in coreclr + MonitorWait, // maps to DebugBlockingItemType::DebugBlock_MonitorEvent in coreclr + Lock, + Condition + } + } +} From 5b4e770daa190ce69f402c1cf92f388b07d3e144 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Strehovsk=C3=BD?= Date: Thu, 25 Apr 2024 06:24:37 +0900 Subject: [PATCH 063/161] Disable most of S.T.Json trimming tests on AOT the right way (#101418) These don't seem to use the source generator, so they're not really "trimming tests" and obviously they don't work. --- .../TrimmingTests/System.Text.Json.TrimmingTests.proj | 4 +++- src/libraries/tests.proj | 1 - 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/TrimmingTests/System.Text.Json.TrimmingTests.proj b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/TrimmingTests/System.Text.Json.TrimmingTests.proj index 6d9885fed2a91a..37188a8dce70d6 100644 --- a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/TrimmingTests/System.Text.Json.TrimmingTests.proj +++ b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/TrimmingTests/System.Text.Json.TrimmingTests.proj @@ -1,7 +1,9 @@ - + + Helper.cs diff --git a/src/libraries/tests.proj b/src/libraries/tests.proj index 6610727190fb34..7106a44c89e967 100644 --- a/src/libraries/tests.proj +++ b/src/libraries/tests.proj @@ -653,7 +653,6 @@ - Date: Thu, 25 Apr 2024 03:28:40 +0100 Subject: [PATCH 064/161] JIT ARM64-SVE: Add Sve.LoadVector*ZeroExtendTo*() (#101291) * JIT ARM64-SVE: Add Sve.LoadVector*ZeroExtendTo*() Add the following APIs: LoadVectorByteZeroExtendToInt16 LoadVectorByteZeroExtendToInt32 LoadVectorByteZeroExtendToInt64 LoadVectorByteZeroExtendToUInt16 LoadVectorByteZeroExtendToUInt32 LoadVectorByteZeroExtendToUInt64 LoadVectorInt16SignExtendToInt32 LoadVectorInt16SignExtendToInt64 LoadVectorInt16SignExtendToUInt32 LoadVectorInt16SignExtendToUInt64 LoadVectorInt32SignExtendToInt64 LoadVectorInt32SignExtendToUInt64 LoadVectorSByteSignExtendToInt16 LoadVectorSByteSignExtendToInt32 LoadVectorSByteSignExtendToInt64 LoadVectorSByteSignExtendToUInt16 LoadVectorSByteSignExtendToUInt32 LoadVectorSByteSignExtendToUInt64 LoadVectorUInt16ZeroExtendToInt32 LoadVectorUInt16ZeroExtendToInt64 LoadVectorUInt16ZeroExtendToUInt32 LoadVectorUInt16ZeroExtendToUInt64 LoadVectorUInt32ZeroExtendToInt64 LoadVectorUInt32ZeroExtendToUInt64 * cleanup: remove unwatnted comments Remove comments that mentions instuctions that APIs are never mapped to. * fix merge conflict * fix merge conflict * fix spacing * Mark LoadVector*Extend* as having HW_Flag_ExplicitMaskedOperation --------- Co-authored-by: Kunal Pathak --- src/coreclr/jit/emitarm64sve.cpp | 3 + src/coreclr/jit/gentree.cpp | 24 ++ src/coreclr/jit/hwintrinsiclistarm64sve.h | 24 ++ .../Arm/Sve.PlatformNotSupported.cs | 216 +++++++++++++++++ .../src/System/Runtime/Intrinsics/Arm/Sve.cs | 217 ++++++++++++++++++ .../ref/System.Runtime.Intrinsics.cs | 25 ++ .../GenerateHWIntrinsicTests_Arm.cs | 27 ++- 7 files changed, 535 insertions(+), 1 deletion(-) diff --git a/src/coreclr/jit/emitarm64sve.cpp b/src/coreclr/jit/emitarm64sve.cpp index 1b90b26ba799af..3eadf273290f85 100644 --- a/src/coreclr/jit/emitarm64sve.cpp +++ b/src/coreclr/jit/emitarm64sve.cpp @@ -4349,8 +4349,11 @@ void emitter::emitInsSve_R_R_R(instruction ins, break; case INS_sve_ld1b: + case INS_sve_ld1sb: case INS_sve_ld1h: + case INS_sve_ld1sh: case INS_sve_ld1w: + case INS_sve_ld1sw: case INS_sve_ld1d: return emitIns_R_R_R_I(ins, size, reg1, reg2, reg3, 0, opt); diff --git a/src/coreclr/jit/gentree.cpp b/src/coreclr/jit/gentree.cpp index 85ce90e94e001d..8076662e183e44 100644 --- a/src/coreclr/jit/gentree.cpp +++ b/src/coreclr/jit/gentree.cpp @@ -26508,6 +26508,30 @@ bool GenTreeHWIntrinsic::OperIsMemoryLoad(GenTree** pAddr) const break; case NI_Sve_LoadVector: + case NI_Sve_LoadVectorByteZeroExtendToInt16: + case NI_Sve_LoadVectorByteZeroExtendToInt32: + case NI_Sve_LoadVectorByteZeroExtendToInt64: + case NI_Sve_LoadVectorByteZeroExtendToUInt16: + case NI_Sve_LoadVectorByteZeroExtendToUInt32: + case NI_Sve_LoadVectorByteZeroExtendToUInt64: + case NI_Sve_LoadVectorInt16SignExtendToInt32: + case NI_Sve_LoadVectorInt16SignExtendToInt64: + case NI_Sve_LoadVectorInt16SignExtendToUInt32: + case NI_Sve_LoadVectorInt16SignExtendToUInt64: + case NI_Sve_LoadVectorInt32SignExtendToInt64: + case NI_Sve_LoadVectorInt32SignExtendToUInt64: + case NI_Sve_LoadVectorSByteSignExtendToInt16: + case NI_Sve_LoadVectorSByteSignExtendToInt32: + case NI_Sve_LoadVectorSByteSignExtendToInt64: + case NI_Sve_LoadVectorSByteSignExtendToUInt16: + case NI_Sve_LoadVectorSByteSignExtendToUInt32: + case NI_Sve_LoadVectorSByteSignExtendToUInt64: + case NI_Sve_LoadVectorUInt16ZeroExtendToInt32: + case NI_Sve_LoadVectorUInt16ZeroExtendToInt64: + case NI_Sve_LoadVectorUInt16ZeroExtendToUInt32: + case NI_Sve_LoadVectorUInt16ZeroExtendToUInt64: + case NI_Sve_LoadVectorUInt32ZeroExtendToInt64: + case NI_Sve_LoadVectorUInt32ZeroExtendToUInt64: addr = Op(2); break; #endif // TARGET_ARM64 diff --git a/src/coreclr/jit/hwintrinsiclistarm64sve.h b/src/coreclr/jit/hwintrinsiclistarm64sve.h index 14b880c8e570e4..02fd4992204c0c 100644 --- a/src/coreclr/jit/hwintrinsiclistarm64sve.h +++ b/src/coreclr/jit/hwintrinsiclistarm64sve.h @@ -32,6 +32,30 @@ HARDWARE_INTRINSIC(Sve, CreateTrueMaskUInt32, HARDWARE_INTRINSIC(Sve, CreateTrueMaskUInt64, -1, 1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sve_ptrue, INS_invalid, INS_invalid}, HW_Category_EnumPattern, HW_Flag_Scalable|HW_Flag_HasImmediateOperand|HW_Flag_ReturnsPerElementMask) HARDWARE_INTRINSIC(Sve, LoadVector, -1, 2, true, {INS_sve_ld1b, INS_sve_ld1b, INS_sve_ld1h, INS_sve_ld1h, INS_sve_ld1w, INS_sve_ld1w, INS_sve_ld1d, INS_sve_ld1d, INS_sve_ld1w, INS_sve_ld1d}, HW_Category_MemoryLoad, HW_Flag_Scalable|HW_Flag_ExplicitMaskedOperation|HW_Flag_LowMaskedOperation) +HARDWARE_INTRINSIC(Sve, LoadVectorByteZeroExtendToInt16, -1, 2, false, {INS_invalid, INS_invalid, INS_sve_ld1b, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_MemoryLoad, HW_Flag_Scalable|HW_Flag_ExplicitMaskedOperation|HW_Flag_LowMaskedOperation) +HARDWARE_INTRINSIC(Sve, LoadVectorByteZeroExtendToInt32, -1, 2, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sve_ld1b, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_MemoryLoad, HW_Flag_Scalable|HW_Flag_ExplicitMaskedOperation|HW_Flag_LowMaskedOperation) +HARDWARE_INTRINSIC(Sve, LoadVectorByteZeroExtendToInt64, -1, 2, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sve_ld1b, INS_invalid, INS_invalid, INS_invalid}, HW_Category_MemoryLoad, HW_Flag_Scalable|HW_Flag_ExplicitMaskedOperation|HW_Flag_LowMaskedOperation) +HARDWARE_INTRINSIC(Sve, LoadVectorByteZeroExtendToUInt16, -1, 2, false, {INS_invalid, INS_invalid, INS_invalid, INS_sve_ld1b, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_MemoryLoad, HW_Flag_Scalable|HW_Flag_ExplicitMaskedOperation|HW_Flag_LowMaskedOperation) +HARDWARE_INTRINSIC(Sve, LoadVectorByteZeroExtendToUInt32, -1, 2, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sve_ld1b, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_MemoryLoad, HW_Flag_Scalable|HW_Flag_ExplicitMaskedOperation|HW_Flag_LowMaskedOperation) +HARDWARE_INTRINSIC(Sve, LoadVectorByteZeroExtendToUInt64, -1, 2, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sve_ld1b, INS_invalid, INS_invalid}, HW_Category_MemoryLoad, HW_Flag_Scalable|HW_Flag_ExplicitMaskedOperation|HW_Flag_LowMaskedOperation) +HARDWARE_INTRINSIC(Sve, LoadVectorInt16SignExtendToInt32, -1, 2, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sve_ld1sh, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_MemoryLoad, HW_Flag_Scalable|HW_Flag_ExplicitMaskedOperation|HW_Flag_LowMaskedOperation) +HARDWARE_INTRINSIC(Sve, LoadVectorInt16SignExtendToInt64, -1, 2, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sve_ld1sh, INS_invalid, INS_invalid, INS_invalid}, HW_Category_MemoryLoad, HW_Flag_Scalable|HW_Flag_ExplicitMaskedOperation|HW_Flag_LowMaskedOperation) +HARDWARE_INTRINSIC(Sve, LoadVectorInt16SignExtendToUInt32, -1, 2, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sve_ld1sh, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_MemoryLoad, HW_Flag_Scalable|HW_Flag_ExplicitMaskedOperation|HW_Flag_LowMaskedOperation) +HARDWARE_INTRINSIC(Sve, LoadVectorInt16SignExtendToUInt64, -1, 2, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sve_ld1sh, INS_invalid, INS_invalid}, HW_Category_MemoryLoad, HW_Flag_Scalable|HW_Flag_ExplicitMaskedOperation|HW_Flag_LowMaskedOperation) +HARDWARE_INTRINSIC(Sve, LoadVectorInt32SignExtendToInt64, -1, 2, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sve_ld1sw, INS_invalid, INS_invalid, INS_invalid}, HW_Category_MemoryLoad, HW_Flag_Scalable|HW_Flag_ExplicitMaskedOperation|HW_Flag_LowMaskedOperation) +HARDWARE_INTRINSIC(Sve, LoadVectorInt32SignExtendToUInt64, -1, 2, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sve_ld1sw, INS_invalid, INS_invalid}, HW_Category_MemoryLoad, HW_Flag_Scalable|HW_Flag_ExplicitMaskedOperation|HW_Flag_LowMaskedOperation) +HARDWARE_INTRINSIC(Sve, LoadVectorSByteSignExtendToInt16, -1, 2, false, {INS_invalid, INS_invalid, INS_sve_ld1sb, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_MemoryLoad, HW_Flag_Scalable|HW_Flag_ExplicitMaskedOperation|HW_Flag_LowMaskedOperation) +HARDWARE_INTRINSIC(Sve, LoadVectorSByteSignExtendToInt32, -1, 2, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sve_ld1sb, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_MemoryLoad, HW_Flag_Scalable|HW_Flag_ExplicitMaskedOperation|HW_Flag_LowMaskedOperation) +HARDWARE_INTRINSIC(Sve, LoadVectorSByteSignExtendToInt64, -1, 2, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sve_ld1sb, INS_invalid, INS_invalid, INS_invalid}, HW_Category_MemoryLoad, HW_Flag_Scalable|HW_Flag_ExplicitMaskedOperation|HW_Flag_LowMaskedOperation) +HARDWARE_INTRINSIC(Sve, LoadVectorSByteSignExtendToUInt16, -1, 2, false, {INS_invalid, INS_invalid, INS_invalid, INS_sve_ld1sb, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_MemoryLoad, HW_Flag_Scalable|HW_Flag_ExplicitMaskedOperation|HW_Flag_LowMaskedOperation) +HARDWARE_INTRINSIC(Sve, LoadVectorSByteSignExtendToUInt32, -1, 2, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sve_ld1sb, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_MemoryLoad, HW_Flag_Scalable|HW_Flag_ExplicitMaskedOperation|HW_Flag_LowMaskedOperation) +HARDWARE_INTRINSIC(Sve, LoadVectorSByteSignExtendToUInt64, -1, 2, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sve_ld1sb, INS_invalid, INS_invalid}, HW_Category_MemoryLoad, HW_Flag_Scalable|HW_Flag_ExplicitMaskedOperation|HW_Flag_LowMaskedOperation) +HARDWARE_INTRINSIC(Sve, LoadVectorUInt16ZeroExtendToInt32, -1, 2, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sve_ld1h, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_MemoryLoad, HW_Flag_Scalable|HW_Flag_ExplicitMaskedOperation|HW_Flag_LowMaskedOperation) +HARDWARE_INTRINSIC(Sve, LoadVectorUInt16ZeroExtendToInt64, -1, 2, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sve_ld1h, INS_invalid, INS_invalid, INS_invalid}, HW_Category_MemoryLoad, HW_Flag_Scalable|HW_Flag_ExplicitMaskedOperation|HW_Flag_LowMaskedOperation) +HARDWARE_INTRINSIC(Sve, LoadVectorUInt16ZeroExtendToUInt32, -1, 2, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sve_ld1h, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_MemoryLoad, HW_Flag_Scalable|HW_Flag_ExplicitMaskedOperation|HW_Flag_LowMaskedOperation) +HARDWARE_INTRINSIC(Sve, LoadVectorUInt16ZeroExtendToUInt64, -1, 2, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sve_ld1h, INS_invalid, INS_invalid}, HW_Category_MemoryLoad, HW_Flag_Scalable|HW_Flag_ExplicitMaskedOperation|HW_Flag_LowMaskedOperation) +HARDWARE_INTRINSIC(Sve, LoadVectorUInt32ZeroExtendToInt64, -1, 2, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sve_ld1w, INS_invalid, INS_invalid, INS_invalid}, HW_Category_MemoryLoad, HW_Flag_Scalable|HW_Flag_ExplicitMaskedOperation|HW_Flag_LowMaskedOperation) +HARDWARE_INTRINSIC(Sve, LoadVectorUInt32ZeroExtendToUInt64, -1, 2, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sve_ld1w, INS_invalid, INS_invalid}, HW_Category_MemoryLoad, HW_Flag_Scalable|HW_Flag_ExplicitMaskedOperation|HW_Flag_LowMaskedOperation) diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Arm/Sve.PlatformNotSupported.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Arm/Sve.PlatformNotSupported.cs index 8d56e32fc863ca..4b0ccfaecd6def 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Arm/Sve.PlatformNotSupported.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Arm/Sve.PlatformNotSupported.cs @@ -372,5 +372,221 @@ internal Arm64() { } public static unsafe Vector LoadVector(Vector mask, double* address) { throw new PlatformNotSupportedException(); } + /// LoadVectorByteZeroExtendToInt16 : Load 8-bit data and zero-extend + + /// + /// svint16_t svld1ub_s16(svbool_t pg, const uint8_t *base) + /// LD1B Zresult.H, Pg/Z, [Xbase, #0, MUL VL] + /// + public static unsafe Vector LoadVectorByteZeroExtendToInt16(Vector mask, byte* address) { throw new PlatformNotSupportedException(); } + + + /// LoadVectorByteZeroExtendToInt32 : Load 8-bit data and zero-extend + + /// + /// svint32_t svld1ub_s32(svbool_t pg, const uint8_t *base) + /// LD1B Zresult.S, Pg/Z, [Xbase, #0, MUL VL] + /// + public static unsafe Vector LoadVectorByteZeroExtendToInt32(Vector mask, byte* address) { throw new PlatformNotSupportedException(); } + + + /// LoadVectorByteZeroExtendToInt64 : Load 8-bit data and zero-extend + + /// + /// svint64_t svld1ub_s64(svbool_t pg, const uint8_t *base) + /// LD1B Zresult.D, Pg/Z, [Xbase, #0, MUL VL] + /// + public static unsafe Vector LoadVectorByteZeroExtendToInt64(Vector mask, byte* address) { throw new PlatformNotSupportedException(); } + + + /// LoadVectorByteZeroExtendToUInt16 : Load 8-bit data and zero-extend + + /// + /// svuint16_t svld1ub_u16(svbool_t pg, const uint8_t *base) + /// LD1B Zresult.H, Pg/Z, [Xbase, #0, MUL VL] + /// + public static unsafe Vector LoadVectorByteZeroExtendToUInt16(Vector mask, byte* address) { throw new PlatformNotSupportedException(); } + + + /// LoadVectorByteZeroExtendToUInt32 : Load 8-bit data and zero-extend + + /// + /// svuint32_t svld1ub_u32(svbool_t pg, const uint8_t *base) + /// LD1B Zresult.S, Pg/Z, [Xbase, #0, MUL VL] + /// + public static unsafe Vector LoadVectorByteZeroExtendToUInt32(Vector mask, byte* address) { throw new PlatformNotSupportedException(); } + + + /// LoadVectorByteZeroExtendToUInt64 : Load 8-bit data and zero-extend + + /// + /// svuint64_t svld1ub_u64(svbool_t pg, const uint8_t *base) + /// LD1B Zresult.D, Pg/Z, [Xbase, #0, MUL VL] + /// + public static unsafe Vector LoadVectorByteZeroExtendToUInt64(Vector mask, byte* address) { throw new PlatformNotSupportedException(); } + + + /// LoadVectorInt16SignExtendToInt32 : Load 16-bit data and sign-extend + + /// + /// svint32_t svld1sh_s32(svbool_t pg, const int16_t *base) + /// LD1SH Zresult.S, Pg/Z, [Xbase, #0, MUL VL] + /// + public static unsafe Vector LoadVectorInt16SignExtendToInt32(Vector mask, short* address) { throw new PlatformNotSupportedException(); } + + + /// LoadVectorInt16SignExtendToInt64 : Load 16-bit data and sign-extend + + /// + /// svint64_t svld1sh_s64(svbool_t pg, const int16_t *base) + /// LD1SH Zresult.D, Pg/Z, [Xbase, #0, MUL VL] + /// + public static unsafe Vector LoadVectorInt16SignExtendToInt64(Vector mask, short* address) { throw new PlatformNotSupportedException(); } + + + /// LoadVectorInt16SignExtendToUInt32 : Load 16-bit data and sign-extend + + /// + /// svuint32_t svld1sh_u32(svbool_t pg, const int16_t *base) + /// LD1SH Zresult.S, Pg/Z, [Xbase, #0, MUL VL] + /// + public static unsafe Vector LoadVectorInt16SignExtendToUInt32(Vector mask, short* address) { throw new PlatformNotSupportedException(); } + + + /// LoadVectorInt16SignExtendToUInt64 : Load 16-bit data and sign-extend + + /// + /// svuint64_t svld1sh_u64(svbool_t pg, const int16_t *base) + /// LD1SH Zresult.D, Pg/Z, [Xbase, #0, MUL VL] + /// + public static unsafe Vector LoadVectorInt16SignExtendToUInt64(Vector mask, short* address) { throw new PlatformNotSupportedException(); } + + + /// LoadVectorInt32SignExtendToInt64 : Load 32-bit data and sign-extend + + /// + /// svint64_t svld1sw_s64(svbool_t pg, const int32_t *base) + /// LD1SW Zresult.D, Pg/Z, [Xbase, #0, MUL VL] + /// + public static unsafe Vector LoadVectorInt32SignExtendToInt64(Vector mask, int* address) { throw new PlatformNotSupportedException(); } + + + /// LoadVectorInt32SignExtendToUInt64 : Load 32-bit data and sign-extend + + /// + /// svuint64_t svld1sw_u64(svbool_t pg, const int32_t *base) + /// LD1SW Zresult.D, Pg/Z, [Xbase, #0, MUL VL] + /// + public static unsafe Vector LoadVectorInt32SignExtendToUInt64(Vector mask, int* address) { throw new PlatformNotSupportedException(); } + + + /// LoadVectorSByteSignExtendToInt16 : Load 8-bit data and sign-extend + + /// + /// svint16_t svld1sb_s16(svbool_t pg, const int8_t *base) + /// LD1SB Zresult.H, Pg/Z, [Xbase, #0, MUL VL] + /// + public static unsafe Vector LoadVectorSByteSignExtendToInt16(Vector mask, sbyte* address) { throw new PlatformNotSupportedException(); } + + + /// LoadVectorSByteSignExtendToInt32 : Load 8-bit data and sign-extend + + /// + /// svint32_t svld1sb_s32(svbool_t pg, const int8_t *base) + /// LD1SB Zresult.S, Pg/Z, [Xbase, #0, MUL VL] + /// + public static unsafe Vector LoadVectorSByteSignExtendToInt32(Vector mask, sbyte* address) { throw new PlatformNotSupportedException(); } + + + /// LoadVectorSByteSignExtendToInt64 : Load 8-bit data and sign-extend + + /// + /// svint64_t svld1sb_s64(svbool_t pg, const int8_t *base) + /// LD1SB Zresult.D, Pg/Z, [Xbase, #0, MUL VL] + /// + public static unsafe Vector LoadVectorSByteSignExtendToInt64(Vector mask, sbyte* address) { throw new PlatformNotSupportedException(); } + + + /// LoadVectorSByteSignExtendToUInt16 : Load 8-bit data and sign-extend + + /// + /// svuint16_t svld1sb_u16(svbool_t pg, const int8_t *base) + /// LD1SB Zresult.H, Pg/Z, [Xbase, #0, MUL VL] + /// + public static unsafe Vector LoadVectorSByteSignExtendToUInt16(Vector mask, sbyte* address) { throw new PlatformNotSupportedException(); } + + + /// LoadVectorSByteSignExtendToUInt32 : Load 8-bit data and sign-extend + + /// + /// svuint32_t svld1sb_u32(svbool_t pg, const int8_t *base) + /// LD1SB Zresult.S, Pg/Z, [Xbase, #0, MUL VL] + /// + public static unsafe Vector LoadVectorSByteSignExtendToUInt32(Vector mask, sbyte* address) { throw new PlatformNotSupportedException(); } + + + /// LoadVectorSByteSignExtendToUInt64 : Load 8-bit data and sign-extend + + /// + /// svuint64_t svld1sb_u64(svbool_t pg, const int8_t *base) + /// LD1SB Zresult.D, Pg/Z, [Xbase, #0, MUL VL] + /// + public static unsafe Vector LoadVectorSByteSignExtendToUInt64(Vector mask, sbyte* address) { throw new PlatformNotSupportedException(); } + + + /// LoadVectorUInt16ZeroExtendToInt32 : Load 16-bit data and zero-extend + + /// + /// svint32_t svld1uh_s32(svbool_t pg, const uint16_t *base) + /// LD1H Zresult.S, Pg/Z, [Xbase, #0, MUL VL] + /// + public static unsafe Vector LoadVectorUInt16ZeroExtendToInt32(Vector mask, ushort* address) { throw new PlatformNotSupportedException(); } + + + /// LoadVectorUInt16ZeroExtendToInt64 : Load 16-bit data and zero-extend + + /// + /// svint64_t svld1uh_s64(svbool_t pg, const uint16_t *base) + /// LD1H Zresult.D, Pg/Z, [Xbase, #0, MUL VL] + /// + public static unsafe Vector LoadVectorUInt16ZeroExtendToInt64(Vector mask, ushort* address) { throw new PlatformNotSupportedException(); } + + + /// LoadVectorUInt16ZeroExtendToUInt32 : Load 16-bit data and zero-extend + + /// + /// svuint32_t svld1uh_u32(svbool_t pg, const uint16_t *base) + /// LD1H Zresult.S, Pg/Z, [Xbase, #0, MUL VL] + /// + public static unsafe Vector LoadVectorUInt16ZeroExtendToUInt32(Vector mask, ushort* address) { throw new PlatformNotSupportedException(); } + + + /// LoadVectorUInt16ZeroExtendToUInt64 : Load 16-bit data and zero-extend + + /// + /// svuint64_t svld1uh_u64(svbool_t pg, const uint16_t *base) + /// LD1H Zresult.D, Pg/Z, [Xbase, #0, MUL VL] + /// + public static unsafe Vector LoadVectorUInt16ZeroExtendToUInt64(Vector mask, ushort* address) { throw new PlatformNotSupportedException(); } + + + /// LoadVectorUInt32ZeroExtendToInt64 : Load 32-bit data and zero-extend + + /// + /// svint64_t svld1uw_s64(svbool_t pg, const uint32_t *base) + /// LD1W Zresult.D, Pg/Z, [Xbase, #0, MUL VL] + /// + public static unsafe Vector LoadVectorUInt32ZeroExtendToInt64(Vector mask, uint* address) { throw new PlatformNotSupportedException(); } + + + /// LoadVectorUInt32ZeroExtendToUInt64 : Load 32-bit data and zero-extend + + /// + /// svuint64_t svld1uw_u64(svbool_t pg, const uint32_t *base) + /// LD1W Zresult.D, Pg/Z, [Xbase, #0, MUL VL] + /// + public static unsafe Vector LoadVectorUInt32ZeroExtendToUInt64(Vector mask, uint* address) { throw new PlatformNotSupportedException(); } + + } } diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Arm/Sve.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Arm/Sve.cs index a13957916f49a7..9f17f6b9008ed0 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Arm/Sve.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Arm/Sve.cs @@ -426,5 +426,222 @@ internal Arm64() { } /// public static unsafe Vector LoadVector(Vector mask, double* address) => LoadVector(mask, address); + + /// LoadVectorByteZeroExtendToInt16 : Load 8-bit data and zero-extend + + /// + /// svint16_t svld1ub_s16(svbool_t pg, const uint8_t *base) + /// LD1B Zresult.H, Pg/Z, [Xbase, #0, MUL VL] + /// + public static unsafe Vector LoadVectorByteZeroExtendToInt16(Vector mask, byte* address) => LoadVectorByteZeroExtendToInt16(mask, address); + + + /// LoadVectorByteZeroExtendToInt32 : Load 8-bit data and zero-extend + + /// + /// svint32_t svld1ub_s32(svbool_t pg, const uint8_t *base) + /// LD1B Zresult.S, Pg/Z, [Xbase, #0, MUL VL] + /// + public static unsafe Vector LoadVectorByteZeroExtendToInt32(Vector mask, byte* address) => LoadVectorByteZeroExtendToInt32(mask, address); + + + /// LoadVectorByteZeroExtendToInt64 : Load 8-bit data and zero-extend + + /// + /// svint64_t svld1ub_s64(svbool_t pg, const uint8_t *base) + /// LD1B Zresult.D, Pg/Z, [Xbase, #0, MUL VL] + /// + public static unsafe Vector LoadVectorByteZeroExtendToInt64(Vector mask, byte* address) => LoadVectorByteZeroExtendToInt64(mask, address); + + + /// LoadVectorByteZeroExtendToUInt16 : Load 8-bit data and zero-extend + + /// + /// svuint16_t svld1ub_u16(svbool_t pg, const uint8_t *base) + /// LD1B Zresult.H, Pg/Z, [Xbase, #0, MUL VL] + /// + public static unsafe Vector LoadVectorByteZeroExtendToUInt16(Vector mask, byte* address) => LoadVectorByteZeroExtendToUInt16(mask, address); + + + /// LoadVectorByteZeroExtendToUInt32 : Load 8-bit data and zero-extend + + /// + /// svuint32_t svld1ub_u32(svbool_t pg, const uint8_t *base) + /// LD1B Zresult.S, Pg/Z, [Xbase, #0, MUL VL] + /// + public static unsafe Vector LoadVectorByteZeroExtendToUInt32(Vector mask, byte* address) => LoadVectorByteZeroExtendToUInt32(mask, address); + + + /// LoadVectorByteZeroExtendToUInt64 : Load 8-bit data and zero-extend + + /// + /// svuint64_t svld1ub_u64(svbool_t pg, const uint8_t *base) + /// LD1B Zresult.D, Pg/Z, [Xbase, #0, MUL VL] + /// + public static unsafe Vector LoadVectorByteZeroExtendToUInt64(Vector mask, byte* address) => LoadVectorByteZeroExtendToUInt64(mask, address); + + + /// LoadVectorInt16SignExtendToInt32 : Load 16-bit data and sign-extend + + /// + /// svint32_t svld1sh_s32(svbool_t pg, const int16_t *base) + /// LD1SH Zresult.S, Pg/Z, [Xbase, #0, MUL VL] + /// + public static unsafe Vector LoadVectorInt16SignExtendToInt32(Vector mask, short* address) => LoadVectorInt16SignExtendToInt32(mask, address); + + + /// LoadVectorInt16SignExtendToInt64 : Load 16-bit data and sign-extend + + /// + /// svint64_t svld1sh_s64(svbool_t pg, const int16_t *base) + /// LD1SH Zresult.D, Pg/Z, [Xbase, #0, MUL VL] + /// + public static unsafe Vector LoadVectorInt16SignExtendToInt64(Vector mask, short* address) => LoadVectorInt16SignExtendToInt64(mask, address); + + + /// LoadVectorInt16SignExtendToUInt32 : Load 16-bit data and sign-extend + + /// + /// svuint32_t svld1sh_u32(svbool_t pg, const int16_t *base) + /// LD1SH Zresult.S, Pg/Z, [Xbase, #0, MUL VL] + /// + public static unsafe Vector LoadVectorInt16SignExtendToUInt32(Vector mask, short* address) => LoadVectorInt16SignExtendToUInt32(mask, address); + + + /// LoadVectorInt16SignExtendToUInt64 : Load 16-bit data and sign-extend + + /// + /// svuint64_t svld1sh_u64(svbool_t pg, const int16_t *base) + /// LD1SH Zresult.D, Pg/Z, [Xbase, #0, MUL VL] + /// + public static unsafe Vector LoadVectorInt16SignExtendToUInt64(Vector mask, short* address) => LoadVectorInt16SignExtendToUInt64(mask, address); + + + /// LoadVectorInt32SignExtendToInt64 : Load 32-bit data and sign-extend + + /// + /// svint64_t svld1sw_s64(svbool_t pg, const int32_t *base) + /// LD1SW Zresult.D, Pg/Z, [Xbase, #0, MUL VL] + /// + public static unsafe Vector LoadVectorInt32SignExtendToInt64(Vector mask, int* address) => LoadVectorInt32SignExtendToInt64(mask, address); + + + /// LoadVectorInt32SignExtendToUInt64 : Load 32-bit data and sign-extend + + /// + /// svuint64_t svld1sw_u64(svbool_t pg, const int32_t *base) + /// LD1SW Zresult.D, Pg/Z, [Xbase, #0, MUL VL] + /// + public static unsafe Vector LoadVectorInt32SignExtendToUInt64(Vector mask, int* address) => LoadVectorInt32SignExtendToUInt64(mask, address); + + + /// LoadVectorSByteSignExtendToInt16 : Load 8-bit data and sign-extend + + /// + /// svint16_t svld1sb_s16(svbool_t pg, const int8_t *base) + /// LD1SB Zresult.H, Pg/Z, [Xbase, #0, MUL VL] + /// + public static unsafe Vector LoadVectorSByteSignExtendToInt16(Vector mask, sbyte* address) => LoadVectorSByteSignExtendToInt16(mask, address); + + + /// LoadVectorSByteSignExtendToInt32 : Load 8-bit data and sign-extend + + /// + /// svint32_t svld1sb_s32(svbool_t pg, const int8_t *base) + /// LD1SB Zresult.S, Pg/Z, [Xbase, #0, MUL VL] + /// + public static unsafe Vector LoadVectorSByteSignExtendToInt32(Vector mask, sbyte* address) => LoadVectorSByteSignExtendToInt32(mask, address); + + + /// LoadVectorSByteSignExtendToInt64 : Load 8-bit data and sign-extend + + /// + /// svint64_t svld1sb_s64(svbool_t pg, const int8_t *base) + /// LD1SB Zresult.D, Pg/Z, [Xbase, #0, MUL VL] + /// + public static unsafe Vector LoadVectorSByteSignExtendToInt64(Vector mask, sbyte* address) => LoadVectorSByteSignExtendToInt64(mask, address); + + + /// LoadVectorSByteSignExtendToUInt16 : Load 8-bit data and sign-extend + + /// + /// svuint16_t svld1sb_u16(svbool_t pg, const int8_t *base) + /// LD1SB Zresult.H, Pg/Z, [Xbase, #0, MUL VL] + /// + public static unsafe Vector LoadVectorSByteSignExtendToUInt16(Vector mask, sbyte* address) => LoadVectorSByteSignExtendToUInt16(mask, address); + + + /// LoadVectorSByteSignExtendToUInt32 : Load 8-bit data and sign-extend + + /// + /// svuint32_t svld1sb_u32(svbool_t pg, const int8_t *base) + /// LD1SB Zresult.S, Pg/Z, [Xbase, #0, MUL VL] + /// + public static unsafe Vector LoadVectorSByteSignExtendToUInt32(Vector mask, sbyte* address) => LoadVectorSByteSignExtendToUInt32(mask, address); + + + /// LoadVectorSByteSignExtendToUInt64 : Load 8-bit data and sign-extend + + /// + /// svuint64_t svld1sb_u64(svbool_t pg, const int8_t *base) + /// LD1SB Zresult.D, Pg/Z, [Xbase, #0, MUL VL] + /// + public static unsafe Vector LoadVectorSByteSignExtendToUInt64(Vector mask, sbyte* address) => LoadVectorSByteSignExtendToUInt64(mask, address); + + + /// LoadVectorUInt16ZeroExtendToInt32 : Load 16-bit data and zero-extend + + /// + /// svint32_t svld1uh_s32(svbool_t pg, const uint16_t *base) + /// LD1H Zresult.S, Pg/Z, [Xbase, #0, MUL VL] + /// + public static unsafe Vector LoadVectorUInt16ZeroExtendToInt32(Vector mask, ushort* address) => LoadVectorUInt16ZeroExtendToInt32(mask, address); + + + /// LoadVectorUInt16ZeroExtendToInt64 : Load 16-bit data and zero-extend + + /// + /// svint64_t svld1uh_s64(svbool_t pg, const uint16_t *base) + /// LD1H Zresult.D, Pg/Z, [Xbase, #0, MUL VL] + /// + public static unsafe Vector LoadVectorUInt16ZeroExtendToInt64(Vector mask, ushort* address) => LoadVectorUInt16ZeroExtendToInt64(mask, address); + + + /// LoadVectorUInt16ZeroExtendToUInt32 : Load 16-bit data and zero-extend + + /// + /// svuint32_t svld1uh_u32(svbool_t pg, const uint16_t *base) + /// LD1H Zresult.S, Pg/Z, [Xbase, #0, MUL VL] + /// + public static unsafe Vector LoadVectorUInt16ZeroExtendToUInt32(Vector mask, ushort* address) => LoadVectorUInt16ZeroExtendToUInt32(mask, address); + + + /// LoadVectorUInt16ZeroExtendToUInt64 : Load 16-bit data and zero-extend + + /// + /// svuint64_t svld1uh_u64(svbool_t pg, const uint16_t *base) + /// LD1H Zresult.D, Pg/Z, [Xbase, #0, MUL VL] + /// + public static unsafe Vector LoadVectorUInt16ZeroExtendToUInt64(Vector mask, ushort* address) => LoadVectorUInt16ZeroExtendToUInt64(mask, address); + + + /// LoadVectorUInt32ZeroExtendToInt64 : Load 32-bit data and zero-extend + + /// + /// svint64_t svld1uw_s64(svbool_t pg, const uint32_t *base) + /// LD1W Zresult.D, Pg/Z, [Xbase, #0, MUL VL] + /// + public static unsafe Vector LoadVectorUInt32ZeroExtendToInt64(Vector mask, uint* address) => LoadVectorUInt32ZeroExtendToInt64(mask, address); + + + /// LoadVectorUInt32ZeroExtendToUInt64 : Load 32-bit data and zero-extend + + /// + /// svuint64_t svld1uw_u64(svbool_t pg, const uint32_t *base) + /// LD1W Zresult.D, Pg/Z, [Xbase, #0, MUL VL] + /// + public static unsafe Vector LoadVectorUInt32ZeroExtendToUInt64(Vector mask, uint* address) => LoadVectorUInt32ZeroExtendToUInt64(mask, address); + + } } diff --git a/src/libraries/System.Runtime.Intrinsics/ref/System.Runtime.Intrinsics.cs b/src/libraries/System.Runtime.Intrinsics/ref/System.Runtime.Intrinsics.cs index 3980308ca0d20e..875d125cb32b50 100644 --- a/src/libraries/System.Runtime.Intrinsics/ref/System.Runtime.Intrinsics.cs +++ b/src/libraries/System.Runtime.Intrinsics/ref/System.Runtime.Intrinsics.cs @@ -4217,6 +4217,31 @@ internal Arm64() { } public static unsafe System.Numerics.Vector LoadVector(System.Numerics.Vector mask, ulong* address) { throw null; } public static unsafe System.Numerics.Vector LoadVector(System.Numerics.Vector mask, float* address) { throw null; } public static unsafe System.Numerics.Vector LoadVector(System.Numerics.Vector mask, double* address) { throw null; } + public static unsafe System.Numerics.Vector LoadVectorByteZeroExtendToInt16(System.Numerics.Vector mask, byte* address) { throw null; } + public static unsafe System.Numerics.Vector LoadVectorByteZeroExtendToInt32(System.Numerics.Vector mask, byte* address) { throw null; } + public static unsafe System.Numerics.Vector LoadVectorByteZeroExtendToInt64(System.Numerics.Vector mask, byte* address) { throw null; } + public static unsafe System.Numerics.Vector LoadVectorByteZeroExtendToUInt16(System.Numerics.Vector mask, byte* address) { throw null; } + public static unsafe System.Numerics.Vector LoadVectorByteZeroExtendToUInt32(System.Numerics.Vector mask, byte* address) { throw null; } + public static unsafe System.Numerics.Vector LoadVectorByteZeroExtendToUInt64(System.Numerics.Vector mask, byte* address) { throw null; } + public static unsafe System.Numerics.Vector LoadVectorInt16SignExtendToInt32(System.Numerics.Vector mask, short* address) { throw null; } + public static unsafe System.Numerics.Vector LoadVectorInt16SignExtendToInt64(System.Numerics.Vector mask, short* address) { throw null; } + public static unsafe System.Numerics.Vector LoadVectorInt16SignExtendToUInt32(System.Numerics.Vector mask, short* address) { throw null; } + public static unsafe System.Numerics.Vector LoadVectorInt16SignExtendToUInt64(System.Numerics.Vector mask, short* address) { throw null; } + public static unsafe System.Numerics.Vector LoadVectorInt32SignExtendToInt64(System.Numerics.Vector mask, int* address) { throw null; } + public static unsafe System.Numerics.Vector LoadVectorInt32SignExtendToUInt64(System.Numerics.Vector mask, int* address) { throw null; } + public static unsafe System.Numerics.Vector LoadVectorSByteSignExtendToInt16(System.Numerics.Vector mask, sbyte* address) { throw null; } + public static unsafe System.Numerics.Vector LoadVectorSByteSignExtendToInt32(System.Numerics.Vector mask, sbyte* address) { throw null; } + public static unsafe System.Numerics.Vector LoadVectorSByteSignExtendToInt64(System.Numerics.Vector mask, sbyte* address) { throw null; } + public static unsafe System.Numerics.Vector LoadVectorSByteSignExtendToUInt16(System.Numerics.Vector mask, sbyte* address) { throw null; } + public static unsafe System.Numerics.Vector LoadVectorSByteSignExtendToUInt32(System.Numerics.Vector mask, sbyte* address) { throw null; } + public static unsafe System.Numerics.Vector LoadVectorSByteSignExtendToUInt64(System.Numerics.Vector mask, sbyte* address) { throw null; } + public static unsafe System.Numerics.Vector LoadVectorUInt16ZeroExtendToInt32(System.Numerics.Vector mask, ushort* address) { throw null; } + public static unsafe System.Numerics.Vector LoadVectorUInt16ZeroExtendToInt64(System.Numerics.Vector mask, ushort* address) { throw null; } + public static unsafe System.Numerics.Vector LoadVectorUInt16ZeroExtendToUInt32(System.Numerics.Vector mask, ushort* address) { throw null; } + public static unsafe System.Numerics.Vector LoadVectorUInt16ZeroExtendToUInt64(System.Numerics.Vector mask, ushort* address) { throw null; } + public static unsafe System.Numerics.Vector LoadVectorUInt32ZeroExtendToInt64(System.Numerics.Vector mask, uint* address) { throw null; } + public static unsafe System.Numerics.Vector LoadVectorUInt32ZeroExtendToUInt64(System.Numerics.Vector mask, uint* address) { throw null; } + } public enum SveMaskPattern : byte diff --git a/src/tests/Common/GenerateHWIntrinsicTests/GenerateHWIntrinsicTests_Arm.cs b/src/tests/Common/GenerateHWIntrinsicTests/GenerateHWIntrinsicTests_Arm.cs index a2ebacb1ce8b8c..42096d7b697c73 100644 --- a/src/tests/Common/GenerateHWIntrinsicTests/GenerateHWIntrinsicTests_Arm.cs +++ b/src/tests/Common/GenerateHWIntrinsicTests/GenerateHWIntrinsicTests_Arm.cs @@ -2907,7 +2907,7 @@ ("SveVecBinOpTest.template", new Dictionary { ["TestName"] = "Sve_Add_ushort", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "Add", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "Helpers.Add(left[i], right[i]) != result[i]", ["GetIterResult"] = "Helpers.Add(left[i], right[i])"}), ("SveVecBinOpTest.template", new Dictionary { ["TestName"] = "Sve_Add_uint", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "Add", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "Helpers.Add(left[i], right[i]) != result[i]", ["GetIterResult"] = "Helpers.Add(left[i], right[i])"}), ("SveVecBinOpTest.template", new Dictionary { ["TestName"] = "Sve_Add_ulong", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "Add", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt64", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "UInt64", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt64()", ["ValidateIterResult"] = "Helpers.Add(left[i], right[i]) != result[i]", ["GetIterResult"] = "Helpers.Add(left[i], right[i])"}), - + ("SveConditionalSelect.template", new Dictionary { ["TestName"] = "Sve_ConditionalSelect_float", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "ConditionalSelect", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "Single", ["Op3VectorType"] = "Vector", ["Op3BaseType"] = "Single", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp3"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "(firstOp[i] != 0 ? (result[i] != secondOp[i]) : (result[i] != thirdOp[i]))",}), ("SveConditionalSelect.template", new Dictionary { ["TestName"] = "Sve_ConditionalSelect_double", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "ConditionalSelect", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "Double", ["Op3VectorType"] = "Vector", ["Op3BaseType"] = "Double", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp3"] = "TestLibrary.Generator.GetDouble()", ["ValidateIterResult"] = "(firstOp[i] != 0 ? (result[i] != secondOp[i]) : (result[i] != thirdOp[i]))",}), ("SveConditionalSelect.template", new Dictionary { ["TestName"] = "Sve_ConditionalSelect_sbyte", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "ConditionalSelect", ["RetVectorType"] = "Vector", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "SByte", ["Op3VectorType"] = "Vector", ["Op3BaseType"] = "SByte", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp3"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "(firstOp[i] != 0 ? (result[i] != secondOp[i]) : (result[i] != thirdOp[i]))",}), @@ -2929,6 +2929,31 @@ ("SveLoadMaskedUnOpTest.template", new Dictionary { ["TestName"] = "SveLoadVector_ushort", ["Isa"] = "Sve", ["Method"] = "LoadVector", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt16", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "64", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), ("SveLoadMaskedUnOpTest.template", new Dictionary { ["TestName"] = "SveLoadVector_uint", ["Isa"] = "Sve", ["Method"] = "LoadVector", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt32", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "64", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), ("SveLoadMaskedUnOpTest.template", new Dictionary { ["TestName"] = "SveLoadVector_ulong", ["Isa"] = "Sve", ["Method"] = "LoadVector", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt64", ["Op2BaseType"] = "UInt64", ["LargestVectorSize"] = "64", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt64()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), + + ("SveLoadMaskedUnOpTest.template", new Dictionary { ["TestName"] = "SveLoadVectorByteZeroExtendToInt16", ["Isa"] = "Sve", ["Method"] = "LoadVectorByteZeroExtendToInt16", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Int16", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "8", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), + ("SveLoadMaskedUnOpTest.template", new Dictionary {["TestName"] = "SveLoadVectorByteZeroExtendToInt32", ["Isa"] = "Sve", ["Method"] = "LoadVectorByteZeroExtendToInt32", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Int32", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "8", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), + ("SveLoadMaskedUnOpTest.template", new Dictionary {["TestName"] = "SveLoadVectorByteZeroExtendToInt64", ["Isa"] = "Sve", ["Method"] = "LoadVectorByteZeroExtendToInt64", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Int64", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "8", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), + ("SveLoadMaskedUnOpTest.template", new Dictionary {["TestName"] = "SveLoadVectorByteZeroExtendToUInt16", ["Isa"] = "Sve", ["Method"] = "LoadVectorByteZeroExtendToUInt16", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt16", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "8", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), + ("SveLoadMaskedUnOpTest.template", new Dictionary {["TestName"] = "SveLoadVectorByteZeroExtendToUInt32", ["Isa"] = "Sve", ["Method"] = "LoadVectorByteZeroExtendToUInt32", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt32", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "8", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), + ("SveLoadMaskedUnOpTest.template", new Dictionary {["TestName"] = "SveLoadVectorByteZeroExtendToUInt64", ["Isa"] = "Sve", ["Method"] = "LoadVectorByteZeroExtendToUInt64", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt64", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "8", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), + ("SveLoadMaskedUnOpTest.template", new Dictionary {["TestName"] = "SveLoadVectorInt16SignExtendToInt32", ["Isa"] = "Sve", ["Method"] = "LoadVectorInt16SignExtendToInt32", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Int32", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "8", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), + ("SveLoadMaskedUnOpTest.template", new Dictionary {["TestName"] = "SveLoadVectorInt16SignExtendToInt64", ["Isa"] = "Sve", ["Method"] = "LoadVectorInt16SignExtendToInt64", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Int64", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "8", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), + ("SveLoadMaskedUnOpTest.template", new Dictionary {["TestName"] = "SveLoadVectorInt16SignExtendToUInt32", ["Isa"] = "Sve", ["Method"] = "LoadVectorInt16SignExtendToUInt32", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt32", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "8", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), + ("SveLoadMaskedUnOpTest.template", new Dictionary {["TestName"] = "SveLoadVectorInt16SignExtendToUInt64", ["Isa"] = "Sve", ["Method"] = "LoadVectorInt16SignExtendToUInt64", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt64", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "8", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "(ulong)firstOp[i] != result[i]"}), + ("SveLoadMaskedUnOpTest.template", new Dictionary {["TestName"] = "SveLoadVectorInt32SignExtendToInt64", ["Isa"] = "Sve", ["Method"] = "LoadVectorInt32SignExtendToInt64", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Int64", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "8", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), + ("SveLoadMaskedUnOpTest.template", new Dictionary {["TestName"] = "SveLoadVectorInt32SignExtendToUInt64", ["Isa"] = "Sve", ["Method"] = "LoadVectorInt32SignExtendToUInt64", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt64", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "8", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "(ulong)firstOp[i] != result[i]"}), + ("SveLoadMaskedUnOpTest.template", new Dictionary {["TestName"] = "SveLoadVectorSByteSignExtendToInt16", ["Isa"] = "Sve", ["Method"] = "LoadVectorSByteSignExtendToInt16", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Int16", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "8", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), + ("SveLoadMaskedUnOpTest.template", new Dictionary {["TestName"] = "SveLoadVectorSByteSignExtendToInt32", ["Isa"] = "Sve", ["Method"] = "LoadVectorSByteSignExtendToInt32", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Int32", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "8", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), + ("SveLoadMaskedUnOpTest.template", new Dictionary {["TestName"] = "SveLoadVectorSByteSignExtendToInt64", ["Isa"] = "Sve", ["Method"] = "LoadVectorSByteSignExtendToInt64", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Int64", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "8", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), + ("SveLoadMaskedUnOpTest.template", new Dictionary {["TestName"] = "SveLoadVectorSByteSignExtendToUInt16", ["Isa"] = "Sve", ["Method"] = "LoadVectorSByteSignExtendToUInt16", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt16", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "8", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), + ("SveLoadMaskedUnOpTest.template", new Dictionary {["TestName"] = "SveLoadVectorSByteSignExtendToUInt32", ["Isa"] = "Sve", ["Method"] = "LoadVectorSByteSignExtendToUInt32", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt32", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "8", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), + ("SveLoadMaskedUnOpTest.template", new Dictionary {["TestName"] = "SveLoadVectorSByteSignExtendToUInt64", ["Isa"] = "Sve", ["Method"] = "LoadVectorSByteSignExtendToUInt64", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt64", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "8", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "(ulong)firstOp[i] != result[i]"}), + ("SveLoadMaskedUnOpTest.template", new Dictionary {["TestName"] = "SveLoadVectorUInt16ZeroExtendToInt32", ["Isa"] = "Sve", ["Method"] = "LoadVectorUInt16ZeroExtendToInt32", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Int32", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "8", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), + ("SveLoadMaskedUnOpTest.template", new Dictionary {["TestName"] = "SveLoadVectorUInt16ZeroExtendToInt64", ["Isa"] = "Sve", ["Method"] = "LoadVectorUInt16ZeroExtendToInt64", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Int64", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "8", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), + ("SveLoadMaskedUnOpTest.template", new Dictionary {["TestName"] = "SveLoadVectorUInt16ZeroExtendToUInt32", ["Isa"] = "Sve", ["Method"] = "LoadVectorUInt16ZeroExtendToUInt32", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt32", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "8", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), + ("SveLoadMaskedUnOpTest.template", new Dictionary {["TestName"] = "SveLoadVectorUInt16ZeroExtendToUInt64", ["Isa"] = "Sve", ["Method"] = "LoadVectorUInt16ZeroExtendToUInt64", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt64", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "8", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), + ("SveLoadMaskedUnOpTest.template", new Dictionary {["TestName"] = "SveLoadVectorUInt32ZeroExtendToInt64", ["Isa"] = "Sve", ["Method"] = "LoadVectorUInt32ZeroExtendToInt64", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Int64", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "8", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), + ("SveLoadMaskedUnOpTest.template", new Dictionary {["TestName"] = "SveLoadVectorUInt32ZeroExtendToUInt64", ["Isa"] = "Sve", ["Method"] = "LoadVectorUInt32ZeroExtendToUInt64", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt64", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "8", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), }; From 5bbd0e1b817c66a1b54130ea039b18a027130e72 Mon Sep 17 00:00:00 2001 From: Eirik Tsarpalis Date: Thu, 25 Apr 2024 03:53:32 +0100 Subject: [PATCH 065/161] Restrict indentation size in JsonWriterOptions theories. (#101498) --- .../tests/System.Text.Json.Tests/Utf8JsonWriterTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Utf8JsonWriterTests.cs b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Utf8JsonWriterTests.cs index c776982b56d925..45986cccb9aaa5 100644 --- a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Utf8JsonWriterTests.cs +++ b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Utf8JsonWriterTests.cs @@ -7637,7 +7637,7 @@ private static IEnumerable JsonOptions() return from indented in new[] { true, false } from skipValidation in new[] { true, false } from indentCharacter in indented ? new char?[] { null, ' ', '\t' } : [] - from indentSize in indented ? new int?[] { null, 0, 1, 2, 127 } : [] + from indentSize in indented ? new int?[] { null, 0, 1, 2, 3 } : [] from newLine in indented ? new string?[] { null, "\n", "\r\n" } : [] select CreateOptions(indented, indentCharacter, indentSize, skipValidation, newLine); From c028937b775855c05c19f5d6209aabf3775f4103 Mon Sep 17 00:00:00 2001 From: Giridhar Trivedi Date: Thu, 25 Apr 2024 12:39:17 +0530 Subject: [PATCH 066/161] Fix big endian issue in Interlocked test cases (#101429) Fix big indian issue wiht BitConverted as part of intercloked test cases. These were causing failures in runtime_community pipeline --------- Co-authored-by: root --- .../src/System/Threading/Interlocked.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libraries/System.Private.CoreLib/src/System/Threading/Interlocked.cs b/src/libraries/System.Private.CoreLib/src/System/Threading/Interlocked.cs index 45ebce76f7b0ee..6e33ce716fd6a1 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Threading/Interlocked.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Threading/Interlocked.cs @@ -126,7 +126,7 @@ public static unsafe ushort Exchange(ref ushort location1, ushort value) nuint offset = Unsafe.OpportunisticMisalignment(ref location1, sizeof(uint)); ref uint alignedRef = ref Unsafe.As(ref Unsafe.SubtractByteOffset(ref location1, offset)); int bitOffset = - (int)((BitConverter.IsLittleEndian ? offset : sizeof(uint) - offset - sizeof(byte)) * 8); // to bit offset + (int)((BitConverter.IsLittleEndian ? offset : sizeof(uint) - offset - sizeof(ushort)) * 8); // to bit offset Debug.Assert(bitOffset is 0 or 16); uint mask = ~((uint)ushort.MaxValue << bitOffset); uint shiftedValue = (uint)value << bitOffset; @@ -308,7 +308,7 @@ public static unsafe ushort CompareExchange(ref ushort location1, ushort value, nuint offset = Unsafe.OpportunisticMisalignment(ref location1, sizeof(uint)); ref uint alignedRef = ref Unsafe.As(ref Unsafe.SubtractByteOffset(ref location1, offset)); int bitOffset = - (int)((BitConverter.IsLittleEndian ? offset : sizeof(uint) - offset - sizeof(byte)) * 8); // to bit offset + (int)((BitConverter.IsLittleEndian ? offset : sizeof(uint) - offset - sizeof(ushort)) * 8); // to bit offset Debug.Assert(bitOffset is 0 or 16); uint mask = ~((uint)ushort.MaxValue << bitOffset); uint shiftedValue = (uint)value << bitOffset; From 43ba3a8af36541e45faaa7034ea76b5ec11b3777 Mon Sep 17 00:00:00 2001 From: Milos Kotlar Date: Thu, 25 Apr 2024 09:29:54 +0200 Subject: [PATCH 067/161] [mono] Fix `LLVMArgWasmVtypeAsScalar` when a method doesn't set its return value (#101299) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Update mini-llvm.c I think we should handle it here, the same way as `LLVMArgVtypeAsScalar`. They differ only in the return type, where the wasm specific one is returning type of the element instead of `int`. * Include TrimmerRootDescriptor only on Apple mobile platforms * Update src/mono/mono/mini/mini-llvm.c --------- Co-authored-by: Radek Doulik Co-authored-by: Aleksey Kliger (λgeek) --- ...tem.Configuration.ConfigurationManager.Tests.csproj | 3 ++- .../tests/System.Data.Common.Tests.csproj | 3 ++- .../System.Diagnostics.FileVersionInfo.Tests.csproj | 3 ++- .../System.Linq/tests/System.Linq.Tests.csproj | 3 ++- .../System.Reflection.MetadataLoadContext.Tests.csproj | 2 +- .../tests/System.Resources.Extensions.Tests.csproj | 3 ++- .../tests/System.Runtime.Loader.Tests.csproj | 2 +- .../System.Globalization.Tests.csproj | 3 ++- ...stem.IO.FileSystem.DisabledFileLocking.Tests.csproj | 3 ++- .../System.IO.FileSystem.Tests.csproj | 3 ++- .../System.Security.Cryptography.Xml.Tests.csproj | 3 ++- .../System.Text.Json.Tests.csproj | 3 ++- src/mono/mono/mini/mini-llvm.c | 10 ++++++++-- 13 files changed, 30 insertions(+), 14 deletions(-) diff --git a/src/libraries/System.Configuration.ConfigurationManager/tests/System.Configuration.ConfigurationManager.Tests.csproj b/src/libraries/System.Configuration.ConfigurationManager/tests/System.Configuration.ConfigurationManager.Tests.csproj index 2a24b7ffaad07f..0a6b23dad7e658 100644 --- a/src/libraries/System.Configuration.ConfigurationManager/tests/System.Configuration.ConfigurationManager.Tests.csproj +++ b/src/libraries/System.Configuration.ConfigurationManager/tests/System.Configuration.ConfigurationManager.Tests.csproj @@ -97,7 +97,8 @@ - + + diff --git a/src/libraries/System.Data.Common/tests/System.Data.Common.Tests.csproj b/src/libraries/System.Data.Common/tests/System.Data.Common.Tests.csproj index ed37aab0c75388..ae85c66d7e8b5f 100644 --- a/src/libraries/System.Data.Common/tests/System.Data.Common.Tests.csproj +++ b/src/libraries/System.Data.Common/tests/System.Data.Common.Tests.csproj @@ -123,6 +123,7 @@ - + + diff --git a/src/libraries/System.Diagnostics.FileVersionInfo/tests/System.Diagnostics.FileVersionInfo.Tests/System.Diagnostics.FileVersionInfo.Tests.csproj b/src/libraries/System.Diagnostics.FileVersionInfo/tests/System.Diagnostics.FileVersionInfo.Tests/System.Diagnostics.FileVersionInfo.Tests.csproj index cdadf742e3d976..fa358a2a90893b 100644 --- a/src/libraries/System.Diagnostics.FileVersionInfo/tests/System.Diagnostics.FileVersionInfo.Tests/System.Diagnostics.FileVersionInfo.Tests.csproj +++ b/src/libraries/System.Diagnostics.FileVersionInfo/tests/System.Diagnostics.FileVersionInfo.Tests/System.Diagnostics.FileVersionInfo.Tests.csproj @@ -52,6 +52,7 @@ - + + diff --git a/src/libraries/System.Linq/tests/System.Linq.Tests.csproj b/src/libraries/System.Linq/tests/System.Linq.Tests.csproj index 33d584fe8f6a15..1e4692999a1743 100644 --- a/src/libraries/System.Linq/tests/System.Linq.Tests.csproj +++ b/src/libraries/System.Linq/tests/System.Linq.Tests.csproj @@ -5,7 +5,8 @@ - + + diff --git a/src/libraries/System.Reflection.MetadataLoadContext/tests/System.Reflection.MetadataLoadContext.Tests.csproj b/src/libraries/System.Reflection.MetadataLoadContext/tests/System.Reflection.MetadataLoadContext.Tests.csproj index 32518ce3efa431..4feacf3ede60ec 100644 --- a/src/libraries/System.Reflection.MetadataLoadContext/tests/System.Reflection.MetadataLoadContext.Tests.csproj +++ b/src/libraries/System.Reflection.MetadataLoadContext/tests/System.Reflection.MetadataLoadContext.Tests.csproj @@ -92,7 +92,7 @@ - + diff --git a/src/libraries/System.Resources.Extensions/tests/System.Resources.Extensions.Tests.csproj b/src/libraries/System.Resources.Extensions/tests/System.Resources.Extensions.Tests.csproj index a0533c343614c6..8a197d09368674 100644 --- a/src/libraries/System.Resources.Extensions/tests/System.Resources.Extensions.Tests.csproj +++ b/src/libraries/System.Resources.Extensions/tests/System.Resources.Extensions.Tests.csproj @@ -27,7 +27,8 @@ - + + + diff --git a/src/libraries/System.Runtime/tests/System.IO.FileSystem.Tests/DisabledFileLockingTests/System.IO.FileSystem.DisabledFileLocking.Tests.csproj b/src/libraries/System.Runtime/tests/System.IO.FileSystem.Tests/DisabledFileLockingTests/System.IO.FileSystem.DisabledFileLocking.Tests.csproj index b029dd3341a710..614de3d1ce979f 100644 --- a/src/libraries/System.Runtime/tests/System.IO.FileSystem.Tests/DisabledFileLockingTests/System.IO.FileSystem.DisabledFileLocking.Tests.csproj +++ b/src/libraries/System.Runtime/tests/System.IO.FileSystem.Tests/DisabledFileLockingTests/System.IO.FileSystem.DisabledFileLocking.Tests.csproj @@ -34,7 +34,8 @@ - + + diff --git a/src/libraries/System.Runtime/tests/System.IO.FileSystem.Tests/System.IO.FileSystem.Tests.csproj b/src/libraries/System.Runtime/tests/System.IO.FileSystem.Tests/System.IO.FileSystem.Tests.csproj index 0e4d3e3770cd61..b4f627b831f2e5 100644 --- a/src/libraries/System.Runtime/tests/System.IO.FileSystem.Tests/System.IO.FileSystem.Tests.csproj +++ b/src/libraries/System.Runtime/tests/System.IO.FileSystem.Tests/System.IO.FileSystem.Tests.csproj @@ -245,6 +245,7 @@ - + + diff --git a/src/libraries/System.Security.Cryptography.Xml/tests/System.Security.Cryptography.Xml.Tests.csproj b/src/libraries/System.Security.Cryptography.Xml/tests/System.Security.Cryptography.Xml.Tests.csproj index 858a44b23608f9..56458c07a5a0f7 100644 --- a/src/libraries/System.Security.Cryptography.Xml/tests/System.Security.Cryptography.Xml.Tests.csproj +++ b/src/libraries/System.Security.Cryptography.Xml/tests/System.Security.Cryptography.Xml.Tests.csproj @@ -75,6 +75,7 @@ - + + diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/System.Text.Json.Tests.csproj b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/System.Text.Json.Tests.csproj index 1e3c083791c653..9eb2e9a2e63d78 100644 --- a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/System.Text.Json.Tests.csproj +++ b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/System.Text.Json.Tests.csproj @@ -307,6 +307,7 @@ - + + diff --git a/src/mono/mono/mini/mini-llvm.c b/src/mono/mono/mini/mini-llvm.c index 63ffbf994657f0..07bbe7d4e0037a 100644 --- a/src/mono/mono/mini/mini-llvm.c +++ b/src/mono/mono/mini/mini-llvm.c @@ -6119,8 +6119,14 @@ process_bb (EmitContext *ctx, MonoBasicBlock *bb) gboolean src_in_reg = FALSE; gboolean is_simd = mini_class_is_simd (ctx->cfg, mono_class_from_mono_type_internal (sig->ret)); switch (linfo->ret.storage) { - case LLVMArgNormal: src_in_reg = TRUE; break; - case LLVMArgVtypeInReg: case LLVMArgVtypeAsScalar: src_in_reg = is_simd; break; + case LLVMArgNormal: + src_in_reg = TRUE; + break; + case LLVMArgVtypeInReg: + case LLVMArgVtypeAsScalar: + case LLVMArgWasmVtypeAsScalar: + src_in_reg = is_simd; + break; } if (src_in_reg && (!lhs || ctx->is_dead [ins->sreg1])) { /* From c0e3e61c9f75295c5b58fb0836a012d8635e77a4 Mon Sep 17 00:00:00 2001 From: Milos Kotlar Date: Thu, 25 Apr 2024 09:39:48 +0200 Subject: [PATCH 068/161] Add runtime test for static gsharedvt methods (#101489) --- .../JitBlue/Runtime_94467/Runtime_94467.cs | 44 +++++++++++++++++++ .../Runtime_94467/Runtime_94467.csproj | 8 ++++ 2 files changed, 52 insertions(+) create mode 100644 src/tests/JIT/Regression/JitBlue/Runtime_94467/Runtime_94467.cs create mode 100644 src/tests/JIT/Regression/JitBlue/Runtime_94467/Runtime_94467.csproj diff --git a/src/tests/JIT/Regression/JitBlue/Runtime_94467/Runtime_94467.cs b/src/tests/JIT/Regression/JitBlue/Runtime_94467/Runtime_94467.cs new file mode 100644 index 00000000000000..85aa6e62655d2f --- /dev/null +++ b/src/tests/JIT/Regression/JitBlue/Runtime_94467/Runtime_94467.cs @@ -0,0 +1,44 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using Xunit; + +public static class Runtime_94467 +{ + public interface ITypeChecker + { + static abstract bool Test(T value); + } + + public interface IHandler + { + bool Test(T value); + } + + public struct TypeChecker : ITypeChecker + { + public static bool Test(T value) => true; + } + + public class Handler : IHandler where TChecker : ITypeChecker + { + public bool Test(T value) => TChecker.Test(value); + } + + public static IHandler GetHandler() => new Handler(); + + [Fact] + public static int Test() + { + try { + var handler = GetHandler(); + if (handler.Test(true) && handler.Test(true)) + return 100; + else + return 101; + } catch (Exception) { + return -1; + } + } +} diff --git a/src/tests/JIT/Regression/JitBlue/Runtime_94467/Runtime_94467.csproj b/src/tests/JIT/Regression/JitBlue/Runtime_94467/Runtime_94467.csproj new file mode 100644 index 00000000000000..15edd99711a1a4 --- /dev/null +++ b/src/tests/JIT/Regression/JitBlue/Runtime_94467/Runtime_94467.csproj @@ -0,0 +1,8 @@ + + + True + + + + + \ No newline at end of file From 127844cf0d4c79e5bb02ced2faac3f44676afa8f Mon Sep 17 00:00:00 2001 From: Radek Zikmund <32671551+rzikm@users.noreply.github.com> Date: Thu, 25 Apr 2024 13:18:43 +0200 Subject: [PATCH 069/161] Fix data race leading to a deadlock when opening QuicStream (#101250) * Fix data race leading to a deadlock. * Remove unwanted change * Code review feedback * Fix hang * Add assert * Fix potential crash * Code review feedback --- .../System/Net/Quic/Internal/ThrowHelper.cs | 27 +++++++++++++++---- .../src/System/Net/Quic/QuicConnection.cs | 23 +++++++++++++--- .../src/System/Net/Quic/QuicStream.cs | 14 +++++++--- 3 files changed, 51 insertions(+), 13 deletions(-) diff --git a/src/libraries/System.Net.Quic/src/System/Net/Quic/Internal/ThrowHelper.cs b/src/libraries/System.Net.Quic/src/System/Net/Quic/Internal/ThrowHelper.cs index 114c39c49c1e5e..bb1cc7d25b7b3e 100644 --- a/src/libraries/System.Net.Quic/src/System/Net/Quic/Internal/ThrowHelper.cs +++ b/src/libraries/System.Net.Quic/src/System/Net/Quic/Internal/ThrowHelper.cs @@ -27,13 +27,27 @@ internal static QuicException GetOperationAbortedException(string? message = nul return new QuicException(QuicError.OperationAborted, null, message ?? SR.net_quic_operationaborted); } - internal static bool TryGetStreamExceptionForMsQuicStatus(int status, [NotNullWhen(true)] out Exception? exception) + internal static bool TryGetStreamExceptionForMsQuicStatus(int status, [NotNullWhen(true)] out Exception? exception, bool streamWasSuccessfullyStarted = true, string? message = null) { if (status == QUIC_STATUS_ABORTED) { - // If status == QUIC_STATUS_ABORTED, we will receive an event later, which will complete the task source. - exception = null; - return false; + // Connection has been closed by the peer (either at transport or application level), + if (streamWasSuccessfullyStarted) + { + // we will receive an event later, which will complete the stream with concrete + // information why the connection was aborted. + exception = null; + return false; + } + else + { + // we won't be receiving any event callback for shutdown on this stream, so we don't + // necessarily know which error to report. So we throw an exception which we can distinguish + // at the caller (ConnectionAborted normally has App error code) and throw the correct + // exception from there. + exception = new QuicException(QuicError.ConnectionAborted, null, ""); + return true; + } } else if (status == QUIC_STATUS_INVALID_STATE) { @@ -43,13 +57,16 @@ internal static bool TryGetStreamExceptionForMsQuicStatus(int status, [NotNullWh } else if (StatusFailed(status)) { - exception = GetExceptionForMsQuicStatus(status); + exception = GetExceptionForMsQuicStatus(status, message: message); return true; } exception = null; return false; } + // see TryGetStreamExceptionForMsQuicStatus for explanation + internal static bool IsConnectionAbortedWhenStartingStreamException(Exception ex) => ex is QuicException qe && qe.QuicError == QuicError.ConnectionAborted && qe.ApplicationErrorCode is null; + internal static Exception GetExceptionForMsQuicStatus(int status, long? errorCode = default, string? message = null) { Exception ex = GetExceptionInternal(status, errorCode, message); diff --git a/src/libraries/System.Net.Quic/src/System/Net/Quic/QuicConnection.cs b/src/libraries/System.Net.Quic/src/System/Net/Quic/QuicConnection.cs index e568eeb6f97b7a..f266acb265a138 100644 --- a/src/libraries/System.Net.Quic/src/System/Net/Quic/QuicConnection.cs +++ b/src/libraries/System.Net.Quic/src/System/Net/Quic/QuicConnection.cs @@ -108,6 +108,11 @@ static async ValueTask StartConnectAsync(QuicClientConnectionOpt /// private int _disposed; + /// + /// Completed when connection shutdown is initiated. + /// + private TaskCompletionSource _connectionCloseTcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); + private readonly ValueTaskSource _connectedTcs = new ValueTaskSource(); private readonly ResettableValueTaskSource _shutdownTcs = new ResettableValueTaskSource() { @@ -424,7 +429,7 @@ public async ValueTask OpenOutboundStreamAsync(QuicStreamType type, await stream.StartAsync(cancellationToken).ConfigureAwait(false); } - catch + catch (Exception ex) { if (stream is not null) { @@ -433,10 +438,16 @@ public async ValueTask OpenOutboundStreamAsync(QuicStreamType type, // Propagate ODE if disposed in the meantime. ObjectDisposedException.ThrowIf(_disposed == 1, this); + + // In case of an incoming race when the connection is closed by the peer just before we open the stream, + // we receive QUIC_STATUS_ABORTED from MsQuic, but we don't know how the connection was closed. We throw + // special exception and handle it here where we can determine the shutdown reason. + bool connectionAbortedByPeer = ThrowHelper.IsConnectionAbortedWhenStartingStreamException(ex); + // Propagate connection error if present. - if (_acceptQueue.Reader.Completion.IsFaulted) + if (_connectionCloseTcs.Task.IsFaulted || connectionAbortedByPeer) { - await _acceptQueue.Reader.Completion.ConfigureAwait(false); + await _connectionCloseTcs.Task.ConfigureAwait(false); } throw; } @@ -534,12 +545,15 @@ private unsafe int HandleEventShutdownInitiatedByTransport(ref SHUTDOWN_INITIATE { Exception exception = ExceptionDispatchInfo.SetCurrentStackTrace(ThrowHelper.GetExceptionForMsQuicStatus(data.Status, (long)data.ErrorCode)); _connectedTcs.TrySetException(exception); + _connectionCloseTcs.TrySetException(exception); _acceptQueue.Writer.TryComplete(exception); return QUIC_STATUS_SUCCESS; } private unsafe int HandleEventShutdownInitiatedByPeer(ref SHUTDOWN_INITIATED_BY_PEER_DATA data) { - _acceptQueue.Writer.TryComplete(ExceptionDispatchInfo.SetCurrentStackTrace(ThrowHelper.GetConnectionAbortedException((long)data.ErrorCode))); + Exception exception = ExceptionDispatchInfo.SetCurrentStackTrace(ThrowHelper.GetConnectionAbortedException((long)data.ErrorCode)); + _connectionCloseTcs.TrySetException(exception); + _acceptQueue.Writer.TryComplete(exception); return QUIC_STATUS_SUCCESS; } private unsafe int HandleEventShutdownComplete() @@ -548,6 +562,7 @@ private unsafe int HandleEventShutdownComplete() _tlsSecret?.WriteSecret(); Exception exception = ExceptionDispatchInfo.SetCurrentStackTrace(_disposed == 1 ? new ObjectDisposedException(GetType().FullName) : ThrowHelper.GetOperationAbortedException()); + _connectionCloseTcs.TrySetException(exception); _acceptQueue.Writer.TryComplete(exception); _connectedTcs.TrySetException(exception); _shutdownTokenSource.Cancel(); diff --git a/src/libraries/System.Net.Quic/src/System/Net/Quic/QuicStream.cs b/src/libraries/System.Net.Quic/src/System/Net/Quic/QuicStream.cs index 6af0f5c5c099f3..320ca9dbcda849 100644 --- a/src/libraries/System.Net.Quic/src/System/Net/Quic/QuicStream.cs +++ b/src/libraries/System.Net.Quic/src/System/Net/Quic/QuicStream.cs @@ -162,13 +162,18 @@ internal unsafe QuicStream(MsQuicContextSafeHandle connectionHandle, QuicStreamT try { QUIC_HANDLE* handle; - ThrowHelper.ThrowIfMsQuicError(MsQuicApi.Api.StreamOpen( + int status = MsQuicApi.Api.StreamOpen( connectionHandle, type == QuicStreamType.Unidirectional ? QUIC_STREAM_OPEN_FLAGS.UNIDIRECTIONAL : QUIC_STREAM_OPEN_FLAGS.NONE, &NativeCallback, (void*)GCHandle.ToIntPtr(context), - &handle), - "StreamOpen failed"); + &handle); + + if (ThrowHelper.TryGetStreamExceptionForMsQuicStatus(status, out Exception? ex, streamWasSuccessfullyStarted: false, message: "StreamOpen failed")) + { + throw ex; + } + _handle = new MsQuicContextSafeHandle(handle, context, SafeHandleType.Stream, connectionHandle); _handle.Disposable = _sendBuffers; } @@ -245,7 +250,8 @@ internal ValueTask StartAsync(CancellationToken cancellationToken = default) int status = MsQuicApi.Api.StreamStart( _handle, QUIC_STREAM_START_FLAGS.SHUTDOWN_ON_FAIL | QUIC_STREAM_START_FLAGS.INDICATE_PEER_ACCEPT); - if (ThrowHelper.TryGetStreamExceptionForMsQuicStatus(status, out Exception? exception)) + + if (ThrowHelper.TryGetStreamExceptionForMsQuicStatus(status, out Exception? exception, streamWasSuccessfullyStarted: false)) { _startedTcs.TrySetException(exception); } From d79bb01433401a144816a386c5411ac4c08b6187 Mon Sep 17 00:00:00 2001 From: Pavel Savara Date: Thu, 25 Apr 2024 14:57:14 +0200 Subject: [PATCH 070/161] [browser] enable CI testing with Firefox (#100697) --- .../templates/wasm-library-aot-tests.yml | 5 +- .../common/templates/wasm-library-tests.yml | 4 +- .../runtime-extra-platforms-wasm.yml | 3 +- eng/pipelines/runtime.yml | 3 + eng/testing/BrowserVersions.props | 4 +- eng/testing/WasmRunnerTemplate.cmd | 30 ++++++++-- eng/testing/WasmRunnerTemplate.sh | 17 +++++- eng/testing/tests.browser.targets | 9 +++ eng/testing/tests.wasi.targets | 7 +++ eng/testing/wasm-provisioning.targets | 59 +++++++++++-------- .../tests/System/Net/Configuration.Http.cs | 25 ++++++-- .../System/Net/Configuration.WebSockets.cs | 31 +++++++++- .../HttpClientHandlerTest.Authentication.cs | 2 +- .../HttpClientHandlerTest.RemoteServer.cs | 14 +++-- ...ttpClientHandlerTest.ServerCertificates.cs | 2 +- .../System/Net/Http/HttpClientHandlerTest.cs | 11 +++- .../tests/System/Net/Http/PostScenarioTest.cs | 2 +- .../System/Net/Http/ResponseStreamTest.cs | 13 ++-- .../HttpClientHandlerTest.Headers.cs | 5 ++ .../HttpClientHandlerTest.Http1.cs | 1 + .../FunctionalTests/HttpRequestMessageTest.cs | 1 + .../FunctionalTests/SocketsHttpHandlerTest.cs | 1 + .../tests/ClientWebSocketTestBase.cs | 9 +-- .../tests/ConnectTest.cs | 1 + .../tests/WebSocketCreateTest.cs | 2 +- .../DateTimeFormatInfoNativeCalendarName.cs | 8 +-- src/libraries/sendtohelix-browser.targets | 25 ++++---- src/libraries/sendtohelix-wasi.targets | 4 ++ src/libraries/sendtohelix-wasm.targets | 2 + .../runtime/hybrid-globalization/locales.ts | 12 ++-- src/mono/sample/Directory.Build.props | 18 ++++-- .../sample/wasm/DefaultBrowserSample.targets | 2 +- .../Wasm.Console.Node.Sample.csproj | 2 +- .../console-v8/Wasm.Console.V8.Sample.csproj | 2 +- 34 files changed, 232 insertions(+), 104 deletions(-) diff --git a/eng/pipelines/common/templates/wasm-library-aot-tests.yml b/eng/pipelines/common/templates/wasm-library-aot-tests.yml index 43b90a370450d1..cbafd9c6b35531 100644 --- a/eng/pipelines/common/templates/wasm-library-aot-tests.yml +++ b/eng/pipelines/common/templates/wasm-library-aot-tests.yml @@ -1,7 +1,7 @@ parameters: alwaysRun: false extraBuildArgs: '' - extraHelixArgs: '' + extraHelixArguments: '' isExtraPlatformsBuild: false isWasmOnlyBuild: false buildAOTOnHelix: true @@ -26,7 +26,7 @@ jobs: isExtraPlatformsBuild: ${{ parameters.isExtraPlatformsBuild }} isWasmOnlyBuild: ${{ parameters.isWasmOnlyBuild }} extraBuildArgs: /p:EnableAggressiveTrimming=true /p:BuildAOTTestsOnHelix=${{ parameters.buildAOTOnHelix }} /p:RunAOTCompilation=${{ parameters.runAOT }} ${{ parameters.extraBuildArgs }} - extraHelixArgs: /p:NeedsToBuildWasmAppsOnHelix=true ${{ parameters.extraHelixArgs }} + extraHelixArguments: /p:NeedsToBuildWasmAppsOnHelix=true ${{ parameters.extraHelixArguments }} alwaysRun: ${{ parameters.alwaysRun }} shouldRunSmokeOnly: ${{ parameters.shouldRunSmokeOnly }} shouldContinueOnError: ${{ parameters.shouldContinueOnError }} @@ -35,5 +35,6 @@ jobs: - WasmTestOnV8 - ${{ if eq(platform, 'browser_wasm_win') }}: - WasmTestOnChrome + - WasmTestOnFirefox - ${{ if or(eq(platform, 'wasi_wasm_win'), eq(platform, 'wasi_wasm')) }}: - WasmTestOnWasmtime diff --git a/eng/pipelines/common/templates/wasm-library-tests.yml b/eng/pipelines/common/templates/wasm-library-tests.yml index 4a1a5a79a30bfc..f015563fef00e3 100644 --- a/eng/pipelines/common/templates/wasm-library-tests.yml +++ b/eng/pipelines/common/templates/wasm-library-tests.yml @@ -1,7 +1,7 @@ parameters: alwaysRun: false extraBuildArgs: '' - extraHelixArgs: '' + extraHelixArguments: '' isExtraPlatformsBuild: false isWasmOnlyBuild: false nameSuffix: '' @@ -97,5 +97,5 @@ jobs: parameters: creator: dotnet-bot testRunNamePrefixSuffix: Mono_$(_BuildConfig) - extraHelixArguments: /p:BrowserHost=$(_hostedOs) $(_wasmRunSmokeTestsOnlyArg) ${{ parameters.extraHelixArgs }} + extraHelixArguments: /p:BrowserHost=$(_hostedOs) $(_wasmRunSmokeTestsOnlyArg) ${{ parameters.extraHelixArguments }} scenarios: ${{ parameters.scenarios }} diff --git a/eng/pipelines/extra-platforms/runtime-extra-platforms-wasm.yml b/eng/pipelines/extra-platforms/runtime-extra-platforms-wasm.yml index 2c947a048e0550..d31cad685995d2 100644 --- a/eng/pipelines/extra-platforms/runtime-extra-platforms-wasm.yml +++ b/eng/pipelines/extra-platforms/runtime-extra-platforms-wasm.yml @@ -199,6 +199,7 @@ jobs: scenarios: - WasmTestOnV8 - WasmTestOnChrome + - WasmTestOnFirefox - WasmTestOnNodeJS # Hybrid Globalization AOT tests @@ -321,4 +322,4 @@ jobs: isExtraPlatformsBuild: ${{ parameters.isExtraPlatformsBuild }} isWasmOnlyBuild: ${{ parameters.isWasmOnlyBuild }} scenarios: - - WasmTestOnV8 + - WasmTestOnWasmtime diff --git a/eng/pipelines/runtime.yml b/eng/pipelines/runtime.yml index 6bb44bd64fc242..32f99429ffd692 100644 --- a/eng/pipelines/runtime.yml +++ b/eng/pipelines/runtime.yml @@ -843,6 +843,7 @@ extends: scenarios: - WasmTestOnV8 - WasmTestOnChrome + - WasmTestOnFirefox - template: /eng/pipelines/common/templates/wasm-library-tests.yml parameters: @@ -861,10 +862,12 @@ extends: #- browser_wasm_win nameSuffix: _Threading extraBuildArgs: /p:WasmEnableThreads=true /p:AotHostArchitecture=x64 /p:AotHostOS=$(_hostedOS) + extraHelixArguments: /p:WasmEnableThreads=true alwaysRun: ${{ variables.isRollingBuild }} shouldRunSmokeOnly: onLibrariesAndIllinkChanges scenarios: - WasmTestOnChrome + - WasmTestOnFirefox #- WasmTestOnNodeJS - this is not supported yet, https://github.com/dotnet/runtime/issues/85592 # EAT Library tests - only run on linux diff --git a/eng/testing/BrowserVersions.props b/eng/testing/BrowserVersions.props index b1e85302a8ed3a..c66b61a6e44042 100644 --- a/eng/testing/BrowserVersions.props +++ b/eng/testing/BrowserVersions.props @@ -8,7 +8,9 @@ 1250580 https://storage.googleapis.com/chromium-browser-snapshots/Win_x64/1250586 12.3.219 - 124.0.2 + 125.0.1 0.34.0 + 125.0.1 + 0.34.0 diff --git a/eng/testing/WasmRunnerTemplate.cmd b/eng/testing/WasmRunnerTemplate.cmd index 0c7f3dc2195d26..e043ce7a34e9f5 100644 --- a/eng/testing/WasmRunnerTemplate.cmd +++ b/eng/testing/WasmRunnerTemplate.cmd @@ -30,7 +30,11 @@ if [%XHARNESS_COMMAND%] == [] ( if /I [%SCENARIO%]==[WasmTestOnChrome] ( set XHARNESS_COMMAND=test-browser ) else ( - set XHARNESS_COMMAND=test + if /I [%SCENARIO%]==[WasmTestOnFirefox] ( + set XHARNESS_COMMAND=test-browser + ) else ( + set XHARNESS_COMMAND=test + ) ) ) @@ -56,11 +60,25 @@ if /I [%XHARNESS_COMMAND%] == [test] ( ) ) ) else ( - if [%BROWSER_PATH%] == [] if not [%HELIX_CORRELATION_PAYLOAD%] == [] ( - set "BROWSER_PATH=--browser-path^=%HELIX_CORRELATION_PAYLOAD%\chrome-win\chrome.exe" - ) - if [%JS_ENGINE_ARGS%] == [] ( - set "JS_ENGINE_ARGS=--browser-arg^=--js-flags^=--stack-trace-limit^=1000" + if /I [%SCENARIO%] == [WasmTestOnChrome] ( + if [%BROWSER_PATH%] == [] if not [%HELIX_CORRELATION_PAYLOAD%] == [] ( + set "BROWSER_PATH=--browser-path^=%HELIX_CORRELATION_PAYLOAD%\chrome-win\chrome.exe" + ) + if [%JS_ENGINE_ARGS%] == [] ( + set "JS_ENGINE_ARGS=--browser-arg^=--js-flags^=--stack-trace-limit^=1000" + ) + ) else ( + if /I [%SCENARIO%] == [WasmTestOnFirefox] ( + if [%BROWSER_PATH%] == [] if not [%HELIX_CORRELATION_PAYLOAD%] == [] ( + set "BROWSER_PATH=--browser-path^=%HELIX_CORRELATION_PAYLOAD%\firefox\firefox.exe" + ) + if [%JS_ENGINE%] == [] ( + set "JS_ENGINE=--browser^=Firefox" + ) + if [%JS_ENGINE_ARGS%] == [] ( + set "JS_ENGINE_ARGS=--browser-arg^=-private-window" + ) + ) ) ) diff --git a/eng/testing/WasmRunnerTemplate.sh b/eng/testing/WasmRunnerTemplate.sh index bd7f1faadf3556..6cf4dc11d4beae 100644 --- a/eng/testing/WasmRunnerTemplate.sh +++ b/eng/testing/WasmRunnerTemplate.sh @@ -26,7 +26,9 @@ else fi if [[ -z "$XHARNESS_COMMAND" ]]; then - if [[ "$SCENARIO" == "WasmTestOnChrome" || "$SCENARIO" == "wasmtestonchrome" ]]; then + if [[ "$SCENARIO" == "WasmTestOnFirefox" || "$SCENARIO" == "wasmtestonfirefox" ]]; then + XHARNESS_COMMAND="test-browser" + elif [[ "$SCENARIO" == "WasmTestOnChrome" || "$SCENARIO" == "wasmtestonchrome" ]]; then XHARNESS_COMMAND="test-browser" else XHARNESS_COMMAND="test" @@ -59,8 +61,17 @@ if [[ "$XHARNESS_COMMAND" == "test" ]]; then fi fi else - if [[ -z "$JS_ENGINE_ARGS" ]]; then - JS_ENGINE_ARGS="--browser-arg=--js-flags=--stack-trace-limit=1000" + if [[ "$SCENARIO" == "WasmTestOnChrome" || "$SCENARIO" == "wasmtestonchrome" ]]; then + if [[ -z "$JS_ENGINE_ARGS" ]]; then + JS_ENGINE_ARGS="--browser-arg=--js-flags=--stack-trace-limit=1000" + fi + elif [[ "$SCENARIO" == "WasmTestOnFirefox" || "$SCENARIO" == "wasmtestonfirefox" ]]; then + if [[ -z "$JS_ENGINE" ]]; then + JS_ENGINE="--browser=Firefox" + fi + if [[ -z "$JS_ENGINE_ARGS" ]]; then + JS_ENGINE_ARGS="--browser-arg=-private-window" + fi fi fi diff --git a/eng/testing/tests.browser.targets b/eng/testing/tests.browser.targets index ccfc96f5211cd1..26a2086c850b5c 100644 --- a/eng/testing/tests.browser.targets +++ b/eng/testing/tests.browser.targets @@ -250,9 +250,18 @@ <_NodeNpmModuleStringTrimmed Include="@(_NodeNpmModuleString->Trim(':'))" /> + WasmTestOnV8 @(_NodeNpmModuleStringTrimmed, ',') + + diff --git a/eng/testing/tests.wasi.targets b/eng/testing/tests.wasi.targets index d147fea218fe4a..989e934dd8412a 100644 --- a/eng/testing/tests.wasi.targets +++ b/eng/testing/tests.wasi.targets @@ -147,6 +147,13 @@ + + WasmTestOnWasmtime + + + diff --git a/eng/testing/wasm-provisioning.targets b/eng/testing/wasm-provisioning.targets index 47076a23770dd3..540fcfb035fa21 100644 --- a/eng/testing/wasm-provisioning.targets +++ b/eng/testing/wasm-provisioning.targets @@ -21,18 +21,30 @@ - - https://ftp.mozilla.org/pub/firefox/releases/$(linux_FirefoxRevision)/linux-x86_64/en-US/firefox-$(linux_FirefoxRevision).tar.bz2 - https://github.com/mozilla/geckodriver/releases/download/v$(linux_GeckoDriverRevision)/geckodriver-v$(linux_GeckoDriverRevision)-linux64.tar.gz - firefox - geckodriver + $(ArtifactsBinDir)firefox\ firefox geckodriver $(ArtifactsBinDir)geckodriver\ + + + https://ftp.mozilla.org/pub/firefox/releases/$(linux_FirefoxRevision)/linux-x86_64/en-US/firefox-$(linux_FirefoxRevision).tar.bz2 + https://github.com/mozilla/geckodriver/releases/download/v$(linux_GeckoDriverRevision)/geckodriver-v$(linux_GeckoDriverRevision)-linux64.tar.gz + firefox + geckodriver $([MSBuild]::NormalizePath($(FirefoxDir), '.install-firefox-$(linux_FirefoxRevision).stamp')) $([MSBuild]::NormalizePath($(GeckoDriverDir), '.install-geckodriver-$(linux_GeckoDriverRevision).stamp')) + $([MSBuild]::NormalizePath($(FirefoxDir), $(FirefoxDirName), $(FirefoxBinaryName))) + $([MSBuild]::NormalizePath($(GeckoDriverDir), $(GeckoDriverDirName), $(GeckoDriverBinaryName))) + + + https://ftp.mozilla.org/pub/firefox/releases/$(win_FirefoxRevision)/win64/en-US/Firefox%20Setup%20$(win_FirefoxRevision).exe + https://github.com/mozilla/geckodriver/releases/download/v$(win_GeckoDriverRevision)/geckodriver-v$(win_GeckoDriverRevision)-win64.zip + firefox.exe + geckodriver.exe + $([MSBuild]::NormalizePath($(FirefoxDir), '.install-firefox-$(win_FirefoxRevision).stamp')) + $([MSBuild]::NormalizePath($(GeckoDriverDir), '.install-geckodriver-$(win_GeckoDriverRevision).stamp')) $([MSBuild]::NormalizePath($(FirefoxDir), $(FirefoxDirName), $(FirefoxBinaryName))) $([MSBuild]::NormalizePath($(GeckoDriverDir), $(GeckoDriverDirName), $(GeckoDriverBinaryName))) @@ -183,7 +195,7 @@ export __SCRIPT_DIR=%24( cd -- "%24( dirname -- "%24{BASH_SOURCE[0]}" )" &> + Condition="!Exists($(FirefoxStampFile)) and '$(InstallFirefoxForTests)' == 'true'"> <_StampFile Include="$(_BrowserStampDir).install-firefox*.stamp" /> @@ -197,24 +209,22 @@ export __SCRIPT_DIR=%24( cd -- "%24( dirname -- "%24{BASH_SOURCE[0]}" )" &> - - - - - <_FirefoxBinaryPath>$([MSBuild]::NormalizePath($(FirefoxDir), $(FirefoxBinaryName))) - + + + + - + - + + Condition="!Exists($(GeckoDriverStampFile)) and '$(InstallFirefoxForTests)' == 'true'"> <_StampFile Include="$(_BrowserStampDir).install-geckodriver*.stamp" /> @@ -228,18 +238,15 @@ export __SCRIPT_DIR=%24( cd -- "%24( dirname -- "%24{BASH_SOURCE[0]}" )" &> - - - - - - <_GeckoDriverBinaryPath>$([MSBuild]::NormalizePath($(GeckoDriverDir), $(GeckoDriverBinaryName))) - + + + + - + - + diff --git a/src/libraries/Common/tests/System/Net/Configuration.Http.cs b/src/libraries/Common/tests/System/Net/Configuration.Http.cs index ae1481c56061c7..460b7893cc635d 100644 --- a/src/libraries/Common/tests/System/Net/Configuration.Http.cs +++ b/src/libraries/Common/tests/System/Net/Configuration.Http.cs @@ -58,12 +58,19 @@ public static partial class Http public static readonly Uri RemoteEchoServer = new Uri("http://" + Host + "/" + EchoHandler); public static readonly Uri SecureRemoteEchoServer = new Uri("https://" + SecureHost + "/" + EchoHandler); public static readonly Uri Http2RemoteEchoServer = new Uri("https://" + Http2Host + "/" + EchoHandler); - public static readonly Uri[] EchoServerList = new Uri[] { RemoteEchoServer, SecureRemoteEchoServer, Http2RemoteEchoServer }; + public static Uri[] GetEchoServerList() + { + if (PlatformDetection.IsFirefox) + { + // https://github.com/dotnet/runtime/issues/101115 + return [RemoteEchoServer]; + } + return [RemoteEchoServer, SecureRemoteEchoServer, Http2RemoteEchoServer]; + } public static readonly Uri RemoteVerifyUploadServer = new Uri("http://" + Host + "/" + VerifyUploadHandler); public static readonly Uri SecureRemoteVerifyUploadServer = new Uri("https://" + SecureHost + "/" + VerifyUploadHandler); public static readonly Uri Http2RemoteVerifyUploadServer = new Uri("https://" + Http2Host + "/" + VerifyUploadHandler); - public static readonly Uri[] VerifyUploadServerList = new Uri[] { RemoteVerifyUploadServer, SecureRemoteVerifyUploadServer, Http2RemoteVerifyUploadServer }; public static readonly Uri RemoteEmptyContentServer = new Uri("http://" + Host + "/" + EmptyContentHandler); public static readonly Uri RemoteDeflateServer = new Uri("http://" + Host + "/" + DeflateHandler); @@ -72,7 +79,7 @@ public static partial class Http public static readonly Uri Http2RemoteGZipServer = new Uri("https://" + Http2Host + "/" + GZipHandler); public static Uri RemoteLoopServer => new Uri("ws://" + RemoteLoopHost + "/" + RemoteLoopHandler); - public static readonly object[][] EchoServers = EchoServerList.Select(x => new object[] { x }).ToArray(); + public static readonly object[][] EchoServers = GetEchoServerList().Select(x => new object[] { x }).ToArray(); public static readonly object[][] VerifyUploadServers = { new object[] { RemoteVerifyUploadServer }, new object[] { SecureRemoteVerifyUploadServer }, new object[] { Http2RemoteVerifyUploadServer } }; public static readonly object[][] CompressedServers = { new object[] { RemoteDeflateServer }, new object[] { RemoteGZipServer }, new object[] { Http2RemoteDeflateServer }, new object[] { Http2RemoteGZipServer } }; @@ -83,9 +90,17 @@ public static partial class Http public static readonly RemoteServer RemoteSecureHttp11Server = new RemoteServer(new Uri("https://" + SecureHost + "/"), HttpVersion.Version11); public static readonly RemoteServer RemoteHttp2Server = new RemoteServer(new Uri("https://" + Http2Host + "/"), new Version(2, 0)); - public static readonly IEnumerable RemoteServers = new RemoteServer[] { RemoteHttp11Server, RemoteSecureHttp11Server, RemoteHttp2Server }; + public static IEnumerable GetRemoteServers() + { + if (PlatformDetection.IsFirefox) + { + // https://github.com/dotnet/runtime/issues/101115 + return new RemoteServer[] { RemoteHttp11Server }; + } + return new RemoteServer[] { RemoteHttp11Server, RemoteSecureHttp11Server, RemoteHttp2Server }; + } - public static readonly IEnumerable RemoteServersMemberData = RemoteServers.Select(s => new object[] { s }); + public static readonly IEnumerable RemoteServersMemberData = GetRemoteServers().Select(s => new object[] { s }); public sealed class RemoteServer { diff --git a/src/libraries/Common/tests/System/Net/Configuration.WebSockets.cs b/src/libraries/Common/tests/System/Net/Configuration.WebSockets.cs index a24512ce3b4a58..c5686be67b4ef9 100644 --- a/src/libraries/Common/tests/System/Net/Configuration.WebSockets.cs +++ b/src/libraries/Common/tests/System/Net/Configuration.WebSockets.cs @@ -22,8 +22,35 @@ public static partial class WebSockets public static readonly Uri RemoteEchoHeadersServer = new Uri("ws://" + Host + "/" + EchoHeadersHandler); public static readonly Uri SecureRemoteEchoHeadersServer = new Uri("wss://" + SecureHost + "/" + EchoHeadersHandler); - public static readonly object[][] EchoServers = { new object[] { RemoteEchoServer }, new object[] { SecureRemoteEchoServer } }; - public static readonly object[][] EchoHeadersServers = { new object[] { RemoteEchoHeadersServer }, new object[] { SecureRemoteEchoHeadersServer } }; + public static object[][] GetEchoServers() + { + if (PlatformDetection.IsFirefox) + { + // https://github.com/dotnet/runtime/issues/101115 + return new object[][] { + new object[] { RemoteEchoServer }, + }; + } + return new object[][] { + new object[] { RemoteEchoServer }, + new object[] { SecureRemoteEchoServer }, + }; + } + + public static object[][] GetEchoHeadersServers() + { + if (PlatformDetection.IsFirefox) + { + // https://github.com/dotnet/runtime/issues/101115 + return new object[][] { + new object[] { RemoteEchoHeadersServer }, + }; + } + return new object[][] { + new object[] { RemoteEchoHeadersServer }, + new object[] { SecureRemoteEchoHeadersServer }, + }; + } } } } diff --git a/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.Authentication.cs b/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.Authentication.cs index b19c02b52ebc01..430cfeb2d47295 100644 --- a/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.Authentication.cs +++ b/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.Authentication.cs @@ -546,7 +546,7 @@ public static IEnumerable ServerUsesWindowsAuthentication_MemberData() public static IEnumerable EchoServersData() { - foreach (Uri serverUri in Configuration.Http.EchoServerList) + foreach (Uri serverUri in Configuration.Http.GetEchoServerList()) { yield return new object[] { serverUri }; } diff --git a/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.RemoteServer.cs b/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.RemoteServer.cs index a264482a5549be..dd9db9bbe1f087 100644 --- a/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.RemoteServer.cs +++ b/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.RemoteServer.cs @@ -47,7 +47,7 @@ private static IEnumerable GetMethods(params string[] methods) { foreach (string method in methods) { - foreach (Uri serverUri in Configuration.Http.EchoServerList) + foreach (Uri serverUri in Configuration.Http.GetEchoServerList()) { yield return new object[] { method, serverUri }; } @@ -164,6 +164,7 @@ public async Task GetAsync_ServerNeedsAuthAndSetCredential_StatusCodeOK(Configur [OuterLoop("Uses external servers", typeof(PlatformDetection), nameof(PlatformDetection.LocalEchoServerIsNotAvailable))] [Theory, MemberData(nameof(RemoteServersMemberData))] + [ActiveIssue("https://github.com/dotnet/runtime/issues/101115", typeof(PlatformDetection), nameof(PlatformDetection.IsFirefox))] public async Task GetAsync_ServerNeedsAuthAndNoCredential_StatusCodeUnauthorized(Configuration.Http.RemoteServer remoteServer) { using (HttpClient client = CreateHttpClientForRemoteServer(remoteServer)) @@ -275,7 +276,7 @@ public static IEnumerable RemoteServersHeaderValuesAndUris() public static IEnumerable<(Configuration.Http.RemoteServer remoteServer, Uri uri)> RemoteServersAndHeaderEchoUris() { - foreach (Configuration.Http.RemoteServer remoteServer in Configuration.Http.RemoteServers) + foreach (Configuration.Http.RemoteServer remoteServer in Configuration.Http.GetRemoteServers()) { yield return (remoteServer, remoteServer.EchoUri); yield return (remoteServer, remoteServer.RedirectUriForDestinationUri( @@ -464,7 +465,7 @@ public static IEnumerable VerifyUploadServersStreamsAndExpectedData { get { - foreach (Configuration.Http.RemoteServer remoteServer in Configuration.Http.RemoteServers) // target server + foreach (Configuration.Http.RemoteServer remoteServer in Configuration.Http.GetRemoteServers()) // target server foreach (bool syncCopy in BoolValues) // force the content copy to happen via Read/Write or ReadAsync/WriteAsync { byte[] data = new byte[1234]; @@ -868,7 +869,7 @@ public async Task SendAsync_SendRequestUsingNoBodyMethodToEchoServerWithContent_ public static IEnumerable SendAsync_SendSameRequestMultipleTimesDirectlyOnHandler_Success_MemberData() { - foreach (var server in Configuration.Http.RemoteServers) + foreach (var server in Configuration.Http.GetRemoteServers()) { yield return new object[] { server, "12345678910", 0 }; yield return new object[] { server, "12345678910", 5 }; @@ -909,7 +910,7 @@ public async Task SendAsync_SendSameRequestMultipleTimesDirectlyOnHandler_Succes public static IEnumerable RemoteServersAndRedirectStatusCodes() { - foreach (Configuration.Http.RemoteServer remoteServer in Configuration.Http.RemoteServers) + foreach (Configuration.Http.RemoteServer remoteServer in Configuration.Http.GetRemoteServers()) { yield return new object[] { remoteServer, 300 }; yield return new object[] { remoteServer, 301 }; @@ -1228,7 +1229,7 @@ public async Task DefaultHeaders_SetCredentials_ClearedOnRedirect(Configuration. public static IEnumerable RemoteServersAndCompressionUris() { - foreach (Configuration.Http.RemoteServer remoteServer in Configuration.Http.RemoteServers) + foreach (Configuration.Http.RemoteServer remoteServer in Configuration.Http.GetRemoteServers()) { yield return new object[] { remoteServer, remoteServer.GZipUri }; @@ -1329,6 +1330,7 @@ public async Task GetAsync_SetAutomaticDecompression_HeadersRemoved(Configuratio [OuterLoop("Uses external servers", typeof(PlatformDetection), nameof(PlatformDetection.LocalEchoServerIsNotAvailable))] [Theory] [MemberData(nameof(Http2Servers))] + [ActiveIssue("https://github.com/dotnet/runtime/issues/101115", typeof(PlatformDetection), nameof(PlatformDetection.IsFirefox))] public async Task SendAsync_RequestVersion20_ResponseVersion20IfHttp2Supported(Uri server) { // Sync API supported only up to HTTP/1.1 diff --git a/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.ServerCertificates.cs b/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.ServerCertificates.cs index eca2101b78edbb..236af85b26035d 100644 --- a/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.ServerCertificates.cs +++ b/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.ServerCertificates.cs @@ -116,7 +116,7 @@ public async Task UseCallback_NotSecureConnection_CallbackNotCalled() public static IEnumerable UseCallback_ValidCertificate_ExpectedValuesDuringCallback_Urls() { - foreach (Configuration.Http.RemoteServer remoteServer in Configuration.Http.RemoteServers) + foreach (Configuration.Http.RemoteServer remoteServer in Configuration.Http.GetRemoteServers()) { if (remoteServer.IsSecure) { diff --git a/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.cs b/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.cs index 0e6faffa6d1622..31d8d9f154fc4f 100644 --- a/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.cs +++ b/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.cs @@ -412,6 +412,7 @@ await LoopbackServer.CreateClientAndServerAsync(async uri => [Fact] [ActiveIssue("https://github.com/dotnet/runtime/issues/86317", typeof(PlatformDetection), nameof(PlatformDetection.IsNodeJS))] + [ActiveIssue("https://github.com/dotnet/runtime/issues/101115", typeof(PlatformDetection), nameof(PlatformDetection.IsFirefox))] public async Task PostAsync_ManyDifferentRequestHeaders_SentCorrectly() { if (IsWinHttpHandler && UseVersion >= HttpVersion20.Value) @@ -826,6 +827,7 @@ await TestHelper.WhenAllCompletedOrAnyFailed( [InlineData("7gibberish")] // valid size then gibberish [InlineData("7\v\f")] // unacceptable whitespace [ActiveIssue("https://github.com/dotnet/runtime/issues/86317", typeof(PlatformDetection), nameof(PlatformDetection.IsNodeJS))] + [ActiveIssue("https://github.com/dotnet/runtime/issues/101115", typeof(PlatformDetection), nameof(PlatformDetection.IsFirefox))] public async Task GetAsync_InvalidChunkSize_ThrowsHttpRequestException(string chunkSize) { if (UseVersion != HttpVersion.Version11) @@ -859,6 +861,7 @@ await LoopbackServer.CreateServerAsync(async (server, url) => [Fact] [ActiveIssue("https://github.com/dotnet/runtime/issues/86317", typeof(PlatformDetection), nameof(PlatformDetection.IsNodeJS))] + [ActiveIssue("https://github.com/dotnet/runtime/issues/101115", typeof(PlatformDetection), nameof(PlatformDetection.IsFirefox))] public async Task GetAsync_InvalidChunkTerminator_ThrowsHttpRequestException() { if (UseVersion != HttpVersion.Version11) @@ -888,6 +891,7 @@ await LoopbackServer.CreateClientAndServerAsync(async url => [Fact] [ActiveIssue("https://github.com/dotnet/runtime/issues/86317", typeof(PlatformDetection), nameof(PlatformDetection.IsNodeJS))] + [ActiveIssue("https://github.com/dotnet/runtime/issues/101115", typeof(PlatformDetection), nameof(PlatformDetection.IsFirefox))] public async Task GetAsync_InfiniteChunkSize_ThrowsHttpRequestException() { if (UseVersion != HttpVersion.Version11) @@ -1011,9 +1015,9 @@ public async Task ReadAsStreamAsync_HandlerProducesWellBehavedResponseStream(boo return; } - if (enableWasmStreaming && !PlatformDetection.IsBrowser) + if (enableWasmStreaming && !PlatformDetection.IsChromium) { - // enableWasmStreaming makes only sense on Browser platform + // enableWasmStreaming makes only sense on Chrome return; } @@ -1331,7 +1335,7 @@ await LoopbackServerFactory.CreateClientAndServerAsync(async uri => server => server.AcceptConnectionSendResponseAndCloseAsync()); } - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsBrowser))] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsChromium))] [ActiveIssue("https://github.com/dotnet/runtime/issues/65429", typeof(PlatformDetection), nameof(PlatformDetection.IsNodeJS))] public async Task ReadAsStreamAsync_StreamingCancellation() { @@ -1425,6 +1429,7 @@ await server.AcceptConnectionAsync(async connection => } [Fact] + [ActiveIssue("https://github.com/dotnet/runtime/issues/101115", typeof(PlatformDetection), nameof(PlatformDetection.IsFirefox))] public async Task Dispose_DisposingHandlerCancelsActiveOperationsWithoutResponses() { if (IsWinHttpHandler && UseVersion >= HttpVersion20.Value) diff --git a/src/libraries/Common/tests/System/Net/Http/PostScenarioTest.cs b/src/libraries/Common/tests/System/Net/Http/PostScenarioTest.cs index 488f00639cb0ad..6f465ff0e998c5 100644 --- a/src/libraries/Common/tests/System/Net/Http/PostScenarioTest.cs +++ b/src/libraries/Common/tests/System/Net/Http/PostScenarioTest.cs @@ -135,7 +135,7 @@ public async Task PostUsingNoSpecifiedSemantics_UsesChunkedSemantics(Configurati public static IEnumerable RemoteServersAndLargeContentSizes() { - foreach (Configuration.Http.RemoteServer remoteServer in Configuration.Http.RemoteServers) + foreach (Configuration.Http.RemoteServer remoteServer in Configuration.Http.GetRemoteServers()) { yield return new object[] { remoteServer, 5 * 1024 }; yield return new object[] { remoteServer, 63 * 1024 }; diff --git a/src/libraries/Common/tests/System/Net/Http/ResponseStreamTest.cs b/src/libraries/Common/tests/System/Net/Http/ResponseStreamTest.cs index e38204ffc031e3..aaa4b9c9b1c3a8 100644 --- a/src/libraries/Common/tests/System/Net/Http/ResponseStreamTest.cs +++ b/src/libraries/Common/tests/System/Net/Http/ResponseStreamTest.cs @@ -21,7 +21,7 @@ public ResponseStreamTest(ITestOutputHelper output) : base(output) { } public static IEnumerable RemoteServersAndReadModes() { - foreach (Configuration.Http.RemoteServer remoteServer in Configuration.Http.RemoteServers) + foreach (Configuration.Http.RemoteServer remoteServer in Configuration.Http.GetRemoteServers()) { for (int i = 0; i < 8; i++) { @@ -230,7 +230,7 @@ await client.GetAsync(remoteServer.EchoUri, HttpCompletionOption.ResponseHeaders #if NETCOREAPP - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsBrowser))] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsChromium))] public async Task BrowserHttpHandler_Streaming() { var WebAssemblyEnableStreamingRequestKey = new HttpRequestOptionsKey("WebAssemblyEnableStreamingRequest"); @@ -287,7 +287,7 @@ public async Task BrowserHttpHandler_Streaming() } [OuterLoop] - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsBrowser))] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsChromium))] public async Task BrowserHttpHandler_StreamingRequest() { var WebAssemblyEnableStreamingRequestKey = new HttpRequestOptionsKey("WebAssemblyEnableStreamingRequest"); @@ -330,7 +330,7 @@ public async Task BrowserHttpHandler_StreamingRequest() // Duplicate of PostAsync_ThrowFromContentCopy_RequestFails using remote server [OuterLoop] - [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsBrowser))] + [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsChromium))] [InlineData(false)] [InlineData(true)] public async Task BrowserHttpHandler_StreamingRequest_ThrowFromContentCopy_RequestFails(bool syncFailure) @@ -368,7 +368,7 @@ public static TheoryData CancelRequestReadFunctions }; [OuterLoop] - [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsBrowser))] + [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsChromium))] [MemberData(nameof(CancelRequestReadFunctions))] public async Task BrowserHttpHandler_StreamingRequest_CancelRequest(bool cancelAsync, Func> readFunc) { @@ -438,7 +438,7 @@ public async Task BrowserHttpHandler_StreamingRequest_Http1Fails() } [OuterLoop] - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsBrowser))] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsChromium))] public async Task BrowserHttpHandler_StreamingResponse() { var WebAssemblyEnableStreamingResponseKey = new HttpRequestOptionsKey("WebAssemblyEnableStreamingResponse"); @@ -477,6 +477,7 @@ public async Task BrowserHttpHandler_StreamingResponse() [InlineData(TransferType.ContentLength, TransferError.ContentLengthTooLarge)] [InlineData(TransferType.Chunked, TransferError.MissingChunkTerminator)] [InlineData(TransferType.Chunked, TransferError.ChunkSizeTooLarge)] + [ActiveIssue("https://github.com/dotnet/runtime/issues/101115", typeof(PlatformDetection), nameof(PlatformDetection.IsFirefox))] public async Task ReadAsStreamAsync_InvalidServerResponse_ThrowsIOException( TransferType transferType, TransferError transferError) diff --git a/src/libraries/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.Headers.cs b/src/libraries/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.Headers.cs index 4807d9de7842cd..cbd74f8188a20f 100644 --- a/src/libraries/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.Headers.cs +++ b/src/libraries/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.Headers.cs @@ -26,6 +26,7 @@ public HttpClientHandlerTest_Headers(ITestOutputHelper output) : base(output) { private sealed class DerivedHttpHeaders : HttpHeaders { } [Fact] + [ActiveIssue("https://github.com/dotnet/runtime/issues/101115", typeof(PlatformDetection), nameof(PlatformDetection.IsFirefox))] public async Task SendAsync_RequestWithSimpleHeader_ResponseReferencesUnmodifiedRequestHeaders() { const string HeaderKey = "some-header-123", HeaderValue = "this is the expected header value"; @@ -73,6 +74,7 @@ await LoopbackServerFactory.CreateClientAndServerAsync(async uri => } [Fact] + [ActiveIssue("https://github.com/dotnet/runtime/issues/101115", typeof(PlatformDetection), nameof(PlatformDetection.IsFirefox))] public async Task SendAsync_LargeHeaders_CorrectlyWritten() { if (UseVersion == HttpVersion.Version30) @@ -108,6 +110,7 @@ await LoopbackServerFactory.CreateClientAndServerAsync(async uri => } [Fact] + [ActiveIssue("https://github.com/dotnet/runtime/issues/101115", typeof(PlatformDetection), nameof(PlatformDetection.IsFirefox))] public async Task SendAsync_DefaultHeaders_CorrectlyWritten() { const string Version = "2017-04-17"; @@ -169,6 +172,7 @@ await LoopbackServerFactory.CreateClientAndServerAsync(async uri => [InlineData("Accept-CharSet", "text/plain, text/json", false)] // invalid format for header but added with TryAddWithoutValidation [InlineData("Content-Location", "", false)] // invalid format for header but added with TryAddWithoutValidation [InlineData("Max-Forwards", "NotAnInteger", false)] // invalid format for header but added with TryAddWithoutValidation + [ActiveIssue("https://github.com/dotnet/runtime/issues/101115", typeof(PlatformDetection), nameof(PlatformDetection.IsFirefox))] public async Task SendAsync_SpecialHeaderKeyOrValue_Success(string key, string value, bool parsable) { if (PlatformDetection.IsBrowser && (key == "Content-Location" || key == "Date" || key == "Accept-CharSet")) @@ -356,6 +360,7 @@ await LoopbackServerFactory.CreateClientAndServerAsync(async uri => [Theory] [InlineData(false)] [InlineData(true)] + [ActiveIssue("https://github.com/dotnet/runtime/issues/101115", typeof(PlatformDetection), nameof(PlatformDetection.IsFirefox))] public async Task SendAsync_GetWithValidHostHeader_Success(bool withPort) { if (UseVersion == HttpVersion.Version30) diff --git a/src/libraries/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.Http1.cs b/src/libraries/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.Http1.cs index b3949e548e7ccc..b57e3812784599 100644 --- a/src/libraries/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.Http1.cs +++ b/src/libraries/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.Http1.cs @@ -17,6 +17,7 @@ public class HttpClientHandlerTest_Http1 : HttpClientHandlerTestBase public HttpClientHandlerTest_Http1(ITestOutputHelper output) : base(output) { } [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotNodeJS))] + [ActiveIssue("https://github.com/dotnet/runtime/issues/101115", typeof(PlatformDetection), nameof(PlatformDetection.IsFirefox))] public async Task SendAsync_HostHeader_First() { // RFC 7230 3.2.2. Field Order diff --git a/src/libraries/System.Net.Http/tests/FunctionalTests/HttpRequestMessageTest.cs b/src/libraries/System.Net.Http/tests/FunctionalTests/HttpRequestMessageTest.cs index 0dd1a485894d6b..d62566f1dd1b4a 100644 --- a/src/libraries/System.Net.Http/tests/FunctionalTests/HttpRequestMessageTest.cs +++ b/src/libraries/System.Net.Http/tests/FunctionalTests/HttpRequestMessageTest.cs @@ -239,6 +239,7 @@ public void ToString_DefaultAndNonDefaultInstance_DumpAllFields() [InlineData("OPTIONS")] [InlineData("HEAD")] [ActiveIssue("https://github.com/dotnet/runtime/issues/86317", typeof(PlatformDetection), nameof(PlatformDetection.IsNodeJS))] + [ActiveIssue("https://github.com/dotnet/runtime/issues/101115", typeof(PlatformDetection), nameof(PlatformDetection.IsFirefox))] public async Task HttpRequest_BodylessMethod_NoContentLength(string method) { using (HttpClient client = CreateHttpClient()) diff --git a/src/libraries/System.Net.Http/tests/FunctionalTests/SocketsHttpHandlerTest.cs b/src/libraries/System.Net.Http/tests/FunctionalTests/SocketsHttpHandlerTest.cs index c0eda6ab1a57ed..67604ca426e798 100644 --- a/src/libraries/System.Net.Http/tests/FunctionalTests/SocketsHttpHandlerTest.cs +++ b/src/libraries/System.Net.Http/tests/FunctionalTests/SocketsHttpHandlerTest.cs @@ -3994,6 +3994,7 @@ public SocketsHttpHandlerTest_HttpClientHandlerTest_Headers_Http11(ITestOutputHe [InlineData("foo", "\tbar\t")] [InlineData("foo", "\t bar \t")] [InlineData("foo ", " \t bar \r\n ")] + [ActiveIssue("https://github.com/dotnet/runtime/issues/101115", typeof(PlatformDetection), nameof(PlatformDetection.IsFirefox))] public async Task ResponseHeaders_ExtraWhitespace_Trimmed(string name, string value) { await LoopbackServer.CreateClientAndServerAsync(async uri => diff --git a/src/libraries/System.Net.WebSockets.Client/tests/ClientWebSocketTestBase.cs b/src/libraries/System.Net.WebSockets.Client/tests/ClientWebSocketTestBase.cs index 0c8b94778a58ea..0dc1775b573454 100644 --- a/src/libraries/System.Net.WebSockets.Client/tests/ClientWebSocketTestBase.cs +++ b/src/libraries/System.Net.WebSockets.Client/tests/ClientWebSocketTestBase.cs @@ -15,18 +15,13 @@ namespace System.Net.WebSockets.Client.Tests { public class ClientWebSocketTestBase { - public static readonly object[][] EchoServers = System.Net.Test.Common.Configuration.WebSockets.EchoServers; - public static readonly object[][] EchoHeadersServers = System.Net.Test.Common.Configuration.WebSockets.EchoHeadersServers; + public static readonly object[][] EchoServers = System.Net.Test.Common.Configuration.WebSockets.GetEchoServers(); + public static readonly object[][] EchoHeadersServers = System.Net.Test.Common.Configuration.WebSockets.GetEchoHeadersServers(); public static readonly object[][] EchoServersAndBoolean = EchoServers.SelectMany(o => new object[][] { new object[] { o[0], false }, new object[] { o[0], true } }).ToArray(); - public static readonly object[][] SecureEchoServersAndBoolean = new object[][] - { - new object[] { Test.Common.Configuration.WebSockets.SecureRemoteEchoServer, false }, - new object[] { Test.Common.Configuration.WebSockets.SecureRemoteEchoServer, true } - }; public const int TimeOutMilliseconds = 30000; public const int CloseDescriptionMaxLength = 123; diff --git a/src/libraries/System.Net.WebSockets.Client/tests/ConnectTest.cs b/src/libraries/System.Net.WebSockets.Client/tests/ConnectTest.cs index 7f44a7a69349a6..cb5f0f978f761e 100644 --- a/src/libraries/System.Net.WebSockets.Client/tests/ConnectTest.cs +++ b/src/libraries/System.Net.WebSockets.Client/tests/ConnectTest.cs @@ -254,6 +254,7 @@ public async Task ConnectAsync_CookieHeaders_Success(Uri server) [OuterLoop("Uses external servers", typeof(PlatformDetection), nameof(PlatformDetection.LocalEchoServerIsNotAvailable))] [ConditionalTheory(nameof(WebSocketsSupported)), MemberData(nameof(EchoServers))] + [ActiveIssue("https://github.com/dotnet/runtime/issues/101115", typeof(PlatformDetection), nameof(PlatformDetection.IsFirefox))] public async Task ConnectAsync_PassNoSubProtocol_ServerRequires_ThrowsWebSocketException(Uri server) { const string AcceptedProtocol = "CustomProtocol"; diff --git a/src/libraries/System.Net.WebSockets/tests/WebSocketCreateTest.cs b/src/libraries/System.Net.WebSockets/tests/WebSocketCreateTest.cs index f8323a20332027..988f8e4eaaa92b 100644 --- a/src/libraries/System.Net.WebSockets/tests/WebSocketCreateTest.cs +++ b/src/libraries/System.Net.WebSockets/tests/WebSocketCreateTest.cs @@ -344,7 +344,7 @@ private static async Task CreateWebSocketStream(Uri echoUri, Socket clie return stream; } - public static readonly object[][] EchoServers = System.Net.Test.Common.Configuration.WebSockets.EchoServers; + public static readonly object[][] EchoServers = System.Net.Test.Common.Configuration.WebSockets.GetEchoServers(); public static readonly object[][] EchoServersAndBoolean = EchoServers.SelectMany(o => new object[][] { new object[] { o[0], false }, diff --git a/src/libraries/System.Runtime/tests/System.Globalization.Tests/DateTimeFormatInfo/DateTimeFormatInfoNativeCalendarName.cs b/src/libraries/System.Runtime/tests/System.Globalization.Tests/DateTimeFormatInfo/DateTimeFormatInfoNativeCalendarName.cs index 86507dc1308f11..377e6d30d597bc 100644 --- a/src/libraries/System.Runtime/tests/System.Globalization.Tests/DateTimeFormatInfo/DateTimeFormatInfoNativeCalendarName.cs +++ b/src/libraries/System.Runtime/tests/System.Globalization.Tests/DateTimeFormatInfo/DateTimeFormatInfoNativeCalendarName.cs @@ -11,10 +11,10 @@ public class DateTimeFormatInfoNativeCalendarName public static IEnumerable NativeCalendarName_Get_TestData_HybridGlobalization() { // see the comments on the right to check the non-Hybrid result, in this collection it always differs - string islamicName = "islamic-umalqura"; - string gregorianName = "gregory"; - string persianName = "persian"; - string bhuddistName = "buddhist"; + string islamicName = PlatformDetection.IsFirefox ? "UMALQURA" : "islamic-umalqura"; + string gregorianName = PlatformDetection.IsFirefox ? "GREGORIAN" : "gregory"; + string persianName = PlatformDetection.IsFirefox ? "PERSIAN" : "persian"; + string bhuddistName = PlatformDetection.IsFirefox ? "THAI" : "buddhist"; yield return new object[] { new CultureInfo("ar-SA").DateTimeFormat, islamicName }; // التقويم الإسلامي (أم القرى) yield return new object[] { new CultureInfo("am-ET").DateTimeFormat, gregorianName }; // የግሪጎሪያን የቀን አቆጣጠር yield return new object[] { new CultureInfo("bg-BG").DateTimeFormat, gregorianName }; // григориански календар diff --git a/src/libraries/sendtohelix-browser.targets b/src/libraries/sendtohelix-browser.targets index 8b9a4194565772..393b4dd38f1ff2 100644 --- a/src/libraries/sendtohelix-browser.targets +++ b/src/libraries/sendtohelix-browser.targets @@ -32,7 +32,8 @@ <_ShippingPackagesPath>$([MSBuild]::NormalizeDirectory($(ArtifactsDir), 'packages', $(Configuration), 'Shipping')) - $(Scenario)- + $(Scenario)-ST- + $(Scenario)-MT- true - - - - @@ -112,10 +109,6 @@ - - - - @@ -182,7 +175,13 @@ - + <_WasmSampleZipFile Condition="'$(Scenario)' == 'WasmTestOnV8'" Include="$(TestArchiveRoot)runonly/**/*.Console.V8.*.Sample.zip" /> - <_WasmSampleZipFile Condition="'$(Scenario)' == 'WasmTestOnNodeJS'" Include="$(TestArchiveRoot)runonly/**/*.Console.Node.*.Sample.zip" /> + <_WasmSampleZipFile Condition="'$(Scenario)' == 'WasmTestOnNodeJS'" Include="$(TestArchiveRoot)runonly/**/*.Console.Node.*.Sample.zip" /> <_WasmSampleZipFile Condition="'$(Scenario)' == 'WasmTestOnChrome'" Include="$(TestArchiveRoot)runonly/**/*.Browser.*.Sample.zip" /> + - + %(Identity) $(HelixCommand) $(_workItemTimeout) diff --git a/src/libraries/sendtohelix-wasi.targets b/src/libraries/sendtohelix-wasi.targets index f89da35e17e3e8..e634fa0c2ea3f8 100644 --- a/src/libraries/sendtohelix-wasi.targets +++ b/src/libraries/sendtohelix-wasi.targets @@ -104,6 +104,10 @@ + + diff --git a/src/libraries/sendtohelix-wasm.targets b/src/libraries/sendtohelix-wasm.targets index d9c2e3aead0845..10dc71976f62b8 100644 --- a/src/libraries/sendtohelix-wasm.targets +++ b/src/libraries/sendtohelix-wasm.targets @@ -31,6 +31,8 @@ Workloads- NoWorkload- $(WorkItemPrefix)NoWebcil- + $(WorkItemPrefix)ST- + $(WorkItemPrefix)MT- diff --git a/src/mono/browser/runtime/hybrid-globalization/locales.ts b/src/mono/browser/runtime/hybrid-globalization/locales.ts index da6a478d1e3931..0f04519efdfd32 100644 --- a/src/mono/browser/runtime/hybrid-globalization/locales.ts +++ b/src/mono/browser/runtime/hybrid-globalization/locales.ts @@ -37,12 +37,12 @@ export function mono_wasm_get_locale_info (culture: number, cultureLength: numbe const language = localeParts.join("-"); languageName = new Intl.DisplayNames([cultureName], { type: "language" }).of(language); } catch (error) { - if (error instanceof RangeError && error.message === "invalid_argument") { + if (error instanceof RangeError) { // if it failed from this reason then cultureName is in a form "language-script", without region try { languageName = new Intl.DisplayNames([cultureName], { type: "language" }).of(localeName); } catch (error) { - if (error instanceof RangeError && error.message === "invalid_argument" && localeNameOriginal) { + if (error instanceof RangeError && localeNameOriginal) { // handle non-standard or malformed locales by forwarding the locale code, e.g. "xx-u-xx" stringToUTF16(dst, dst + 2 * localeNameOriginal.length, localeNameOriginal); setI32(dstLength, localeNameOriginal.length); @@ -113,8 +113,8 @@ function getFirstDayOfWeek (locale: string) { if (saturdayLocales.includes(locale)) { return 6; } - const sundayLanguages = ["zh", "th", "pt", "mr", "ml", "ko", "kn", "ja", "id", "hi", "he", "gu", "fil", "bn", "am", "ar"]; - const sundayLocales = ["ta-SG", "ta-IN", "sw-KE", "ms-SG", "fr-CA", "es-MX", "en-US", "en-ZW", "en-ZA", "en-WS", "en-VI", "en-UM", "en-TT", "en-SG", "en-PR", "en-PK", "en-PH", "en-MT", "en-MO", "en-MH", "en-KE", "en-JM", "en-IN", "en-IL", "en-HK", "en-GU", "en-DM", "en-CA", "en-BZ", "en-BW", "en-BS", "en-AU", "en-AS", "en-AG"]; + const sundayLanguages = ["th", "pt", "mr", "ml", "ko", "kn", "ja", "id", "hi", "he", "gu", "fil", "bn", "am", "ar", "te"]; + const sundayLocales = ["ta-SG", "ta-IN", "sw-KE", "ms-SG", "fr-CA", "es-MX", "en-US", "en-ZW", "en-ZA", "en-WS", "en-VI", "en-UM", "en-TT", "en-SG", "en-PR", "en-PK", "en-PH", "en-MT", "en-MO", "en-MH", "en-KE", "en-JM", "en-IN", "en-IL", "en-HK", "en-GU", "en-DM", "en-CA", "en-BZ", "en-BW", "en-BS", "en-AS", "en-AG", "zh-Hans-HK", "zh-SG", "zh-HK", "zh-TW"]; // "en-AU" is Monday in chrome, so firefox should be in line const localeLang = locale.split("-")[0]; if (sundayLanguages.includes(localeLang) || sundayLocales.includes(locale)) { return 0; @@ -134,8 +134,8 @@ function getFirstWeekOfYear (locale: string) { } // Firefox does not support it rn but we can make a temporary workaround for it, // that should be removed when it starts being supported: - const firstFourDayWeekLocales = ["pt-PT", "fr-CH", "fr-FR", "fr-BE", "es-ES", "en-SE", "en-NL", "en-JE", "en-IM", "en-IE", "en-GI", "en-GG", "en-GB", "en-FJ", "en-FI", "en-DK", "en-DE", "en-CH", "en-BE", "en-AT", "el-GR"]; - const firstFourDayWeekLanguages = ["sv", "sk", "ru", "pl", "nl", "no", "lt", "it", "hu", "fi", "et", "de", "da", "cs", "ca", "bg"]; + const firstFourDayWeekLocales = ["pt-PT", "fr-CH", "fr-FR", "fr-BE", "es-ES", "en-SE", "en-NL", "en-JE", "en-IM", "en-IE", "en-GI", "en-GG", "en-GB", "en-FJ", "en-FI", "en-DK", "en-DE", "en-CH", "en-BE", "en-AT", "el-GR", "nl-BE", "nl-NL"]; + const firstFourDayWeekLanguages = ["sv", "sk", "ru", "pl", "no", "nb", "lt", "it", "hu", "fi", "et", "de", "da", "cs", "ca", "bg"]; const localeLang = locale.split("-")[0]; if (firstFourDayWeekLocales.includes(locale) || firstFourDayWeekLanguages.includes(localeLang)) { return 2; diff --git a/src/mono/sample/Directory.Build.props b/src/mono/sample/Directory.Build.props index 8780899630286b..2d5011ce41f881 100644 --- a/src/mono/sample/Directory.Build.props +++ b/src/mono/sample/Directory.Build.props @@ -5,14 +5,22 @@ true + - $HARNESS_RUNNER - $XHARNESS_OUT + $HARNESS_RUNNER + $XHARNESS_OUT + $XHARNESS_COMMAND + $XHARNESS_ARGS - - %HARNESS_RUNNER% - %XHARNESS_OUT% + %HARNESS_RUNNER% + %XHARNESS_OUT% + %XHARNESS_COMMAND% + %XHARNESS_ARGS% diff --git a/src/mono/sample/wasm/DefaultBrowserSample.targets b/src/mono/sample/wasm/DefaultBrowserSample.targets index d34e280cf19c6d..af224ce9c48af3 100644 --- a/src/mono/sample/wasm/DefaultBrowserSample.targets +++ b/src/mono/sample/wasm/DefaultBrowserSample.targets @@ -7,7 +7,7 @@ -1 true $(WasmXHarnessArgs) --web-server-use-cop - $(ExecXHarnessCmd) wasm test-browser --app=. --browser=Chrome $(XHarnessBrowserPathArg) $(WasmXHarnessArgs) --html-file=index.html --output-directory=$(XHarnessOutput) -- $(MSBuildProjectName).dll + $(ExecXHarnessVar) wasm $(XHarnessCommandVar) --app=. $(XHarnessBrowserPathArg) $(WasmXHarnessArgsVar) $(WasmXHarnessArgs) --html-file=index.html --output-directory=$(XHarnessOutputVar) -- $(MSBuildProjectName).dll true $(TestArchiveRoot)chromeonly/ $(TestArchiveTestsRoot)$(OSPlatformConfig)/ diff --git a/src/mono/sample/wasm/console-node/Wasm.Console.Node.Sample.csproj b/src/mono/sample/wasm/console-node/Wasm.Console.Node.Sample.csproj index 7234698ff22837..995e1d3650e2ca 100644 --- a/src/mono/sample/wasm/console-node/Wasm.Console.Node.Sample.csproj +++ b/src/mono/sample/wasm/console-node/Wasm.Console.Node.Sample.csproj @@ -6,7 +6,7 @@ true 2 - $(ExecXHarnessCmd) wasm test --app=. --engine=NodeJS --engine-arg=--stack-trace-limit=1000 --js-file=main.mjs --output-directory=$(XHarnessOutput) --expected-exit-code $(ExpectedExitCode) + $(ExecXHarnessVar) wasm test --app=. --engine=NodeJS --engine-arg=--stack-trace-limit=1000 --js-file=main.mjs --output-directory=$(XHarnessOutputVar) --expected-exit-code $(ExpectedExitCode) diff --git a/src/mono/sample/wasm/console-v8/Wasm.Console.V8.Sample.csproj b/src/mono/sample/wasm/console-v8/Wasm.Console.V8.Sample.csproj index 13ed38bfe63e4c..09e9f7bf1a0d2d 100644 --- a/src/mono/sample/wasm/console-v8/Wasm.Console.V8.Sample.csproj +++ b/src/mono/sample/wasm/console-v8/Wasm.Console.V8.Sample.csproj @@ -5,7 +5,7 @@ true true - $(ExecXHarnessCmd) wasm test --app=. --engine=V8 --engine-arg=--stack-trace-limit=1000 --engine-arg=--module --js-file=main.mjs --output-directory=$(XHarnessOutput) -- --run $(MSBuildProjectName).dll + $(ExecXHarnessVar) wasm test --app=. --engine=V8 --engine-arg=--stack-trace-limit=1000 --engine-arg=--module --js-file=main.mjs --output-directory=$(XHarnessOutputVar) -- --run $(MSBuildProjectName).dll From d0dffe1dcfc6dbc9208546ffcb39aa9e6945e783 Mon Sep 17 00:00:00 2001 From: Pavel Savara Date: Thu, 25 Apr 2024 14:59:01 +0200 Subject: [PATCH 071/161] [WASI] update WASI SDK to 22 and wasmtime to 19.0.2 (#101392) --- Directory.Build.props | 2 ++ eng/native/gen-buildsys.cmd | 2 +- eng/testing/tests.wasi.targets | 2 +- src/mono/Directory.Build.props | 8 +++++--- src/mono/mono.proj | 2 +- src/mono/mono/tools/offsets-tool/offsets-tool.py | 4 +++- src/mono/wasi/wasi-sdk-version.txt | 2 +- src/mono/wasi/wasi.proj | 2 +- src/mono/wasi/wasmtime-version.txt | 2 +- src/native/libs/Common/pal_error_common.h | 4 ++++ .../System.Globalization.Native/pal_localeNumberData.c | 5 +++++ src/native/libs/System.Native/pal_io.c | 6 ++++++ 12 files changed, 31 insertions(+), 10 deletions(-) diff --git a/Directory.Build.props b/Directory.Build.props index 40c75f103b8be8..c6bae2a825b1bf 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -184,7 +184,9 @@ $([MSBuild]::NormalizePath('$(TestExclusionListTasksDir)', 'TestExclusionListTasks.dll')) $([MSBuild]::NormalizeDirectory('$(ArtifactsBinDir)', 'coreclr', '$(TargetOS).$(TargetArchitecture).$(RuntimeConfiguration)')) $(CoreCLRToolPath) + $([MSBuild]::NormalizeDirectory($(ArtifactsObjDir), 'wasmtime')) true $([MSBuild]::NormalizeDirectory($(WasmProjectRoot), 'build')) diff --git a/eng/native/gen-buildsys.cmd b/eng/native/gen-buildsys.cmd index f67f17b8d47942..79db6bffae062d 100644 --- a/eng/native/gen-buildsys.cmd +++ b/eng/native/gen-buildsys.cmd @@ -62,7 +62,7 @@ if /i "%__Arch%" == "wasm" ( if /i "%__Os%" == "wasi" ( if "%WASI_SDK_PATH%" == "" ( if not exist "%__repoRoot%\src\mono\wasi\wasi-sdk" ( - echo Error: Should set WASI_SDK_PATH environment variable pointing to emsdk root. + echo Error: Should set WASI_SDK_PATH environment variable pointing to WASI SDK root. exit /B 1 ) diff --git a/eng/testing/tests.wasi.targets b/eng/testing/tests.wasi.targets index 989e934dd8412a..e8f75ee3821bc5 100644 --- a/eng/testing/tests.wasi.targets +++ b/eng/testing/tests.wasi.targets @@ -46,7 +46,7 @@ <_XHarnessArgs Condition="'$(IsFunctionalTest)' == 'true'" >$(_XHarnessArgs) --expected-exit-code=$(ExpectedExitCode) <_XHarnessArgs Condition="'$(WasmXHarnessArgs)' != ''" >$(_XHarnessArgs) $(WasmXHarnessArgs) <_XHarnessArgs Condition="'$(WasmXHarnessTestsTimeout)' != ''" >$(_XHarnessArgs) "--timeout=$(WasmXHarnessTestsTimeout)" - <_XHarnessArgs >$(_XHarnessArgs) --engine-arg=--max-wasm-stack=134217728 + <_XHarnessArgs >$(_XHarnessArgs) --engine-arg=-W --engine-arg=max-wasm-stack=134217728 <_XHarnessArgs Condition="'$(WasmXHarnessArgsCli)' != ''" >$(_XHarnessArgs) $(WasmXHarnessArgsCli) <_InvariantGlobalization Condition="'$(InvariantGlobalization)' == 'true'">--env=DOTNET_SYSTEM_GLOBALIZATION_INVARIANT=true diff --git a/src/mono/Directory.Build.props b/src/mono/Directory.Build.props index 12d6fdb34cfc57..d97bf84a1da660 100644 --- a/src/mono/Directory.Build.props +++ b/src/mono/Directory.Build.props @@ -34,10 +34,12 @@ - <_ProvisionWasiSdkDir>$([MSBuild]::NormalizeDirectory($(MSBuildThisFileDirectory), 'wasi', 'wasi-sdk')) - true - $(_ProvisionWasiSdkDir) + + $([MSBuild]::NormalizeDirectory($(MSBuildThisFileDirectory), 'wasi', 'wasi-sdk')) $([MSBuild]::EnsureTrailingSlash('$(WASI_SDK_PATH)').Replace('\', '/')) + true diff --git a/src/mono/mono.proj b/src/mono/mono.proj index 47eeb0937a88fa..0d855362d99211 100644 --- a/src/mono/mono.proj +++ b/src/mono/mono.proj @@ -797,7 +797,7 @@ - + - + https://github.com/dotnet/emsdk - 9d28301f6a5f512db14f242f7403a4bfbcbcc8a4 + 53288f87c588907e8ff01f129786820fe998573c diff --git a/eng/Versions.props b/eng/Versions.props index 5e732a3a2e1871..0fb3f86bcf6fe6 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -235,9 +235,9 @@ Note: when the name is updated, make sure to update dependency name in eng/pipelines/common/xplat-setup.yml like - DarcDependenciesChanged.Microsoft_NET_Workload_Emscripten_Current_Manifest-9_0_100_Transport --> - 9.0.0-preview.4.24222.2 + 9.0.0-preview.5.24223.2 $(MicrosoftNETWorkloadEmscriptenCurrentManifest90100TransportVersion) - 9.0.0-preview.4.24222.2 + 9.0.0-preview.5.24223.2 1.1.87-gba258badda 1.0.0-v3.14.0.5722 From e1bda8a765a5dd3e7ea1e9dfeafa7fe44ae486aa Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Thu, 25 Apr 2024 20:45:29 -0500 Subject: [PATCH 091/161] [main] Update dependencies from dotnet/cecil, dotnet/hotreload-utils, dotnet/icu, dotnet/runtime, dotnet/runtime-assets, dotnet/sdk, dotnet/xharness (#101378) * Update dependencies from https://github.com/dotnet/runtime build 20240419.3 Microsoft.DotNet.ILCompiler , Microsoft.NET.Sdk.IL , Microsoft.NETCore.App.Runtime.win-x64 , Microsoft.NETCore.ILAsm , runtime.native.System.IO.Ports , System.Reflection.Metadata , System.Reflection.MetadataLoadContext , System.Text.Json , Microsoft.SourceBuild.Intermediate.runtime.linux-x64 From Version 9.0.0-preview.4.24215.1 -> To Version 9.0.0-preview.4.24219.3 * Update dependencies from https://github.com/dotnet/sdk build 20240421.4 Microsoft.SourceBuild.Intermediate.sdk , Microsoft.DotNet.ApiCompat.Task From Version 9.0.100-preview.4.24215.1 -> To Version 9.0.100-preview.4.24221.4 * Update dependencies from https://github.com/dotnet/icu build 20240422.1 Microsoft.NETCore.Runtime.ICU.Transport From Version 9.0.0-preview.4.24215.1 -> To Version 9.0.0-preview.4.24222.1 * Update dependencies from https://github.com/dotnet/xharness build 20240422.1 Microsoft.DotNet.XHarness.CLI , Microsoft.DotNet.XHarness.TestRunners.Common , Microsoft.DotNet.XHarness.TestRunners.Xunit From Version 9.0.0-prerelease.24208.1 -> To Version 9.0.0-prerelease.24222.1 * Update dependencies from https://github.com/dotnet/runtime-assets build 20240422.1 Microsoft.DotNet.CilStrip.Sources , System.ComponentModel.TypeConverter.TestData , System.Data.Common.TestData , System.Drawing.Common.TestData , System.Formats.Tar.TestData , System.IO.Compression.TestData , System.IO.Packaging.TestData , System.Net.TestData , System.Private.Runtime.UnicodeData , System.Runtime.Numerics.TestData , System.Runtime.TimeZoneData , System.Security.Cryptography.X509Certificates.TestData , System.Text.RegularExpressions.TestData , System.Windows.Extensions.TestData From Version 9.0.0-beta.24215.1 -> To Version 9.0.0-beta.24222.1 * Update dependencies from https://github.com/dotnet/hotreload-utils build 20240422.1 Microsoft.DotNet.HotReload.Utils.Generator.BuildTool From Version 9.0.0-alpha.0.24215.1 -> To Version 9.0.0-alpha.0.24222.1 * Update dependencies from https://github.com/dotnet/cecil build 20240422.1 Microsoft.SourceBuild.Intermediate.cecil , Microsoft.DotNet.Cecil From Version 0.11.4-alpha.24215.1 -> To Version 0.11.4-alpha.24222.1 * Fix Enum constraint mismatches * More mismatches * INumber constraint * Update dependencies from https://github.com/dotnet/icu build 20240423.2 Microsoft.NETCore.Runtime.ICU.Transport From Version 9.0.0-preview.4.24215.1 -> To Version 9.0.0-preview.5.24223.2 * Update dependencies from https://github.com/dotnet/xharness build 20240422.1 Microsoft.DotNet.XHarness.CLI , Microsoft.DotNet.XHarness.TestRunners.Common , Microsoft.DotNet.XHarness.TestRunners.Xunit From Version 9.0.0-prerelease.24208.1 -> To Version 9.0.0-prerelease.24222.1 * Update dependencies from https://github.com/dotnet/runtime-assets build 20240422.1 Microsoft.DotNet.CilStrip.Sources , System.ComponentModel.TypeConverter.TestData , System.Data.Common.TestData , System.Drawing.Common.TestData , System.Formats.Tar.TestData , System.IO.Compression.TestData , System.IO.Packaging.TestData , System.Net.TestData , System.Private.Runtime.UnicodeData , System.Runtime.Numerics.TestData , System.Runtime.TimeZoneData , System.Security.Cryptography.X509Certificates.TestData , System.Text.RegularExpressions.TestData , System.Windows.Extensions.TestData From Version 9.0.0-beta.24215.1 -> To Version 9.0.0-beta.24222.1 * Update dependencies from https://github.com/dotnet/hotreload-utils build 20240422.1 Microsoft.DotNet.HotReload.Utils.Generator.BuildTool From Version 9.0.0-alpha.0.24215.1 -> To Version 9.0.0-alpha.0.24222.1 * Update dependencies from https://github.com/dotnet/cecil build 20240422.1 Microsoft.SourceBuild.Intermediate.cecil , Microsoft.DotNet.Cecil From Version 0.11.4-alpha.24215.1 -> To Version 0.11.4-alpha.24222.1 * Fix issues with missing generic constraints * Remove constraint from Enum.TryFormat ref * Update ApiCompat suppression files * Update dependencies from https://github.com/dotnet/icu build 20240423.2 Microsoft.NETCore.Runtime.ICU.Transport From Version 9.0.0-preview.4.24215.1 -> To Version 9.0.0-preview.5.24223.2 * Update dependencies from https://github.com/dotnet/xharness build 20240424.1 Microsoft.DotNet.XHarness.CLI , Microsoft.DotNet.XHarness.TestRunners.Common , Microsoft.DotNet.XHarness.TestRunners.Xunit From Version 9.0.0-prerelease.24208.1 -> To Version 9.0.0-prerelease.24224.1 * Update dependencies from https://github.com/dotnet/runtime-assets build 20240422.1 Microsoft.DotNet.CilStrip.Sources , System.ComponentModel.TypeConverter.TestData , System.Data.Common.TestData , System.Drawing.Common.TestData , System.Formats.Tar.TestData , System.IO.Compression.TestData , System.IO.Packaging.TestData , System.Net.TestData , System.Private.Runtime.UnicodeData , System.Runtime.Numerics.TestData , System.Runtime.TimeZoneData , System.Security.Cryptography.X509Certificates.TestData , System.Text.RegularExpressions.TestData , System.Windows.Extensions.TestData From Version 9.0.0-beta.24215.1 -> To Version 9.0.0-beta.24222.1 * Update dependencies from https://github.com/dotnet/hotreload-utils build 20240422.1 Microsoft.DotNet.HotReload.Utils.Generator.BuildTool From Version 9.0.0-alpha.0.24215.1 -> To Version 9.0.0-alpha.0.24222.1 * Update dependencies from https://github.com/dotnet/cecil build 20240422.1 Microsoft.SourceBuild.Intermediate.cecil , Microsoft.DotNet.Cecil From Version 0.11.4-alpha.24215.1 -> To Version 0.11.4-alpha.24222.1 --------- Co-authored-by: dotnet-maestro[bot] Co-authored-by: Jan Kotas Co-authored-by: Eric StJohn --- .config/dotnet-tools.json | 2 +- eng/Version.Details.xml | 128 +++--- eng/Versions.props | 56 +-- global.json | 2 +- .../src/CompatibilitySuppressions.xml | 1 + ...em.Diagnostics.DiagnosticSourceActivity.cs | 2 +- ....Private.CoreLib.ManualShimTypeForwards.cs | 2 +- .../System.Private.CoreLib/src/System/Enum.cs | 2 +- .../ref/System.Runtime.InteropServices.cs | 6 +- .../src/CompatibilitySuppressions.xml | 1 + ...iCompatBaseline.NetCoreAppLatestStable.xml | 60 +++ .../ApiCompatBaseline.netstandard2.0.xml | 378 ++++++++++++++++++ .../ApiCompatBaseline.netstandard2.1.xml | 126 ++++++ 13 files changed, 666 insertions(+), 100 deletions(-) diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json index 78d06c501e8835..1315a20dd66bec 100644 --- a/.config/dotnet-tools.json +++ b/.config/dotnet-tools.json @@ -15,7 +15,7 @@ ] }, "microsoft.dotnet.xharness.cli": { - "version": "9.0.0-prerelease.24208.1", + "version": "9.0.0-prerelease.24224.1", "commands": [ "xharness" ] diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 627f374cb45637..c35213b8ecadb5 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -1,8 +1,8 @@ - + https://github.com/dotnet/icu - 0ea0175965771285846b5d077bebe5946036a595 + 88c4ff85536a2397ba3945dd4a7cdc860c584914 https://github.com/dotnet/msquic @@ -58,14 +58,14 @@ a045dd54a4c44723c215d992288160eb1401bb7f - + https://github.com/dotnet/cecil - 861f49c137941b9722a43e5993ccac7716c8528c + 4abe3e63a5d4653ca098c633644432c1395411c1 - + https://github.com/dotnet/cecil - 861f49c137941b9722a43e5993ccac7716c8528c + 4abe3e63a5d4653ca098c633644432c1395411c1 @@ -174,57 +174,57 @@ https://github.com/dotnet/arcade b4f4d40741f161e2c0d96c19c51a4013850ef65f - + https://github.com/dotnet/runtime-assets - 30b6a8d9d3af5681e4caef1ea453619a4b0e9f2e + 6e78861f1f307cd9f0e64a45b1d7884fa4470930 - + https://github.com/dotnet/runtime-assets - 30b6a8d9d3af5681e4caef1ea453619a4b0e9f2e + 6e78861f1f307cd9f0e64a45b1d7884fa4470930 - + https://github.com/dotnet/runtime-assets - 30b6a8d9d3af5681e4caef1ea453619a4b0e9f2e + 6e78861f1f307cd9f0e64a45b1d7884fa4470930 - + https://github.com/dotnet/runtime-assets - 30b6a8d9d3af5681e4caef1ea453619a4b0e9f2e + 6e78861f1f307cd9f0e64a45b1d7884fa4470930 - + https://github.com/dotnet/runtime-assets - 30b6a8d9d3af5681e4caef1ea453619a4b0e9f2e + 6e78861f1f307cd9f0e64a45b1d7884fa4470930 - + https://github.com/dotnet/runtime-assets - 30b6a8d9d3af5681e4caef1ea453619a4b0e9f2e + 6e78861f1f307cd9f0e64a45b1d7884fa4470930 - + https://github.com/dotnet/runtime-assets - 30b6a8d9d3af5681e4caef1ea453619a4b0e9f2e + 6e78861f1f307cd9f0e64a45b1d7884fa4470930 - + https://github.com/dotnet/runtime-assets - 30b6a8d9d3af5681e4caef1ea453619a4b0e9f2e + 6e78861f1f307cd9f0e64a45b1d7884fa4470930 - + https://github.com/dotnet/runtime-assets - 30b6a8d9d3af5681e4caef1ea453619a4b0e9f2e + 6e78861f1f307cd9f0e64a45b1d7884fa4470930 - + https://github.com/dotnet/runtime-assets - 30b6a8d9d3af5681e4caef1ea453619a4b0e9f2e + 6e78861f1f307cd9f0e64a45b1d7884fa4470930 - + https://github.com/dotnet/runtime-assets - 30b6a8d9d3af5681e4caef1ea453619a4b0e9f2e + 6e78861f1f307cd9f0e64a45b1d7884fa4470930 - + https://github.com/dotnet/runtime-assets - 30b6a8d9d3af5681e4caef1ea453619a4b0e9f2e + 6e78861f1f307cd9f0e64a45b1d7884fa4470930 - + https://github.com/dotnet/runtime-assets - 30b6a8d9d3af5681e4caef1ea453619a4b0e9f2e + 6e78861f1f307cd9f0e64a45b1d7884fa4470930 https://github.com/dotnet/llvm-project @@ -282,55 +282,55 @@ https://github.com/dotnet/llvm-project 26f8c30340764cfa7fa9090dc01a36c222bf09c1 - + https://github.com/dotnet/runtime - 85fbd98765c47a867564fff6ae18cc92423cdc66 + 56610095196ac12a397b1acd00835db4d86849b9 - + https://github.com/dotnet/runtime - 85fbd98765c47a867564fff6ae18cc92423cdc66 + 56610095196ac12a397b1acd00835db4d86849b9 - + https://github.com/dotnet/runtime - 85fbd98765c47a867564fff6ae18cc92423cdc66 + 56610095196ac12a397b1acd00835db4d86849b9 - + https://github.com/dotnet/runtime - 85fbd98765c47a867564fff6ae18cc92423cdc66 + 56610095196ac12a397b1acd00835db4d86849b9 - + https://github.com/dotnet/runtime - 85fbd98765c47a867564fff6ae18cc92423cdc66 + 56610095196ac12a397b1acd00835db4d86849b9 - + https://github.com/dotnet/runtime - 85fbd98765c47a867564fff6ae18cc92423cdc66 + 56610095196ac12a397b1acd00835db4d86849b9 - + https://github.com/dotnet/runtime - 85fbd98765c47a867564fff6ae18cc92423cdc66 + 56610095196ac12a397b1acd00835db4d86849b9 - + https://github.com/dotnet/runtime - 85fbd98765c47a867564fff6ae18cc92423cdc66 + 56610095196ac12a397b1acd00835db4d86849b9 - + https://github.com/dotnet/runtime - 85fbd98765c47a867564fff6ae18cc92423cdc66 + 56610095196ac12a397b1acd00835db4d86849b9 - + https://github.com/dotnet/xharness - 50b43ece7daf9f8a88ac16a95a4f8647a4c71c4b + ec633d9ddbdb86dd3d772989889690821f790484 - + https://github.com/dotnet/xharness - 50b43ece7daf9f8a88ac16a95a4f8647a4c71c4b + ec633d9ddbdb86dd3d772989889690821f790484 - + https://github.com/dotnet/xharness - 50b43ece7daf9f8a88ac16a95a4f8647a4c71c4b + ec633d9ddbdb86dd3d772989889690821f790484 https://github.com/dotnet/arcade @@ -352,13 +352,13 @@ https://dev.azure.com/dnceng/internal/_git/dotnet-optimization c54b8e8611d50594cc926fd7c81205871a38be6f - + https://github.com/dotnet/hotreload-utils - 4670b9e37293570f8d93d6af40c4710e2686bf67 + 249050528f8ac9882f04b2c719bda3e5a532b258 - + https://github.com/dotnet/runtime-assets - 30b6a8d9d3af5681e4caef1ea453619a4b0e9f2e + 6e78861f1f307cd9f0e64a45b1d7884fa4470930 https://github.com/dotnet/roslyn @@ -386,14 +386,14 @@ 3027ed4a9186a6924722a1597c8d31a59d411f7c - + https://github.com/dotnet/sdk - cf8c24575410adf397c0823fd7061f9451049ea1 + 1529907f03b73e097a6e4f33fd3c5aea2246f021 - + https://github.com/dotnet/sdk - cf8c24575410adf397c0823fd7061f9451049ea1 + 1529907f03b73e097a6e4f33fd3c5aea2246f021 diff --git a/eng/Versions.props b/eng/Versions.props index 0fb3f86bcf6fe6..8ca09ea0685ae1 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -81,7 +81,7 @@ 0.2.0 - 9.0.100-preview.4.24215.1 + 9.0.100-preview.4.24221.4 9.0.0-beta.24219.1 9.0.0-beta.24219.1 @@ -104,10 +104,10 @@ 6.0.0-preview.1.102 - 9.0.0-preview.4.24215.1 + 9.0.0-preview.4.24219.3 6.0.0 - 9.0.0-preview.4.24215.1 + 9.0.0-preview.4.24219.3 6.0.0 1.1.1 @@ -119,39 +119,39 @@ 8.0.0 5.0.0 4.5.5 - 9.0.0-preview.4.24215.1 - 9.0.0-preview.4.24215.1 + 9.0.0-preview.4.24219.3 + 9.0.0-preview.4.24219.3 6.0.0 5.0.0 5.0.0 5.0.0 7.0.0 - 9.0.0-preview.4.24215.1 + 9.0.0-preview.4.24219.3 6.0.0 7.0.0 4.5.4 4.5.0 - 9.0.0-preview.4.24215.1 + 9.0.0-preview.4.24219.3 8.0.0 8.0.0 8.0.0 8.0.0 - 9.0.0-beta.24215.1 - 9.0.0-beta.24215.1 - 9.0.0-beta.24215.1 - 9.0.0-beta.24215.1 - 9.0.0-beta.24215.1 - 9.0.0-beta.24215.1 - 9.0.0-beta.24215.1 - 9.0.0-beta.24215.1 - 9.0.0-beta.24215.1 - 9.0.0-beta.24215.1 - 9.0.0-beta.24215.1 - 9.0.0-beta.24215.1 - 9.0.0-beta.24215.1 - 9.0.0-beta.24215.1 + 9.0.0-beta.24222.1 + 9.0.0-beta.24222.1 + 9.0.0-beta.24222.1 + 9.0.0-beta.24222.1 + 9.0.0-beta.24222.1 + 9.0.0-beta.24222.1 + 9.0.0-beta.24222.1 + 9.0.0-beta.24222.1 + 9.0.0-beta.24222.1 + 9.0.0-beta.24222.1 + 9.0.0-beta.24222.1 + 9.0.0-beta.24222.1 + 9.0.0-beta.24222.1 + 9.0.0-beta.24222.1 1.0.0-prerelease.24219.3 1.0.0-prerelease.24219.3 @@ -179,10 +179,10 @@ 1.4.0 17.4.0-preview-20220707-01 - 9.0.0-prerelease.24208.1 - 9.0.0-prerelease.24208.1 - 9.0.0-prerelease.24208.1 - 9.0.0-alpha.0.24215.1 + 9.0.0-prerelease.24224.1 + 9.0.0-prerelease.24224.1 + 9.0.0-prerelease.24224.1 + 9.0.0-alpha.0.24222.1 3.12.0 4.5.0 6.0.0 @@ -208,11 +208,11 @@ 8.0.0-preview-20230918.1 - 0.11.4-alpha.24215.1 + 0.11.4-alpha.24222.1 - 9.0.0-preview.4.24215.1 + 9.0.0-preview.4.24219.3 - 9.0.0-preview.4.24215.1 + 9.0.0-preview.5.24223.2 2.3.5 9.0.0-alpha.1.24167.3 diff --git a/global.json b/global.json index eb06a253442796..a19b0072e32e2e 100644 --- a/global.json +++ b/global.json @@ -13,6 +13,6 @@ "Microsoft.DotNet.SharedFramework.Sdk": "9.0.0-beta.24219.1", "Microsoft.Build.NoTargets": "3.7.0", "Microsoft.Build.Traversal": "3.4.0", - "Microsoft.NET.Sdk.IL": "9.0.0-preview.4.24215.1" + "Microsoft.NET.Sdk.IL": "9.0.0-preview.4.24219.3" } } diff --git a/src/libraries/System.Collections/src/CompatibilitySuppressions.xml b/src/libraries/System.Collections/src/CompatibilitySuppressions.xml index c313881d43172b..f281317339d43b 100644 --- a/src/libraries/System.Collections/src/CompatibilitySuppressions.xml +++ b/src/libraries/System.Collections/src/CompatibilitySuppressions.xml @@ -1,4 +1,5 @@  + CP0001 diff --git a/src/libraries/System.Diagnostics.DiagnosticSource/ref/System.Diagnostics.DiagnosticSourceActivity.cs b/src/libraries/System.Diagnostics.DiagnosticSource/ref/System.Diagnostics.DiagnosticSourceActivity.cs index 382499070cd1d9..3908224b0a1a13 100644 --- a/src/libraries/System.Diagnostics.DiagnosticSource/ref/System.Diagnostics.DiagnosticSourceActivity.cs +++ b/src/libraries/System.Diagnostics.DiagnosticSource/ref/System.Diagnostics.DiagnosticSourceActivity.cs @@ -402,7 +402,7 @@ public abstract class Instrument : Instrument where T : struct public ReadOnlySpan> Tags { get { throw null; } } public T Value { get { throw null; } } } - public delegate void MeasurementCallback(Instrument instrument, T measurement, ReadOnlySpan> tags, object? state); + public delegate void MeasurementCallback(Instrument instrument, T measurement, ReadOnlySpan> tags, object? state) where T : struct; public class Meter : IDisposable { public Counter CreateCounter(string name, string? unit = null, string? description = null) where T : struct { throw null; } diff --git a/src/libraries/System.Private.CoreLib/ref/System.Private.CoreLib.ManualShimTypeForwards.cs b/src/libraries/System.Private.CoreLib/ref/System.Private.CoreLib.ManualShimTypeForwards.cs index 0a93320ccff1eb..ab8473216cd87a 100644 --- a/src/libraries/System.Private.CoreLib/ref/System.Private.CoreLib.ManualShimTypeForwards.cs +++ b/src/libraries/System.Private.CoreLib/ref/System.Private.CoreLib.ManualShimTypeForwards.cs @@ -65,7 +65,7 @@ public ByteEqualityComparer() { } public override int GetHashCode() { throw null; } public override int GetHashCode(byte b) { throw null; } } - public sealed partial class EnumEqualityComparer : System.Collections.Generic.EqualityComparer, System.Runtime.Serialization.ISerializable where T : struct + public sealed partial class EnumEqualityComparer : System.Collections.Generic.EqualityComparer, System.Runtime.Serialization.ISerializable where T : struct, System.Enum { public EnumEqualityComparer() { } public override bool Equals([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] object? obj) { throw null; } diff --git a/src/libraries/System.Private.CoreLib/src/System/Enum.cs b/src/libraries/System.Private.CoreLib/src/System/Enum.cs index 20fd34bf70d89c..d2b18ed344cc37 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Enum.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Enum.cs @@ -1746,7 +1746,7 @@ bool ISpanFormattable.TryFormat(Span destination, out int charsWritten, Re /// A span containing the character that represents the standard format string that defines the acceptable format of destination. This may be empty, or "g", "d", "f", or "x". /// if the formatting was successful; otherwise, if the destination span wasn't large enough to contain the formatted value. /// The format parameter contains an invalid value. - public static unsafe bool TryFormat(TEnum value, Span destination, out int charsWritten, [StringSyntax(StringSyntaxAttribute.EnumFormat)] ReadOnlySpan format = default) where TEnum : struct, Enum + public static unsafe bool TryFormat(TEnum value, Span destination, out int charsWritten, [StringSyntax(StringSyntaxAttribute.EnumFormat)] ReadOnlySpan format = default) where TEnum : struct { RuntimeType rt = (RuntimeType)typeof(TEnum); Type underlyingType = typeof(TEnum).GetEnumUnderlyingType(); diff --git a/src/libraries/System.Runtime.InteropServices/ref/System.Runtime.InteropServices.cs b/src/libraries/System.Runtime.InteropServices/ref/System.Runtime.InteropServices.cs index 3b718d224417c7..f7665833c0a758 100644 --- a/src/libraries/System.Runtime.InteropServices/ref/System.Runtime.InteropServices.cs +++ b/src/libraries/System.Runtime.InteropServices/ref/System.Runtime.InteropServices.cs @@ -362,17 +362,17 @@ public void FinalRelease() { } System.Runtime.InteropServices.Marshalling.VirtualMethodTableInfo System.Runtime.InteropServices.Marshalling.IUnmanagedVirtualMethodTableProvider.GetVirtualMethodTableInfoForKey(System.Type type) { throw null; } } [System.Runtime.InteropServices.Marshalling.CustomMarshallerAttribute(typeof(System.Exception), System.Runtime.InteropServices.Marshalling.MarshalMode.UnmanagedToManagedOut, typeof(System.Runtime.InteropServices.Marshalling.ExceptionAsDefaultMarshaller<>))] - public static partial class ExceptionAsDefaultMarshaller where T : struct + public static partial class ExceptionAsDefaultMarshaller where T : unmanaged { public static T ConvertToUnmanaged(System.Exception e) { throw null; } } [System.Runtime.InteropServices.Marshalling.CustomMarshallerAttribute(typeof(System.Exception), System.Runtime.InteropServices.Marshalling.MarshalMode.UnmanagedToManagedOut, typeof(System.Runtime.InteropServices.Marshalling.ExceptionAsHResultMarshaller<>))] - public static partial class ExceptionAsHResultMarshaller where T : struct + public static partial class ExceptionAsHResultMarshaller where T : unmanaged, System.Numerics.INumber { public static T ConvertToUnmanaged(System.Exception e) { throw null; } } [System.Runtime.InteropServices.Marshalling.CustomMarshallerAttribute(typeof(System.Exception), System.Runtime.InteropServices.Marshalling.MarshalMode.UnmanagedToManagedOut, typeof(System.Runtime.InteropServices.Marshalling.ExceptionAsNaNMarshaller<>))] - public static partial class ExceptionAsNaNMarshaller where T : struct + public static partial class ExceptionAsNaNMarshaller where T : unmanaged, System.Numerics.IFloatingPointIeee754 { public static T ConvertToUnmanaged(System.Exception e) { throw null; } } diff --git a/src/libraries/System.Runtime.InteropServices/src/CompatibilitySuppressions.xml b/src/libraries/System.Runtime.InteropServices/src/CompatibilitySuppressions.xml index ebabc977812cb7..b4c6a062718672 100644 --- a/src/libraries/System.Runtime.InteropServices/src/CompatibilitySuppressions.xml +++ b/src/libraries/System.Runtime.InteropServices/src/CompatibilitySuppressions.xml @@ -1,4 +1,5 @@  + CP0001 diff --git a/src/libraries/apicompat/ApiCompatBaseline.NetCoreAppLatestStable.xml b/src/libraries/apicompat/ApiCompatBaseline.NetCoreAppLatestStable.xml index 09cfe417e3812f..935f4a69d115ad 100644 --- a/src/libraries/apicompat/ApiCompatBaseline.NetCoreAppLatestStable.xml +++ b/src/libraries/apicompat/ApiCompatBaseline.NetCoreAppLatestStable.xml @@ -469,4 +469,64 @@ net8.0/System.dll net9.0/System.dll + + CP0021 + T:System.Diagnostics.Metrics.MeasurementCallback`1``0:struct + net8.0/System.Diagnostics.DiagnosticSource.dll + net9.0/System.Diagnostics.DiagnosticSource.dll + + + CP0021 + T:System.Runtime.InteropServices.Marshalling.ExceptionAsDefaultMarshaller`1``0:struct + net8.0/System.Runtime.InteropServices.dll + net9.0/System.Runtime.InteropServices.dll + + + CP0021 + T:System.Runtime.InteropServices.Marshalling.ExceptionAsDefaultMarshaller`1``0:unmanaged + net8.0/System.Runtime.InteropServices.dll + net9.0/System.Runtime.InteropServices.dll + + + CP0021 + T:System.Runtime.InteropServices.Marshalling.ExceptionAsHResultMarshaller`1``0:struct + net8.0/System.Runtime.InteropServices.dll + net9.0/System.Runtime.InteropServices.dll + + + CP0021 + T:System.Runtime.InteropServices.Marshalling.ExceptionAsHResultMarshaller`1``0:T:System.Numerics.INumber{`0} + net8.0/System.Runtime.InteropServices.dll + net9.0/System.Runtime.InteropServices.dll + + + CP0021 + T:System.Runtime.InteropServices.Marshalling.ExceptionAsHResultMarshaller`1``0:unmanaged + net8.0/System.Runtime.InteropServices.dll + net9.0/System.Runtime.InteropServices.dll + + + CP0021 + T:System.Runtime.InteropServices.Marshalling.ExceptionAsNaNMarshaller`1``0:struct + net8.0/System.Runtime.InteropServices.dll + net9.0/System.Runtime.InteropServices.dll + + + CP0021 + T:System.Runtime.InteropServices.Marshalling.ExceptionAsNaNMarshaller`1``0:T:System.Numerics.IFloatingPointIeee754{`0} + net8.0/System.Runtime.InteropServices.dll + net9.0/System.Runtime.InteropServices.dll + + + CP0021 + T:System.Runtime.InteropServices.Marshalling.ExceptionAsNaNMarshaller`1``0:unmanaged + net8.0/System.Runtime.InteropServices.dll + net9.0/System.Runtime.InteropServices.dll + + + CP0021 + T:System.Text.Json.Serialization.JsonNumberEnumConverter`1``0:T:System.Enum + net8.0/System.Text.Json.dll + net9.0/System.Text.Json.dll + \ No newline at end of file diff --git a/src/libraries/apicompat/ApiCompatBaseline.netstandard2.0.xml b/src/libraries/apicompat/ApiCompatBaseline.netstandard2.0.xml index e03170246c0a50..939342fce86a04 100644 --- a/src/libraries/apicompat/ApiCompatBaseline.netstandard2.0.xml +++ b/src/libraries/apicompat/ApiCompatBaseline.netstandard2.0.xml @@ -2791,4 +2791,382 @@ netstandard2.0/System.dll net9.0/System.dll + + CP0021 + M:System.Runtime.InteropServices.Marshal.CreateAggregatedObject``1(System.IntPtr,``0)``0:notnull + netstandard2.0/mscorlib.dll + net9.0/mscorlib.dll + + + CP0021 + M:System.Runtime.InteropServices.Marshal.GetFunctionPointerForDelegate``1(``0)``0:notnull + netstandard2.0/mscorlib.dll + net9.0/mscorlib.dll + + + CP0021 + T:System.Collections.Concurrent.ConcurrentDictionary`2``0:notnull + netstandard2.0/mscorlib.dll + net9.0/mscorlib.dll + + + CP0021 + T:System.Collections.Generic.Dictionary`2``0:notnull + netstandard2.0/mscorlib.dll + net9.0/mscorlib.dll + + + CP0021 + T:System.Collections.ObjectModel.KeyedCollection`2``0:notnull + netstandard2.0/mscorlib.dll + net9.0/mscorlib.dll + + + CP0021 + T:System.Collections.ObjectModel.ReadOnlyDictionary`2``0:notnull + netstandard2.0/mscorlib.dll + net9.0/mscorlib.dll + + + CP0021 + T:System.Tuple`8``7:notnull + netstandard2.0/mscorlib.dll + net9.0/mscorlib.dll + + + CP0021 + M:System.Linq.Enumerable.ToDictionary``2(System.Collections.Generic.IEnumerable{``0},System.Func{``0,``1},System.Collections.Generic.IEqualityComparer{``1})``1:notnull + netstandard2.0/netstandard.dll + net9.0/netstandard.dll + + + CP0021 + M:System.Linq.Enumerable.ToDictionary``2(System.Collections.Generic.IEnumerable{``0},System.Func{``0,``1})``1:notnull + netstandard2.0/netstandard.dll + net9.0/netstandard.dll + + + CP0021 + M:System.Linq.Enumerable.ToDictionary``3(System.Collections.Generic.IEnumerable{``0},System.Func{``0,``1},System.Func{``0,``2},System.Collections.Generic.IEqualityComparer{``1})``1:notnull + netstandard2.0/netstandard.dll + net9.0/netstandard.dll + + + CP0021 + M:System.Linq.Enumerable.ToDictionary``3(System.Collections.Generic.IEnumerable{``0},System.Func{``0,``1},System.Func{``0,``2})``1:notnull + netstandard2.0/netstandard.dll + net9.0/netstandard.dll + + + CP0021 + M:System.Linq.ParallelEnumerable.ToDictionary``2(System.Linq.ParallelQuery{``0},System.Func{``0,``1},System.Collections.Generic.IEqualityComparer{``1})``1:notnull + netstandard2.0/netstandard.dll + net9.0/netstandard.dll + + + CP0021 + M:System.Linq.ParallelEnumerable.ToDictionary``2(System.Linq.ParallelQuery{``0},System.Func{``0,``1})``1:notnull + netstandard2.0/netstandard.dll + net9.0/netstandard.dll + + + CP0021 + M:System.Linq.ParallelEnumerable.ToDictionary``3(System.Linq.ParallelQuery{``0},System.Func{``0,``1},System.Func{``0,``2},System.Collections.Generic.IEqualityComparer{``1})``1:notnull + netstandard2.0/netstandard.dll + net9.0/netstandard.dll + + + CP0021 + M:System.Linq.ParallelEnumerable.ToDictionary``3(System.Linq.ParallelQuery{``0},System.Func{``0,``1},System.Func{``0,``2})``1:notnull + netstandard2.0/netstandard.dll + net9.0/netstandard.dll + + + CP0021 + M:System.Linq.ParallelEnumerable.ToLookup``2(System.Linq.ParallelQuery{``0},System.Func{``0,``1},System.Collections.Generic.IEqualityComparer{``1})``1:notnull + netstandard2.0/netstandard.dll + net9.0/netstandard.dll + + + CP0021 + M:System.Linq.ParallelEnumerable.ToLookup``2(System.Linq.ParallelQuery{``0},System.Func{``0,``1})``1:notnull + netstandard2.0/netstandard.dll + net9.0/netstandard.dll + + + CP0021 + M:System.Linq.ParallelEnumerable.ToLookup``3(System.Linq.ParallelQuery{``0},System.Func{``0,``1},System.Func{``0,``2},System.Collections.Generic.IEqualityComparer{``1})``1:notnull + netstandard2.0/netstandard.dll + net9.0/netstandard.dll + + + CP0021 + M:System.Linq.ParallelEnumerable.ToLookup``3(System.Linq.ParallelQuery{``0},System.Func{``0,``1},System.Func{``0,``2})``1:notnull + netstandard2.0/netstandard.dll + net9.0/netstandard.dll + + + CP0021 + M:System.Runtime.InteropServices.Marshal.CreateAggregatedObject``1(System.IntPtr,``0)``0:notnull + netstandard2.0/netstandard.dll + net9.0/netstandard.dll + + + CP0021 + M:System.Runtime.InteropServices.Marshal.GetFunctionPointerForDelegate``1(``0)``0:notnull + netstandard2.0/netstandard.dll + net9.0/netstandard.dll + + + CP0021 + T:System.Collections.Concurrent.ConcurrentDictionary`2``0:notnull + netstandard2.0/netstandard.dll + net9.0/netstandard.dll + + + CP0021 + T:System.Collections.Generic.Dictionary`2``0:notnull + netstandard2.0/netstandard.dll + net9.0/netstandard.dll + + + CP0021 + T:System.Collections.Generic.SortedDictionary`2``0:notnull + netstandard2.0/netstandard.dll + net9.0/netstandard.dll + + + CP0021 + T:System.Collections.Generic.SortedList`2``0:notnull + netstandard2.0/netstandard.dll + net9.0/netstandard.dll + + + CP0021 + T:System.Collections.ObjectModel.KeyedCollection`2``0:notnull + netstandard2.0/netstandard.dll + net9.0/netstandard.dll + + + CP0021 + T:System.Collections.ObjectModel.ReadOnlyDictionary`2``0:notnull + netstandard2.0/netstandard.dll + net9.0/netstandard.dll + + + CP0021 + T:System.Tuple`8``7:notnull + netstandard2.0/netstandard.dll + net9.0/netstandard.dll + + + CP0021 + T:System.Collections.Concurrent.ConcurrentDictionary`2``0:notnull + netstandard2.0/System.Collections.Concurrent.dll + net9.0/System.Collections.Concurrent.dll + + + CP0021 + T:System.Collections.Generic.Dictionary`2``0:notnull + netstandard2.0/System.Collections.dll + net9.0/System.Collections.dll + + + CP0021 + T:System.Collections.Generic.SortedDictionary`2``0:notnull + netstandard2.0/System.Collections.dll + net9.0/System.Collections.dll + + + CP0021 + T:System.Collections.Generic.SortedList`2``0:notnull + netstandard2.0/System.Collections.dll + net9.0/System.Collections.dll + + + CP0021 + M:System.Linq.Enumerable.ToDictionary``2(System.Collections.Generic.IEnumerable{``0},System.Func{``0,``1},System.Collections.Generic.IEqualityComparer{``1})``1:notnull + netstandard2.0/System.Core.dll + net9.0/System.Core.dll + + + CP0021 + M:System.Linq.Enumerable.ToDictionary``2(System.Collections.Generic.IEnumerable{``0},System.Func{``0,``1})``1:notnull + netstandard2.0/System.Core.dll + net9.0/System.Core.dll + + + CP0021 + M:System.Linq.Enumerable.ToDictionary``3(System.Collections.Generic.IEnumerable{``0},System.Func{``0,``1},System.Func{``0,``2},System.Collections.Generic.IEqualityComparer{``1})``1:notnull + netstandard2.0/System.Core.dll + net9.0/System.Core.dll + + + CP0021 + M:System.Linq.Enumerable.ToDictionary``3(System.Collections.Generic.IEnumerable{``0},System.Func{``0,``1},System.Func{``0,``2})``1:notnull + netstandard2.0/System.Core.dll + net9.0/System.Core.dll + + + CP0021 + M:System.Linq.ParallelEnumerable.ToDictionary``2(System.Linq.ParallelQuery{``0},System.Func{``0,``1},System.Collections.Generic.IEqualityComparer{``1})``1:notnull + netstandard2.0/System.Core.dll + net9.0/System.Core.dll + + + CP0021 + M:System.Linq.ParallelEnumerable.ToDictionary``2(System.Linq.ParallelQuery{``0},System.Func{``0,``1})``1:notnull + netstandard2.0/System.Core.dll + net9.0/System.Core.dll + + + CP0021 + M:System.Linq.ParallelEnumerable.ToDictionary``3(System.Linq.ParallelQuery{``0},System.Func{``0,``1},System.Func{``0,``2},System.Collections.Generic.IEqualityComparer{``1})``1:notnull + netstandard2.0/System.Core.dll + net9.0/System.Core.dll + + + CP0021 + M:System.Linq.ParallelEnumerable.ToDictionary``3(System.Linq.ParallelQuery{``0},System.Func{``0,``1},System.Func{``0,``2})``1:notnull + netstandard2.0/System.Core.dll + net9.0/System.Core.dll + + + CP0021 + M:System.Linq.ParallelEnumerable.ToLookup``2(System.Linq.ParallelQuery{``0},System.Func{``0,``1},System.Collections.Generic.IEqualityComparer{``1})``1:notnull + netstandard2.0/System.Core.dll + net9.0/System.Core.dll + + + CP0021 + M:System.Linq.ParallelEnumerable.ToLookup``2(System.Linq.ParallelQuery{``0},System.Func{``0,``1})``1:notnull + netstandard2.0/System.Core.dll + net9.0/System.Core.dll + + + CP0021 + M:System.Linq.ParallelEnumerable.ToLookup``3(System.Linq.ParallelQuery{``0},System.Func{``0,``1},System.Func{``0,``2},System.Collections.Generic.IEqualityComparer{``1})``1:notnull + netstandard2.0/System.Core.dll + net9.0/System.Core.dll + + + CP0021 + M:System.Linq.ParallelEnumerable.ToLookup``3(System.Linq.ParallelQuery{``0},System.Func{``0,``1},System.Func{``0,``2})``1:notnull + netstandard2.0/System.Core.dll + net9.0/System.Core.dll + + + CP0021 + T:System.Collections.Generic.SortedDictionary`2``0:notnull + netstandard2.0/System.dll + net9.0/System.dll + + + CP0021 + T:System.Collections.Generic.SortedList`2``0:notnull + netstandard2.0/System.dll + net9.0/System.dll + + + CP0021 + M:System.Linq.Enumerable.ToDictionary``2(System.Collections.Generic.IEnumerable{``0},System.Func{``0,``1},System.Collections.Generic.IEqualityComparer{``1})``1:notnull + netstandard2.0/System.Linq.dll + net9.0/System.Linq.dll + + + CP0021 + M:System.Linq.Enumerable.ToDictionary``2(System.Collections.Generic.IEnumerable{``0},System.Func{``0,``1})``1:notnull + netstandard2.0/System.Linq.dll + net9.0/System.Linq.dll + + + CP0021 + M:System.Linq.Enumerable.ToDictionary``3(System.Collections.Generic.IEnumerable{``0},System.Func{``0,``1},System.Func{``0,``2},System.Collections.Generic.IEqualityComparer{``1})``1:notnull + netstandard2.0/System.Linq.dll + net9.0/System.Linq.dll + + + CP0021 + M:System.Linq.Enumerable.ToDictionary``3(System.Collections.Generic.IEnumerable{``0},System.Func{``0,``1},System.Func{``0,``2})``1:notnull + netstandard2.0/System.Linq.dll + net9.0/System.Linq.dll + + + CP0021 + M:System.Linq.ParallelEnumerable.ToDictionary``2(System.Linq.ParallelQuery{``0},System.Func{``0,``1},System.Collections.Generic.IEqualityComparer{``1})``1:notnull + netstandard2.0/System.Linq.Parallel.dll + net9.0/System.Linq.Parallel.dll + + + CP0021 + M:System.Linq.ParallelEnumerable.ToDictionary``2(System.Linq.ParallelQuery{``0},System.Func{``0,``1})``1:notnull + netstandard2.0/System.Linq.Parallel.dll + net9.0/System.Linq.Parallel.dll + + + CP0021 + M:System.Linq.ParallelEnumerable.ToDictionary``3(System.Linq.ParallelQuery{``0},System.Func{``0,``1},System.Func{``0,``2},System.Collections.Generic.IEqualityComparer{``1})``1:notnull + netstandard2.0/System.Linq.Parallel.dll + net9.0/System.Linq.Parallel.dll + + + CP0021 + M:System.Linq.ParallelEnumerable.ToDictionary``3(System.Linq.ParallelQuery{``0},System.Func{``0,``1},System.Func{``0,``2})``1:notnull + netstandard2.0/System.Linq.Parallel.dll + net9.0/System.Linq.Parallel.dll + + + CP0021 + M:System.Linq.ParallelEnumerable.ToLookup``2(System.Linq.ParallelQuery{``0},System.Func{``0,``1},System.Collections.Generic.IEqualityComparer{``1})``1:notnull + netstandard2.0/System.Linq.Parallel.dll + net9.0/System.Linq.Parallel.dll + + + CP0021 + M:System.Linq.ParallelEnumerable.ToLookup``2(System.Linq.ParallelQuery{``0},System.Func{``0,``1})``1:notnull + netstandard2.0/System.Linq.Parallel.dll + net9.0/System.Linq.Parallel.dll + + + CP0021 + M:System.Linq.ParallelEnumerable.ToLookup``3(System.Linq.ParallelQuery{``0},System.Func{``0,``1},System.Func{``0,``2},System.Collections.Generic.IEqualityComparer{``1})``1:notnull + netstandard2.0/System.Linq.Parallel.dll + net9.0/System.Linq.Parallel.dll + + + CP0021 + M:System.Linq.ParallelEnumerable.ToLookup``3(System.Linq.ParallelQuery{``0},System.Func{``0,``1},System.Func{``0,``2})``1:notnull + netstandard2.0/System.Linq.Parallel.dll + net9.0/System.Linq.Parallel.dll + + + CP0021 + T:System.Collections.ObjectModel.KeyedCollection`2``0:notnull + netstandard2.0/System.ObjectModel.dll + net9.0/System.ObjectModel.dll + + + CP0021 + T:System.Collections.ObjectModel.ReadOnlyDictionary`2``0:notnull + netstandard2.0/System.ObjectModel.dll + net9.0/System.ObjectModel.dll + + + CP0021 + T:System.Tuple`8``7:notnull + netstandard2.0/System.Runtime.dll + net9.0/System.Runtime.dll + + + CP0021 + M:System.Runtime.InteropServices.Marshal.CreateAggregatedObject``1(System.IntPtr,``0)``0:notnull + netstandard2.0/System.Runtime.InteropServices.dll + net9.0/System.Runtime.InteropServices.dll + + + CP0021 + M:System.Runtime.InteropServices.Marshal.GetFunctionPointerForDelegate``1(``0)``0:notnull + netstandard2.0/System.Runtime.InteropServices.dll + net9.0/System.Runtime.InteropServices.dll + \ No newline at end of file diff --git a/src/libraries/apicompat/ApiCompatBaseline.netstandard2.1.xml b/src/libraries/apicompat/ApiCompatBaseline.netstandard2.1.xml index f7c8eb8430ef04..f0ef02d93c1a19 100644 --- a/src/libraries/apicompat/ApiCompatBaseline.netstandard2.1.xml +++ b/src/libraries/apicompat/ApiCompatBaseline.netstandard2.1.xml @@ -877,4 +877,130 @@ netstandard2.1/netstandard.dll net9.0/netstandard.dll + + CP0021 + M:System.Linq.Enumerable.ToDictionary``2(System.Collections.Generic.IEnumerable{``0},System.Func{``0,``1},System.Collections.Generic.IEqualityComparer{``1})``1:notnull + netstandard2.1/netstandard.dll + net9.0/netstandard.dll + + + CP0021 + M:System.Linq.Enumerable.ToDictionary``2(System.Collections.Generic.IEnumerable{``0},System.Func{``0,``1})``1:notnull + netstandard2.1/netstandard.dll + net9.0/netstandard.dll + + + CP0021 + M:System.Linq.Enumerable.ToDictionary``3(System.Collections.Generic.IEnumerable{``0},System.Func{``0,``1},System.Func{``0,``2},System.Collections.Generic.IEqualityComparer{``1})``1:notnull + netstandard2.1/netstandard.dll + net9.0/netstandard.dll + + + CP0021 + M:System.Linq.Enumerable.ToDictionary``3(System.Collections.Generic.IEnumerable{``0},System.Func{``0,``1},System.Func{``0,``2})``1:notnull + netstandard2.1/netstandard.dll + net9.0/netstandard.dll + + + CP0021 + M:System.Linq.ParallelEnumerable.ToDictionary``2(System.Linq.ParallelQuery{``0},System.Func{``0,``1},System.Collections.Generic.IEqualityComparer{``1})``1:notnull + netstandard2.1/netstandard.dll + net9.0/netstandard.dll + + + CP0021 + M:System.Linq.ParallelEnumerable.ToDictionary``2(System.Linq.ParallelQuery{``0},System.Func{``0,``1})``1:notnull + netstandard2.1/netstandard.dll + net9.0/netstandard.dll + + + CP0021 + M:System.Linq.ParallelEnumerable.ToDictionary``3(System.Linq.ParallelQuery{``0},System.Func{``0,``1},System.Func{``0,``2},System.Collections.Generic.IEqualityComparer{``1})``1:notnull + netstandard2.1/netstandard.dll + net9.0/netstandard.dll + + + CP0021 + M:System.Linq.ParallelEnumerable.ToDictionary``3(System.Linq.ParallelQuery{``0},System.Func{``0,``1},System.Func{``0,``2})``1:notnull + netstandard2.1/netstandard.dll + net9.0/netstandard.dll + + + CP0021 + M:System.Linq.ParallelEnumerable.ToLookup``2(System.Linq.ParallelQuery{``0},System.Func{``0,``1},System.Collections.Generic.IEqualityComparer{``1})``1:notnull + netstandard2.1/netstandard.dll + net9.0/netstandard.dll + + + CP0021 + M:System.Linq.ParallelEnumerable.ToLookup``2(System.Linq.ParallelQuery{``0},System.Func{``0,``1})``1:notnull + netstandard2.1/netstandard.dll + net9.0/netstandard.dll + + + CP0021 + M:System.Linq.ParallelEnumerable.ToLookup``3(System.Linq.ParallelQuery{``0},System.Func{``0,``1},System.Func{``0,``2},System.Collections.Generic.IEqualityComparer{``1})``1:notnull + netstandard2.1/netstandard.dll + net9.0/netstandard.dll + + + CP0021 + M:System.Linq.ParallelEnumerable.ToLookup``3(System.Linq.ParallelQuery{``0},System.Func{``0,``1},System.Func{``0,``2})``1:notnull + netstandard2.1/netstandard.dll + net9.0/netstandard.dll + + + CP0021 + M:System.Runtime.InteropServices.Marshal.CreateAggregatedObject``1(System.IntPtr,``0)``0:notnull + netstandard2.1/netstandard.dll + net9.0/netstandard.dll + + + CP0021 + M:System.Runtime.InteropServices.Marshal.GetFunctionPointerForDelegate``1(``0)``0:notnull + netstandard2.1/netstandard.dll + net9.0/netstandard.dll + + + CP0021 + T:System.Collections.Concurrent.ConcurrentDictionary`2``0:notnull + netstandard2.1/netstandard.dll + net9.0/netstandard.dll + + + CP0021 + T:System.Collections.Generic.Dictionary`2``0:notnull + netstandard2.1/netstandard.dll + net9.0/netstandard.dll + + + CP0021 + T:System.Collections.Generic.SortedDictionary`2``0:notnull + netstandard2.1/netstandard.dll + net9.0/netstandard.dll + + + CP0021 + T:System.Collections.Generic.SortedList`2``0:notnull + netstandard2.1/netstandard.dll + net9.0/netstandard.dll + + + CP0021 + T:System.Collections.ObjectModel.KeyedCollection`2``0:notnull + netstandard2.1/netstandard.dll + net9.0/netstandard.dll + + + CP0021 + T:System.Collections.ObjectModel.ReadOnlyDictionary`2``0:notnull + netstandard2.1/netstandard.dll + net9.0/netstandard.dll + + + CP0021 + T:System.Tuple`8``7:notnull + netstandard2.1/netstandard.dll + net9.0/netstandard.dll + \ No newline at end of file From 264023ee550d71b1609788145dd03e47ed77c943 Mon Sep 17 00:00:00 2001 From: Andrew Au Date: Thu, 25 Apr 2024 19:57:34 -0700 Subject: [PATCH 092/161] Fix compact time computation (#100599) --- src/coreclr/gc/gc.cpp | 18 ++---------------- 1 file changed, 2 insertions(+), 16 deletions(-) diff --git a/src/coreclr/gc/gc.cpp b/src/coreclr/gc/gc.cpp index e43047cf6e113a..0861a15d274d7c 100644 --- a/src/coreclr/gc/gc.cpp +++ b/src/coreclr/gc/gc.cpp @@ -29966,7 +29966,7 @@ void gc_heap::mark_phase (int condemned_gen_number) #endif //MULTIPLE_HEAPS { #ifdef FEATURE_EVENT_TRACE - record_mark_time (gc_time_info[time_plan - 1], current_mark_time, last_mark_time); + record_mark_time (gc_time_info[time_mark_long_weak], current_mark_time, last_mark_time); gc_time_info[time_plan] = last_mark_time; #endif //FEATURE_EVENT_TRACE @@ -33964,26 +33964,12 @@ void gc_heap::plan_phase (int condemned_gen_number) if (gc_t_join.joined()) #endif //MULTIPLE_HEAPS { -#ifdef FEATURE_EVENT_TRACE - if (informational_event_enabled_p) - { - uint64_t current_time = GetHighPrecisionTimeStamp(); - gc_time_info[time_compact] = current_time - gc_time_info[time_compact]; - } -#endif //FEATURE_EVENT_TRACE - #ifdef MULTIPLE_HEAPS for (int i = 0; i < n_heaps; i++) { -#ifdef USE_REGIONS - g_heaps [i]->rearrange_uoh_segments(); -#endif //USE_REGIONS g_heaps [i]->rearrange_heap_segments (TRUE); } #else //MULTIPLE_HEAPS -#ifdef USE_REGIONS - rearrange_uoh_segments(); -#endif //USE_REGIONS rearrange_heap_segments (TRUE); #endif //MULTIPLE_HEAPS @@ -34018,7 +34004,7 @@ void gc_heap::plan_phase (int condemned_gen_number) #endif //MULTIPLE_HEAPS #ifdef FEATURE_EVENT_TRACE - if (informational_event_enabled_p && (condemned_gen_number < (max_generation -1))) + if (informational_event_enabled_p) { uint64_t current_time = GetHighPrecisionTimeStamp(); gc_time_info[time_compact] = current_time - gc_time_info[time_compact]; From 2d335f34af696feda5fc3e80f98c991b3aeb93d0 Mon Sep 17 00:00:00 2001 From: Elinor Fung Date: Thu, 25 Apr 2024 20:30:44 -0700 Subject: [PATCH 093/161] [cdac] Read/store globals from contract descriptor (#101450) - Map indirect global values to corresponding values in `pointer_data` array from contract descriptor - Add `[Try]Read`, `[Try]ReadPointer`, `[Try]ReadGlobal` and `[Try]ReadGlobalPointer` to `Target` - Make cDAC implementation of `ISOSDacInterface9.GetBreakingChangeVersion` read value from globals - Create test helpers for mocking out reading from the target and providing a contract descriptor for different bitness/endianness - Add unit tests for reading global values (direct and indirect) --- .../datacontracts/contract-descriptor.md | 4 +- src/coreclr/debug/daccess/cdac.cpp | 30 +- src/coreclr/debug/daccess/cdac.h | 9 +- src/coreclr/debug/daccess/daccess.cpp | 2 +- .../managed/cdacreader/src/Constants.cs | 13 + .../cdacreader/src/Legacy/SOSDacImpl.cs | 3 +- src/native/managed/cdacreader/src/Target.cs | 142 +++++-- .../managed/cdacreader/tests/TargetTests.cs | 358 ++++++++++++++++++ 8 files changed, 507 insertions(+), 54 deletions(-) create mode 100644 src/native/managed/cdacreader/src/Constants.cs create mode 100644 src/native/managed/cdacreader/tests/TargetTests.cs diff --git a/docs/design/datacontracts/contract-descriptor.md b/docs/design/datacontracts/contract-descriptor.md index e63ae11b4ae936..fbd58eb33eb9a5 100644 --- a/docs/design/datacontracts/contract-descriptor.md +++ b/docs/design/datacontracts/contract-descriptor.md @@ -45,7 +45,7 @@ reserved bits should be written as zero. Diagnostic tooling may ignore non-zero The `descriptor` is a pointer to a UTF-8 JSON string described in [data descriptor physical layout](./data_descriptor.md#Physical_JSON_descriptor). The total number of bytes is given by `descriptor_size`. -The auxiliary data for the JSON descriptor is stored at the location `aux_data` in `aux_data_count` pointer-sized slots. +The auxiliary data for the JSON descriptor is stored at the location `pointer_data` in `pointer_data_count` pointer-sized slots. ### Architecture properties @@ -83,7 +83,7 @@ a JSON integer constant. "globals": { "FEATURE_COMINTEROP": 0, - "s_pThreadStore": [ 0 ] // indirect from aux data offset 0 + "s_pThreadStore": [ 0 ] // indirect from pointer data offset 0 }, "contracts": {"Thread": 1, "GCHandle": 1, "ThreadStore": 1} } diff --git a/src/coreclr/debug/daccess/cdac.cpp b/src/coreclr/debug/daccess/cdac.cpp index a4146709ec7233..b7bb7585e6bcf7 100644 --- a/src/coreclr/debug/daccess/cdac.cpp +++ b/src/coreclr/debug/daccess/cdac.cpp @@ -41,27 +41,31 @@ CDAC CDAC::Create(uint64_t descriptorAddr, ICorDebugDataTarget* target) { HMODULE cdacLib; if (!TryLoadCDACLibrary(&cdacLib)) - return CDAC::Invalid(); + return {}; - return CDAC{cdacLib, descriptorAddr, target}; + decltype(&cdac_reader_init) init = reinterpret_cast(::GetProcAddress(cdacLib, "cdac_reader_init")); + _ASSERTE(init != nullptr); + + intptr_t handle; + if (init(descriptorAddr, &ReadFromTargetCallback, target, &handle) != 0) + { + ::FreeLibrary(cdacLib); + return {}; + } + + return CDAC{cdacLib, handle, target}; } -CDAC::CDAC(HMODULE module, uint64_t descriptorAddr, ICorDebugDataTarget* target) - : m_module(module) +CDAC::CDAC(HMODULE module, intptr_t handle, ICorDebugDataTarget* target) + : m_module{module} + , m_cdac_handle{handle} , m_target{target} { - if (m_module == NULL) - { - m_cdac_handle = 0; - return; - } + _ASSERTE(m_module != NULL && m_cdac_handle != 0 && m_target != NULL); m_target->AddRef(); - decltype(&cdac_reader_init) init = reinterpret_cast(::GetProcAddress(m_module, "cdac_reader_init")); decltype(&cdac_reader_get_sos_interface) getSosInterface = reinterpret_cast(::GetProcAddress(m_module, "cdac_reader_get_sos_interface")); - _ASSERTE(init != nullptr && getSosInterface != nullptr); - - init(descriptorAddr, &ReadFromTargetCallback, m_target, &m_cdac_handle); + _ASSERTE(getSosInterface != nullptr); getSosInterface(m_cdac_handle, &m_sos); } diff --git a/src/coreclr/debug/daccess/cdac.h b/src/coreclr/debug/daccess/cdac.h index d5c0eecb0f7373..51078ffcf2e46b 100644 --- a/src/coreclr/debug/daccess/cdac.h +++ b/src/coreclr/debug/daccess/cdac.h @@ -9,12 +9,9 @@ class CDAC final public: // static static CDAC Create(uint64_t descriptorAddr, ICorDebugDataTarget *pDataTarget); - static CDAC Invalid() - { - return CDAC{nullptr, 0, nullptr}; - } - public: + CDAC() = default; + CDAC(const CDAC&) = delete; CDAC& operator=(const CDAC&) = delete; @@ -56,7 +53,7 @@ class CDAC final IUnknown* SosInterface(); private: - CDAC(HMODULE module, uint64_t descriptorAddr, ICorDebugDataTarget* target); + CDAC(HMODULE module, intptr_t handle, ICorDebugDataTarget* target); private: HMODULE m_module; diff --git a/src/coreclr/debug/daccess/daccess.cpp b/src/coreclr/debug/daccess/daccess.cpp index 971b8b90980b32..37e7d37edd9f9c 100644 --- a/src/coreclr/debug/daccess/daccess.cpp +++ b/src/coreclr/debug/daccess/daccess.cpp @@ -3038,7 +3038,7 @@ class DacStreamManager //---------------------------------------------------------------------------- ClrDataAccess::ClrDataAccess(ICorDebugDataTarget * pTarget, ICLRDataTarget * pLegacyTarget/*=0*/) - : m_cdac{CDAC::Invalid()} + : m_cdac{} { SUPPORTS_DAC_HOST_ONLY; // ctor does no marshalling - don't check with DacCop diff --git a/src/native/managed/cdacreader/src/Constants.cs b/src/native/managed/cdacreader/src/Constants.cs new file mode 100644 index 00000000000000..0fbcaa0a246c73 --- /dev/null +++ b/src/native/managed/cdacreader/src/Constants.cs @@ -0,0 +1,13 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace Microsoft.Diagnostics.DataContractReader; + +internal static class Constants +{ + internal static class Globals + { + // See src/coreclr/debug/runtimeinfo/datadescriptor.h + internal const string SOSBreakingChangeVersion = nameof(SOSBreakingChangeVersion); + } +} diff --git a/src/native/managed/cdacreader/src/Legacy/SOSDacImpl.cs b/src/native/managed/cdacreader/src/Legacy/SOSDacImpl.cs index b0640c44efc98d..261aa034c3f894 100644 --- a/src/native/managed/cdacreader/src/Legacy/SOSDacImpl.cs +++ b/src/native/managed/cdacreader/src/Legacy/SOSDacImpl.cs @@ -35,8 +35,7 @@ public SOSDacImpl(Target target) public int GetBreakingChangeVersion() { - // TODO: Return non-hard-coded version - return 4; + return _target.ReadGlobal(Constants.Globals.SOSBreakingChangeVersion); } public unsafe int GetCCWData(ulong ccw, void* data) => HResults.E_NOTIMPL; diff --git a/src/native/managed/cdacreader/src/Target.cs b/src/native/managed/cdacreader/src/Target.cs index 049a9f80ed2265..c2e09d9d0fa116 100644 --- a/src/native/managed/cdacreader/src/Target.cs +++ b/src/native/managed/cdacreader/src/Target.cs @@ -4,6 +4,8 @@ using System; using System.Buffers.Binary; using System.Collections.Generic; +using System.Numerics; +using System.Runtime.CompilerServices; namespace Microsoft.Diagnostics.DataContractReader; @@ -15,7 +17,7 @@ public struct TargetPointer public TargetPointer(ulong value) => Value = value; } -internal sealed unsafe class Target +public sealed unsafe class Target { private const int StackAllocByteThreshold = 1024; @@ -29,7 +31,7 @@ private readonly struct Configuration private readonly Reader _reader; private readonly IReadOnlyDictionary _contracts = new Dictionary(); - private readonly TargetPointer[] _pointerData = []; + private readonly IReadOnlyDictionary _globals = new Dictionary(); public static bool TryCreate(ulong contractDescriptor, delegate* unmanaged readFromTarget, void* readContext, out Target? target) { @@ -49,11 +51,30 @@ private Target(Configuration config, ContractDescriptorParser.ContractDescriptor _config = config; _reader = reader; - // TODO: [cdac] Read globals and types + // TODO: [cdac] Read types // note: we will probably want to store the globals and types into a more usable form _contracts = descriptor.Contracts ?? []; - _pointerData = pointerData; + // Read globals and map indirect values to pointer data + if (descriptor.Globals is not null) + { + Dictionary globals = []; + foreach ((string name, ContractDescriptorParser.GlobalDescriptor global) in descriptor.Globals) + { + ulong value = global.Value; + if (global.Indirect) + { + if (value >= (ulong)pointerData.Length) + throw new InvalidOperationException($"Invalid pointer data index {value}."); + + value = pointerData[value].Value; + } + + globals[name] = (value, global.Type); + } + + _globals = globals; + } } // See docs/design/datacontracts/contract-descriptor.md @@ -81,7 +102,7 @@ private static bool TryReadContractDescriptor( return false; // Flags - uint32_t - if (!TryReadUInt32(address, isLittleEndian, reader, out uint flags)) + if (!TryRead(address, isLittleEndian, reader, out uint flags)) return false; address += sizeof(uint); @@ -92,7 +113,7 @@ private static bool TryReadContractDescriptor( config = new Configuration { IsLittleEndian = isLittleEndian, PointerSize = pointerSize }; // Descriptor size - uint32_t - if (!TryReadUInt32(address, config.IsLittleEndian, reader, out uint descriptorSize)) + if (!TryRead(address, config.IsLittleEndian, reader, out uint descriptorSize)) return false; address += sizeof(uint); @@ -104,7 +125,7 @@ private static bool TryReadContractDescriptor( address += (uint)pointerSize; // Pointer data count - uint32_t - if (!TryReadUInt32(address, config.IsLittleEndian, reader, out uint pointerDataCount)) + if (!TryRead(address, config.IsLittleEndian, reader, out uint pointerDataCount)) return false; address += sizeof(uint); @@ -138,30 +159,33 @@ private static bool TryReadContractDescriptor( return true; } - public uint ReadUInt32(ulong address) + public T Read(ulong address, out T value) where T : unmanaged, IBinaryInteger, IMinMaxValue { - if (!TryReadUInt32(address, out uint value)) - throw new InvalidOperationException($"Failed to read uint32 at 0x{address:x8}."); + if (!TryRead(address, out value)) + throw new InvalidOperationException($"Failed to read {typeof(T)} at 0x{address:x8}."); return value; } - public bool TryReadUInt32(ulong address, out uint value) - => TryReadUInt32(address, _config.IsLittleEndian, _reader, out value); + public bool TryRead(ulong address, out T value) where T : unmanaged, IBinaryInteger, IMinMaxValue + => TryRead(address, _config.IsLittleEndian, _reader, out value); - private static bool TryReadUInt32(ulong address, bool isLittleEndian, Reader reader, out uint value) + private static bool TryRead(ulong address, bool isLittleEndian, Reader reader, out T value) where T : unmanaged, IBinaryInteger, IMinMaxValue { - value = 0; - - Span buffer = stackalloc byte[sizeof(uint)]; + value = default; + Span buffer = stackalloc byte[sizeof(T)]; if (reader.ReadFromTarget(address, buffer) < 0) return false; - value = isLittleEndian - ? BinaryPrimitives.ReadUInt32LittleEndian(buffer) - : BinaryPrimitives.ReadUInt32BigEndian(buffer); + return isLittleEndian + ? T.TryReadLittleEndian(buffer, !IsSigned(), out value) + : T.TryReadBigEndian(buffer, !IsSigned(), out value); + } - return true; + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static bool IsSigned() where T : struct, INumberBase, IMinMaxValue + { + return T.IsNegative(T.MinValue); } public TargetPointer ReadPointer(ulong address) @@ -183,21 +207,79 @@ private static bool TryReadPointer(ulong address, Configuration config, Reader r if (reader.ReadFromTarget(address, buffer) < 0) return false; - if (config.PointerSize == sizeof(uint)) + if (config.PointerSize == sizeof(uint) + && TryRead(address, config.IsLittleEndian, reader, out uint value32)) { - pointer = new TargetPointer( - config.IsLittleEndian - ? BinaryPrimitives.ReadUInt32LittleEndian(buffer) - : BinaryPrimitives.ReadUInt32BigEndian(buffer)); + pointer = new TargetPointer(value32); + return true; } - else if (config.PointerSize == sizeof(ulong)) + else if (config.PointerSize == sizeof(ulong) + && TryRead(address, config.IsLittleEndian, reader, out ulong value64)) { - pointer = new TargetPointer( - config.IsLittleEndian - ? BinaryPrimitives.ReadUInt64LittleEndian(buffer) - : BinaryPrimitives.ReadUInt64BigEndian(buffer)); + pointer = new TargetPointer(value64); + return true; } + return false; + } + + public T ReadGlobal(string name) where T : struct, INumber + { + if (!TryReadGlobal(name, out T value)) + throw new InvalidOperationException($"Failed to read global {typeof(T)} '{name}'."); + + return value; + } + + public bool TryReadGlobal(string name, out T value) where T : struct, INumber, INumberBase + { + value = default; + if (!_globals.TryGetValue(name, out (ulong Value, string? Type) global)) + return false; + + // TODO: [cdac] Move type validation out of the read such that it does not have to happen for every read + if (global.Type is not null) + { + string? expectedType = Type.GetTypeCode(typeof(T)) switch + { + TypeCode.SByte => "int8", + TypeCode.Byte => "uint8", + TypeCode.Int16 => "int16", + TypeCode.UInt16 => "uint16", + TypeCode.Int32 => "int32", + TypeCode.UInt32 => "uint32", + TypeCode.Int64 => "int64", + TypeCode.UInt64 => "uint64", + _ => null, + }; + if (expectedType is null || global.Type != expectedType) + { + return false; + } + } + + value = T.CreateChecked(global.Value); + return true; + } + + public TargetPointer ReadGlobalPointer(string name) + { + if (!TryReadGlobalPointer(name, out TargetPointer pointer)) + throw new InvalidOperationException($"Failed to read global pointer '{name}'."); + + return pointer; + } + + public bool TryReadGlobalPointer(string name, out TargetPointer pointer) + { + pointer = TargetPointer.Null; + if (!_globals.TryGetValue(name, out (ulong Value, string? Type) global)) + return false; + + if (global.Type is not null && Array.IndexOf(["pointer", "nint", "nuint"], global.Type) == -1) + return false; + + pointer = new TargetPointer(global.Value); return true; } diff --git a/src/native/managed/cdacreader/tests/TargetTests.cs b/src/native/managed/cdacreader/tests/TargetTests.cs new file mode 100644 index 00000000000000..5a8569c1b557cb --- /dev/null +++ b/src/native/managed/cdacreader/tests/TargetTests.cs @@ -0,0 +1,358 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Buffers.Binary; +using System.Linq; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Text; +using Xunit; + +namespace Microsoft.Diagnostics.DataContractReader.UnitTests; + +public unsafe class TargetTests +{ + private const ulong ContractDescriptorAddr = 0xaaaaaaaa; + private const uint JsonDescriptorAddr = 0xdddddddd; + private const uint PointerDataAddr = 0xeeeeeeee; + + private static readonly (string Name, ulong Value, string? Type)[] TestGlobals = + [ + ("value", (ulong)sbyte.MaxValue, null), + ("int8Value", 0x12, "int8"), + ("uint8Value", 0x12, "uint8"), + ("int16Value", 0x1234, "int16"), + ("uint16Value", 0x1234, "uint16"), + ("int32Value", 0x12345678, "int32"), + ("uint32Value", 0x12345678, "uint32"), + ("int64Value", 0x123456789abcdef0, "int64"), + ("uint64Value", 0x123456789abcdef0, "uint64"), + ("nintValue", 0xabcdef0, "nint"), + ("nuintValue", 0xabcdef0, "nuint"), + ("pointerValue", 0xabcdef0, "pointer"), + ]; + + [Theory] + [InlineData(true, true)] + [InlineData(true, false)] + [InlineData(false, true)] + [InlineData(false, false)] + public void ReadGlobalValue(bool isLittleEndian, bool is64Bit) + { + string globalsJson = string.Join(',', TestGlobals.Select(i => $"\"{i.Name}\": {(i.Type is null ? i.Value.ToString() : $"[{i.Value}, \"{i.Type}\"]")}")); + byte[] json = Encoding.UTF8.GetBytes($$""" + { + "version": 0, + "baseline": "empty", + "contracts": {}, + "types": {}, + "globals": { {{globalsJson}} } + } + """); + Span descriptor = stackalloc byte[ContractDescriptor.Size(is64Bit)]; + ContractDescriptor.Fill(descriptor, isLittleEndian, is64Bit, json.Length, 0); + fixed (byte* jsonPtr = json) + { + ReadContext context = new ReadContext + { + ContractDescriptor = (byte*)Unsafe.AsPointer(ref MemoryMarshal.GetReference(descriptor)), + ContractDescriptorLength = descriptor.Length, + JsonDescriptor = jsonPtr, + JsonDescriptorLength = json.Length, + }; + + bool success = Target.TryCreate(ContractDescriptorAddr, &ReadFromTarget, &context, out Target? target); + Assert.True(success); + + ValidateGlobals(target, TestGlobals); + } + } + + [Theory] + [InlineData(true, true)] + [InlineData(true, false)] + [InlineData(false, true)] + [InlineData(false, false)] + public void ReadIndirectGlobalValue(bool isLittleEndian, bool is64Bit) + { + int pointerSize = is64Bit ? sizeof(ulong) : sizeof(uint); + Span pointerData = stackalloc byte[TestGlobals.Length * pointerSize]; + for (int i = 0; i < TestGlobals.Length; i++) + { + var (_, value, _) = TestGlobals[i]; + WritePointer(pointerData.Slice(i * pointerSize), value, isLittleEndian, pointerSize); + } + + string globalsJson = string.Join(',', TestGlobals.Select((g, i) => $"\"{g.Name}\": {(g.Type is null ? $"[{i}]" : $"[[{i}], \"{g.Type}\"]")}")); + byte[] json = Encoding.UTF8.GetBytes($$""" + { + "version": 0, + "baseline": "empty", + "contracts": {}, + "types": {}, + "globals": { {{globalsJson}} } + } + """); + Span descriptor = stackalloc byte[ContractDescriptor.Size(is64Bit)]; + ContractDescriptor.Fill(descriptor, isLittleEndian, is64Bit, json.Length, pointerData.Length / pointerSize); + fixed (byte* jsonPtr = json) + { + ReadContext context = new ReadContext + { + ContractDescriptor = (byte*)Unsafe.AsPointer(ref MemoryMarshal.GetReference(descriptor)), + ContractDescriptorLength = descriptor.Length, + JsonDescriptor = jsonPtr, + JsonDescriptorLength = json.Length, + PointerData = (byte*)Unsafe.AsPointer(ref MemoryMarshal.GetReference(pointerData)), + PointerDataLength = pointerData.Length + }; + + bool success = Target.TryCreate(ContractDescriptorAddr, &ReadFromTarget, &context, out Target? target); + Assert.True(success); + + // Indirect values are pointer-sized, so max 32-bits for a 32-bit target + var expected = is64Bit + ? TestGlobals + : TestGlobals.Select(g => (g.Name, g.Value & 0xffffffff, g.Type)).ToArray(); + + ValidateGlobals(target, expected); + } + } + + private static void WritePointer(Span dest, ulong value, bool isLittleEndian, int pointerSize) + { + if (pointerSize == sizeof(ulong)) + { + if (isLittleEndian) + { + BinaryPrimitives.WriteUInt64LittleEndian(dest, value); + } + else + { + BinaryPrimitives.WriteUInt64BigEndian(dest, value); + } + } + else if (pointerSize == sizeof(uint)) + { + if (isLittleEndian) + { + BinaryPrimitives.WriteUInt32LittleEndian(dest, (uint)value); + } + else + { + BinaryPrimitives.WriteUInt32BigEndian(dest, (uint)value); + } + } + } + + private static void ValidateGlobals( + Target target, + (string Name, ulong Value, string? Type)[] globals, + [CallerMemberName] string caller = "", + [CallerFilePath] string filePath = "", + [CallerLineNumber] int lineNumber = 0) + { + foreach (var (name, value, type) in globals) + { + // Validate that each global can/cannot be read successfully based on its type + // and that it matches the expected value if successfully read + { + bool success = target.TryReadGlobal(name, out sbyte actual); + AssertEqualsWithCallerInfo(type is null || type == "int8", success); + if (success) + AssertEqualsWithCallerInfo((sbyte)value, actual); + } + { + bool success = target.TryReadGlobal(name, out byte actual); + AssertEqualsWithCallerInfo(type is null || type == "uint8", success); + if (success) + AssertEqualsWithCallerInfo(value, actual); + } + { + bool success = target.TryReadGlobal(name, out short actual); + AssertEqualsWithCallerInfo(type is null || type == "int16", success); + if (success) + AssertEqualsWithCallerInfo((short)value, actual); + } + { + bool success = target.TryReadGlobal(name, out ushort actual); + AssertEqualsWithCallerInfo(type is null || type == "uint16", success); + if (success) + AssertEqualsWithCallerInfo(value, actual); + } + { + bool success = target.TryReadGlobal(name, out int actual); + AssertEqualsWithCallerInfo(type is null || type == "int32", success); + if (success) + AssertEqualsWithCallerInfo((int)value, actual); + } + { + bool success = target.TryReadGlobal(name, out uint actual); + AssertEqualsWithCallerInfo(type is null || type == "uint32", success); + if (success) + AssertEqualsWithCallerInfo(value, actual); + } + { + bool success = target.TryReadGlobal(name, out long actual); + AssertEqualsWithCallerInfo(type is null || type == "int64", success); + if (success) + AssertEqualsWithCallerInfo((long)value, actual); + } + { + bool success = target.TryReadGlobal(name, out ulong actual); + AssertEqualsWithCallerInfo(type is null || type == "uint64", success); + if (success) + AssertEqualsWithCallerInfo(value, actual); + } + { + bool success = target.TryReadGlobalPointer(name, out TargetPointer actual); + AssertEqualsWithCallerInfo(type is null || type == "pointer" || type == "nint" || type == "nuint", success); + if (success) + AssertEqualsWithCallerInfo(value, actual.Value); + } + } + + void AssertEqualsWithCallerInfo(T expected, T actual) where T : unmanaged + { + Assert.True(expected.Equals(actual), $"Expected: {expected}. Actual: {actual}. [test case: {caller} in {filePath}:{lineNumber}]"); + } + } + + [UnmanagedCallersOnly] + private static int ReadFromTarget(ulong address, byte* buffer, uint length, void* context) + { + ReadContext* readContext = (ReadContext*)context; + var span = new Span(buffer, (int)length); + + // Populate the span with the requested portion of the contract descriptor + if (address >= ContractDescriptorAddr && address <= ContractDescriptorAddr + (ulong)readContext->ContractDescriptorLength - length) + { + ulong offset = address - ContractDescriptorAddr; + new ReadOnlySpan(readContext->ContractDescriptor + offset, (int)length).CopyTo(span); + return 0; + } + + // Populate the span with the JSON descriptor - this assumes the product will read it all at once. + if (address == JsonDescriptorAddr) + { + new ReadOnlySpan(readContext->JsonDescriptor, readContext->JsonDescriptorLength).CopyTo(span); + return 0; + } + + // Populate the span with the requested portion of the pointer data + if (address >= PointerDataAddr && address <= PointerDataAddr + (ulong)readContext->PointerDataLength - length) + { + ulong offset = address - PointerDataAddr; + new ReadOnlySpan(readContext->PointerData + offset, (int)length).CopyTo(span); + return 0; + } + + return -1; + } + + // Used by ReadFromTarget to return the appropriate bytes + private struct ReadContext + { + public byte* ContractDescriptor; + public int ContractDescriptorLength; + + public byte* JsonDescriptor; + public int JsonDescriptorLength; + + public byte* PointerData; + public int PointerDataLength; + } + + private static class ContractDescriptor + { + public static int Size(bool is64Bit) => is64Bit ? sizeof(ContractDescriptor64) : sizeof(ContractDescriptor32); + + public static void Fill(Span dest, bool isLittleEndian, bool is64Bit, int jsonDescriptorSize, int pointerDataCount) + { + if (is64Bit) + { + ContractDescriptor64.Fill(dest, isLittleEndian, jsonDescriptorSize, pointerDataCount); + } + else + { + ContractDescriptor32.Fill(dest, isLittleEndian, jsonDescriptorSize, pointerDataCount); + } + } + + private struct ContractDescriptor32 + { + public ulong Magic = BitConverter.ToUInt64("DNCCDAC\0"u8); + public uint Flags = 0x2 /*32-bit*/ | 0x1; + public uint DescriptorSize; + public uint Descriptor = JsonDescriptorAddr; + public uint PointerDataCount; + public uint Pad0 = 0; + public uint PointerData = PointerDataAddr; + + public ContractDescriptor32() { } + + public static void Fill(Span dest, bool isLittleEndian, int jsonDescriptorSize, int pointerDataCount) + { + ContractDescriptor32 descriptor = new() + { + DescriptorSize = (uint)jsonDescriptorSize, + PointerDataCount = (uint)pointerDataCount, + }; + if (BitConverter.IsLittleEndian != isLittleEndian) + descriptor.ReverseEndianness(); + + MemoryMarshal.AsBytes(MemoryMarshal.CreateSpan(ref descriptor, 1)).CopyTo(dest); + } + + private void ReverseEndianness() + { + Magic = BinaryPrimitives.ReverseEndianness(Magic); + Flags = BinaryPrimitives.ReverseEndianness(Flags); + DescriptorSize = BinaryPrimitives.ReverseEndianness(DescriptorSize); + Descriptor = BinaryPrimitives.ReverseEndianness(Descriptor); + PointerDataCount = BinaryPrimitives.ReverseEndianness(PointerDataCount); + Pad0 = BinaryPrimitives.ReverseEndianness(Pad0); + PointerData = BinaryPrimitives.ReverseEndianness(PointerData); + } + } + + private struct ContractDescriptor64 + { + public ulong Magic = BitConverter.ToUInt64("DNCCDAC\0"u8); + public uint Flags = 0x1; + public uint DescriptorSize; + public ulong Descriptor = JsonDescriptorAddr; + public uint PointerDataCount; + public uint Pad0 = 0; + public ulong PointerData = PointerDataAddr; + + public ContractDescriptor64() { } + + public static void Fill(Span dest, bool isLittleEndian, int jsonDescriptorSize, int pointerDataCount) + { + ContractDescriptor64 descriptor = new() + { + DescriptorSize = (uint)jsonDescriptorSize, + PointerDataCount = (uint)pointerDataCount, + }; + if (BitConverter.IsLittleEndian != isLittleEndian) + descriptor.ReverseEndianness(); + + MemoryMarshal.AsBytes(MemoryMarshal.CreateSpan(ref descriptor, 1)).CopyTo(dest); + } + + private void ReverseEndianness() + { + Magic = BinaryPrimitives.ReverseEndianness(Magic); + Flags = BinaryPrimitives.ReverseEndianness(Flags); + DescriptorSize = BinaryPrimitives.ReverseEndianness(DescriptorSize); + Descriptor = BinaryPrimitives.ReverseEndianness(Descriptor); + PointerDataCount = BinaryPrimitives.ReverseEndianness(PointerDataCount); + Pad0 = BinaryPrimitives.ReverseEndianness(Pad0); + PointerData = BinaryPrimitives.ReverseEndianness(PointerData); + } + } + } + +} From f5ea326fff2f89ab8188950531c0290d2ae7a827 Mon Sep 17 00:00:00 2001 From: Dan Moseley Date: Thu, 25 Apr 2024 20:53:56 -0700 Subject: [PATCH 094/161] remove nuget (#101584) --- .github/dependabot.yml | 5 ----- 1 file changed, 5 deletions(-) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index aea8ab73e1ef04..9a538c12cfa42d 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -1,10 +1,5 @@ version: 2 -registries: - public-nuget: - type: nuget-feed - url: https://api.nuget.org/v3/index.json updates: - - package-ecosystem: "github-actions" directory: "/" schedule: From a45853c4751b5f532cdb38e3db5d4324b5ca878a Mon Sep 17 00:00:00 2001 From: Xu Liangyu Date: Fri, 26 Apr 2024 12:54:46 +0800 Subject: [PATCH 095/161] [LoongArch64] Add some R2R missing codes. (#101480) --- .../tools/Common/Compiler/InstructionSetSupport.cs | 4 ++++ .../Common/Compiler/VectorFieldLayoutAlgorithm.cs | 10 ++++++++++ src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs | 3 ++- .../JitInterface/LoongArch64PassStructInRegister.cs | 6 ------ .../tools/aot/ILCompiler.Diagnostics/PerfMapWriter.cs | 1 + .../ReadyToRunDiagnosticsConstants.cs | 1 + src/coreclr/vm/methodtablebuilder.cpp | 6 ++++++ .../Reflection/PortableExecutable/PEHeaderBuilder.cs | 2 +- src/tasks/Crossgen2Tasks/ResolveReadyToRunCompilers.cs | 4 ++++ 9 files changed, 29 insertions(+), 8 deletions(-) diff --git a/src/coreclr/tools/Common/Compiler/InstructionSetSupport.cs b/src/coreclr/tools/Common/Compiler/InstructionSetSupport.cs index a1725f3db9d928..f6c34091bc0fe9 100644 --- a/src/coreclr/tools/Common/Compiler/InstructionSetSupport.cs +++ b/src/coreclr/tools/Common/Compiler/InstructionSetSupport.cs @@ -97,6 +97,10 @@ public static string GetHardwareIntrinsicId(TargetArchitecture architecture, Typ if (potentialType.Namespace != "System.Runtime.Intrinsics.Arm") return ""; } + else if (architecture == TargetArchitecture.LoongArch64) + { + return ""; + } else if (architecture == TargetArchitecture.RiscV64) { return ""; diff --git a/src/coreclr/tools/Common/Compiler/VectorFieldLayoutAlgorithm.cs b/src/coreclr/tools/Common/Compiler/VectorFieldLayoutAlgorithm.cs index bb0a5bc71a626c..1f3722ab019bcc 100644 --- a/src/coreclr/tools/Common/Compiler/VectorFieldLayoutAlgorithm.cs +++ b/src/coreclr/tools/Common/Compiler/VectorFieldLayoutAlgorithm.cs @@ -58,6 +58,11 @@ public override ComputedInstanceFieldLayout ComputeInstanceLayout(DefType defTyp // 16-byte alignment for __m256. alignment = new LayoutInt(16); } + else if (defType.Context.Target.Architecture == TargetArchitecture.LoongArch64) + { + // TODO-LoongArch64: Update alignment to proper value when implement LoongArch64 intrinsic. + alignment = new LayoutInt(16); + } else if (defType.Context.Target.Architecture == TargetArchitecture.RiscV64) { // TODO-RISCV64: Update alignment to proper value when we implement RISC-V intrinsic. @@ -86,6 +91,11 @@ public override ComputedInstanceFieldLayout ComputeInstanceLayout(DefType defTyp // 16-byte alignment for __m256. alignment = new LayoutInt(16); } + else if (defType.Context.Target.Architecture == TargetArchitecture.LoongArch64) + { + // TODO-LoongArch64: Update alignment to proper value when implement LoongArch64 intrinsic. + alignment = new LayoutInt(16); + } else if (defType.Context.Target.Architecture == TargetArchitecture.RiscV64) { // TODO-RISCV64: Update alignment to proper value when we implement RISC-V intrinsic. diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs index 7719b39aa7e852..ed04f8625d486e 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs @@ -415,9 +415,10 @@ private CompilationResult CompileMethodInternal(IMethodNode methodCodeNodeNeedin if (codeSize < _code.Length) { if (_compilation.TypeSystemContext.Target.Architecture != TargetArchitecture.ARM64 + && _compilation.TypeSystemContext.Target.Architecture != TargetArchitecture.LoongArch64 && _compilation.TypeSystemContext.Target.Architecture != TargetArchitecture.RiscV64) { - // For xarch/arm32/RiscV64, the generated code is sometimes smaller than the memory allocated. + // For xarch/arm32/LoongArch64/RiscV64, the generated code is sometimes smaller than the memory allocated. // In that case, trim the codeBlock to the actual value. // // For arm64, the allocation request of `hotCodeSize` also includes the roData size diff --git a/src/coreclr/tools/Common/JitInterface/LoongArch64PassStructInRegister.cs b/src/coreclr/tools/Common/JitInterface/LoongArch64PassStructInRegister.cs index b0c193d0950071..856b9905a1fb43 100644 --- a/src/coreclr/tools/Common/JitInterface/LoongArch64PassStructInRegister.cs +++ b/src/coreclr/tools/Common/JitInterface/LoongArch64PassStructInRegister.cs @@ -29,12 +29,6 @@ public static uint GetLoongArch64PassStructInRegisterFlags(TypeDesc typeDesc) return (uint)StructFloatFieldInfoFlags.STRUCT_NO_FLOAT_FIELD; } - //// The SIMD Intrinsic types are meant to be handled specially and should not be passed as struct registers - if (typeDesc.IsIntrinsic) - { - throw new NotImplementedException("For LoongArch64, SIMD would be implemented later"); - } - MetadataType mdType = typeDesc as MetadataType; Debug.Assert(mdType != null); diff --git a/src/coreclr/tools/aot/ILCompiler.Diagnostics/PerfMapWriter.cs b/src/coreclr/tools/aot/ILCompiler.Diagnostics/PerfMapWriter.cs index 98941b37c185e4..16f82023ad0b57 100644 --- a/src/coreclr/tools/aot/ILCompiler.Diagnostics/PerfMapWriter.cs +++ b/src/coreclr/tools/aot/ILCompiler.Diagnostics/PerfMapWriter.cs @@ -136,6 +136,7 @@ private static PerfmapTokensForTarget TranslateTargetDetailsToPerfmapConstants(T TargetArchitecture.X64 => PerfMapArchitectureToken.X64, TargetArchitecture.X86 => PerfMapArchitectureToken.X86, TargetArchitecture.RiscV64 => PerfMapArchitectureToken.RiscV64, + TargetArchitecture.LoongArch64 => PerfMapArchitectureToken.LoongArch64, _ => throw new NotImplementedException(details.Architecture.ToString()) }; diff --git a/src/coreclr/tools/aot/ILCompiler.Diagnostics/ReadyToRunDiagnosticsConstants.cs b/src/coreclr/tools/aot/ILCompiler.Diagnostics/ReadyToRunDiagnosticsConstants.cs index 395b26f151ee83..281349be80e52e 100644 --- a/src/coreclr/tools/aot/ILCompiler.Diagnostics/ReadyToRunDiagnosticsConstants.cs +++ b/src/coreclr/tools/aot/ILCompiler.Diagnostics/ReadyToRunDiagnosticsConstants.cs @@ -20,6 +20,7 @@ public enum PerfMapArchitectureToken : uint X64 = 3, X86 = 4, RiscV64 = 5, + LoongArch64 = 6, } public enum PerfMapOSToken : uint diff --git a/src/coreclr/vm/methodtablebuilder.cpp b/src/coreclr/vm/methodtablebuilder.cpp index 69d2a105ecd8d5..db015d227538e2 100644 --- a/src/coreclr/vm/methodtablebuilder.cpp +++ b/src/coreclr/vm/methodtablebuilder.cpp @@ -10051,6 +10051,9 @@ void MethodTableBuilder::CheckForSystemTypes() // The Procedure Call Standard for ARM 64-bit (with SVE support) defaults to // 16-byte alignment for __m256. + pLayout->m_ManagedLargestAlignmentRequirementOfAllMembers = 16; + #elif defined(TARGET_LOONGARCH64) + // TODO-LoongArch64: Update alignment to proper value when implement LoongArch64 intrinsic. pLayout->m_ManagedLargestAlignmentRequirementOfAllMembers = 16; #elif defined(TARGET_RISCV64) // TODO-RISCV64: Update alignment to proper value when we implement RISC-V intrinsic. @@ -10074,6 +10077,9 @@ void MethodTableBuilder::CheckForSystemTypes() pLayout->m_ManagedLargestAlignmentRequirementOfAllMembers = 16; + #elif defined(TARGET_LOONGARCH64) + // TODO-LoongArch64: Update alignment to proper value when implement LoongArch64 intrinsic. + pLayout->m_ManagedLargestAlignmentRequirementOfAllMembers = 16; #elif defined(TARGET_RISCV64) // TODO-RISCV64: Update alignment to proper value when we implement RISC-V intrinsic. // RISC-V Vector Extenstion Intrinsic Document diff --git a/src/libraries/System.Reflection.Metadata/src/System/Reflection/PortableExecutable/PEHeaderBuilder.cs b/src/libraries/System.Reflection.Metadata/src/System/Reflection/PortableExecutable/PEHeaderBuilder.cs index f93b8bc0716de8..9ddb82d35aa4e3 100644 --- a/src/libraries/System.Reflection.Metadata/src/System/Reflection/PortableExecutable/PEHeaderBuilder.cs +++ b/src/libraries/System.Reflection.Metadata/src/System/Reflection/PortableExecutable/PEHeaderBuilder.cs @@ -105,7 +105,7 @@ public static PEHeaderBuilder CreateLibraryHeader() return new PEHeaderBuilder(imageCharacteristics: Characteristics.ExecutableImage | Characteristics.Dll); } - internal bool Is32Bit => Machine != Machine.Amd64 && Machine != Machine.IA64 && Machine != Machine.Arm64 && Machine != Machine.RiscV64; + internal bool Is32Bit => Machine != Machine.Amd64 && Machine != Machine.IA64 && Machine != Machine.Arm64 && Machine != Machine.LoongArch64 && Machine != Machine.RiscV64; internal int ComputeSizeOfPEHeaders(int sectionCount) => PEBuilder.DosHeaderSize + diff --git a/src/tasks/Crossgen2Tasks/ResolveReadyToRunCompilers.cs b/src/tasks/Crossgen2Tasks/ResolveReadyToRunCompilers.cs index 843333ff3fcbbd..1ec6c1a090a69b 100644 --- a/src/tasks/Crossgen2Tasks/ResolveReadyToRunCompilers.cs +++ b/src/tasks/Crossgen2Tasks/ResolveReadyToRunCompilers.cs @@ -233,6 +233,9 @@ private static bool ExtractTargetPlatformAndArchitecture(string runtimeIdentifie case "riscv64": architecture = Architecture.RiscV64; break; + case "loongarch64": + architecture = Architecture.LoongArch64; + break; default: return false; } @@ -391,6 +394,7 @@ private static string ArchitectureToString(Architecture architecture) Architecture.Arm => "arm", Architecture.Arm64 => "arm64", Architecture.RiscV64 => "riscv64", + Architecture.LoongArch64 => "loongarch64", _ => null }; } From aec52ab4133dc6fd7b728a56ee4760e613853508 Mon Sep 17 00:00:00 2001 From: Xu Liangyu Date: Fri, 26 Apr 2024 15:57:40 +0800 Subject: [PATCH 096/161] [LoongArch64] Enable printing disassembly instructions under release mode for JitDisasm. (#101281) --- src/coreclr/jit/emitloongarch64.cpp | 57 ++++++----------------------- src/coreclr/jit/emitloongarch64.h | 5 --- 2 files changed, 11 insertions(+), 51 deletions(-) diff --git a/src/coreclr/jit/emitloongarch64.cpp b/src/coreclr/jit/emitloongarch64.cpp index 8d8ccbc2a88ed1..63d4e9a975b9b1 100644 --- a/src/coreclr/jit/emitloongarch64.cpp +++ b/src/coreclr/jit/emitloongarch64.cpp @@ -3848,8 +3848,7 @@ size_t emitter::emitOutputInstr(insGroup* ig, instrDesc* id, BYTE** dp) } } -#ifdef DEBUG - if (emitComp->opts.disAsm || emitComp->verbose) + if (emitComp->opts.disAsm INDEBUG(|| emitComp->verbose)) { code_t* cp = (code_t*)(*dp + writeableOffset); while ((BYTE*)cp != dstRW) @@ -3859,6 +3858,7 @@ size_t emitter::emitOutputInstr(insGroup* ig, instrDesc* id, BYTE** dp) } } +#ifdef DEBUG if (emitComp->compDebugBreak) { // For example, set JitBreakEmitOutputInstr=a6 will break when this method is called for @@ -3882,8 +3882,6 @@ size_t emitter::emitOutputInstr(insGroup* ig, instrDesc* id, BYTE** dp) /*****************************************************************************/ /*****************************************************************************/ -#ifdef DEBUG - // clang-format off static const char* const RegNames[] = { @@ -3964,19 +3962,21 @@ void emitter::emitDisInsName(code_t code, const BYTE* addr, instrDesc* id) { const BYTE* insAdr = addr - writeableOffset; - bool disOpcode = !emitComp->opts.disDiffable; - bool disAddr = emitComp->opts.disAddr; - if (disAddr) +#ifdef DEBUG + if (emitComp->opts.disAddr) { printf(" 0x%llx", insAdr); } printf(" "); - if (disOpcode) + if (!emitComp->opts.disDiffable) { printf("%08X ", code); } +#else + printf(" "); +#endif const int regd = code & 0x1f; const int regj = (code >> 5) & 0x1f; @@ -4540,51 +4540,16 @@ void emitter::emitDispIns( } } +#ifdef DEBUG /***************************************************************************** * * Display a stack frame reference. */ - void emitter::emitDispFrameRef(int varx, int disp, int offs, bool asmfm) { - printf("["); - - if (varx < 0) - printf("TEMP_%02u", -varx); - else - emitComp->gtDispLclVar(+varx, false); - - if (disp < 0) - printf("-0x%02x", -disp); - else if (disp > 0) - printf("+0x%02x", +disp); - - printf("]"); - - if (varx >= 0 && emitComp->opts.varNames) - { - LclVarDsc* varDsc; - const char* varName; - - assert((unsigned)varx < emitComp->lvaCount); - varDsc = emitComp->lvaTable + varx; - varName = emitComp->compLocalVarName(varx, offs); - - if (varName) - { - printf("'%s", varName); - - if (disp < 0) - printf("-%d", -disp); - else if (disp > 0) - printf("+%d", +disp); - - printf("'"); - } - } + NYI_LOONGARCH64("emitDispFrameRef-----unused on LoongArch64."); } - -#endif // DEBUG +#endif // Generate code for a load or store operation with a potentially complex addressing mode // This method handles the case of a GT_IND with contained GT_LEA op1 of the x86 form [base + index*sccale + offset] diff --git a/src/coreclr/jit/emitloongarch64.h b/src/coreclr/jit/emitloongarch64.h index afaca5b2ba04b8..bae6d188ca1f79 100644 --- a/src/coreclr/jit/emitloongarch64.h +++ b/src/coreclr/jit/emitloongarch64.h @@ -19,10 +19,6 @@ struct CnsVal bool cnsReloc; }; -#ifdef DEBUG -/************************************************************************/ -/* Debug-only routines to display instructions */ -/************************************************************************/ enum insDisasmFmt { DF_G_INVALID = 0, @@ -108,7 +104,6 @@ code_t emitGetInsMask(int ins); insDisasmFmt emitGetInsFmt(instruction ins); void emitDispInst(instruction ins); void emitDisInsName(code_t code, const BYTE* addr, instrDesc* id); -#endif // DEBUG void emitIns_J_cond_la(instruction ins, BasicBlock* dst, regNumber reg1 = REG_R0, regNumber reg2 = REG_R0); void emitIns_I_la(emitAttr attr, regNumber reg, ssize_t imm); From 99dd60d8886155bb60768c8ef5a5a3225ad95ba4 Mon Sep 17 00:00:00 2001 From: Jakob Botsch Nielsen Date: Fri, 26 Apr 2024 10:00:38 +0200 Subject: [PATCH 097/161] JIT: Check more invariants on ABI info and fix some arm32 bugs (#101372) - Implicit byref parameters should be passed as a single pointer sized segment - Segments should not point outside the local size - Segments should not overlap each other - Segments should have size > 0 - Segments should be ordered by offset - Fix a bug in the arm32 classifier when structs are split - Fix a bug in the arm32 classifier for odd-sized structs with 8 byte alignment. For example ```csharp [StructLayout(LayoutKind.Sequential, Size = 12)] struct S { public double X; public float Y; } ``` would be considered to take 4 slots before. - Fix a bug in the Swift classifier that would cause the tail segments to have an out-of-bounds size --- src/coreclr/jit/abi.cpp | 3 +++ src/coreclr/jit/codegencommon.cpp | 4 ++++ src/coreclr/jit/lclvars.cpp | 36 +++++++++++++++++++++++++++++++ src/coreclr/jit/targetarm.cpp | 10 ++++----- 4 files changed, 48 insertions(+), 5 deletions(-) diff --git a/src/coreclr/jit/abi.cpp b/src/coreclr/jit/abi.cpp index fd899b899546b1..c6dbd8aa9202fd 100644 --- a/src/coreclr/jit/abi.cpp +++ b/src/coreclr/jit/abi.cpp @@ -415,6 +415,9 @@ ABIPassingInformation SwiftABIClassifier::Classify(Compiler* comp, { ABIPassingSegment newSegment = elemInfo.Segments[j]; newSegment.Offset += lowering->offsets[i]; + // Adjust the tail size if necessary; the lowered sequence can + // pass the tail as a larger type than the tail size. + newSegment.Size = min(newSegment.Size, structLayout->GetSize() - newSegment.Offset); segments.Push(newSegment); } } diff --git a/src/coreclr/jit/codegencommon.cpp b/src/coreclr/jit/codegencommon.cpp index c8211a7e731440..9f3120d274d57d 100644 --- a/src/coreclr/jit/codegencommon.cpp +++ b/src/coreclr/jit/codegencommon.cpp @@ -4185,9 +4185,13 @@ void CodeGen::genHomeSwiftStructParameters(bool handleStack) case 2: loadType = TYP_USHORT; break; + case 3: case 4: loadType = TYP_INT; break; + case 5: + case 6: + case 7: case 8: loadType = TYP_LONG; break; diff --git a/src/coreclr/jit/lclvars.cpp b/src/coreclr/jit/lclvars.cpp index e6645e1f03d8f4..97986eefee4b27 100644 --- a/src/coreclr/jit/lclvars.cpp +++ b/src/coreclr/jit/lclvars.cpp @@ -1885,6 +1885,42 @@ void Compiler::lvaClassifyParameterABI() } } } + + for (unsigned lclNum = 0; lclNum < info.compArgsCount; lclNum++) + { + const ABIPassingInformation& abiInfo = lvaGetParameterABIInfo(lclNum); + + if (lvaIsImplicitByRefLocal(lclNum)) + { + assert((abiInfo.NumSegments == 1) && (abiInfo.Segments[0].Size == TARGET_POINTER_SIZE)); + } + else + { + for (unsigned i = 0; i < abiInfo.NumSegments; i++) + { + const ABIPassingSegment& segment = abiInfo.Segments[i]; + assert(segment.Size > 0); + assert(segment.Offset + segment.Size <= lvaLclExactSize(lclNum)); + + if (i > 0) + { + assert(segment.Offset > abiInfo.Segments[i - 1].Offset); + } + + for (unsigned j = 0; j < abiInfo.NumSegments; j++) + { + if (i == j) + { + continue; + } + + const ABIPassingSegment& otherSegment = abiInfo.Segments[j]; + assert((segment.Offset + segment.Size <= otherSegment.Offset) || + (segment.Offset >= otherSegment.Offset + otherSegment.Size)); + } + } + } + } #endif // DEBUG } diff --git a/src/coreclr/jit/targetarm.cpp b/src/coreclr/jit/targetarm.cpp index 037578fa67b85c..675fd04230d531 100644 --- a/src/coreclr/jit/targetarm.cpp +++ b/src/coreclr/jit/targetarm.cpp @@ -85,11 +85,11 @@ ABIPassingInformation Arm32Classifier::Classify(Compiler* comp, m_nextIntReg = roundUp(m_nextIntReg, 2); } - unsigned size = type == TYP_STRUCT ? structLayout->GetSize() : genTypeSize(type); - unsigned alignedSize = roundUp(size, alignment); + unsigned size = type == TYP_STRUCT ? structLayout->GetSize() : genTypeSize(type); + unsigned numSlots = (size + 3) / 4; - unsigned numInRegs = min(alignedSize / 4, 4 - m_nextIntReg); - bool anyOnStack = numInRegs < (alignedSize / 4); + unsigned numInRegs = min(numSlots, 4 - m_nextIntReg); + bool anyOnStack = numInRegs < numSlots; // If we already passed anything on stack (due to float args) then we // cannot split an arg. @@ -116,7 +116,7 @@ ABIPassingInformation Arm32Classifier::Classify(Compiler* comp, { m_stackArgSize = roundUp(m_stackArgSize, alignment); unsigned stackSize = size - (numInRegs * 4); - info.Segments[numInRegs] = ABIPassingSegment::OnStack(m_stackArgSize, 0, stackSize); + info.Segments[numInRegs] = ABIPassingSegment::OnStack(m_stackArgSize, numInRegs * 4, stackSize); m_stackArgSize += roundUp(stackSize, 4); // As soon as any int arg goes on stack we cannot put anything else in From 0f508f26cd22fffb7e8ab0ed3f7133ee48f3a6a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Strehovsk=C3=BD?= Date: Fri, 26 Apr 2024 21:58:39 +0900 Subject: [PATCH 098/161] Allow preinitializing `EventSource` (#101573) We currently don't preinitialize any event sources because they have a finalizer. This is a bit of a problem for places like this: https://github.com/dotnet/runtime/blob/5c01ed22b7468a2bee13b498855dcfcc5ae4da50/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/AsyncTaskMethodBuilderT.cs#L229-L232. We know `IsSupported` is false so we eliminate the branch, but we still need a cctor check because we access a static. The cctor check in a generic method that is instantiated many many many times becomes a death by a thousand papercuts. Saves 0.7% in size on the stage2 app with EventSource disabled. --- .../aot/ILCompiler.Compiler/Compiler/TypePreinit.cs | 10 ++++++++-- .../src/ILLink/ILLink.Substitutions.Shared.xml | 1 + .../src/System/Diagnostics/Tracing/EventSource.cs | 3 +++ 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/TypePreinit.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/TypePreinit.cs index 19d8ee6efd959b..37a7d0de344893 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/TypePreinit.cs +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/TypePreinit.cs @@ -533,8 +533,14 @@ private Status TryScanMethod(MethodIL methodIL, Value[] parameters, Stack + diff --git a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventSource.cs b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventSource.cs index 265035996eee0b..48cab155a9425c 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventSource.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventSource.cs @@ -1461,6 +1461,8 @@ public void Dispose() /// True if called from Dispose(), false if called from the finalizer. protected virtual void Dispose(bool disposing) { + // NOTE: If !IsSupported, we use ILLink.Substitutions to nop out the finalizer. + // Do not add any code before this line (or you'd need to delete the substitution). if (!IsSupported) { return; @@ -1504,6 +1506,7 @@ protected virtual void Dispose(bool disposing) /// ~EventSource() { + // NOTE: we nop out this method body if !IsSupported using ILLink.Substitutions. this.Dispose(false); } #endregion From be49b323fa18c8e2d6256ae023bc6336a4f2263a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20K=C3=B6plinger?= Date: Fri, 26 Apr 2024 15:42:27 +0200 Subject: [PATCH 099/161] Reenable disabled test on s390x in ParallelForEachAsyncTests.cs (#101527) --- .../tests/ParallelForEachAsyncTests.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/libraries/System.Threading.Tasks.Parallel/tests/ParallelForEachAsyncTests.cs b/src/libraries/System.Threading.Tasks.Parallel/tests/ParallelForEachAsyncTests.cs index 01a4dd37908ee7..77c16ddd72c928 100644 --- a/src/libraries/System.Threading.Tasks.Parallel/tests/ParallelForEachAsyncTests.cs +++ b/src/libraries/System.Threading.Tasks.Parallel/tests/ParallelForEachAsyncTests.cs @@ -459,7 +459,6 @@ await Parallel.ForEachAsync(EnumerableRangeAsync(0, 0), (item, cancellationToken [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] [InlineData(false)] [InlineData(true)] - [ActiveIssue("https://github.com/dotnet/runtime/issues/101380", typeof(PlatformDetection), nameof(PlatformDetection.IsS390xProcess))] public async Task AllItemsEnumeratedOnce_For(bool yield) { await Test(yield); From 9892d46d0789329919d9a17f275fd1fff603b76f Mon Sep 17 00:00:00 2001 From: SwapnilGaikwad Date: Fri, 26 Apr 2024 15:02:35 +0100 Subject: [PATCH 100/161] Add support for Sve.UnzipEven/Odd & Sve.ZipHighLow (#101294) * Add support for Sve.UnzipEven/Odd & Sve.ZipHighLow * Rename the test template --------- Co-authored-by: Kunal Pathak --- src/coreclr/jit/hwintrinsiccodegenarm64.cpp | 9 + src/coreclr/jit/hwintrinsiclistarm64sve.h | 5 + .../Arm/Sve.PlatformNotSupported.cs | 255 ++++++++++++++ .../src/System/Runtime/Intrinsics/Arm/Sve.cs | 282 +++++++++++++++ .../ref/System.Runtime.Intrinsics.cs | 43 +++ .../GenerateHWIntrinsicTests_Arm.cs | 109 ++++-- .../Shared/_BinaryOp_SveTestTemplate.template | 327 ++++++++++++++++++ 7 files changed, 996 insertions(+), 34 deletions(-) create mode 100644 src/tests/JIT/HardwareIntrinsics/Arm/Shared/_BinaryOp_SveTestTemplate.template diff --git a/src/coreclr/jit/hwintrinsiccodegenarm64.cpp b/src/coreclr/jit/hwintrinsiccodegenarm64.cpp index edabd7030359f7..462aaa521c6756 100644 --- a/src/coreclr/jit/hwintrinsiccodegenarm64.cpp +++ b/src/coreclr/jit/hwintrinsiccodegenarm64.cpp @@ -1443,6 +1443,15 @@ void CodeGen::genHWIntrinsic(GenTreeHWIntrinsic* node) break; } + case NI_Sve_UnzipEven: + case NI_Sve_UnzipOdd: + case NI_Sve_ZipHigh: + case NI_Sve_ZipLow: + // Use non-predicated version explicitly + GetEmitter()->emitIns_R_R_R(ins, emitSize, targetReg, op1Reg, op2Reg, opt, + INS_SCALABLE_OPTS_UNPREDICATED); + break; + default: unreached(); } diff --git a/src/coreclr/jit/hwintrinsiclistarm64sve.h b/src/coreclr/jit/hwintrinsiclistarm64sve.h index 4cc3e86a170ff3..773b3766a28a55 100644 --- a/src/coreclr/jit/hwintrinsiclistarm64sve.h +++ b/src/coreclr/jit/hwintrinsiclistarm64sve.h @@ -64,6 +64,11 @@ HARDWARE_INTRINSIC(Sve, LoadVectorUInt16ZeroExtendToUInt64, HARDWARE_INTRINSIC(Sve, LoadVectorUInt32ZeroExtendToInt64, -1, 2, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sve_ld1w, INS_invalid, INS_invalid, INS_invalid}, HW_Category_MemoryLoad, HW_Flag_Scalable|HW_Flag_ExplicitMaskedOperation|HW_Flag_LowMaskedOperation) HARDWARE_INTRINSIC(Sve, LoadVectorUInt32ZeroExtendToUInt64, -1, 2, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sve_ld1w, INS_invalid, INS_invalid}, HW_Category_MemoryLoad, HW_Flag_Scalable|HW_Flag_ExplicitMaskedOperation|HW_Flag_LowMaskedOperation) +HARDWARE_INTRINSIC(Sve, UnzipEven, -1, 2, true, {INS_sve_uzp1, INS_sve_uzp1, INS_sve_uzp1, INS_sve_uzp1, INS_sve_uzp1, INS_sve_uzp1, INS_sve_uzp1, INS_sve_uzp1, INS_sve_uzp1, INS_sve_uzp1}, HW_Category_SIMD, HW_Flag_Scalable|HW_Flag_SpecialCodeGen) +HARDWARE_INTRINSIC(Sve, UnzipOdd, -1, 2, true, {INS_sve_uzp2, INS_sve_uzp2, INS_sve_uzp2, INS_sve_uzp2, INS_sve_uzp2, INS_sve_uzp2, INS_sve_uzp2, INS_sve_uzp2, INS_sve_uzp2, INS_sve_uzp2}, HW_Category_SIMD, HW_Flag_Scalable|HW_Flag_SpecialCodeGen) +HARDWARE_INTRINSIC(Sve, ZipHigh, -1, 2, true, {INS_sve_zip2, INS_sve_zip2, INS_sve_zip2, INS_sve_zip2, INS_sve_zip2, INS_sve_zip2, INS_sve_zip2, INS_sve_zip2, INS_sve_zip2, INS_sve_zip2}, HW_Category_SIMD, HW_Flag_Scalable|HW_Flag_SpecialCodeGen) +HARDWARE_INTRINSIC(Sve, ZipLow, -1, 2, true, {INS_sve_zip1, INS_sve_zip1, INS_sve_zip1, INS_sve_zip1, INS_sve_zip1, INS_sve_zip1, INS_sve_zip1, INS_sve_zip1, INS_sve_zip1, INS_sve_zip1}, HW_Category_SIMD, HW_Flag_Scalable|HW_Flag_SpecialCodeGen) + // *************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************** // ISA Function name SIMD size NumArg EncodesExtraTypeArg Instructions Category Flags diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Arm/Sve.PlatformNotSupported.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Arm/Sve.PlatformNotSupported.cs index 918b8664739b62..f23fb1b8ee2c7d 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Arm/Sve.PlatformNotSupported.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Arm/Sve.PlatformNotSupported.cs @@ -806,5 +806,260 @@ internal Arm64() { } public static unsafe Vector LoadVectorUInt32ZeroExtendToUInt64(Vector mask, uint* address) { throw new PlatformNotSupportedException(); } + /// UnzipEven : Concatenate even elements from two inputs + + /// + /// svint8_t svuzp1[_s8](svint8_t op1, svint8_t op2) + /// + public static unsafe Vector UnzipEven(Vector left, Vector right) { throw new PlatformNotSupportedException(); } + + /// + /// svint16_t svuzp1[_s16](svint16_t op1, svint16_t op2) + /// + public static unsafe Vector UnzipEven(Vector left, Vector right) { throw new PlatformNotSupportedException(); } + + /// + /// svint32_t svuzp1[_s32](svint32_t op1, svint32_t op2) + /// + public static unsafe Vector UnzipEven(Vector left, Vector right) { throw new PlatformNotSupportedException(); } + + /// + /// svint64_t svuzp1[_s64](svint64_t op1, svint64_t op2) + /// + public static unsafe Vector UnzipEven(Vector left, Vector right) { throw new PlatformNotSupportedException(); } + + /// + /// svuint8_t svuzp1[_u8](svuint8_t op1, svuint8_t op2) + /// svbool_t svuzp1_b8(svbool_t op1, svbool_t op2) + /// + public static unsafe Vector UnzipEven(Vector left, Vector right) { throw new PlatformNotSupportedException(); } + + /// + /// svuint16_t svuzp1[_u16](svuint16_t op1, svuint16_t op2) + /// svbool_t svuzp1_b16(svbool_t op1, svbool_t op2) + /// + public static unsafe Vector UnzipEven(Vector left, Vector right) { throw new PlatformNotSupportedException(); } + + /// + /// svuint32_t svuzp1[_u32](svuint32_t op1, svuint32_t op2) + /// svbool_t svuzp1_b32(svbool_t op1, svbool_t op2) + /// + public static unsafe Vector UnzipEven(Vector left, Vector right) { throw new PlatformNotSupportedException(); } + + /// + /// svuint64_t svuzp1[_u64](svuint64_t op1, svuint64_t op2) + /// svbool_t svuzp1_b64(svbool_t op1, svbool_t op2) + /// + public static unsafe Vector UnzipEven(Vector left, Vector right) { throw new PlatformNotSupportedException(); } + + /// + /// svfloat32_t svuzp1[_f32](svfloat32_t op1, svfloat32_t op2) + /// + public static unsafe Vector UnzipEven(Vector left, Vector right) { throw new PlatformNotSupportedException(); } + + /// + /// svfloat64_t svuzp1[_f64](svfloat64_t op1, svfloat64_t op2) + /// + public static unsafe Vector UnzipEven(Vector left, Vector right) { throw new PlatformNotSupportedException(); } + + + /// UnzipOdd : Concatenate odd elements from two inputs + + /// + /// svuint8_t svuzp2[_u8](svuint8_t op1, svuint8_t op2) + /// svbool_t svuzp2_b8(svbool_t op1, svbool_t op2) + /// + public static unsafe Vector UnzipOdd(Vector left, Vector right) { throw new PlatformNotSupportedException(); } + + /// + /// svfloat64_t svuzp2[_f64](svfloat64_t op1, svfloat64_t op2) + /// + public static unsafe Vector UnzipOdd(Vector left, Vector right) { throw new PlatformNotSupportedException(); } + + /// + /// svint16_t svuzp2[_s16](svint16_t op1, svint16_t op2) + /// UZP2 Zresult.H, Zop1.H, Zop2.H + /// + public static unsafe Vector UnzipOdd(Vector left, Vector right) { throw new PlatformNotSupportedException(); } + + /// + /// svint32_t svuzp2[_s32](svint32_t op1, svint32_t op2) + /// + public static unsafe Vector UnzipOdd(Vector left, Vector right) { throw new PlatformNotSupportedException(); } + + /// + /// svint64_t svuzp2[_s64](svint64_t op1, svint64_t op2) + /// + public static unsafe Vector UnzipOdd(Vector left, Vector right) { throw new PlatformNotSupportedException(); } + + /// + /// svint8_t svuzp2[_s8](svint8_t op1, svint8_t op2) + /// + public static unsafe Vector UnzipOdd(Vector left, Vector right) { throw new PlatformNotSupportedException(); } + + /// + /// svfloat32_t svuzp2[_f32](svfloat32_t op1, svfloat32_t op2) + /// + public static unsafe Vector UnzipOdd(Vector left, Vector right) { throw new PlatformNotSupportedException(); } + + /// + /// svuint16_t svuzp2[_u16](svuint16_t op1, svuint16_t op2) + /// svbool_t svuzp2_b16(svbool_t op1, svbool_t op2) + /// + public static unsafe Vector UnzipOdd(Vector left, Vector right) { throw new PlatformNotSupportedException(); } + + /// + /// svuint32_t svuzp2[_u32](svuint32_t op1, svuint32_t op2) + /// svbool_t svuzp2_b32(svbool_t op1, svbool_t op2) + /// + public static unsafe Vector UnzipOdd(Vector left, Vector right) { throw new PlatformNotSupportedException(); } + + /// + /// svuint64_t svuzp2[_u64](svuint64_t op1, svuint64_t op2) + /// svbool_t svuzp2_b64(svbool_t op1, svbool_t op2) + /// + public static unsafe Vector UnzipOdd(Vector left, Vector right) { throw new PlatformNotSupportedException(); } + + + /// ZipHigh : Interleave elements from high halves of two inputs + + /// + /// svuint8_t svzip2[_u8](svuint8_t op1, svuint8_t op2) + /// ZIP2 Zresult.B, Zop1.B, Zop2.B + /// svbool_t svzip2_b8(svbool_t op1, svbool_t op2) + /// ZIP2 Presult.B, Pop1.B, Pop2.B + /// + public static unsafe Vector ZipHigh(Vector left, Vector right) { throw new PlatformNotSupportedException(); } + + /// + /// svfloat64_t svzip2[_f64](svfloat64_t op1, svfloat64_t op2) + /// ZIP2 Zresult.D, Zop1.D, Zop2.D + /// + public static unsafe Vector ZipHigh(Vector left, Vector right) { throw new PlatformNotSupportedException(); } + + /// + /// svint16_t svzip2[_s16](svint16_t op1, svint16_t op2) + /// ZIP2 Zresult.H, Zop1.H, Zop2.H + /// + public static unsafe Vector ZipHigh(Vector left, Vector right) { throw new PlatformNotSupportedException(); } + + /// + /// svint32_t svzip2[_s32](svint32_t op1, svint32_t op2) + /// ZIP2 Zresult.S, Zop1.S, Zop2.S + /// + public static unsafe Vector ZipHigh(Vector left, Vector right) { throw new PlatformNotSupportedException(); } + + /// + /// svint64_t svzip2[_s64](svint64_t op1, svint64_t op2) + /// ZIP2 Zresult.D, Zop1.D, Zop2.D + /// + public static unsafe Vector ZipHigh(Vector left, Vector right) { throw new PlatformNotSupportedException(); } + + /// + /// svint8_t svzip2[_s8](svint8_t op1, svint8_t op2) + /// ZIP2 Zresult.B, Zop1.B, Zop2.B + /// + public static unsafe Vector ZipHigh(Vector left, Vector right) { throw new PlatformNotSupportedException(); } + + /// + /// svfloat32_t svzip2[_f32](svfloat32_t op1, svfloat32_t op2) + /// ZIP2 Zresult.S, Zop1.S, Zop2.S + /// + public static unsafe Vector ZipHigh(Vector left, Vector right) { throw new PlatformNotSupportedException(); } + + /// + /// svuint16_t svzip2[_u16](svuint16_t op1, svuint16_t op2) + /// ZIP2 Zresult.H, Zop1.H, Zop2.H + /// svbool_t svzip2_b16(svbool_t op1, svbool_t op2) + /// ZIP2 Presult.H, Pop1.H, Pop2.H + /// + public static unsafe Vector ZipHigh(Vector left, Vector right) { throw new PlatformNotSupportedException(); } + + /// + /// svuint32_t svzip2[_u32](svuint32_t op1, svuint32_t op2) + /// ZIP2 Zresult.S, Zop1.S, Zop2.S + /// svbool_t svzip2_b32(svbool_t op1, svbool_t op2) + /// ZIP2 Presult.S, Pop1.S, Pop2.S + /// + public static unsafe Vector ZipHigh(Vector left, Vector right) { throw new PlatformNotSupportedException(); } + + /// + /// svuint64_t svzip2[_u64](svuint64_t op1, svuint64_t op2) + /// ZIP2 Zresult.D, Zop1.D, Zop2.D + /// svbool_t svzip2_b64(svbool_t op1, svbool_t op2) + /// ZIP2 Presult.D, Pop1.D, Pop2.D + /// + public static unsafe Vector ZipHigh(Vector left, Vector right) { throw new PlatformNotSupportedException(); } + + + /// ZipLow : Interleave elements from low halves of two inputs + + /// + /// svuint8_t svzip1[_u8](svuint8_t op1, svuint8_t op2) + /// ZIP1 Zresult.B, Zop1.B, Zop2.B + /// svbool_t svzip1_b8(svbool_t op1, svbool_t op2) + /// ZIP1 Presult.B, Pop1.B, Pop2.B + /// + public static unsafe Vector ZipLow(Vector left, Vector right) { throw new PlatformNotSupportedException(); } + + /// + /// svfloat64_t svzip1[_f64](svfloat64_t op1, svfloat64_t op2) + /// ZIP1 Zresult.D, Zop1.D, Zop2.D + /// + public static unsafe Vector ZipLow(Vector left, Vector right) { throw new PlatformNotSupportedException(); } + + /// + /// svint16_t svzip1[_s16](svint16_t op1, svint16_t op2) + /// ZIP1 Zresult.H, Zop1.H, Zop2.H + /// + public static unsafe Vector ZipLow(Vector left, Vector right) { throw new PlatformNotSupportedException(); } + + /// + /// svint32_t svzip1[_s32](svint32_t op1, svint32_t op2) + /// ZIP1 Zresult.S, Zop1.S, Zop2.S + /// + public static unsafe Vector ZipLow(Vector left, Vector right) { throw new PlatformNotSupportedException(); } + + /// + /// svint64_t svzip1[_s64](svint64_t op1, svint64_t op2) + /// ZIP1 Zresult.D, Zop1.D, Zop2.D + /// + public static unsafe Vector ZipLow(Vector left, Vector right) { throw new PlatformNotSupportedException(); } + + /// + /// svint8_t svzip1[_s8](svint8_t op1, svint8_t op2) + /// ZIP1 Zresult.B, Zop1.B, Zop2.B + /// + public static unsafe Vector ZipLow(Vector left, Vector right) { throw new PlatformNotSupportedException(); } + + /// + /// svfloat32_t svzip1[_f32](svfloat32_t op1, svfloat32_t op2) + /// ZIP1 Zresult.S, Zop1.S, Zop2.S + /// + public static unsafe Vector ZipLow(Vector left, Vector right) { throw new PlatformNotSupportedException(); } + + /// + /// svuint16_t svzip1[_u16](svuint16_t op1, svuint16_t op2) + /// ZIP1 Zresult.H, Zop1.H, Zop2.H + /// svbool_t svzip1_b16(svbool_t op1, svbool_t op2) + /// ZIP1 Presult.H, Pop1.H, Pop2.H + /// + public static unsafe Vector ZipLow(Vector left, Vector right) { throw new PlatformNotSupportedException(); } + + /// + /// svuint32_t svzip1[_u32](svuint32_t op1, svuint32_t op2) + /// ZIP1 Zresult.S, Zop1.S, Zop2.S + /// svbool_t svzip1_b32(svbool_t op1, svbool_t op2) + /// ZIP1 Presult.S, Pop1.S, Pop2.S + /// + public static unsafe Vector ZipLow(Vector left, Vector right) { throw new PlatformNotSupportedException(); } + + /// + /// svuint64_t svzip1[_u64](svuint64_t op1, svuint64_t op2) + /// ZIP1 Zresult.D, Zop1.D, Zop2.D + /// svbool_t svzip1_b64(svbool_t op1, svbool_t op2) + /// ZIP1 Presult.D, Pop1.D, Pop2.D + /// + public static unsafe Vector ZipLow(Vector left, Vector right) { throw new PlatformNotSupportedException(); } } } diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Arm/Sve.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Arm/Sve.cs index 98f1824f5ecfea..494607f5952c46 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Arm/Sve.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Arm/Sve.cs @@ -861,5 +861,287 @@ internal Arm64() { } public static unsafe Vector LoadVectorUInt32ZeroExtendToUInt64(Vector mask, uint* address) => LoadVectorUInt32ZeroExtendToUInt64(mask, address); + /// UnzipEven : Concatenate even elements from two inputs + + /// + /// svuint8_t svuzp1[_u8](svuint8_t op1, svuint8_t op2) + /// UZP1 Zresult.B, Zop1.B, Zop2.B + /// svbool_t svuzp1_b8(svbool_t op1, svbool_t op2) + /// UZP1 Presult.B, Pop1.B, Pop2.B + /// + public static unsafe Vector UnzipEven(Vector left, Vector right) => UnzipEven(left, right); + + /// + /// svfloat64_t svuzp1[_f64](svfloat64_t op1, svfloat64_t op2) + /// UZP1 Zresult.D, Zop1.D, Zop2.D + /// + public static unsafe Vector UnzipEven(Vector left, Vector right) => UnzipEven(left, right); + + /// + /// svint16_t svuzp1[_s16](svint16_t op1, svint16_t op2) + /// UZP1 Zresult.H, Zop1.H, Zop2.H + /// + public static unsafe Vector UnzipEven(Vector left, Vector right) => UnzipEven(left, right); + + /// + /// svint32_t svuzp1[_s32](svint32_t op1, svint32_t op2) + /// UZP1 Zresult.S, Zop1.S, Zop2.S + /// + public static unsafe Vector UnzipEven(Vector left, Vector right) => UnzipEven(left, right); + + /// + /// svint64_t svuzp1[_s64](svint64_t op1, svint64_t op2) + /// UZP1 Zresult.D, Zop1.D, Zop2.D + /// + public static unsafe Vector UnzipEven(Vector left, Vector right) => UnzipEven(left, right); + + /// + /// svint8_t svuzp1[_s8](svint8_t op1, svint8_t op2) + /// UZP1 Zresult.B, Zop1.B, Zop2.B + /// + public static unsafe Vector UnzipEven(Vector left, Vector right) => UnzipEven(left, right); + + /// + /// svfloat32_t svuzp1[_f32](svfloat32_t op1, svfloat32_t op2) + /// UZP1 Zresult.S, Zop1.S, Zop2.S + /// + public static unsafe Vector UnzipEven(Vector left, Vector right) => UnzipEven(left, right); + + /// + /// svuint16_t svuzp1[_u16](svuint16_t op1, svuint16_t op2) + /// UZP1 Zresult.H, Zop1.H, Zop2.H + /// svbool_t svuzp1_b16(svbool_t op1, svbool_t op2) + /// UZP1 Presult.H, Pop1.H, Pop2.H + /// + public static unsafe Vector UnzipEven(Vector left, Vector right) => UnzipEven(left, right); + + /// + /// svuint32_t svuzp1[_u32](svuint32_t op1, svuint32_t op2) + /// UZP1 Zresult.S, Zop1.S, Zop2.S + /// svbool_t svuzp1_b32(svbool_t op1, svbool_t op2) + /// UZP1 Presult.S, Pop1.S, Pop2.S + /// + public static unsafe Vector UnzipEven(Vector left, Vector right) => UnzipEven(left, right); + + /// + /// svuint64_t svuzp1[_u64](svuint64_t op1, svuint64_t op2) + /// UZP1 Zresult.D, Zop1.D, Zop2.D + /// svbool_t svuzp1_b64(svbool_t op1, svbool_t op2) + /// UZP1 Presult.D, Pop1.D, Pop2.D + /// + public static unsafe Vector UnzipEven(Vector left, Vector right) => UnzipEven(left, right); + + + /// UnzipOdd : Concatenate odd elements from two inputs + + /// + /// svuint8_t svuzp2[_u8](svuint8_t op1, svuint8_t op2) + /// UZP2 Zresult.B, Zop1.B, Zop2.B + /// svbool_t svuzp2_b8(svbool_t op1, svbool_t op2) + /// UZP2 Presult.B, Pop1.B, Pop2.B + /// + public static unsafe Vector UnzipOdd(Vector left, Vector right) => UnzipOdd(left, right); + + /// + /// svfloat64_t svuzp2[_f64](svfloat64_t op1, svfloat64_t op2) + /// UZP2 Zresult.D, Zop1.D, Zop2.D + /// + public static unsafe Vector UnzipOdd(Vector left, Vector right) => UnzipOdd(left, right); + + /// + /// svint16_t svuzp2[_s16](svint16_t op1, svint16_t op2) + /// UZP2 Zresult.H, Zop1.H, Zop2.H + /// + public static unsafe Vector UnzipOdd(Vector left, Vector right) => UnzipOdd(left, right); + + /// + /// svint32_t svuzp2[_s32](svint32_t op1, svint32_t op2) + /// UZP2 Zresult.S, Zop1.S, Zop2.S + /// + public static unsafe Vector UnzipOdd(Vector left, Vector right) => UnzipOdd(left, right); + + /// + /// svint64_t svuzp2[_s64](svint64_t op1, svint64_t op2) + /// UZP2 Zresult.D, Zop1.D, Zop2.D + /// + public static unsafe Vector UnzipOdd(Vector left, Vector right) => UnzipOdd(left, right); + + /// + /// svint8_t svuzp2[_s8](svint8_t op1, svint8_t op2) + /// UZP2 Zresult.B, Zop1.B, Zop2.B + /// + public static unsafe Vector UnzipOdd(Vector left, Vector right) => UnzipOdd(left, right); + + /// + /// svfloat32_t svuzp2[_f32](svfloat32_t op1, svfloat32_t op2) + /// UZP2 Zresult.S, Zop1.S, Zop2.S + /// + public static unsafe Vector UnzipOdd(Vector left, Vector right) => UnzipOdd(left, right); + + /// + /// svuint16_t svuzp2[_u16](svuint16_t op1, svuint16_t op2) + /// UZP2 Zresult.H, Zop1.H, Zop2.H + /// svbool_t svuzp2_b16(svbool_t op1, svbool_t op2) + /// UZP2 Presult.H, Pop1.H, Pop2.H + /// + public static unsafe Vector UnzipOdd(Vector left, Vector right) => UnzipOdd(left, right); + + /// + /// svuint32_t svuzp2[_u32](svuint32_t op1, svuint32_t op2) + /// UZP2 Zresult.S, Zop1.S, Zop2.S + /// svbool_t svuzp2_b32(svbool_t op1, svbool_t op2) + /// UZP2 Presult.S, Pop1.S, Pop2.S + /// + public static unsafe Vector UnzipOdd(Vector left, Vector right) => UnzipOdd(left, right); + + /// + /// svuint64_t svuzp2[_u64](svuint64_t op1, svuint64_t op2) + /// UZP2 Zresult.D, Zop1.D, Zop2.D + /// svbool_t svuzp2_b64(svbool_t op1, svbool_t op2) + /// UZP2 Presult.D, Pop1.D, Pop2.D + /// + public static unsafe Vector UnzipOdd(Vector left, Vector right) => UnzipOdd(left, right); + /// ZipHigh : Interleave elements from high halves of two inputs + + /// + /// svuint8_t svzip2[_u8](svuint8_t op1, svuint8_t op2) + /// ZIP2 Zresult.B, Zop1.B, Zop2.B + /// svbool_t svzip2_b8(svbool_t op1, svbool_t op2) + /// ZIP2 Presult.B, Pop1.B, Pop2.B + /// + + + public static unsafe Vector ZipHigh(Vector left, Vector right) => ZipHigh(left, right); + + /// + /// svfloat64_t svzip2[_f64](svfloat64_t op1, svfloat64_t op2) + /// ZIP2 Zresult.D, Zop1.D, Zop2.D + /// + public static unsafe Vector ZipHigh(Vector left, Vector right) => ZipHigh(left, right); + + /// + /// svint16_t svzip2[_s16](svint16_t op1, svint16_t op2) + /// ZIP2 Zresult.H, Zop1.H, Zop2.H + /// + public static unsafe Vector ZipHigh(Vector left, Vector right) => ZipHigh(left, right); + + /// + /// svint32_t svzip2[_s32](svint32_t op1, svint32_t op2) + /// ZIP2 Zresult.S, Zop1.S, Zop2.S + /// + public static unsafe Vector ZipHigh(Vector left, Vector right) => ZipHigh(left, right); + + /// + /// svint64_t svzip2[_s64](svint64_t op1, svint64_t op2) + /// ZIP2 Zresult.D, Zop1.D, Zop2.D + /// + public static unsafe Vector ZipHigh(Vector left, Vector right) => ZipHigh(left, right); + + /// + /// svint8_t svzip2[_s8](svint8_t op1, svint8_t op2) + /// ZIP2 Zresult.B, Zop1.B, Zop2.B + /// + public static unsafe Vector ZipHigh(Vector left, Vector right) => ZipHigh(left, right); + + /// + /// svfloat32_t svzip2[_f32](svfloat32_t op1, svfloat32_t op2) + /// ZIP2 Zresult.S, Zop1.S, Zop2.S + /// + public static unsafe Vector ZipHigh(Vector left, Vector right) => ZipHigh(left, right); + + /// + /// svuint16_t svzip2[_u16](svuint16_t op1, svuint16_t op2) + /// ZIP2 Zresult.H, Zop1.H, Zop2.H + /// svbool_t svzip2_b16(svbool_t op1, svbool_t op2) + /// ZIP2 Presult.H, Pop1.H, Pop2.H + /// + public static unsafe Vector ZipHigh(Vector left, Vector right) => ZipHigh(left, right); + + /// + /// svuint32_t svzip2[_u32](svuint32_t op1, svuint32_t op2) + /// ZIP2 Zresult.S, Zop1.S, Zop2.S + /// svbool_t svzip2_b32(svbool_t op1, svbool_t op2) + /// ZIP2 Presult.S, Pop1.S, Pop2.S + /// + public static unsafe Vector ZipHigh(Vector left, Vector right) => ZipHigh(left, right); + + /// + /// svuint64_t svzip2[_u64](svuint64_t op1, svuint64_t op2) + /// ZIP2 Zresult.D, Zop1.D, Zop2.D + /// svbool_t svzip2_b64(svbool_t op1, svbool_t op2) + /// ZIP2 Presult.D, Pop1.D, Pop2.D + /// + public static unsafe Vector ZipHigh(Vector left, Vector right) => ZipHigh(left, right); + + + /// ZipLow : Interleave elements from low halves of two inputs + + /// + /// svuint8_t svzip1[_u8](svuint8_t op1, svuint8_t op2) + /// ZIP1 Zresult.B, Zop1.B, Zop2.B + /// svbool_t svzip1_b8(svbool_t op1, svbool_t op2) + /// ZIP1 Presult.B, Pop1.B, Pop2.B + /// + public static unsafe Vector ZipLow(Vector left, Vector right) => ZipLow(left, right); + + /// + /// svfloat64_t svzip1[_f64](svfloat64_t op1, svfloat64_t op2) + /// ZIP1 Zresult.D, Zop1.D, Zop2.D + /// + public static unsafe Vector ZipLow(Vector left, Vector right) => ZipLow(left, right); + + /// + /// svint16_t svzip1[_s16](svint16_t op1, svint16_t op2) + /// ZIP1 Zresult.H, Zop1.H, Zop2.H + /// + public static unsafe Vector ZipLow(Vector left, Vector right) => ZipLow(left, right); + + /// + /// svint32_t svzip1[_s32](svint32_t op1, svint32_t op2) + /// ZIP1 Zresult.S, Zop1.S, Zop2.S + /// + public static unsafe Vector ZipLow(Vector left, Vector right) => ZipLow(left, right); + + /// + /// svint64_t svzip1[_s64](svint64_t op1, svint64_t op2) + /// ZIP1 Zresult.D, Zop1.D, Zop2.D + /// + public static unsafe Vector ZipLow(Vector left, Vector right) => ZipLow(left, right); + + /// + /// svint8_t svzip1[_s8](svint8_t op1, svint8_t op2) + /// ZIP1 Zresult.B, Zop1.B, Zop2.B + /// + public static unsafe Vector ZipLow(Vector left, Vector right) => ZipLow(left, right); + + /// + /// svfloat32_t svzip1[_f32](svfloat32_t op1, svfloat32_t op2) + /// ZIP1 Zresult.S, Zop1.S, Zop2.S + /// + public static unsafe Vector ZipLow(Vector left, Vector right) => ZipLow(left, right); + + /// + /// svuint16_t svzip1[_u16](svuint16_t op1, svuint16_t op2) + /// ZIP1 Zresult.H, Zop1.H, Zop2.H + /// svbool_t svzip1_b16(svbool_t op1, svbool_t op2) + /// ZIP1 Presult.H, Pop1.H, Pop2.H + /// + public static unsafe Vector ZipLow(Vector left, Vector right) => ZipLow(left, right); + + /// + /// svuint32_t svzip1[_u32](svuint32_t op1, svuint32_t op2) + /// ZIP1 Zresult.S, Zop1.S, Zop2.S + /// svbool_t svzip1_b32(svbool_t op1, svbool_t op2) + /// ZIP1 Presult.S, Pop1.S, Pop2.S + /// + public static unsafe Vector ZipLow(Vector left, Vector right) => ZipLow(left, right); + + /// + /// svuint64_t svzip1[_u64](svuint64_t op1, svuint64_t op2) + /// ZIP1 Zresult.D, Zop1.D, Zop2.D + /// svbool_t svzip1_b64(svbool_t op1, svbool_t op2) + /// ZIP1 Presult.D, Pop1.D, Pop2.D + /// + public static unsafe Vector ZipLow(Vector left, Vector right) => ZipLow(left, right); } } diff --git a/src/libraries/System.Runtime.Intrinsics/ref/System.Runtime.Intrinsics.cs b/src/libraries/System.Runtime.Intrinsics/ref/System.Runtime.Intrinsics.cs index e2ddb85806910a..e5f394aca8168a 100644 --- a/src/libraries/System.Runtime.Intrinsics/ref/System.Runtime.Intrinsics.cs +++ b/src/libraries/System.Runtime.Intrinsics/ref/System.Runtime.Intrinsics.cs @@ -4274,6 +4274,49 @@ internal Arm64() { } public static unsafe System.Numerics.Vector LoadVectorUInt32ZeroExtendToInt64(System.Numerics.Vector mask, uint* address) { throw null; } public static unsafe System.Numerics.Vector LoadVectorUInt32ZeroExtendToUInt64(System.Numerics.Vector mask, uint* address) { throw null; } + public static System.Numerics.Vector UnzipEven(System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } + public static System.Numerics.Vector UnzipEven(System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } + public static System.Numerics.Vector UnzipEven(System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } + public static System.Numerics.Vector UnzipEven(System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } + public static System.Numerics.Vector UnzipEven(System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } + public static System.Numerics.Vector UnzipEven(System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } + public static System.Numerics.Vector UnzipEven(System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } + public static System.Numerics.Vector UnzipEven(System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } + public static System.Numerics.Vector UnzipEven(System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } + public static System.Numerics.Vector UnzipEven(System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } + + public static System.Numerics.Vector UnzipOdd(System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } + public static System.Numerics.Vector UnzipOdd(System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } + public static System.Numerics.Vector UnzipOdd(System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } + public static System.Numerics.Vector UnzipOdd(System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } + public static System.Numerics.Vector UnzipOdd(System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } + public static System.Numerics.Vector UnzipOdd(System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } + public static System.Numerics.Vector UnzipOdd(System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } + public static System.Numerics.Vector UnzipOdd(System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } + public static System.Numerics.Vector UnzipOdd(System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } + public static System.Numerics.Vector UnzipOdd(System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } + + public static System.Numerics.Vector ZipHigh(System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } + public static System.Numerics.Vector ZipHigh(System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } + public static System.Numerics.Vector ZipHigh(System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } + public static System.Numerics.Vector ZipHigh(System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } + public static System.Numerics.Vector ZipHigh(System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } + public static System.Numerics.Vector ZipHigh(System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } + public static System.Numerics.Vector ZipHigh(System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } + public static System.Numerics.Vector ZipHigh(System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } + public static System.Numerics.Vector ZipHigh(System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } + public static System.Numerics.Vector ZipHigh(System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } + + public static System.Numerics.Vector ZipLow(System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } + public static System.Numerics.Vector ZipLow(System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } + public static System.Numerics.Vector ZipLow(System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } + public static System.Numerics.Vector ZipLow(System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } + public static System.Numerics.Vector ZipLow(System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } + public static System.Numerics.Vector ZipLow(System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } + public static System.Numerics.Vector ZipLow(System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } + public static System.Numerics.Vector ZipLow(System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } + public static System.Numerics.Vector ZipLow(System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } + public static System.Numerics.Vector ZipLow(System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } } public enum SveMaskPattern : byte diff --git a/src/tests/Common/GenerateHWIntrinsicTests/GenerateHWIntrinsicTests_Arm.cs b/src/tests/Common/GenerateHWIntrinsicTests/GenerateHWIntrinsicTests_Arm.cs index 91e67daa18b976..e1e048d72ed60a 100644 --- a/src/tests/Common/GenerateHWIntrinsicTests/GenerateHWIntrinsicTests_Arm.cs +++ b/src/tests/Common/GenerateHWIntrinsicTests/GenerateHWIntrinsicTests_Arm.cs @@ -112,6 +112,7 @@ ("_UnaryOpTestTemplate.template", "SimpleUnOpTest.template", new Dictionary { ["TemplateName"] = "Simple", ["TemplateValidationLogic"] = SimpleOpTest_ValidationLogic }), ("_UnaryOpTestTemplate.template", "SimpleVecOpTest.template", new Dictionary { ["TemplateName"] = "Simple", ["TemplateValidationLogic"] = SimpleVecOpTest_ValidationLogic }), ("_BinaryOpTestTemplate.template", "VecPairBinOpTest.template", new Dictionary { ["TemplateName"] = "Simple", ["TemplateValidationLogic"] = VecPairBinOpTest_ValidationLogic }), + ("_BinaryOp_SveTestTemplate.template", "SveVecPairBinOpTest.template", new Dictionary { ["TemplateName"] = "Simple", ["TemplateValidationLogic"] = VecPairBinOpTest_ValidationLogic }), ("_UnaryOpTestTemplate.template", "VecReduceUnOpTest.template", new Dictionary { ["TemplateName"] = "Simple", ["TemplateValidationLogic"] = VecReduceOpTest_ValidationLogic }), ("_BinaryOpTestTemplate.template", "VecBinOpTest.template", new Dictionary { ["TemplateName"] = "Simple", ["TemplateValidationLogic"] = SimpleVecOpTest_ValidationLogic }), ("_TernaryOpTestTemplate.template", "SimpleTernOpTest.template", new Dictionary { ["TemplateName"] = "Simple", ["TemplateValidationLogic"] = SimpleOpTest_ValidationLogic }), @@ -2908,16 +2909,16 @@ ("SveVecBinOpTest.template", new Dictionary { ["TestName"] = "Sve_Add_uint", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "Add", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "Helpers.Add(left[i], right[i]) != result[i]", ["GetIterResult"] = "Helpers.Add(left[i], right[i])"}), ("SveVecBinOpTest.template", new Dictionary { ["TestName"] = "Sve_Add_ulong", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "Add", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt64", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "UInt64", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt64()", ["ValidateIterResult"] = "Helpers.Add(left[i], right[i]) != result[i]", ["GetIterResult"] = "Helpers.Add(left[i], right[i])"}), - ("SveConditionalSelect.template", new Dictionary { ["TestName"] = "Sve_ConditionalSelect_float", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "ConditionalSelect", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "Single", ["Op3VectorType"] = "Vector", ["Op3BaseType"] = "Single", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp3"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "(firstOp[i] != 0 ? (result[i] != secondOp[i]) : (result[i] != thirdOp[i]))",}), - ("SveConditionalSelect.template", new Dictionary { ["TestName"] = "Sve_ConditionalSelect_double", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "ConditionalSelect", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "Double", ["Op3VectorType"] = "Vector", ["Op3BaseType"] = "Double", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp3"] = "TestLibrary.Generator.GetDouble()", ["ValidateIterResult"] = "(firstOp[i] != 0 ? (result[i] != secondOp[i]) : (result[i] != thirdOp[i]))",}), - ("SveConditionalSelect.template", new Dictionary { ["TestName"] = "Sve_ConditionalSelect_sbyte", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "ConditionalSelect", ["RetVectorType"] = "Vector", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "SByte", ["Op3VectorType"] = "Vector", ["Op3BaseType"] = "SByte", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp3"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "(firstOp[i] != 0 ? (result[i] != secondOp[i]) : (result[i] != thirdOp[i]))",}), - ("SveConditionalSelect.template", new Dictionary { ["TestName"] = "Sve_ConditionalSelect_short", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "ConditionalSelect", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "Int16", ["Op3VectorType"] = "Vector", ["Op3BaseType"] = "Int16", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp3"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "(firstOp[i] != 0 ? (result[i] != secondOp[i]) : (result[i] != thirdOp[i]))",}), - ("SveConditionalSelect.template", new Dictionary { ["TestName"] = "Sve_ConditionalSelect_int", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "ConditionalSelect", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "Int32", ["Op3VectorType"] = "Vector", ["Op3BaseType"] = "Int32", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp3"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "(firstOp[i] != 0 ? (result[i] != secondOp[i]) : (result[i] != thirdOp[i]))",}), - ("SveConditionalSelect.template", new Dictionary { ["TestName"] = "Sve_ConditionalSelect_long", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "ConditionalSelect", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Int64", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "Int64", ["Op3VectorType"] = "Vector", ["Op3BaseType"] = "Int64", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt64()", ["NextValueOp3"] = "TestLibrary.Generator.GetInt64()", ["ValidateIterResult"] = "(firstOp[i] != 0 ? (result[i] != secondOp[i]) : (result[i] != thirdOp[i]))",}), - ("SveConditionalSelect.template", new Dictionary { ["TestName"] = "Sve_ConditionalSelect_byte", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "ConditionalSelect", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "Byte", ["Op3VectorType"] = "Vector", ["Op3BaseType"] = "Byte", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["NextValueOp3"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "(firstOp[i] != 0 ? (result[i] != secondOp[i]) : (result[i] != thirdOp[i]))",}), - ("SveConditionalSelect.template", new Dictionary { ["TestName"] = "Sve_ConditionalSelect_ushort", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "ConditionalSelect", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "UInt16", ["Op3VectorType"] = "Vector", ["Op3BaseType"] = "UInt16", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp3"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "(firstOp[i] != 0 ? (result[i] != secondOp[i]) : (result[i] != thirdOp[i]))",}), - ("SveConditionalSelect.template", new Dictionary { ["TestName"] = "Sve_ConditionalSelect_uint", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "ConditionalSelect", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "UInt32", ["Op3VectorType"] = "Vector", ["Op3BaseType"] = "UInt32", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp3"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "(firstOp[i] != 0 ? (result[i] != secondOp[i]) : (result[i] != thirdOp[i]))",}), - ("SveConditionalSelect.template", new Dictionary { ["TestName"] = "Sve_ConditionalSelect_ulong", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "ConditionalSelect", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt64", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "UInt64", ["Op3VectorType"] = "Vector", ["Op3BaseType"] = "UInt64", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt64()", ["NextValueOp3"] = "TestLibrary.Generator.GetUInt64()", ["ValidateIterResult"] = "(firstOp[i] != 0 ? (result[i] != secondOp[i]) : (result[i] != thirdOp[i]))",}), + ("SveConditionalSelect.template", new Dictionary { ["TestName"] = "Sve_ConditionalSelect_float", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "ConditionalSelect", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "Single", ["Op3VectorType"] = "Vector", ["Op3BaseType"] = "Single", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp3"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "(firstOp[i] != 0 ? (result[i] != secondOp[i]) : (result[i] != thirdOp[i]))",}), + ("SveConditionalSelect.template", new Dictionary { ["TestName"] = "Sve_ConditionalSelect_double", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "ConditionalSelect", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "Double", ["Op3VectorType"] = "Vector", ["Op3BaseType"] = "Double", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp3"] = "TestLibrary.Generator.GetDouble()", ["ValidateIterResult"] = "(firstOp[i] != 0 ? (result[i] != secondOp[i]) : (result[i] != thirdOp[i]))",}), + ("SveConditionalSelect.template", new Dictionary { ["TestName"] = "Sve_ConditionalSelect_sbyte", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "ConditionalSelect", ["RetVectorType"] = "Vector", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "SByte", ["Op3VectorType"] = "Vector", ["Op3BaseType"] = "SByte", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp3"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "(firstOp[i] != 0 ? (result[i] != secondOp[i]) : (result[i] != thirdOp[i]))",}), + ("SveConditionalSelect.template", new Dictionary { ["TestName"] = "Sve_ConditionalSelect_short", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "ConditionalSelect", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "Int16", ["Op3VectorType"] = "Vector", ["Op3BaseType"] = "Int16", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp3"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "(firstOp[i] != 0 ? (result[i] != secondOp[i]) : (result[i] != thirdOp[i]))",}), + ("SveConditionalSelect.template", new Dictionary { ["TestName"] = "Sve_ConditionalSelect_int", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "ConditionalSelect", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "Int32", ["Op3VectorType"] = "Vector", ["Op3BaseType"] = "Int32", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp3"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "(firstOp[i] != 0 ? (result[i] != secondOp[i]) : (result[i] != thirdOp[i]))",}), + ("SveConditionalSelect.template", new Dictionary { ["TestName"] = "Sve_ConditionalSelect_long", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "ConditionalSelect", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Int64", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "Int64", ["Op3VectorType"] = "Vector", ["Op3BaseType"] = "Int64", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt64()", ["NextValueOp3"] = "TestLibrary.Generator.GetInt64()", ["ValidateIterResult"] = "(firstOp[i] != 0 ? (result[i] != secondOp[i]) : (result[i] != thirdOp[i]))",}), + ("SveConditionalSelect.template", new Dictionary { ["TestName"] = "Sve_ConditionalSelect_byte", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "ConditionalSelect", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "Byte", ["Op3VectorType"] = "Vector", ["Op3BaseType"] = "Byte", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["NextValueOp3"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "(firstOp[i] != 0 ? (result[i] != secondOp[i]) : (result[i] != thirdOp[i]))",}), + ("SveConditionalSelect.template", new Dictionary { ["TestName"] = "Sve_ConditionalSelect_ushort", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "ConditionalSelect", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "UInt16", ["Op3VectorType"] = "Vector", ["Op3BaseType"] = "UInt16", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp3"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "(firstOp[i] != 0 ? (result[i] != secondOp[i]) : (result[i] != thirdOp[i]))",}), + ("SveConditionalSelect.template", new Dictionary { ["TestName"] = "Sve_ConditionalSelect_uint", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "ConditionalSelect", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "UInt32", ["Op3VectorType"] = "Vector", ["Op3BaseType"] = "UInt32", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp3"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "(firstOp[i] != 0 ? (result[i] != secondOp[i]) : (result[i] != thirdOp[i]))",}), + ("SveConditionalSelect.template", new Dictionary { ["TestName"] = "Sve_ConditionalSelect_ulong", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "ConditionalSelect", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt64", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "UInt64", ["Op3VectorType"] = "Vector", ["Op3BaseType"] = "UInt64", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt64()", ["NextValueOp3"] = "TestLibrary.Generator.GetUInt64()", ["ValidateIterResult"] = "(firstOp[i] != 0 ? (result[i] != secondOp[i]) : (result[i] != thirdOp[i]))",}), ("ScalarBinOpRetVecTest.template",new Dictionary {["TestName"] = "Sve_CreateWhileLessThanMask16Bit_Int32", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "CreateWhileLessThanMask16Bit", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt16", ["Op1BaseType"] = "Int32", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.WhileLessThanMask(left + (Int32)i, right) != (Int32)result[i]",}), ("ScalarBinOpRetVecTest.template",new Dictionary {["TestName"] = "Sve_CreateWhileLessThanMask16Bit_Int64", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "CreateWhileLessThanMask16Bit", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt16", ["Op1BaseType"] = "Int64", ["Op2BaseType"] = "Int64", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt64()", ["ValidateIterResult"] = "Helpers.WhileLessThanMask(left + (Int64)i, right) != (Int64)result[i]",}), @@ -2963,30 +2964,70 @@ ("SveLoadMaskedUnOpTest.template", new Dictionary { ["TestName"] = "SveLoadVector_uint", ["Isa"] = "Sve", ["Method"] = "LoadVector", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt32", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "64", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), ("SveLoadMaskedUnOpTest.template", new Dictionary { ["TestName"] = "SveLoadVector_ulong", ["Isa"] = "Sve", ["Method"] = "LoadVector", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt64", ["Op2BaseType"] = "UInt64", ["LargestVectorSize"] = "64", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt64()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), - ("SveLoadMaskedUnOpTest.template", new Dictionary { ["TestName"] = "SveLoadVectorByteZeroExtendToInt16", ["Isa"] = "Sve", ["Method"] = "LoadVectorByteZeroExtendToInt16", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Int16", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "8", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), - ("SveLoadMaskedUnOpTest.template", new Dictionary {["TestName"] = "SveLoadVectorByteZeroExtendToInt32", ["Isa"] = "Sve", ["Method"] = "LoadVectorByteZeroExtendToInt32", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Int32", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "8", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), - ("SveLoadMaskedUnOpTest.template", new Dictionary {["TestName"] = "SveLoadVectorByteZeroExtendToInt64", ["Isa"] = "Sve", ["Method"] = "LoadVectorByteZeroExtendToInt64", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Int64", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "8", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), - ("SveLoadMaskedUnOpTest.template", new Dictionary {["TestName"] = "SveLoadVectorByteZeroExtendToUInt16", ["Isa"] = "Sve", ["Method"] = "LoadVectorByteZeroExtendToUInt16", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt16", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "8", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), - ("SveLoadMaskedUnOpTest.template", new Dictionary {["TestName"] = "SveLoadVectorByteZeroExtendToUInt32", ["Isa"] = "Sve", ["Method"] = "LoadVectorByteZeroExtendToUInt32", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt32", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "8", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), - ("SveLoadMaskedUnOpTest.template", new Dictionary {["TestName"] = "SveLoadVectorByteZeroExtendToUInt64", ["Isa"] = "Sve", ["Method"] = "LoadVectorByteZeroExtendToUInt64", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt64", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "8", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), - ("SveLoadMaskedUnOpTest.template", new Dictionary {["TestName"] = "SveLoadVectorInt16SignExtendToInt32", ["Isa"] = "Sve", ["Method"] = "LoadVectorInt16SignExtendToInt32", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Int32", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "8", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), - ("SveLoadMaskedUnOpTest.template", new Dictionary {["TestName"] = "SveLoadVectorInt16SignExtendToInt64", ["Isa"] = "Sve", ["Method"] = "LoadVectorInt16SignExtendToInt64", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Int64", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "8", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), - ("SveLoadMaskedUnOpTest.template", new Dictionary {["TestName"] = "SveLoadVectorInt16SignExtendToUInt32", ["Isa"] = "Sve", ["Method"] = "LoadVectorInt16SignExtendToUInt32", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt32", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "8", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), - ("SveLoadMaskedUnOpTest.template", new Dictionary {["TestName"] = "SveLoadVectorInt16SignExtendToUInt64", ["Isa"] = "Sve", ["Method"] = "LoadVectorInt16SignExtendToUInt64", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt64", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "8", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "(ulong)firstOp[i] != result[i]"}), - ("SveLoadMaskedUnOpTest.template", new Dictionary {["TestName"] = "SveLoadVectorInt32SignExtendToInt64", ["Isa"] = "Sve", ["Method"] = "LoadVectorInt32SignExtendToInt64", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Int64", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "8", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), - ("SveLoadMaskedUnOpTest.template", new Dictionary {["TestName"] = "SveLoadVectorInt32SignExtendToUInt64", ["Isa"] = "Sve", ["Method"] = "LoadVectorInt32SignExtendToUInt64", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt64", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "8", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "(ulong)firstOp[i] != result[i]"}), - ("SveLoadMaskedUnOpTest.template", new Dictionary {["TestName"] = "SveLoadVectorSByteSignExtendToInt16", ["Isa"] = "Sve", ["Method"] = "LoadVectorSByteSignExtendToInt16", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Int16", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "8", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), - ("SveLoadMaskedUnOpTest.template", new Dictionary {["TestName"] = "SveLoadVectorSByteSignExtendToInt32", ["Isa"] = "Sve", ["Method"] = "LoadVectorSByteSignExtendToInt32", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Int32", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "8", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), - ("SveLoadMaskedUnOpTest.template", new Dictionary {["TestName"] = "SveLoadVectorSByteSignExtendToInt64", ["Isa"] = "Sve", ["Method"] = "LoadVectorSByteSignExtendToInt64", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Int64", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "8", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), - ("SveLoadMaskedUnOpTest.template", new Dictionary {["TestName"] = "SveLoadVectorSByteSignExtendToUInt16", ["Isa"] = "Sve", ["Method"] = "LoadVectorSByteSignExtendToUInt16", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt16", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "8", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), - ("SveLoadMaskedUnOpTest.template", new Dictionary {["TestName"] = "SveLoadVectorSByteSignExtendToUInt32", ["Isa"] = "Sve", ["Method"] = "LoadVectorSByteSignExtendToUInt32", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt32", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "8", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), - ("SveLoadMaskedUnOpTest.template", new Dictionary {["TestName"] = "SveLoadVectorSByteSignExtendToUInt64", ["Isa"] = "Sve", ["Method"] = "LoadVectorSByteSignExtendToUInt64", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt64", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "8", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "(ulong)firstOp[i] != result[i]"}), - ("SveLoadMaskedUnOpTest.template", new Dictionary {["TestName"] = "SveLoadVectorUInt16ZeroExtendToInt32", ["Isa"] = "Sve", ["Method"] = "LoadVectorUInt16ZeroExtendToInt32", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Int32", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "8", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), - ("SveLoadMaskedUnOpTest.template", new Dictionary {["TestName"] = "SveLoadVectorUInt16ZeroExtendToInt64", ["Isa"] = "Sve", ["Method"] = "LoadVectorUInt16ZeroExtendToInt64", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Int64", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "8", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), - ("SveLoadMaskedUnOpTest.template", new Dictionary {["TestName"] = "SveLoadVectorUInt16ZeroExtendToUInt32", ["Isa"] = "Sve", ["Method"] = "LoadVectorUInt16ZeroExtendToUInt32", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt32", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "8", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), - ("SveLoadMaskedUnOpTest.template", new Dictionary {["TestName"] = "SveLoadVectorUInt16ZeroExtendToUInt64", ["Isa"] = "Sve", ["Method"] = "LoadVectorUInt16ZeroExtendToUInt64", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt64", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "8", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), - ("SveLoadMaskedUnOpTest.template", new Dictionary {["TestName"] = "SveLoadVectorUInt32ZeroExtendToInt64", ["Isa"] = "Sve", ["Method"] = "LoadVectorUInt32ZeroExtendToInt64", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Int64", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "8", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), - ("SveLoadMaskedUnOpTest.template", new Dictionary {["TestName"] = "SveLoadVectorUInt32ZeroExtendToUInt64", ["Isa"] = "Sve", ["Method"] = "LoadVectorUInt32ZeroExtendToUInt64", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt64", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "8", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), + ("SveLoadMaskedUnOpTest.template", new Dictionary { ["TestName"] = "SveLoadVectorByteZeroExtendToInt16", ["Isa"] = "Sve", ["Method"] = "LoadVectorByteZeroExtendToInt16", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Int16", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "8", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), + ("SveLoadMaskedUnOpTest.template", new Dictionary { ["TestName"] = "SveLoadVectorByteZeroExtendToInt32", ["Isa"] = "Sve", ["Method"] = "LoadVectorByteZeroExtendToInt32", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Int32", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "8", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), + ("SveLoadMaskedUnOpTest.template", new Dictionary { ["TestName"] = "SveLoadVectorByteZeroExtendToInt64", ["Isa"] = "Sve", ["Method"] = "LoadVectorByteZeroExtendToInt64", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Int64", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "8", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), + ("SveLoadMaskedUnOpTest.template", new Dictionary { ["TestName"] = "SveLoadVectorByteZeroExtendToUInt16", ["Isa"] = "Sve", ["Method"] = "LoadVectorByteZeroExtendToUInt16", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt16", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "8", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), + ("SveLoadMaskedUnOpTest.template", new Dictionary { ["TestName"] = "SveLoadVectorByteZeroExtendToUInt32", ["Isa"] = "Sve", ["Method"] = "LoadVectorByteZeroExtendToUInt32", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt32", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "8", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), + ("SveLoadMaskedUnOpTest.template", new Dictionary { ["TestName"] = "SveLoadVectorByteZeroExtendToUInt64", ["Isa"] = "Sve", ["Method"] = "LoadVectorByteZeroExtendToUInt64", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt64", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "8", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), + ("SveLoadMaskedUnOpTest.template", new Dictionary { ["TestName"] = "SveLoadVectorInt16SignExtendToInt32", ["Isa"] = "Sve", ["Method"] = "LoadVectorInt16SignExtendToInt32", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Int32", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "8", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), + ("SveLoadMaskedUnOpTest.template", new Dictionary { ["TestName"] = "SveLoadVectorInt16SignExtendToInt64", ["Isa"] = "Sve", ["Method"] = "LoadVectorInt16SignExtendToInt64", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Int64", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "8", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), + ("SveLoadMaskedUnOpTest.template", new Dictionary { ["TestName"] = "SveLoadVectorInt16SignExtendToUInt32", ["Isa"] = "Sve", ["Method"] = "LoadVectorInt16SignExtendToUInt32", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt32", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "8", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), + ("SveLoadMaskedUnOpTest.template", new Dictionary { ["TestName"] = "SveLoadVectorInt16SignExtendToUInt64", ["Isa"] = "Sve", ["Method"] = "LoadVectorInt16SignExtendToUInt64", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt64", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "8", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "(ulong)firstOp[i] != result[i]"}), + ("SveLoadMaskedUnOpTest.template", new Dictionary { ["TestName"] = "SveLoadVectorInt32SignExtendToInt64", ["Isa"] = "Sve", ["Method"] = "LoadVectorInt32SignExtendToInt64", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Int64", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "8", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), + ("SveLoadMaskedUnOpTest.template", new Dictionary { ["TestName"] = "SveLoadVectorInt32SignExtendToUInt64", ["Isa"] = "Sve", ["Method"] = "LoadVectorInt32SignExtendToUInt64", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt64", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "8", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "(ulong)firstOp[i] != result[i]"}), + ("SveLoadMaskedUnOpTest.template", new Dictionary { ["TestName"] = "SveLoadVectorSByteSignExtendToInt16", ["Isa"] = "Sve", ["Method"] = "LoadVectorSByteSignExtendToInt16", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Int16", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "8", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), + ("SveLoadMaskedUnOpTest.template", new Dictionary { ["TestName"] = "SveLoadVectorSByteSignExtendToInt32", ["Isa"] = "Sve", ["Method"] = "LoadVectorSByteSignExtendToInt32", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Int32", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "8", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), + ("SveLoadMaskedUnOpTest.template", new Dictionary { ["TestName"] = "SveLoadVectorSByteSignExtendToInt64", ["Isa"] = "Sve", ["Method"] = "LoadVectorSByteSignExtendToInt64", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Int64", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "8", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), + ("SveLoadMaskedUnOpTest.template", new Dictionary { ["TestName"] = "SveLoadVectorSByteSignExtendToUInt16", ["Isa"] = "Sve", ["Method"] = "LoadVectorSByteSignExtendToUInt16", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt16", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "8", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), + ("SveLoadMaskedUnOpTest.template", new Dictionary { ["TestName"] = "SveLoadVectorSByteSignExtendToUInt32", ["Isa"] = "Sve", ["Method"] = "LoadVectorSByteSignExtendToUInt32", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt32", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "8", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), + ("SveLoadMaskedUnOpTest.template", new Dictionary { ["TestName"] = "SveLoadVectorSByteSignExtendToUInt64", ["Isa"] = "Sve", ["Method"] = "LoadVectorSByteSignExtendToUInt64", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt64", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "8", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "(ulong)firstOp[i] != result[i]"}), + ("SveLoadMaskedUnOpTest.template", new Dictionary { ["TestName"] = "SveLoadVectorUInt16ZeroExtendToInt32", ["Isa"] = "Sve", ["Method"] = "LoadVectorUInt16ZeroExtendToInt32", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Int32", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "8", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), + ("SveLoadMaskedUnOpTest.template", new Dictionary { ["TestName"] = "SveLoadVectorUInt16ZeroExtendToInt64", ["Isa"] = "Sve", ["Method"] = "LoadVectorUInt16ZeroExtendToInt64", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Int64", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "8", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), + ("SveLoadMaskedUnOpTest.template", new Dictionary { ["TestName"] = "SveLoadVectorUInt16ZeroExtendToUInt32", ["Isa"] = "Sve", ["Method"] = "LoadVectorUInt16ZeroExtendToUInt32", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt32", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "8", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), + ("SveLoadMaskedUnOpTest.template", new Dictionary { ["TestName"] = "SveLoadVectorUInt16ZeroExtendToUInt64", ["Isa"] = "Sve", ["Method"] = "LoadVectorUInt16ZeroExtendToUInt64", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt64", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "8", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), + ("SveLoadMaskedUnOpTest.template", new Dictionary { ["TestName"] = "SveLoadVectorUInt32ZeroExtendToInt64", ["Isa"] = "Sve", ["Method"] = "LoadVectorUInt32ZeroExtendToInt64", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Int64", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "8", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), + ("SveLoadMaskedUnOpTest.template", new Dictionary { ["TestName"] = "SveLoadVectorUInt32ZeroExtendToUInt64", ["Isa"] = "Sve", ["Method"] = "LoadVectorUInt32ZeroExtendToUInt64", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt64", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "8", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), + ("SveVecPairBinOpTest.template", new Dictionary { ["TestName"] = "SveUnzipEven_float", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "UnzipEven", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateEntry"] = "result[index] != left[i] || result[index + half] != right[i]"}), + ("SveVecPairBinOpTest.template", new Dictionary { ["TestName"] = "SveUnzipEven_double", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "UnzipEven", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "Double", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["ValidateEntry"] = "result[index] != left[i] || result[index + half] != right[i]"}), + ("SveVecPairBinOpTest.template", new Dictionary { ["TestName"] = "SveUnzipEven_sbyte", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "UnzipEven", ["RetVectorType"] = "Vector", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateEntry"] = "result[index] != left[i] || result[index + half] != right[i]"}), + ("SveVecPairBinOpTest.template", new Dictionary { ["TestName"] = "SveUnzipEven_short", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "UnzipEven", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateEntry"] = "result[index] != left[i] || result[index + half] != right[i]"}), + ("SveVecPairBinOpTest.template", new Dictionary { ["TestName"] = "SveUnzipEven_int", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "UnzipEven", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateEntry"] = "result[index] != left[i] || result[index + half] != right[i]"}), + ("SveVecPairBinOpTest.template", new Dictionary { ["TestName"] = "SveUnzipEven_long", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "UnzipEven", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Int64", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "Int64", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt64()", ["ValidateEntry"] = "result[index] != left[i] || result[index + half] != right[i]"}), + ("SveVecPairBinOpTest.template", new Dictionary { ["TestName"] = "SveUnzipEven_byte", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "UnzipEven", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateEntry"] = "result[index] != left[i] || result[index + half] != right[i]"}), + ("SveVecPairBinOpTest.template", new Dictionary { ["TestName"] = "SveUnzipEven_ushort", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "UnzipEven", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["ValidateEntry"] = "result[index] != left[i] || result[index + half] != right[i]"}), + ("SveVecPairBinOpTest.template", new Dictionary { ["TestName"] = "SveUnzipEven_uint", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "UnzipEven", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["ValidateEntry"] = "result[index] != left[i] || result[index + half] != right[i]"}), + ("SveVecPairBinOpTest.template", new Dictionary { ["TestName"] = "SveUnzipEven_ulong", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "UnzipEven", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt64", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "UInt64", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt64()", ["ValidateEntry"] = "result[index] != left[i] || result[index + half] != right[i]"}), + ("SveVecPairBinOpTest.template", new Dictionary { ["TestName"] = "SveUnzipOdd_float", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "UnzipOdd", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateEntry"] = "result[index] != left[i + 1] || result[index + half] != right[i + 1]"}), + ("SveVecPairBinOpTest.template", new Dictionary { ["TestName"] = "SveUnzipOdd_double", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "UnzipOdd", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "Double", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["ValidateEntry"] = "result[index] != left[i + 1] || result[index + half] != right[i + 1]"}), + ("SveVecPairBinOpTest.template", new Dictionary { ["TestName"] = "SveUnzipOdd_sbyte", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "UnzipOdd", ["RetVectorType"] = "Vector", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateEntry"] = "result[index] != left[i + 1] || result[index + half] != right[i + 1]"}), + ("SveVecPairBinOpTest.template", new Dictionary { ["TestName"] = "SveUnzipOdd_short", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "UnzipOdd", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateEntry"] = "result[index] != left[i + 1] || result[index + half] != right[i + 1]"}), + ("SveVecPairBinOpTest.template", new Dictionary { ["TestName"] = "SveUnzipOdd_int", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "UnzipOdd", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateEntry"] = "result[index] != left[i + 1] || result[index + half] != right[i + 1]"}), + ("SveVecPairBinOpTest.template", new Dictionary { ["TestName"] = "SveUnzipOdd_long", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "UnzipOdd", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Int64", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "Int64", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt64()", ["ValidateEntry"] = "result[index] != left[i + 1] || result[index + half] != right[i + 1]"}), + ("SveVecPairBinOpTest.template", new Dictionary { ["TestName"] = "SveUnzipOdd_byte", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "UnzipOdd", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateEntry"] = "result[index] != left[i + 1] || result[index + half] != right[i + 1]"}), + ("SveVecPairBinOpTest.template", new Dictionary { ["TestName"] = "SveUnzipOdd_ushort", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "UnzipOdd", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["ValidateEntry"] = "result[index] != left[i + 1] || result[index + half] != right[i + 1]"}), + ("SveVecPairBinOpTest.template", new Dictionary { ["TestName"] = "SveUnzipOdd_uint", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "UnzipOdd", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["ValidateEntry"] = "result[index] != left[i + 1] || result[index + half] != right[i + 1]"}), + ("SveVecPairBinOpTest.template", new Dictionary { ["TestName"] = "SveUnzipOdd_ulong", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "UnzipOdd", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt64", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "UInt64", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt64()", ["ValidateEntry"] = "result[index] != left[i + 1] || result[index + half] != right[i + 1]"}), + ("SveVecPairBinOpTest.template", new Dictionary { ["TestName"] = "SveZipHigh_float", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "ZipHigh", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateEntry"] = "result[i] != left[index + half] || result[i + 1] != right[index + half]"}), + ("SveVecPairBinOpTest.template", new Dictionary { ["TestName"] = "SveZipHigh_double", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "ZipHigh", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "Double", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["ValidateEntry"] = "result[i] != left[index + half] || result[i + 1] != right[index + half]"}), + ("SveVecPairBinOpTest.template", new Dictionary { ["TestName"] = "SveZipHigh_sbyte", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "ZipHigh", ["RetVectorType"] = "Vector", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateEntry"] = "result[i] != left[index + half] || result[i + 1] != right[index + half]"}), + ("SveVecPairBinOpTest.template", new Dictionary { ["TestName"] = "SveZipHigh_short", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "ZipHigh", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateEntry"] = "result[i] != left[index + half] || result[i + 1] != right[index + half]"}), + ("SveVecPairBinOpTest.template", new Dictionary { ["TestName"] = "SveZipHigh_int", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "ZipHigh", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateEntry"] = "result[i] != left[index + half] || result[i + 1] != right[index + half]"}), + ("SveVecPairBinOpTest.template", new Dictionary { ["TestName"] = "SveZipHigh_long", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "ZipHigh", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Int64", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "Int64", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt64()", ["ValidateEntry"] = "result[i] != left[index + half] || result[i + 1] != right[index + half]"}), + ("SveVecPairBinOpTest.template", new Dictionary { ["TestName"] = "SveZipHigh_byte", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "ZipHigh", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateEntry"] = "result[i] != left[index + half] || result[i + 1] != right[index + half]"}), + ("SveVecPairBinOpTest.template", new Dictionary { ["TestName"] = "SveZipHigh_ushort", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "ZipHigh", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["ValidateEntry"] = "result[i] != left[index + half] || result[i + 1] != right[index + half]"}), + ("SveVecPairBinOpTest.template", new Dictionary { ["TestName"] = "SveZipHigh_uint", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "ZipHigh", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["ValidateEntry"] = "result[i] != left[index + half] || result[i + 1] != right[index + half]"}), + ("SveVecPairBinOpTest.template", new Dictionary { ["TestName"] = "SveZipHigh_ulong", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "ZipHigh", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt64", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "UInt64", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt64()", ["ValidateEntry"] = "result[i] != left[index + half] || result[i + 1] != right[index + half]"}), + ("SveVecPairBinOpTest.template", new Dictionary { ["TestName"] = "SveZipLow_float", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "ZipLow", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateEntry"] = "result[i] != left[index] || result[i + 1] != right[index]"}), + ("SveVecPairBinOpTest.template", new Dictionary { ["TestName"] = "SveZipLow_double", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "ZipLow", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "Double", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["ValidateEntry"] = "result[i] != left[index] || result[i + 1] != right[index]"}), + ("SveVecPairBinOpTest.template", new Dictionary { ["TestName"] = "SveZipLow_sbyte", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "ZipLow", ["RetVectorType"] = "Vector", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateEntry"] = "result[i] != left[index] || result[i + 1] != right[index]"}), + ("SveVecPairBinOpTest.template", new Dictionary { ["TestName"] = "SveZipLow_short", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "ZipLow", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateEntry"] = "result[i] != left[index] || result[i + 1] != right[index]"}), + ("SveVecPairBinOpTest.template", new Dictionary { ["TestName"] = "SveZipLow_int", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "ZipLow", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateEntry"] = "result[i] != left[index] || result[i + 1] != right[index]"}), + ("SveVecPairBinOpTest.template", new Dictionary { ["TestName"] = "SveZipLow_long", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "ZipLow", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Int64", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "Int64", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt64()", ["ValidateEntry"] = "result[i] != left[index] || result[i + 1] != right[index]"}), + ("SveVecPairBinOpTest.template", new Dictionary { ["TestName"] = "SveZipLow_byte", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "ZipLow", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateEntry"] = "result[i] != left[index] || result[i + 1] != right[index]"}), + ("SveVecPairBinOpTest.template", new Dictionary { ["TestName"] = "SveZipLow_ushort", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "ZipLow", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["ValidateEntry"] = "result[i] != left[index] || result[i + 1] != right[index]"}), + ("SveVecPairBinOpTest.template", new Dictionary { ["TestName"] = "SveZipLow_uint", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "ZipLow", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["ValidateEntry"] = "result[i] != left[index] || result[i + 1] != right[index]"}), + ("SveVecPairBinOpTest.template", new Dictionary { ["TestName"] = "SveZipLow_ulong", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "ZipLow", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt64", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "UInt64", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt64()", ["ValidateEntry"] = "result[i] != left[index] || result[i + 1] != right[index]"}), }; diff --git a/src/tests/JIT/HardwareIntrinsics/Arm/Shared/_BinaryOp_SveTestTemplate.template b/src/tests/JIT/HardwareIntrinsics/Arm/Shared/_BinaryOp_SveTestTemplate.template new file mode 100644 index 00000000000000..19923127555c1e --- /dev/null +++ b/src/tests/JIT/HardwareIntrinsics/Arm/Shared/_BinaryOp_SveTestTemplate.template @@ -0,0 +1,327 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Numerics; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; +using Xunit; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + [Fact] + public static void {TestName}() + { + var test = new {TemplateName}BinaryOpTest__{TestName}(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if ({LoadIsa}.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class {TemplateName}BinaryOpTest__{TestName} + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable({Op1BaseType}[] inArray1, {Op2BaseType}[] inArray2, {RetBaseType}[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf<{Op1BaseType}>(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf<{Op2BaseType}>(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf<{RetBaseType}>(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As<{Op1BaseType}, byte>(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As<{Op2BaseType}, byte>(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public {Op1VectorType}<{Op1BaseType}> _fld1; + public {Op2VectorType}<{Op2BaseType}> _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = {NextValueOp1}; } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<{Op1VectorType}<{Op1BaseType}>, byte>(ref testStruct._fld1), ref Unsafe.As<{Op1BaseType}, byte>(ref _data1[0]), (uint)Unsafe.SizeOf<{Op1VectorType}<{Op1BaseType}>>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = {NextValueOp2}; } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<{Op2VectorType}<{Op2BaseType}>, byte>(ref testStruct._fld2), ref Unsafe.As<{Op2BaseType}, byte>(ref _data2[0]), (uint)Unsafe.SizeOf<{Op2VectorType}<{Op2BaseType}>>()); + + return testStruct; + } + + public void RunStructFldScenario({TemplateName}BinaryOpTest__{TestName} testClass) + { + var result = {Isa}.{Method}(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + + private static readonly int LargestVectorSize = {LargestVectorSize}; + + private static readonly int Op1ElementCount = Unsafe.SizeOf<{Op1VectorType}<{Op1BaseType}>>() / sizeof({Op1BaseType}); + private static readonly int Op2ElementCount = Unsafe.SizeOf<{Op2VectorType}<{Op2BaseType}>>() / sizeof({Op2BaseType}); + private static readonly int RetElementCount = Unsafe.SizeOf<{RetVectorType}<{RetBaseType}>>() / sizeof({RetBaseType}); + + private static {Op1BaseType}[] _data1 = new {Op1BaseType}[Op1ElementCount]; + private static {Op2BaseType}[] _data2 = new {Op2BaseType}[Op2ElementCount]; + + private {Op1VectorType}<{Op1BaseType}> _fld1; + private {Op2VectorType}<{Op2BaseType}> _fld2; + + private DataTable _dataTable; + + public {TemplateName}BinaryOpTest__{TestName}() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = {NextValueOp1}; } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<{Op1VectorType}<{Op1BaseType}>, byte>(ref _fld1), ref Unsafe.As<{Op1BaseType}, byte>(ref _data1[0]), (uint)Unsafe.SizeOf<{Op1VectorType}<{Op1BaseType}>>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = {NextValueOp2}; } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<{Op2VectorType}<{Op2BaseType}>, byte>(ref _fld2), ref Unsafe.As<{Op2BaseType}, byte>(ref _data2[0]), (uint)Unsafe.SizeOf<{Op2VectorType}<{Op2BaseType}>>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = {NextValueOp1}; } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = {NextValueOp2}; } + _dataTable = new DataTable(_data1, _data2, new {RetBaseType}[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => {Isa}.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = {Isa}.{Method}( + Unsafe.Read<{Op1VectorType}<{Op1BaseType}>>(_dataTable.inArray1Ptr), + Unsafe.Read<{Op2VectorType}<{Op2BaseType}>>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + Vector<{Op1BaseType}> loadMask = Sve.CreateTrueMask{Op1BaseType}(SveMaskPattern.All); + + var result = {Isa}.{Method}( + {LoadIsa}.Load{Op1VectorType}(loadMask, ({Op1BaseType}*)(_dataTable.inArray1Ptr)), + {LoadIsa}.Load{Op2VectorType}(loadMask, ({Op2BaseType}*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof({Isa}).GetMethod(nameof({Isa}.{Method}), new Type[] { typeof({Op1VectorType}<{Op1BaseType}>), typeof({Op2VectorType}<{Op2BaseType}>) }) + .Invoke(null, new object[] { + Unsafe.Read<{Op1VectorType}<{Op1BaseType}>>(_dataTable.inArray1Ptr), + Unsafe.Read<{Op2VectorType}<{Op2BaseType}>>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, ({RetVectorType}<{RetBaseType}>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read<{Op1VectorType}<{Op1BaseType}>>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read<{Op2VectorType}<{Op2BaseType}>>(_dataTable.inArray2Ptr); + var result = {Isa}.{Method}(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = {Isa}.{Method}(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = {Isa}.{Method}(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult({Op1VectorType}<{Op1BaseType}> op1, {Op2VectorType}<{Op2BaseType}> op2, void* result, [CallerMemberName] string method = "") + { + {Op1BaseType}[] inArray1 = new {Op1BaseType}[Op1ElementCount]; + {Op2BaseType}[] inArray2 = new {Op2BaseType}[Op2ElementCount]; + {RetBaseType}[] outArray = new {RetBaseType}[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As<{Op1BaseType}, byte>(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As<{Op2BaseType}, byte>(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<{RetBaseType}, byte>(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf<{RetVectorType}<{RetBaseType}>>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + {Op1BaseType}[] inArray1 = new {Op1BaseType}[Op1ElementCount]; + {Op2BaseType}[] inArray2 = new {Op2BaseType}[Op2ElementCount]; + {RetBaseType}[] outArray = new {RetBaseType}[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As<{Op1BaseType}, byte>(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf<{Op1VectorType}<{Op1BaseType}>>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<{Op2BaseType}, byte>(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf<{Op2VectorType}<{Op2BaseType}>>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<{RetBaseType}, byte>(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf<{RetVectorType}<{RetBaseType}>>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult({Op1BaseType}[] left, {Op2BaseType}[] right, {RetBaseType}[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + {TemplateValidationLogic} + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof({Isa})}.{nameof({Isa}.{Method})}<{RetBaseType}>({Op1VectorType}<{Op1BaseType}>, {Op2VectorType}<{Op2BaseType}>): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} From c5ca516583831091a5659e723db56a689b13be13 Mon Sep 17 00:00:00 2001 From: Stephen Toub Date: Fri, 26 Apr 2024 12:45:45 -0400 Subject: [PATCH 101/161] Fix regression in RegexGenerator.GetSHA256FieldName (#101606) A previous refactoring deleted the use of the hash. --- .../gen/RegexGenerator.Emitter.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libraries/System.Text.RegularExpressions/gen/RegexGenerator.Emitter.cs b/src/libraries/System.Text.RegularExpressions/gen/RegexGenerator.Emitter.cs index b2ab52c4c71fac..0a6cb3212cb2fa 100644 --- a/src/libraries/System.Text.RegularExpressions/gen/RegexGenerator.Emitter.cs +++ b/src/libraries/System.Text.RegularExpressions/gen/RegexGenerator.Emitter.cs @@ -5405,7 +5405,7 @@ private static string GetSHA256FieldName(string prefix, string toEncode) { #pragma warning disable CA1850 // SHA256.HashData isn't available on netstandard2.0 using SHA256 sha = SHA256.Create(); - return $"{prefix}{ToHexStringNoDashes(Encoding.UTF8.GetBytes(toEncode))}"; + return $"{prefix}{ToHexStringNoDashes(sha.ComputeHash(Encoding.UTF8.GetBytes(toEncode)))}"; #pragma warning restore CA1850 } From c29b59199057ba0a63e055284f4d3879fd203c48 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Fri, 26 Apr 2024 19:05:48 +0200 Subject: [PATCH 102/161] Implement Activity.AddLink (#101381) * implement Activity.AddLink * extend tests * Add remarks to docs required by https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/trace/api.md#link --- ...em.Diagnostics.DiagnosticSourceActivity.cs | 1 + .../src/System/Diagnostics/Activity.cs | 19 +++++++++++ .../tests/ActivityTests.cs | 34 +++++++++++++++++++ 3 files changed, 54 insertions(+) diff --git a/src/libraries/System.Diagnostics.DiagnosticSource/ref/System.Diagnostics.DiagnosticSourceActivity.cs b/src/libraries/System.Diagnostics.DiagnosticSource/ref/System.Diagnostics.DiagnosticSourceActivity.cs index 3908224b0a1a13..47677b1f612b56 100644 --- a/src/libraries/System.Diagnostics.DiagnosticSource/ref/System.Diagnostics.DiagnosticSourceActivity.cs +++ b/src/libraries/System.Diagnostics.DiagnosticSource/ref/System.Diagnostics.DiagnosticSourceActivity.cs @@ -50,6 +50,7 @@ public string? Id public string? TraceStateString { get { throw null; } set { } } public System.Diagnostics.Activity AddBaggage(string key, string? value) { throw null; } public System.Diagnostics.Activity AddEvent(System.Diagnostics.ActivityEvent e) { throw null; } + public System.Diagnostics.Activity AddLink(System.Diagnostics.ActivityLink link) { throw null; } public System.Diagnostics.Activity AddTag(string key, string? value) { throw null; } public System.Diagnostics.Activity AddTag(string key, object? value) { throw null; } public System.Diagnostics.Activity SetTag(string key, object? value) { throw null; } diff --git a/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Activity.cs b/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Activity.cs index 0605251a93b7a7..3a332ec4f13239 100644 --- a/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Activity.cs +++ b/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Activity.cs @@ -517,6 +517,25 @@ public Activity AddEvent(ActivityEvent e) return this; } + /// + /// Add an to the list. + /// + /// The to add. + /// for convenient chaining. + /// + /// For contexts that are available during span creation, adding links at span creation is preferred to calling later, + /// because head sampling decisions can only consider information present during span creation. + /// + public Activity AddLink(ActivityLink link) + { + if (_links != null || Interlocked.CompareExchange(ref _links, new DiagLinkedList(link), null) != null) + { + _links.Add(link); + } + + return this; + } + /// /// Update the Activity to have baggage with an additional 'key' and value 'value'. /// This shows up in the enumeration as well as the diff --git a/src/libraries/System.Diagnostics.DiagnosticSource/tests/ActivityTests.cs b/src/libraries/System.Diagnostics.DiagnosticSource/tests/ActivityTests.cs index ae3c138e369714..00cb26017a3846 100644 --- a/src/libraries/System.Diagnostics.DiagnosticSource/tests/ActivityTests.cs +++ b/src/libraries/System.Diagnostics.DiagnosticSource/tests/ActivityTests.cs @@ -1597,6 +1597,35 @@ public void TestEvent() Assert.Equal(0, activity.Events.ElementAt(1).Tags.Count()); } + [Fact] + public void AddLinkTest() + { + ActivityContext c1 = new ActivityContext(ActivityTraceId.CreateRandom(), ActivitySpanId.CreateRandom(), ActivityTraceFlags.None); + ActivityContext c2 = new ActivityContext(ActivityTraceId.CreateRandom(), ActivitySpanId.CreateRandom(), ActivityTraceFlags.None); + + ActivityLink l1 = new ActivityLink(c1); + ActivityLink l2 = new ActivityLink(c2, new ActivityTagsCollection() + { + new KeyValuePair("foo", 99) + }); + + Activity activity = new Activity("LinkTest"); + Assert.True(ReferenceEquals(activity, activity.AddLink(l1))); + Assert.True(ReferenceEquals(activity, activity.AddLink(l2))); + + // Add a duplicate of l1. The implementation doesn't check for duplicates. + Assert.True(ReferenceEquals(activity, activity.AddLink(l1))); + + ActivityLink[] links = activity.Links.ToArray(); + Assert.Equal(3, links.Length); + Assert.Equal(c1, links[0].Context); + Assert.Equal(c2, links[1].Context); + Assert.Equal(c1, links[2].Context); + KeyValuePair tag = links[1].Tags.Single(); + Assert.Equal("foo", tag.Key); + Assert.Equal(99, tag.Value); + } + [Fact] public void TestIsAllDataRequested() { @@ -2163,12 +2192,14 @@ public void EnumerateLinksTest() var context1 = new ActivityContext(ActivityTraceId.CreateRandom(), default, ActivityTraceFlags.None); var context2 = new ActivityContext(ActivityTraceId.CreateRandom(), default, ActivityTraceFlags.None); + var context3 = new ActivityContext(ActivityTraceId.CreateRandom(), default, ActivityTraceFlags.None); a = source.CreateActivity( name: "Root", kind: ActivityKind.Internal, parentContext: default, links: new[] { new ActivityLink(context1), new ActivityLink(context2) }); + a.AddLink(new ActivityLink(context3)); Assert.NotNull(a); @@ -2182,6 +2213,9 @@ public void EnumerateLinksTest() Assert.True(enumerator.MoveNext()); Assert.Equal(context2.TraceId, enumerator.Current.Context.TraceId); values.Add(enumerator.Current); + Assert.True(enumerator.MoveNext()); + Assert.Equal(context3.TraceId, enumerator.Current.Context.TraceId); + values.Add(enumerator.Current); Assert.False(enumerator.MoveNext()); Assert.Equal(a.Links, values); From b8f96afc39bab9fae5065afa26e58c1200935d25 Mon Sep 17 00:00:00 2001 From: Radek Doulik Date: Fri, 26 Apr 2024 19:59:29 +0200 Subject: [PATCH 103/161] [wasm] Add optimization flags to bitcode compilation (#101538) * [wasm] Add optimization flag to bitcode compilation comping from LD optimization flags. This should also fix the recent size regression. * Document the new property * Update src/mono/browser/build/BrowserWasmApp.targets Co-authored-by: Larry Ewing * Fix the conditions --------- Co-authored-by: Larry Ewing --- src/mono/browser/build/BrowserWasmApp.targets | 3 +++ src/mono/wasi/build/WasiApp.targets | 3 +++ src/mono/wasm/build/WasmApp.Common.targets | 2 ++ 3 files changed, 8 insertions(+) diff --git a/src/mono/browser/build/BrowserWasmApp.targets b/src/mono/browser/build/BrowserWasmApp.targets index 484d3486c5eaa8..d75513604304c6 100644 --- a/src/mono/browser/build/BrowserWasmApp.targets +++ b/src/mono/browser/build/BrowserWasmApp.targets @@ -260,6 +260,8 @@ $(_EmccOptimizationFlagDefault) $(EmccCompileOptimizationFlag) + -O2 + $(WasmCompileOptimizationFlag) -O2 $(WasmCompileOptimizationFlag) $(EmccLinkOptimizationFlag) @@ -406,6 +408,7 @@ + <_BitcodeCompileFlags Include="$(WasmBitcodeCompileOptimizationFlag)" /> <_BitcodeCompileFlags Include="@(_EmccCommonFlags)" /> <_BitcodeCompileFlags Include="$(EmccExtraBitcodeCompilationFlags)" /> diff --git a/src/mono/wasi/build/WasiApp.targets b/src/mono/wasi/build/WasiApp.targets index c5ecf84ad0c73c..cad25a76067295 100644 --- a/src/mono/wasi/build/WasiApp.targets +++ b/src/mono/wasi/build/WasiApp.targets @@ -148,6 +148,8 @@ $(_WasiClangOptimizationFlagDefault) $(WasiClangCompileOptimizationFlag) + -O2 + $(WasiClangCompileOptimizationFlag) -O2 $(WasiClangCompileOptimizationFlag) $(WasiClangLinkOptimizationFlag) @@ -265,6 +267,7 @@ + <_BitcodeCompileFlags Include="@(WasiBitcodeCompileOptimizationFlag)" /> <_BitcodeCompileFlags Include="@(_WasiClangCommonFlags)" /> <_BitcodeCompileFlags Include="$(WasiClangExtraBitcodeCompileFlags)" /> diff --git a/src/mono/wasm/build/WasmApp.Common.targets b/src/mono/wasm/build/WasmApp.Common.targets index f06b9a1261fe5e..e9cda6ccea50e1 100644 --- a/src/mono/wasm/build/WasmApp.Common.targets +++ b/src/mono/wasm/build/WasmApp.Common.targets @@ -44,6 +44,8 @@ - $(EmccLinkOptimizationFlag) - Optimization flag to use for the link step - $(EmccCompileOptimizationFlag) - Optimization flag to use for compiling native files + - $(WasmBitcodeCompileOptimizationFlag) + - Optimization flag to use for compiling bitcode files - $(EmccFlags) - Emcc flags used for both compiling native files, and linking - $(EmccExtraLDFlags) - Extra emcc flags for linking From c652f1095bd8e02b7762b1f6a019db49fab03416 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Fi=C5=A1era?= Date: Fri, 26 Apr 2024 20:00:02 +0200 Subject: [PATCH 104/161] [wasi] Separate payload directories per WorkItemPrefix (#101599) * Separate wasi payload dirs per WorkItemPrefix * Use NormalizeDirectory * Remove debug output * Revert NormalizeDirectory --- src/libraries/sendtohelix-wasi.targets | 6 ++---- src/libraries/sendtohelix-wasm.targets | 16 ++++++++-------- 2 files changed, 10 insertions(+), 12 deletions(-) diff --git a/src/libraries/sendtohelix-wasi.targets b/src/libraries/sendtohelix-wasi.targets index e634fa0c2ea3f8..8a1902eb378fc5 100644 --- a/src/libraries/sendtohelix-wasi.targets +++ b/src/libraries/sendtohelix-wasi.targets @@ -48,8 +48,8 @@ $(RepoRoot)src\mono\wasi\wasi-sdk\ $([MSBuild]::NormalizeDirectory('$(RepoRoot)', 'src', 'mono', 'wasi', 'build')) - $(HelixDependenciesStagingPath)\wasi-sdk - $(HelixDependenciesStagingPath)\wasmtime + $(HelixDependenciesStagingPath)$(WorkItemPrefix)wasi-sdk + $(HelixDependenciesStagingPath)$(WorkItemPrefix)wasmtime true true @@ -110,8 +110,6 @@ - - diff --git a/src/libraries/sendtohelix-wasm.targets b/src/libraries/sendtohelix-wasm.targets index 10dc71976f62b8..3fce57cf9c4e1b 100644 --- a/src/libraries/sendtohelix-wasm.targets +++ b/src/libraries/sendtohelix-wasm.targets @@ -9,6 +9,14 @@ $([MSBuild]::NormalizeDirectory($(WasmProjectRoot), 'build')) + + Workloads- + NoWorkload- + $(WorkItemPrefix)NoWebcil- + $(WorkItemPrefix)ST- + $(WorkItemPrefix)MT- + + @@ -27,14 +35,6 @@ - - Workloads- - NoWorkload- - $(WorkItemPrefix)NoWebcil- - $(WorkItemPrefix)ST- - $(WorkItemPrefix)MT- - - <_WasmWorkItem Include="$(WorkItemArchiveWildCard)" Exclude="$(HelixCorrelationPayload)" /> From 4c14fb030f7504cf503ea06549fb390b8c2770b8 Mon Sep 17 00:00:00 2001 From: Alan Hayward Date: Fri, 26 Apr 2024 19:14:13 +0100 Subject: [PATCH 105/161] JIT ARM64-SVE: Add Count*BitElements (#101188) * JIT ARM64-SVE: Add Count*BitElements * Generic ValidateResult testing * Fix formatting * Add option to change SVE vector length for current and children processes. TEST_LABEL: ent-arch-aarch64 TEST_IMG: ubuntu/dotnet-build TEST_CMD: safe ./projects/dotnet/test-runtime.sh --scope coreclr,libs Jira: ENTLLT-7328 Change-Id: I727edf8652a5c8648e7008d4ca47e7a4f36d5a1e * Revert "Add option to change SVE vector length for current and children processes." This reverts commit 293755790176a75fb985e50300c4f3e5d1728066. * fix CreateTrueMask --------- Co-authored-by: Swapnil Gaikwad --- src/coreclr/jit/hwintrinsic.h | 14 +- src/coreclr/jit/hwintrinsicarm64.cpp | 4 + src/coreclr/jit/hwintrinsiccodegenarm64.cpp | 18 +- src/coreclr/jit/hwintrinsiclistarm64sve.h | 24 +- src/coreclr/jit/lowerarmarch.cpp | 4 + src/coreclr/jit/lsraarm64.cpp | 4 + .../Arm/Sve.PlatformNotSupported.cs | 159 ++++++++----- .../src/System/Runtime/Intrinsics/Arm/Sve.cs | 214 ++++++++++-------- .../ref/System.Runtime.Intrinsics.cs | 24 +- .../GenerateHWIntrinsicTests_Arm.cs | 5 + .../Arm/Shared/ScalarUnOpTest.template | 1 + 11 files changed, 297 insertions(+), 174 deletions(-) diff --git a/src/coreclr/jit/hwintrinsic.h b/src/coreclr/jit/hwintrinsic.h index e7bd08d5cb33dc..82cf179c742f4f 100644 --- a/src/coreclr/jit/hwintrinsic.h +++ b/src/coreclr/jit/hwintrinsic.h @@ -58,7 +58,6 @@ enum HWIntrinsicCategory : uint8_t HW_Category_ShiftLeftByImmediate, HW_Category_ShiftRightByImmediate, HW_Category_SIMDByIndexedElement, - HW_Category_EnumPattern, // Helper intrinsics // - do not directly correspond to a instruction, such as Vector64.AllBitsSet @@ -232,6 +231,11 @@ enum HWIntrinsicFlag : unsigned int // The intrinsic is an embedded masking incompatible intrinsic HW_Flag_EmbMaskingIncompatible = 0x20000000, +#elif defined(TARGET_ARM64) + + // The intrinsic has an enum operand. Using this implies HW_Flag_HasImmediateOperand. + HW_Flag_HasEnumOperand = 0x1000000, + #endif // TARGET_XARCH HW_Flag_CanBenefitFromConstantProp = 0x80000000, @@ -867,7 +871,7 @@ struct HWIntrinsicInfo static bool HasImmediateOperand(NamedIntrinsic id) { const HWIntrinsicFlag flags = lookupFlags(id); - return (flags & HW_Flag_HasImmediateOperand) != 0; + return ((flags & HW_Flag_HasImmediateOperand) != 0) || HasEnumOperand(id); } static bool IsScalable(NamedIntrinsic id) @@ -906,6 +910,12 @@ struct HWIntrinsicInfo return (flags & HW_Flag_ExplicitMaskedOperation) != 0; } + static bool HasEnumOperand(NamedIntrinsic id) + { + const HWIntrinsicFlag flags = lookupFlags(id); + return (flags & HW_Flag_HasEnumOperand) != 0; + } + #endif // TARGET_ARM64 static bool HasSpecialSideEffect(NamedIntrinsic id) diff --git a/src/coreclr/jit/hwintrinsicarm64.cpp b/src/coreclr/jit/hwintrinsicarm64.cpp index 07018824458a0b..90dde12bde8220 100644 --- a/src/coreclr/jit/hwintrinsicarm64.cpp +++ b/src/coreclr/jit/hwintrinsicarm64.cpp @@ -290,6 +290,10 @@ void HWIntrinsicInfo::lookupImmBounds( case NI_Sve_CreateTrueMaskUInt16: case NI_Sve_CreateTrueMaskUInt32: case NI_Sve_CreateTrueMaskUInt64: + case NI_Sve_Count16BitElements: + case NI_Sve_Count32BitElements: + case NI_Sve_Count64BitElements: + case NI_Sve_Count8BitElements: immLowerBound = (int)SVE_PATTERN_POW2; immUpperBound = (int)SVE_PATTERN_ALL; break; diff --git a/src/coreclr/jit/hwintrinsiccodegenarm64.cpp b/src/coreclr/jit/hwintrinsiccodegenarm64.cpp index 462aaa521c6756..e9983f700361c5 100644 --- a/src/coreclr/jit/hwintrinsiccodegenarm64.cpp +++ b/src/coreclr/jit/hwintrinsiccodegenarm64.cpp @@ -380,7 +380,7 @@ void CodeGen::genHWIntrinsic(GenTreeHWIntrinsic* node) emitShift(intrin.op2, op1Reg); } } - else if (intrin.category == HW_Category_EnumPattern) + else if (HWIntrinsicInfo::HasEnumOperand(intrin.id)) { assert(hasImmediateOperand); @@ -1404,6 +1404,22 @@ void CodeGen::genHWIntrinsic(GenTreeHWIntrinsic* node) GetEmitter()->emitIns_R_R_R_I(ins, emitSize, targetReg, op1Reg, op2Reg, 0, opt); break; + case NI_Sve_Count16BitElements: + case NI_Sve_Count32BitElements: + case NI_Sve_Count64BitElements: + case NI_Sve_Count8BitElements: + { + // Instruction has an additional immediate to multiply the result by. Use 1. + assert(hasImmediateOperand); + HWIntrinsicImmOpHelper helper(this, intrin.op1, node); + for (helper.EmitBegin(); !helper.Done(); helper.EmitCaseEnd()) + { + const insSvePattern pattern = (insSvePattern)helper.ImmValue(); + GetEmitter()->emitIns_R_PATTERN_I(ins, emitSize, targetReg, pattern, 1, opt); + } + break; + } + case NI_Sve_CreateTrueMaskAll: // Must use the pattern variant, as the non-pattern varient is SVE2.1. GetEmitter()->emitIns_R_PATTERN(ins, emitSize, targetReg, opt, SVE_PATTERN_ALL); diff --git a/src/coreclr/jit/hwintrinsiclistarm64sve.h b/src/coreclr/jit/hwintrinsiclistarm64sve.h index 773b3766a28a55..ef9740e4556523 100644 --- a/src/coreclr/jit/hwintrinsiclistarm64sve.h +++ b/src/coreclr/jit/hwintrinsiclistarm64sve.h @@ -20,16 +20,20 @@ HARDWARE_INTRINSIC(Sve, Abs, -1, -1, false, {INS_sve_abs, INS_invalid, INS_sve_abs, INS_invalid, INS_sve_abs, INS_invalid, INS_sve_abs, INS_invalid, INS_sve_fabs, INS_sve_fabs}, HW_Category_SIMD, HW_Flag_Scalable|HW_Flag_EmbeddedMaskedOperation) HARDWARE_INTRINSIC(Sve, Add, -1, -1, false, {INS_sve_add, INS_sve_add, INS_sve_add, INS_sve_add, INS_sve_add, INS_sve_add, INS_sve_add, INS_sve_add, INS_sve_fadd, INS_sve_fadd}, HW_Category_SIMD, HW_Flag_Scalable|HW_Flag_OptionalEmbeddedMaskedOperation|HW_Flag_HasRMWSemantics|HW_Flag_LowMaskedOperation) HARDWARE_INTRINSIC(Sve, ConditionalSelect, -1, 3, true, {INS_sve_sel, INS_sve_sel, INS_sve_sel, INS_sve_sel, INS_sve_sel, INS_sve_sel, INS_sve_sel, INS_sve_sel, INS_sve_sel, INS_sve_sel}, HW_Category_SIMD, HW_Flag_Scalable|HW_Flag_ExplicitMaskedOperation|HW_Flag_SupportsContainment) -HARDWARE_INTRINSIC(Sve, CreateTrueMaskByte, -1, 1, false, {INS_invalid, INS_sve_ptrue, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_EnumPattern, HW_Flag_Scalable|HW_Flag_HasImmediateOperand|HW_Flag_ReturnsPerElementMask) -HARDWARE_INTRINSIC(Sve, CreateTrueMaskDouble, -1, 1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sve_ptrue}, HW_Category_EnumPattern, HW_Flag_Scalable|HW_Flag_HasImmediateOperand|HW_Flag_ReturnsPerElementMask) -HARDWARE_INTRINSIC(Sve, CreateTrueMaskInt16, -1, 1, false, {INS_invalid, INS_invalid, INS_sve_ptrue, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_EnumPattern, HW_Flag_Scalable|HW_Flag_HasImmediateOperand|HW_Flag_ReturnsPerElementMask) -HARDWARE_INTRINSIC(Sve, CreateTrueMaskInt32, -1, 1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sve_ptrue, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_EnumPattern, HW_Flag_Scalable|HW_Flag_HasImmediateOperand|HW_Flag_ReturnsPerElementMask) -HARDWARE_INTRINSIC(Sve, CreateTrueMaskInt64, -1, 1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sve_ptrue, INS_invalid, INS_invalid, INS_invalid}, HW_Category_EnumPattern, HW_Flag_Scalable|HW_Flag_HasImmediateOperand|HW_Flag_ReturnsPerElementMask) -HARDWARE_INTRINSIC(Sve, CreateTrueMaskSByte, -1, 1, false, {INS_sve_ptrue, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_EnumPattern, HW_Flag_Scalable|HW_Flag_HasImmediateOperand|HW_Flag_ReturnsPerElementMask) -HARDWARE_INTRINSIC(Sve, CreateTrueMaskSingle, -1, 1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sve_ptrue, INS_invalid}, HW_Category_EnumPattern, HW_Flag_Scalable|HW_Flag_HasImmediateOperand|HW_Flag_ReturnsPerElementMask) -HARDWARE_INTRINSIC(Sve, CreateTrueMaskUInt16, -1, 1, false, {INS_invalid, INS_invalid, INS_invalid, INS_sve_ptrue, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_EnumPattern, HW_Flag_Scalable|HW_Flag_HasImmediateOperand|HW_Flag_ReturnsPerElementMask) -HARDWARE_INTRINSIC(Sve, CreateTrueMaskUInt32, -1, 1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sve_ptrue, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_EnumPattern, HW_Flag_Scalable|HW_Flag_HasImmediateOperand|HW_Flag_ReturnsPerElementMask) -HARDWARE_INTRINSIC(Sve, CreateTrueMaskUInt64, -1, 1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sve_ptrue, INS_invalid, INS_invalid}, HW_Category_EnumPattern, HW_Flag_Scalable|HW_Flag_HasImmediateOperand|HW_Flag_ReturnsPerElementMask) +HARDWARE_INTRINSIC(Sve, Count16BitElements, 0, 1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sve_cnth, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Scalar, HW_Flag_Scalable|HW_Flag_HasEnumOperand|HW_Flag_SpecialCodeGen|HW_Flag_NoFloatingPointUsed) +HARDWARE_INTRINSIC(Sve, Count32BitElements, 0, 1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sve_cntw, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Scalar, HW_Flag_Scalable|HW_Flag_HasEnumOperand|HW_Flag_SpecialCodeGen|HW_Flag_NoFloatingPointUsed) +HARDWARE_INTRINSIC(Sve, Count64BitElements, 0, 1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sve_cntd, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Scalar, HW_Flag_Scalable|HW_Flag_HasEnumOperand|HW_Flag_SpecialCodeGen|HW_Flag_NoFloatingPointUsed) +HARDWARE_INTRINSIC(Sve, Count8BitElements, 0, 1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sve_cntb, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Scalar, HW_Flag_Scalable|HW_Flag_HasEnumOperand|HW_Flag_SpecialCodeGen|HW_Flag_NoFloatingPointUsed) +HARDWARE_INTRINSIC(Sve, CreateTrueMaskByte, -1, 1, false, {INS_invalid, INS_sve_ptrue, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SIMD, HW_Flag_Scalable|HW_Flag_HasEnumOperand|HW_Flag_ReturnsPerElementMask) +HARDWARE_INTRINSIC(Sve, CreateTrueMaskDouble, -1, 1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sve_ptrue}, HW_Category_SIMD, HW_Flag_Scalable|HW_Flag_HasEnumOperand|HW_Flag_ReturnsPerElementMask) +HARDWARE_INTRINSIC(Sve, CreateTrueMaskInt16, -1, 1, false, {INS_invalid, INS_invalid, INS_sve_ptrue, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SIMD, HW_Flag_Scalable|HW_Flag_HasEnumOperand|HW_Flag_ReturnsPerElementMask) +HARDWARE_INTRINSIC(Sve, CreateTrueMaskInt32, -1, 1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sve_ptrue, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SIMD, HW_Flag_Scalable|HW_Flag_HasEnumOperand|HW_Flag_ReturnsPerElementMask) +HARDWARE_INTRINSIC(Sve, CreateTrueMaskInt64, -1, 1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sve_ptrue, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SIMD, HW_Flag_Scalable|HW_Flag_HasEnumOperand|HW_Flag_ReturnsPerElementMask) +HARDWARE_INTRINSIC(Sve, CreateTrueMaskSByte, -1, 1, false, {INS_sve_ptrue, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SIMD, HW_Flag_Scalable|HW_Flag_HasEnumOperand|HW_Flag_ReturnsPerElementMask) +HARDWARE_INTRINSIC(Sve, CreateTrueMaskSingle, -1, 1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sve_ptrue, INS_invalid}, HW_Category_SIMD, HW_Flag_Scalable|HW_Flag_HasEnumOperand|HW_Flag_ReturnsPerElementMask) +HARDWARE_INTRINSIC(Sve, CreateTrueMaskUInt16, -1, 1, false, {INS_invalid, INS_invalid, INS_invalid, INS_sve_ptrue, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SIMD, HW_Flag_Scalable|HW_Flag_HasEnumOperand|HW_Flag_ReturnsPerElementMask) +HARDWARE_INTRINSIC(Sve, CreateTrueMaskUInt32, -1, 1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sve_ptrue, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SIMD, HW_Flag_Scalable|HW_Flag_HasEnumOperand|HW_Flag_ReturnsPerElementMask) +HARDWARE_INTRINSIC(Sve, CreateTrueMaskUInt64, -1, 1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sve_ptrue, INS_invalid, INS_invalid}, HW_Category_SIMD, HW_Flag_Scalable|HW_Flag_HasEnumOperand|HW_Flag_ReturnsPerElementMask) HARDWARE_INTRINSIC(Sve, CreateWhileLessThanMask16Bit, -1, 2, false, {INS_invalid, INS_invalid, INS_invalid, INS_sve_whilelt, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SIMD, HW_Flag_Scalable|HW_Flag_SpecialCodeGen|HW_Flag_ReturnsPerElementMask) HARDWARE_INTRINSIC(Sve, CreateWhileLessThanMask32Bit, -1, 2, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sve_whilelt, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SIMD, HW_Flag_Scalable|HW_Flag_SpecialCodeGen|HW_Flag_ReturnsPerElementMask) HARDWARE_INTRINSIC(Sve, CreateWhileLessThanMask64Bit, -1, 2, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sve_whilelt, INS_invalid, INS_invalid}, HW_Category_SIMD, HW_Flag_Scalable|HW_Flag_SpecialCodeGen|HW_Flag_ReturnsPerElementMask) diff --git a/src/coreclr/jit/lowerarmarch.cpp b/src/coreclr/jit/lowerarmarch.cpp index 7ea9a90d62343e..6456b2b972ea9a 100644 --- a/src/coreclr/jit/lowerarmarch.cpp +++ b/src/coreclr/jit/lowerarmarch.cpp @@ -3295,6 +3295,10 @@ void Lowering::ContainCheckHWIntrinsic(GenTreeHWIntrinsic* node) case NI_Sve_CreateTrueMaskUInt16: case NI_Sve_CreateTrueMaskUInt32: case NI_Sve_CreateTrueMaskUInt64: + case NI_Sve_Count16BitElements: + case NI_Sve_Count32BitElements: + case NI_Sve_Count64BitElements: + case NI_Sve_Count8BitElements: assert(hasImmediateOperand); assert(varTypeIsIntegral(intrin.op1)); if (intrin.op1->IsCnsIntOrI()) diff --git a/src/coreclr/jit/lsraarm64.cpp b/src/coreclr/jit/lsraarm64.cpp index dfcebf4392c53c..6ea3ad27706cea 100644 --- a/src/coreclr/jit/lsraarm64.cpp +++ b/src/coreclr/jit/lsraarm64.cpp @@ -1464,6 +1464,10 @@ int LinearScan::BuildHWIntrinsic(GenTreeHWIntrinsic* intrinsicTree, int* pDstCou case NI_Sve_CreateTrueMaskUInt16: case NI_Sve_CreateTrueMaskUInt32: case NI_Sve_CreateTrueMaskUInt64: + case NI_Sve_Count16BitElements: + case NI_Sve_Count32BitElements: + case NI_Sve_Count64BitElements: + case NI_Sve_Count8BitElements: needBranchTargetReg = !intrin.op1->isContainedIntOrIImmed(); break; diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Arm/Sve.PlatformNotSupported.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Arm/Sve.PlatformNotSupported.cs index f23fb1b8ee2c7d..3b992e440ef6b5 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Arm/Sve.PlatformNotSupported.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Arm/Sve.PlatformNotSupported.cs @@ -31,7 +31,6 @@ internal Arm64() { } public static new bool IsSupported { [Intrinsic] get { return false; } } } - /// Abs : Absolute value /// @@ -150,6 +149,103 @@ internal Arm64() { } public static unsafe Vector Add(Vector left, Vector right) { throw new PlatformNotSupportedException(); } + /// ConditionalSelect : Conditionally select elements + + /// + /// svint8_t svsel[_s8](svbool_t pg, svint8_t op1, svint8_t op2) + /// svbool_t svsel[_b](svbool_t pg, svbool_t op1, svbool_t op2) + /// + public static unsafe Vector ConditionalSelect(Vector mask, Vector left, Vector right) { throw new PlatformNotSupportedException(); } + + /// + /// svint16_t svsel[_s16](svbool_t pg, svint16_t op1, svint16_t op2) + /// svbool_t svsel[_b](svbool_t pg, svbool_t op1, svbool_t op2) + /// + public static unsafe Vector ConditionalSelect(Vector mask, Vector left, Vector right) { throw new PlatformNotSupportedException(); } + + /// + /// svint32_t svsel[_s32](svbool_t pg, svint32_t op1, svint32_t op2) + /// svbool_t svsel[_b](svbool_t pg, svbool_t op1, svbool_t op2) + /// + public static unsafe Vector ConditionalSelect(Vector mask, Vector left, Vector right) { throw new PlatformNotSupportedException(); } + + /// + /// svint64_t svsel[_s64](svbool_t pg, svint64_t op1, svint64_t op2) + /// svbool_t svsel[_b](svbool_t pg, svbool_t op1, svbool_t op2) + /// + public static unsafe Vector ConditionalSelect(Vector mask, Vector left, Vector right) { throw new PlatformNotSupportedException(); } + + /// + /// svuint8_t svsel[_u8](svbool_t pg, svuint8_t op1, svuint8_t op2) + /// svbool_t svsel[_b](svbool_t pg, svbool_t op1, svbool_t op2) + /// + public static unsafe Vector ConditionalSelect(Vector mask, Vector left, Vector right) { throw new PlatformNotSupportedException(); } + + /// + /// svuint16_t svsel[_u16](svbool_t pg, svuint16_t op1, svuint16_t op2) + /// svbool_t svsel[_b](svbool_t pg, svbool_t op1, svbool_t op2) + /// + public static unsafe Vector ConditionalSelect(Vector mask, Vector left, Vector right) { throw new PlatformNotSupportedException(); } + + /// + /// svuint32_t svsel[_u32](svbool_t pg, svuint32_t op1, svuint32_t op2) + /// svbool_t svsel[_b](svbool_t pg, svbool_t op1, svbool_t op2) + /// + public static unsafe Vector ConditionalSelect(Vector mask, Vector left, Vector right) { throw new PlatformNotSupportedException(); } + + /// + /// svuint64_t svsel[_u64](svbool_t pg, svuint64_t op1, svuint64_t op2) + /// svbool_t svsel[_b](svbool_t pg, svbool_t op1, svbool_t op2) + /// + public static unsafe Vector ConditionalSelect(Vector mask, Vector left, Vector right) { throw new PlatformNotSupportedException(); } + + /// + /// svfloat32_t svsel[_f32](svbool_t pg, svfloat32_t op1, svfloat32_t op2) + /// + public static unsafe Vector ConditionalSelect(Vector mask, Vector left, Vector right) { throw new PlatformNotSupportedException(); } + + /// + /// svfloat64_t svsel[_f64](svbool_t pg, svfloat64_t op1, svfloat64_t op2) + /// + public static unsafe Vector ConditionalSelect(Vector mask, Vector left, Vector right) { throw new PlatformNotSupportedException(); } + + + /// Count16BitElements : Count the number of 16-bit elements in a vector + + /// + /// uint64_t svcnth_pat(enum svpattern pattern) + /// CNTH Xresult, pattern + /// + public static unsafe ulong Count16BitElements([ConstantExpected] SveMaskPattern pattern = SveMaskPattern.All) { throw new PlatformNotSupportedException(); } + + + /// Count32BitElements : Count the number of 32-bit elements in a vector + + /// + /// uint64_t svcntw_pat(enum svpattern pattern) + /// CNTW Xresult, pattern + /// + public static unsafe ulong Count32BitElements([ConstantExpected] SveMaskPattern pattern = SveMaskPattern.All) { throw new PlatformNotSupportedException(); } + + + /// Count64BitElements : Count the number of 64-bit elements in a vector + + /// + /// uint64_t svcntd_pat(enum svpattern pattern) + /// CNTD Xresult, pattern + /// + public static unsafe ulong Count64BitElements([ConstantExpected] SveMaskPattern pattern = SveMaskPattern.All) { throw new PlatformNotSupportedException(); } + + + /// Count8BitElements : Count the number of 8-bit elements in a vector + + /// + /// uint64_t svcntb_pat(enum svpattern pattern) + /// CNTB Xresult, pattern + /// + public static unsafe ulong Count8BitElements([ConstantExpected] SveMaskPattern pattern = SveMaskPattern.All) { throw new PlatformNotSupportedException(); } + + /// CreateTrueMaskByte : Set predicate elements to true /// @@ -456,67 +552,6 @@ internal Arm64() { } public static unsafe Vector CreateWhileLessThanOrEqualMask8Bit(ulong left, ulong right) { throw new PlatformNotSupportedException(); } - /// ConditionalSelect : Conditionally select elements - - /// - /// svint8_t svsel[_s8](svbool_t pg, svint8_t op1, svint8_t op2) - /// svbool_t svsel[_b](svbool_t pg, svbool_t op1, svbool_t op2) - /// - public static unsafe Vector ConditionalSelect(Vector mask, Vector left, Vector right) { throw new PlatformNotSupportedException(); } - - /// - /// svint16_t svsel[_s16](svbool_t pg, svint16_t op1, svint16_t op2) - /// svbool_t svsel[_b](svbool_t pg, svbool_t op1, svbool_t op2) - /// - public static unsafe Vector ConditionalSelect(Vector mask, Vector left, Vector right) { throw new PlatformNotSupportedException(); } - - /// - /// svint32_t svsel[_s32](svbool_t pg, svint32_t op1, svint32_t op2) - /// svbool_t svsel[_b](svbool_t pg, svbool_t op1, svbool_t op2) - /// - public static unsafe Vector ConditionalSelect(Vector mask, Vector left, Vector right) { throw new PlatformNotSupportedException(); } - - /// - /// svint64_t svsel[_s64](svbool_t pg, svint64_t op1, svint64_t op2) - /// svbool_t svsel[_b](svbool_t pg, svbool_t op1, svbool_t op2) - /// - public static unsafe Vector ConditionalSelect(Vector mask, Vector left, Vector right) { throw new PlatformNotSupportedException(); } - - /// - /// svuint8_t svsel[_u8](svbool_t pg, svuint8_t op1, svuint8_t op2) - /// svbool_t svsel[_b](svbool_t pg, svbool_t op1, svbool_t op2) - /// - public static unsafe Vector ConditionalSelect(Vector mask, Vector left, Vector right) { throw new PlatformNotSupportedException(); } - - /// - /// svuint16_t svsel[_u16](svbool_t pg, svuint16_t op1, svuint16_t op2) - /// svbool_t svsel[_b](svbool_t pg, svbool_t op1, svbool_t op2) - /// - public static unsafe Vector ConditionalSelect(Vector mask, Vector left, Vector right) { throw new PlatformNotSupportedException(); } - - /// - /// svuint32_t svsel[_u32](svbool_t pg, svuint32_t op1, svuint32_t op2) - /// svbool_t svsel[_b](svbool_t pg, svbool_t op1, svbool_t op2) - /// - public static unsafe Vector ConditionalSelect(Vector mask, Vector left, Vector right) { throw new PlatformNotSupportedException(); } - - /// - /// svuint64_t svsel[_u64](svbool_t pg, svuint64_t op1, svuint64_t op2) - /// svbool_t svsel[_b](svbool_t pg, svbool_t op1, svbool_t op2) - /// - public static unsafe Vector ConditionalSelect(Vector mask, Vector left, Vector right) { throw new PlatformNotSupportedException(); } - - /// - /// svfloat32_t svsel[_f32](svbool_t pg, svfloat32_t op1, svfloat32_t op2) - /// - public static unsafe Vector ConditionalSelect(Vector mask, Vector left, Vector right) { throw new PlatformNotSupportedException(); } - - /// - /// svfloat64_t svsel[_f64](svbool_t pg, svfloat64_t op1, svfloat64_t op2) - /// - public static unsafe Vector ConditionalSelect(Vector mask, Vector left, Vector right) { throw new PlatformNotSupportedException(); } - - /// LoadVector : Unextended load /// diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Arm/Sve.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Arm/Sve.cs index 494607f5952c46..0f4f57dad8e9bc 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Arm/Sve.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Arm/Sve.cs @@ -177,6 +177,131 @@ internal Arm64() { } public static unsafe Vector Add(Vector left, Vector right) => Add(left, right); + /// ConditionalSelect : Conditionally select elements + + /// + /// svint8_t svsel[_s8](svbool_t pg, svint8_t op1, svint8_t op2) + /// SEL Zresult.B, Pg, Zop1.B, Zop2.B + /// svbool_t svsel[_b](svbool_t pg, svbool_t op1, svbool_t op2) + /// SEL Presult.B, Pg, Pop1.B, Pop2.B + /// + /// + public static unsafe Vector ConditionalSelect(Vector mask, Vector left, Vector right) => ConditionalSelect(mask, left, right); + + /// + /// svint16_t svsel[_s16](svbool_t pg, svint16_t op1, svint16_t op2) + /// SEL Zresult.H, Pg, Zop1.H, Zop2.H + /// svbool_t svsel[_b](svbool_t pg, svbool_t op1, svbool_t op2) + /// SEL Presult.B, Pg, Pop1.B, Pop2.B + /// + /// + public static unsafe Vector ConditionalSelect(Vector mask, Vector left, Vector right) => ConditionalSelect(mask, left, right); + + /// + /// svint32_t svsel[_s32](svbool_t pg, svint32_t op1, svint32_t op2) + /// SEL Zresult.S, Pg, Zop1.S, Zop2.S + /// svbool_t svsel[_b](svbool_t pg, svbool_t op1, svbool_t op2) + /// SEL Presult.B, Pg, Pop1.B, Pop2.B + /// + /// + public static unsafe Vector ConditionalSelect(Vector mask, Vector left, Vector right) => ConditionalSelect(mask, left, right); + + /// + /// svint64_t svsel[_s64](svbool_t pg, svint64_t op1, svint64_t op2) + /// SEL Zresult.D, Pg, Zop1.D, Zop2.D + /// svbool_t svsel[_b](svbool_t pg, svbool_t op1, svbool_t op2) + /// SEL Presult.B, Pg, Pop1.B, Pop2.B + /// + /// + public static unsafe Vector ConditionalSelect(Vector mask, Vector left, Vector right) => ConditionalSelect(mask, left, right); + + /// + /// svuint8_t svsel[_u8](svbool_t pg, svuint8_t op1, svuint8_t op2) + /// SEL Zresult.B, Pg, Zop1.B, Zop2.B + /// svbool_t svsel[_b](svbool_t pg, svbool_t op1, svbool_t op2) + /// SEL Presult.B, Pg, Pop1.B, Pop2.B + /// + /// + public static unsafe Vector ConditionalSelect(Vector mask, Vector left, Vector right) => ConditionalSelect(mask, left, right); + + /// + /// svuint16_t svsel[_u16](svbool_t pg, svuint16_t op1, svuint16_t op2) + /// SEL Zresult.H, Pg, Zop1.H, Zop2.H + /// svbool_t svsel[_b](svbool_t pg, svbool_t op1, svbool_t op2) + /// SEL Presult.B, Pg, Pop1.B, Pop2.B + /// + /// + public static unsafe Vector ConditionalSelect(Vector mask, Vector left, Vector right) => ConditionalSelect(mask, left, right); + + /// + /// svuint32_t svsel[_u32](svbool_t pg, svuint32_t op1, svuint32_t op2) + /// SEL Zresult.S, Pg, Zop1.S, Zop2.S + /// svbool_t svsel[_b](svbool_t pg, svbool_t op1, svbool_t op2) + /// SEL Presult.B, Pg, Pop1.B, Pop2.B + /// + /// + public static unsafe Vector ConditionalSelect(Vector mask, Vector left, Vector right) => ConditionalSelect(mask, left, right); + + /// + /// svuint64_t svsel[_u64](svbool_t pg, svuint64_t op1, svuint64_t op2) + /// SEL Zresult.D, Pg, Zop1.D, Zop2.D + /// svbool_t svsel[_b](svbool_t pg, svbool_t op1, svbool_t op2) + /// SEL Presult.B, Pg, Pop1.B, Pop2.B + /// + /// + public static unsafe Vector ConditionalSelect(Vector mask, Vector left, Vector right) => ConditionalSelect(mask, left, right); + + /// + /// svfloat32_t svsel[_f32](svbool_t pg, svfloat32_t op1, svfloat32_t op2) + /// SEL Zresult.S, Pg, Zop1.S, Zop2.S + /// + /// + public static unsafe Vector ConditionalSelect(Vector mask, Vector left, Vector right) => ConditionalSelect(mask, left, right); + + /// + /// svfloat64_t svsel[_f64](svbool_t pg, svfloat64_t op1, svfloat64_t op2) + /// SEL Zresult.D, Pg, Zop1.D, Zop2.D + /// + /// + public static unsafe Vector ConditionalSelect(Vector mask, Vector left, Vector right) => ConditionalSelect(mask, left, right); + + + /// Count16BitElements : Count the number of 16-bit elements in a vector + + /// + /// uint64_t svcnth_pat(enum svpattern pattern) + /// CNTH Xresult, pattern + /// + public static unsafe ulong Count16BitElements([ConstantExpected] SveMaskPattern pattern = SveMaskPattern.All) => Count16BitElements(pattern); + + + /// Count32BitElements : Count the number of 32-bit elements in a vector + + /// + /// uint64_t svcntw_pat(enum svpattern pattern) + /// CNTW Xresult, pattern + /// + public static unsafe ulong Count32BitElements([ConstantExpected] SveMaskPattern pattern = SveMaskPattern.All) => Count32BitElements(pattern); + + + /// Count64BitElements : Count the number of 64-bit elements in a vector + + /// + /// uint64_t svcntd_pat(enum svpattern pattern) + /// CNTD Xresult, pattern + /// + public static unsafe ulong Count64BitElements([ConstantExpected] SveMaskPattern pattern = SveMaskPattern.All) => Count64BitElements(pattern); + + + /// Count8BitElements : Count the number of 8-bit elements in a vector + + /// + /// uint64_t svcntb_pat(enum svpattern pattern) + /// CNTB Xresult, pattern + /// + public static unsafe ulong Count8BitElements([ConstantExpected] SveMaskPattern pattern = SveMaskPattern.All) => Count8BitElements(pattern); + + /// CreateTrueMaskByte : Set predicate elements to true /// @@ -483,95 +608,6 @@ internal Arm64() { } public static unsafe Vector CreateWhileLessThanOrEqualMask8Bit(ulong left, ulong right) => CreateWhileLessThanOrEqualMask8Bit(left, right); - /// ConditionalSelect : Conditionally select elements - - /// - /// svint8_t svsel[_s8](svbool_t pg, svint8_t op1, svint8_t op2) - /// SEL Zresult.B, Pg, Zop1.B, Zop2.B - /// svbool_t svsel[_b](svbool_t pg, svbool_t op1, svbool_t op2) - /// SEL Presult.B, Pg, Pop1.B, Pop2.B - /// - /// - public static unsafe Vector ConditionalSelect(Vector mask, Vector left, Vector right) => ConditionalSelect(mask, left, right); - - /// - /// svint16_t svsel[_s16](svbool_t pg, svint16_t op1, svint16_t op2) - /// SEL Zresult.H, Pg, Zop1.H, Zop2.H - /// svbool_t svsel[_b](svbool_t pg, svbool_t op1, svbool_t op2) - /// SEL Presult.B, Pg, Pop1.B, Pop2.B - /// - /// - public static unsafe Vector ConditionalSelect(Vector mask, Vector left, Vector right) => ConditionalSelect(mask, left, right); - - /// - /// svint32_t svsel[_s32](svbool_t pg, svint32_t op1, svint32_t op2) - /// SEL Zresult.S, Pg, Zop1.S, Zop2.S - /// svbool_t svsel[_b](svbool_t pg, svbool_t op1, svbool_t op2) - /// SEL Presult.B, Pg, Pop1.B, Pop2.B - /// - /// - public static unsafe Vector ConditionalSelect(Vector mask, Vector left, Vector right) => ConditionalSelect(mask, left, right); - - /// - /// svint64_t svsel[_s64](svbool_t pg, svint64_t op1, svint64_t op2) - /// SEL Zresult.D, Pg, Zop1.D, Zop2.D - /// svbool_t svsel[_b](svbool_t pg, svbool_t op1, svbool_t op2) - /// SEL Presult.B, Pg, Pop1.B, Pop2.B - /// - /// - public static unsafe Vector ConditionalSelect(Vector mask, Vector left, Vector right) => ConditionalSelect(mask, left, right); - - /// - /// svuint8_t svsel[_u8](svbool_t pg, svuint8_t op1, svuint8_t op2) - /// SEL Zresult.B, Pg, Zop1.B, Zop2.B - /// svbool_t svsel[_b](svbool_t pg, svbool_t op1, svbool_t op2) - /// SEL Presult.B, Pg, Pop1.B, Pop2.B - /// - /// - public static unsafe Vector ConditionalSelect(Vector mask, Vector left, Vector right) => ConditionalSelect(mask, left, right); - - /// - /// svuint16_t svsel[_u16](svbool_t pg, svuint16_t op1, svuint16_t op2) - /// SEL Zresult.H, Pg, Zop1.H, Zop2.H - /// svbool_t svsel[_b](svbool_t pg, svbool_t op1, svbool_t op2) - /// SEL Presult.B, Pg, Pop1.B, Pop2.B - /// - /// - public static unsafe Vector ConditionalSelect(Vector mask, Vector left, Vector right) => ConditionalSelect(mask, left, right); - - /// - /// svuint32_t svsel[_u32](svbool_t pg, svuint32_t op1, svuint32_t op2) - /// SEL Zresult.S, Pg, Zop1.S, Zop2.S - /// svbool_t svsel[_b](svbool_t pg, svbool_t op1, svbool_t op2) - /// SEL Presult.B, Pg, Pop1.B, Pop2.B - /// - /// - public static unsafe Vector ConditionalSelect(Vector mask, Vector left, Vector right) => ConditionalSelect(mask, left, right); - - /// - /// svuint64_t svsel[_u64](svbool_t pg, svuint64_t op1, svuint64_t op2) - /// SEL Zresult.D, Pg, Zop1.D, Zop2.D - /// svbool_t svsel[_b](svbool_t pg, svbool_t op1, svbool_t op2) - /// SEL Presult.B, Pg, Pop1.B, Pop2.B - /// - /// - public static unsafe Vector ConditionalSelect(Vector mask, Vector left, Vector right) => ConditionalSelect(mask, left, right); - - /// - /// svfloat32_t svsel[_f32](svbool_t pg, svfloat32_t op1, svfloat32_t op2) - /// SEL Zresult.S, Pg, Zop1.S, Zop2.S - /// - /// - public static unsafe Vector ConditionalSelect(Vector mask, Vector left, Vector right) => ConditionalSelect(mask, left, right); - - /// - /// svfloat64_t svsel[_f64](svbool_t pg, svfloat64_t op1, svfloat64_t op2) - /// SEL Zresult.D, Pg, Zop1.D, Zop2.D - /// - /// - public static unsafe Vector ConditionalSelect(Vector mask, Vector left, Vector right) => ConditionalSelect(mask, left, right); - - /// LoadVector : Unextended load /// diff --git a/src/libraries/System.Runtime.Intrinsics/ref/System.Runtime.Intrinsics.cs b/src/libraries/System.Runtime.Intrinsics/ref/System.Runtime.Intrinsics.cs index e5f394aca8168a..881100ff95976c 100644 --- a/src/libraries/System.Runtime.Intrinsics/ref/System.Runtime.Intrinsics.cs +++ b/src/libraries/System.Runtime.Intrinsics/ref/System.Runtime.Intrinsics.cs @@ -4187,6 +4187,20 @@ internal Arm64() { } public static System.Numerics.Vector Add(System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } public static System.Numerics.Vector Add(System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } public static System.Numerics.Vector Add(System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } + public static ulong Count16BitElements([ConstantExpected] SveMaskPattern pattern = SveMaskPattern.All) { throw null; } + public static ulong Count32BitElements([ConstantExpected] SveMaskPattern pattern = SveMaskPattern.All) { throw null; } + public static ulong Count64BitElements([ConstantExpected] SveMaskPattern pattern = SveMaskPattern.All) { throw null; } + public static ulong Count8BitElements([ConstantExpected] SveMaskPattern pattern = SveMaskPattern.All) { throw null; } + public static System.Numerics.Vector ConditionalSelect(System.Numerics.Vector mask, System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } + public static System.Numerics.Vector ConditionalSelect(System.Numerics.Vector mask, System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } + public static System.Numerics.Vector ConditionalSelect(System.Numerics.Vector mask, System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } + public static System.Numerics.Vector ConditionalSelect(System.Numerics.Vector mask, System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } + public static System.Numerics.Vector ConditionalSelect(System.Numerics.Vector mask, System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } + public static System.Numerics.Vector ConditionalSelect(System.Numerics.Vector mask, System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } + public static System.Numerics.Vector ConditionalSelect(System.Numerics.Vector mask, System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } + public static System.Numerics.Vector ConditionalSelect(System.Numerics.Vector mask, System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } + public static System.Numerics.Vector ConditionalSelect(System.Numerics.Vector mask, System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } + public static System.Numerics.Vector ConditionalSelect(System.Numerics.Vector mask, System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } public static System.Numerics.Vector CreateTrueMaskByte([ConstantExpected] SveMaskPattern pattern = SveMaskPattern.All) { throw null; } public static System.Numerics.Vector CreateTrueMaskDouble([ConstantExpected] SveMaskPattern pattern = SveMaskPattern.All) { throw null; } public static System.Numerics.Vector CreateTrueMaskInt16([ConstantExpected] SveMaskPattern pattern = SveMaskPattern.All) { throw null; } @@ -4229,16 +4243,6 @@ internal Arm64() { } public static System.Numerics.Vector CreateWhileLessThanOrEqualMask8Bit(long left, long right) { throw null; } public static System.Numerics.Vector CreateWhileLessThanOrEqualMask8Bit(uint left, uint right) { throw null; } public static System.Numerics.Vector CreateWhileLessThanOrEqualMask8Bit(ulong left, ulong right) { throw null; } - public static System.Numerics.Vector ConditionalSelect(System.Numerics.Vector mask, System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } - public static System.Numerics.Vector ConditionalSelect(System.Numerics.Vector mask, System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } - public static System.Numerics.Vector ConditionalSelect(System.Numerics.Vector mask, System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } - public static System.Numerics.Vector ConditionalSelect(System.Numerics.Vector mask, System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } - public static System.Numerics.Vector ConditionalSelect(System.Numerics.Vector mask, System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } - public static System.Numerics.Vector ConditionalSelect(System.Numerics.Vector mask, System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } - public static System.Numerics.Vector ConditionalSelect(System.Numerics.Vector mask, System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } - public static System.Numerics.Vector ConditionalSelect(System.Numerics.Vector mask, System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } - public static System.Numerics.Vector ConditionalSelect(System.Numerics.Vector mask, System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } - public static System.Numerics.Vector ConditionalSelect(System.Numerics.Vector mask, System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } public static unsafe System.Numerics.Vector LoadVector(System.Numerics.Vector mask, sbyte* address) { throw null; } public static unsafe System.Numerics.Vector LoadVector(System.Numerics.Vector mask, short* address) { throw null; } public static unsafe System.Numerics.Vector LoadVector(System.Numerics.Vector mask, int* address) { throw null; } diff --git a/src/tests/Common/GenerateHWIntrinsicTests/GenerateHWIntrinsicTests_Arm.cs b/src/tests/Common/GenerateHWIntrinsicTests/GenerateHWIntrinsicTests_Arm.cs index e1e048d72ed60a..db964d4793e1bb 100644 --- a/src/tests/Common/GenerateHWIntrinsicTests/GenerateHWIntrinsicTests_Arm.cs +++ b/src/tests/Common/GenerateHWIntrinsicTests/GenerateHWIntrinsicTests_Arm.cs @@ -2920,6 +2920,11 @@ ("SveConditionalSelect.template", new Dictionary { ["TestName"] = "Sve_ConditionalSelect_uint", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "ConditionalSelect", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "UInt32", ["Op3VectorType"] = "Vector", ["Op3BaseType"] = "UInt32", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp3"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "(firstOp[i] != 0 ? (result[i] != secondOp[i]) : (result[i] != thirdOp[i]))",}), ("SveConditionalSelect.template", new Dictionary { ["TestName"] = "Sve_ConditionalSelect_ulong", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "ConditionalSelect", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt64", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "UInt64", ["Op3VectorType"] = "Vector", ["Op3BaseType"] = "UInt64", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt64()", ["NextValueOp3"] = "TestLibrary.Generator.GetUInt64()", ["ValidateIterResult"] = "(firstOp[i] != 0 ? (result[i] != secondOp[i]) : (result[i] != thirdOp[i]))",}), + ("ScalarUnOpTest.template", new Dictionary { ["TestName"] = "Sve_Count16BitElements", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "Count16BitElements", ["RetBaseType"] = "UInt64", ["Op1BaseType"] = "SveMaskPattern", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "SveMaskPattern.All", ["ValidateResult"] = "isUnexpectedResult = (result != (UInt64)(Unsafe.SizeOf>() / sizeof(Int16)));",}), + ("ScalarUnOpTest.template", new Dictionary { ["TestName"] = "Sve_Count32BitElements", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "Count32BitElements", ["RetBaseType"] = "UInt64", ["Op1BaseType"] = "SveMaskPattern", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "SveMaskPattern.All", ["ValidateResult"] = "isUnexpectedResult = (result != (UInt64)(Unsafe.SizeOf>() / sizeof(Int32)));",}), + ("ScalarUnOpTest.template", new Dictionary { ["TestName"] = "Sve_Count64BitElements", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "Count64BitElements", ["RetBaseType"] = "UInt64", ["Op1BaseType"] = "SveMaskPattern", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "SveMaskPattern.All", ["ValidateResult"] = "isUnexpectedResult = (result != (UInt64)(Unsafe.SizeOf>() / sizeof(Int64)));",}), + ("ScalarUnOpTest.template", new Dictionary { ["TestName"] = "Sve_Count8BitElements", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "Count8BitElements", ["RetBaseType"] = "UInt64", ["Op1BaseType"] = "SveMaskPattern", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "SveMaskPattern.All", ["ValidateResult"] = "isUnexpectedResult = (result != (UInt64)(Unsafe.SizeOf>() / sizeof(Byte)));",}), + ("ScalarBinOpRetVecTest.template",new Dictionary {["TestName"] = "Sve_CreateWhileLessThanMask16Bit_Int32", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "CreateWhileLessThanMask16Bit", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt16", ["Op1BaseType"] = "Int32", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.WhileLessThanMask(left + (Int32)i, right) != (Int32)result[i]",}), ("ScalarBinOpRetVecTest.template",new Dictionary {["TestName"] = "Sve_CreateWhileLessThanMask16Bit_Int64", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "CreateWhileLessThanMask16Bit", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt16", ["Op1BaseType"] = "Int64", ["Op2BaseType"] = "Int64", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt64()", ["ValidateIterResult"] = "Helpers.WhileLessThanMask(left + (Int64)i, right) != (Int64)result[i]",}), ("ScalarBinOpRetVecTest.template",new Dictionary {["TestName"] = "Sve_CreateWhileLessThanMask16Bit_UInt32", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "CreateWhileLessThanMask16Bit", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt16", ["Op1BaseType"] = "UInt32", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "Helpers.WhileLessThanMask(left + (UInt32)i, right) != (UInt32)result[i]",}), diff --git a/src/tests/JIT/HardwareIntrinsics/Arm/Shared/ScalarUnOpTest.template b/src/tests/JIT/HardwareIntrinsics/Arm/Shared/ScalarUnOpTest.template index c6fe68908e5627..f057ad4a818680 100644 --- a/src/tests/JIT/HardwareIntrinsics/Arm/Shared/ScalarUnOpTest.template +++ b/src/tests/JIT/HardwareIntrinsics/Arm/Shared/ScalarUnOpTest.template @@ -9,6 +9,7 @@ ******************************************************************************/ using System; +using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Intrinsics; From cab2d119a785d7d3a4f6461021364e849560fa62 Mon Sep 17 00:00:00 2001 From: Meri Khamoyan <96171496+mkhamoyan@users.noreply.github.com> Date: Fri, 26 Apr 2024 20:18:33 +0200 Subject: [PATCH 106/161] [mono][wasm] Include NativeLibrary items to the NativeFileReference items (#101532) * Include NativeLibary and add test case * Move to common place * Ignore missing NativeLibraries * Move items copying into target --- .../Wasm.Build.Tests/NativeLibraryTests.cs | 31 +++++++++++++++++++ src/mono/wasm/build/WasmApp.Common.targets | 5 +++ 2 files changed, 36 insertions(+) diff --git a/src/mono/wasm/Wasm.Build.Tests/NativeLibraryTests.cs b/src/mono/wasm/Wasm.Build.Tests/NativeLibraryTests.cs index c8cca6cd0774e7..555cfa73fad176 100644 --- a/src/mono/wasm/Wasm.Build.Tests/NativeLibraryTests.cs +++ b/src/mono/wasm/Wasm.Build.Tests/NativeLibraryTests.cs @@ -136,5 +136,36 @@ public static int Main() string cryptoInitMsg = "MONO_WASM: Initializing Crypto WebWorker"; Assert.DoesNotContain(cryptoInitMsg, output); } + + [Theory] + [BuildAndRun(aot: false)] + [BuildAndRun(aot: true)] + public void ProjectWithNativeLibrary(BuildArgs buildArgs, RunHost host, string id) + { + string projectName = $"AppUsingNativeLibrary-a"; + buildArgs = buildArgs with { ProjectName = projectName }; + buildArgs = ExpandBuildArgs(buildArgs, extraItems: "\n"); + + if (!_buildContext.TryGetBuildFor(buildArgs, out BuildProduct? _)) + { + InitPaths(id); + if (Directory.Exists(_projectDir)) + Directory.Delete(_projectDir, recursive: true); + + Utils.DirectoryCopy(Path.Combine(BuildEnvironment.TestAssetsPath, "AppUsingNativeLib"), _projectDir); + File.Copy(Path.Combine(BuildEnvironment.TestAssetsPath, "native-libs", "native-lib.o"), Path.Combine(_projectDir, "native-lib.o")); + } + + BuildProject(buildArgs, + id: id, + new BuildProjectOptions(DotnetWasmFromRuntimePack: false)); + + string output = RunAndTestWasmApp(buildArgs, buildDir: _projectDir, expectedExitCode: 0, + test: output => {}, + host: host, id: id); + + Assert.Contains("print_line: 100", output); + Assert.Contains("from pinvoke: 142", output); + } } } diff --git a/src/mono/wasm/build/WasmApp.Common.targets b/src/mono/wasm/build/WasmApp.Common.targets index e9cda6ccea50e1..501a98264538c3 100644 --- a/src/mono/wasm/build/WasmApp.Common.targets +++ b/src/mono/wasm/build/WasmApp.Common.targets @@ -297,6 +297,11 @@ <_WasmShouldAOT Condition="'$(_WasmShouldAOT)' == ''">false + + <_ExistingNativeLibrary Include="@(NativeLibrary->Exists())" /> + + + From 2c99786b58009d4422c198e8aeaebc068c4b6245 Mon Sep 17 00:00:00 2001 From: Adam Sitnik Date: Fri, 26 Apr 2024 20:51:10 +0200 Subject: [PATCH 107/161] Revert "FileConfigurationProvider.Dispose should dispose FileProvider when it owns it" (#101609) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Revert "FileConfigurationProvider.Dispose should dispose FileProvider when it…" This reverts commit 63fad3c36fdf36e31ab0dd4c7e32732750390c4a. * Add test to ensure the bug does not come back --- .../src/FileConfigurationExtensions.cs | 10 +-- .../src/FileConfigurationProvider.cs | 5 -- .../src/FileConfigurationSource.cs | 11 ---- .../tests/JsonConfigurationTest.cs | 48 +++------------ .../tests/XmlConfigurationTest.cs | 61 ------------------- 5 files changed, 15 insertions(+), 120 deletions(-) diff --git a/src/libraries/Microsoft.Extensions.Configuration.FileExtensions/src/FileConfigurationExtensions.cs b/src/libraries/Microsoft.Extensions.Configuration.FileExtensions/src/FileConfigurationExtensions.cs index 77ac387d096077..f84c5c10eea771 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.FileExtensions/src/FileConfigurationExtensions.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.FileExtensions/src/FileConfigurationExtensions.cs @@ -29,9 +29,6 @@ public static IConfigurationBuilder SetFileProvider(this IConfigurationBuilder b return builder; } - internal static IFileProvider? GetUserDefinedFileProvider(this IConfigurationBuilder builder) - => builder.Properties.TryGetValue(FileProviderKey, out object? provider) ? (IFileProvider)provider : null; - /// /// Gets the default to be used for file-based providers. /// @@ -41,7 +38,12 @@ public static IFileProvider GetFileProvider(this IConfigurationBuilder builder) { ThrowHelper.ThrowIfNull(builder); - return GetUserDefinedFileProvider(builder) ?? new PhysicalFileProvider(AppContext.BaseDirectory ?? string.Empty); + if (builder.Properties.TryGetValue(FileProviderKey, out object? provider)) + { + return (IFileProvider)provider; + } + + return new PhysicalFileProvider(AppContext.BaseDirectory ?? string.Empty); } /// diff --git a/src/libraries/Microsoft.Extensions.Configuration.FileExtensions/src/FileConfigurationProvider.cs b/src/libraries/Microsoft.Extensions.Configuration.FileExtensions/src/FileConfigurationProvider.cs index c0d8c9f341278a..d226051b1ab838 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.FileExtensions/src/FileConfigurationProvider.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.FileExtensions/src/FileConfigurationProvider.cs @@ -162,11 +162,6 @@ private void HandleException(ExceptionDispatchInfo info) protected virtual void Dispose(bool disposing) { _changeTokenRegistration?.Dispose(); - - if (Source.OwnsFileProvider) - { - (Source.FileProvider as IDisposable)?.Dispose(); - } } } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.FileExtensions/src/FileConfigurationSource.cs b/src/libraries/Microsoft.Extensions.Configuration.FileExtensions/src/FileConfigurationSource.cs index 60555b2c672558..d58c265f406a9a 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.FileExtensions/src/FileConfigurationSource.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.FileExtensions/src/FileConfigurationSource.cs @@ -18,11 +18,6 @@ public abstract class FileConfigurationSource : IConfigurationSource /// public IFileProvider? FileProvider { get; set; } - /// - /// Set to true when was not provided by user and can be safely disposed. - /// - internal bool OwnsFileProvider { get; private set; } - /// /// The path to the file. /// @@ -63,11 +58,6 @@ public abstract class FileConfigurationSource : IConfigurationSource /// The . public void EnsureDefaults(IConfigurationBuilder builder) { - if (FileProvider is null && builder.GetUserDefinedFileProvider() is null) - { - OwnsFileProvider = true; - } - FileProvider ??= builder.GetFileProvider(); OnLoadException ??= builder.GetFileLoadExceptionHandler(); } @@ -91,7 +81,6 @@ public void ResolveFileProvider() } if (Directory.Exists(directory)) { - OwnsFileProvider = true; FileProvider = new PhysicalFileProvider(directory); Path = pathToFile; } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Json/tests/JsonConfigurationTest.cs b/src/libraries/Microsoft.Extensions.Configuration.Json/tests/JsonConfigurationTest.cs index 4b08c918fb8981..08d59e30ea6ebc 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Json/tests/JsonConfigurationTest.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Json/tests/JsonConfigurationTest.cs @@ -222,56 +222,26 @@ public void ThrowFormatExceptionWhenFileIsEmpty() Assert.Contains("Could not parse the JSON file.", exception.Message); } - [Theory] - [InlineData(true)] - [InlineData(false)] - public void AddJsonFile_FileProvider_Gets_Disposed_When_It_Was_Not_Created_By_The_User(bool disposeConfigRoot) + [Fact] + public void AddJsonFile_FileProvider_Is_Not_Disposed_When_SourcesGetReloaded() { - string filePath = Path.Combine(Path.GetTempPath(), $"{nameof(AddJsonFile_FileProvider_Gets_Disposed_When_It_Was_Not_Created_By_The_User)}.json"); + string filePath = Path.Combine(Path.GetTempPath(), $"{nameof(AddJsonFile_FileProvider_Is_Not_Disposed_When_SourcesGetReloaded)}.json"); File.WriteAllText(filePath, @"{ ""some"": ""value"" }"); - IConfigurationRoot config = new ConfigurationBuilder().AddJsonFile(filePath, optional: false).Build(); - JsonConfigurationProvider jsonConfigurationProvider = config.Providers.OfType().Single(); - - Assert.NotNull(jsonConfigurationProvider.Source.FileProvider); - PhysicalFileProvider fileProvider = (PhysicalFileProvider)jsonConfigurationProvider.Source.FileProvider; - Assert.False(GetIsDisposed(fileProvider)); - - if (disposeConfigRoot) - { - (config as IDisposable).Dispose(); // disposing ConfigurationRoot - } - else - { - jsonConfigurationProvider.Dispose(); // disposing JsonConfigurationProvider - } - - Assert.True(GetIsDisposed(fileProvider)); - } + IConfigurationBuilder builder = new ConfigurationManager(); - [Fact] - public void AddJsonFile_FileProvider_Is_Not_Disposed_When_It_Is_Owned_By_The_User() - { - string filePath = Path.Combine(Path.GetTempPath(), $"{nameof(AddJsonFile_FileProvider_Is_Not_Disposed_When_It_Is_Owned_By_The_User)}.json"); - File.WriteAllText(filePath, @"{ ""some"": ""value"" }"); + builder.AddJsonFile(filePath, optional: false); - PhysicalFileProvider fileProvider = new(Path.GetDirectoryName(filePath)); - JsonConfigurationProvider configurationProvider = new(new JsonConfigurationSource() - { - Path = filePath, - FileProvider = fileProvider - }); - IConfigurationRoot config = new ConfigurationBuilder().AddJsonFile(configurationProvider.Source.FileProvider, filePath, optional: true, reloadOnChange: false).Build(); + FileConfigurationSource fileConfigurationSource = (FileConfigurationSource)builder.Sources.Last(); + PhysicalFileProvider fileProvider = (PhysicalFileProvider)fileConfigurationSource.FileProvider; Assert.False(GetIsDisposed(fileProvider)); - (config as IDisposable).Dispose(); // disposing ConfigurationRoot that does not own the provider - Assert.False(GetIsDisposed(fileProvider)); + builder.Properties.Add("simplest", "repro"); - configurationProvider.Dispose(); // disposing JsonConfigurationProvider that does not own the provider Assert.False(GetIsDisposed(fileProvider)); - fileProvider.Dispose(); // disposing PhysicalFileProvider itself + fileProvider.Dispose(); Assert.True(GetIsDisposed(fileProvider)); } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Xml/tests/XmlConfigurationTest.cs b/src/libraries/Microsoft.Extensions.Configuration.Xml/tests/XmlConfigurationTest.cs index d248d96d9d464f..4012d775afa5f2 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Xml/tests/XmlConfigurationTest.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Xml/tests/XmlConfigurationTest.cs @@ -3,13 +3,11 @@ using System; using System.IO; -using System.Linq; using System.Security.Cryptography; using System.Security.Cryptography.Xml; using System.Tests; using System.Xml; using Microsoft.Extensions.Configuration.Test; -using Microsoft.Extensions.FileProviders; using Xunit; namespace Microsoft.Extensions.Configuration.Xml.Test @@ -781,64 +779,5 @@ public void LoadKeyValuePairsFromValidEncryptedXml() Assert.Equal("AnotherTestConnectionString", xmlConfigSrc.Get("data.setting:inventory:connectionstring")); Assert.Equal("MySql", xmlConfigSrc.Get("Data.setting:Inventory:Provider")); } - - [Theory] - [InlineData(true)] - [InlineData(false)] - public void AddXmlFile_FileProvider_Gets_Disposed_When_It_Was_Not_Created_By_The_User(bool disposeConfigRoot) - { - string filePath = Path.Combine(Path.GetTempPath(), $"{nameof(AddXmlFile_FileProvider_Gets_Disposed_When_It_Was_Not_Created_By_The_User)}.xml"); - File.WriteAllText(filePath, @"Settings"); - - IConfigurationRoot config = new ConfigurationBuilder().AddXmlFile(filePath, optional: false).Build(); - XmlConfigurationProvider xmlConfigurationProvider = config.Providers.OfType().Single(); - - Assert.NotNull(xmlConfigurationProvider.Source.FileProvider); - PhysicalFileProvider fileProvider = (PhysicalFileProvider)xmlConfigurationProvider.Source.FileProvider; - Assert.False(GetIsDisposed(fileProvider)); - - if (disposeConfigRoot) - { - (config as IDisposable).Dispose(); // disposing ConfigurationRoot - } - else - { - xmlConfigurationProvider.Dispose(); // disposing XmlConfigurationProvider - } - - Assert.True(GetIsDisposed(fileProvider)); - } - - [Fact] - public void AddXmlFile_FileProvider_Is_Not_Disposed_When_It_Is_Owned_By_The_User() - { - string filePath = Path.Combine(Path.GetTempPath(), $"{nameof(AddXmlFile_FileProvider_Is_Not_Disposed_When_It_Is_Owned_By_The_User)}.xml"); - File.WriteAllText(filePath, @"Settings"); - - PhysicalFileProvider fileProvider = new(Path.GetDirectoryName(filePath)); - XmlConfigurationProvider configurationProvider = new(new XmlConfigurationSource() - { - Path = filePath, - FileProvider = fileProvider - }); - IConfigurationRoot config = new ConfigurationBuilder().AddXmlFile(configurationProvider.Source.FileProvider, filePath, optional: true, reloadOnChange: false).Build(); - - Assert.False(GetIsDisposed(fileProvider)); - - (config as IDisposable).Dispose(); // disposing ConfigurationRoot that does not own the provider - Assert.False(GetIsDisposed(fileProvider)); - - configurationProvider.Dispose(); // disposing XmlConfigurationProvider - Assert.False(GetIsDisposed(fileProvider)); - - fileProvider.Dispose(); // disposing PhysicalFileProvider itself - Assert.True(GetIsDisposed(fileProvider)); - } - - private static bool GetIsDisposed(PhysicalFileProvider fileProvider) - { - System.Reflection.FieldInfo isDisposedField = typeof(PhysicalFileProvider).GetField("_disposed", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic); - return (bool)isDisposedField.GetValue(fileProvider); - } } } From 0f562e911e7248a8aba966ddd27ed02d617225af Mon Sep 17 00:00:00 2001 From: Jan Kotas Date: Fri, 26 Apr 2024 11:54:58 -0700 Subject: [PATCH 108/161] Improve tests/profiler/multiple/multiple.cs (#101607) - Add volatile for a field accessed by multiple threads without synchronization - Improve logging - Delete test supression against closed issue - Revert timeout increase that tried to work around a hang that was fixed since then --- src/tests/profiler/common/ProfilerTestRunner.cs | 14 ++++++++------ src/tests/profiler/multiple/multiple.cs | 7 +------ 2 files changed, 9 insertions(+), 12 deletions(-) diff --git a/src/tests/profiler/common/ProfilerTestRunner.cs b/src/tests/profiler/common/ProfilerTestRunner.cs index d78a1221b42213..2dfc2530c59d65 100644 --- a/src/tests/profiler/common/ProfilerTestRunner.cs +++ b/src/tests/profiler/common/ProfilerTestRunner.cs @@ -135,9 +135,9 @@ public static int Run(string profileePath, if (!verifier.HasPassingOutput) { - FailFastWithMessage("Profiler tests are expected to contain the text \'" + verifier.SuccessPhrase + "\' in the console output " + - "of the profilee app to indicate a passing test. Usually it is printed from the Shutdown() method of the profiler implementation. This " + - "text was not found in the output above."); + FailFastWithMessage($"Profiler tests are expected to contain the text '{verifier.SuccessPhrase}' in the console output " + + $"of the profilee app to indicate a passing test. Usually it is printed from the Shutdown() method of the profiler implementation. This " + + $"text was not found in the output above. Profilee returned exit code {process.ExitCode}."); } if (process.ExitCode != 100) @@ -195,14 +195,16 @@ private static void FailFastWithMessage(string error) /// class ProfileeOutputVerifier { + private volatile bool _hasPassingOutput; + public string SuccessPhrase = "PROFILER TEST PASSES"; - public bool HasPassingOutput { get; private set; } + public bool HasPassingOutput => _hasPassingOutput; public void WriteLine(string message) { if (message != null && message.Contains(SuccessPhrase)) { - HasPassingOutput = true; + _hasPassingOutput = true; } } @@ -210,7 +212,7 @@ public void WriteLine(string format, params object[] args) { if (string.Format(format,args).Contains(SuccessPhrase)) { - HasPassingOutput = true; + _hasPassingOutput = true; } } } diff --git a/src/tests/profiler/multiple/multiple.cs b/src/tests/profiler/multiple/multiple.cs index 0d686ae0691a94..a0952687021bf0 100644 --- a/src/tests/profiler/multiple/multiple.cs +++ b/src/tests/profiler/multiple/multiple.cs @@ -35,7 +35,7 @@ public static int RunTest(String[] args) } Console.WriteLine("Waiting for profilers to all detach"); - if (!_profilerDone.WaitOne(TimeSpan.FromMinutes(10))) + if (!_profilerDone.WaitOne(TimeSpan.FromMinutes(5))) { throw new Exception("Test timed out waiting for the profilers to set the callback, test will fail."); } @@ -45,11 +45,6 @@ public static int RunTest(String[] args) public static int Main(string[] args) { - // failing on MacOs 12 https://github.com/dotnet/runtime/issues/64765 - if (OperatingSystem.IsMacOS()) - { - return 100; - } if (args.Length > 0 && args[0].Equals("RunTest", StringComparison.OrdinalIgnoreCase)) { return RunTest(args); From 1a811ea83965a3ce41ae573a6265b557d7662113 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Paulus=20P=C3=A4rssinen?= Date: Fri, 26 Apr 2024 22:27:36 +0300 Subject: [PATCH 109/161] Update link to dotnet-format tool (#101619) * Update link to dotnet-format tool * It now lives in dotnet/sdk * Link to official docs instead Co-authored-by: Jan Kotas --------- Co-authored-by: Jan Kotas --- docs/coding-guidelines/coding-style.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/coding-guidelines/coding-style.md b/docs/coding-guidelines/coding-style.md index 075155a9ee63d8..32dd1ec8bb65e5 100644 --- a/docs/coding-guidelines/coding-style.md +++ b/docs/coding-guidelines/coding-style.md @@ -36,7 +36,7 @@ The general rule we follow is "use Visual Studio defaults". An [EditorConfig](https://editorconfig.org "EditorConfig homepage") file (`.editorconfig`) has been provided at the root of the runtime repository, enabling C# auto-formatting conforming to the above guidelines. -We also use the [dotnet-format Tool](https://github.com/dotnet/format) to ensure the code base maintains a consistent style over time, the tool automatically fixes the code base to conform to the guidelines outlined above. +We also use the [dotnet-format tool](https://learn.microsoft.com/dotnet/core/tools/dotnet-format) to ensure the code base maintains a consistent style over time, the tool automatically fixes the code base to conform to the guidelines outlined above. ### Example File: From dd87633a81b5094c5afb9690b4aa050d47e19771 Mon Sep 17 00:00:00 2001 From: Aman Khalid Date: Fri, 26 Apr 2024 20:46:26 +0000 Subject: [PATCH 110/161] JIT: Remove HANDLER_ENTRY_MUST_BE_IN_HOT_SECTION (#101611) --- src/coreclr/jit/block.h | 21 --------------------- src/coreclr/jit/fgehopt.cpp | 10 ---------- src/coreclr/jit/fgprofile.cpp | 11 ----------- src/coreclr/jit/flowgraph.cpp | 20 +++----------------- src/coreclr/jit/jit.h | 5 ++--- 5 files changed, 5 insertions(+), 62 deletions(-) diff --git a/src/coreclr/jit/block.h b/src/coreclr/jit/block.h index 168f29cca084dd..37c97bfdca6485 100644 --- a/src/coreclr/jit/block.h +++ b/src/coreclr/jit/block.h @@ -1256,27 +1256,6 @@ struct BasicBlock : private LIR::Range this->scaleBBWeight(BB_ZERO_WEIGHT); } - // makeBlockHot() - // This is used to override any profiling data - // and force a block to be in the hot region. - // We only call this method for handler entry point - // and only when HANDLER_ENTRY_MUST_BE_IN_HOT_SECTION is 1. - // Doing this helps fgReorderBlocks() by telling - // it to try to move these blocks into the hot region. - // Note that we do this strictly as an optimization, - // not for correctness. fgDetermineFirstColdBlock() - // will find all handler entry points and ensure that - // for now we don't place them in the cold section. - // - void makeBlockHot() - { - if (this->bbWeight == BB_ZERO_WEIGHT) - { - this->RemoveFlags(BBF_RUN_RARELY | BBF_PROF_WEIGHT); - this->bbWeight = 1; - } - } - bool isMaxBBWeight() const { return (bbWeight >= BB_MAX_WEIGHT); diff --git a/src/coreclr/jit/fgehopt.cpp b/src/coreclr/jit/fgehopt.cpp index a26eaf0bfa8b3d..743559717e47cb 100644 --- a/src/coreclr/jit/fgehopt.cpp +++ b/src/coreclr/jit/fgehopt.cpp @@ -1229,16 +1229,6 @@ PhaseStatus Compiler::fgCloneFinally() block->setBBProfileWeight(blockWeight * originalScale); JITDUMP("Set weight of " FMT_BB " to " FMT_WT "\n", block->bbNum, block->bbWeight); -#if HANDLER_ENTRY_MUST_BE_IN_HOT_SECTION - // Handle a special case -- some handler entries can't have zero profile count. - // - if (bbIsHandlerBeg(block) && block->isRunRarely()) - { - JITDUMP("Suppressing zero count for " FMT_BB " as it is a handler entry\n", block->bbNum); - block->makeBlockHot(); - } -#endif - BasicBlock* const clonedBlock = blockMap[block]; clonedBlock->setBBProfileWeight(blockWeight * clonedScale); JITDUMP("Set weight of " FMT_BB " to " FMT_WT "\n", clonedBlock->bbNum, clonedBlock->bbWeight); diff --git a/src/coreclr/jit/fgprofile.cpp b/src/coreclr/jit/fgprofile.cpp index 05f97ffd14ef59..10fdd6035e0b3f 100644 --- a/src/coreclr/jit/fgprofile.cpp +++ b/src/coreclr/jit/fgprofile.cpp @@ -3018,21 +3018,10 @@ PhaseStatus Compiler::fgIncorporateProfileData() // // Notes: // Does inlinee scaling. -// Handles handler entry special case. // void Compiler::fgSetProfileWeight(BasicBlock* block, weight_t profileWeight) { block->setBBProfileWeight(profileWeight); - -#if HANDLER_ENTRY_MUST_BE_IN_HOT_SECTION - // Handle a special case -- some handler entries can't have zero profile count. - // - if (this->bbIsHandlerBeg(block) && block->isRunRarely()) - { - JITDUMP("Suppressing zero count for " FMT_BB " as it is a handler entry\n", block->bbNum); - block->makeBlockHot(); - } -#endif } //------------------------------------------------------------------------ diff --git a/src/coreclr/jit/flowgraph.cpp b/src/coreclr/jit/flowgraph.cpp index 6ab0977c55c252..8b73d10aa8dc1d 100644 --- a/src/coreclr/jit/flowgraph.cpp +++ b/src/coreclr/jit/flowgraph.cpp @@ -3083,17 +3083,12 @@ bool Compiler::fgFuncletsAreCold() // // Notes: // Walk the basic blocks list to determine the first block to place in the -// cold section. This would be the first of a series of rarely executed blocks +// cold section. This would be the first of a series of rarely executed blocks // such that no succeeding blocks are in a try region or an exception handler // or are rarely executed. // PhaseStatus Compiler::fgDetermineFirstColdBlock() { - // Since we may need to create a new transition block - // we assert that it is OK to create new blocks. - // - assert(fgPredsComputed); - assert(fgSafeBasicBlockCreation); assert(fgFirstColdBlock == nullptr); if (!opts.compProcedureSplitting) @@ -3134,15 +3129,6 @@ PhaseStatus Compiler::fgDetermineFirstColdBlock() for (lblk = nullptr, block = fgFirstBB; block != nullptr; lblk = block, block = block->Next()) { - bool blockMustBeInHotSection = false; - -#if HANDLER_ENTRY_MUST_BE_IN_HOT_SECTION - if (bbIsHandlerBeg(block)) - { - blockMustBeInHotSection = true; - } -#endif // HANDLER_ENTRY_MUST_BE_IN_HOT_SECTION - // Make note of if we're in the funclet section, // so we can stop the search early. if (block == fgFirstFuncletBB) @@ -3156,7 +3142,7 @@ PhaseStatus Compiler::fgDetermineFirstColdBlock() // We have a candidate for first cold block // Is this a hot block? - if (blockMustBeInHotSection || (block->isRunRarely() == false)) + if (!block->isRunRarely()) { // We have to restart the search for the first cold block firstColdBlock = nullptr; @@ -3195,7 +3181,7 @@ PhaseStatus Compiler::fgDetermineFirstColdBlock() } // Is this a cold block? - if (!blockMustBeInHotSection && block->isRunRarely()) + if (block->isRunRarely()) { // // If the last block that was hot was a BBJ_COND diff --git a/src/coreclr/jit/jit.h b/src/coreclr/jit/jit.h index cc8c8cb717d9ab..11cd55699dc99f 100644 --- a/src/coreclr/jit/jit.h +++ b/src/coreclr/jit/jit.h @@ -470,9 +470,8 @@ class GlobalJitOptions /*****************************************************************************/ -#define CSE_INTO_HANDLERS 0 -#define DUMP_FLOWGRAPHS DEBUG // Support for creating Xml Flowgraph reports in *.fgx files -#define HANDLER_ENTRY_MUST_BE_IN_HOT_SECTION 0 // if 1 we must have all handler entry points in the Hot code section +#define CSE_INTO_HANDLERS 0 +#define DUMP_FLOWGRAPHS DEBUG // Support for creating Xml Flowgraph reports in *.fgx files /*****************************************************************************/ From a0beed4fa56aaf4d3cb2f02b5cdb68f8929e1a60 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Fri, 26 Apr 2024 13:54:43 -0700 Subject: [PATCH 111/161] Handle case where falseValue is contained (#101515) * Handle case where falseValue is contained * Handle cases where Abs() is wrapped in conditional with AllBitsSet mask * Add a missing case for Abs() handling * jit format * Review comments * Review feedback * Another review feedback --- src/coreclr/jit/gentree.h | 27 ++++++++++++ src/coreclr/jit/hwintrinsic.cpp | 2 +- src/coreclr/jit/hwintrinsiccodegenarm64.cpp | 48 ++++++++++++++++++++- 3 files changed, 74 insertions(+), 3 deletions(-) diff --git a/src/coreclr/jit/gentree.h b/src/coreclr/jit/gentree.h index 079174f67e939b..2f3a2a7b2f573b 100644 --- a/src/coreclr/jit/gentree.h +++ b/src/coreclr/jit/gentree.h @@ -1770,6 +1770,7 @@ struct GenTree inline bool IsVectorZero() const; inline bool IsVectorCreate() const; inline bool IsVectorAllBitsSet() const; + inline bool IsMaskAllBitsSet() const; inline bool IsVectorConst(); inline uint64_t GetIntegralVectorConstElement(size_t index, var_types simdBaseType); @@ -9238,6 +9239,32 @@ inline bool GenTree::IsVectorAllBitsSet() const return false; } +inline bool GenTree::IsMaskAllBitsSet() const +{ +#ifdef TARGET_ARM64 + static_assert_no_msg(AreContiguous(NI_Sve_CreateTrueMaskByte, NI_Sve_CreateTrueMaskDouble, + NI_Sve_CreateTrueMaskInt16, NI_Sve_CreateTrueMaskInt32, + NI_Sve_CreateTrueMaskInt64, NI_Sve_CreateTrueMaskSByte, + NI_Sve_CreateTrueMaskSingle, NI_Sve_CreateTrueMaskUInt16, + NI_Sve_CreateTrueMaskUInt32, NI_Sve_CreateTrueMaskUInt64)); + + if (OperIsHWIntrinsic()) + { + NamedIntrinsic id = AsHWIntrinsic()->GetHWIntrinsicId(); + if (id == NI_Sve_ConvertMaskToVector) + { + GenTree* op1 = AsHWIntrinsic()->Op(1); + assert(op1->OperIsHWIntrinsic()); + id = op1->AsHWIntrinsic()->GetHWIntrinsicId(); + } + return ((id == NI_Sve_CreateTrueMaskAll) || + ((id >= NI_Sve_CreateTrueMaskByte) && (id <= NI_Sve_CreateTrueMaskUInt64))); + } + +#endif + return false; +} + //------------------------------------------------------------------- // IsVectorConst: returns true if this node is a HWIntrinsic that represents a constant. // diff --git a/src/coreclr/jit/hwintrinsic.cpp b/src/coreclr/jit/hwintrinsic.cpp index 96060b2beacb7d..3187c3e5c2e044 100644 --- a/src/coreclr/jit/hwintrinsic.cpp +++ b/src/coreclr/jit/hwintrinsic.cpp @@ -1622,7 +1622,7 @@ GenTree* Compiler::impHWIntrinsic(NamedIntrinsic intrinsic, GenTree* op1 = retNode->AsHWIntrinsic()->Op(1); if (intrinsic == NI_Sve_ConditionalSelect) { - if (op1->IsVectorAllBitsSet()) + if (op1->IsVectorAllBitsSet() || op1->IsMaskAllBitsSet()) { return retNode->AsHWIntrinsic()->Op(2); } diff --git a/src/coreclr/jit/hwintrinsiccodegenarm64.cpp b/src/coreclr/jit/hwintrinsiccodegenarm64.cpp index e9983f700361c5..c38afb87a83340 100644 --- a/src/coreclr/jit/hwintrinsiccodegenarm64.cpp +++ b/src/coreclr/jit/hwintrinsiccodegenarm64.cpp @@ -406,8 +406,8 @@ void CodeGen::genHWIntrinsic(GenTreeHWIntrinsic* node) // Handle case where op2 is operation that needs embedded mask GenTree* op2 = intrin.op2; assert(intrin.id == NI_Sve_ConditionalSelect); - assert(op2->isContained()); assert(op2->OperIsHWIntrinsic()); + assert(op2->isContained()); // Get the registers and intrinsics that needs embedded mask const HWIntrinsic intrinEmbMask(op2->AsHWIntrinsic()); @@ -439,10 +439,54 @@ void CodeGen::genHWIntrinsic(GenTreeHWIntrinsic* node) { case 1: assert(!instrIsRMW); + if (targetReg != falseReg) { - GetEmitter()->emitIns_R_R(INS_sve_movprfx, EA_SCALABLE, targetReg, falseReg); + // If targetReg is not the same as `falseReg` then need to move + // the `falseReg` to `targetReg`. + + if (intrin.op3->isContained()) + { + assert(intrin.op3->IsVectorZero()); + if (intrin.op1->isContained()) + { + // We already skip importing ConditionalSelect if op1 == trueAll, however + // if we still see it here, it is because we wrapped the predicated instruction + // inside ConditionalSelect. + // As such, no need to move the `falseReg` to `targetReg` + // because the predicated instruction will eventually set it. + assert(intrin.op1->IsMaskAllBitsSet()); + } + else + { + // If falseValue is zero, just zero out those lanes of targetReg using `movprfx` + // and /Z + GetEmitter()->emitIns_R_R_R(INS_sve_movprfx, emitSize, targetReg, maskReg, targetReg, + opt); + } + } + else if (targetReg == embMaskOp1Reg) + { + // target != falseValue, but we do not want to overwrite target with `embMaskOp1Reg`. + // We will first do the predicate operation and then do conditionalSelect inactive + // elements from falseValue + + // We cannot use use `movprfx` here to move falseReg to targetReg because that will + // overwrite the value of embMaskOp1Reg which is present in targetReg. + GetEmitter()->emitIns_R_R_R(insEmbMask, emitSize, targetReg, maskReg, embMaskOp1Reg, opt); + + GetEmitter()->emitIns_R_R_R_R(INS_sve_sel, emitSize, targetReg, maskReg, targetReg, + falseReg, opt, INS_SCALABLE_OPTS_UNPREDICATED); + break; + } + else + { + // At this point, target != embMaskOp1Reg != falseReg, so just go ahead + // and move the falseReg unpredicated into targetReg. + GetEmitter()->emitIns_R_R(INS_sve_movprfx, EA_SCALABLE, targetReg, falseReg); + } } + GetEmitter()->emitIns_R_R_R(insEmbMask, emitSize, targetReg, maskReg, embMaskOp1Reg, opt); break; From cdfc8f255ddda5f6578e55fabb3b7382e6770730 Mon Sep 17 00:00:00 2001 From: Jackson Schuster <36744439+jtschuster@users.noreply.github.com> Date: Fri, 26 Apr 2024 15:25:05 -0700 Subject: [PATCH 112/161] Create separate attribute for warning behavior differences (#101220) To help track differences in the warning behavior of the trimming related tools, this modifies how adds UnexpectedWarning, and requires an issue link to be provided when there is a ProducedBy argument to the constructor. To enforce that either both a ProducedBy and IssueLink is provided or neither, the ProducedBy property is removed and is provided as the second to last argument, and IssueLink is provided as the last argument. ExpectedWarning means that the correct behavior is to warn. Any attributes that expect it only from a subset of the tools must provide an issue link. (These are mostly blank strings now, though) UnexpectedWarning means that this warning is not the correct behavior. These attributes always include a ProducedBy anrdshould link to an issue. Changes Look for a Tool attribute argument in the second to last position of ExpectedWarning and Unexpected warning when a ProducedBy property is not found. Find a replace existing ExpectedWarnings to use the new constructors. Adds issue links within AttributedMembersAccessedViaReflection.cs and in some places in ArrayDataFlow.cs --- .../TestCasesRunner/ResultChecker.cs | 25 +- .../TestChecker.cs | 69 ++- .../DataFlowTests.g.cs | 6 - .../Assertions/ExpectedWarningAttribute.cs | 25 +- .../Assertions/UnexpectedWarningAttribute.cs | 26 ++ .../CoreLink/InvalidIsTrimmableAttribute.cs | 2 +- .../AnnotatedMembersAccessedViaReflection.cs | 98 ++--- ...notatedMembersAccessedViaUnsafeAccessor.cs | 14 +- .../DataFlow/ArrayDataFlow.cs | 147 +++---- .../DataFlow/AssemblyQualifiedNameDataflow.cs | 5 +- .../DataFlow/AttributeConstructorDataflow.cs | 4 +- .../DataFlow/AttributeFieldDataflow.cs | 2 +- .../DataFlow/AttributePropertyDataflow.cs | 6 +- .../DataFlow/ByRefDataflow.cs | 30 +- ...pilerGeneratedCodeAccessedViaReflection.cs | 234 ++++------ .../DataFlow/CompilerGeneratedCodeDataflow.cs | 16 +- ...ompilerGeneratedCodeInPreservedAssembly.cs | 4 +- ...ratedCodeInPreservedAssemblyWithWarning.cs | 4 +- .../DataFlow/ComplexTypeHandling.cs | 2 +- .../DataFlow/ConstructedTypesDataFlow.cs | 12 +- .../DataFlow/ConstructorDataFlow.cs | 12 +- .../DataFlow/DynamicObjects.cs | 20 +- .../DataFlow/ExceptionalDataFlow.cs | 236 ++++------- .../DataFlow/ExponentialDataFlow.cs | 46 +- .../DataFlow/FeatureCheckDataFlow.cs | 117 +++-- .../DataFlow/FeatureGuardAttributeDataFlow.cs | 44 +- .../DataFlow/FieldDataFlow.cs | 13 +- .../DataFlow/GenericParameterDataFlow.cs | 36 +- .../GenericParameterWarningLocation.cs | 154 +++---- .../DataFlow/GetTypeDataFlow.cs | 6 +- .../DataFlow/InlineArrayDataflow.cs | 4 +- .../DataFlow/LocalDataFlow.cs | 49 +-- .../DataFlow/MakeGenericDataFlow.cs | 6 +- .../DataFlow/MakeGenericDataflowIntrinsics.cs | 8 +- .../DataFlow/MethodByRefParameterDataFlow.cs | 12 +- .../DataFlow/MethodByRefReturnDataFlow.cs | 14 +- .../DataFlow/MethodOutParameterDataFlow.cs | 4 +- .../DataFlow/MethodParametersDataFlow.cs | 6 +- .../DataFlow/MethodReturnParameterDataFlow.cs | 6 +- .../DataFlow/MethodThisDataFlow.cs | 2 +- .../DataFlow/PropertyDataFlow.cs | 105 ++--- .../DataFlow/RefFieldDataFlow.cs | 84 ++-- .../DataFlow/TypeBaseTypeDataFlow.cs | 5 +- .../DataFlow/UnresolvedMembers.cs | 16 +- ...odHierarchyDataflowAnnotationValidation.cs | 52 +-- .../Extensibility/CustomWarningUsage.cs | 2 +- .../LinkXml/LinkXmlErrorCases.cs | 10 +- .../Logging/SourceLines.cs | 8 +- .../Reflection/ActivatorCreateInstance.cs | 10 +- .../ExpressionPropertyMethodInfo.cs | 4 +- .../Reflection/MethodsUsedViaReflection.cs | 2 +- .../Reflection/ObjectGetType.cs | 4 +- .../TypeHierarchyReflectionWarnings.cs | 16 +- .../Reflection/TypeUsedViaReflection.cs | 12 +- .../RequiresCapability/BasicRequires.cs | 56 +-- ...flectionAccessFromCompilerGeneratedCode.cs | 64 ++- .../RequiresAccessedThrough.cs | 82 ++-- .../RequiresAttributeMismatch.cs | 316 +++++++------- .../RequiresInCompilerGeneratedCode.cs | 400 +++++++++--------- .../RequiresCapability/RequiresOnAttribute.cs | 48 +-- .../RequiresCapability/RequiresOnClass.cs | 282 ++++++------ .../RequiresOnStaticConstructor.cs | 26 +- .../RequiresOnVirtualsAndInterfaces.cs | 72 ++-- .../RequiresCapability/RequiresViaDataflow.cs | 26 +- .../RequiresCapability/RequiresViaXml.cs | 2 +- .../RequiresWithCopyAssembly.cs | 16 +- .../SingleFile/SingleFileIntrinsics.cs | 12 +- .../FeatureGuardSubstitutions.cs | 26 +- .../FeatureGuardSubstitutionsDisabled.cs | 4 +- .../Substitutions/ResourceSubstitutions.cs | 2 +- ...dundantSuppressionsFeatureSubstitutions.cs | 2 +- .../DetectRedundantSuppressionsFromXML.cs | 6 +- .../DetectRedundantSuppressionsInAssembly.cs | 2 +- ...dantSuppressionsInCompilerGeneratedCode.cs | 8 +- ...tRedundantSuppressionsInMembersAndTypes.cs | 34 +- ...uppressionsInMembersAndTypesUsingTarget.cs | 8 +- .../DetectRedundantSuppressionsInModule.cs | 2 +- ...SuppressWarningsInCompilerGeneratedCode.cs | 16 +- .../TestCasesRunner/ResultChecker.cs | 28 +- 79 files changed, 1642 insertions(+), 1754 deletions(-) create mode 100644 src/tools/illink/test/Mono.Linker.Tests.Cases.Expectations/Assertions/UnexpectedWarningAttribute.cs diff --git a/src/coreclr/tools/aot/ILCompiler.Trimming.Tests/TestCasesRunner/ResultChecker.cs b/src/coreclr/tools/aot/ILCompiler.Trimming.Tests/TestCasesRunner/ResultChecker.cs index 770bc1e97dfa2b..a6eb6007661f62 100644 --- a/src/coreclr/tools/aot/ILCompiler.Trimming.Tests/TestCasesRunner/ResultChecker.cs +++ b/src/coreclr/tools/aot/ILCompiler.Trimming.Tests/TestCasesRunner/ResultChecker.cs @@ -159,6 +159,8 @@ protected virtual void AdditionalChecking (TrimmedTestCaseResult linkResult, Ass private static bool IsProducedByNativeAOT (CustomAttribute attr) { + if (attr.ConstructorArguments.Count > 2 && attr.ConstructorArguments[^2].Type.Name == "Tool") + return ((Tool)attr.ConstructorArguments[^2].Value).HasFlag(Tool.NativeAot); var producedBy = attr.GetPropertyValue ("ProducedBy"); return producedBy is null ? true : ((Tool) producedBy).HasFlag (Tool.NativeAot); } @@ -227,12 +229,29 @@ private void VerifyLoggedMessages (AssemblyDefinition original, TrimmingTestLogg } break; - case nameof (ExpectedWarningAttribute): { + case nameof (ExpectedWarningAttribute) or nameof(UnexpectedWarningAttribute): { var expectedWarningCode = (string) attr.GetConstructorArgumentValue (0); if (!expectedWarningCode.StartsWith ("IL")) { - Assert.Fail ($"The warning code specified in {nameof (ExpectedWarningAttribute)} must start with the 'IL' prefix. Specified value: '{expectedWarningCode}'."); + Assert.Fail ($"The warning code specified in {attr.AttributeType.Name} must start with the 'IL' prefix. Specified value: '{expectedWarningCode}'."); } - var expectedMessageContains = ((CustomAttributeArgument[]) attr.GetConstructorArgumentValue (1)).Select (a => (string) a.Value).ToArray (); + IEnumerable expectedMessageContains = attr.Constructor.Parameters switch + { + // ExpectedWarningAttribute(string warningCode, params string[] expectedMessages) + // ExpectedWarningAttribute(string warningCode, string[] expectedMessages, Tool producedBy, string issueLink) + [_, { ParameterType.IsArray: true }, ..] + => ((CustomAttributeArgument[])attr.ConstructorArguments[1].Value) + .Select(caa => (string)caa.Value), + // ExpectedWarningAttribute(string warningCode, string expectedMessage1, string expectedMessage2, Tool producedBy, string issueLink) + [_, { ParameterType.Name: "String" }, { ParameterType.Name: "String" }, { ParameterType.Name: "Tool" }, _] + => [(string)attr.GetConstructorArgumentValue(1), (string)attr.GetConstructorArgumentValue(2)], + // ExpectedWarningAttribute(string warningCode, string expectedMessage, Tool producedBy, string issueLink) + [_, { ParameterType.Name: "String" }, { ParameterType.Name: "Tool" }, _] + => [(string)attr.GetConstructorArgumentValue(1)], + // ExpectedWarningAttribute(string warningCode, Tool producedBy, string issueLink) + [_, { ParameterType.Name: "Tool" }, _] + => [], + _ => throw new UnreachableException(), + }; string fileName = (string) attr.GetPropertyValue ("FileName")!; int? sourceLine = (int?) attr.GetPropertyValue ("SourceLine"); int? sourceColumn = (int?) attr.GetPropertyValue ("SourceColumn"); diff --git a/src/tools/illink/test/ILLink.RoslynAnalyzer.Tests/TestChecker.cs b/src/tools/illink/test/ILLink.RoslynAnalyzer.Tests/TestChecker.cs index 7631b802fbcc87..c50d24f136051d 100644 --- a/src/tools/illink/test/ILLink.RoslynAnalyzer.Tests/TestChecker.cs +++ b/src/tools/illink/test/ILLink.RoslynAnalyzer.Tests/TestChecker.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using System.Collections.Immutable; +using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Text.RegularExpressions; @@ -66,7 +67,7 @@ public void Check (bool allowMissingWarnings) } if (message.Length > 0) { - Assert.Fail(message); + Assert.Fail (message); } } @@ -207,51 +208,62 @@ private void ValidateDiagnostics (CSharpSyntaxNode memberSyntax, SyntaxList arg.Key.StartsWith ('#')).Count () - 2; + if (args.TryGetValue ($"#{toolArg}", out var maybeProducedBy) && TryGetProducedBy (maybeProducedBy, out Tool producedByTool)) { + return producedByTool.HasFlag (Tool.Analyzer); + } return true; default: return false; } - static Tool GetProducedBy (ExpressionSyntax expression) + static bool TryGetProducedBy (ExpressionSyntax expression, out Tool producedBy) { - var producedBy = (Tool) 0x0; + producedBy = (Tool) 0x0; switch (expression) { - case BinaryExpressionSyntax binaryExpressionSyntax: + case BinaryExpressionSyntax binaryExpressionSyntax when binaryExpressionSyntax.Kind () == SyntaxKind.BitwiseOrExpression: if (!Enum.TryParse ((binaryExpressionSyntax.Left as MemberAccessExpressionSyntax)!.Name.Identifier.ValueText, out var besProducedBy)) - throw new ArgumentException ("Expression must be a ProducedBy value", nameof (expression)); + return false; producedBy |= besProducedBy; producedBy |= GetProducedBy (binaryExpressionSyntax.Right); break; case MemberAccessExpressionSyntax memberAccessExpressionSyntax: if (!Enum.TryParse (memberAccessExpressionSyntax.Name.Identifier.ValueText, out var maeProducedBy)) - throw new ArgumentException ("Expression must be a ProducedBy value", nameof (expression)); + return false; producedBy |= maeProducedBy; break; default: - break; + return false; } - return producedBy; + return true; + } + + static Tool GetProducedBy (ExpressionSyntax expression) + { + return TryGetProducedBy (expression, out var tool) ? tool : throw new ArgumentException ("Expression must be a ProducedBy value", nameof (expression)); } } bool TryValidateExpectedDiagnostic (AttributeSyntax attribute, List diagnostics, [NotNullWhen (true)] out int? matchIndex, [NotNullWhen (false)] out string? missingDiagnosticMessage) { - switch (attribute.Name.ToString ()) { - case "ExpectedWarning": + switch (attribute.Name.ToString () + "Attribute") { + case nameof (ExpectedWarningAttribute): + case nameof (UnexpectedWarningAttribute): return TryValidateExpectedWarningAttribute (attribute!, diagnostics, out matchIndex, out missingDiagnosticMessage); - case "LogContains": + case nameof (LogContainsAttribute): return TryValidateLogContainsAttribute (attribute!, diagnostics, out matchIndex, out missingDiagnosticMessage); default: throw new InvalidOperationException ($"Unsupported attribute type {attribute.Name}"); @@ -268,10 +280,29 @@ private bool TryValidateExpectedWarningAttribute (AttributeSyntax attribute, Lis if (!expectedWarningCode.StartsWith ("IL")) throw new InvalidOperationException ($"Expected warning code should start with \"IL\" prefix."); - List expectedMessages = args - .Where (arg => arg.Key.StartsWith ("#") && arg.Key != "#0") - .Select (arg => LinkerTestBase.GetStringFromExpression (arg.Value, _semanticModel)) - .ToList (); + List expectedMessages = ((IMethodSymbol) (_semanticModel.GetSymbolInfo (attribute).Symbol!)).Parameters switch { + // ExpectedWarningAttribute(string warningCode, params string[] expectedMessages) + [_, { IsParams: true }] + => args + .Where (arg => arg.Key.StartsWith ('#') && arg.Key != "#0") + .Select (arg => LinkerTestBase.GetStringFromExpression (arg.Value, _semanticModel)) + .ToList (), + // ExpectedWarningAttribute(string warningCode, string[] expectedMessages, Tool producedBy, string issueLink) + [_, { Type.TypeKind: TypeKind.Array }, _, _] + => ((CollectionExpressionSyntax) args["#1"]).Elements + .Select (arg => LinkerTestBase.GetStringFromExpression (((ExpressionElementSyntax) arg).Expression, _semanticModel)) + .ToList (), + // ExpectedWarningAttribute(string warningCode, string expectedMessage, Tool producedBy, string issueLink) + [_, { Type.SpecialType: SpecialType.System_String }, _, _] + => [LinkerTestBase.GetStringFromExpression (args["#1"], _semanticModel)], + // ExpectedWarningAttribute(string warningCode, string expectedMessage1, string expectedMessage2, Tool producedBy, string issueLink) + [_, { Type.SpecialType: SpecialType.System_String }, { Type.SpecialType: SpecialType.System_String }, _, _] + => [LinkerTestBase.GetStringFromExpression (args["#1"], _semanticModel), LinkerTestBase.GetStringFromExpression (args["#2"], _semanticModel)], + // ExpectedWarningAttribute(string warningCode, Tool producedBy, string issueLink) + [_, _, _] + => [], + _ => throw new UnreachableException (), + }; for (int i = 0; i < diagnostics.Count; i++) { if (Matches (diagnostics[i])) { @@ -318,7 +349,7 @@ private void ValidateLogDoesNotContainAttribute (AttributeSyntax attribute, IRea Assert.False (args.ContainsKey ("#1")); _ = LinkerTestBase.GetStringFromExpression (arg, _semanticModel); if (LogContains (attribute, diagnosticMessages, out var matchIndex, out var findText)) { - Assert.Fail($"LogDoesNotContain failure: Text\n\"{findText}\"\nfound in diagnostic:\n {diagnosticMessages[(int) matchIndex]}"); + Assert.Fail ($"LogDoesNotContain failure: Text\n\"{findText}\"\nfound in diagnostic:\n {diagnosticMessages[(int) matchIndex]}"); } } diff --git a/src/tools/illink/test/ILLink.RoslynAnalyzer.Tests/generated/ILLink.RoslynAnalyzer.Tests.Generator/ILLink.RoslynAnalyzer.Tests.TestCaseGenerator/DataFlowTests.g.cs b/src/tools/illink/test/ILLink.RoslynAnalyzer.Tests/generated/ILLink.RoslynAnalyzer.Tests.Generator/ILLink.RoslynAnalyzer.Tests.TestCaseGenerator/DataFlowTests.g.cs index 0a390275ea81c4..5c3bd5a9d6654f 100644 --- a/src/tools/illink/test/ILLink.RoslynAnalyzer.Tests/generated/ILLink.RoslynAnalyzer.Tests.Generator/ILLink.RoslynAnalyzer.Tests.TestCaseGenerator/DataFlowTests.g.cs +++ b/src/tools/illink/test/ILLink.RoslynAnalyzer.Tests/generated/ILLink.RoslynAnalyzer.Tests.Generator/ILLink.RoslynAnalyzer.Tests.TestCaseGenerator/DataFlowTests.g.cs @@ -19,12 +19,6 @@ public Task GenericParameterDataFlowMarking () return RunTest (allowMissingWarnings: true); } - [Fact] - public Task MakeGenericDataflowIntrinsics () - { - return RunTest (allowMissingWarnings: true); - } - [Fact] public Task MethodByRefParameterDataFlow () { diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases.Expectations/Assertions/ExpectedWarningAttribute.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases.Expectations/Assertions/ExpectedWarningAttribute.cs index 648241200ef16a..19b785adabcc06 100644 --- a/src/tools/illink/test/Mono.Linker.Tests.Cases.Expectations/Assertions/ExpectedWarningAttribute.cs +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases.Expectations/Assertions/ExpectedWarningAttribute.cs @@ -9,8 +9,27 @@ namespace Mono.Linker.Tests.Cases.Expectations.Assertions AttributeTargets.Assembly | AttributeTargets.Struct | AttributeTargets.Class | AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Constructor | AttributeTargets.Field | AttributeTargets.Interface | AttributeTargets.Event, AllowMultiple = true, Inherited = false)] + /// + /// An attribute applied to a member to indicate that a warning is expected in ideal behavior, and is present in all tools + /// public class ExpectedWarningAttribute : EnableLoggerAttribute { + public ExpectedWarningAttribute (string warningCode, string[] messageContains, Tool producedBy, string issueLinkOrReason) + { + } + + public ExpectedWarningAttribute (string warningCode, string messageContains, Tool producedBy, string issueLinkOrReason) + { + } + + public ExpectedWarningAttribute (string warningCode, string messageContains, string messageContains2, Tool producedBy, string issueLinkOrReason) + { + } + + public ExpectedWarningAttribute (string warningCode, Tool producedBy, string issueLinkOrReason) + { + } + public ExpectedWarningAttribute (string warningCode, params string[] messageContains) { } @@ -19,12 +38,6 @@ public ExpectedWarningAttribute (string warningCode, params string[] messageCont public int SourceLine { get; set; } public int SourceColumn { get; set; } - /// - /// Property used by the result checkers of trimmer and analyzers to determine whether - /// the tool should have produced the specified warning on the annotated member. - /// - public Tool ProducedBy { get; set; } = Tool.TrimmerAnalyzerAndNativeAot; - public bool CompilerGeneratedCode { get; set; } } } diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases.Expectations/Assertions/UnexpectedWarningAttribute.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases.Expectations/Assertions/UnexpectedWarningAttribute.cs new file mode 100644 index 00000000000000..d745b61f3a1675 --- /dev/null +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases.Expectations/Assertions/UnexpectedWarningAttribute.cs @@ -0,0 +1,26 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; + +namespace Mono.Linker.Tests.Cases.Expectations.Assertions +{ + [AttributeUsage ( + AttributeTargets.Assembly | AttributeTargets.Struct | AttributeTargets.Class | AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Constructor | AttributeTargets.Field | AttributeTargets.Interface | AttributeTargets.Event, + AllowMultiple = true, + Inherited = false)] + /// + /// An attribute applied to a member to indicate that a warning is raised in tests, but should not be present in ideal behavior + /// + public class UnexpectedWarningAttribute : ExpectedWarningAttribute + { + public UnexpectedWarningAttribute (string warningCode, string[] messageContains, Tool producedBy, string issueLinkOrReason) + : base (warningCode, messageContains, producedBy, issueLinkOrReason) { } + public UnexpectedWarningAttribute (string warningCode, string messageContains, Tool producedBy, string issueLinkOrReason) + : base (warningCode, messageContains, producedBy, issueLinkOrReason) { } + public UnexpectedWarningAttribute (string warningCode, string messageContains, string messageContains2, Tool producedBy, string issueLinkOrReason) + : base (warningCode, messageContains, messageContains2, producedBy, issueLinkOrReason) { } + public UnexpectedWarningAttribute (string warningCode, Tool producedBy, string issueLinkOrReason) + : base (warningCode, producedBy, issueLinkOrReason) { } + } +} diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/CoreLink/InvalidIsTrimmableAttribute.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/CoreLink/InvalidIsTrimmableAttribute.cs index 35463fd52d442f..57b000fe3d377e 100644 --- a/src/tools/illink/test/Mono.Linker.Tests.Cases/CoreLink/InvalidIsTrimmableAttribute.cs +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/CoreLink/InvalidIsTrimmableAttribute.cs @@ -29,4 +29,4 @@ public static void Unused () { } } -} \ No newline at end of file +} diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/AnnotatedMembersAccessedViaReflection.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/AnnotatedMembersAccessedViaReflection.cs index d3fcbf32df47e5..f071090462b2e4 100644 --- a/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/AnnotatedMembersAccessedViaReflection.cs +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/AnnotatedMembersAccessedViaReflection.cs @@ -4,6 +4,7 @@ using System; using System.Diagnostics.CodeAnalysis; using System.Linq.Expressions; +using System.Reflection; using System.Runtime.InteropServices; using Mono.Linker.Tests.Cases.DataFlow; using Mono.Linker.Tests.Cases.Expectations.Assertions; @@ -54,8 +55,8 @@ static void ReflectionReadOnly () typeof (AnnotatedField).GetField ("_annotatedField").GetValue (null); } - // DynamicDependency is not supported yet in the analyzer https://github.com/dotnet/runtime/issues/83080 - [ExpectedWarning ("IL2110", nameof (_annotatedField), ProducedBy = Tool.Trimmer | Tool.NativeAot)] + // DynamicDependency is not supported yet in the analyzer + [ExpectedWarning ("IL2110", nameof (_annotatedField), Tool.Trimmer | Tool.NativeAot, "https://github.com/dotnet/runtime/issues/83080")] [DynamicDependency (DynamicallyAccessedMemberTypes.PublicFields, typeof (AnnotatedField))] static void DynamicDependency () { @@ -67,8 +68,8 @@ static void DynamicDependencySuppressedByRUC () { } - // DynamicDependency is not supported yet in the analyzer https://github.com/dotnet/runtime/issues/83080 - [ExpectedWarning ("IL2110", nameof (_annotatedField), ProducedBy = Tool.Trimmer | Tool.NativeAot)] + // DynamicDependency is not supported yet in the analyzer + [ExpectedWarning ("IL2110", nameof (_annotatedField), Tool.Trimmer | Tool.NativeAot, "https://github.com/dotnet/runtime/issues/83080")] [DynamicDependency (nameof (_annotatedField), typeof (AnnotatedField))] static void DynamicDependencyByName () { @@ -128,8 +129,7 @@ static void PotentialWriteAccess (ref Type type) { } - // https://github.com/dotnet/linker/issues/3172 - [ExpectedWarning ("IL2110", nameof (AnnotatedField._annotatedField), ProducedBy = Tool.Trimmer | Tool.NativeAot)] + [ExpectedWarning ("IL2110", nameof (AnnotatedField._annotatedField), Tool.Trimmer | Tool.NativeAot, "https://github.com/dotnet/linker/issues/3172")] static void LdToken () { Expression a = () => PotentialWriteAccess (ref _annotatedField); @@ -177,7 +177,7 @@ void LdftnOnLambda () { var _ = new Action ( [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] - () => MethodWithAnnotatedThisParameter ()); + () => MethodWithAnnotatedThisParameter ()); } [ExpectedWarning ("IL2111")] @@ -233,8 +233,8 @@ static void AnnotatedAttributeConstructor () { } - // DynamicDependency is not supported yet in the analyzer https://github.com/dotnet/runtime/issues/83080 - [ExpectedWarning ("IL2111", nameof (MethodWithSingleAnnotatedParameter), ProducedBy = Tool.Trimmer | Tool.NativeAot)] + // DynamicDependency is not supported yet in the analyzer + [ExpectedWarning ("IL2111", nameof (MethodWithSingleAnnotatedParameter), Tool.Trimmer | Tool.NativeAot, "https://github.com/dotnet/runtime/issues/83080")] [DynamicDependency (DynamicallyAccessedMemberTypes.PublicMethods, typeof (AnnotatedMethodParameters))] static void DynamicDependency () { @@ -246,8 +246,8 @@ static void DynamicDependencySuppressedByRUC () { } - // DynamicDependency is not supported yet in the analyzer https://github.com/dotnet/runtime/issues/83080 - [ExpectedWarning ("IL2111", nameof (MethodWithSingleAnnotatedParameter), ProducedBy = Tool.Trimmer | Tool.NativeAot)] + // DynamicDependency is not supported yet in the analyzer + [ExpectedWarning ("IL2111", nameof (MethodWithSingleAnnotatedParameter), Tool.Trimmer | Tool.NativeAot, "https://github.com/dotnet/runtime/issues/83080")] [DynamicDependency (nameof (MethodWithSingleAnnotatedParameter), typeof (AnnotatedMethodParameters))] static void DynamicDependencyByName () { @@ -278,7 +278,7 @@ static void LdftnSuppressedByRequiresUnreferencedCode () } [ExpectedWarning ("IL2111")] - static void + static void LdftnOnLambda () { var _ = new Action ( @@ -299,7 +299,7 @@ static void LdftnOnLambdaTriggersLamdaAnalysis () { var _ = new Action ( [ExpectedWarning ("IL2067", nameof (type), nameof (DataFlowTypeExtensions.RequiresAll))] - (Type type) => { type.RequiresAll (); }); + (Type type) => { type.RequiresAll (); }); } static void LdftnOnLocalMethodTriggersLocalMethodAnalysis () @@ -332,8 +332,8 @@ static void Ldvirtftn () [ExpectedWarning ("IL2111", nameof (MethodWithSingleAnnotatedParameter))] [ExpectedWarning ("IL2111", nameof (IWithAnnotatedMethod.AnnotatedMethod))] [ExpectedWarning ("IL2111", nameof (IWithAnnotatedMethod.AnnotatedMethod))] - [ExpectedWarning ("IL2118", nameof (LdftnOnLambdaTriggersLamdaAnalysis), ProducedBy = Tool.Trimmer)] - [ExpectedWarning ("IL2118", nameof (LdftnOnLocalMethodTriggersLocalMethodAnalysis), ProducedBy = Tool.Trimmer)] + [ExpectedWarning ("IL2118", nameof (LdftnOnLambdaTriggersLamdaAnalysis), Tool.Trimmer, "https://github.com/dotnet/runtime/issues/85042")] + [ExpectedWarning ("IL2118", nameof (LdftnOnLocalMethodTriggersLocalMethodAnalysis), Tool.Trimmer, "https://github.com/dotnet/runtime/issues/85042")] static void DynamicallyAccessedMembersAll1 () { typeof (AnnotatedMethodParameters).RequiresAll (); @@ -346,16 +346,15 @@ static void DynamicallyAccessedMembersAll1 () [ExpectedWarning ("IL2111", nameof (MethodWithSingleAnnotatedParameter))] [ExpectedWarning ("IL2111", nameof (IWithAnnotatedMethod.AnnotatedMethod))] [ExpectedWarning ("IL2111", nameof (IWithAnnotatedMethod.AnnotatedMethod))] - [ExpectedWarning ("IL2118", nameof (LdftnOnLambdaTriggersLamdaAnalysis), ProducedBy = Tool.Trimmer)] - [ExpectedWarning ("IL2118", nameof (LdftnOnLocalMethodTriggersLocalMethodAnalysis), ProducedBy = Tool.Trimmer)] + [ExpectedWarning ("IL2118", nameof (LdftnOnLambdaTriggersLamdaAnalysis), Tool.Trimmer, "https://github.com/dotnet/runtime/issues/85042")] + [ExpectedWarning ("IL2118", nameof (LdftnOnLocalMethodTriggersLocalMethodAnalysis), Tool.Trimmer, "https://github.com/dotnet/runtime/issues/85042")] static void DynamicallyAccessedMembersAll2 () { typeof (AnnotatedMethodParameters).RequiresAll (); } - // https://github.com/dotnet/linker/issues/3172 - [ExpectedWarning ("IL2111", nameof (MethodWithSingleAnnotatedParameter), ProducedBy = Tool.Trimmer | Tool.NativeAot)] - [ExpectedWarning ("IL2067", nameof (MethodWithSingleAnnotatedParameter), ProducedBy = Tool.Analyzer)] + [ExpectedWarning ("IL2111", nameof (MethodWithSingleAnnotatedParameter), Tool.Trimmer | Tool.NativeAot, "https://github.com/dotnet/linker/issues/3172")] + [UnexpectedWarning ("IL2067", nameof (MethodWithSingleAnnotatedParameter), Tool.Analyzer, "https://github.com/dotnet/linker/issues/3172")] static void LdToken () { Expression> _ = (Type t) => MethodWithSingleAnnotatedParameter (t); @@ -420,8 +419,7 @@ static void ReflectionOnVirtualSuppressedByRUC () typeof (AnnotatedMethodReturnValue).GetMethod (nameof (VirtualMethodWithAnnotatedReturnValue)).Invoke (null, null); } - // DynamicDependency is not supported yet in the analyzer https://github.com/dotnet/runtime/issues/83080 - [ExpectedWarning ("IL2111", nameof (VirtualMethodWithAnnotatedReturnValue), ProducedBy = Tool.Trimmer | Tool.NativeAot)] + [ExpectedWarning ("IL2111", nameof (VirtualMethodWithAnnotatedReturnValue), Tool.Trimmer | Tool.NativeAot, "https://github.com/dotnet/runtime/issues/83080")] [DynamicDependency (DynamicallyAccessedMemberTypes.PublicMethods, typeof (AnnotatedMethodReturnValue))] static void DynamicDependency () { @@ -443,8 +441,7 @@ static void DynamicDependencyByNameOnInstance () { } - // DynamicDependency is not supported yet in the analyzer https://github.com/dotnet/runtime/issues/83080 - [ExpectedWarning ("IL2111", nameof (VirtualMethodWithAnnotatedReturnValue), ProducedBy = Tool.Trimmer | Tool.NativeAot)] + [ExpectedWarning ("IL2111", nameof (VirtualMethodWithAnnotatedReturnValue), Tool.Trimmer | Tool.NativeAot, "https://github.com/dotnet/runtime/issues/83080")] [DynamicDependency (nameof (VirtualMethodWithAnnotatedReturnValue), typeof (AnnotatedMethodReturnValue))] static void DynamicDependencyByNameOnVirtual () { @@ -483,8 +480,7 @@ static void LdTokenOnStatic () Expression _ = () => StaticMethodWithAnnotatedReturnValue (); } - // https://github.com/dotnet/linker/issues/3172 - [ExpectedWarning ("IL2111", nameof (VirtualMethodWithAnnotatedReturnValue), ProducedBy = Tool.Trimmer | Tool.NativeAot)] + [ExpectedWarning ("IL2111", nameof (VirtualMethodWithAnnotatedReturnValue), Tool.Trimmer | Tool.NativeAot, "https://github.com/dotnet/linker/issues/3172")] static void LdTokenOnVirtual () { Expression> _ = (a) => a.VirtualMethodWithAnnotatedReturnValue (); @@ -527,7 +523,7 @@ class AnnotatedProperty public virtual Type VirtualProperty4WithAnnotation { get => null; set { value.ToString (); } } public static Type Property5WithAnnotationOnMembers { - [ExpectedWarning ("IL2078", nameof (Property5WithAnnotationOnMembers) + ".get", ProducedBy = Tool.Trimmer | Tool.NativeAot)] + [ExpectedWarning ("IL2078", nameof (Property5WithAnnotationOnMembers) + ".get", Tool.Trimmer | Tool.NativeAot, "https://github.com/dotnet/runtime/issues/101191")] [return: DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicEvents)] get; [param: DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicEvents)] @@ -596,13 +592,13 @@ static void AnnotatedAttributeProperty () } // DynamicDependency is not supported yet in the analyzer https://github.com/dotnet/runtime/issues/83080 - [ExpectedWarning ("IL2111", nameof (Property1WithAnnotation) + ".set", ProducedBy = Tool.Trimmer | Tool.NativeAot)] - [ExpectedWarning ("IL2111", nameof (VirtualProperty3WithAnnotationGetterOnly) + ".get", ProducedBy = Tool.Trimmer | Tool.NativeAot)] - [ExpectedWarning ("IL2111", nameof (VirtualProperty4WithAnnotation) + ".get", ProducedBy = Tool.Trimmer | Tool.NativeAot)] - [ExpectedWarning ("IL2111", nameof (VirtualProperty4WithAnnotation) + ".set", ProducedBy = Tool.Trimmer | Tool.NativeAot)] - [ExpectedWarning ("IL2111", nameof (Property5WithAnnotationOnMembers) + ".set", ProducedBy = Tool.Trimmer | Tool.NativeAot)] - [ExpectedWarning ("IL2111", nameof (VirtualProperty6WithAnnotationOnMembers) + ".get", ProducedBy = Tool.Trimmer | Tool.NativeAot)] - [ExpectedWarning ("IL2111", nameof (VirtualProperty6WithAnnotationOnMembers) + ".set", ProducedBy = Tool.Trimmer | Tool.NativeAot)] + [ExpectedWarning ("IL2111", nameof (Property1WithAnnotation) + ".set", Tool.Trimmer | Tool.NativeAot, "https://github.com/dotnet/runtime/issues/83080")] + [ExpectedWarning ("IL2111", nameof (VirtualProperty3WithAnnotationGetterOnly) + ".get", Tool.Trimmer | Tool.NativeAot, "https://github.com/dotnet/runtime/issues/83080")] + [ExpectedWarning ("IL2111", nameof (VirtualProperty4WithAnnotation) + ".get", Tool.Trimmer | Tool.NativeAot, "https://github.com/dotnet/runtime/issues/83080")] + [ExpectedWarning ("IL2111", nameof (VirtualProperty4WithAnnotation) + ".set", Tool.Trimmer | Tool.NativeAot, "https://github.com/dotnet/runtime/issues/83080")] + [ExpectedWarning ("IL2111", nameof (Property5WithAnnotationOnMembers) + ".set", Tool.Trimmer | Tool.NativeAot, "https://github.com/dotnet/runtime/issues/83080")] + [ExpectedWarning ("IL2111", nameof (VirtualProperty6WithAnnotationOnMembers) + ".get", Tool.Trimmer | Tool.NativeAot, "https://github.com/dotnet/runtime/issues/83080")] + [ExpectedWarning ("IL2111", nameof (VirtualProperty6WithAnnotationOnMembers) + ".set", Tool.Trimmer | Tool.NativeAot, "https://github.com/dotnet/runtime/issues/83080")] [DynamicDependency (DynamicallyAccessedMemberTypes.PublicProperties, typeof (AnnotatedProperty))] static void DynamicDependency () { @@ -685,15 +681,15 @@ static void DynamicallyAccessedMembersAll2 () typeof (AnnotatedProperty).RequiresAll (); } - // Analyzer doesn't produce this warning https://github.com/dotnet/linker/issues/2628 - [ExpectedWarning ("IL2110", nameof (Property1WithAnnotation), ProducedBy = Tool.Trimmer | Tool.NativeAot)] + // Analyzer doesn't produce this warning + [ExpectedWarning ("IL2110", nameof (Property1WithAnnotation), Tool.Trimmer | Tool.NativeAot, "https://github.com/dotnet/linker/issues/2628")] static void DynamicallyAccessedFields () { typeof (AnnotatedProperty).RequiresNonPublicFields (); } - // Action delegate is not handled correctly https://github.com/dotnet/runtime/issues/84918 - [ExpectedWarning ("IL2111", nameof (Property1WithAnnotation), ProducedBy = Tool.Trimmer | Tool.NativeAot)] + // Analyzer doesn't recognize Linq.Expressions + [ExpectedWarning ("IL2111", nameof (Property1WithAnnotation) + ".set", Tool.Trimmer | Tool.NativeAot, "https://github.com/dotnet/runtime/issues/101148")] static void LdToken () { Expression> _ = () => Property1WithAnnotation; @@ -835,8 +831,7 @@ static void DynamicallyAccessedMembersAll2 () typeof (AnnotationOnGenerics).RequiresAll (); } - // https://github.com/dotnet/linker/issues/3172 - [ExpectedWarning ("IL2111", "GenericWithAnnotatedMethod", "AnnotatedMethod", ProducedBy = Tool.Trimmer | Tool.NativeAot)] + [ExpectedWarning ("IL2111", ["GenericWithAnnotatedMethod", "AnnotatedMethod"], Tool.Trimmer | Tool.NativeAot, "https://github.com/dotnet/linker/issues/3172")] static void LdToken () { // Note that this should warn even though the code looks "Correct" @@ -867,13 +862,13 @@ struct ValueWithAnnotatedField public Type _typeField; } - // Analyzer doesn't take into account interop attributes https://github.com/dotnet/linker/issues/2562 - [ExpectedWarning ("IL2110", nameof (ValueWithAnnotatedField._typeField), ProducedBy = Tool.Trimmer)] + // Analyzer doesn't take into account interop attributes + [ExpectedWarning ("IL2110", nameof (ValueWithAnnotatedField._typeField), Tool.Trimmer, "https://github.com/dotnet/linker/issues/2562")] [DllImport ("nonexistent")] static extern ValueWithAnnotatedField GetValueWithAnnotatedField (); - // Analyzer doesn't take into account interop attributes https://github.com/dotnet/linker/issues/2562 - [ExpectedWarning ("IL2110", nameof (ValueWithAnnotatedField._typeField), ProducedBy = Tool.Trimmer)] + // Analyzer doesn't take into account interop attributes + [ExpectedWarning ("IL2110", nameof (ValueWithAnnotatedField._typeField), Tool.Trimmer, "https://github.com/dotnet/linker/issues/2562")] [DllImport ("nonexistent")] static extern void AcceptValueWithAnnotatedField (ValueWithAnnotatedField value); @@ -899,29 +894,28 @@ class DelegateCreation static void TestField () { var d = new UnannotatedDelegate (field); - d(typeof(int)); + d (typeof (int)); } static void TestProperty () { var d = new UnannotatedDelegate (Property); - d(typeof(int)); + d (typeof (int)); } [ExpectedWarning ("IL2111")] static void TestLambda () { var d = new UnannotatedDelegate ( - ([DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] Type t) => - { }); - d(typeof(int)); + ([DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] Type t) => { }); + d (typeof (int)); } [ExpectedWarning ("IL2111", "LocalMethod")] static void TestLocalMethod () { var d = new UnannotatedDelegate (LocalMethod); - d(typeof(int)); + d (typeof (int)); void LocalMethod ( [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] Type type) @@ -931,14 +925,14 @@ void LocalMethod ( static void TestMethodReturnValue () { var d = new UnannotatedDelegate (MethodReturnValue ()); - d(typeof(int)); + d (typeof (int)); } static void TestEvent () { var d = new UnannotatedDelegate (Event); - d(typeof(int)); + d (typeof (int)); } public static void Test () diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/AnnotatedMembersAccessedViaUnsafeAccessor.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/AnnotatedMembersAccessedViaUnsafeAccessor.cs index 9b8cd8959651b0..eb016da603f4c6 100644 --- a/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/AnnotatedMembersAccessedViaUnsafeAccessor.cs +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/AnnotatedMembersAccessedViaUnsafeAccessor.cs @@ -54,7 +54,7 @@ private static void MethodWithAnnotationMismatch ([DynamicallyAccessedMembers (D private static Type FieldWithAnnotationMismatch; } - [ExpectedWarning ("IL2111", ProducedBy = Tool.Trimmer)] + [UnexpectedWarning ("IL2111", Tool.Trimmer, "https://github.com/dotnet/runtime/issues/101195")] [UnsafeAccessor (UnsafeAccessorKind.StaticMethod)] extern static void MethodWithAnnotatedParameter (Target target, [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] Type type); @@ -63,23 +63,23 @@ private static void MethodWithAnnotationMismatch ([DynamicallyAccessedMembers (D [return: DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] extern static Type StaticMethodWithAnnotatedReturnValue (Target target); - [ExpectedWarning ("IL2111", ProducedBy = Tool.Trimmer)] + [UnexpectedWarning ("IL2111", Tool.Trimmer, "https://github.com/dotnet/runtime/issues/101195")] [UnsafeAccessor (UnsafeAccessorKind.Method)] [return: DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] extern static Type VirtualMethodWithAnnotatedReturnValue (Target target); - [ExpectedWarning ("IL2110", ProducedBy = Tool.Trimmer)] + [UnexpectedWarning ("IL2110", Tool.Trimmer, "https://github.com/dotnet/runtime/issues/101195")] [UnsafeAccessor (UnsafeAccessorKind.StaticField)] [return: DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] extern static ref Type AnnotatedField (Target target); - [ExpectedWarning ("IL2111", ProducedBy = Tool.Trimmer)] - [ExpectedWarning ("IL2067", ProducedBy = Tool.NativeAot)] + [UnexpectedWarning ("IL2111", Tool.Trimmer, "https://github.com/dotnet/runtime/issues/101195")] + [ExpectedWarning ("IL2067", Tool.NativeAot, "https://github.com/dotnet/runtime/issues/101195")] [UnsafeAccessor (UnsafeAccessorKind.StaticMethod)] extern static void MethodWithAnnotationMismatch (Target target, [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicFields)] Type type); - [ExpectedWarning ("IL2110", ProducedBy = Tool.Trimmer)] - [ExpectedWarning ("IL2078", ProducedBy = Tool.NativeAot)] + [UnexpectedWarning ("IL2110", Tool.Trimmer, "https://github.com/dotnet/runtime/issues/101195")] + [ExpectedWarning ("IL2078", Tool.NativeAot, "https://github.com/dotnet/runtime/issues/101195")] [UnsafeAccessor (UnsafeAccessorKind.StaticField)] [return: DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicFields)] extern static ref Type FieldWithAnnotationMismatch (Target target); diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/ArrayDataFlow.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/ArrayDataFlow.cs index 1fc103037b3886..b819d459758530 100644 --- a/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/ArrayDataFlow.cs +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/ArrayDataFlow.cs @@ -117,13 +117,10 @@ static void TestArraySetElementOneElementMix () arr[0].RequiresAll (); } - [ExpectedWarning ("IL2072", nameof (GetUnknownType), nameof (DataFlowTypeExtensions.RequiresAll), - ProducedBy = Tool.Analyzer)] - [ExpectedWarning ("IL2072", nameof (GetTypeWithPublicConstructors), nameof (DataFlowTypeExtensions.RequiresAll), - ProducedBy = Tool.Analyzer)] + [ExpectedWarning ("IL2072", nameof (GetUnknownType), nameof (DataFlowTypeExtensions.RequiresAll), Tool.Analyzer, "")] + [ExpectedWarning ("IL2072", nameof (GetTypeWithPublicConstructors), nameof (DataFlowTypeExtensions.RequiresAll), Tool.Analyzer, "")] // https://github.com/dotnet/linker/issues/2737 - [ExpectedWarning ("IL2062", nameof (DataFlowTypeExtensions.RequiresAll), - ProducedBy = Tool.Trimmer | Tool.NativeAot)] + [ExpectedWarning ("IL2062", nameof (DataFlowTypeExtensions.RequiresAll), Tool.Trimmer | Tool.NativeAot, "")] static void TestArraySetElementOneElementMerged () { Type[] arr = new Type[1]; @@ -210,14 +207,9 @@ static void TestGetElementAtUnknownIndex (int i = 0) arr[i].RequiresPublicFields (); } - // https://github.com/dotnet/runtime/issues/93416 tracks the discrepancy between - // the analyzer and ILLink/ILCompiler. - [ExpectedWarning ("IL2062", nameof (DataFlowTypeExtensions.RequiresAll), - ProducedBy = Tool.Trimmer | Tool.NativeAot)] - [ExpectedWarning ("IL2072", nameof (GetMethods), nameof (DataFlowTypeExtensions.RequiresAll), - ProducedBy = Tool.Analyzer)] - [ExpectedWarning ("IL2072", nameof (GetFields), nameof (DataFlowTypeExtensions.RequiresAll), - ProducedBy = Tool.Analyzer)] + [UnexpectedWarning ("IL2062", nameof (DataFlowTypeExtensions.RequiresAll), Tool.Trimmer | Tool.NativeAot, "https://github.com/dotnet/runtime/issues/93416")] + [ExpectedWarning ("IL2072", [nameof (GetMethods), nameof (DataFlowTypeExtensions.RequiresAll)], Tool.Analyzer, "https://github.com/dotnet/runtime/issues/93416")] + [ExpectedWarning ("IL2072", [nameof (GetFields), nameof (DataFlowTypeExtensions.RequiresAll)], Tool.Analyzer, "https://github.com/dotnet/runtime/issues/93416")] static void TestGetMergedArrayElement (bool b = true) { Type[] arr = new Type[] { GetMethods () }; @@ -227,8 +219,8 @@ static void TestGetMergedArrayElement (bool b = true) arr[0].RequiresAll (); } - // Trimmer code doesnt handle locals from different branches separetely, therefore merges incorrectly GetMethods with Unknown producing both warnings - [ExpectedWarning ("IL2072", nameof (ArrayDataFlow.GetMethods), ProducedBy = Tool.Trimmer | Tool.NativeAot)] + // Trimmer code doesn't handle locals from different branches separately, therefore merges incorrectly GetMethods with Unknown producing both warnings + [UnexpectedWarning ("IL2072", nameof (ArrayDataFlow.GetMethods), Tool.Trimmer | Tool.NativeAot, "https://github.com/dotnet/runtime/issues/93416")] [ExpectedWarning ("IL2062", nameof (DataFlowTypeExtensions.RequiresAll))] static void TestMergedArrayElementWithUnknownIndex (int i) { @@ -252,9 +244,9 @@ static void TestArrayResetStoreUnknownIndex (int i = 0) } // https://github.com/dotnet/linker/issues/2680 - analyzer doesn't reset array in this case - [ExpectedWarning ("IL2062", nameof (DataFlowTypeExtensions.RequiresPublicFields), ProducedBy = Tool.Trimmer | Tool.NativeAot)] + [ExpectedWarning ("IL2062", nameof (DataFlowTypeExtensions.RequiresPublicFields), Tool.Trimmer | Tool.NativeAot, "")] // https://github.com/dotnet/linker/issues/2680 - analyzer doesn't reset array in this case - [ExpectedWarning ("IL2062", nameof (DataFlowTypeExtensions.RequiresPublicMethods), ProducedBy = Tool.Trimmer | Tool.NativeAot)] + [ExpectedWarning ("IL2062", nameof (DataFlowTypeExtensions.RequiresPublicMethods), Tool.Trimmer | Tool.NativeAot, "")] static void TestArrayResetGetElementOnByRefArray (int i = 0) { Type[] arr = new Type[] { typeof (TestType), typeof (TestType) }; @@ -286,7 +278,7 @@ static void TestArrayResetAfterCall () static void TakesTypesArray (Type[] types) { } // https://github.com/dotnet/linker/issues/2680 - // [ExpectedWarning ("IL2062", nameof (DataFlowTypeExtensions.RequiresPublicFields))] + // [ExpectedSharedWarning ("IL2062", nameof (DataFlowTypeExtensions.RequiresPublicFields))] static void TestArrayResetAfterAssignment () { Type[] arr = new Type[] { typeof (TestType) }; @@ -344,9 +336,9 @@ public static void Test () TestAddressOfElement (); } - [ExpectedWarning ("IL2062", nameof (DataFlowTypeExtensions.RequiresPublicMethods), ProducedBy = Tool.Trimmer | Tool.NativeAot)] + [ExpectedWarning ("IL2062", nameof (DataFlowTypeExtensions.RequiresPublicMethods), Tool.Trimmer | Tool.NativeAot, "")] // Multidimensional Arrays not handled -- assumed to be UnknownValue - [ExpectedWarning ("IL2062", nameof (DataFlowTypeExtensions.RequiresAll), ProducedBy = Tool.Trimmer | Tool.NativeAot)] + [ExpectedWarning ("IL2062", nameof (DataFlowTypeExtensions.RequiresAll), Tool.Trimmer | Tool.NativeAot, "")] static void TestArrayWithInitializerOneElementStaticType () { Type[,] arr = new Type[,] { { typeof (TestType) } }; @@ -354,9 +346,9 @@ static void TestArrayWithInitializerOneElementStaticType () arr[0, 1].RequiresPublicMethods (); // Should warn - unknown value at this index } - [ExpectedWarning ("IL2062", nameof (DataFlowTypeExtensions.RequiresPublicMethods), ProducedBy = Tool.Trimmer | Tool.NativeAot)] + [ExpectedWarning ("IL2062", nameof (DataFlowTypeExtensions.RequiresPublicMethods), Tool.Trimmer | Tool.NativeAot, "")] // Multidimensional Arrays not handled -- assumed to be UnknownValue - [ExpectedWarning ("IL2062", nameof (DataFlowTypeExtensions.RequiresAll), ProducedBy = Tool.Trimmer | Tool.NativeAot)] + [ExpectedWarning ("IL2062", nameof (DataFlowTypeExtensions.RequiresAll), Tool.Trimmer | Tool.NativeAot, "")] static void TestArrayWithInitializerOneElementParameter ([DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.All)] Type type) { Type[,] arr = new Type[,] { { type } }; @@ -364,11 +356,11 @@ static void TestArrayWithInitializerOneElementParameter ([DynamicallyAccessedMem arr[0, 1].RequiresPublicMethods (); // Should warn - unknown value at this index } - [ExpectedWarning ("IL2062", nameof (DataFlowTypeExtensions.RequiresPublicMethods), ProducedBy = Tool.Trimmer | Tool.NativeAot)] + [ExpectedWarning ("IL2062", nameof (DataFlowTypeExtensions.RequiresPublicMethods), Tool.Trimmer | Tool.NativeAot, "")] // Below are because we do not handle Multi dimensional arrays - [ExpectedWarning ("IL2062", nameof (DataFlowTypeExtensions.RequiresAll), ProducedBy = Tool.Trimmer | Tool.NativeAot)] - [ExpectedWarning ("IL2062", nameof (DataFlowTypeExtensions.RequiresAll), ProducedBy = Tool.Trimmer | Tool.NativeAot)] - [ExpectedWarning ("IL2062", nameof (DataFlowTypeExtensions.RequiresAll), ProducedBy = Tool.Trimmer | Tool.NativeAot)] + [ExpectedWarning ("IL2062", nameof (DataFlowTypeExtensions.RequiresAll), Tool.Trimmer | Tool.NativeAot, "")] + [ExpectedWarning ("IL2062", nameof (DataFlowTypeExtensions.RequiresAll), Tool.Trimmer | Tool.NativeAot, "")] + [ExpectedWarning ("IL2062", nameof (DataFlowTypeExtensions.RequiresAll), Tool.Trimmer | Tool.NativeAot, "")] static void TestArrayWithInitializerMultipleElementsStaticType () { Type[,] arr = new Type[,] { { typeof (TestType), typeof (TestType), typeof (TestType) } }; @@ -379,13 +371,13 @@ static void TestArrayWithInitializerMultipleElementsStaticType () } // Bug - // [ExpectedWarning ("IL2087", nameof (DataFlowTypeExtensions.RequiresPublicFields), ProducedBy = ProducedBy.Trimmer | ProducedBy.NativeAot)] - [ExpectedWarning ("IL2062", nameof (DataFlowTypeExtensions.RequiresPublicMethods), ProducedBy = Tool.Trimmer | Tool.NativeAot)] + // [ExpectedWarning ("IL2087", nameof (DataFlowTypeExtensions.RequiresPublicFields), Tool.Trimmer | Tool.NativeAot, "")] + [ExpectedWarning ("IL2062", nameof (DataFlowTypeExtensions.RequiresPublicMethods), Tool.Trimmer | Tool.NativeAot, "")] // Below are because we do not handle Multi dimensional arrays - [ExpectedWarning ("IL2062", nameof (DataFlowTypeExtensions.RequiresAll), ProducedBy = Tool.Trimmer | Tool.NativeAot)] - [ExpectedWarning ("IL2062", nameof (DataFlowTypeExtensions.RequiresPublicProperties), ProducedBy = Tool.Trimmer | Tool.NativeAot)] - [ExpectedWarning ("IL2062", nameof (DataFlowTypeExtensions.RequiresPublicFields), ProducedBy = Tool.Trimmer | Tool.NativeAot)] - [ExpectedWarning ("IL2062", nameof (DataFlowTypeExtensions.RequiresAll), ProducedBy = Tool.Trimmer | Tool.NativeAot)] + [ExpectedWarning ("IL2062", nameof (DataFlowTypeExtensions.RequiresAll), Tool.Trimmer | Tool.NativeAot, "")] + [ExpectedWarning ("IL2062", nameof (DataFlowTypeExtensions.RequiresPublicProperties), Tool.Trimmer | Tool.NativeAot, "")] + [ExpectedWarning ("IL2062", nameof (DataFlowTypeExtensions.RequiresPublicFields), Tool.Trimmer | Tool.NativeAot, "")] + [ExpectedWarning ("IL2062", nameof (DataFlowTypeExtensions.RequiresAll), Tool.Trimmer | Tool.NativeAot, "")] static void TestArrayWithInitializerMultipleElementsMix<[DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicProperties)] TProperties> ( [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.All)] Type typeAll) { @@ -397,9 +389,9 @@ static void TestArrayWithInitializerMultipleElementsStaticType () arr[0, 3].RequiresPublicMethods (); // Should warn - unknown value at this index } - [ExpectedWarning ("IL2062", nameof (DataFlowTypeExtensions.RequiresPublicMethods), ProducedBy = Tool.Trimmer | Tool.NativeAot)] + [ExpectedWarning ("IL2062", nameof (DataFlowTypeExtensions.RequiresPublicMethods), Tool.Trimmer | Tool.NativeAot, "")] // Multidimensional Arrays not handled -- assumed to be UnknownValue - [ExpectedWarning ("IL2062", nameof (DataFlowTypeExtensions.RequiresAll), ProducedBy = Tool.Trimmer | Tool.NativeAot)] + [ExpectedWarning ("IL2062", nameof (DataFlowTypeExtensions.RequiresAll), Tool.Trimmer | Tool.NativeAot, "")] static void TestArraySetElementOneElementStaticType () { Type[,] arr = new Type[1, 1]; @@ -408,9 +400,9 @@ static void TestArraySetElementOneElementStaticType () arr[0, 1].RequiresPublicMethods (); // Should warn - unknown value at this index } - [ExpectedWarning ("IL2062", nameof (DataFlowTypeExtensions.RequiresPublicMethods), ProducedBy = Tool.Trimmer | Tool.NativeAot)] + [ExpectedWarning ("IL2062", nameof (DataFlowTypeExtensions.RequiresPublicMethods), Tool.Trimmer | Tool.NativeAot, "")] // Multidimensional Arrays not handled -- assumed to be UnknownValue - [ExpectedWarning ("IL2062", nameof (DataFlowTypeExtensions.RequiresAll), ProducedBy = Tool.Trimmer | Tool.NativeAot)] + [ExpectedWarning ("IL2062", nameof (DataFlowTypeExtensions.RequiresAll), Tool.Trimmer | Tool.NativeAot, "")] static void TestArraySetElementOneElementParameter ([DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.All)] Type type) { Type[,] arr = new Type[1, 1]; @@ -419,11 +411,11 @@ static void TestArraySetElementOneElementParameter ([DynamicallyAccessedMembers arr[0, 1].RequiresPublicMethods (); // Should warn - unknown value at this index } - [ExpectedWarning ("IL2062", nameof (DataFlowTypeExtensions.RequiresPublicMethods), ProducedBy = Tool.Trimmer | Tool.NativeAot)] + [ExpectedWarning ("IL2062", nameof (DataFlowTypeExtensions.RequiresPublicMethods), Tool.Trimmer | Tool.NativeAot, "")] // Below are because we do not handle Multi dimensional arrays - [ExpectedWarning ("IL2062", nameof (DataFlowTypeExtensions.RequiresAll), ProducedBy = Tool.Trimmer | Tool.NativeAot)] - [ExpectedWarning ("IL2062", nameof (DataFlowTypeExtensions.RequiresAll), ProducedBy = Tool.Trimmer | Tool.NativeAot)] - [ExpectedWarning ("IL2062", nameof (DataFlowTypeExtensions.RequiresAll), ProducedBy = Tool.Trimmer | Tool.NativeAot)] + [ExpectedWarning ("IL2062", nameof (DataFlowTypeExtensions.RequiresAll), Tool.Trimmer | Tool.NativeAot, "")] + [ExpectedWarning ("IL2062", nameof (DataFlowTypeExtensions.RequiresAll), Tool.Trimmer | Tool.NativeAot, "")] + [ExpectedWarning ("IL2062", nameof (DataFlowTypeExtensions.RequiresAll), Tool.Trimmer | Tool.NativeAot, "")] static void TestArraySetElementMultipleElementsStaticType () { Type[,] arr = new Type[1, 3]; @@ -437,13 +429,13 @@ static void TestArraySetElementMultipleElementsStaticType () } // Bug - // [ExpectedWarning ("IL2087", nameof (DataFlowTypeExtensions.RequiresPublicFields), ProducedBy = ProducedBy.Trimmer | ProducedBy.NativeAot)] - [ExpectedWarning ("IL2062", nameof (DataFlowTypeExtensions.RequiresPublicMethods), ProducedBy = Tool.Trimmer | Tool.NativeAot)] + // [ExpectedWarning ("IL2087", nameof (DataFlowTypeExtensions.RequiresPublicFields), Tool.Trimmer | Tool.NativeAot, "")] + [ExpectedWarning ("IL2062", nameof (DataFlowTypeExtensions.RequiresPublicMethods), Tool.Trimmer | Tool.NativeAot, "")] // Below are because we do not handle Multi dimensional arrays - [ExpectedWarning ("IL2062", nameof (DataFlowTypeExtensions.RequiresPublicFields), ProducedBy = Tool.Trimmer | Tool.NativeAot)] - [ExpectedWarning ("IL2062", nameof (DataFlowTypeExtensions.RequiresPublicProperties), ProducedBy = Tool.Trimmer | Tool.NativeAot)] - [ExpectedWarning ("IL2062", nameof (DataFlowTypeExtensions.RequiresAll), ProducedBy = Tool.Trimmer | Tool.NativeAot)] - [ExpectedWarning ("IL2062", nameof (DataFlowTypeExtensions.RequiresAll), ProducedBy = Tool.Trimmer | Tool.NativeAot)] + [ExpectedWarning ("IL2062", nameof (DataFlowTypeExtensions.RequiresPublicFields), Tool.Trimmer | Tool.NativeAot, "")] + [ExpectedWarning ("IL2062", nameof (DataFlowTypeExtensions.RequiresPublicProperties), Tool.Trimmer | Tool.NativeAot, "")] + [ExpectedWarning ("IL2062", nameof (DataFlowTypeExtensions.RequiresAll), Tool.Trimmer | Tool.NativeAot, "")] + [ExpectedWarning ("IL2062", nameof (DataFlowTypeExtensions.RequiresAll), Tool.Trimmer | Tool.NativeAot, "")] static void TestArraySetElementMultipleElementsMix<[DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicProperties)] TProperties> ( [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.All)] Type typeAll) { @@ -459,13 +451,13 @@ static void TestArraySetElementMultipleElementsStaticType () } // Bug - // [ExpectedWarning ("IL2087", nameof (DataFlowTypeExtensions.RequiresPublicFields), ProducedBy = ProducedBy.Trimmer | ProducedBy.NativeAot)] - [ExpectedWarning ("IL2062", nameof (DataFlowTypeExtensions.RequiresPublicMethods), ProducedBy = Tool.Trimmer | Tool.NativeAot)] + // [ExpectedWarning ("IL2087", nameof (DataFlowTypeExtensions.RequiresPublicFields), Tool.Trimmer | Tool.NativeAot, "")] + [ExpectedWarning ("IL2062", nameof (DataFlowTypeExtensions.RequiresPublicMethods), Tool.Trimmer | Tool.NativeAot, "")] // Below are because we do not handle Multi dimensional arrays - [ExpectedWarning ("IL2062", nameof (DataFlowTypeExtensions.RequiresPublicFields), ProducedBy = Tool.Trimmer | Tool.NativeAot)] - [ExpectedWarning ("IL2062", nameof (DataFlowTypeExtensions.RequiresPublicProperties), ProducedBy = Tool.Trimmer | Tool.NativeAot)] - [ExpectedWarning ("IL2062", nameof (DataFlowTypeExtensions.RequiresAll), ProducedBy = Tool.Trimmer | Tool.NativeAot)] - [ExpectedWarning ("IL2062", nameof (DataFlowTypeExtensions.RequiresAll), ProducedBy = Tool.Trimmer | Tool.NativeAot)] + [ExpectedWarning ("IL2062", nameof (DataFlowTypeExtensions.RequiresPublicFields), Tool.Trimmer | Tool.NativeAot, "")] + [ExpectedWarning ("IL2062", nameof (DataFlowTypeExtensions.RequiresPublicProperties), Tool.Trimmer | Tool.NativeAot, "")] + [ExpectedWarning ("IL2062", nameof (DataFlowTypeExtensions.RequiresAll), Tool.Trimmer | Tool.NativeAot, "")] + [ExpectedWarning ("IL2062", nameof (DataFlowTypeExtensions.RequiresAll), Tool.Trimmer | Tool.NativeAot, "")] static void TestArraySetElementAndInitializerMultipleElementsMix<[DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicProperties)] TProperties> ( [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.All)] Type typeAll) { @@ -479,16 +471,16 @@ static void TestArraySetElementMultipleElementsStaticType () arr[0, 3].RequiresPublicMethods (); // Should warn - unknown value at this index } - [ExpectedWarning ("IL2062", nameof (DataFlowTypeExtensions.RequiresPublicFields), ProducedBy = Tool.Trimmer | Tool.NativeAot)] + [ExpectedWarning ("IL2062", nameof (DataFlowTypeExtensions.RequiresPublicFields), Tool.Trimmer | Tool.NativeAot, "")] static void TestGetElementAtUnknownIndex (int i = 0) { Type[,] arr = new Type[,] { { typeof (TestType) } }; arr[0, i].RequiresPublicFields (); } - [ExpectedWarning ("IL2062", nameof (DataFlowTypeExtensions.RequiresPublicFields), ProducedBy = Tool.Trimmer | Tool.NativeAot)] + [ExpectedWarning ("IL2062", nameof (DataFlowTypeExtensions.RequiresPublicFields), Tool.Trimmer | Tool.NativeAot, "")] // Multidimensional Arrays not handled -- assumed to be UnknownValue - [ExpectedWarning ("IL2062", nameof (DataFlowTypeExtensions.RequiresPublicProperties), ProducedBy = Tool.Trimmer | Tool.NativeAot)] + [ExpectedWarning ("IL2062", nameof (DataFlowTypeExtensions.RequiresPublicProperties), Tool.Trimmer | Tool.NativeAot, "")] static void TestArrayResetStoreUnknownIndex (int i = 0) { Type[,] arr = new Type[,] { { typeof (TestType) } }; @@ -500,11 +492,11 @@ static void TestArrayResetStoreUnknownIndex (int i = 0) } // https://github.com/dotnet/linker/issues/2680 - analyzer doesn't reset array in this case - [ExpectedWarning ("IL2062", nameof (DataFlowTypeExtensions.RequiresPublicFields), ProducedBy = Tool.Trimmer | Tool.NativeAot)] + [ExpectedWarning ("IL2062", nameof (DataFlowTypeExtensions.RequiresPublicFields), Tool.Trimmer | Tool.NativeAot, "")] // Multidimensional Arrays not handled -- assumed to be UnknownValue - [ExpectedWarning ("IL2062", nameof (DataFlowTypeExtensions.RequiresPublicProperties), ProducedBy = Tool.Trimmer | Tool.NativeAot)] + [ExpectedWarning ("IL2062", nameof (DataFlowTypeExtensions.RequiresPublicProperties), Tool.Trimmer | Tool.NativeAot, "")] // Multidimensional Arrays not handled -- assumed to be UnknownValue - [ExpectedWarning ("IL2062", nameof (DataFlowTypeExtensions.RequiresPublicMethods), ProducedBy = Tool.Trimmer | Tool.NativeAot)] + [ExpectedWarning ("IL2062", nameof (DataFlowTypeExtensions.RequiresPublicMethods), Tool.Trimmer | Tool.NativeAot, "")] static void TestArrayResetGetElementOnByRefArray (int i = 0) { Type[,] arr = new Type[,] { { typeof (TestType) } }; @@ -519,9 +511,9 @@ static void TestArrayResetGetElementOnByRefArray (int i = 0) static void TakesTypeByRef (ref Type type) { } - [ExpectedWarning ("IL2062", nameof (DataFlowTypeExtensions.RequiresPublicFields), ProducedBy = Tool.Trimmer | Tool.NativeAot)] + [ExpectedWarning ("IL2062", nameof (DataFlowTypeExtensions.RequiresPublicFields), Tool.Trimmer | Tool.NativeAot, "")] // Multidimensional Arrays not handled -- assumed to be UnknownValue - [ExpectedWarning ("IL2062", nameof (DataFlowTypeExtensions.RequiresPublicProperties), ProducedBy = Tool.Trimmer | Tool.NativeAot)] + [ExpectedWarning ("IL2062", nameof (DataFlowTypeExtensions.RequiresPublicProperties), Tool.Trimmer | Tool.NativeAot, "")] static void TestArrayResetAfterCall () { Type[,] arr = new Type[,] { { typeof (TestType) } }; @@ -537,9 +529,9 @@ static void TestArrayResetAfterCall () static void TakesTypesArray (Type[,] types) { } // https://github.com/dotnet/linker/issues/2680 - [ExpectedWarning ("IL2062", nameof (DataFlowTypeExtensions.RequiresPublicFields), ProducedBy = Tool.Trimmer | Tool.NativeAot)] + [ExpectedWarning ("IL2062", nameof (DataFlowTypeExtensions.RequiresPublicFields), Tool.Trimmer | Tool.NativeAot, "")] // Multidimensional Arrays not handled -- assumed to be UnknownValue - [ExpectedWarning ("IL2062", nameof (DataFlowTypeExtensions.RequiresPublicProperties), ProducedBy = Tool.Trimmer | Tool.NativeAot)] + [ExpectedWarning ("IL2062", nameof (DataFlowTypeExtensions.RequiresPublicProperties), Tool.Trimmer | Tool.NativeAot, "")] static void TestArrayResetAfterAssignment () { Type[,] arr = new Type[,] { { typeof (TestType) } }; @@ -553,7 +545,7 @@ static void TestArrayResetAfterAssignment () arr[0, 0].RequiresPublicFields (); // Should warn } - [ExpectedWarning ("IL2062", nameof (DataFlowTypeExtensions.RequiresPublicMethods), ProducedBy = Tool.Trimmer | Tool.NativeAot)] + [ExpectedWarning ("IL2062", nameof (DataFlowTypeExtensions.RequiresPublicMethods), Tool.Trimmer | Tool.NativeAot, "")] static void TestAddressOfElement () { Type[,] arr = new Type[,] { { typeof (TestType) } }; @@ -566,13 +558,10 @@ static void TestAddressOfElement () class WriteCapturedArrayElement { - [ExpectedWarning ("IL2072", nameof (GetUnknownType), nameof (DataFlowTypeExtensions.RequiresAll), - ProducedBy = Tool.Analyzer)] - [ExpectedWarning ("IL2072", nameof (GetTypeWithPublicConstructors), nameof (DataFlowTypeExtensions.RequiresAll), - ProducedBy = Tool.Analyzer)] + [ExpectedWarning ("IL2072", nameof (GetUnknownType), nameof (DataFlowTypeExtensions.RequiresAll), Tool.Analyzer, "")] + [ExpectedWarning ("IL2072", nameof (GetTypeWithPublicConstructors), nameof (DataFlowTypeExtensions.RequiresAll), Tool.Analyzer, "")] // https://github.com/dotnet/linker/issues/2737 - [ExpectedWarning ("IL2062", nameof (DataFlowTypeExtensions.RequiresAll), - ProducedBy = Tool.Trimmer | Tool.NativeAot)] + [ExpectedWarning ("IL2062", nameof (DataFlowTypeExtensions.RequiresAll), Tool.Trimmer | Tool.NativeAot, "")] static void TestNullCoalesce () { Type[] arr = new Type[1]; @@ -590,11 +579,9 @@ static void TestNullCoalescingAssignment () arr[0].RequiresAll (); } - [ExpectedWarning ("IL2062", nameof (DataFlowTypeExtensions.RequiresAll), - ProducedBy = Tool.Analyzer)] + [ExpectedWarning ("IL2062", nameof (DataFlowTypeExtensions.RequiresAll), Tool.Analyzer, "")] // https://github.com/dotnet/linker/issues/2746 - [ExpectedWarning ("IL2072", nameof (GetUnknownType), nameof (DataFlowTypeExtensions.RequiresAll), - ProducedBy = Tool.Trimmer | Tool.NativeAot)] + [ExpectedWarning ("IL2072", nameof (GetUnknownType), nameof (DataFlowTypeExtensions.RequiresAll), Tool.Trimmer | Tool.NativeAot, "")] static void TestNullCoalescingAssignmentToEmpty () { Type[] arr = new Type[1]; @@ -604,10 +591,8 @@ static void TestNullCoalescingAssignmentToEmpty () [ExpectedWarning ("IL2072", nameof (GetWithPublicMethods), nameof (DataFlowTypeExtensions.RequiresAll))] // https://github.com/dotnet/linker/issues/2746 (ILLink produces incomplete set of IL2072 warnings) - [ExpectedWarning ("IL2072", nameof (GetUnknownType), nameof (DataFlowTypeExtensions.RequiresAll), - ProducedBy = Tool.Analyzer)] - [ExpectedWarning ("IL2072", nameof (GetTypeWithPublicConstructors), nameof (DataFlowTypeExtensions.RequiresAll), - ProducedBy = Tool.Analyzer)] + [ExpectedWarning ("IL2072", nameof (GetUnknownType), nameof (DataFlowTypeExtensions.RequiresAll), Tool.Analyzer, "")] + [ExpectedWarning ("IL2072", nameof (GetTypeWithPublicConstructors), nameof (DataFlowTypeExtensions.RequiresAll), Tool.Analyzer, "")] static void TestNullCoalescingAssignmentComplex () { Type[] arr = new Type[1]; @@ -702,7 +687,7 @@ static void TestNullCoalesce (bool b = false) arr2[0].RequiresPublicFields (); } - [ExpectedWarning ("IL2087", nameof (T), nameof (DataFlowTypeExtensions.RequiresAll), ProducedBy = Tool.Analyzer)] + [ExpectedWarning ("IL2087", [nameof (T), nameof (DataFlowTypeExtensions.RequiresAll)], Tool.Analyzer, "")] [ExpectedWarning ("IL2087", nameof (U), nameof (DataFlowTypeExtensions.RequiresPublicFields))] // Missing warnings for 'V' possibly assigned to arr or arr2 because write to temp // array isn't reflected back in the local variables. https://github.com/dotnet/linker/issues/2158 @@ -710,8 +695,8 @@ static void TestNullCoalesce (bool b = false) // possible assignment of arr2 to arr, without overwriting index '0'. And it produces a warning // for each possible value, unlike ILLink/ILCompiler, which produce an unknown value for a merged // array value: https://github.com/dotnet/runtime/issues/93416 - [ExpectedWarning ("IL2087", nameof (U), nameof (DataFlowTypeExtensions.RequiresAll), ProducedBy = Tool.Analyzer)] - [ExpectedWarning ("IL2062", nameof (DataFlowTypeExtensions.RequiresAll), ProducedBy = Tool.Trimmer | Tool.NativeAot)] + [ExpectedWarning ("IL2087", [nameof (U), nameof (DataFlowTypeExtensions.RequiresAll)], Tool.Analyzer, "")] + [ExpectedWarning ("IL2062", nameof (DataFlowTypeExtensions.RequiresAll), Tool.Trimmer | Tool.NativeAot, "")] static void TestNullCoalescingAssignment (bool b = true) { Type[]? arr = new Type[1] { typeof (T) }; diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/AssemblyQualifiedNameDataflow.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/AssemblyQualifiedNameDataflow.cs index f2c0f5185f5cf2..c6dbd60598c608 100644 --- a/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/AssemblyQualifiedNameDataflow.cs +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/AssemblyQualifiedNameDataflow.cs @@ -58,10 +58,7 @@ static void TestConstructors () RequireNothing (type); } - [ExpectedWarning ("IL2105", - "Type 'System.Invalid.TypeName' was not found in the caller assembly nor in the base library. " + - "Type name strings used for dynamically accessing a type should be assembly qualified.", - ProducedBy = Tool.Trimmer | Tool.NativeAot)] + [ExpectedWarning ("IL2105", "Type 'System.Invalid.TypeName' was not found in the caller assembly nor in the base library. " + "Type name strings used for dynamically accessing a type should be assembly qualified.", Tool.Trimmer | Tool.NativeAot, "")] static void TestUnqualifiedTypeNameWarns () { RequirePublicConstructors ("System.Invalid.TypeName"); diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/AttributeConstructorDataflow.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/AttributeConstructorDataflow.cs index 4611e06773df85..5f54d6dd471262 100644 --- a/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/AttributeConstructorDataflow.cs +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/AttributeConstructorDataflow.cs @@ -9,7 +9,7 @@ [assembly: KeptAttributeAttribute (typeof (AttributeConstructorDataflow.KeepsPublicPropertiesAttribute))] // https://github.com/dotnet/linker/issues/2273 -[assembly: ExpectedWarning ("IL2026", "--ClassWithKeptPublicProperties--", ProducedBy = Tool.Trimmer | Tool.NativeAot)] +[assembly: ExpectedWarning ("IL2026", "--ClassWithKeptPublicProperties--", Tool.Trimmer | Tool.NativeAot, "")] [assembly: AttributeConstructorDataflow.KeepsPublicProperties (typeof (AttributeConstructorDataflow.ClassWithKeptPublicProperties))] namespace Mono.Linker.Tests.Cases.DataFlow @@ -27,7 +27,7 @@ class AttributeConstructorDataflow [KeepsPublicFields (null, null)] [TypeArray (new Type[] { typeof (AttributeConstructorDataflow) })] // https://github.com/dotnet/linker/issues/2273 - [ExpectedWarning ("IL2026", "--ClassWithKeptPublicMethods--", ProducedBy = Tool.Trimmer | Tool.NativeAot)] + [ExpectedWarning ("IL2026", "--ClassWithKeptPublicMethods--", Tool.Trimmer | Tool.NativeAot, "")] public static void Main () { typeof (AttributeConstructorDataflow).GetMethod ("Main").GetCustomAttribute (typeof (KeepsPublicConstructorAttribute)); diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/AttributeFieldDataflow.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/AttributeFieldDataflow.cs index e581797e234742..4807f7c039771d 100644 --- a/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/AttributeFieldDataflow.cs +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/AttributeFieldDataflow.cs @@ -41,7 +41,7 @@ public static void TestKeepsPublicMethods () [Kept] [KeptAttributeAttribute (typeof (KeepsPublicMethodsAttribute))] // Trimmer/NativeAot only for now - https://github.com/dotnet/linker/issues/2273 - [ExpectedWarning ("IL2026", "--ClassWithKeptPublicMethods--", ProducedBy = Tool.Trimmer | Tool.NativeAot)] + [ExpectedWarning ("IL2026", "--ClassWithKeptPublicMethods--", Tool.Trimmer | Tool.NativeAot, "")] [KeepsPublicMethods (TypeName = "Mono.Linker.Tests.Cases.DataFlow.AttributeFieldDataflow+ClassWithKeptPublicMethods")] public static void TestKeepsPublicMethodsString () { diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/AttributePropertyDataflow.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/AttributePropertyDataflow.cs index f953784dc37537..a6c254a00ab4c4 100644 --- a/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/AttributePropertyDataflow.cs +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/AttributePropertyDataflow.cs @@ -56,7 +56,7 @@ public static void TestKeepsPublicMethods () [Kept] [KeptAttributeAttribute (typeof (KeepsPublicMethodsAttribute))] // Trimmer/NativeAot only for now - https://github.com/dotnet/runtime/issues/95118 - [ExpectedWarning ("IL2026", "--ClassWithKeptPublicMethodsKeptByName--", ProducedBy = Tool.Trimmer | Tool.NativeAot)] + [ExpectedWarning ("IL2026", "--ClassWithKeptPublicMethodsKeptByName--", Tool.Trimmer | Tool.NativeAot, "")] [KeepsPublicMethods (TypeName = "Mono.Linker.Tests.Cases.DataFlow.AttributePropertyDataflow+AttributesOnMethod+ClassWithKeptPublicMethodsKeptByName")] public static void TestKeepsPublicMethodsByName () { @@ -212,7 +212,7 @@ class AttributeWithConditionalExpression [Kept] [KeptAttributeAttribute (typeof (KeepsPublicMethodsAttribute))] // Trimmer/NativeAot only for now - https://github.com/dotnet/linker/issues/2273 - [ExpectedWarning ("IL2026", "--ClassWithKeptPublicMethods--", ProducedBy = Tool.Trimmer | Tool.NativeAot)] + [ExpectedWarning ("IL2026", "--ClassWithKeptPublicMethods--", Tool.Trimmer | Tool.NativeAot, "")] [KeepsPublicMethods (TypeName = 1 + 1 == 2 ? "Mono.Linker.Tests.Cases.DataFlow.AttributePropertyDataflow+AttributeWithConditionalExpression+ClassWithKeptPublicMethods" : null)] public static void Test () { @@ -224,7 +224,7 @@ public static void Test () // where the owning symbol is not a method. [Kept] [KeptAttributeAttribute (typeof (KeepsPublicMethodsAttribute))] - [ExpectedWarning ("IL2026", "--ClassWithKeptPublicMethods--", ProducedBy = Tool.Trimmer | Tool.NativeAot)] + [ExpectedWarning ("IL2026", "--ClassWithKeptPublicMethods--", Tool.Trimmer | Tool.NativeAot, "")] [KeepsPublicMethods (TypeName = 1 + 1 == 2 ? "Mono.Linker.Tests.Cases.DataFlow.AttributePropertyDataflow+AttributeWithConditionalExpression+ClassWithKeptPublicMethods" : null)] public static int field; diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/ByRefDataflow.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/ByRefDataflow.cs index d00af37b2bebb1..08cb41710cb151 100644 --- a/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/ByRefDataflow.cs +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/ByRefDataflow.cs @@ -46,12 +46,12 @@ public static void Main () [Kept] // Trimmer and analyzer use different formats for ref parameters: https://github.com/dotnet/linker/issues/2406 - [ExpectedWarning ("IL2077", nameof (ByRefDataflow) + "." + nameof (MethodWithRefParameter) + "(Type&)", ProducedBy = Tool.Trimmer | Tool.NativeAot)] - [ExpectedWarning ("IL2077", nameof (ByRefDataflow) + "." + nameof (MethodWithRefParameter) + "(ref Type)", ProducedBy = Tool.Analyzer)] - [ExpectedWarning ("IL2069", nameof (s_typeWithPublicParameterlessConstructor), "parameter 'type'", nameof (MethodWithRefParameter), ProducedBy = Tool.Trimmer | Tool.NativeAot)] + [ExpectedWarning ("IL2077", nameof (ByRefDataflow) + "." + nameof (MethodWithRefParameter) + "(Type&)", Tool.Trimmer | Tool.NativeAot, "")] + [ExpectedWarning ("IL2077", nameof (ByRefDataflow) + "." + nameof (MethodWithRefParameter) + "(ref Type)", Tool.Analyzer, "")] + [ExpectedWarning ("IL2069", [nameof (s_typeWithPublicParameterlessConstructor), "parameter 'type'", nameof (MethodWithRefParameter)], Tool.Trimmer | Tool.NativeAot, "")] // MethodWithRefParameter (ref x) - [ExpectedWarning ("IL2077", nameof (ByRefDataflow) + "." + nameof (MethodWithRefParameter) + "(Type&)", ProducedBy = Tool.Trimmer | Tool.NativeAot)] - [ExpectedWarning ("IL2077", nameof (ByRefDataflow) + "." + nameof (MethodWithRefParameter) + "(ref Type)", ProducedBy = Tool.Analyzer)] + [ExpectedWarning ("IL2077", nameof (ByRefDataflow) + "." + nameof (MethodWithRefParameter) + "(Type&)", Tool.Trimmer | Tool.NativeAot, "")] + [ExpectedWarning ("IL2077", nameof (ByRefDataflow) + "." + nameof (MethodWithRefParameter) + "(ref Type)", Tool.Analyzer, "")] public static void PassRefToField () { MethodWithRefParameter (ref s_typeWithPublicParameterlessConstructor); @@ -61,8 +61,8 @@ public static void PassRefToField () [Kept] // Trimmer and analyzer use different formats for ref parameters: https://github.com/dotnet/linker/issues/2406 - [ExpectedWarning ("IL2067", nameof (ByRefDataflow) + "." + nameof (MethodWithRefParameter) + "(Type&)", ProducedBy = Tool.Trimmer | Tool.NativeAot)] - [ExpectedWarning ("IL2067", nameof (ByRefDataflow) + "." + nameof (MethodWithRefParameter) + "(ref Type)", ProducedBy = Tool.Analyzer)] + [ExpectedWarning ("IL2067", nameof (ByRefDataflow) + "." + nameof (MethodWithRefParameter) + "(Type&)", Tool.Trimmer | Tool.NativeAot, "")] + [ExpectedWarning ("IL2067", nameof (ByRefDataflow) + "." + nameof (MethodWithRefParameter) + "(ref Type)", Tool.Analyzer, "")] public static void PassRefToParameter (Type parameter) { MethodWithRefParameter (ref parameter); @@ -182,8 +182,8 @@ static void TwoOutRefs ( [Kept] // https://github.com/dotnet/runtime/issues/85464 - [ExpectedWarning ("IL2069", ProducedBy = Tool.Trimmer | Tool.NativeAot)] - [ExpectedWarning ("IL2069", ProducedBy = Tool.Trimmer | Tool.NativeAot)] + [ExpectedWarning ("IL2069", Tool.Trimmer | Tool.NativeAot, "")] + [ExpectedWarning ("IL2069", Tool.Trimmer | Tool.NativeAot, "")] public static void Test () { TwoOutRefs (out _publicMethodsField, out _publicPropertiesField); @@ -243,13 +243,13 @@ static void TestLocalAssignment (bool b = true) } [Kept] - [ExpectedWarning ("IL2072", nameof (GetUnknownType), nameof (DataFlowTypeExtensions.RequiresAll), ProducedBy = Tool.Analyzer)] - [ExpectedWarning ("IL2072", nameof (GetTypeWithPublicConstructors), nameof (DataFlowTypeExtensions.RequiresAll), ProducedBy = Tool.Analyzer)] - [ExpectedWarning ("IL2072", nameof (GetTypeWithPublicFields), nameof (DataFlowTypeExtensions.RequiresAll), ProducedBy = Tool.Analyzer)] - [ExpectedWarning ("IL2072", nameof (GetTypeWithPublicFields), nameof (DataFlowTypeExtensions.RequiresAll), ProducedBy = Tool.Analyzer)] + [ExpectedWarning ("IL2072", [nameof (GetUnknownType), nameof (DataFlowTypeExtensions.RequiresAll)], Tool.Analyzer, "")] + [ExpectedWarning ("IL2072", [nameof (GetTypeWithPublicConstructors), nameof (DataFlowTypeExtensions.RequiresAll)], Tool.Analyzer, "")] + [ExpectedWarning ("IL2072", [nameof (GetTypeWithPublicFields), nameof (DataFlowTypeExtensions.RequiresAll)], Tool.Analyzer, "")] + [ExpectedWarning ("IL2072", [nameof (GetTypeWithPublicFields), nameof (DataFlowTypeExtensions.RequiresAll)], Tool.Analyzer, "")] // ILLink/ILCompiler produce different warning code: https://github.com/dotnet/linker/issues/2737 - [ExpectedWarning ("IL2062", nameof (DataFlowTypeExtensions.RequiresAll), ProducedBy = Tool.Trimmer | Tool.NativeAot)] - [ExpectedWarning ("IL2062", nameof (DataFlowTypeExtensions.RequiresAll), ProducedBy = Tool.Trimmer | Tool.NativeAot)] + [ExpectedWarning ("IL2062", nameof (DataFlowTypeExtensions.RequiresAll), Tool.Trimmer | Tool.NativeAot, "")] + [ExpectedWarning ("IL2062", nameof (DataFlowTypeExtensions.RequiresAll), Tool.Trimmer | Tool.NativeAot, "")] static void TestArrayElementReferenceAssignment (bool b = true) { var arr1 = new Type[] { GetUnknownType () }; diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/CompilerGeneratedCodeAccessedViaReflection.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/CompilerGeneratedCodeAccessedViaReflection.cs index cb609bc5906025..17924d0f3a2437 100644 --- a/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/CompilerGeneratedCodeAccessedViaReflection.cs +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/CompilerGeneratedCodeAccessedViaReflection.cs @@ -39,10 +39,8 @@ public static IEnumerable BaseIteratorWithCorrectDataflow () } } - [ExpectedWarning ("IL2120", "<" + nameof (BaseIteratorWithCorrectDataflow) + ">", "MoveNext", - ProducedBy = Tool.Trimmer)] - [ExpectedWarning ("IL2120", "<" + nameof (BaseIteratorWithCorrectDataflow) + ">", "", - ProducedBy = Tool.Trimmer)] + [ExpectedWarning ("IL2120", ["<" + nameof (BaseIteratorWithCorrectDataflow) + ">", "MoveNext"], Tool.Trimmer, "")] + [ExpectedWarning ("IL2120", ["<" + nameof (BaseIteratorWithCorrectDataflow) + ">", ""], Tool.Trimmer, "")] [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.All)] class IteratorStateMachines : BaseTypeWithIteratorStateMachines { @@ -52,22 +50,17 @@ public static IEnumerable IteratorWithoutDataflow () } [ExpectedWarning ("IL2026", "--MethodWithRequires--", CompilerGeneratedCode = true)] - [ExpectedWarning ("IL3002", "--MethodWithRequires--", - ProducedBy = Tool.Analyzer | Tool.NativeAot, CompilerGeneratedCode = true)] - [ExpectedWarning ("IL3050", "--MethodWithRequires--", - ProducedBy = Tool.Analyzer | Tool.NativeAot, CompilerGeneratedCode = true)] - [ExpectedWarning ("IL2119", "<" + nameof (IteratorCallsMethodWithRequires) + ">", "MoveNext", CompilerGeneratedCode = true, - ProducedBy = Tool.Trimmer)] + [ExpectedWarning ("IL3002", "--MethodWithRequires--", Tool.Analyzer | Tool.NativeAot, "", CompilerGeneratedCode = true)] + [ExpectedWarning ("IL3050", "--MethodWithRequires--", Tool.Analyzer | Tool.NativeAot, "", CompilerGeneratedCode = true)] + [ExpectedWarning ("IL2119", "<" + nameof (IteratorCallsMethodWithRequires) + ">", "MoveNext", Tool.Trimmer, "", CompilerGeneratedCode = true)] public static IEnumerable IteratorCallsMethodWithRequires () { yield return 0; MethodWithRequires (); } - [ExpectedWarning ("IL2119", "<" + nameof (IteratorWithCorrectDataflow) + ">", "MoveNext", CompilerGeneratedCode = true, - ProducedBy = Tool.Trimmer)] - [ExpectedWarning ("IL2119", "", CompilerGeneratedCode = true, - ProducedBy = Tool.Trimmer)] + [ExpectedWarning ("IL2119", "<" + nameof (IteratorWithCorrectDataflow) + ">", "MoveNext", Tool.Trimmer, "", CompilerGeneratedCode = true)] + [ExpectedWarning ("IL2119", "", Tool.Trimmer, "", CompilerGeneratedCode = true)] public static IEnumerable IteratorWithCorrectDataflow () { var t_IteratorWithCorrectDataflow = GetAll (); @@ -75,10 +68,8 @@ public static IEnumerable IteratorWithCorrectDataflow () t_IteratorWithCorrectDataflow.RequiresAll (); } - [ExpectedWarning ("IL2119", "<" + nameof (IteratorWithIntegerDataflow) + ">", "MoveNext", CompilerGeneratedCode = true, - ProducedBy = Tool.Trimmer)] - [ExpectedWarning ("IL2119", "", CompilerGeneratedCode = true, - ProducedBy = Tool.Trimmer)] + [ExpectedWarning ("IL2119", "<" + nameof (IteratorWithIntegerDataflow) + ">", "MoveNext", Tool.Trimmer, "", CompilerGeneratedCode = true)] + [ExpectedWarning ("IL2119", "", Tool.Trimmer, "", CompilerGeneratedCode = true)] public static IEnumerable IteratorWithIntegerDataflow () { int integerLocal = 0; @@ -87,10 +78,8 @@ public static IEnumerable IteratorWithIntegerDataflow () types[integerLocal].RequiresPublicMethods (); } - [ExpectedWarning ("IL2119", "<" + nameof (IteratorWithProblematicDataflow) + ">", "MoveNext", CompilerGeneratedCode = true, - ProducedBy = Tool.Trimmer)] - [ExpectedWarning ("IL2119", "", CompilerGeneratedCode = true, - ProducedBy = Tool.Trimmer)] + [ExpectedWarning ("IL2119", "<" + nameof (IteratorWithProblematicDataflow) + ">", "MoveNext", Tool.Trimmer, "", CompilerGeneratedCode = true)] + [ExpectedWarning ("IL2119", "", Tool.Trimmer, "", CompilerGeneratedCode = true)] [ExpectedWarning ("IL2072", nameof (GetWithPublicMethods), nameof (DataFlowTypeExtensions.RequiresAll), CompilerGeneratedCode = true)] public static IEnumerable IteratorWithProblematicDataflow () { @@ -99,25 +88,22 @@ public static IEnumerable IteratorWithProblematicDataflow () t_IteratorWithProblematicDataflow.RequiresAll (); } - [ExpectedWarning ("IL2112", nameof (RUCTypeWithIterators) + "()", "--RUCTypeWithIterators--", CompilerGeneratedCode = true, - ProducedBy = Tool.Trimmer | Tool.NativeAot)] // warning about .ctor + [ExpectedWarning ("IL2112", nameof (RUCTypeWithIterators) + "()", "--RUCTypeWithIterators--", Tool.Trimmer | Tool.NativeAot, "", CompilerGeneratedCode = true)] // warning about .ctor [RequiresUnreferencedCode ("--RUCTypeWithIterators--")] class RUCTypeWithIterators { - [ExpectedWarning ("IL2112", nameof (StaticIteratorCallsMethodWithRequires) + "()", - ProducedBy = Tool.Trimmer | Tool.NativeAot)] - [ExpectedWarning ("IL3002", "--MethodWithRequires--", ProducedBy = Tool.Analyzer | Tool.NativeAot, CompilerGeneratedCode = true)] - [ExpectedWarning ("IL3050", "--MethodWithRequires--", ProducedBy = Tool.Analyzer | Tool.NativeAot, CompilerGeneratedCode = true)] + [ExpectedWarning ("IL2112", nameof (StaticIteratorCallsMethodWithRequires) + "()", Tool.Trimmer | Tool.NativeAot, "")] + [ExpectedWarning ("IL3002", "--MethodWithRequires--", Tool.Analyzer | Tool.NativeAot, "", CompilerGeneratedCode = true)] + [ExpectedWarning ("IL3050", "--MethodWithRequires--", Tool.Analyzer | Tool.NativeAot, "", CompilerGeneratedCode = true)] public static IEnumerable StaticIteratorCallsMethodWithRequires () { yield return 0; MethodWithRequires (); } - [ExpectedWarning ("IL2112", nameof (InstanceIteratorCallsMethodWithRequires) + "()", - ProducedBy = Tool.Trimmer | Tool.NativeAot)] - [ExpectedWarning ("IL3002", "--MethodWithRequires--", ProducedBy = Tool.Analyzer | Tool.NativeAot, CompilerGeneratedCode = true)] - [ExpectedWarning ("IL3050", "--MethodWithRequires--", ProducedBy = Tool.Analyzer | Tool.NativeAot, CompilerGeneratedCode = true)] + [ExpectedWarning ("IL2112", nameof (InstanceIteratorCallsMethodWithRequires) + "()", Tool.Trimmer | Tool.NativeAot, "")] + [ExpectedWarning ("IL3002", "--MethodWithRequires--", Tool.Analyzer | Tool.NativeAot, "", CompilerGeneratedCode = true)] + [ExpectedWarning ("IL3050", "--MethodWithRequires--", Tool.Analyzer | Tool.NativeAot, "", CompilerGeneratedCode = true)] public IEnumerable InstanceIteratorCallsMethodWithRequires () { yield return 0; @@ -125,32 +111,23 @@ public IEnumerable InstanceIteratorCallsMethodWithRequires () } } - [ExpectedWarning ("IL2118", "<" + nameof (IteratorWithProblematicDataflow) + ">", "MoveNext", - ProducedBy = Tool.Trimmer)] - [ExpectedWarning ("IL2118", "<" + nameof (IteratorCallsMethodWithRequires) + ">", "MoveNext", - ProducedBy = Tool.Trimmer)] - [ExpectedWarning ("IL2118", "<" + nameof (IteratorWithCorrectDataflow) + ">", "MoveNext", - ProducedBy = Tool.Trimmer)] - [ExpectedWarning ("IL2118", "<" + nameof (IteratorWithIntegerDataflow) + ">", "MoveNext", - ProducedBy = Tool.Trimmer)] - [ExpectedWarning ("IL2118", "<" + nameof (BaseIteratorWithCorrectDataflow) + ">", "MoveNext", - ProducedBy = Tool.Trimmer)] + [ExpectedWarning ("IL2118", "<" + nameof (IteratorWithProblematicDataflow) + ">", "MoveNext", Tool.Trimmer, "")] + [ExpectedWarning ("IL2118", "<" + nameof (IteratorCallsMethodWithRequires) + ">", "MoveNext", Tool.Trimmer, "")] + [ExpectedWarning ("IL2118", "<" + nameof (IteratorWithCorrectDataflow) + ">", "MoveNext", Tool.Trimmer, "")] + [ExpectedWarning ("IL2118", "<" + nameof (IteratorWithIntegerDataflow) + ">", "MoveNext", Tool.Trimmer, "")] + [ExpectedWarning ("IL2118", "<" + nameof (BaseIteratorWithCorrectDataflow) + ">", "MoveNext", Tool.Trimmer, "")] [ExpectedWarning ("IL2026", nameof (RUCTypeWithIterators) + "()", "--RUCTypeWithIterators--")] // Expect to see warnings about RUC on type, for all static state machine members. [ExpectedWarning ("IL2026", nameof (RUCTypeWithIterators.StaticIteratorCallsMethodWithRequires) + "()", "--RUCTypeWithIterators--")] [ExpectedWarning ("IL2026", nameof (RUCTypeWithIterators.InstanceIteratorCallsMethodWithRequires) + "()")] - [ExpectedWarning ("IL2118", "<" + nameof (IteratorWithCorrectDataflow) + ">", "", - ProducedBy = Tool.Trimmer)] - [ExpectedWarning ("IL2118", "<" + nameof (IteratorWithProblematicDataflow) + ">", "", - ProducedBy = Tool.Trimmer)] + [ExpectedWarning ("IL2118", "<" + nameof (IteratorWithCorrectDataflow) + ">", "", Tool.Trimmer, "")] + [ExpectedWarning ("IL2118", "<" + nameof (IteratorWithProblematicDataflow) + ">", "", Tool.Trimmer, "")] // Technically the access to IteratorWithIntegerDataflow should warn about access to the integer // field integerLocal, but our heuristics only warn if the field type satisfies the // "IsTypeInterestingForDatafllow" check. This is likely good enough because in most cases the // compiler-generated code will have other hoisted fields with types that _are_ interesting for dataflow. - [ExpectedWarning ("IL2118", "<" + nameof (IteratorWithIntegerDataflow) + ">", "", - ProducedBy = Tool.Trimmer)] - [ExpectedWarning ("IL2118", "<" + nameof (BaseIteratorWithCorrectDataflow) + ">", "", - ProducedBy = Tool.Trimmer)] + [ExpectedWarning ("IL2118", "<" + nameof (IteratorWithIntegerDataflow) + ">", "", Tool.Trimmer, "")] + [ExpectedWarning ("IL2118", "<" + nameof (BaseIteratorWithCorrectDataflow) + ">", "", Tool.Trimmer, "")] public static void Test (IteratorStateMachines test = null) { typeof (IteratorStateMachines).RequiresAll (); @@ -166,8 +143,8 @@ public static async Task AsyncWithoutDataflow () } [ExpectedWarning ("IL2026", "--MethodWithRequires--", CompilerGeneratedCode = true)] - [ExpectedWarning ("IL3002", "--MethodWithRequires--", ProducedBy = Tool.Analyzer | Tool.NativeAot, CompilerGeneratedCode = true)] - [ExpectedWarning ("IL3050", "--MethodWithRequires--", ProducedBy = Tool.Analyzer | Tool.NativeAot, CompilerGeneratedCode = true)] + [ExpectedWarning ("IL3002", "--MethodWithRequires--", Tool.Analyzer | Tool.NativeAot, "", CompilerGeneratedCode = true)] + [ExpectedWarning ("IL3050", "--MethodWithRequires--", Tool.Analyzer | Tool.NativeAot, "", CompilerGeneratedCode = true)] public static async Task AsyncCallsMethodWithRequires () { MethodWithRequires (); @@ -186,16 +163,11 @@ public static async Task AsyncWithProblematicDataflow () t_AsyncWithProblematicDataflow.RequiresAll (); } - [ExpectedWarning ("IL2118", "<" + nameof (AsyncWithProblematicDataflow) + ">", "MoveNext", - ProducedBy = Tool.Trimmer)] - [ExpectedWarning ("IL2118", "<" + nameof (AsyncCallsMethodWithRequires) + ">", "MoveNext", - ProducedBy = Tool.Trimmer)] - [ExpectedWarning ("IL2118", "<" + nameof (AsyncWithCorrectDataflow) + ">", "MoveNext", - ProducedBy = Tool.Trimmer)] - [ExpectedWarning ("IL2118", "<" + nameof (AsyncWithCorrectDataflow) + ">", "", - ProducedBy = Tool.Trimmer)] - [ExpectedWarning ("IL2118", "<" + nameof (AsyncWithProblematicDataflow) + ">", "", - ProducedBy = Tool.Trimmer)] + [ExpectedWarning ("IL2118", "<" + nameof (AsyncWithProblematicDataflow) + ">", "MoveNext", Tool.Trimmer, "")] + [ExpectedWarning ("IL2118", "<" + nameof (AsyncCallsMethodWithRequires) + ">", "MoveNext", Tool.Trimmer, "")] + [ExpectedWarning ("IL2118", "<" + nameof (AsyncWithCorrectDataflow) + ">", "MoveNext", Tool.Trimmer, "")] + [ExpectedWarning ("IL2118", "<" + nameof (AsyncWithCorrectDataflow) + ">", "", Tool.Trimmer, "")] + [ExpectedWarning ("IL2118", "<" + nameof (AsyncWithProblematicDataflow) + ">", "", Tool.Trimmer, "")] public static void Test () { typeof (AsyncStateMachines).RequiresAll (); @@ -210,8 +182,8 @@ public static async IAsyncEnumerable AsyncIteratorWithoutDataflow () } [ExpectedWarning ("IL2026", "--MethodWithRequires--", CompilerGeneratedCode = true)] - [ExpectedWarning ("IL3002", "--MethodWithRequires--", ProducedBy = Tool.Analyzer | Tool.NativeAot, CompilerGeneratedCode = true)] - [ExpectedWarning ("IL3050", "--MethodWithRequires--", ProducedBy = Tool.Analyzer | Tool.NativeAot, CompilerGeneratedCode = true)] + [ExpectedWarning ("IL3002", "--MethodWithRequires--", Tool.Analyzer | Tool.NativeAot, "", CompilerGeneratedCode = true)] + [ExpectedWarning ("IL3050", "--MethodWithRequires--", Tool.Analyzer | Tool.NativeAot, "", CompilerGeneratedCode = true)] public static async IAsyncEnumerable AsyncIteratorCallsMethodWithRequires () { yield return await MethodAsync (); @@ -233,16 +205,11 @@ public static async IAsyncEnumerable AsyncIteratorWithProblematicDataflow ( t.RequiresAll (); } - [ExpectedWarning ("IL2118", "<" + nameof (AsyncIteratorWithProblematicDataflow) + ">", "MoveNext", - ProducedBy = Tool.Trimmer)] - [ExpectedWarning ("IL2118", "<" + nameof (AsyncIteratorCallsMethodWithRequires) + ">", "MoveNext", - ProducedBy = Tool.Trimmer)] - [ExpectedWarning ("IL2118", "<" + nameof (AsyncIteratorWithCorrectDataflow) + ">", "MoveNext", - ProducedBy = Tool.Trimmer)] - [ExpectedWarning ("IL2118", "<" + nameof (AsyncIteratorWithCorrectDataflow) + ">", "", - ProducedBy = Tool.Trimmer)] - [ExpectedWarning ("IL2118", "<" + nameof (AsyncIteratorWithProblematicDataflow) + ">", "", - ProducedBy = Tool.Trimmer)] + [ExpectedWarning ("IL2118", "<" + nameof (AsyncIteratorWithProblematicDataflow) + ">", "MoveNext", Tool.Trimmer, "")] + [ExpectedWarning ("IL2118", "<" + nameof (AsyncIteratorCallsMethodWithRequires) + ">", "MoveNext", Tool.Trimmer, "")] + [ExpectedWarning ("IL2118", "<" + nameof (AsyncIteratorWithCorrectDataflow) + ">", "MoveNext", Tool.Trimmer, "")] + [ExpectedWarning ("IL2118", "<" + nameof (AsyncIteratorWithCorrectDataflow) + ">", "", Tool.Trimmer, "")] + [ExpectedWarning ("IL2118", "<" + nameof (AsyncIteratorWithProblematicDataflow) + ">", "", Tool.Trimmer, "")] public static void Test () { typeof (AsyncIteratorStateMachines).RequiresAll (); @@ -262,10 +229,9 @@ static void LambdaCallsMethodWithRequires () { var lambda = [ExpectedWarning ("IL2026", "--MethodWithRequires--")] - [ExpectedWarning ("IL3002", "--MethodWithRequires--", ProducedBy = Tool.Analyzer | Tool.NativeAot)] - [ExpectedWarning ("IL3050", "--MethodWithRequires--", ProducedBy = Tool.Analyzer | Tool.NativeAot)] - [ExpectedWarning ("IL2119", "<" + nameof (LambdaCallsMethodWithRequires) + ">", - ProducedBy = Tool.Trimmer)] + [ExpectedWarning ("IL3002", "--MethodWithRequires--", Tool.Analyzer | Tool.NativeAot, "")] + [ExpectedWarning ("IL3050", "--MethodWithRequires--", Tool.Analyzer | Tool.NativeAot, "")] + [ExpectedWarning ("IL2119", "<" + nameof (LambdaCallsMethodWithRequires) + ">", Tool.Trimmer, "")] () => MethodWithRequires (); lambda (); } @@ -273,8 +239,7 @@ static void LambdaCallsMethodWithRequires () static void LambdaWithCorrectDataflow () { var lambda = - [ExpectedWarning ("IL2119", "<" + nameof (LambdaWithCorrectDataflow) + ">", - ProducedBy = Tool.Trimmer)] + [ExpectedWarning ("IL2119", "<" + nameof (LambdaWithCorrectDataflow) + ">", Tool.Trimmer, "")] () => { var t = GetAll (); t.RequiresAll (); @@ -295,8 +260,7 @@ static void LambdaWithCorrectParameter () static void LambdaWithProblematicDataflow () { var lambda = - [ExpectedWarning ("IL2119", "<" + nameof (LambdaWithProblematicDataflow) + ">", - ProducedBy = Tool.Trimmer)] + [ExpectedWarning ("IL2119", "<" + nameof (LambdaWithProblematicDataflow) + ">", Tool.Trimmer, "")] [ExpectedWarning ("IL2072", nameof (DataFlowTypeExtensions.RequiresAll))] () => { var t = GetWithPublicMethods (); @@ -309,8 +273,7 @@ static void LambdaWithCapturedTypeToDAM () { var t = GetWithPublicMethods (); var lambda = - [ExpectedWarning ("IL2119", "<" + nameof (LambdaWithCapturedTypeToDAM) + ">", - ProducedBy = Tool.Trimmer)] + [ExpectedWarning ("IL2119", "<" + nameof (LambdaWithCapturedTypeToDAM) + ">", Tool.Trimmer, "")] [ExpectedWarning ("IL2072", nameof (GetWithPublicMethods), nameof (DataFlowTypeExtensions.RequiresAll))] () => { t.RequiresAll (); @@ -337,29 +300,27 @@ static void LambdaCallsPInvokeTakingObject () { var lambda = [ExpectedWarning ("IL2050")] - [ExpectedWarning ("IL2119", "<" + nameof (LambdaCallsPInvokeTakingObject) + ">", - ProducedBy = Tool.Trimmer)] + [ExpectedWarning ("IL2119", "<" + nameof (LambdaCallsPInvokeTakingObject) + ">", Tool.Trimmer, "")] () => MethodTakingObject (null); lambda (); } - [ExpectedWarning ("IL2112", nameof (RUCTypeWithLambdas) + "()", "--RUCTypeWithLambdas--", CompilerGeneratedCode = true, - ProducedBy = Tool.Trimmer | Tool.NativeAot)] + [ExpectedWarning ("IL2112", nameof (RUCTypeWithLambdas) + "()", "--RUCTypeWithLambdas--", Tool.Trimmer | Tool.NativeAot, "", CompilerGeneratedCode = true)] [RequiresUnreferencedCode ("--RUCTypeWithLambdas--")] class RUCTypeWithLambdas { - [ExpectedWarning ("IL2112", nameof (MethodWithLambdas), "--RUCTypeWithLambdas--", ProducedBy = Tool.Trimmer | Tool.NativeAot)] + [ExpectedWarning ("IL2112", [nameof (MethodWithLambdas), "--RUCTypeWithLambdas--"], Tool.Trimmer | Tool.NativeAot, "")] public void MethodWithLambdas () { var lambda = - [ExpectedWarning ("IL3002", "--MethodWithRequires--", ProducedBy = Tool.Analyzer | Tool.NativeAot)] - [ExpectedWarning ("IL3050", "--MethodWithRequires--", ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3002", "--MethodWithRequires--", Tool.Analyzer | Tool.NativeAot, "")] + [ExpectedWarning ("IL3050", "--MethodWithRequires--", Tool.Analyzer | Tool.NativeAot, "")] () => MethodWithRequires (); int i = 0; var lambdaWithCapturedState = - [ExpectedWarning ("IL3002", "--MethodWithRequires--", ProducedBy = Tool.Analyzer | Tool.NativeAot)] - [ExpectedWarning ("IL3050", "--MethodWithRequires--", ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3002", "--MethodWithRequires--", Tool.Analyzer | Tool.NativeAot, "")] + [ExpectedWarning ("IL3050", "--MethodWithRequires--", Tool.Analyzer | Tool.NativeAot, "")] () => { i++; MethodWithRequires (); @@ -370,16 +331,11 @@ public void MethodWithLambdas () } } - [ExpectedWarning ("IL2118", "<" + nameof (LambdaCallsPInvokeTakingObject) + ">", - ProducedBy = Tool.Trimmer)] - [ExpectedWarning ("IL2118", "<" + nameof (LambdaCallsMethodWithRequires) + ">", - ProducedBy = Tool.Trimmer)] - [ExpectedWarning ("IL2118", "<" + nameof (LambdaWithCorrectDataflow) + ">", - ProducedBy = Tool.Trimmer)] - [ExpectedWarning ("IL2118", "<" + nameof (LambdaWithProblematicDataflow) + ">", - ProducedBy = Tool.Trimmer)] - [ExpectedWarning ("IL2118", "<" + nameof (LambdaWithCapturedTypeToDAM) + ">", - ProducedBy = Tool.Trimmer)] + [ExpectedWarning ("IL2118", "<" + nameof (LambdaCallsPInvokeTakingObject) + ">", Tool.Trimmer, "")] + [ExpectedWarning ("IL2118", "<" + nameof (LambdaCallsMethodWithRequires) + ">", Tool.Trimmer, "")] + [ExpectedWarning ("IL2118", "<" + nameof (LambdaWithCorrectDataflow) + ">", Tool.Trimmer, "")] + [ExpectedWarning ("IL2118", "<" + nameof (LambdaWithProblematicDataflow) + ">", Tool.Trimmer, "")] + [ExpectedWarning ("IL2118", "<" + nameof (LambdaWithCapturedTypeToDAM) + ">", Tool.Trimmer, "")] [ExpectedWarning ("IL2026", nameof (RUCTypeWithLambdas) + "()", "--RUCTypeWithLambdas--")] [ExpectedWarning ("IL2026", nameof (RUCTypeWithLambdas.MethodWithLambdas) + "()", "--RUCTypeWithLambdas--")] public static void Test (Lambdas test = null) @@ -402,18 +358,16 @@ static void LocalFunctionWithoutDataflow () static void LocalFunctionCallsMethodWithRequires () { [ExpectedWarning ("IL2026", "--MethodWithRequires--")] - [ExpectedWarning ("IL3002", "--MethodWithRequires--", ProducedBy = Tool.Analyzer | Tool.NativeAot)] - [ExpectedWarning ("IL3050", "--MethodWithRequires--", ProducedBy = Tool.Analyzer | Tool.NativeAot)] - [ExpectedWarning ("IL2119", "<" + nameof (LocalFunctionCallsMethodWithRequires) + ">", - ProducedBy = Tool.Trimmer)] + [ExpectedWarning ("IL3002", "--MethodWithRequires--", Tool.Analyzer | Tool.NativeAot, "")] + [ExpectedWarning ("IL3050", "--MethodWithRequires--", Tool.Analyzer | Tool.NativeAot, "")] + [ExpectedWarning ("IL2119", "<" + nameof (LocalFunctionCallsMethodWithRequires) + ">", Tool.Trimmer, "")] void LocalFunction () => MethodWithRequires (); LocalFunction (); } static void LocalFunctionWithCorrectDataflow () { - [ExpectedWarning ("IL2119", "<" + nameof (LocalFunctionWithCorrectDataflow) + ">", - ProducedBy = Tool.Trimmer)] + [ExpectedWarning ("IL2119", "<" + nameof (LocalFunctionWithCorrectDataflow) + ">", Tool.Trimmer, "")] void LocalFunction () { var t = GetAll (); @@ -425,8 +379,7 @@ void LocalFunction () static void LocalFunctionWithProblematicDataflow () { [ExpectedWarning ("IL2072", nameof (DataFlowTypeExtensions.RequiresAll))] - [ExpectedWarning ("IL2119", "<" + nameof (LocalFunctionWithProblematicDataflow) + ">", - ProducedBy = Tool.Trimmer)] + [ExpectedWarning ("IL2119", "<" + nameof (LocalFunctionWithProblematicDataflow) + ">", Tool.Trimmer, "")] void LocalFunction () { var t = GetWithPublicMethods (); @@ -438,8 +391,7 @@ void LocalFunction () static void LocalFunctionWithCapturedTypeToDAM () { var t = GetAll (); - [ExpectedWarning ("IL2119", "<" + nameof (LocalFunctionWithCapturedTypeToDAM) + ">", - ProducedBy = Tool.Trimmer)] + [ExpectedWarning ("IL2119", "<" + nameof (LocalFunctionWithCapturedTypeToDAM) + ">", Tool.Trimmer, "")] void LocalFunction () { t.RequiresAll (); @@ -464,32 +416,29 @@ static void LocalFunctionCallsPInvokeTakingPrimitiveType () static void LocalFunctionCallsPInvokeTakingObject () { [ExpectedWarning ("IL2050")] - [ExpectedWarning ("IL2119", "<" + nameof (LocalFunctionCallsPInvokeTakingObject) + ">", - ProducedBy = Tool.Trimmer)] + [ExpectedWarning ("IL2119", "<" + nameof (LocalFunctionCallsPInvokeTakingObject) + ">", Tool.Trimmer, "")] void LocalFunction () => MethodTakingObject (null); LocalFunction (); } - [ExpectedWarning ("IL2112", nameof (RUCTypeWithLocalFunctions) + "()", CompilerGeneratedCode = true, - ProducedBy = Tool.Trimmer | Tool.NativeAot)] + [ExpectedWarning ("IL2112", nameof (RUCTypeWithLocalFunctions) + "()", Tool.Trimmer | Tool.NativeAot, "", CompilerGeneratedCode = true)] [RequiresUnreferencedCode ("--RUCTypeWithLocalFunctions--")] class RUCTypeWithLocalFunctions { - [ExpectedWarning ("IL2112", nameof (MethodWithLocalFunctions), "--RUCTypeWithLocalFunctions--", - ProducedBy = Tool.Trimmer | Tool.NativeAot)] + [ExpectedWarning ("IL2112", nameof (MethodWithLocalFunctions), "--RUCTypeWithLocalFunctions--", Tool.Trimmer | Tool.NativeAot, "")] public void MethodWithLocalFunctions () { - [ExpectedWarning ("IL3002", "--MethodWithRequires--", ProducedBy = Tool.Analyzer | Tool.NativeAot)] - [ExpectedWarning ("IL3050", "--MethodWithRequires--", ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3002", "--MethodWithRequires--", Tool.Analyzer | Tool.NativeAot, "")] + [ExpectedWarning ("IL3050", "--MethodWithRequires--", Tool.Analyzer | Tool.NativeAot, "")] void LocalFunction () => MethodWithRequires (); - [ExpectedWarning ("IL3002", "--MethodWithRequires--", ProducedBy = Tool.Analyzer | Tool.NativeAot)] - [ExpectedWarning ("IL3050", "--MethodWithRequires--", ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3002", "--MethodWithRequires--", Tool.Analyzer | Tool.NativeAot, "")] + [ExpectedWarning ("IL3050", "--MethodWithRequires--", Tool.Analyzer | Tool.NativeAot, "")] static void StaticLocalFunction () => MethodWithRequires (); int i = 0; - [ExpectedWarning ("IL3002", "--MethodWithRequires--", ProducedBy = Tool.Analyzer | Tool.NativeAot)] - [ExpectedWarning ("IL3050", "--MethodWithRequires--", ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3002", "--MethodWithRequires--", Tool.Analyzer | Tool.NativeAot, "")] + [ExpectedWarning ("IL3050", "--MethodWithRequires--", Tool.Analyzer | Tool.NativeAot, "")] void LocalFunctionWithCapturedState () { i++; @@ -502,16 +451,11 @@ void LocalFunctionWithCapturedState () } } - [ExpectedWarning ("IL2118", nameof (LocalFunctionCallsPInvokeTakingObject), - ProducedBy = Tool.Trimmer)] - [ExpectedWarning ("IL2118", nameof (LocalFunctionCallsMethodWithRequires), - ProducedBy = Tool.Trimmer)] - [ExpectedWarning ("IL2118", nameof (LocalFunctionWithCorrectDataflow), - ProducedBy = Tool.Trimmer)] - [ExpectedWarning ("IL2118", nameof (LocalFunctionWithProblematicDataflow), - ProducedBy = Tool.Trimmer)] - [ExpectedWarning ("IL2118", nameof (LocalFunctionWithCapturedTypeToDAM), - ProducedBy = Tool.Trimmer)] + [ExpectedWarning ("IL2118", nameof (LocalFunctionCallsPInvokeTakingObject), Tool.Trimmer, "")] + [ExpectedWarning ("IL2118", nameof (LocalFunctionCallsMethodWithRequires), Tool.Trimmer, "")] + [ExpectedWarning ("IL2118", nameof (LocalFunctionWithCorrectDataflow), Tool.Trimmer, "")] + [ExpectedWarning ("IL2118", nameof (LocalFunctionWithProblematicDataflow), Tool.Trimmer, "")] + [ExpectedWarning ("IL2118", nameof (LocalFunctionWithCapturedTypeToDAM), Tool.Trimmer, "")] // Expect RUC warnings for static, compiler-generated code warnings for instance. [ExpectedWarning ("IL2026", nameof (RUCTypeWithLocalFunctions) + "()", "--RUCTypeWithLocalFunctions--")] [ExpectedWarning ("IL2026", nameof (RUCTypeWithLocalFunctions.MethodWithLocalFunctions) + "()")] @@ -648,7 +592,7 @@ static void TestLocalFunctionThroughDelegate () Action a = LocalFunction; a (null); - void LocalFunction ([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] Type type) + void LocalFunction ([DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] Type type) { } } @@ -658,7 +602,7 @@ static void TestGenericLocalFunctionThroughDelegate () Action a = LocalFunction; a (); - void LocalFunction <[DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] T> () + void LocalFunction<[DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] T> () { } } @@ -685,10 +629,10 @@ static void Lambda () a (typeof (string)); } - static void LambdaOnGeneric<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] T> () + static void LambdaOnGeneric<[DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] T> () { Action a = () => { - typeof(T).GetMethods (); + typeof (T).GetMethods (); }; a (); @@ -698,23 +642,23 @@ static void LocalFunction () { LocalFunctionInner (typeof (string)); - static void LocalFunctionInner ([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] Type type) + static void LocalFunctionInner ([DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] Type type) { type.GetMethods (); } } - static void LocalFunctionOnGeneric<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] T>() + static void LocalFunctionOnGeneric<[DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] T> () { LocalFunctionInner (); static void LocalFunctionInner () { - typeof(T).GetMethods (); + typeof (T).GetMethods (); } } - static IEnumerable IteratorOnGeneric<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] T>() + static IEnumerable IteratorOnGeneric<[DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] T> () { yield return 0; } @@ -730,8 +674,8 @@ static void LocalFunctionInner () await Task.Delay (100); } - [ExpectedWarning ("IL2118", "<" + nameof (LambdaOnGeneric) + ">", ProducedBy = Tool.Trimmer)] - [ExpectedWarning ("IL2118", "<" + nameof (LocalFunctionOnGeneric) + ">", ProducedBy = Tool.Trimmer)] + [ExpectedWarning ("IL2118", "<" + nameof (LambdaOnGeneric) + ">", Tool.Trimmer, "")] + [ExpectedWarning ("IL2118", "<" + nameof (LocalFunctionOnGeneric) + ">", Tool.Trimmer, "")] public static void Test () { typeof (DAMReflectionAccessToCompilerGeneratedCode).RequiresAll (); diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/CompilerGeneratedCodeDataflow.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/CompilerGeneratedCodeDataflow.cs index bae9341ecde8bf..e0bb05872b8445 100644 --- a/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/CompilerGeneratedCodeDataflow.cs +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/CompilerGeneratedCodeDataflow.cs @@ -38,10 +38,8 @@ static IEnumerable FlowAcrossYieldReturn () } // Trimmer tracks all assignments of hoisted locals, so this produces warnings. - [ExpectedWarning ("IL2072", nameof (GetWithPublicMethods), nameof (DataFlowTypeExtensions.RequiresPublicFields), CompilerGeneratedCode = true, - ProducedBy = Tool.Trimmer | Tool.NativeAot)] - [ExpectedWarning ("IL2072", nameof (GetWithPublicFields), nameof (DataFlowTypeExtensions.RequiresPublicMethods), CompilerGeneratedCode = true, - ProducedBy = Tool.Trimmer | Tool.NativeAot)] + [ExpectedWarning ("IL2072", nameof (GetWithPublicMethods), nameof (DataFlowTypeExtensions.RequiresPublicFields), Tool.Trimmer | Tool.NativeAot, "", CompilerGeneratedCode = true)] + [ExpectedWarning ("IL2072", [nameof (GetWithPublicFields), nameof (DataFlowTypeExtensions.RequiresPublicMethods)], Tool.Trimmer | Tool.NativeAot, "", CompilerGeneratedCode = true)] static IEnumerable NoFlowAcrossYieldReturn () { Type t = GetWithPublicMethods (); @@ -227,10 +225,8 @@ static async void FlowAcrossAwait () } // Trimmer tracks all assignments of hoisted locals, so this produces warnings. - [ExpectedWarning ("IL2072", nameof (GetWithPublicMethods), nameof (DataFlowTypeExtensions.RequiresPublicFields), CompilerGeneratedCode = true, - ProducedBy = Tool.Trimmer | Tool.NativeAot)] - [ExpectedWarning ("IL2072", nameof (GetWithPublicFields), nameof (DataFlowTypeExtensions.RequiresPublicMethods), CompilerGeneratedCode = true, - ProducedBy = Tool.Trimmer | Tool.NativeAot)] + [ExpectedWarning ("IL2072", nameof (GetWithPublicMethods), nameof (DataFlowTypeExtensions.RequiresPublicFields), Tool.Trimmer | Tool.NativeAot, "", CompilerGeneratedCode = true)] + [ExpectedWarning ("IL2072", nameof (GetWithPublicFields), nameof (DataFlowTypeExtensions.RequiresPublicMethods), Tool.Trimmer | Tool.NativeAot, "", CompilerGeneratedCode = true)] static async void NoFlowAcrossAwait () { Type t = GetWithPublicMethods (); @@ -447,7 +443,7 @@ public static void ReadCapturedParameterAfterWrite (Type tParameter = null) void LocalFunction () => tParameter.RequiresPublicMethods (); } - [ExpectedWarning ("IL2072", "tParameter", nameof (GetWithPublicFields), ProducedBy = Tool.Analyzer)] + [ExpectedWarning ("IL2072", ["tParameter", nameof (GetWithPublicFields)], Tool.Analyzer, "")] public static void ReadCapturedParameterAfterWriteMismatch ([DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] Type tParameter = null) { tParameter = GetWithPublicFields (); @@ -576,7 +572,7 @@ public static void ReadCapturedParameterAfterWrite (Type tParameter = null) lambda (); } - [ExpectedWarning ("IL2072", "tParameter", nameof (GetWithPublicFields), ProducedBy = Tool.Analyzer)] + [ExpectedWarning ("IL2072", ["tParameter", nameof (GetWithPublicFields)], Tool.Analyzer, "")] public static void ReadCapturedParameterAfterWriteMismatch ([DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] Type tParameter = null) { tParameter = GetWithPublicFields (); diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/CompilerGeneratedCodeInPreservedAssembly.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/CompilerGeneratedCodeInPreservedAssembly.cs index 2cd0f49317f17b..83ae5834cdc96b 100644 --- a/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/CompilerGeneratedCodeInPreservedAssembly.cs +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/CompilerGeneratedCodeInPreservedAssembly.cs @@ -42,7 +42,7 @@ public static void WithLocalFunctionInner () // Analyzer doesn't implement constant propagation and branch removal, so it reaches this code // NativeAOT behavioral difference: // https://github.com/dotnet/runtime/issues/85161 - [ExpectedWarning ("IL2026", ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL2026", Tool.Analyzer | Tool.NativeAot, "")] void LocalWithWarning () { // No warning @@ -64,7 +64,7 @@ public static void WithLocalFunction () // Analyzer doesn't implement constant propagation and branch removal, so it reaches this code // NativeAOT behavioral difference: // https://github.com/dotnet/runtime/issues/85161 - [ExpectedWarning ("IL2026", ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL2026", Tool.Analyzer | Tool.NativeAot, "")] void LocalWithWarning () { Requires (); diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/CompilerGeneratedCodeInPreservedAssemblyWithWarning.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/CompilerGeneratedCodeInPreservedAssemblyWithWarning.cs index 2023c19aaa85b1..58af92cb3e179b 100644 --- a/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/CompilerGeneratedCodeInPreservedAssemblyWithWarning.cs +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/CompilerGeneratedCodeInPreservedAssemblyWithWarning.cs @@ -38,7 +38,7 @@ public static void WithLocalFunctionInner () } // https://github.com/dotnet/linker/issues/2937 - [ExpectedWarning ("IL2091", ProducedBy = Tool.Trimmer)] + [ExpectedWarning ("IL2091", Tool.Trimmer, "")] void LocalWithWarning () { // Warning! @@ -55,7 +55,7 @@ public static void WithLocalFunction () } // https://github.com/dotnet/linker/issues/2937 - [ExpectedWarning ("IL2091", ProducedBy = Tool.Trimmer)] + [ExpectedWarning ("IL2091", Tool.Trimmer, "")] void LocalWithWarning () { // No warning diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/ComplexTypeHandling.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/ComplexTypeHandling.cs index ad29941cae2ce8..36d22c3ff904c2 100644 --- a/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/ComplexTypeHandling.cs +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/ComplexTypeHandling.cs @@ -151,7 +151,7 @@ public ArrayCreateInstanceByNameElement () } [Kept] - [ExpectedWarning ("IL2032", ProducedBy = Tool.NativeAot)] // https://github.com/dotnet/runtime/issues/82447 + [ExpectedWarning ("IL2032", Tool.NativeAot, "")] // https://github.com/dotnet/runtime/issues/82447 static void TestArrayCreateInstanceByName () { Activator.CreateInstance ("test", "Mono.Linker.Tests.Cases.DataFlow.ComplexTypeHandling+ArrayCreateInstanceByNameElement[]"); diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/ConstructedTypesDataFlow.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/ConstructedTypesDataFlow.cs index abeed77e1bc0ed..d2dbbc2f416977 100644 --- a/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/ConstructedTypesDataFlow.cs +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/ConstructedTypesDataFlow.cs @@ -21,7 +21,7 @@ public static void Main () class DeconstructedVariable { // https://github.com/dotnet/linker/issues/3158 - [ExpectedWarning ("IL2077", ProducedBy = Tool.Trimmer | Tool.NativeAot)] + [ExpectedWarning ("IL2077", Tool.Trimmer | Tool.NativeAot, "")] static void DeconstructVariableNoAnnotation ((Type type, object instance) input) { var (type, instance) = input; @@ -31,7 +31,7 @@ static void DeconstructVariableNoAnnotation ((Type type, object instance) input) static (Type type, object instance) GetInput (int unused) => (typeof (string), null); // https://github.com/dotnet/linker/issues/3158 - [ExpectedWarning ("IL2077", ProducedBy = Tool.Trimmer | Tool.NativeAot)] + [ExpectedWarning ("IL2077", Tool.Trimmer | Tool.NativeAot, "")] static void DeconstructVariableFlowCapture (bool b = true) { // This creates a control-flow graph where the tuple elements assigned to @@ -51,8 +51,8 @@ static void DeconstructVariableFlowCapture (bool b = true) static ref Type AnnotatedProperty => ref annotatedfield; // https://github.com/dotnet/linker/issues/3158 - [ExpectedWarning ("IL2062", ProducedBy = Tool.Trimmer | Tool.NativeAot)] - [ExpectedWarning ("IL2078", ProducedBy = Tool.Trimmer | Tool.NativeAot)] + [ExpectedWarning ("IL2062", Tool.Trimmer | Tool.NativeAot, "")] + [ExpectedWarning ("IL2078", Tool.Trimmer | Tool.NativeAot, "")] static void DeconstructVariablePropertyReference ((Type type, object instance) input) { object instance; @@ -72,7 +72,7 @@ record TypeAndInstance ( // For analyzer, this is currently // https://github.com/dotnet/linker/issues/3158 // But it's possible that with that fixed there won't be a warning from the analyzer anyway (depends on the implementation) - [ExpectedWarning ("IL2067", ProducedBy = Tool.Trimmer | Tool.NativeAot)] + [ExpectedWarning ("IL2067", Tool.Trimmer | Tool.NativeAot, "")] static void DeconstructRecordWithAnnotation (TypeAndInstance value) { var (type, instance) = value; @@ -119,7 +119,7 @@ static void DeconstructRecordManualWithAnnotation (TypeAndInstanceRecordManual v } // https://github.com/dotnet/linker/issues/3158 - [ExpectedWarning ("IL2067", ProducedBy = Tool.Trimmer | Tool.NativeAot)] + [ExpectedWarning ("IL2067", Tool.Trimmer | Tool.NativeAot, "")] static void DeconstructRecordManualWithMismatchAnnotation (TypeAndInstanceRecordManual value) { var (type, instance) = value; diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/ConstructorDataFlow.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/ConstructorDataFlow.cs index fe0d1af1f62c7c..f1a3788aaa11bd 100644 --- a/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/ConstructorDataFlow.cs +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/ConstructorDataFlow.cs @@ -39,13 +39,11 @@ public DataFlowInConstructor () [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.All)] Type annotatedField = GetUnknown (); - [ExpectedWarning ("IL2074", nameof (GetUnknown), nameof (AnnotatedProperty), CompilerGeneratedCode = true, - ProducedBy = Tool.Trimmer | Tool.NativeAot)] // https://github.com/dotnet/runtime/issues/93277 + [ExpectedWarning ("IL2074", nameof (GetUnknown), nameof (AnnotatedProperty), Tool.Trimmer | Tool.NativeAot, "", CompilerGeneratedCode = true)] // https://github.com/dotnet/runtime/issues/93277 [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.All)] Type AnnotatedProperty { get; } = GetUnknown (); - [ExpectedWarning ("IL2074", nameof (GetUnknown), nameof (AnnotatedPropertyWithSetter), CompilerGeneratedCode = true, - ProducedBy = Tool.Trimmer | Tool.NativeAot)] // https://github.com/dotnet/runtime/issues/93277 + [ExpectedWarning ("IL2074", nameof (GetUnknown), nameof (AnnotatedPropertyWithSetter), Tool.Trimmer | Tool.NativeAot, "", CompilerGeneratedCode = true)] // https://github.com/dotnet/runtime/issues/93277 [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.All)] Type AnnotatedPropertyWithSetter { get; set; } = GetUnknown (); @@ -81,12 +79,10 @@ public DataFlowInConstructor () int PropertyWithThrowStatementInInitializer { get; } = string.Empty.Length == 0 ? throw new Exception() : 0; - [ExpectedWarning ("IL2067", nameof (TryGetUnknown), nameof (RequireAll), CompilerGeneratedCode = true, - ProducedBy = Tool.Trimmer | Tool.NativeAot)] // https://github.com/dotnet/linker/issues/2158 + [ExpectedWarning ("IL2067", nameof (TryGetUnknown), nameof (RequireAll), Tool.Trimmer | Tool.NativeAot, "", CompilerGeneratedCode = true)] // https://github.com/dotnet/linker/issues/2158 int fieldWithLocalReferenceInInitializer = TryGetUnknown (out var type) ? RequireAll (type) : 0; - [ExpectedWarning ("IL2067", nameof (TryGetUnknown), nameof (RequireAll), CompilerGeneratedCode = true, - ProducedBy = Tool.Trimmer | Tool.NativeAot)] // https://github.com/dotnet/linker/issues/2158 + [ExpectedWarning ("IL2067", nameof (TryGetUnknown), nameof (RequireAll), Tool.Trimmer | Tool.NativeAot, "", CompilerGeneratedCode = true)] // https://github.com/dotnet/linker/issues/2158 int PropertyWithLocalReferenceInInitializer { get; } = TryGetUnknown (out var type) ? RequireAll (type) : 0; public static void Test () diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/DynamicObjects.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/DynamicObjects.cs index d048bec91e5d29..01a5ecb9cb3657 100644 --- a/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/DynamicObjects.cs +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/DynamicObjects.cs @@ -29,7 +29,7 @@ public static void Main () class InvocationOnDynamicType { [ExpectedWarning ("IL2026", "Microsoft.CSharp.RuntimeBinder.Binder.InvokeMember")] - [ExpectedWarning ("IL3050", ProducedBy = Tool.NativeAot)] // https://github.com/dotnet/runtime/issues/94427 + [ExpectedWarning ("IL3050", Tool.NativeAot, "")] // https://github.com/dotnet/runtime/issues/94427 static void DynamicArgument () { dynamic dynamicObject = "Some string"; @@ -48,15 +48,15 @@ static void MethodWithDynamicParameterDoNothing (dynamic arg) } [ExpectedWarning ("IL2026", "Microsoft.CSharp.RuntimeBinder.Binder.InvokeMember")] - [ExpectedWarning ("IL3050", ProducedBy = Tool.NativeAot)] // https://github.com/dotnet/runtime/issues/94427 + [ExpectedWarning ("IL3050", Tool.NativeAot, "")] // https://github.com/dotnet/runtime/issues/94427 static void MethodWithDynamicParameter (dynamic arg) { arg.MethodWithDynamicParameter (arg); } // Roslyn codegen no longer produces a call to Binder.InvokeConstructor. - // [ExpectedWarning ("IL2026", "Microsoft.CSharp.RuntimeBinder.Binder.InvokeConstructor")] - // [ExpectedWarning ("IL3050", ProducedBy = Tool.NativeAot)] // https://github.com/dotnet/runtime/issues/94427 + // [ExpectedSharedWarning ("IL2026", "Microsoft.CSharp.RuntimeBinder.Binder.InvokeConstructor")] + // [ExpectedWarning ("IL3050", Tool.NativeAot, "")] // https://github.com/dotnet/runtime/issues/94427 // static void ObjectCreationDynamicArgument () // { // dynamic dynamicObject = "Some string"; @@ -81,14 +81,14 @@ public static void Test () class DynamicMemberReference { [ExpectedWarning ("IL2026", "Microsoft.CSharp.RuntimeBinder.Binder.GetMember")] - [ExpectedWarning ("IL3050", ProducedBy = Tool.NativeAot)] // https://github.com/dotnet/runtime/issues/94427 + [ExpectedWarning ("IL3050", Tool.NativeAot, "")] // https://github.com/dotnet/runtime/issues/94427 static void Read (dynamic d) { var x = d.Member; } [ExpectedWarning ("IL2026", "Microsoft.CSharp.RuntimeBinder.Binder.SetMember")] - [ExpectedWarning ("IL3050", ProducedBy = Tool.NativeAot)] // https://github.com/dotnet/runtime/issues/94427 + [ExpectedWarning ("IL3050", Tool.NativeAot, "")] // https://github.com/dotnet/runtime/issues/94427 static void Write (dynamic d) { d.Member = 0; @@ -104,14 +104,14 @@ public static void Test () class DynamicIndexerAccess { [ExpectedWarning ("IL2026", "Microsoft.CSharp.RuntimeBinder.Binder.GetIndex")] - [ExpectedWarning ("IL3050", ProducedBy = Tool.NativeAot)] // https://github.com/dotnet/runtime/issues/94427 + [ExpectedWarning ("IL3050", Tool.NativeAot, "")] // https://github.com/dotnet/runtime/issues/94427 static void Read (dynamic d) { var x = d[0]; } [ExpectedWarning ("IL2026", "Microsoft.CSharp.RuntimeBinder.Binder.SetIndex")] - [ExpectedWarning ("IL3050", ProducedBy = Tool.NativeAot)] // https://github.com/dotnet/runtime/issues/94427 + [ExpectedWarning ("IL3050", Tool.NativeAot, "")] // https://github.com/dotnet/runtime/issues/94427 static void Write (dynamic d) { d[0] = 0; @@ -129,7 +129,7 @@ class DynamicInRequiresUnreferencedCodeClass [RequiresUnreferencedCode("message")] class ClassWithRequires { - [ExpectedWarning ("IL3050", ProducedBy = Tool.NativeAot)] // https://github.com/dotnet/runtime/issues/94427 + [ExpectedWarning ("IL3050", Tool.NativeAot, "")] // https://github.com/dotnet/runtime/issues/94427 public static void MethodWithDynamicArg (dynamic arg) { arg.DynamicInvocation (); @@ -154,7 +154,7 @@ static void MethodWithRequires () } [ExpectedWarning ("IL2026", nameof (MethodWithRequires))] - [ExpectedWarning ("IL3050", nameof (MethodWithRequires), ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3050", nameof (MethodWithRequires), Tool.Analyzer | Tool.NativeAot, "")] public static void Test () { MethodWithRequires (); diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/ExceptionalDataFlow.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/ExceptionalDataFlow.cs index beaf3237c7c4d3..8cc5bf9b6c1a7e 100644 --- a/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/ExceptionalDataFlow.cs +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/ExceptionalDataFlow.cs @@ -46,10 +46,8 @@ public static void Main () ExceptionFilterWithException (); } - [ExpectedWarning ("IL2072", nameof (RequireAll) + "(Type)", nameof (GetWithPublicFields) + "()", - ProducedBy = Tool.Analyzer)] - [ExpectedWarning ("IL2072", nameof (RequireAll) + "(Type)", nameof (GetWithPublicMethods) + "()", - ProducedBy = Tool.Analyzer)] + [ExpectedWarning ("IL2072", nameof (RequireAll) + "(Type)", nameof (GetWithPublicFields) + "()", Tool.Analyzer, "")] + [ExpectedWarning ("IL2072", nameof (RequireAll) + "(Type)", nameof (GetWithPublicMethods) + "()", Tool.Analyzer, "")] [ExpectedWarning ("IL2072", nameof (RequireAll) + "(Type)", nameof (GetWithPublicProperties) + "()")] public static void TryFlowsToFinally () { @@ -109,12 +107,9 @@ public static void MultipleTryExits () // On each path, only one state is possible, but we conservatively merge the (non-exceptional) // finally states for each path and expect the warnings to reflect this merged state. [ExpectedWarning ("IL2072", nameof (RequireAll1) + "(Type)", nameof (GetWithPublicMethods) + "()")] - [ExpectedWarning ("IL2072", nameof (RequireAll1) + "(Type)", nameof (GetWithPublicFields) + "()", - ProducedBy = Tool.Analyzer)] - [ExpectedWarning ("IL2072", nameof (RequireAll1) + "(Type)", nameof (GetWithPublicProperties) + "()", - ProducedBy = Tool.Analyzer)] - [ExpectedWarning ("IL2072", nameof (RequireAll1) + "(Type)", nameof (GetWithPublicEvents) + "()", - ProducedBy = Tool.Analyzer)] + [ExpectedWarning ("IL2072", nameof (RequireAll1) + "(Type)", nameof (GetWithPublicFields) + "()", Tool.Analyzer, "")] + [ExpectedWarning ("IL2072", nameof (RequireAll1) + "(Type)", nameof (GetWithPublicProperties) + "()", Tool.Analyzer, "")] + [ExpectedWarning ("IL2072", nameof (RequireAll1) + "(Type)", nameof (GetWithPublicEvents) + "()", Tool.Analyzer, "")] [ExpectedWarning ("IL2072", nameof (RequireAll2) + "(Type)", nameof (GetWithPublicMethods) + "()")] [ExpectedWarning ("IL2072", nameof (RequireAll2) + "(Type)", nameof (GetWithPublicFields) + "()")] @@ -124,12 +119,9 @@ public static void MultipleTryExits () [ExpectedWarning ("IL2073", nameof (MultipleFinallyPaths) + "()", nameof (GetWithPublicEvents) + "()")] // Trimmer merges branches going forward. - [ExpectedWarning ("IL2073", nameof (MultipleFinallyPaths) + "()", nameof (GetWithPublicMethods) + "()", - ProducedBy = Tool.Trimmer | Tool.NativeAot)] - [ExpectedWarning ("IL2073", nameof (MultipleFinallyPaths) + "()", nameof (GetWithPublicFields) + "()", - ProducedBy = Tool.Trimmer | Tool.NativeAot)] - [ExpectedWarning ("IL2073", nameof (MultipleFinallyPaths) + "()", nameof (GetWithPublicProperties) + "()", - ProducedBy = Tool.Trimmer | Tool.NativeAot)] + [ExpectedWarning ("IL2073", nameof (MultipleFinallyPaths) + "()", nameof (GetWithPublicMethods) + "()", Tool.Trimmer | Tool.NativeAot, "")] + [ExpectedWarning ("IL2073", nameof (MultipleFinallyPaths) + "()", nameof (GetWithPublicFields) + "()", Tool.Trimmer | Tool.NativeAot, "")] + [ExpectedWarning ("IL2073", nameof (MultipleFinallyPaths) + "()", nameof (GetWithPublicProperties) + "()", Tool.Trimmer | Tool.NativeAot, "")] [return: DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.All)] public static Type MultipleFinallyPaths () { @@ -160,14 +152,11 @@ public static Type MultipleFinallyPaths () throw new Exception (); } - [ExpectedWarning ("IL2072", nameof (RequireAll1) + "(Type)", nameof (GetWithPublicFields) + "()", - ProducedBy = Tool.Analyzer)] + [ExpectedWarning ("IL2072", nameof (RequireAll1) + "(Type)", nameof (GetWithPublicFields) + "()", Tool.Analyzer, "")] [ExpectedWarning ("IL2072", nameof (RequireAll1) + "(Type)", nameof (GetWithPublicProperties) + "()")] - [ExpectedWarning ("IL2072", nameof (RequireAll2) + "(Type)", nameof (GetWithPublicMethods) + "()", - ProducedBy = Tool.Analyzer)] - [ExpectedWarning ("IL2072", nameof (RequireAll2) + "(Type)", nameof (GetWithPublicFields) + "()", - ProducedBy = Tool.Analyzer)] + [ExpectedWarning ("IL2072", nameof (RequireAll2) + "(Type)", nameof (GetWithPublicMethods) + "()", Tool.Analyzer, "")] + [ExpectedWarning ("IL2072", nameof (RequireAll2) + "(Type)", nameof (GetWithPublicFields) + "()", Tool.Analyzer, "")] [ExpectedWarning ("IL2072", nameof (RequireAll2) + "(Type)", nameof (GetWithPublicProperties) + "()")] public static void FinallyChain () { @@ -184,16 +173,12 @@ public static void FinallyChain () } } - [ExpectedWarning ("IL2072", nameof (RequireAll1) + "(Type)", nameof (GetWithPublicFields) + "()", - ProducedBy = Tool.Analyzer)] - [ExpectedWarning ("IL2072", nameof (RequireAll1) + "(Type)", nameof (GetWithPublicProperties) + "()")] - + [ExpectedWarning ("IL2072", nameof (RequireAll1) + "(Type)", nameof (GetWithPublicFields) + "()", Tool.Analyzer, "")] + [ExpectedWarning ("IL2072", nameof (RequireAll1) + "(Type)", nameof (GetWithPublicProperties) + "()")] [ExpectedWarning ("IL2072", nameof (RequireAll2) + "(Type)", nameof (GetWithPublicProperties) + "()")] - [ExpectedWarning ("IL2072", nameof (RequireAll3) + "(Type)", nameof (GetWithPublicMethods) + "()", - ProducedBy = Tool.Analyzer)] - [ExpectedWarning ("IL2072", nameof (RequireAll3) + "(Type)", nameof (GetWithPublicFields) + "()", - ProducedBy = Tool.Analyzer)] + [ExpectedWarning ("IL2072", nameof (RequireAll3) + "(Type)", nameof (GetWithPublicMethods) + "()", Tool.Analyzer, "")] + [ExpectedWarning ("IL2072", nameof (RequireAll3) + "(Type)", nameof (GetWithPublicFields) + "()", Tool.Analyzer, "")] [ExpectedWarning ("IL2072", nameof (RequireAll3) + "(Type)", nameof (GetWithPublicProperties) + "()")] [ExpectedWarning ("IL2072", nameof (RequireAll4) + "(Type)", nameof (GetWithPublicProperties) + "()")] @@ -218,10 +203,8 @@ public static void FinallyChainWithPostFinallyState () RequireAll4 (t); } - [ExpectedWarning ("IL2072", nameof (RequireAll) + "(Type)", nameof (GetWithPublicFields) + "()", - ProducedBy = Tool.Analyzer)] - [ExpectedWarning ("IL2072", nameof (RequireAll) + "(Type)", nameof (GetWithPublicMethods) + "()", - ProducedBy = Tool.Analyzer)] + [ExpectedWarning ("IL2072", nameof (RequireAll) + "(Type)", nameof (GetWithPublicFields) + "()", Tool.Analyzer, "")] + [ExpectedWarning ("IL2072", nameof (RequireAll) + "(Type)", nameof (GetWithPublicMethods) + "()", Tool.Analyzer, "")] [ExpectedWarning ("IL2072", nameof (RequireAll) + "(Type)", nameof (GetWithPublicProperties) + "()")] public static void TryFlowsToCatch () { @@ -235,10 +218,8 @@ public static void TryFlowsToCatch () } } - [ExpectedWarning ("IL2072", nameof (RequireAll) + "(Type)", nameof (GetWithPublicFields) + "()", - ProducedBy = Tool.Analyzer)] - [ExpectedWarning ("IL2072", nameof (RequireAll) + "(Type)", nameof (GetWithPublicMethods) + "()", - ProducedBy = Tool.Analyzer)] + [ExpectedWarning ("IL2072", nameof (RequireAll) + "(Type)", nameof (GetWithPublicFields) + "()", Tool.Analyzer, "")] + [ExpectedWarning ("IL2072", nameof (RequireAll) + "(Type)", nameof (GetWithPublicMethods) + "()", Tool.Analyzer, "")] [ExpectedWarning ("IL2072", nameof (RequireAll) + "(Type)", nameof (GetWithPublicProperties) + "()")] public static void CatchFlowsToFinally () { @@ -253,8 +234,7 @@ public static void CatchFlowsToFinally () } } - [ExpectedWarning ("IL2072", nameof (RequireAll) + "(Type)", nameof (GetWithPublicMethods) + "()", - ProducedBy = Tool.Analyzer)] + [ExpectedWarning ("IL2072", nameof (RequireAll) + "(Type)", nameof (GetWithPublicMethods) + "()", Tool.Analyzer, "")] [ExpectedWarning ("IL2072", nameof (RequireAll) + "(Type)", nameof (GetWithPublicProperties) + "()")] public static void CatchFlowsToAfterTry () { @@ -268,8 +248,7 @@ public static void CatchFlowsToAfterTry () RequireAll (t); } - [ExpectedWarning ("IL2072", nameof (RequireAll) + "(Type)", nameof (GetWithPublicMethods) + "()", - ProducedBy = Tool.Analyzer)] + [ExpectedWarning ("IL2072", nameof (RequireAll) + "(Type)", nameof (GetWithPublicMethods) + "()", Tool.Analyzer, "")] [ExpectedWarning ("IL2072", nameof (RequireAll) + "(Type)", nameof (GetWithPublicProperties) + "()")] public static void CatchFlowsToAfterFinally () { @@ -303,20 +282,17 @@ public class Exception2 : Exception { } [ExpectedWarning ("IL2072", nameof (RequireAll1) + "(Type)", nameof (GetWithPublicFields) + "()")] - [ExpectedWarning ("IL2072", nameof (RequireAll2) + "(Type)", nameof (GetWithPublicMethods) + "()", - ProducedBy = Tool.Analyzer)] + [ExpectedWarning ("IL2072", nameof (RequireAll2) + "(Type)", nameof (GetWithPublicMethods) + "()", Tool.Analyzer, "")] [ExpectedWarning ("IL2072", nameof (RequireAll2) + "(Type)", nameof (GetWithPublicFields) + "()")] [ExpectedWarning ("IL2072", nameof (RequireAll3) + "(Type)", nameof (GetWithPublicProperties) + "()")] - [ExpectedWarning ("IL2072", nameof (RequireAll4) + "(Type)", nameof (GetWithPublicMethods) + "()", - ProducedBy = Tool.Analyzer)] + [ExpectedWarning ("IL2072", nameof (RequireAll4) + "(Type)", nameof (GetWithPublicMethods) + "()", Tool.Analyzer, "")] [ExpectedWarning ("IL2072", nameof (RequireAll4) + "(Type)", nameof (GetWithPublicFields) + "()")] [ExpectedWarning ("IL2072", nameof (RequireAll5) + "(Type)", nameof (GetWithPublicEvents) + "()")] - [ExpectedWarning ("IL2072", nameof (RequireAll6) + "(Type)", nameof (GetWithPublicMethods) + "()", - ProducedBy = Tool.Analyzer)] + [ExpectedWarning ("IL2072", nameof (RequireAll6) + "(Type)", nameof (GetWithPublicMethods) + "()", Tool.Analyzer, "")] [ExpectedWarning ("IL2072", nameof (RequireAll6) + "(Type)", nameof (GetWithPublicFields) + "()")] [ExpectedWarning ("IL2072", nameof (RequireAll6) + "(Type)", nameof (GetWithPublicProperties) + "()")] [ExpectedWarning ("IL2072", nameof (RequireAll6) + "(Type)", nameof (GetWithPublicEvents) + "()")] @@ -326,26 +302,16 @@ public class Exception2 : Exception { } [ExpectedWarning ("IL2072", nameof (RequireAll) + "(Type)", nameof (GetWithPublicConstructors) + "()")] // Trimmer merges branches going forward. - [ExpectedWarning ("IL2072", nameof (RequireAll3) + "(Type)", nameof (GetWithPublicFields) + "()", - ProducedBy = Tool.Trimmer | Tool.NativeAot)] - [ExpectedWarning ("IL2072", nameof (RequireAll4) + "(Type)", nameof (GetWithPublicProperties) + "()", - ProducedBy = Tool.Trimmer | Tool.NativeAot)] - [ExpectedWarning ("IL2072", nameof (RequireAll5) + "(Type)", nameof (GetWithPublicFields) + "()", - ProducedBy = Tool.Trimmer | Tool.NativeAot)] - [ExpectedWarning ("IL2072", nameof (RequireAll5) + "(Type)", nameof (GetWithPublicProperties) + "()", - ProducedBy = Tool.Trimmer | Tool.NativeAot)] - [ExpectedWarning ("IL2072", nameof (RequireAll7) + "(Type)", nameof (GetWithPublicFields) + "()", - ProducedBy = Tool.Trimmer | Tool.NativeAot)] - [ExpectedWarning ("IL2072", nameof (RequireAll7) + "(Type)", nameof (GetWithPublicProperties) + "()", - ProducedBy = Tool.Trimmer | Tool.NativeAot)] - [ExpectedWarning ("IL2072", nameof (RequireAll7) + "(Type)", nameof (GetWithPublicEvents) + "()", - ProducedBy = Tool.Trimmer | Tool.NativeAot)] - [ExpectedWarning ("IL2072", nameof (RequireAll) + "(Type)", nameof (GetWithPublicFields) + "()", - ProducedBy = Tool.Trimmer | Tool.NativeAot)] - [ExpectedWarning ("IL2072", nameof (RequireAll) + "(Type)", nameof (GetWithPublicProperties) + "()", - ProducedBy = Tool.Trimmer | Tool.NativeAot)] - [ExpectedWarning ("IL2072", nameof (RequireAll) + "(Type)", nameof (GetWithPublicEvents) + "()", - ProducedBy = Tool.Trimmer | Tool.NativeAot)] + [ExpectedWarning ("IL2072", nameof (RequireAll3) + "(Type)", nameof (GetWithPublicFields) + "()", Tool.Trimmer | Tool.NativeAot, "")] + [ExpectedWarning ("IL2072", nameof (RequireAll4) + "(Type)", nameof (GetWithPublicProperties) + "()", Tool.Trimmer | Tool.NativeAot, "")] + [ExpectedWarning ("IL2072", nameof (RequireAll5) + "(Type)", nameof (GetWithPublicFields) + "()", Tool.Trimmer | Tool.NativeAot, "")] + [ExpectedWarning ("IL2072", nameof (RequireAll5) + "(Type)", nameof (GetWithPublicProperties) + "()", Tool.Trimmer | Tool.NativeAot, "")] + [ExpectedWarning ("IL2072", nameof (RequireAll7) + "(Type)", nameof (GetWithPublicFields) + "()", Tool.Trimmer | Tool.NativeAot, "")] + [ExpectedWarning ("IL2072", nameof (RequireAll7) + "(Type)", nameof (GetWithPublicProperties) + "()", Tool.Trimmer | Tool.NativeAot, "")] + [ExpectedWarning ("IL2072", nameof (RequireAll7) + "(Type)", nameof (GetWithPublicEvents) + "()", Tool.Trimmer | Tool.NativeAot, "")] + [ExpectedWarning ("IL2072", nameof (RequireAll) + "(Type)", nameof (GetWithPublicFields) + "()", Tool.Trimmer | Tool.NativeAot, "")] + [ExpectedWarning ("IL2072", nameof (RequireAll) + "(Type)", nameof (GetWithPublicProperties) + "()", Tool.Trimmer | Tool.NativeAot, "")] + [ExpectedWarning ("IL2072", nameof (RequireAll) + "(Type)", nameof (GetWithPublicEvents) + "()", Tool.Trimmer | Tool.NativeAot, "")] public static void TryFlowsToMultipleCatchAndFinally () { @@ -370,20 +336,15 @@ public static void TryFlowsToMultipleCatchAndFinally () } - [ExpectedWarning ("IL2072", nameof (RequireAll1) + "(Type)", nameof (GetWithPublicFields) + "()", - ProducedBy = Tool.Analyzer)] + [ExpectedWarning ("IL2072", nameof (RequireAll1) + "(Type)", nameof (GetWithPublicFields) + "()", Tool.Analyzer, "")] [ExpectedWarning ("IL2072", nameof (RequireAll1) + "(Type)", nameof (GetWithPublicProperties) + "()")] [ExpectedWarning ("IL2072", nameof (RequireAll2) + "(Type)", nameof (GetWithPublicConstructors) + "()")] - [ExpectedWarning ("IL2072", nameof (RequireAll3) + "(Type)", nameof (GetWithPublicMethods) + "()", - ProducedBy = Tool.Analyzer)] - [ExpectedWarning ("IL2072", nameof (RequireAll3) + "(Type)", nameof (GetWithPublicFields) + "()", - ProducedBy = Tool.Analyzer)] - [ExpectedWarning ("IL2072", nameof (RequireAll3) + "(Type)", nameof (GetWithPublicProperties) + "()", - ProducedBy = Tool.Analyzer)] - [ExpectedWarning ("IL2072", nameof (RequireAll3) + "(Type)", nameof (GetWithPublicEvents) + "()", - ProducedBy = Tool.Analyzer)] + [ExpectedWarning ("IL2072", nameof (RequireAll3) + "(Type)", nameof (GetWithPublicMethods) + "()", Tool.Analyzer, "")] + [ExpectedWarning ("IL2072", nameof (RequireAll3) + "(Type)", nameof (GetWithPublicFields) + "()", Tool.Analyzer, "")] + [ExpectedWarning ("IL2072", nameof (RequireAll3) + "(Type)", nameof (GetWithPublicProperties) + "()", Tool.Analyzer, "")] + [ExpectedWarning ("IL2072", nameof (RequireAll3) + "(Type)", nameof (GetWithPublicEvents) + "()", Tool.Analyzer, "")] [ExpectedWarning ("IL2072", nameof (RequireAll3) + "(Type)", nameof (GetWithPublicConstructors) + "()")] public static void NestedWithFinally () @@ -408,17 +369,14 @@ public static void NestedWithFinally () } } - [ExpectedWarning ("IL2072", nameof (RequireAll1) + "(Type)", nameof (GetWithPublicMethods) + "()", - ProducedBy = Tool.Analyzer)] + [ExpectedWarning ("IL2072", nameof (RequireAll1) + "(Type)", nameof (GetWithPublicMethods) + "()", Tool.Analyzer, "")] [ExpectedWarning ("IL2072", nameof (RequireAll1) + "(Type)", nameof (GetWithPublicFields) + "()")] - [ExpectedWarning ("IL2072", nameof (RequireAll2) + "(Type)", nameof (GetWithPublicMethods) + "()", - ProducedBy = Tool.Analyzer)] + [ExpectedWarning ("IL2072", nameof (RequireAll2) + "(Type)", nameof (GetWithPublicMethods) + "()", Tool.Analyzer, "")] [ExpectedWarning ("IL2072", nameof (RequireAll2) + "(Type)", nameof (GetWithPublicFields) + "()")] [ExpectedWarning ("IL2072", nameof (RequireAll2) + "(Type)", nameof (GetWithPublicProperties) + "()")] - [ExpectedWarning ("IL2072", nameof (RequireAll3) + "(Type)", nameof (GetWithPublicMethods) + "()", - ProducedBy = Tool.Analyzer)] + [ExpectedWarning ("IL2072", nameof (RequireAll3) + "(Type)", nameof (GetWithPublicMethods) + "()", Tool.Analyzer, "")] [ExpectedWarning ("IL2072", nameof (RequireAll3) + "(Type)", nameof (GetWithPublicFields) + "()")] [ExpectedWarning ("IL2072", nameof (RequireAll3) + "(Type)", nameof (GetWithPublicProperties) + "()")] [ExpectedWarning ("IL2072", nameof (RequireAll3) + "(Type)", nameof (GetWithPublicEvents) + "()")] @@ -446,22 +404,16 @@ public static void ControlFlowsOutOfMultipleFinally () } - [ExpectedWarning ("IL2072", nameof (RequireAll1) + "(Type)", nameof (GetWithPublicFields) + "()", - ProducedBy = Tool.Analyzer)] + [ExpectedWarning ("IL2072", nameof (RequireAll1) + "(Type)", nameof (GetWithPublicFields) + "()", Tool.Analyzer, "")] [ExpectedWarning ("IL2072", nameof (RequireAll1) + "(Type)", nameof (GetWithPublicProperties) + "()")] - [ExpectedWarning ("IL2072", nameof (RequireAll2) + "(Type)", nameof (GetWithPublicProperties) + "()", - ProducedBy = Tool.Analyzer)] + [ExpectedWarning ("IL2072", nameof (RequireAll2) + "(Type)", nameof (GetWithPublicProperties) + "()", Tool.Analyzer, "")] [ExpectedWarning ("IL2072", nameof (RequireAll2) + "(Type)", nameof (GetWithPublicConstructors) + "()")] - [ExpectedWarning ("IL2072", nameof (RequireAll3) + "(Type)", nameof (GetWithPublicMethods) + "()", - ProducedBy = Tool.Analyzer)] - [ExpectedWarning ("IL2072", nameof (RequireAll3) + "(Type)", nameof (GetWithPublicFields) + "()", - ProducedBy = Tool.Analyzer)] - [ExpectedWarning ("IL2072", nameof (RequireAll3) + "(Type)", nameof (GetWithPublicProperties) + "()", - ProducedBy = Tool.Analyzer)] - [ExpectedWarning ("IL2072", nameof (RequireAll3) + "(Type)", nameof (GetWithPublicEvents) + "()", - ProducedBy = Tool.Analyzer)] + [ExpectedWarning ("IL2072", nameof (RequireAll3) + "(Type)", nameof (GetWithPublicMethods) + "()", Tool.Analyzer, "")] + [ExpectedWarning ("IL2072", nameof (RequireAll3) + "(Type)", nameof (GetWithPublicFields) + "()", Tool.Analyzer, "")] + [ExpectedWarning ("IL2072", nameof (RequireAll3) + "(Type)", nameof (GetWithPublicProperties) + "()", Tool.Analyzer, "")] + [ExpectedWarning ("IL2072", nameof (RequireAll3) + "(Type)", nameof (GetWithPublicEvents) + "()", Tool.Analyzer, "")] [ExpectedWarning ("IL2072", nameof (RequireAll3) + "(Type)", nameof (GetWithPublicConstructors) + "()")] public static void NestedWithCatch () @@ -488,8 +440,7 @@ public static void NestedWithCatch () [ExpectedWarning ("IL2072", nameof (RequireAll) + "(Type)", nameof (GetWithPublicFields) + "()")] // Trimmer merges branches going forward. - [ExpectedWarning ("IL2072", nameof (RequireAll) + "(Type)", nameof (GetWithPublicMethods) + "()", - ProducedBy = Tool.Trimmer | Tool.NativeAot)] + [ExpectedWarning ("IL2072", nameof (RequireAll) + "(Type)", nameof (GetWithPublicMethods) + "()", Tool.Trimmer | Tool.NativeAot, "")] public static void CatchInTry () { try { @@ -510,11 +461,10 @@ public static void CatchInTry () [ExpectedWarning ("IL2072", nameof (RequireAll2) + "(Type)", nameof (GetWithPublicMethods) + "()")] [ExpectedWarning ("IL2072", nameof (RequireAll2) + "(Type)", nameof (GetWithPublicFields) + "()")] // The bug was producing this warning: - // [ExpectedWarning ("IL2072", nameof (RequireAll2) + "(Type)", nameof (GetWithPublicConstructors) + "()")] + // [ExpectedSharedWarning ("IL2072", nameof (RequireAll2) + "(Type)", nameof (GetWithPublicConstructors) + "()")] // Trimmer merges branches going forward. - [ExpectedWarning ("IL2072", nameof (RequireAll1) + "(Type)", nameof (GetWithPublicMethods) + "()", - ProducedBy = Tool.Trimmer | Tool.NativeAot)] + [ExpectedWarning ("IL2072", nameof (RequireAll1) + "(Type)", nameof (GetWithPublicMethods) + "()", Tool.Trimmer | Tool.NativeAot, "")] public static void CatchInTryWithFinally () { Type t = GetWithPublicConstructors (); @@ -540,12 +490,10 @@ public static void CatchInTryWithFinally () } } - [ExpectedWarning ("IL2072", nameof (RequireAll1) + "(Type)", nameof (GetWithPublicConstructors) + "()", - ProducedBy = Tool.Analyzer)] + [ExpectedWarning ("IL2072", nameof (RequireAll1) + "(Type)", nameof (GetWithPublicConstructors) + "()", Tool.Analyzer, "")] [ExpectedWarning ("IL2072", nameof (RequireAll1) + "(Type)", nameof (GetWithPublicMethods) + "()")] [ExpectedWarning ("IL2072", nameof (RequireAll1) + "(Type)", nameof (GetWithPublicFields) + "()")] - [ExpectedWarning ("IL2072", nameof (RequireAll2) + "(Type)", nameof (GetWithPublicConstructors) + "()", - ProducedBy = Tool.Analyzer)] + [ExpectedWarning ("IL2072", nameof (RequireAll2) + "(Type)", nameof (GetWithPublicConstructors) + "()", Tool.Analyzer, "")] [ExpectedWarning ("IL2072", nameof (RequireAll2) + "(Type)", nameof (GetWithPublicMethods) + "()")] [ExpectedWarning ("IL2072", nameof (RequireAll2) + "(Type)", nameof (GetWithPublicFields) + "()")] static void CatchInFinally () { @@ -565,8 +513,7 @@ static void CatchInFinally () { [ExpectedWarning ("IL2072", nameof (RequireAll) + "(Type)", nameof (GetWithPublicMethods) + "()")] // Trimmer merges branches going forward. - [ExpectedWarning ("IL2072", nameof (RequireAll) + "(Type)", nameof (GetWithPublicFields) + "()", - ProducedBy = Tool.Trimmer | Tool.NativeAot)] + [ExpectedWarning ("IL2072", nameof (RequireAll) + "(Type)", nameof (GetWithPublicFields) + "()", Tool.Trimmer | Tool.NativeAot, "")] public static void TestCatchesHaveSeparateState () { Type t = GetWithPublicMethods (); @@ -581,8 +528,7 @@ public static void TestCatchesHaveSeparateState () } [ExpectedWarning ("IL2072", nameof (RequireAll) + "(Type)", nameof (GetWithPublicMethods) + "()")] - [ExpectedWarning ("IL2072", nameof (RequireAll) + "(Type)", nameof (GetWithPublicFields) + "()", - ProducedBy = Tool.Analyzer)] + [ExpectedWarning ("IL2072", nameof (RequireAll) + "(Type)", nameof (GetWithPublicFields) + "()", Tool.Analyzer, "")] public static void FinallyWithBranchToFirstBlock () { Type t = GetWithPublicMethods (); @@ -596,8 +542,7 @@ public static void FinallyWithBranchToFirstBlock () } [ExpectedWarning ("IL2072", nameof (RequireAll) + "(Type)", nameof (GetWithPublicMethods) + "()")] - [ExpectedWarning ("IL2072", nameof (RequireAll) + "(Type)", nameof (GetWithPublicFields) + "()", - ProducedBy = Tool.Analyzer)] + [ExpectedWarning ("IL2072", nameof (RequireAll) + "(Type)", nameof (GetWithPublicFields) + "()", Tool.Analyzer, "")] public static void FinallyWithBranchToFirstBlockAndEnclosingTryCatchState () { try { @@ -619,8 +564,7 @@ public static void FinallyWithBranchToFirstBlockAndEnclosingTryCatchState () } [ExpectedWarning ("IL2072", nameof (RequireAll) + "(Type)", nameof (GetWithPublicMethods) + "()")] - [ExpectedWarning ("IL2072", nameof (RequireAll) + "(Type)", nameof (GetWithPublicFields) + "()", - ProducedBy = Tool.Analyzer)] + [ExpectedWarning ("IL2072", nameof (RequireAll) + "(Type)", nameof (GetWithPublicFields) + "()", Tool.Analyzer, "")] public static void CatchWithBranchToFirstBlock () { Type t = GetWithPublicMethods (); @@ -634,8 +578,7 @@ public static void CatchWithBranchToFirstBlock () } [ExpectedWarning ("IL2072", nameof (RequireAll) + "(Type)", nameof (GetWithPublicMethods) + "()")] - [ExpectedWarning ("IL2072", nameof (RequireAll) + "(Type)", nameof (GetWithPublicFields) + "()", - ProducedBy = Tool.Analyzer)] + [ExpectedWarning ("IL2072", nameof (RequireAll) + "(Type)", nameof (GetWithPublicFields) + "()", Tool.Analyzer, "")] public static void CatchWithBranchToFirstBlockAndReassignment () { Type t = GetWithPublicMethods (); @@ -651,10 +594,8 @@ public static void CatchWithBranchToFirstBlockAndReassignment () [ExpectedWarning ("IL2072", nameof (RequireAll1) + "(Type)", nameof (GetWithPublicProperties) + "()")] - [ExpectedWarning ("IL2072", nameof (RequireAll2) + "(Type)", nameof (GetWithPublicMethods) + "()", - ProducedBy = Tool.Analyzer)] - [ExpectedWarning ("IL2072", nameof (RequireAll2) + "(Type)", nameof (GetWithPublicFields) + "()", - ProducedBy = Tool.Analyzer)] + [ExpectedWarning ("IL2072", nameof (RequireAll2) + "(Type)", nameof (GetWithPublicMethods) + "()", Tool.Analyzer, "")] + [ExpectedWarning ("IL2072", nameof (RequireAll2) + "(Type)", nameof (GetWithPublicFields) + "()", Tool.Analyzer, "")] [ExpectedWarning ("IL2072", nameof (RequireAll2) + "(Type)", nameof (GetWithPublicProperties) + "()")] public static void CatchWithNonSimplePredecessor () { @@ -676,10 +617,8 @@ public static void CatchWithNonSimplePredecessor () [ExpectedWarning ("IL2072", nameof (RequireAll1) + "(Type)", nameof (GetWithPublicProperties) + "()")] - [ExpectedWarning ("IL2072", nameof (RequireAll2) + "(Type)", nameof (GetWithPublicMethods) + "()", - ProducedBy = Tool.Analyzer)] - [ExpectedWarning ("IL2072", nameof (RequireAll2) + "(Type)", nameof (GetWithPublicFields) + "()", - ProducedBy = Tool.Analyzer)] + [ExpectedWarning ("IL2072", nameof (RequireAll2) + "(Type)", nameof (GetWithPublicMethods) + "()", Tool.Analyzer, "")] + [ExpectedWarning ("IL2072", nameof (RequireAll2) + "(Type)", nameof (GetWithPublicFields) + "()", Tool.Analyzer, "")] [ExpectedWarning ("IL2072", nameof (RequireAll2) + "(Type)", nameof (GetWithPublicProperties) + "()")] public static void FinallyWithNonSimplePredecessor () { @@ -701,10 +640,8 @@ public static void FinallyWithNonSimplePredecessor () [ExpectedWarning ("IL2072", nameof (RequireAll1) + "(Type)", nameof (GetWithPublicProperties) + "()")] - [ExpectedWarning ("IL2072", nameof (RequireAll2) + "(Type)", nameof (GetWithPublicMethods) + "()", - ProducedBy = Tool.Analyzer)] - [ExpectedWarning ("IL2072", nameof (RequireAll2) + "(Type)", nameof (GetWithPublicFields) + "()", - ProducedBy = Tool.Analyzer)] + [ExpectedWarning ("IL2072", nameof (RequireAll2) + "(Type)", nameof (GetWithPublicMethods) + "()", Tool.Analyzer, "")] + [ExpectedWarning ("IL2072", nameof (RequireAll2) + "(Type)", nameof (GetWithPublicFields) + "()", Tool.Analyzer, "")] [ExpectedWarning ("IL2072", nameof (RequireAll2) + "(Type)", nameof (GetWithPublicProperties) + "()")] public static void FinallyInTryWithPredecessor () { @@ -724,20 +661,17 @@ public static void FinallyInTryWithPredecessor () } } - [ExpectedWarning ("IL2072", nameof (RequireAll1) + "(Type)", nameof (GetWithPublicMethods) + "()", - ProducedBy = Tool.Analyzer)] + [ExpectedWarning ("IL2072", nameof (RequireAll1) + "(Type)", nameof (GetWithPublicMethods) + "()", Tool.Analyzer, "")] [ExpectedWarning ("IL2072", nameof (RequireAll1) + "(Type)", nameof (GetWithPublicFields) + "()")] - [ExpectedWarning ("IL2072", nameof (RequireAll2) + "(Type)", nameof (GetWithPublicMethods) + "()", - ProducedBy = Tool.Analyzer)] + [ExpectedWarning ("IL2072", nameof (RequireAll2) + "(Type)", nameof (GetWithPublicMethods) + "()", Tool.Analyzer, "")] [ExpectedWarning ("IL2072", nameof (RequireAll2) + "(Type)", nameof (GetWithPublicFields) + "()")] [ExpectedWarning ("IL2072", nameof (RequireAll2) + "(Type)", nameof (GetWithPublicProperties) + "()")] [ExpectedWarning ("IL2072", nameof (RequireAll3) + "(Type)", nameof (GetWithPublicProperties) + "()")] // Trimmer merges branches going forward. - [ExpectedWarning ("IL2072", nameof (RequireAll3) + "(Type)", nameof (GetWithPublicFields) + "()", - ProducedBy = Tool.Trimmer | Tool.NativeAot)] + [ExpectedWarning ("IL2072", nameof (RequireAll3) + "(Type)", nameof (GetWithPublicFields) + "()", Tool.Trimmer | Tool.NativeAot, "")] public static void NestedFinally () { Type t = GetWithPublicMethods (); @@ -760,10 +694,8 @@ public static void NestedFinally () [ExpectedWarning ("IL2072", nameof (RequireAll4) + "(Type)", nameof (GetWithPublicFields) + "()")] // Trimmer merges branches going forward. - [ExpectedWarning ("IL2072", nameof (RequireAll3) + "(Type)", nameof (GetWithPublicMethods) + "()", - ProducedBy = Tool.Trimmer | Tool.NativeAot)] - [ExpectedWarning ("IL2072", nameof (RequireAll4) + "(Type)", nameof (GetWithPublicMethods) + "()", - ProducedBy = Tool.Trimmer | Tool.NativeAot)] + [ExpectedWarning ("IL2072", nameof (RequireAll3) + "(Type)", nameof (GetWithPublicMethods) + "()", Tool.Trimmer | Tool.NativeAot, "")] + [ExpectedWarning ("IL2072", nameof (RequireAll4) + "(Type)", nameof (GetWithPublicMethods) + "()", Tool.Trimmer | Tool.NativeAot, "")] public static void ChangeInFinallyNestedInFinally () { Type t = GetWithPublicMethods (); @@ -780,20 +712,17 @@ public static void ChangeInFinallyNestedInFinally () RequireAll4 (t); // fields only } - [ExpectedWarning ("IL2072", nameof (RequireAll1) + "(Type)", nameof (GetWithPublicMethods) + "()", - ProducedBy = Tool.Analyzer)] + [ExpectedWarning ("IL2072", nameof (RequireAll1) + "(Type)", nameof (GetWithPublicMethods) + "()", Tool.Analyzer, "")] [ExpectedWarning ("IL2072", nameof (RequireAll1) + "(Type)", nameof (GetWithPublicFields) + "()")] - [ExpectedWarning ("IL2072", nameof (RequireAll2) + "(Type)", nameof (GetWithPublicMethods) + "()", - ProducedBy = Tool.Analyzer)] + [ExpectedWarning ("IL2072", nameof (RequireAll2) + "(Type)", nameof (GetWithPublicMethods) + "()", Tool.Analyzer, "")] [ExpectedWarning ("IL2072", nameof (RequireAll2) + "(Type)", nameof (GetWithPublicFields) + "()")] [ExpectedWarning ("IL2072", nameof (RequireAll2) + "(Type)", nameof (GetWithPublicProperties) + "()")] [ExpectedWarning ("IL2072", nameof (RequireAll3) + "(Type)", nameof (GetWithPublicProperties) + "()")] // Trimmer merges branches going forward. - [ExpectedWarning ("IL2072", nameof (RequireAll3) + "(Type)", nameof (GetWithPublicFields) + "()", - ProducedBy = Tool.Trimmer | Tool.NativeAot)] + [ExpectedWarning ("IL2072", nameof (RequireAll3) + "(Type)", nameof (GetWithPublicFields) + "()", Tool.Trimmer | Tool.NativeAot, "")] public static void NestedFinallyWithPredecessor () { Type t = GetWithPublicMethods (); @@ -811,11 +740,9 @@ public static void NestedFinallyWithPredecessor () } } - [ExpectedWarning ("IL2072", nameof (RequireAllTrue) + "(Type)", nameof (GetWithPublicMethods) + "()", - ProducedBy = Tool.Analyzer)] + [ExpectedWarning ("IL2072", nameof (RequireAllTrue) + "(Type)", nameof (GetWithPublicMethods) + "()", Tool.Analyzer, "")] [ExpectedWarning ("IL2072", nameof (RequireAllTrue) + "(Type)", nameof (GetWithPublicFields) + "()")] - [ExpectedWarning ("IL2072", nameof (RequireAll) + "(Type)", nameof (GetWithPublicMethods) + "()", - ProducedBy = Tool.Analyzer)] + [ExpectedWarning ("IL2072", nameof (RequireAll) + "(Type)", nameof (GetWithPublicMethods) + "()", Tool.Analyzer, "")] [ExpectedWarning ("IL2072", nameof (RequireAll) + "(Type)", nameof (GetWithPublicFields) + "()")] public static void ExceptionFilter () { @@ -833,8 +760,7 @@ public static void ExceptionFilter () [ExpectedWarning ("IL2072", nameof (RequireAll2) + "(Type)", nameof (GetWithPublicFields) + "()")] // Trimmer merges branches going forward. - [ExpectedWarning ("IL2072", nameof (RequireAll) + "(Type)", nameof (GetWithPublicMethods) + "()", - ProducedBy = Tool.Trimmer | Tool.NativeAot)] + [ExpectedWarning ("IL2072", nameof (RequireAll) + "(Type)", nameof (GetWithPublicMethods) + "()", Tool.Trimmer | Tool.NativeAot, "")] public static void ExceptionFilterStateChange () { Type t = GetWithPublicMethods (); @@ -872,12 +798,9 @@ public static void ExceptionFilterStateChange () [ExpectedWarning ("IL2072", nameof (RequireAll6) + "(Type)", nameof (GetWithPublicProperties) + "()")] // Trimmer merges branches going forward. - [ExpectedWarning ("IL2072", nameof (RequireAll) + "(Type)", nameof (GetWithPublicMethods) + "()", - ProducedBy = Tool.Trimmer | Tool.NativeAot)] - [ExpectedWarning ("IL2072", nameof (RequireAll2) + "(Type)", nameof (GetWithPublicMethods) + "()", - ProducedBy = Tool.Trimmer | Tool.NativeAot)] - [ExpectedWarning ("IL2072", nameof (RequireAll2) + "(Type)", nameof (GetWithPublicFields) + "()", - ProducedBy = Tool.Trimmer | Tool.NativeAot)] + [ExpectedWarning ("IL2072", nameof (RequireAll) + "(Type)", nameof (GetWithPublicMethods) + "()", Tool.Trimmer | Tool.NativeAot, "")] + [ExpectedWarning ("IL2072", nameof (RequireAll2) + "(Type)", nameof (GetWithPublicMethods) + "()", Tool.Trimmer | Tool.NativeAot, "")] + [ExpectedWarning ("IL2072", nameof (RequireAll2) + "(Type)", nameof (GetWithPublicFields) + "()", Tool.Trimmer | Tool.NativeAot, "")] public static void ExceptionMultipleFilters () { Type t = GetWithPublicMethods (); @@ -908,8 +831,7 @@ public static void ExceptionMultipleFilters () [ExpectedWarning ("IL2072", nameof (RequireAll2) + "(Type)", nameof (GetWithPublicProperties))] // Trimmer merges branches going forward. - [ExpectedWarning ("IL2072", nameof (RequireAll) + "(Type)", nameof (GetWithPublicMethods), - ProducedBy = Tool.Trimmer | Tool.NativeAot)] + [ExpectedWarning ("IL2072", nameof (RequireAll) + "(Type)", nameof (GetWithPublicMethods), Tool.Trimmer | Tool.NativeAot, "")] public static void ExceptionFilterWithBranch () { Type t = GetWithPublicMethods (); diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/ExponentialDataFlow.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/ExponentialDataFlow.cs index 2f749beae0f813..a7715c507f2a32 100644 --- a/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/ExponentialDataFlow.cs +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/ExponentialDataFlow.cs @@ -58,7 +58,7 @@ class GenericTypeWithRequires<[DynamicallyAccessedMembers (DynamicallyAccessedMe { } - [ExpectedWarning ("IL3050", ProducedBy = Tool.Analyzer)] + [ExpectedWarning ("IL3050", Tool.Analyzer, "")] [ExpectedWarning ("IL2090", "'T'")] public static void Test () { @@ -94,32 +94,32 @@ class GenericTypeWithRequires< { } - [ExpectedWarning ("IL3050", ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3050", Tool.Analyzer | Tool.NativeAot, "")] // The way we track arrays causes the analyzer to track exponentially many // ArrayValues in the ValueSet for the pattern in this method, hitting the limit. // When this happens, we replace the ValueSet with an unknown value, producing // this warning. - [ExpectedWarning ("IL2055", ProducedBy = Tool.Analyzer)] - [ExpectedWarning ("IL2090", "'T'", ProducedBy = Tool.Trimmer | Tool.NativeAot)] - [ExpectedWarning ("IL2090", "'T'", ProducedBy = Tool.Trimmer | Tool.NativeAot)] - [ExpectedWarning ("IL2090", "'T'", ProducedBy = Tool.Trimmer | Tool.NativeAot)] - [ExpectedWarning ("IL2090", "'T'", ProducedBy = Tool.Trimmer | Tool.NativeAot)] - [ExpectedWarning ("IL2090", "'T'", ProducedBy = Tool.Trimmer | Tool.NativeAot)] - [ExpectedWarning ("IL2090", "'T'", ProducedBy = Tool.Trimmer | Tool.NativeAot)] - [ExpectedWarning ("IL2090", "'T'", ProducedBy = Tool.Trimmer | Tool.NativeAot)] - [ExpectedWarning ("IL2090", "'T'", ProducedBy = Tool.Trimmer | Tool.NativeAot)] - [ExpectedWarning ("IL2090", "'T'", ProducedBy = Tool.Trimmer | Tool.NativeAot)] - [ExpectedWarning ("IL2090", "'T'", ProducedBy = Tool.Trimmer | Tool.NativeAot)] - [ExpectedWarning ("IL2090", "'T'", ProducedBy = Tool.Trimmer | Tool.NativeAot)] - [ExpectedWarning ("IL2090", "'T'", ProducedBy = Tool.Trimmer | Tool.NativeAot)] - [ExpectedWarning ("IL2090", "'T'", ProducedBy = Tool.Trimmer | Tool.NativeAot)] - [ExpectedWarning ("IL2090", "'T'", ProducedBy = Tool.Trimmer | Tool.NativeAot)] - [ExpectedWarning ("IL2090", "'T'", ProducedBy = Tool.Trimmer | Tool.NativeAot)] - [ExpectedWarning ("IL2090", "'T'", ProducedBy = Tool.Trimmer | Tool.NativeAot)] - [ExpectedWarning ("IL2090", "'T'", ProducedBy = Tool.Trimmer | Tool.NativeAot)] - [ExpectedWarning ("IL2090", "'T'", ProducedBy = Tool.Trimmer | Tool.NativeAot)] - [ExpectedWarning ("IL2090", "'T'", ProducedBy = Tool.Trimmer | Tool.NativeAot)] - [ExpectedWarning ("IL2090", "'T'", ProducedBy = Tool.Trimmer | Tool.NativeAot)] + [ExpectedWarning ("IL2055", Tool.Analyzer, "")] + [ExpectedWarning ("IL2090", "'T'", Tool.Trimmer | Tool.NativeAot, "")] + [ExpectedWarning ("IL2090", "'T'", Tool.Trimmer | Tool.NativeAot, "")] + [ExpectedWarning ("IL2090", "'T'", Tool.Trimmer | Tool.NativeAot, "")] + [ExpectedWarning ("IL2090", "'T'", Tool.Trimmer | Tool.NativeAot, "")] + [ExpectedWarning ("IL2090", "'T'", Tool.Trimmer | Tool.NativeAot, "")] + [ExpectedWarning ("IL2090", "'T'", Tool.Trimmer | Tool.NativeAot, "")] + [ExpectedWarning ("IL2090", "'T'", Tool.Trimmer | Tool.NativeAot, "")] + [ExpectedWarning ("IL2090", "'T'", Tool.Trimmer | Tool.NativeAot, "")] + [ExpectedWarning ("IL2090", "'T'", Tool.Trimmer | Tool.NativeAot, "")] + [ExpectedWarning ("IL2090", "'T'", Tool.Trimmer | Tool.NativeAot, "")] + [ExpectedWarning ("IL2090", "'T'", Tool.Trimmer | Tool.NativeAot, "")] + [ExpectedWarning ("IL2090", "'T'", Tool.Trimmer | Tool.NativeAot, "")] + [ExpectedWarning ("IL2090", "'T'", Tool.Trimmer | Tool.NativeAot, "")] + [ExpectedWarning ("IL2090", "'T'", Tool.Trimmer | Tool.NativeAot, "")] + [ExpectedWarning ("IL2090", "'T'", Tool.Trimmer | Tool.NativeAot, "")] + [ExpectedWarning ("IL2090", "'T'", Tool.Trimmer | Tool.NativeAot, "")] + [ExpectedWarning ("IL2090", "'T'", Tool.Trimmer | Tool.NativeAot, "")] + [ExpectedWarning ("IL2090", "'T'", Tool.Trimmer | Tool.NativeAot, "")] + [ExpectedWarning ("IL2090", "'T'", Tool.Trimmer | Tool.NativeAot, "")] + [ExpectedWarning ("IL2090", "'T'", Tool.Trimmer | Tool.NativeAot, "")] public static void Test () { Type[] types = new Type[20] { diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/FeatureCheckDataFlow.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/FeatureCheckDataFlow.cs index 8c8c3baf5ab5c6..ab94f5052d4294 100644 --- a/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/FeatureCheckDataFlow.cs +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/FeatureCheckDataFlow.cs @@ -40,8 +40,8 @@ public static void Main () class CallFeatureUnguarded { [ExpectedWarning ("IL2026", nameof (RequiresUnreferencedCode))] - [ExpectedWarning ("IL3050", nameof (RequiresDynamicCode), ProducedBy = Tool.Analyzer | Tool.NativeAot)] - [ExpectedWarning ("IL3002", nameof (RequiresAssemblyFiles), ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3050", nameof (RequiresDynamicCode), Tool.Analyzer | Tool.NativeAot, "")] + [ExpectedWarning ("IL3002", nameof (RequiresAssemblyFiles), Tool.Analyzer | Tool.NativeAot, "")] static void Unguarded () { RequiresUnreferencedCode (); @@ -50,8 +50,8 @@ static void Unguarded () } [ExpectedWarning ("IL2026", nameof (RequiresUnreferencedCode))] - [ExpectedWarning ("IL3050", nameof (RequiresDynamicCode), ProducedBy = Tool.Analyzer | Tool.NativeAot)] - [ExpectedWarning ("IL3002", nameof (RequiresAssemblyFiles), ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3050", nameof (RequiresDynamicCode), Tool.Analyzer | Tool.NativeAot, "")] + [ExpectedWarning ("IL3002", nameof (RequiresAssemblyFiles), Tool.Analyzer | Tool.NativeAot, "")] static void UnguardedIf () { if (!TestFeatures.IsUnreferencedCodeSupported) { @@ -62,8 +62,8 @@ static void UnguardedIf () } [ExpectedWarning ("IL2026", nameof (RequiresUnreferencedCode))] - [ExpectedWarning ("IL3050", nameof (RequiresDynamicCode), ProducedBy = Tool.Analyzer | Tool.NativeAot)] - [ExpectedWarning ("IL3002", nameof (RequiresAssemblyFiles), ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3050", nameof (RequiresDynamicCode), Tool.Analyzer | Tool.NativeAot, "")] + [ExpectedWarning ("IL3002", nameof (RequiresAssemblyFiles), Tool.Analyzer | Tool.NativeAot, "")] static void UnguardedElse () { if (TestFeatures.IsUnreferencedCodeSupported) @@ -99,8 +99,8 @@ static void UnguardedTernary () } [ExpectedWarning ("IL2026", nameof (RequiresUnreferencedCode))] - [ExpectedWarning ("IL3050", nameof (RequiresDynamicCode), ProducedBy = Tool.Analyzer | Tool.NativeAot)] - [ExpectedWarning ("IL3002", nameof (RequiresAssemblyFiles), ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3050", nameof (RequiresDynamicCode), Tool.Analyzer | Tool.NativeAot, "")] + [ExpectedWarning ("IL3002", nameof (RequiresAssemblyFiles), Tool.Analyzer | Tool.NativeAot, "")] static void UnguardedThrow () { if (TestFeatures.IsUnreferencedCodeSupported) @@ -114,8 +114,8 @@ static void UnguardedThrow () } [ExpectedWarning ("IL2026", nameof (RequiresUnreferencedCode))] - [ExpectedWarning ("IL3050", nameof (RequiresDynamicCode), ProducedBy = Tool.Analyzer | Tool.NativeAot)] - [ExpectedWarning ("IL3002", nameof (RequiresAssemblyFiles), ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3050", nameof (RequiresDynamicCode), Tool.Analyzer | Tool.NativeAot, "")] + [ExpectedWarning ("IL3002", nameof (RequiresAssemblyFiles), Tool.Analyzer | Tool.NativeAot, "")] static void UnguardedReturn () { if (TestFeatures.IsUnreferencedCodeSupported) @@ -205,8 +205,8 @@ public static void Test () GuardedDoesNotReturnIfFalseCtor (); } - [ExpectedWarning ("IL3050", nameof (RequiresDynamicCode), ProducedBy = Tool.Analyzer)] - [ExpectedWarning ("IL3002", nameof (RequiresAssemblyFiles), ProducedBy = Tool.Analyzer)] + [ExpectedWarning ("IL3050", nameof (RequiresDynamicCode), Tool.Analyzer, "")] + [ExpectedWarning ("IL3002", nameof (RequiresAssemblyFiles), Tool.Analyzer, "")] static void GuardedIf () { if (TestFeatures.IsUnreferencedCodeSupported) { @@ -216,8 +216,8 @@ static void GuardedIf () } } - [ExpectedWarning ("IL3050", nameof (RequiresDynamicCode), ProducedBy = Tool.Analyzer)] - [ExpectedWarning ("IL3002", nameof (RequiresAssemblyFiles), ProducedBy = Tool.Analyzer)] + [ExpectedWarning ("IL3050", nameof (RequiresDynamicCode), Tool.Analyzer, "")] + [ExpectedWarning ("IL3002", nameof (RequiresAssemblyFiles), Tool.Analyzer, "")] static void GuardedElse () { if (!TestFeatures.IsUnreferencedCodeSupported) @@ -248,8 +248,8 @@ static void GuardedTernary () var b = !TestFeatures.IsUnreferencedCodeSupported ? true : RequiresUnreferencedCodeBool (); } - [ExpectedWarning ("IL3050", nameof (RequiresDynamicCode), ProducedBy = Tool.Analyzer)] - [ExpectedWarning ("IL3002", nameof (RequiresAssemblyFiles), ProducedBy = Tool.Analyzer)] + [ExpectedWarning ("IL3050", nameof (RequiresDynamicCode), Tool.Analyzer, "")] + [ExpectedWarning ("IL3002", nameof (RequiresAssemblyFiles), Tool.Analyzer, "")] static void GuardedThrow () { if (!TestFeatures.IsUnreferencedCodeSupported) @@ -262,8 +262,8 @@ static void GuardedThrow () RequiresAssemblyFiles (); } - [ExpectedWarning ("IL3050", nameof (RequiresDynamicCode), ProducedBy = Tool.Analyzer)] - [ExpectedWarning ("IL3002", nameof (RequiresAssemblyFiles), ProducedBy = Tool.Analyzer)] + [ExpectedWarning ("IL3050", nameof (RequiresDynamicCode), Tool.Analyzer, "")] + [ExpectedWarning ("IL3002", nameof (RequiresAssemblyFiles), Tool.Analyzer, "")] static void GuardedReturn () { if (!TestFeatures.IsUnreferencedCodeSupported) @@ -277,7 +277,7 @@ static void GuardedReturn () } // Trimmer/NativeAot don't optimize branches away based on DoesNotReturnIfAttribute - [ExpectedWarning ("IL2026", nameof (RequiresUnreferencedCode), ProducedBy = Tool.Trimmer | Tool.NativeAot)] + [ExpectedWarning ("IL2026", nameof (RequiresUnreferencedCode), Tool.Trimmer | Tool.NativeAot, "")] static void GuardedAssert () { Debug.Assert (TestFeatures.IsUnreferencedCodeSupported); @@ -286,7 +286,7 @@ static void GuardedAssert () } // Trimmer/NativeAot don't optimize branches away based on DoesNotReturnIfAttribute - [ExpectedWarning ("IL2026", nameof (RequiresUnreferencedCode), ProducedBy = Tool.Trimmer | Tool.NativeAot)] + [ExpectedWarning ("IL2026", nameof (RequiresUnreferencedCode), Tool.Trimmer | Tool.NativeAot, "")] static void GuardedDoesNotReturnIfTrue () { DoesNotReturnIfTrue (!TestFeatures.IsUnreferencedCodeSupported); @@ -295,7 +295,7 @@ static void GuardedDoesNotReturnIfTrue () } // Trimmer/NativeAot don't optimize branches away based on DoesNotReturnIfAttribute - [ExpectedWarning ("IL2026", nameof (RequiresUnreferencedCode), ProducedBy = Tool.Trimmer | Tool.NativeAot)] + [ExpectedWarning ("IL2026", nameof (RequiresUnreferencedCode), Tool.Trimmer | Tool.NativeAot, "")] static void GuardedDoesNotReturnIfFalse () { DoesNotReturnIfFalse (TestFeatures.IsUnreferencedCodeSupported); @@ -304,7 +304,7 @@ static void GuardedDoesNotReturnIfFalse () } // Trimmer/NativeAot don't optimize branches away based on DoesNotReturnIfAttribute - [ExpectedWarning ("IL2026", nameof (RequiresUnreferencedCode), ProducedBy = Tool.Trimmer | Tool.NativeAot)] + [ExpectedWarning ("IL2026", nameof (RequiresUnreferencedCode), Tool.Trimmer | Tool.NativeAot, "")] static void GuardedDoesNotReturn () { if (!TestFeatures.IsUnreferencedCodeSupported) @@ -314,7 +314,7 @@ static void GuardedDoesNotReturn () } // Trimmer/NativeAot don't optimize branches away based on DoesNotReturnIfAttribute - [ExpectedWarning ("IL2026", nameof (RequiresUnreferencedCode), ProducedBy = Tool.Trimmer | Tool.NativeAot)] + [ExpectedWarning ("IL2026", nameof (RequiresUnreferencedCode), Tool.Trimmer | Tool.NativeAot, "")] static void GuardedDoesNotReturnIfFalseCtor () { new DoesNotReturnIfFalseCtor (TestFeatures.IsUnreferencedCodeSupported); @@ -326,8 +326,8 @@ static void GuardedDoesNotReturnIfFalseCtor () class FeatureCheckBooleanExpressions { // Trimmer/NativeAot aren't able to optimize away the branch in this case. - [ExpectedWarning ("IL2026", nameof (RequiresUnreferencedCode), ProducedBy = Tool.Trimmer | Tool.NativeAot)] - [ExpectedWarning ("IL3050", nameof (RequiresDynamicCode), ProducedBy = Tool.NativeAot)] + [ExpectedWarning ("IL2026", nameof (RequiresUnreferencedCode), Tool.Trimmer | Tool.NativeAot, "")] + [ExpectedWarning ("IL3050", nameof (RequiresDynamicCode), Tool.NativeAot, "")] static void And () { if (TestFeatures.IsUnreferencedCodeSupported && RuntimeFeature.IsDynamicCodeSupported) { @@ -337,7 +337,7 @@ static void And () } [ExpectedWarning ("IL2026", nameof (RequiresUnreferencedCode))] - [ExpectedWarning ("IL3050", nameof (RequiresDynamicCode), ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3050", nameof (RequiresDynamicCode), Tool.Analyzer | Tool.NativeAot, "")] static void AndNot () { if (!TestFeatures.IsUnreferencedCodeSupported && !RuntimeFeature.IsDynamicCodeSupported) @@ -348,8 +348,8 @@ static void AndNot () } // Trimmer/NativeAot aren't able to optimize away the branch in this case. - [ExpectedWarning ("IL2026", nameof (RequiresUnreferencedCode), ProducedBy = Tool.Trimmer | Tool.NativeAot)] - [ExpectedWarning ("IL3050", nameof (RequiresDynamicCode), ProducedBy = Tool.NativeAot)] + [ExpectedWarning ("IL2026", nameof (RequiresUnreferencedCode), Tool.Trimmer | Tool.NativeAot, "")] + [ExpectedWarning ("IL3050", nameof (RequiresDynamicCode), Tool.NativeAot, "")] static void NotAnd () { if (!(TestFeatures.IsUnreferencedCodeSupported && RuntimeFeature.IsDynamicCodeSupported)) @@ -360,7 +360,7 @@ static void NotAnd () } [ExpectedWarning ("IL2026", nameof (RequiresUnreferencedCode))] - [ExpectedWarning ("IL3050", nameof (RequiresDynamicCode), ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3050", nameof (RequiresDynamicCode), Tool.Analyzer | Tool.NativeAot, "")] static void Or () { if (TestFeatures.IsUnreferencedCodeSupported || RuntimeFeature.IsDynamicCodeSupported) { @@ -370,8 +370,8 @@ static void Or () } // Trimmer/NativeAot aren't able to optimize away the branch in this case. - [ExpectedWarning ("IL2026", nameof (RequiresUnreferencedCode), ProducedBy = Tool.Trimmer | Tool.NativeAot)] - [ExpectedWarning ("IL3050", nameof (RequiresDynamicCode), ProducedBy = Tool.NativeAot)] + [ExpectedWarning ("IL2026", nameof (RequiresUnreferencedCode), Tool.Trimmer | Tool.NativeAot, "")] + [ExpectedWarning ("IL3050", nameof (RequiresDynamicCode), Tool.NativeAot, "")] static void OrNot () { if (!TestFeatures.IsUnreferencedCodeSupported || !RuntimeFeature.IsDynamicCodeSupported) @@ -382,7 +382,7 @@ static void OrNot () } [ExpectedWarning ("IL2026", nameof (RequiresUnreferencedCode))] - [ExpectedWarning ("IL3050", nameof (RequiresDynamicCode), ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3050", nameof (RequiresDynamicCode), Tool.Analyzer | Tool.NativeAot, "")] static void NotOr () { if (!(TestFeatures.IsUnreferencedCodeSupported || RuntimeFeature.IsDynamicCodeSupported)) @@ -477,7 +477,7 @@ static void IsNotFalse () } [ExpectedWarning ("IL2026", nameof (RequiresUnreferencedCode))] - [ExpectedWarning ("IL2026", nameof (RequiresUnreferencedCode), ProducedBy = Tool.Trimmer | Tool.NativeAot)] + [ExpectedWarning ("IL2026", nameof (RequiresUnreferencedCode), Tool.Trimmer | Tool.NativeAot, "")] static void Contradiction () { if (TestFeatures.IsUnreferencedCodeSupported && !TestFeatures.IsUnreferencedCodeSupported) { @@ -532,7 +532,7 @@ static void CallTestDynamicCodeGuarded () RequiresDynamicCode (); } - [ExpectedWarning ("IL3050", nameof (RequiresDynamicCode), ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3050", nameof (RequiresDynamicCode), Tool.Analyzer | Tool.NativeAot, "")] static void CallTestDynamicCodeUnguarded () { RequiresDynamicCode (); @@ -545,7 +545,7 @@ static void CallTestAssemblyFilesGuarded () } } - [ExpectedWarning ("IL3002", nameof (RequiresAssemblyFiles), ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3002", nameof (RequiresAssemblyFiles), Tool.Analyzer | Tool.NativeAot, "")] static void CallTestAssemblyFilesUnguarded () { RequiresAssemblyFiles (); @@ -564,9 +564,9 @@ public static void Test () class FeatureCheckCombinations { - [ExpectedWarning ("IL3050", nameof (RequiresDynamicCode), ProducedBy = Tool.Analyzer)] + [ExpectedWarning ("IL3050", nameof (RequiresDynamicCode), Tool.Analyzer, "")] // Trimmer warns because IsDynamicCodeSupported is not a constant, so the call is reachable. - [ExpectedWarning ("IL2026", nameof (RequiresUnreferencedCode), ProducedBy = Tool.Analyzer | Tool.Trimmer)] + [ExpectedWarning ("IL2026", nameof (RequiresUnreferencedCode), Tool.Analyzer | Tool.Trimmer, "")] static void MeetFeaturesEmptyIntersection (bool b = true) { if (b) { @@ -582,7 +582,7 @@ static void MeetFeaturesEmptyIntersection (bool b = true) // Shows that ILLink has the same branch removal as NativeAot for this pattern, when // the branches both use a feature check that's substituted by ILLink. - [ExpectedWarning ("IL3050", nameof (RequiresDynamicCode), ProducedBy = Tool.Analyzer)] + [ExpectedWarning ("IL3050", nameof (RequiresDynamicCode), Tool.Analyzer, "")] static void MeetFeaturesEmptyIntersection_IdenticalBranches (bool b = true) { if (b) { @@ -596,7 +596,7 @@ static void MeetFeaturesEmptyIntersection_IdenticalBranches (bool b = true) RequiresDynamicCode (); } - [ExpectedWarning ("IL3050", nameof (RequiresDynamicCode), ProducedBy = Tool.Analyzer)] + [ExpectedWarning ("IL3050", nameof (RequiresDynamicCode), Tool.Analyzer, "")] static void MeetFeaturesIntersection (bool b = true) { if (b) { @@ -622,7 +622,7 @@ static void IntroduceFeature () } } - [ExpectedWarning ("IL3002", nameof (RequiresAssemblyFiles), ProducedBy = Tool.Analyzer)] + [ExpectedWarning ("IL3002", nameof (RequiresAssemblyFiles), Tool.Analyzer, "")] static void RemoveFeature () { if (TestFeatures.IsUnreferencedCodeSupported) { @@ -787,7 +787,7 @@ static void NestedTryInCheckInFinally () [ExpectedWarning ("IL2026", nameof (RequiresUnreferencedCode0))] // Trimmer/NativeAot don't optimize branches away based on DoesNotReturnIfAttribute - [ExpectedWarning ("IL2026", nameof (RequiresUnreferencedCode1), ProducedBy = Tool.Trimmer | Tool.NativeAot)] + [ExpectedWarning ("IL2026", nameof (RequiresUnreferencedCode1), Tool.Trimmer | Tool.NativeAot, "")] static void AssertInTryNoCatch () { try { Debug.Assert (TestFeatures.IsUnreferencedCodeSupported); @@ -828,7 +828,7 @@ static void AssertInCatch () { [ExpectedWarning ("IL2026", nameof (RequiresUnreferencedCode0))] [ExpectedWarning ("IL2026", nameof (RequiresUnreferencedCode1))] // Trimmer/NativeAot don't optimize branches away based on DoesNotReturnIfAttribute - [ExpectedWarning ("IL2026", nameof (RequiresUnreferencedCode2), ProducedBy = Tool.Trimmer | Tool.NativeAot)] + [ExpectedWarning ("IL2026", nameof (RequiresUnreferencedCode2), Tool.Trimmer | Tool.NativeAot, "")] static void AssertInFinally () { try { RequiresUnreferencedCode0 (); @@ -843,8 +843,8 @@ static void AssertInFinally () { [ExpectedWarning ("IL2026", nameof (RequiresUnreferencedCode0))] [ExpectedWarning ("IL2026", nameof (RequiresUnreferencedCode2))] // Trimmer/NativeAot don't optimize branches away based on DoesNotReturnIfAttribute - [ExpectedWarning ("IL2026", nameof (RequiresUnreferencedCode1), ProducedBy = Tool.Trimmer | Tool.NativeAot)] - [ExpectedWarning ("IL2026", nameof (RequiresUnreferencedCode3), ProducedBy = Tool.Trimmer | Tool.NativeAot)] + [ExpectedWarning ("IL2026", nameof (RequiresUnreferencedCode1), Tool.Trimmer | Tool.NativeAot, "")] + [ExpectedWarning ("IL2026", nameof (RequiresUnreferencedCode3), Tool.Trimmer | Tool.NativeAot, "")] static void AssertInTryNestedInTry () { try { @@ -885,8 +885,8 @@ static void AssertInTryWithCatchNestedInTry () [ExpectedWarning ("IL2026", nameof (RequiresUnreferencedCode0))] [ExpectedWarning ("IL2026", nameof (RequiresUnreferencedCode1))] // Trimmer/NativeAot don't optimize branches away based on DoesNotReturnIfAttribute - [ExpectedWarning ("IL2026", nameof (RequiresUnreferencedCode2), ProducedBy = Tool.Trimmer | Tool.NativeAot)] - [ExpectedWarning ("IL2026", nameof (RequiresUnreferencedCode3), ProducedBy = Tool.Trimmer | Tool.NativeAot)] + [ExpectedWarning ("IL2026", nameof (RequiresUnreferencedCode2), Tool.Trimmer | Tool.NativeAot, "")] + [ExpectedWarning ("IL2026", nameof (RequiresUnreferencedCode3), Tool.Trimmer | Tool.NativeAot, "")] static void AssertInTryNestedInFinally () { try { @@ -925,8 +925,8 @@ static void AssertInTryWithCatchNestedInFinally () [ExpectedWarning ("IL2026", nameof (RequiresUnreferencedCode0))] [ExpectedWarning ("IL2026", nameof (RequiresUnreferencedCode2))] // Trimmer/NativeAot don't optimize branches away based on DoesNotReturnIfAttribute - [ExpectedWarning ("IL2026", nameof (RequiresUnreferencedCode1), ProducedBy = Tool.Trimmer | Tool.NativeAot)] - [ExpectedWarning ("IL2026", nameof (RequiresUnreferencedCode3), ProducedBy = Tool.Trimmer | Tool.NativeAot)] + [ExpectedWarning ("IL2026", nameof (RequiresUnreferencedCode1), Tool.Trimmer | Tool.NativeAot, "")] + [ExpectedWarning ("IL2026", nameof (RequiresUnreferencedCode3), Tool.Trimmer | Tool.NativeAot, "")] static void AssertInFinallyNestedInTry () { try { try { @@ -944,8 +944,8 @@ static void AssertInFinallyNestedInTry () { [ExpectedWarning ("IL2026", nameof (RequiresUnreferencedCode0))] [ExpectedWarning ("IL2026", nameof (RequiresUnreferencedCode2))] // Trimmer/NativeAot don't optimize branches away based on DoesNotReturnIfAttribute - [ExpectedWarning ("IL2026", nameof (RequiresUnreferencedCode1), ProducedBy = Tool.Trimmer | Tool.NativeAot)] - [ExpectedWarning ("IL2026", nameof (RequiresUnreferencedCode3), ProducedBy = Tool.Trimmer | Tool.NativeAot)] + [ExpectedWarning ("IL2026", nameof (RequiresUnreferencedCode1), Tool.Trimmer | Tool.NativeAot, "")] + [ExpectedWarning ("IL2026", nameof (RequiresUnreferencedCode3), Tool.Trimmer | Tool.NativeAot, "")] static void AssertInFinallyWithCatchNestedInTry () { try { try { @@ -965,8 +965,8 @@ static void AssertInFinallyWithCatchNestedInTry () { [ExpectedWarning ("IL2026", nameof (RequiresUnreferencedCode0))] [ExpectedWarning ("IL2026", nameof (RequiresUnreferencedCode1))] // Trimmer/NativeAot don't optimize branches away based on DoesNotReturnIfAttribute - [ExpectedWarning ("IL2026", nameof (RequiresUnreferencedCode2), ProducedBy = Tool.Trimmer | Tool.NativeAot)] - [ExpectedWarning ("IL2026", nameof (RequiresUnreferencedCode3), ProducedBy = Tool.Trimmer | Tool.NativeAot)] + [ExpectedWarning ("IL2026", nameof (RequiresUnreferencedCode2), Tool.Trimmer | Tool.NativeAot, "")] + [ExpectedWarning ("IL2026", nameof (RequiresUnreferencedCode3), Tool.Trimmer | Tool.NativeAot, "")] static void AssertInFinallyNestedInFinally () { try { @@ -985,8 +985,8 @@ static void AssertInFinallyNestedInFinally () [ExpectedWarning ("IL2026", nameof (RequiresUnreferencedCode0))] [ExpectedWarning ("IL2026", nameof (RequiresUnreferencedCode1))] // Trimmer/NativeAot doesn't optimize branches away based on DoesNotReturnIfAttribute - [ExpectedWarning ("IL2026", nameof (RequiresUnreferencedCode2), ProducedBy = Tool.Trimmer | Tool.NativeAot)] - [ExpectedWarning ("IL2026", nameof (RequiresUnreferencedCode3), ProducedBy = Tool.Trimmer | Tool.NativeAot)] + [ExpectedWarning ("IL2026", nameof (RequiresUnreferencedCode2), Tool.Trimmer | Tool.NativeAot, "")] + [ExpectedWarning ("IL2026", nameof (RequiresUnreferencedCode3), Tool.Trimmer | Tool.NativeAot, "")] static void AssertInFinallyWithCatchNestedInFinally () { try { @@ -1056,8 +1056,7 @@ static IEnumerable GuardInIterator () } } - [ExpectedWarning ("IL2026", nameof (RequiresUnreferencedCode), ProducedBy = Tool.Trimmer, - CompilerGeneratedCode = true)] + [ExpectedWarning ("IL2026", nameof (RequiresUnreferencedCode), Tool.Trimmer, "", CompilerGeneratedCode = true)] static IEnumerable StateFlowsAcrossYield () { if (!TestFeatures.IsUnreferencedCodeSupported) @@ -1076,8 +1075,7 @@ static async Task GuardInAsync () } } - [ExpectedWarning ("IL2026", nameof (RequiresUnreferencedCode), ProducedBy = Tool.Trimmer | Tool.NativeAot, - CompilerGeneratedCode = true)] + [ExpectedWarning ("IL2026", nameof (RequiresUnreferencedCode), Tool.Trimmer | Tool.NativeAot, "", CompilerGeneratedCode = true)] static async Task StateFlowsAcrossAwait () { if (!TestFeatures.IsUnreferencedCodeSupported) @@ -1097,8 +1095,7 @@ static async IAsyncEnumerable GuardInAsyncIterator () } } - [ExpectedWarning ("IL2026", nameof (RequiresUnreferencedCode), ProducedBy = Tool.Trimmer | Tool.NativeAot, - CompilerGeneratedCode = true)] + [ExpectedWarning ("IL2026", nameof (RequiresUnreferencedCode), Tool.Trimmer | Tool.NativeAot, "", CompilerGeneratedCode = true)] static async IAsyncEnumerable StateFlowsAcrossAwaitAndYield () { if (!TestFeatures.IsUnreferencedCodeSupported) diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/FeatureGuardAttributeDataFlow.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/FeatureGuardAttributeDataFlow.cs index f4daacec7a0e1d..6b0e605ac7730d 100644 --- a/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/FeatureGuardAttributeDataFlow.cs +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/FeatureGuardAttributeDataFlow.cs @@ -65,7 +65,7 @@ static void TestIndirectGuard () // // The analyzer doesn't do constant propagation of the boolean, so it doesn't know that // the return value is always false when TestFeatures.IsUnreferencedCodeSupported is false. - [ExpectedWarning ("IL4000", nameof (RequiresUnreferencedCodeAttribute), ProducedBy = Tool.Analyzer)] + [ExpectedWarning ("IL4000", nameof (RequiresUnreferencedCodeAttribute), Tool.Analyzer, "")] [FeatureGuard (typeof(RequiresUnreferencedCodeAttribute))] static bool AndGuard => TestFeatures.IsUnreferencedCodeSupported && OtherCondition (); @@ -138,7 +138,7 @@ static void TestIsNotFalseGuard () RequiresUnreferencedCode (); } - [ExpectedWarning ("IL4000", nameof (RequiresUnreferencedCodeAttribute), ProducedBy = Tool.Analyzer)] + [ExpectedWarning ("IL4000", nameof (RequiresUnreferencedCodeAttribute), Tool.Analyzer, "")] [FeatureGuard (typeof(RequiresUnreferencedCodeAttribute))] static bool IfReturnTrueGuard { get { @@ -148,7 +148,7 @@ static bool IfReturnTrueGuard { } } - [ExpectedWarning ("IL4000", nameof (RequiresUnreferencedCodeAttribute), ProducedBy = Tool.Analyzer)] + [ExpectedWarning ("IL4000", nameof (RequiresUnreferencedCodeAttribute), Tool.Analyzer, "")] [FeatureGuard (typeof(RequiresUnreferencedCodeAttribute))] static bool ElseReturnTrueGuard { get { @@ -199,7 +199,7 @@ static void TestAssertNotReturnFalseGuard () RequiresUnreferencedCode (); } - [ExpectedWarning ("IL4000", nameof (RequiresUnreferencedCodeAttribute), ProducedBy = Tool.Analyzer)] + [ExpectedWarning ("IL4000", nameof (RequiresUnreferencedCodeAttribute), Tool.Analyzer, "")] [FeatureGuard (typeof (RequiresUnreferencedCodeAttribute))] static bool AssertReturnTrueGuard { get { @@ -229,7 +229,7 @@ static void TestThrowGuard () RequiresUnreferencedCode (); } - [ExpectedWarning ("IL4000", nameof (RequiresUnreferencedCodeAttribute), ProducedBy = Tool.Analyzer)] + [ExpectedWarning ("IL4000", nameof (RequiresUnreferencedCodeAttribute), Tool.Analyzer, "")] [FeatureGuard (typeof(RequiresUnreferencedCodeAttribute))] static bool TernaryIfGuard => TestFeatures.IsUnreferencedCodeSupported ? true : false; @@ -239,7 +239,7 @@ static void TestTernaryIfGuard () RequiresUnreferencedCode (); } - [ExpectedWarning ("IL4000", nameof (RequiresUnreferencedCodeAttribute), ProducedBy = Tool.Analyzer)] + [ExpectedWarning ("IL4000", nameof (RequiresUnreferencedCodeAttribute), Tool.Analyzer, "")] [FeatureGuard (typeof(RequiresUnreferencedCodeAttribute))] static bool TernaryElseGuard => !TestFeatures.IsUnreferencedCodeSupported ? false : true; @@ -275,7 +275,7 @@ public static void Test () } class InvalidGuardBodies { - [ExpectedWarning ("IL4000", nameof (RequiresUnreferencedCodeAttribute), ProducedBy = Tool.Analyzer)] + [ExpectedWarning ("IL4000", nameof (RequiresUnreferencedCodeAttribute), Tool.Analyzer, "")] [FeatureGuard (typeof(RequiresUnreferencedCodeAttribute))] static bool ReturnTrueGuard => true; @@ -285,7 +285,7 @@ static void TestReturnTrueGuard () RequiresUnreferencedCode (); } - [ExpectedWarning ("IL4000", nameof (RequiresUnreferencedCodeAttribute), ProducedBy = Tool.Analyzer)] + [ExpectedWarning ("IL4000", nameof (RequiresUnreferencedCodeAttribute), Tool.Analyzer, "")] [FeatureGuard (typeof(RequiresUnreferencedCodeAttribute))] static bool OtherConditionGuard => OtherCondition (); @@ -295,7 +295,7 @@ static void TestOtherConditionGuard () RequiresUnreferencedCode (); } - [ExpectedWarning ("IL4000", nameof (RequiresUnreferencedCodeAttribute), ProducedBy = Tool.Analyzer)] + [ExpectedWarning ("IL4000", nameof (RequiresUnreferencedCodeAttribute), Tool.Analyzer, "")] [FeatureGuard (typeof(RequiresUnreferencedCodeAttribute))] static bool OrGuard => TestFeatures.IsUnreferencedCodeSupported || OtherCondition (); @@ -305,7 +305,7 @@ static void TestOrGuard () RequiresUnreferencedCode (); } - [ExpectedWarning ("IL4000", nameof (RequiresUnreferencedCodeAttribute), ProducedBy = Tool.Analyzer)] + [ExpectedWarning ("IL4000", nameof (RequiresUnreferencedCodeAttribute), Tool.Analyzer, "")] [FeatureGuard (typeof(RequiresUnreferencedCodeAttribute))] static bool NotGuard => !TestFeatures.IsUnreferencedCodeSupported; @@ -315,7 +315,7 @@ static void TestNotGuard () RequiresUnreferencedCode (); } - [ExpectedWarning ("IL4000", nameof (RequiresUnreferencedCodeAttribute), ProducedBy = Tool.Analyzer)] + [ExpectedWarning ("IL4000", nameof (RequiresUnreferencedCodeAttribute), Tool.Analyzer, "")] [FeatureGuard (typeof(RequiresUnreferencedCodeAttribute))] static bool EqualsFalseGuard => TestFeatures.IsUnreferencedCodeSupported == false; @@ -325,7 +325,7 @@ static void TestEqualsFalseGuard () RequiresUnreferencedCode (); } - [ExpectedWarning ("IL4000", nameof (RequiresUnreferencedCodeAttribute), ProducedBy = Tool.Analyzer)] + [ExpectedWarning ("IL4000", nameof (RequiresUnreferencedCodeAttribute), Tool.Analyzer, "")] [FeatureGuard (typeof(RequiresUnreferencedCodeAttribute))] static bool FalseEqualsGuard => false == TestFeatures.IsUnreferencedCodeSupported; @@ -335,7 +335,7 @@ static void TestFalseEqualsGuard () RequiresUnreferencedCode (); } - [ExpectedWarning ("IL4000", nameof (RequiresUnreferencedCodeAttribute), ProducedBy = Tool.Analyzer)] + [ExpectedWarning ("IL4000", nameof (RequiresUnreferencedCodeAttribute), Tool.Analyzer, "")] [FeatureGuard (typeof(RequiresUnreferencedCodeAttribute))] static bool NotEqualsTrueGuard => TestFeatures.IsUnreferencedCodeSupported != true; @@ -345,7 +345,7 @@ static void TestNotEqualsTrueGuard () RequiresUnreferencedCode (); } - [ExpectedWarning ("IL4000", nameof (RequiresUnreferencedCodeAttribute), ProducedBy = Tool.Analyzer)] + [ExpectedWarning ("IL4000", nameof (RequiresUnreferencedCodeAttribute), Tool.Analyzer, "")] [FeatureGuard (typeof(RequiresUnreferencedCodeAttribute))] static bool TrueNotEqualsGuard => true != TestFeatures.IsUnreferencedCodeSupported; @@ -355,7 +355,7 @@ static void TestTrueNotEqualsGuard () RequiresUnreferencedCode (); } - [ExpectedWarning ("IL4000", nameof (RequiresUnreferencedCodeAttribute), ProducedBy = Tool.Analyzer)] + [ExpectedWarning ("IL4000", nameof (RequiresUnreferencedCodeAttribute), Tool.Analyzer, "")] [FeatureGuard (typeof(RequiresUnreferencedCodeAttribute))] static bool IsNotTrueGuard => TestFeatures.IsUnreferencedCodeSupported is not true; @@ -365,7 +365,7 @@ static void TestIsNotTrueGuard () RequiresUnreferencedCode (); } - [ExpectedWarning ("IL4000", nameof (RequiresUnreferencedCodeAttribute), ProducedBy = Tool.Analyzer)] + [ExpectedWarning ("IL4000", nameof (RequiresUnreferencedCodeAttribute), Tool.Analyzer, "")] [FeatureGuard (typeof(RequiresUnreferencedCodeAttribute))] static bool IsFalseGuard => TestFeatures.IsUnreferencedCodeSupported is false; @@ -375,7 +375,7 @@ static void TestIsFalseGuard () RequiresUnreferencedCode (); } - [ExpectedWarning ("IL4000", nameof (RequiresUnreferencedCodeAttribute), ProducedBy = Tool.Analyzer)] + [ExpectedWarning ("IL4000", nameof (RequiresUnreferencedCodeAttribute), Tool.Analyzer, "")] [FeatureGuard (typeof(RequiresUnreferencedCodeAttribute))] static bool IfReturnFalseGuard { get { @@ -391,7 +391,7 @@ static void TestIfReturnFalseGuard () RequiresUnreferencedCode (); } - [ExpectedWarning ("IL4000", nameof (RequiresUnreferencedCodeAttribute), ProducedBy = Tool.Analyzer)] + [ExpectedWarning ("IL4000", nameof (RequiresUnreferencedCodeAttribute), Tool.Analyzer, "")] [FeatureGuard (typeof(RequiresUnreferencedCodeAttribute))] static bool ElseReturnFalseGuard { get { @@ -408,7 +408,7 @@ static void TestElseReturnFalseGuard () RequiresUnreferencedCode (); } - [ExpectedWarning ("IL4000", nameof (RequiresUnreferencedCodeAttribute), ProducedBy = Tool.Analyzer)] + [ExpectedWarning ("IL4000", nameof (RequiresUnreferencedCodeAttribute), Tool.Analyzer, "")] [FeatureGuard (typeof (RequiresUnreferencedCodeAttribute))] static bool AssertNotReturnTrueGuard { get { @@ -443,7 +443,7 @@ public static void Test () } class InvalidFeatureGuards { - [ExpectedWarning ("IL4001", ProducedBy = Tool.Analyzer)] + [ExpectedWarning ("IL4001", Tool.Analyzer, "")] [FeatureGuard (typeof(RequiresUnreferencedCodeAttribute))] static int NonBooleanProperty => 0; @@ -454,7 +454,7 @@ static void TestNonBooleanProperty () RequiresUnreferencedCode (); } - [ExpectedWarning ("IL4001", ProducedBy = Tool.Analyzer)] + [ExpectedWarning ("IL4001", Tool.Analyzer, "")] [FeatureGuard (typeof(RequiresUnreferencedCodeAttribute))] bool NonStaticProperty => true; @@ -476,7 +476,7 @@ static void TestSetOnlyProperty () RequiresUnreferencedCode (); } - [ExpectedWarning ("IL4001", ProducedBy = Tool.Analyzer)] + [ExpectedWarning ("IL4001", Tool.Analyzer, "")] [FeatureGuard (typeof(RequiresUnreferencedCodeAttribute))] static bool GetAndSetProperty { get => true; set => throw null; } diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/FieldDataFlow.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/FieldDataFlow.cs index 26e880378057a3..46f9e9844c3564 100644 --- a/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/FieldDataFlow.cs +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/FieldDataFlow.cs @@ -230,24 +230,21 @@ class AccessReturnedInstanceField static AccessReturnedInstanceField GetInstance ([DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.All)] Type unused) => null; - [ExpectedWarning ("IL2072", nameof (GetUnknownType), nameof (GetInstance), - ProducedBy = Tool.Trimmer | Tool.NativeAot)] // https://github.com/dotnet/linker/issues/2832 + [ExpectedWarning ("IL2072", nameof (GetUnknownType), nameof (GetInstance), Tool.Trimmer | Tool.NativeAot, "")] // https://github.com/dotnet/linker/issues/2832 [ExpectedWarning ("IL2077", nameof (field), nameof (DataFlowTypeExtensions.RequiresAll))] static void TestRead () { GetInstance (GetUnknownType ()).field.RequiresAll (); } - [ExpectedWarning ("IL2072", nameof (GetUnknownType), nameof (GetInstance), - ProducedBy = Tool.Trimmer | Tool.NativeAot)] // https://github.com/dotnet/linker/issues/2832 + [ExpectedWarning ("IL2072", nameof (GetUnknownType), nameof (GetInstance), Tool.Trimmer | Tool.NativeAot, "")] // https://github.com/dotnet/linker/issues/2832 [ExpectedWarning ("IL2074", nameof (GetUnknownType), nameof (field))] static void TestWrite () { GetInstance (GetUnknownType ()).field = GetUnknownType (); } - [ExpectedWarning ("IL2072", nameof (GetUnknownType), nameof (GetInstance), - ProducedBy = Tool.Trimmer | Tool.NativeAot)] // https://github.com/dotnet/linker/issues/2832 + [ExpectedWarning ("IL2072", nameof (GetUnknownType), nameof (GetInstance), Tool.Trimmer | Tool.NativeAot, "")] // https://github.com/dotnet/linker/issues/2832 [ExpectedWarning ("IL2074", nameof (GetUnknownType), nameof (field))] static void TestNullCoalescingAssignment () { @@ -341,13 +338,13 @@ static void RequirePublicFields ( { } - [ExpectedWarning ("IL2077", ProducedBy = Tool.Analyzer)] // https://github.com/dotnet/runtime/issues/101211 + [ExpectedWarning ("IL2077", Tool.Analyzer, "")] // https://github.com/dotnet/runtime/issues/101211 static void TestFlowOutOfField () { RequirePublicFields (unsupportedTypeInstance); } - [ExpectedWarning ("IL2074", ProducedBy = Tool.Analyzer)] // https://github.com/dotnet/runtime/issues/101211 + [ExpectedWarning ("IL2074", Tool.Analyzer, "")] // https://github.com/dotnet/runtime/issues/101211 public static void Test () { var t = GetUnsupportedTypeInstance (); unsupportedTypeInstance = t; diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/GenericParameterDataFlow.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/GenericParameterDataFlow.cs index e7b96db55e6893..2cbd62f6d43432 100644 --- a/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/GenericParameterDataFlow.cs +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/GenericParameterDataFlow.cs @@ -408,7 +408,7 @@ class TypeGenericRequirementsOnMembers<[DynamicallyAccessedMembers (DynamicallyA { public TypeRequiresPublicFields PublicFieldsField; - [ExpectedWarning ("IL2091", nameof (TypeRequiresPublicMethods), ProducedBy = Tool.Trimmer)] // NativeAOT_StorageSpaceType + [ExpectedWarning ("IL2091", nameof (TypeRequiresPublicMethods), Tool.Trimmer, "")] // NativeAOT_StorageSpaceType public TypeRequiresPublicMethods PublicMethodsField; public TypeRequiresPublicFields PublicFieldsProperty { @@ -417,23 +417,23 @@ public TypeRequiresPublicFields PublicFieldsProperty { } public TypeRequiresPublicMethods PublicMethodsProperty { - [ExpectedWarning ("IL2091", nameof (TypeRequiresPublicMethods), ProducedBy = Tool.Trimmer)] // NativeAOT_StorageSpaceType + [ExpectedWarning ("IL2091", nameof (TypeRequiresPublicMethods), Tool.Trimmer, "")] // NativeAOT_StorageSpaceType get => null; - [ExpectedWarning ("IL2091", nameof (TypeRequiresPublicMethods), ProducedBy = Tool.Trimmer)] // NativeAOT_StorageSpaceType + [ExpectedWarning ("IL2091", nameof (TypeRequiresPublicMethods), Tool.Trimmer, "")] // NativeAOT_StorageSpaceType set { } } - [ExpectedWarning ("IL2091", nameof (TypeRequiresPublicMethods), ProducedBy = Tool.Trimmer, CompilerGeneratedCode = true)] // NativeAOT_StorageSpaceType + [ExpectedWarning ("IL2091", nameof (TypeRequiresPublicMethods), Tool.Trimmer, "", CompilerGeneratedCode = true)] // NativeAOT_StorageSpaceType public TypeRequiresPublicMethods PublicMethodsImplicitGetter => null; public void PublicFieldsMethodParameter (TypeRequiresPublicFields param) { } - [ExpectedWarning ("IL2091", nameof (TypeRequiresPublicMethods), ProducedBy = Tool.Trimmer)] // NativeAOT_StorageSpaceType + [ExpectedWarning ("IL2091", nameof (TypeRequiresPublicMethods), Tool.Trimmer, "")] // NativeAOT_StorageSpaceType public void PublicMethodsMethodParameter (TypeRequiresPublicMethods param) { } public TypeRequiresPublicFields PublicFieldsMethodReturnValue () { return null; } - [ExpectedWarning ("IL2091", nameof (TypeRequiresPublicMethods), ProducedBy = Tool.Trimmer)] // NativeAOT_StorageSpaceType - [ExpectedWarning ("IL2091", nameof (TypeRequiresPublicMethods), ProducedBy = Tool.Trimmer)] // NativeAOT_StorageSpaceType + [ExpectedWarning ("IL2091", nameof (TypeRequiresPublicMethods), Tool.Trimmer, "")] // NativeAOT_StorageSpaceType + [ExpectedWarning ("IL2091", nameof (TypeRequiresPublicMethods), Tool.Trimmer, "")] // NativeAOT_StorageSpaceType public TypeRequiresPublicMethods PublicMethodsMethodReturnValue () { return null; } public void PublicFieldsMethodLocalVariable () @@ -442,7 +442,7 @@ public void PublicFieldsMethodLocalVariable () } // The analyzer matches NativeAot behavior for local variables - it doesn't warn on generic types of local variables. - [ExpectedWarning ("IL2091", nameof (TypeRequiresPublicMethods), ProducedBy = Tool.Trimmer)] // NativeAOT_StorageSpaceType + [ExpectedWarning ("IL2091", nameof (TypeRequiresPublicMethods), Tool.Trimmer, "")] // NativeAOT_StorageSpaceType public void PublicMethodsMethodLocalVariable () { TypeRequiresPublicMethods t = null; @@ -711,17 +711,15 @@ public static void StaticPartialInstantiation () } [ExpectedWarning ("IL2091", - nameof (TOuter), + [nameof (TOuter), "Mono.Linker.Tests.Cases.DataFlow.GenericParameterDataFlow.TypeWithInstantiatedGenericMethodViaGenericParameter", "TMethods", - "Mono.Linker.Tests.Cases.DataFlow.GenericParameterDataFlow.BaseTypeWithGenericMethod.StaticRequiresMultipleGenericParams()", - ProducedBy = Tool.Analyzer)] + "Mono.Linker.Tests.Cases.DataFlow.GenericParameterDataFlow.BaseTypeWithGenericMethod.StaticRequiresMultipleGenericParams()"], Tool.Analyzer, "")] [ExpectedWarning ("IL2091", - "'TOuter'", + ["'TOuter'", "Mono.Linker.Tests.Cases.DataFlow.GenericParameterDataFlow.TypeWithInstantiatedGenericMethodViaGenericParameter", "'TMethods'", - "Mono.Linker.Tests.Cases.DataFlow.GenericParameterDataFlow.BaseTypeWithGenericMethod.StaticRequiresMultipleGenericParams", - ProducedBy = Tool.Trimmer | Tool.NativeAot)] + "Mono.Linker.Tests.Cases.DataFlow.GenericParameterDataFlow.BaseTypeWithGenericMethod.StaticRequiresMultipleGenericParams"], Tool.Trimmer | Tool.NativeAot, "")] public static void StaticPartialInstantiationUnrecognized () { StaticRequiresMultipleGenericParams (); @@ -833,10 +831,10 @@ static void TestNoWarningsInRUCMethod () [ExpectedWarning ("IL2091", "RUCTypeRequiresPublicFields")] // StaticMethodRequiresPublicMethods [ExpectedWarning ("IL2091", "RUCTypeRequiresPublicFields")] // StaticMethodRequiresPublicMethods [ExpectedWarning ("IL2091", "RUCTypeRequiresPublicFields")] // RUCTypeRequiresPublicFields ctor - [ExpectedWarning ("IL2091", "RUCTypeRequiresPublicFields", ProducedBy = Tool.Trimmer)] // RUCTypeRequiresPublicFields local, // NativeAOT_StorageSpaceType - [ExpectedWarning ("IL2091", "RUCTypeRequiresPublicFields", ProducedBy = Tool.Trimmer)] // InstanceMethod, // NativeAOT_StorageSpaceType + [ExpectedWarning ("IL2091", "RUCTypeRequiresPublicFields", Tool.Trimmer, "")] // RUCTypeRequiresPublicFields local, // NativeAOT_StorageSpaceType + [ExpectedWarning ("IL2091", "RUCTypeRequiresPublicFields", Tool.Trimmer, "")] // InstanceMethod, // NativeAOT_StorageSpaceType [ExpectedWarning ("IL2091", "RUCTypeRequiresPublicFields")] // InstanceMethodRequiresPublicMethods - [ExpectedWarning ("IL2091", "RUCTypeRequiresPublicFields", ProducedBy = Tool.Trimmer)] // VirtualMethod, // NativeAOT_StorageSpaceType + [ExpectedWarning ("IL2091", "RUCTypeRequiresPublicFields", Tool.Trimmer, "")] // VirtualMethod, // NativeAOT_StorageSpaceType [ExpectedWarning ("IL2091", "RUCTypeRequiresPublicFields")] // VirtualMethodRequiresPublicMethods static void TestNoWarningsInRUCType () { @@ -908,9 +906,9 @@ static void TestGenericParameterFlowsToDelegateMethodDeclaringType () [ExpectedWarning ("IL2091", nameof (DelegateMethodTypeRequiresFields))] // NativeAOT_StorageSpaceType: illink warns about the type of 'instance' local variable - [ExpectedWarning ("IL2091", nameof (DelegateMethodTypeRequiresFields), ProducedBy = Tool.Trimmer)] + [ExpectedWarning ("IL2091", nameof (DelegateMethodTypeRequiresFields), Tool.Trimmer, "")] // NativeAOT_StorageSpaceType: illink warns about the declaring type of 'InstanceMethod' on ldftn - [ExpectedWarning ("IL2091", nameof (DelegateMethodTypeRequiresFields), ProducedBy = Tool.Trimmer)] + [ExpectedWarning ("IL2091", nameof (DelegateMethodTypeRequiresFields), Tool.Trimmer, "")] static void TestGenericParameterFlowsToDelegateMethodDeclaringTypeInstance () { var instance = new DelegateMethodTypeRequiresFields (); diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/GenericParameterWarningLocation.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/GenericParameterWarningLocation.cs index d3aa2e17ac021b..560560df1223d0 100644 --- a/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/GenericParameterWarningLocation.cs +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/GenericParameterWarningLocation.cs @@ -190,11 +190,11 @@ interface IWithTwo< static void MethodWithSpecificType (TypeWithPublicMethods one, IWithTwo two) { } - [ExpectedWarning ("IL2091", ProducedBy = Tool.Trimmer)] // NativeAOT_StorageSpaceType + [ExpectedWarning ("IL2091", Tool.Trimmer, "")] // NativeAOT_StorageSpaceType static void MethodWithOneMismatch (TypeWithPublicMethods one) { } - [ExpectedWarning ("IL2091", nameof (IWithTwo), ProducedBy = Tool.Trimmer)] // NativeAOT_StorageSpaceType - [ExpectedWarning ("IL2091", nameof (TypeWithPublicMethods), ProducedBy = Tool.Trimmer)] // NativeAOT_StorageSpaceType + [ExpectedWarning ("IL2091", nameof (IWithTwo), Tool.Trimmer, "")] // NativeAOT_StorageSpaceType + [ExpectedWarning ("IL2091", nameof (TypeWithPublicMethods), Tool.Trimmer, "")] // NativeAOT_StorageSpaceType static void MethodWithTwoMismatches< [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicFields)] TPublicFields, [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] TPublicMethods> @@ -205,11 +205,11 @@ static void MethodWithTwoMismatches< static TypeWithPublicMethods MethodWithMatchingReturn<[DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] TPublicMethods> () => null; - [ExpectedWarning ("IL2091", ProducedBy = Tool.Trimmer)] // NativeAOT_StorageSpaceType + [ExpectedWarning ("IL2091", Tool.Trimmer, "")] // NativeAOT_StorageSpaceType static TypeWithPublicMethods MethodWithOneMismatchReturn () => null; - [ExpectedWarning ("IL2091", ProducedBy = Tool.Trimmer)] // NativeAOT_StorageSpaceType - [ExpectedWarning ("IL2091", ProducedBy = Tool.Trimmer)] // NativeAOT_StorageSpaceType + [ExpectedWarning ("IL2091", Tool.Trimmer, "")] // NativeAOT_StorageSpaceType + [ExpectedWarning ("IL2091", Tool.Trimmer, "")] // NativeAOT_StorageSpaceType static IWithTwo MethodWithTwoMismatchesInReturn< [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicFields)] TPublicFields, [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] TPublicMethods> @@ -217,7 +217,7 @@ static IWithTwo MethodWithTwoMismatchesInReturn< class ConstructorWithOneMatchAndOneMismatch<[DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] TMethods> { - [ExpectedWarning ("IL2091", ProducedBy = Tool.Trimmer)] // NativeAOT_StorageSpaceType + [ExpectedWarning ("IL2091", Tool.Trimmer, "")] // NativeAOT_StorageSpaceType public ConstructorWithOneMatchAndOneMismatch (IWithTwo two) { } } @@ -252,11 +252,11 @@ interface IWithTwo< static void MethodWithSpecificType (TypeWithPublicMethods one, IWithTwo two) { } - [ExpectedWarning ("IL2091", ProducedBy = Tool.NativeAot | Tool.Trimmer)] + [ExpectedWarning ("IL2091", Tool.NativeAot | Tool.Trimmer, "")] static void MethodWithOneMismatch (TypeWithPublicMethods one) { } - [ExpectedWarning ("IL2091", nameof (IWithTwo), ProducedBy = Tool.NativeAot | Tool.Trimmer)] - [ExpectedWarning ("IL2091", nameof (TypeWithPublicMethods), ProducedBy = Tool.NativeAot | Tool.Trimmer)] + [ExpectedWarning ("IL2091", nameof (IWithTwo), Tool.NativeAot | Tool.Trimmer, "")] + [ExpectedWarning ("IL2091", nameof (TypeWithPublicMethods), Tool.NativeAot | Tool.Trimmer, "")] static void MethodWithTwoMismatches< [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicFields)] TPublicFields, [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] TPublicMethods> @@ -267,11 +267,11 @@ static void MethodWithTwoMismatches< static TypeWithPublicMethods MethodWithMatchingReturn<[DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] TPublicMethods> () => null; - [ExpectedWarning ("IL2091", ProducedBy = Tool.NativeAot | Tool.Trimmer)] + [ExpectedWarning ("IL2091", Tool.NativeAot | Tool.Trimmer, "")] static TypeWithPublicMethods MethodWithOneMismatchReturn () => null; - [ExpectedWarning ("IL2091", ProducedBy = Tool.NativeAot | Tool.Trimmer)] - [ExpectedWarning ("IL2091", ProducedBy = Tool.NativeAot | Tool.Trimmer)] + [ExpectedWarning ("IL2091", Tool.NativeAot | Tool.Trimmer, "")] + [ExpectedWarning ("IL2091", Tool.NativeAot | Tool.Trimmer, "")] static IWithTwo MethodWithTwoMismatchesInReturn< [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicFields)] TPublicFields, [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] TPublicMethods> @@ -279,7 +279,7 @@ static IWithTwo MethodWithTwoMismatchesInReturn< class ConstructorWithOneMatchAndOneMismatch<[DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] TMethods> { - [ExpectedWarning ("IL2091", ProducedBy = Tool.NativeAot | Tool.Trimmer)] + [ExpectedWarning ("IL2091", Tool.NativeAot | Tool.Trimmer, "")] public ConstructorWithOneMatchAndOneMismatch (IWithTwo two) { } } @@ -325,10 +325,10 @@ public static void Test () class MultipleReferencesToTheSameType<[DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] TPublicMethods, TUnknown> { - [ExpectedWarning ("IL2091", ProducedBy = Tool.Trimmer)] // NativeAOT_StorageSpaceType + [ExpectedWarning ("IL2091", Tool.Trimmer, "")] // NativeAOT_StorageSpaceType static TypeWithPublicMethods _field1; static TypeWithPublicMethods _field2; - [ExpectedWarning ("IL2091", ProducedBy = Tool.Trimmer)] // NativeAOT_StorageSpaceType + [ExpectedWarning ("IL2091", Tool.Trimmer, "")] // NativeAOT_StorageSpaceType static TypeWithPublicMethods _field3; public static void Test () @@ -343,8 +343,8 @@ class TwoMismatchesInOne< [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] TPublicMethods, [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicFields)] TPublicFields> { - [ExpectedWarning ("IL2091", ProducedBy = Tool.Trimmer)] // NativeAOT_StorageSpaceType - [ExpectedWarning ("IL2091", ProducedBy = Tool.Trimmer)] // NativeAOT_StorageSpaceType + [ExpectedWarning ("IL2091", Tool.Trimmer, "")] // NativeAOT_StorageSpaceType + [ExpectedWarning ("IL2091", Tool.Trimmer, "")] // NativeAOT_StorageSpaceType static IWithTwo _field; public static void Test () @@ -388,10 +388,10 @@ class OneMatchingAnnotation<[DynamicallyAccessedMembers (DynamicallyAccessedMemb class MultipleReferencesToTheSameType<[DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] TPublicMethods, TUnknown> { - [ExpectedWarning ("IL2091", ProducedBy = Tool.Trimmer | Tool.NativeAot)] + [ExpectedWarning ("IL2091", Tool.Trimmer | Tool.NativeAot, "")] static TypeWithPublicMethods _field1; static TypeWithPublicMethods _field2; - [ExpectedWarning ("IL2091", ProducedBy = Tool.Trimmer | Tool.NativeAot)] + [ExpectedWarning ("IL2091", Tool.Trimmer | Tool.NativeAot, "")] static TypeWithPublicMethods _field3; } @@ -399,8 +399,8 @@ class TwoMismatchesInOne< [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] TPublicMethods, [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicFields)] TPublicFields> { - [ExpectedWarning ("IL2091", ProducedBy = Tool.Trimmer | Tool.NativeAot)] - [ExpectedWarning ("IL2091", ProducedBy = Tool.Trimmer | Tool.NativeAot)] + [ExpectedWarning ("IL2091", Tool.Trimmer | Tool.NativeAot, "")] + [ExpectedWarning ("IL2091", Tool.Trimmer | Tool.NativeAot, "")] static IWithTwo _field; } @@ -450,12 +450,12 @@ public static void Test () class MultipleReferencesToTheSameType<[DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] TPublicMethods, TUnknown> { // The warning is generated on the backing field - [ExpectedWarning ("IL2091", CompilerGeneratedCode = true, ProducedBy = Tool.Trimmer)] // NativeAOT_StorageSpaceType + [ExpectedWarning ("IL2091", Tool.Trimmer, "", CompilerGeneratedCode = true)] // NativeAOT_StorageSpaceType static TypeWithPublicMethods Property1 { - [ExpectedWarning ("IL2091", ProducedBy = Tool.Trimmer)] // NativeAOT_StorageSpaceType + [ExpectedWarning ("IL2091", Tool.Trimmer, "")] // NativeAOT_StorageSpaceType get; - [ExpectedWarning ("IL2091", ProducedBy = Tool.Trimmer)] // NativeAOT_StorageSpaceType + [ExpectedWarning ("IL2091", Tool.Trimmer, "")] // NativeAOT_StorageSpaceType set; } @@ -465,12 +465,12 @@ static TypeWithPublicMethods Property2 { } // The warning is generated on the backing field - [ExpectedWarning ("IL2091", CompilerGeneratedCode = true, ProducedBy = Tool.Trimmer)] // NativeAOT_StorageSpaceType + [ExpectedWarning ("IL2091", Tool.Trimmer, "", CompilerGeneratedCode = true)] // NativeAOT_StorageSpaceType static TypeWithPublicMethods Property3 { - [ExpectedWarning ("IL2091", ProducedBy = Tool.Trimmer)] // NativeAOT_StorageSpaceType + [ExpectedWarning ("IL2091", Tool.Trimmer, "")] // NativeAOT_StorageSpaceType get; - [ExpectedWarning ("IL2091", ProducedBy = Tool.Trimmer)] // NativeAOT_StorageSpaceType + [ExpectedWarning ("IL2091", Tool.Trimmer, "")] // NativeAOT_StorageSpaceType set; } @@ -487,14 +487,14 @@ class TwoMismatchesInOne< [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicFields)] TPublicFields> { // The warnings are generated on the backing field - [ExpectedWarning ("IL2091", CompilerGeneratedCode = true, ProducedBy = Tool.Trimmer)] // NativeAOT_StorageSpaceType - [ExpectedWarning ("IL2091", CompilerGeneratedCode = true, ProducedBy = Tool.Trimmer)] // NativeAOT_StorageSpaceType + [ExpectedWarning ("IL2091", Tool.Trimmer, "", CompilerGeneratedCode = true)] // NativeAOT_StorageSpaceType + [ExpectedWarning ("IL2091", Tool.Trimmer, "", CompilerGeneratedCode = true)] // NativeAOT_StorageSpaceType static IWithTwo Property { // Getter is trimmed and doesn't produce any warning get; - [ExpectedWarning ("IL2091", ProducedBy = Tool.Trimmer)] // NativeAOT_StorageSpaceType - [ExpectedWarning ("IL2091", ProducedBy = Tool.Trimmer)] // NativeAOT_StorageSpaceType + [ExpectedWarning ("IL2091", Tool.Trimmer, "")] // NativeAOT_StorageSpaceType + [ExpectedWarning ("IL2091", Tool.Trimmer, "")] // NativeAOT_StorageSpaceType set; } @@ -554,7 +554,7 @@ static void MethodWithTwo< static MethodBody GetInstance () => null; - [ExpectedWarning ("IL2091", ProducedBy = Tool.Trimmer)] // return type // NativeAOT_StorageSpaceType + [ExpectedWarning ("IL2091", Tool.Trimmer, "")] // return type // NativeAOT_StorageSpaceType static TypeWithPublicMethods GetInstanceForTypeWithPublicMethods () => null; class TypeOf @@ -578,8 +578,8 @@ static void SpecificType () } // Analyzer doesn't warn on typeof - [ExpectedWarning ("IL2091", ProducedBy = Tool.Trimmer | Tool.NativeAot)] - [ExpectedWarning ("IL2091", ProducedBy = Tool.Trimmer | Tool.NativeAot)] + [ExpectedWarning ("IL2091", Tool.Trimmer | Tool.NativeAot, "")] + [ExpectedWarning ("IL2091", Tool.Trimmer | Tool.NativeAot, "")] static void MultipleReferencesToTheSameType< [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] TPublicMethods, TUnknown> () @@ -590,8 +590,8 @@ static void MultipleReferencesToTheSameType< } // Analyzer doesn't warn on typeof - [ExpectedWarning ("IL2091", ProducedBy = Tool.Trimmer | Tool.NativeAot)] - [ExpectedWarning ("IL2091", ProducedBy = Tool.Trimmer | Tool.NativeAot)] + [ExpectedWarning ("IL2091", Tool.Trimmer | Tool.NativeAot, "")] + [ExpectedWarning ("IL2091", Tool.Trimmer | Tool.NativeAot, "")] static void TwoMismatchesInOneStatement< [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicFields)] TPublicFields, [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] TPublicMethods> @@ -694,8 +694,8 @@ static void TwoMismatchesInOneStatement< IWithTwo.Method (); } - [ExpectedWarning ("IL2091", ProducedBy = Tool.Trimmer)] // NativeAOT_StorageSpaceType - [ExpectedWarning ("IL2091", ProducedBy = Tool.Trimmer)] // local variable // NativeAOT_StorageSpaceType + [ExpectedWarning ("IL2091", Tool.Trimmer, "")] // NativeAOT_StorageSpaceType + [ExpectedWarning ("IL2091", Tool.Trimmer, "")] // local variable // NativeAOT_StorageSpaceType static void InstanceMethodMismatch () { TypeWithPublicMethods instance = GetInstanceForTypeWithPublicMethods (); @@ -746,8 +746,8 @@ static void TwoMismatchesInOneStatement< _ = IWithTwo.Field; } - [ExpectedWarning ("IL2091", ProducedBy = Tool.Trimmer)] // NativeAOT_StorageSpaceType - [ExpectedWarning ("IL2091", ProducedBy = Tool.Trimmer)] // access to the field // NativeAOT_StorageSpaceType + [ExpectedWarning ("IL2091", Tool.Trimmer, "")] // NativeAOT_StorageSpaceType + [ExpectedWarning ("IL2091", Tool.Trimmer, "")] // access to the field // NativeAOT_StorageSpaceType static void InstanceFieldMismatch () { TypeWithPublicMethods instance = GetInstanceForTypeWithPublicMethods (); @@ -779,8 +779,8 @@ static void SpecificType () TypeWithPublicMethods t = null; } - [ExpectedWarning ("IL2091", ProducedBy = Tool.Trimmer)] // NativeAOT_StorageSpaceType - [ExpectedWarning ("IL2091", ProducedBy = Tool.Trimmer)] // NativeAOT_StorageSpaceType + [ExpectedWarning ("IL2091", Tool.Trimmer, "")] // NativeAOT_StorageSpaceType + [ExpectedWarning ("IL2091", Tool.Trimmer, "")] // NativeAOT_StorageSpaceType static void MultipleReferencesToTheSameType< [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] TPublicMethods, TUnknown> () @@ -790,8 +790,8 @@ static void MultipleReferencesToTheSameType< TypeWithPublicMethods t3 = null; // Warn } - [ExpectedWarning ("IL2091", ProducedBy = Tool.Trimmer)] // NativeAOT_StorageSpaceType - [ExpectedWarning ("IL2091", ProducedBy = Tool.Trimmer)] // NativeAOT_StorageSpaceType + [ExpectedWarning ("IL2091", Tool.Trimmer, "")] // NativeAOT_StorageSpaceType + [ExpectedWarning ("IL2091", Tool.Trimmer, "")] // NativeAOT_StorageSpaceType static void TwoMismatchesInOneStatement< [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicFields)] TPublicFields, [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] TPublicMethods> @@ -952,9 +952,9 @@ static void SpecificType () // ldtoken owningtype // In order to call the right Expression APIs. [ExpectedWarning ("IL2091")] - [ExpectedWarning ("IL2091", ProducedBy = Tool.Trimmer | Tool.NativeAot)] + [ExpectedWarning ("IL2091", Tool.Trimmer | Tool.NativeAot, "")] [ExpectedWarning ("IL2091")] - [ExpectedWarning ("IL2091", ProducedBy = Tool.Trimmer | Tool.NativeAot)] + [ExpectedWarning ("IL2091", Tool.Trimmer | Tool.NativeAot, "")] static void MultipleReferencesToTheSameMethod< [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] TPublicMethods, TUnknown> () @@ -969,9 +969,9 @@ static void MultipleReferencesToTheSameMethod< // ldtoken owningtype // In order to call the right Expression APIs. [ExpectedWarning ("IL2091")] - [ExpectedWarning ("IL2091", ProducedBy = Tool.Trimmer | Tool.NativeAot)] + [ExpectedWarning ("IL2091", Tool.Trimmer | Tool.NativeAot, "")] [ExpectedWarning ("IL2091")] - [ExpectedWarning ("IL2091", ProducedBy = Tool.Trimmer | Tool.NativeAot)] + [ExpectedWarning ("IL2091", Tool.Trimmer | Tool.NativeAot, "")] static void TwoMismatchesInOneStatement< [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicFields)] TPublicFields, [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] TPublicMethods> @@ -1007,8 +1007,8 @@ static void SpecificType () // ldtoken field // ldtoken owningtype // In order to call the right Expression APIs. - [ExpectedWarning ("IL2091", ProducedBy = Tool.Trimmer | Tool.NativeAot)] - [ExpectedWarning ("IL2091", ProducedBy = Tool.Trimmer | Tool.NativeAot)] + [ExpectedWarning ("IL2091", Tool.Trimmer | Tool.NativeAot, "")] + [ExpectedWarning ("IL2091", Tool.Trimmer | Tool.NativeAot, "")] static void MultipleReferencesToTheSameField< [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] TPublicMethods, TUnknown> () @@ -1024,8 +1024,8 @@ static void MultipleReferencesToTheSameField< // ldtoken field // ldtoken owningtype // In order to call the right Expression APIs. - [ExpectedWarning ("IL2091", ProducedBy = Tool.Trimmer | Tool.NativeAot)] - [ExpectedWarning ("IL2091", ProducedBy = Tool.Trimmer | Tool.NativeAot)] + [ExpectedWarning ("IL2091", Tool.Trimmer | Tool.NativeAot, "")] + [ExpectedWarning ("IL2091", Tool.Trimmer | Tool.NativeAot, "")] static void TwoMismatchesInOneStatement< [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicFields)] TPublicFields, [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] TPublicMethods> @@ -1061,8 +1061,8 @@ static void SpecificType () // ldtoken method (getter) // ldtoken owningtype // In order to call the right Expression APIs. - [ExpectedWarning ("IL2091", ProducedBy = Tool.Trimmer | Tool.NativeAot)] - [ExpectedWarning ("IL2091", ProducedBy = Tool.Trimmer | Tool.NativeAot)] + [ExpectedWarning ("IL2091", Tool.Trimmer | Tool.NativeAot, "")] + [ExpectedWarning ("IL2091", Tool.Trimmer | Tool.NativeAot, "")] static void MultipleReferencesToTheSameProperty< [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] TPublicMethods, TUnknown> () @@ -1078,8 +1078,8 @@ static void MultipleReferencesToTheSameProperty< // ldtoken method (getter) // ldtoken owningtype // In order to call the right Expression APIs. - [ExpectedWarning ("IL2091", ProducedBy = Tool.Trimmer | Tool.NativeAot)] - [ExpectedWarning ("IL2091", ProducedBy = Tool.Trimmer | Tool.NativeAot)] + [ExpectedWarning ("IL2091", Tool.Trimmer | Tool.NativeAot, "")] + [ExpectedWarning ("IL2091", Tool.Trimmer | Tool.NativeAot, "")] static void TwoMismatchesInOneStatement< [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicFields)] TPublicFields, [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] TPublicMethods> @@ -1155,8 +1155,8 @@ static void SpecificType () bool a = _value is TypeWithPublicMethods; } - [ExpectedWarning ("IL2091", ProducedBy = Tool.Trimmer)] // NativeAOT_StorageSpaceType - [ExpectedWarning ("IL2091", ProducedBy = Tool.Trimmer)] // NativeAOT_StorageSpaceType + [ExpectedWarning ("IL2091", Tool.Trimmer, "")] // NativeAOT_StorageSpaceType + [ExpectedWarning ("IL2091", Tool.Trimmer, "")] // NativeAOT_StorageSpaceType static void MultipleReferencesToTheSameMethod< [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] TPublicMethods, TUnknown> () @@ -1166,8 +1166,8 @@ static void MultipleReferencesToTheSameMethod< bool a3 = _value is TypeWithPublicMethods; // Warn } - [ExpectedWarning ("IL2091", ProducedBy = Tool.Trimmer)] // NativeAOT_StorageSpaceType - [ExpectedWarning ("IL2091", ProducedBy = Tool.Trimmer)] // NativeAOT_StorageSpaceType + [ExpectedWarning ("IL2091", Tool.Trimmer, "")] // NativeAOT_StorageSpaceType + [ExpectedWarning ("IL2091", Tool.Trimmer, "")] // NativeAOT_StorageSpaceType static void TwoMismatchesInOneStatement< [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicFields)] TPublicFields, [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] TPublicMethods> @@ -1200,8 +1200,8 @@ static void SpecificType () object a = _value as TypeWithPublicMethods; } - [ExpectedWarning ("IL2091", ProducedBy = Tool.Trimmer)] // NativeAOT_StorageSpaceType - [ExpectedWarning ("IL2091", ProducedBy = Tool.Trimmer)] // NativeAOT_StorageSpaceType + [ExpectedWarning ("IL2091", Tool.Trimmer, "")] // NativeAOT_StorageSpaceType + [ExpectedWarning ("IL2091", Tool.Trimmer, "")] // NativeAOT_StorageSpaceType static void MultipleReferencesToTheSameMethod< [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] TPublicMethods, TUnknown> () @@ -1211,8 +1211,8 @@ static void MultipleReferencesToTheSameMethod< object a3 = _value as TypeWithPublicMethods; // Warn } - [ExpectedWarning ("IL2091", ProducedBy = Tool.Trimmer)] // NativeAOT_StorageSpaceType - [ExpectedWarning ("IL2091", ProducedBy = Tool.Trimmer)] // NativeAOT_StorageSpaceType + [ExpectedWarning ("IL2091", Tool.Trimmer, "")] // NativeAOT_StorageSpaceType + [ExpectedWarning ("IL2091", Tool.Trimmer, "")] // NativeAOT_StorageSpaceType static void TwoMismatchesInOneStatement< [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicFields)] TPublicFields, [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] TPublicMethods> @@ -1251,8 +1251,8 @@ static void SpecificType () } } - [ExpectedWarning ("IL2091", ProducedBy = Tool.Trimmer)] // NativeAOT_StorageSpaceType - [ExpectedWarning ("IL2091", ProducedBy = Tool.Trimmer)] // NativeAOT_StorageSpaceType + [ExpectedWarning ("IL2091", Tool.Trimmer, "")] // NativeAOT_StorageSpaceType + [ExpectedWarning ("IL2091", Tool.Trimmer, "")] // NativeAOT_StorageSpaceType static void MultipleReferencesToTheSameType< [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] TPublicMethods, TUnknown> () @@ -1273,8 +1273,8 @@ static void MultipleReferencesToTheSameType< } } - [ExpectedWarning ("IL2091", ProducedBy = Tool.Trimmer)] // NativeAOT_StorageSpaceType - [ExpectedWarning ("IL2091", ProducedBy = Tool.Trimmer)] // NativeAOT_StorageSpaceType + [ExpectedWarning ("IL2091", Tool.Trimmer, "")] // NativeAOT_StorageSpaceType + [ExpectedWarning ("IL2091", Tool.Trimmer, "")] // NativeAOT_StorageSpaceType static void TwoMismatchesInOneStatement< [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicFields)] TPublicFields, [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] TPublicMethods> @@ -1314,8 +1314,8 @@ static void SpecificType () } } - [ExpectedWarning ("IL2091", ProducedBy = Tool.Trimmer)] // NativeAOT_StorageSpaceType - [ExpectedWarning ("IL2091", ProducedBy = Tool.Trimmer)] // NativeAOT_StorageSpaceType + [ExpectedWarning ("IL2091", Tool.Trimmer, "")] // NativeAOT_StorageSpaceType + [ExpectedWarning ("IL2091", Tool.Trimmer, "")] // NativeAOT_StorageSpaceType static void MultipleReferencesToTheSameType< [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] TPublicMethods, TUnknown> () @@ -1336,8 +1336,8 @@ static void MultipleReferencesToTheSameType< } } - [ExpectedWarning ("IL2091", ProducedBy = Tool.Trimmer)] // NativeAOT_StorageSpaceType - [ExpectedWarning ("IL2091", ProducedBy = Tool.Trimmer)] // NativeAOT_StorageSpaceType + [ExpectedWarning ("IL2091", Tool.Trimmer, "")] // NativeAOT_StorageSpaceType + [ExpectedWarning ("IL2091", Tool.Trimmer, "")] // NativeAOT_StorageSpaceType static void TwoMismatchesInOneStatement< [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicFields)] TPublicFields, [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] TPublicMethods> @@ -1373,14 +1373,14 @@ class AnnotatedString static void MethodWithAnnotatedParameter ([DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] string typeName) { } // Analyzer: https://github.com/dotnet/runtime/issues/95118 - [ExpectedWarning ("IL2026", "TypeWithRUCMethod.PrivateRUCMethod", ProducedBy = Tool.Trimmer | Tool.NativeAot)] + [ExpectedWarning ("IL2026", "TypeWithRUCMethod.PrivateRUCMethod", Tool.Trimmer | Tool.NativeAot, "")] static void AnnotatedParameter () { MethodWithAnnotatedParameter ("Mono.Linker.Tests.Cases.DataFlow.GenericParameterWarningLocation+MethodBody+TypeWithPrivateMethods`1[[Mono.Linker.Tests.Cases.DataFlow.GenericParameterWarningLocation+MethodBody+TypeWithRUCMethod]]"); } // Analyzer: https://github.com/dotnet/runtime/issues/95118 - [ExpectedWarning ("IL2026", "TypeWithRUCMethod.PrivateRUCMethod", ProducedBy = Tool.Trimmer | Tool.NativeAot)] + [ExpectedWarning ("IL2026", "TypeWithRUCMethod.PrivateRUCMethod", Tool.Trimmer | Tool.NativeAot, "")] [return: DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] static string AnnotatedReturnValue () { @@ -1391,7 +1391,7 @@ static string AnnotatedReturnValue () static string _annotatedField; // Analyzer: https://github.com/dotnet/runtime/issues/95118 - [ExpectedWarning ("IL2026", "TypeWithRUCMethod.PrivateRUCMethod", ProducedBy = Tool.Trimmer | Tool.NativeAot)] + [ExpectedWarning ("IL2026", "TypeWithRUCMethod.PrivateRUCMethod", Tool.Trimmer | Tool.NativeAot, "")] static void AnnotatedField () { _annotatedField = "Mono.Linker.Tests.Cases.DataFlow.GenericParameterWarningLocation+MethodBody+TypeWithPrivateMethods`1[[Mono.Linker.Tests.Cases.DataFlow.GenericParameterWarningLocation+MethodBody+TypeWithRUCMethod]]"; @@ -1408,7 +1408,7 @@ public static void Test () class TypeGetType { // Analyzer: https://github.com/dotnet/runtime/issues/95118 - [ExpectedWarning ("IL2026", "TypeWithRUCMethod.PrivateRUCMethod", ProducedBy = Tool.Trimmer | Tool.NativeAot)] + [ExpectedWarning ("IL2026", "TypeWithRUCMethod.PrivateRUCMethod", Tool.Trimmer | Tool.NativeAot, "")] static void SpecificType () { Type.GetType ("Mono.Linker.Tests.Cases.DataFlow.GenericParameterWarningLocation+MethodBody+TypeWithPrivateMethods`1[[Mono.Linker.Tests.Cases.DataFlow.GenericParameterWarningLocation+MethodBody+TypeWithRUCMethod]]"); diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/GetTypeDataFlow.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/GetTypeDataFlow.cs index d99b7557a257a3..c5361f835534c9 100644 --- a/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/GetTypeDataFlow.cs +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/GetTypeDataFlow.cs @@ -169,8 +169,8 @@ public void Method1 () { } public void Method2 () { } // https://github.com/dotnet/linker/issues/2273 - [ExpectedWarning ("IL2026", "--Method1--", ProducedBy = Tool.Trimmer | Tool.NativeAot)] - [ExpectedWarning ("IL2026", "--Method2--", ProducedBy = Tool.Trimmer | Tool.NativeAot)] + [ExpectedWarning ("IL2026", "--Method1--", Tool.Trimmer | Tool.NativeAot, "")] + [ExpectedWarning ("IL2026", "--Method2--", Tool.Trimmer | Tool.NativeAot, "")] public static void Test () { Type.GetType ("Mono.Linker.Tests.Cases.DataFlow." + nameof (GetTypeDataFlow) + "+" + nameof (TypeWithWarnings)).RequiresPublicMethods (); @@ -185,7 +185,7 @@ class OverConstTypeName public void Method1 () { } // https://github.com/dotnet/linker/issues/2273 - [ExpectedWarning ("IL2026", "--Method1--", ProducedBy = Tool.Trimmer | Tool.NativeAot)] + [ExpectedWarning ("IL2026", "--Method1--", Tool.Trimmer | Tool.NativeAot, "")] public static void Test () { Type.GetType (s_ConstTypeName).RequiresPublicMethods (); diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/InlineArrayDataflow.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/InlineArrayDataflow.cs index c7725fcdf2617c..5915bb2d45384c 100644 --- a/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/InlineArrayDataflow.cs +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/InlineArrayDataflow.cs @@ -14,7 +14,7 @@ namespace Mono.Linker.Tests.Cases.DataFlow [ExpectedNoWarnings] public class InlineArrayDataflow { - public static void Main() + public static void Main () { AccessPrimitiveTypeArray (); AccessUnannotatedTypeArray (); @@ -63,7 +63,7 @@ struct AnnotatedTypeArray } // Currently tracking of annotations on inline array values is not implemented - [ExpectedWarning("IL2065", "GetProperty")] + [ExpectedWarning ("IL2065", "GetProperty")] static void AccessAnnotatedTypeArray () { AnnotatedTypeArray a = new AnnotatedTypeArray (); diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/LocalDataFlow.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/LocalDataFlow.cs index 788312c2c262df..71b08b3a6af17e 100644 --- a/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/LocalDataFlow.cs +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/LocalDataFlow.cs @@ -218,8 +218,7 @@ public static void TestBranchMergeCatch () nameof (LocalDataFlow) + "." + nameof (GetWithPublicFields) + "()")] // ILLink produces extraneous warnings [ExpectedWarning ("IL2072", nameof (DataFlowStringExtensions) + "." + nameof (DataFlowStringExtensions.RequiresPublicFields) + "(String)", - nameof (LocalDataFlow) + "." + nameof (GetWithPublicMethods) + "()", - ProducedBy = Tool.Trimmer)] + nameof (LocalDataFlow) + "." + nameof (GetWithPublicMethods) + "()", Tool.Trimmer, "")] public static void TestBranchMergeFinally () { string str = GetWithPublicMethods (); @@ -235,8 +234,7 @@ public static void TestBranchMergeFinally () } // Analyzer gets this right (no warning), but trimmer merges all branches going forward. - [ExpectedWarning ("IL2072", nameof (DataFlowStringExtensions) + "." + nameof (DataFlowStringExtensions.RequiresPublicFields) + "(String)", - ProducedBy = Tool.Trimmer)] + [ExpectedWarning ("IL2072", nameof (DataFlowStringExtensions) + "." + nameof (DataFlowStringExtensions.RequiresPublicFields) + "(String)", Tool.Trimmer, "")] public static void TestBranchGoto () { string str = GetWithPublicMethods (); @@ -249,8 +247,7 @@ public static void TestBranchGoto () } // Analyzer gets this right (no warning), but trimmer merges all branches going forward. - [ExpectedWarning ("IL2072", nameof (DataFlowStringExtensions) + "." + nameof (DataFlowStringExtensions.RequiresPublicFields), - ProducedBy = Tool.Trimmer)] + [ExpectedWarning ("IL2072", nameof (DataFlowStringExtensions) + "." + nameof (DataFlowStringExtensions.RequiresPublicFields), Tool.Trimmer, "")] public static void TestBranchIf () { string str = GetWithPublicMethods (); @@ -261,8 +258,7 @@ public static void TestBranchIf () } // Analyzer gets this right (no warning), but trimmer merges all branches going forward. - [ExpectedWarning ("IL2072", nameof (DataFlowStringExtensions) + "." + nameof (DataFlowStringExtensions.RequiresPublicFields), - ProducedBy = Tool.Trimmer)] + [ExpectedWarning ("IL2072", nameof (DataFlowStringExtensions) + "." + nameof (DataFlowStringExtensions.RequiresPublicFields), Tool.Trimmer, "")] public static void TestBranchIfElse () { string str; @@ -278,18 +274,12 @@ public static void TestBranchIfElse () } // Analyzer gets this right (no warning), but trimmer merges all branches going forward. - [ExpectedWarning ("IL2072", nameof (DataFlowStringExtensions) + "." + nameof (DataFlowStringExtensions.RequiresNonPublicMethods) + "(String)", - ProducedBy = Tool.Trimmer)] - [ExpectedWarning ("IL2072", nameof (DataFlowStringExtensions) + "." + nameof (DataFlowStringExtensions.RequiresPublicMethods) + "(String)", - ProducedBy = Tool.Trimmer)] - [ExpectedWarning ("IL2072", nameof (DataFlowStringExtensions) + "." + nameof (DataFlowStringExtensions.RequiresPublicMethods) + "(String)", - ProducedBy = Tool.Trimmer)] - [ExpectedWarning ("IL2072", nameof (DataFlowStringExtensions) + "." + nameof (DataFlowStringExtensions.RequiresPublicConstructors) + "(String)", - ProducedBy = Tool.Trimmer)] - [ExpectedWarning ("IL2072", nameof (DataFlowStringExtensions) + "." + nameof (DataFlowStringExtensions.RequiresPublicConstructors) + "(String)", - ProducedBy = Tool.Trimmer)] - [ExpectedWarning ("IL2072", nameof (DataFlowStringExtensions) + "." + nameof (DataFlowStringExtensions.RequiresPublicConstructors) + "(String)", - ProducedBy = Tool.Trimmer)] + [ExpectedWarning ("IL2072", nameof (DataFlowStringExtensions) + "." + nameof (DataFlowStringExtensions.RequiresNonPublicMethods) + "(String)", Tool.Trimmer, "")] + [ExpectedWarning ("IL2072", nameof (DataFlowStringExtensions) + "." + nameof (DataFlowStringExtensions.RequiresPublicMethods) + "(String)", Tool.Trimmer, "")] + [ExpectedWarning ("IL2072", nameof (DataFlowStringExtensions) + "." + nameof (DataFlowStringExtensions.RequiresPublicMethods) + "(String)", Tool.Trimmer, "")] + [ExpectedWarning ("IL2072", nameof (DataFlowStringExtensions) + "." + nameof (DataFlowStringExtensions.RequiresPublicConstructors) + "(String)", Tool.Trimmer, "")] + [ExpectedWarning ("IL2072", nameof (DataFlowStringExtensions) + "." + nameof (DataFlowStringExtensions.RequiresPublicConstructors) + "(String)", Tool.Trimmer, "")] + [ExpectedWarning ("IL2072", nameof (DataFlowStringExtensions) + "." + nameof (DataFlowStringExtensions.RequiresPublicConstructors) + "(String)", Tool.Trimmer, "")] public static void TestBranchSwitch () { string str = null; @@ -315,8 +305,7 @@ public static void TestBranchSwitch () // Analyzer gets this right (no warning), but trimmer merges all branches going forward. [ExpectedWarning ("IL2072", nameof (DataFlowStringExtensions) + "." + nameof (DataFlowStringExtensions.RequiresPublicFields), - nameof (LocalDataFlow) + "." + nameof (GetWithPublicMethods) + "()", - ProducedBy = Tool.Trimmer)] + nameof (LocalDataFlow) + "." + nameof (GetWithPublicMethods) + "()", Tool.Trimmer, "")] public static void TestBranchTry () { string str = GetWithPublicMethods (); @@ -332,8 +321,7 @@ public static void TestBranchTry () // Analyzer gets this right (no warning), but trimmer merges all branches going forward. [ExpectedWarning ("IL2072", nameof (DataFlowStringExtensions) + "." + nameof (DataFlowStringExtensions.RequiresPublicFields), - nameof (LocalDataFlow) + "." + nameof (GetWithPublicMethods) + "()", - ProducedBy = Tool.Trimmer)] + nameof (LocalDataFlow) + "." + nameof (GetWithPublicMethods) + "()", Tool.Trimmer, "")] public static void TestBranchCatch () { string str = GetWithPublicMethods (); @@ -348,8 +336,7 @@ public static void TestBranchCatch () // Analyzer gets this right (no warning), but trimmer merges all branches going forward. [ExpectedWarning ("IL2072", nameof (DataFlowStringExtensions) + "." + nameof (DataFlowStringExtensions.RequiresPublicFields), - nameof (LocalDataFlow) + "." + nameof (GetWithPublicMethods) + "()", - ProducedBy = Tool.Trimmer)] + nameof (LocalDataFlow) + "." + nameof (GetWithPublicMethods) + "()", Tool.Trimmer, "")] public static void TestBranchFinally () { string str = GetWithPublicMethods (); @@ -365,8 +352,7 @@ public static void TestBranchFinally () // Analyzer gets this right, but ILLink doesn't consider backwards branches. [ExpectedWarning ("IL2072", nameof (DataFlowStringExtensions) + "." + nameof (DataFlowStringExtensions.RequiresPublicMethods) + "(String)", - nameof (LocalDataFlow) + "." + nameof (GetWithPublicFields) + "()", - ProducedBy = Tool.Analyzer)] + nameof (LocalDataFlow) + "." + nameof (GetWithPublicFields) + "()", Tool.Analyzer, "")] public static void TestBackwardsEdgeLoop () { string str = GetWithPublicMethods (); @@ -382,8 +368,7 @@ public static void TestBackwardsEdgeLoop () // Analyzer gets this right, but ILLink doesn't consider backwards branches. [ExpectedWarning ("IL2072", nameof (DataFlowStringExtensions) + "." + nameof (DataFlowStringExtensions.RequiresPublicMethods) + "(String)", - nameof (LocalDataFlow) + "." + nameof (GetWithPublicFields) + "()", - ProducedBy = Tool.Analyzer)] + nameof (LocalDataFlow) + "." + nameof (GetWithPublicFields) + "()", Tool.Analyzer, "")] public static void TestBackwardsEdgeGoto () { string str = null; @@ -440,8 +425,8 @@ public virtual void VirtualMethod () // https://github.com/dotnet/linker/issues/2273 // Analyzer doesn't see through foreach over array at all - will not warn - [ExpectedWarning ("IL2063", ProducedBy = Tool.Trimmer)] // The types loaded from the array don't have annotations, so the "return" should warn - [ExpectedWarning ("IL2073", ProducedBy = Tool.Analyzer)] // Analyzer tracks resultType as the value from IEnumerable.Current.get() + [ExpectedWarning ("IL2063", Tool.Trimmer, "")] // The types loaded from the array don't have annotations, so the "return" should warn + [ExpectedWarning ("IL2073", Tool.Analyzer, "")] // Analyzer tracks resultType as the value from IEnumerable.Current.get() [return: DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] public static Type TestBackwardEdgeWithLdElem (Type[] types = null) { diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/MakeGenericDataFlow.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/MakeGenericDataFlow.cs index 50451dcd3f1e4e..32342ee39eecbc 100644 --- a/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/MakeGenericDataFlow.cs +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/MakeGenericDataFlow.cs @@ -126,7 +126,7 @@ static void TestWithRequirementsFromParam ( } // https://github.com/dotnet/linker/issues/2428 - // [ExpectedWarning ("IL2071", "'T'")] + // [ExpectedSharedWarning ("IL2071", "'T'")] [ExpectedWarning ("IL2070", "'this'")] static void TestWithRequirementsFromParamWithMismatch ( [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] Type type) @@ -141,7 +141,7 @@ static void TestWithRequirementsFromGenericParam< } // https://github.com/dotnet/linker/issues/2428 - // [ExpectedWarning ("IL2091", "'T'")] + // [ExpectedSharedWarning ("IL2091", "'T'")] [ExpectedWarning ("IL2090", "'this'")] // Note that this actually produces a warning which should not be possible to produce right now static void TestWithRequirementsFromGenericParamWithMismatch< [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] TInput> () @@ -551,7 +551,7 @@ static void TestWithArrayUnknownIndexSet (int indexToSet) } // https://github.com/dotnet/linker/issues/2158 - analyzer doesn't work the same as ILLink, it simply doesn't handle refs - [ExpectedWarning ("IL2060", nameof (MethodInfo.MakeGenericMethod), ProducedBy = Tool.Trimmer | Tool.NativeAot)] + [ExpectedWarning ("IL2060", nameof (MethodInfo.MakeGenericMethod), Tool.Trimmer | Tool.NativeAot, "")] static void TestWithArrayUnknownIndexSetByRef (int indexToSet) { Type[] types = new Type[1]; diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/MakeGenericDataflowIntrinsics.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/MakeGenericDataflowIntrinsics.cs index 4fe39ab6da1ca4..b1a67bd42dbdfe 100644 --- a/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/MakeGenericDataflowIntrinsics.cs +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/MakeGenericDataflowIntrinsics.cs @@ -34,10 +34,10 @@ public static void Test () public static void TestRecognizedGenericIntrinsic () => typeof (Gen<>).MakeGenericType (typeof (T)); [ExpectedWarning ("IL2055", nameof (Type.MakeGenericType))] - [ExpectedWarning ("IL3050", nameof (Type.MakeGenericType), ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3050", nameof (Type.MakeGenericType), Tool.Analyzer | Tool.NativeAot, "")] public static void TestUnknownOwningType () => GrabUnknownType ().MakeGenericType (typeof (object)); - [ExpectedWarning ("IL3050", nameof (Type.MakeGenericType), ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3050", nameof (Type.MakeGenericType), Tool.Analyzer | Tool.NativeAot, "")] public static void TestUnknownArgument () => typeof (Gen<>).MakeGenericType (GrabUnknownType ()); } @@ -62,10 +62,10 @@ public static void Test () public static void TestRecognizedGenericIntrinsic () => typeof (MakeGenericMethod).GetMethod (nameof (Gen)).MakeGenericMethod (typeof (T)); [ExpectedWarning ("IL2060", nameof (MethodInfo.MakeGenericMethod))] - [ExpectedWarning ("IL3050", nameof (MethodInfo.MakeGenericMethod), ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3050", nameof (MethodInfo.MakeGenericMethod), Tool.Analyzer | Tool.NativeAot, "")] public static void TestUnknownOwningMethod () => GrabUnknownMethod ().MakeGenericMethod (typeof (object)); - [ExpectedWarning ("IL3050", nameof (MethodInfo.MakeGenericMethod), ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3050", nameof (MethodInfo.MakeGenericMethod), Tool.Analyzer | Tool.NativeAot, "")] public static void TestUnknownArgument () => typeof (MakeGenericMethod).GetMethod (nameof (Gen)).MakeGenericMethod (GrabUnknownType()); } } diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/MethodByRefParameterDataFlow.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/MethodByRefParameterDataFlow.cs index 7ea036c5c39bbd..4396d6c26e3b2f 100644 --- a/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/MethodByRefParameterDataFlow.cs +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/MethodByRefParameterDataFlow.cs @@ -123,7 +123,7 @@ static void TestReadFromRefParameter_MismatchOnOutput_PassedTwice () // https://github.com/dotnet/linker/issues/2632 // This second warning should not be generated, the value of typeWithMethods should have PublicMethods // after the call with out parameter. - [ExpectedWarning ("IL2072", nameof (DataFlowTypeExtensions.RequiresPublicMethods), ProducedBy = Tool.Analyzer)] + [ExpectedWarning ("IL2072", nameof (DataFlowTypeExtensions.RequiresPublicMethods), Tool.Analyzer, "")] static void TestReadFromRefParameter_MismatchOnInput () { Type typeWithMethods = GetTypeWithFields (); @@ -136,7 +136,7 @@ static void TestReadFromRefParameter_MismatchOnInput () // https://github.com/dotnet/linker/issues/2632 // This third warning should not be generated, the value of typeWithMethods should have PublicMethods // after the call with ref parameter. - [ExpectedWarning ("IL2072", nameof (DataFlowTypeExtensions.RequiresPublicMethods), ProducedBy = Tool.Analyzer)] + [ExpectedWarning ("IL2072", nameof (DataFlowTypeExtensions.RequiresPublicMethods), Tool.Analyzer, "")] static void TestReadFromRefParameter_MismatchOnInput_PassedTwice () { Type typeWithMethods = GetTypeWithFields (); @@ -269,7 +269,7 @@ static void TestPassingRefProperty_OutParameter () TryGetAnnotatedValueOut (out TypeWithMethodsProperty); } - [ExpectedWarning ("IL2072", nameof (TryGetAnnotatedValue), ProducedBy = Tool.Trimmer | Tool.NativeAot)] + [ExpectedWarning ("IL2072", nameof (TryGetAnnotatedValue), Tool.Trimmer | Tool.NativeAot, "")] static void TestPassingRefProperty_Mismatch () { TryGetAnnotatedValue (ref TypeWithFieldsProperty); @@ -316,8 +316,8 @@ static void TestPassingRefIndexer_OutParameter () } // https://github.com/dotnet/linker/issues/2158 - [ExpectedWarning ("IL2068", nameof (TryGetAnnotatedValue), ProducedBy = Tool.Trimmer | Tool.NativeAot)] - [ExpectedWarning ("IL2072", nameof (TryGetAnnotatedValue), ProducedBy = Tool.Trimmer | Tool.NativeAot)] + [ExpectedWarning ("IL2068", nameof (TryGetAnnotatedValue), Tool.Trimmer | Tool.NativeAot, "")] + [ExpectedWarning ("IL2072", nameof (TryGetAnnotatedValue), Tool.Trimmer | Tool.NativeAot, "")] static void TestPassingRefIndexer_Mismatch () { var indexer = new RefIndexer_PublicFields (); @@ -325,7 +325,7 @@ static void TestPassingRefIndexer_Mismatch () } // https://github.com/dotnet/linker/issues/2158 - [ExpectedWarning ("IL2068", nameof (TryGetAnnotatedValue), ProducedBy = Tool.Trimmer | Tool.NativeAot)] + [ExpectedWarning ("IL2068", nameof (TryGetAnnotatedValue), Tool.Trimmer | Tool.NativeAot, "")] static void TestPassingRefIndexer_OutParameter_Mismatch () { var indexer = new RefIndexer_PublicFields (); diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/MethodByRefReturnDataFlow.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/MethodByRefReturnDataFlow.cs index 7220a83d3ce2dd..99978295d67570 100644 --- a/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/MethodByRefReturnDataFlow.cs +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/MethodByRefReturnDataFlow.cs @@ -43,7 +43,7 @@ public static void Main () // Correct behavior in the trimming tools, but needs to be added in analyzer // Bug link: https://github.com/dotnet/linker/issues/2158 - [ExpectedWarning ("IL2026", "Message for --TestType.Requires--", ProducedBy = Tool.Trimmer | Tool.NativeAot)] + [ExpectedWarning ("IL2026", "Message for --TestType.Requires--", Tool.Trimmer | Tool.NativeAot, "")] static void AssignToAnnotatedTypeReference () { ref Type typeShouldHaveAllMethods = ref ReturnAnnotatedTypeReferenceAsAnnotated (); @@ -53,7 +53,7 @@ static void AssignToAnnotatedTypeReference () // Same as above for IL analysis, but this looks different to the Roslyn analyzer. // https://github.com/dotnet/linker/issues/2158 - [ExpectedWarning ("IL2026", "Message for --TestType.Requires--", ProducedBy = Tool.Trimmer | Tool.NativeAot)] + [ExpectedWarning ("IL2026", "Message for --TestType.Requires--", Tool.Trimmer | Tool.NativeAot, "")] static void AssignDirectlyToAnnotatedTypeReference () { ReturnAnnotatedTypeReferenceAsAnnotated () = typeof (TestTypeWithRequires); @@ -61,7 +61,7 @@ static void AssignDirectlyToAnnotatedTypeReference () } // https://github.com/dotnet/linker/issues/2158 - [ExpectedWarning ("IL2073", nameof (GetWithPublicFields), ProducedBy = Tool.Trimmer | Tool.NativeAot)] + [ExpectedWarning ("IL2073", nameof (GetWithPublicFields), Tool.Trimmer | Tool.NativeAot, "")] static void AssignToCapturedAnnotatedTypeReference () { // In this testcase, the Roslyn analyzer sees an assignment to a flow-capture reference. @@ -69,7 +69,7 @@ static void AssignToCapturedAnnotatedTypeReference () } [ExpectedWarning ("IL2072", nameof (GetWithPublicMethods), nameof (ReturnAnnotatedTypeWithRequirements))] - [ExpectedWarning ("IL2073", nameof (ReturnAnnotatedTypeWithRequirements), nameof (GetWithPublicFields), ProducedBy = Tool.Trimmer | Tool.NativeAot)] + [ExpectedWarning ("IL2073", nameof (ReturnAnnotatedTypeWithRequirements), nameof (GetWithPublicFields), Tool.Trimmer | Tool.NativeAot, "")] static void AssignToAnnotatedTypeReferenceWithRequirements () { ReturnAnnotatedTypeWithRequirements (GetWithPublicMethods ()) = GetWithPublicFields (); @@ -80,7 +80,7 @@ static void AssignToAnnotatedTypeReferenceWithRequirements () [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] static ref Type AnnotatedTypeReferenceAsAnnotatedProperty => ref _annotatedField; - [ExpectedWarning ("IL2026", "Message for --TestType.Requires--", ProducedBy = Tool.Trimmer | Tool.NativeAot)] + [ExpectedWarning ("IL2026", "Message for --TestType.Requires--", Tool.Trimmer | Tool.NativeAot, "")] static void AssignToAnnotatedTypeReferenceProperty () { ref Type typeShouldHaveAllMethods = ref AnnotatedTypeReferenceAsAnnotatedProperty; @@ -89,7 +89,7 @@ static void AssignToAnnotatedTypeReferenceProperty () } // https://github.com/dotnet/linker/issues/2158 - [ExpectedWarning ("IL2026", "Message for --TestType.Requires--", ProducedBy = Tool.Trimmer | Tool.NativeAot)] + [ExpectedWarning ("IL2026", "Message for --TestType.Requires--", Tool.Trimmer | Tool.NativeAot, "")] static void AssignDirectlyToAnnotatedTypeReferenceProperty () { AnnotatedTypeReferenceAsAnnotatedProperty = typeof (TestTypeWithRequires); @@ -97,7 +97,7 @@ static void AssignDirectlyToAnnotatedTypeReferenceProperty () } // https://github.com/dotnet/linker/issues/2158 - [ExpectedWarning ("IL2073", nameof (GetWithPublicFields), ProducedBy = Tool.Trimmer | Tool.NativeAot)] + [ExpectedWarning ("IL2073", nameof (GetWithPublicFields), Tool.Trimmer | Tool.NativeAot, "")] static void AssignToCapturedAnnotatedTypeReferenceProperty () { AnnotatedTypeReferenceAsAnnotatedProperty = GetWithPublicMethods () ?? GetWithPublicFields (); diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/MethodOutParameterDataFlow.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/MethodOutParameterDataFlow.cs index 582c86ee012b4b..22f7bd5e8b1274 100644 --- a/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/MethodOutParameterDataFlow.cs +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/MethodOutParameterDataFlow.cs @@ -76,7 +76,7 @@ static void TestInitializedReadFromOutParameter_MismatchOnOutput_PassedTwice () // https://github.com/dotnet/linker/issues/2632 // This warning should not be generated, the value of typeWithMethods should have PublicMethods // after the call with out parameter. - [ExpectedWarning ("IL2072", nameof (DataFlowTypeExtensions.RequiresPublicMethods), ProducedBy = Tool.Analyzer)] + [ExpectedWarning ("IL2072", nameof (DataFlowTypeExtensions.RequiresPublicMethods), Tool.Analyzer, "")] static void TestInitializedReadFromOutParameter_MismatchOnInput () { Type typeWithMethods = GetTypeWithFields (); @@ -89,7 +89,7 @@ static void TestInitializedReadFromOutParameter_MismatchOnInput () // https://github.com/dotnet/linker/issues/2632 // This warning should not be generated, the value of typeWithMethods should have PublicMethods // after the call with out parameter. - [ExpectedWarning ("IL2072", nameof (DataFlowTypeExtensions.RequiresPublicMethods), ProducedBy = Tool.Analyzer)] + [ExpectedWarning ("IL2072", nameof (DataFlowTypeExtensions.RequiresPublicMethods), Tool.Analyzer, "")] static void TestInitializedReadFromOutParameter_MismatchOnInput_PassedTwice () { Type typeWithMethods = GetTypeWithFields (); diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/MethodParametersDataFlow.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/MethodParametersDataFlow.cs index 0c6c1d02d8c10c..aa2783332e429e 100644 --- a/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/MethodParametersDataFlow.cs +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/MethodParametersDataFlow.cs @@ -142,8 +142,6 @@ private void TwoAnnotatedParameters ( type2.RequiresPublicConstructors (); } - // TODO: https://github.com/dotnet/linker/issues/2273 - // (Dataflow analysis is not supported by the analyzer yet) [ExpectedWarning ("IL2067", nameof (DataFlowTypeExtensions) + "." + nameof (DataFlowTypeExtensions.RequiresPublicConstructors) + "(Type)", "'type'")] @@ -246,7 +244,7 @@ class UnsupportedType () static UnsupportedType GetUnsupportedTypeInstance () => null; [ExpectedWarning ("IL2098", nameof (UnsupportedType))] - [ExpectedWarning ("IL2067", ProducedBy = Tool.Analyzer)] // https://github.com/dotnet/runtime/issues/101211 + [ExpectedWarning ("IL2067", Tool.Analyzer, "")] // https://github.com/dotnet/runtime/issues/101211 static void RequirePublicMethods ( [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] UnsupportedType unsupportedTypeInstance) @@ -261,7 +259,7 @@ static void RequirePublicFields ( { } - [ExpectedWarning ("IL2072", ProducedBy = Tool.Analyzer)] // https://github.com/dotnet/runtime/issues/101211 + [ExpectedWarning ("IL2072", Tool.Analyzer, "")] // https://github.com/dotnet/runtime/issues/101211 public static void Test () { var t = GetUnsupportedTypeInstance (); RequirePublicMethods (t); diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/MethodReturnParameterDataFlow.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/MethodReturnParameterDataFlow.cs index 4bd9257124654b..8f3adcbdaa0889 100644 --- a/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/MethodReturnParameterDataFlow.cs +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/MethodReturnParameterDataFlow.cs @@ -190,7 +190,7 @@ class AnnotationOnUnsupportedReturnType { class UnsupportedType { - [ExpectedWarning ("IL2082", ProducedBy = Tool.Analyzer)] // https://github.com/dotnet/runtime/issues/101211 + [UnexpectedWarning ("IL2082", Tool.Analyzer, "")] // https://github.com/dotnet/runtime/issues/101211 public UnsupportedType () { RequirePublicFields (this); } @@ -202,7 +202,7 @@ public UnsupportedType () { // Linker and NativeAot should not produce IL2073 // They produce dataflow warnings despite the invalid annotations. // https://github.com/dotnet/runtime/issues/101211 - [ExpectedWarning ("IL2073", ProducedBy = Tool.Trimmer | Tool.NativeAot)] + [ExpectedWarning ("IL2073", Tool.Trimmer | Tool.NativeAot, "")] [return: DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] static UnsupportedType GetWithPublicMethods () { return GetUnsupportedTypeInstance (); @@ -215,7 +215,7 @@ static void RequirePublicFields ( { } - [ExpectedWarning ("IL2072", ProducedBy = Tool.Analyzer)] // https://github.com/dotnet/runtime/issues/101211 + [ExpectedWarning ("IL2072", Tool.Analyzer, "")] // https://github.com/dotnet/runtime/issues/101211 static void TestMethodReturnValue () { var t = GetWithPublicMethods (); RequirePublicFields (t); diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/MethodThisDataFlow.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/MethodThisDataFlow.cs index 28dc0669d2aa02..50ae6925bdb4ef 100644 --- a/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/MethodThisDataFlow.cs +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/MethodThisDataFlow.cs @@ -122,7 +122,7 @@ static void RequirePublicFields ( [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] UnsupportedType unsupportedTypeInstance) { } - [ExpectedWarning ("IL2075", nameof (UnsupportedType), nameof (UnsupportedType.GetMethod), ProducedBy = Tool.Analyzer)] // BUG + [ExpectedWarning ("IL2075", nameof (UnsupportedType), nameof (UnsupportedType.GetMethod), Tool.Analyzer, "")] // BUG static void TestMethodThisParameter () { var t = GetUnsupportedTypeInstance (); t.GetMethod ("foo"); diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/PropertyDataFlow.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/PropertyDataFlow.cs index 1a8930c8a7c8e0..76a1a48a06425c 100644 --- a/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/PropertyDataFlow.cs +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/PropertyDataFlow.cs @@ -215,8 +215,7 @@ static Type PropertyWithSimpleGetter { // is highly unlikely to be done by anybody. If it happens, the analyzer will produce warnings which the trimming tools will not // but those warnings are not really wrong, so it's better if the developer fixes them anyway. [ExpectedWarning ("IL2077", nameof (DataFlowTypeExtensions) + "." + nameof (DataFlowTypeExtensions.RequiresPublicConstructors) + "(Type)", - nameof (TestAutomaticPropagationType) + "." + nameof (PropertyWhichLooksLikeCompilerGenerated_Field), - ProducedBy = Tool.Analyzer)] + nameof (TestAutomaticPropagationType) + "." + nameof (PropertyWhichLooksLikeCompilerGenerated_Field), Tool.Analyzer, "")] public void TestPropertyWhichLooksLikeCompilerGenerated () { // If the property was correctly recognized both the property getter and the backing field should get the annotation. @@ -231,8 +230,7 @@ public void TestPropertyWhichLooksLikeCompilerGenerated () static Type PropertyWhichLooksLikeCompilerGenerated { // See above comment about fake compiler generated backing fields - this warning is expected from the analyzer [ExpectedWarning ("IL2078", nameof (TestAutomaticPropagationType) + "." + nameof (PropertyWhichLooksLikeCompilerGenerated) + ".get", - nameof (TestAutomaticPropagationType) + "." + nameof (PropertyWhichLooksLikeCompilerGenerated_Field), - ProducedBy = Tool.Analyzer)] + nameof (TestAutomaticPropagationType) + "." + nameof (PropertyWhichLooksLikeCompilerGenerated_Field), Tool.Analyzer, "")] get { return PropertyWhichLooksLikeCompilerGenerated_Field; } @@ -272,17 +270,14 @@ public void TestPropertyWithDifferentBackingFields () // Analyzer doesn't try to detect backing fields of properties: https://github.com/dotnet/linker/issues/2273 [ExpectedWarning ("IL2042", - "Mono.Linker.Tests.Cases.DataFlow.PropertyDataFlow.TestAutomaticPropagationType.PropertyWithDifferentBackingFields", - ProducedBy = Tool.Trimmer | Tool.NativeAot)] + "Mono.Linker.Tests.Cases.DataFlow.PropertyDataFlow.TestAutomaticPropagationType.PropertyWithDifferentBackingFields", Tool.Trimmer | Tool.NativeAot, "")] [ExpectedWarning ("IL2078", nameof (TestAutomaticPropagationType) + "." + nameof (PropertyWithDifferentBackingFields) + ".get", - "Type", - ProducedBy = Tool.Analyzer)] + "Type", Tool.Analyzer, "")] [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicConstructors)] Type PropertyWithDifferentBackingFields { [ExpectedWarning ("IL2078", - nameof (TestAutomaticPropagationType) + "." + nameof (PropertyWithDifferentBackingFields) + ".get", - ProducedBy = Tool.Trimmer | Tool.NativeAot)] + nameof (TestAutomaticPropagationType) + "." + nameof (PropertyWithDifferentBackingFields) + ".get", Tool.Trimmer | Tool.NativeAot, "")] get { return PropertyWithDifferentBackingFields_GetterField; } @@ -299,25 +294,22 @@ public void TestPropertyWithExistingAttributes () } // Analyzer doesn't try to detect backing fields of properties: https://github.com/dotnet/linker/issues/2273 - [ExpectedWarning ("IL2056", "PropertyWithExistingAttributes", "PropertyWithExistingAttributes_Field", - ProducedBy = Tool.Trimmer | Tool.NativeAot)] + [ExpectedWarning ("IL2056", "PropertyWithExistingAttributes", "PropertyWithExistingAttributes_Field", Tool.Trimmer | Tool.NativeAot, "")] [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicConstructors)] [CompilerGenerated] Type PropertyWithExistingAttributes_Field; - [ExpectedWarning ("IL2043", "PropertyWithExistingAttributes", "PropertyWithExistingAttributes.get", ProducedBy = Tool.Analyzer)] - [ExpectedWarning ("IL2043", "PropertyWithExistingAttributes", "PropertyWithExistingAttributes.set", ProducedBy = Tool.Analyzer)] + [ExpectedWarning ("IL2043", ["PropertyWithExistingAttributes", "PropertyWithExistingAttributes.get"], Tool.Analyzer, "")] + [ExpectedWarning ("IL2043", [ "PropertyWithExistingAttributes", "PropertyWithExistingAttributes.set"], Tool.Analyzer, "")] [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicConstructors)] Type PropertyWithExistingAttributes { // On property/accessor mismatch, ILLink warns on accessor and analyzer warns on property https://github.com/dotnet/linker/issues/2654 - [ExpectedWarning ("IL2043", "PropertyWithExistingAttributes", "PropertyWithExistingAttributes.get", - ProducedBy = Tool.Trimmer | Tool.NativeAot)] + [ExpectedWarning ("IL2043", "PropertyWithExistingAttributes", "PropertyWithExistingAttributes.get", Tool.Trimmer | Tool.NativeAot, "")] [return: DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicConstructors)] get { return PropertyWithExistingAttributes_Field; } // On property/accessor mismatch, ILLink warns on accessor and analyzer warns on property https://github.com/dotnet/linker/issues/2654 - [ExpectedWarning ("IL2043", "PropertyWithExistingAttributes", "PropertyWithExistingAttributes.set", - ProducedBy = Tool.Trimmer | Tool.NativeAot)] + [ExpectedWarning ("IL2043", "PropertyWithExistingAttributes", "PropertyWithExistingAttributes.set", Tool.Trimmer | Tool.NativeAot, "")] [param: DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicConstructors)] set { PropertyWithExistingAttributes_Field = value; } } @@ -337,25 +329,22 @@ public void TestPropertyWithConflictingAttributes () } // Analyzer doesn't try to detect backing fields of properties: https://github.com/dotnet/linker/issues/2273 - [ExpectedWarning ("IL2056", "PropertyWithConflictingAttributes", "PropertyWithConflictingAttributes_Field", - ProducedBy = Tool.Trimmer | Tool.NativeAot)] + [ExpectedWarning ("IL2056", "PropertyWithConflictingAttributes", "PropertyWithConflictingAttributes_Field", Tool.Trimmer | Tool.NativeAot, "")] [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.NonPublicConstructors)] [CompilerGenerated] Type PropertyWithConflictingAttributes_Field; - [ExpectedWarning ("IL2043", "PropertyWithConflictingAttributes", "PropertyWithConflictingAttributes.get", ProducedBy = Tool.Analyzer)] - [ExpectedWarning ("IL2043", "PropertyWithConflictingAttributes", "PropertyWithConflictingAttributes.set", ProducedBy = Tool.Analyzer)] + [ExpectedWarning ("IL2043", ["PropertyWithConflictingAttributes", "PropertyWithConflictingAttributes.get"], Tool.Analyzer, "")] + [ExpectedWarning ("IL2043", ["PropertyWithConflictingAttributes", "PropertyWithConflictingAttributes.set"], Tool.Analyzer, "")] [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicConstructors)] Type PropertyWithConflictingAttributes { // On property/accessor mismatch, ILLink warns on accessor and analyzer warns on property https://github.com/dotnet/linker/issues/2654 - [ExpectedWarning ("IL2043", "PropertyWithConflictingAttributes", "PropertyWithConflictingAttributes.get", - ProducedBy = Tool.Trimmer | Tool.NativeAot)] + [ExpectedWarning ("IL2043", "PropertyWithConflictingAttributes", "PropertyWithConflictingAttributes.get", Tool.Trimmer | Tool.NativeAot, "")] [return: DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.NonPublicConstructors)] get { return PropertyWithConflictingAttributes_Field; } // On property/accessor mismatch, ILLink warns on accessor and analyzer warns on property https://github.com/dotnet/linker/issues/2654 - [ExpectedWarning ("IL2043", "PropertyWithConflictingAttributes", "PropertyWithConflictingAttributes.set", - ProducedBy = Tool.Trimmer | Tool.NativeAot)] + [ExpectedWarning ("IL2043", "PropertyWithConflictingAttributes", "PropertyWithConflictingAttributes.set", Tool.Trimmer | Tool.NativeAot, "")] [param: DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.NonPublicConstructors)] set { PropertyWithConflictingAttributes_Field = value; } } @@ -382,8 +371,7 @@ public void TestPropertyWithConflictingNoneAttributes () Type PropertyWithConflictingNoneAttributes { // See above comment about fake compiler generated backing fields - this warning is expected from analyzer [ExpectedWarning ("IL2078", nameof (TestAutomaticPropagationType) + "." + nameof (PropertyWithConflictingNoneAttributes) + ".get", - nameof (TestAutomaticPropagationType) + "." + nameof (PropertyWithConflictingNoneAttributes_Field), - ProducedBy = Tool.Analyzer)] + nameof (TestAutomaticPropagationType) + "." + nameof (PropertyWithConflictingNoneAttributes_Field), Tool.Analyzer, "")] [return: DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.None)] get { return PropertyWithConflictingNoneAttributes_Field; } @@ -399,8 +387,8 @@ public void TestPropertyWithIndexerWithMatchingAnnotations ([DynamicallyAccessed } // Trimmer and analyzer handle formatting of indexers differently. - [ExpectedWarning ("IL2067", nameof (PropertyWithIndexer) + ".Item.set", ProducedBy = Tool.Trimmer | Tool.NativeAot)] - [ExpectedWarning ("IL2067", nameof (PropertyWithIndexer) + ".this[Int32].set", ProducedBy = Tool.Analyzer)] + [ExpectedWarning ("IL2067", nameof (PropertyWithIndexer) + ".Item.set", Tool.Trimmer | Tool.NativeAot, "")] + [ExpectedWarning ("IL2067", nameof (PropertyWithIndexer) + ".this[Int32].set", Tool.Analyzer, "")] [ExpectedWarning ("IL2072", nameof (DataFlowTypeExtensions) + "." + nameof (DataFlowTypeExtensions.RequiresNonPublicConstructors) + "(Type)")] [LogDoesNotContain ("'Value passed to parameter 'index' of method 'Mono.Linker.Tests.Cases.DataFlow.PropertyDataFlow.TestAutomaticPropagationType.PropertyWithIndexer.Item.set'")] public void TestPropertyWithIndexerWithoutMatchingAnnotations (Type myType) @@ -418,8 +406,8 @@ public class PropertyWithIndexer [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicConstructors)] public Type this[int index] { // Trimmer and analyzer handle formatting of indexers differently. - [ExpectedWarning ("IL2063", nameof (PropertyWithIndexer) + ".Item.get", ProducedBy = Tool.Trimmer | Tool.NativeAot)] - [ExpectedWarning ("IL2063", nameof (PropertyWithIndexer) + ".this[Int32].get", ProducedBy = Tool.Analyzer)] + [ExpectedWarning ("IL2063", nameof (PropertyWithIndexer) + ".Item.get", Tool.Trimmer | Tool.NativeAot, "")] + [ExpectedWarning ("IL2063", nameof (PropertyWithIndexer) + ".this[Int32].get", Tool.Analyzer, "")] get => Property_Field[index]; set => Property_Field[index] = value; } @@ -482,8 +470,7 @@ class WriteToGetOnlyProperty public Type GetOnlyProperty { get; } // Analyzer doesn't warn about compiler-generated backing field of property: https://github.com/dotnet/runtime/issues/93277 - [ExpectedWarning ("IL2074", nameof (WriteToGetOnlyProperty), nameof (GetUnknownType), - ProducedBy = Tool.Trimmer | Tool.NativeAot)] + [ExpectedWarning ("IL2074", nameof (WriteToGetOnlyProperty), nameof (GetUnknownType), Tool.Trimmer | Tool.NativeAot, "")] public WriteToGetOnlyProperty () { GetOnlyProperty = GetUnknownType (); @@ -562,10 +549,8 @@ class WriteCapturedGetOnlyProperty Type GetOnlyProperty { get; } // Analyzer doesn't warn about compiler-generated backing field of property: https://github.com/dotnet/runtime/issues/93277 - [ExpectedWarning ("IL2074", nameof (WriteCapturedGetOnlyProperty), nameof (GetUnknownType), - ProducedBy = Tool.Trimmer | Tool.NativeAot)] - [ExpectedWarning ("IL2074", nameof (WriteCapturedGetOnlyProperty), nameof (GetTypeWithPublicConstructors), - ProducedBy = Tool.Trimmer | Tool.NativeAot)] + [ExpectedWarning ("IL2074", nameof (WriteCapturedGetOnlyProperty), nameof (GetUnknownType), Tool.Trimmer | Tool.NativeAot, "")] + [ExpectedWarning ("IL2074", nameof (WriteCapturedGetOnlyProperty), nameof (GetTypeWithPublicConstructors), Tool.Trimmer | Tool.NativeAot, "")] public WriteCapturedGetOnlyProperty () { GetOnlyProperty = GetUnknownType () ?? GetTypeWithPublicConstructors (); @@ -677,15 +662,15 @@ Type this[Index idx] { set => throw new NotImplementedException (); } - [ExpectedWarning ("IL2072", "this[Index].get", nameof (DataFlowTypeExtensions.RequiresAll), ProducedBy = Tool.Analyzer)] - [ExpectedWarning ("IL2072", "Item.get", nameof (DataFlowTypeExtensions.RequiresAll), ProducedBy = Tool.Trimmer | Tool.NativeAot)] + [ExpectedWarning ("IL2072", ["this[Index].get", nameof (DataFlowTypeExtensions.RequiresAll)], Tool.Analyzer, "")] + [ExpectedWarning ("IL2072", ["Item.get", nameof (DataFlowTypeExtensions.RequiresAll)], Tool.Trimmer | Tool.NativeAot, "")] static void TestRead (ExplicitIndexerAccess instance = null) { instance[new Index (1)].RequiresAll (); } - [ExpectedWarning ("IL2072", nameof (GetTypeWithPublicConstructors), "this[Index].set", ProducedBy = Tool.Analyzer)] - [ExpectedWarning ("IL2072", nameof (GetTypeWithPublicConstructors), "Item.set", ProducedBy = Tool.Trimmer | Tool.NativeAot)] + [ExpectedWarning ("IL2072", [nameof (GetTypeWithPublicConstructors), "this[Index].set"], Tool.Analyzer, "")] + [ExpectedWarning ("IL2072", [nameof (GetTypeWithPublicConstructors), "Item.set"], Tool.Trimmer | Tool.NativeAot, "")] static void TestWrite (ExplicitIndexerAccess instance = null) { instance[^1] = GetTypeWithPublicConstructors (); @@ -708,22 +693,22 @@ Type this[int idx] { int Length => throw new NotImplementedException (); - [ExpectedWarning ("IL2072", "this[Int32].get", nameof (DataFlowTypeExtensions.RequiresAll), ProducedBy = Tool.Analyzer)] - [ExpectedWarning ("IL2072", "Item.get", nameof (DataFlowTypeExtensions.RequiresAll), ProducedBy = Tool.Trimmer | Tool.NativeAot)] + [ExpectedWarning ("IL2072", ["this[Int32].get", nameof (DataFlowTypeExtensions.RequiresAll)], Tool.Analyzer, "")] + [ExpectedWarning ("IL2072", ["Item.get", nameof (DataFlowTypeExtensions.RequiresAll)], Tool.Trimmer | Tool.NativeAot, "")] static void TestRead (ImplicitIndexerAccess instance = null) { instance[new Index (1)].RequiresAll (); } - [ExpectedWarning ("IL2072", nameof (GetTypeWithPublicConstructors), "this[Int32].set", ProducedBy = Tool.Analyzer)] - [ExpectedWarning ("IL2072", nameof (GetTypeWithPublicConstructors), "Item.set", ProducedBy = Tool.Trimmer | Tool.NativeAot)] + [ExpectedWarning ("IL2072", [nameof (GetTypeWithPublicConstructors), "this[Int32].set"], Tool.Analyzer, "")] + [ExpectedWarning ("IL2072", [nameof (GetTypeWithPublicConstructors), "Item.set"], Tool.Trimmer | Tool.NativeAot, "")] static void TestWrite (ImplicitIndexerAccess instance = null) { instance[^1] = GetTypeWithPublicConstructors (); } - [ExpectedWarning ("IL2072", nameof (GetUnknownType), "this[Int32].set", ProducedBy = Tool.Analyzer)] - [ExpectedWarning ("IL2072", nameof (GetUnknownType), "Item.set", ProducedBy = Tool.Trimmer | Tool.NativeAot)] + [ExpectedWarning ("IL2072", [nameof (GetUnknownType), "this[Int32].set"], Tool.Analyzer, "")] + [ExpectedWarning ("IL2072", [nameof (GetUnknownType), "Item.set"], Tool.Trimmer | Tool.NativeAot, "")] static void TestNullCoalescingAssignment (ImplicitIndexerAccess instance = null) { instance[new Index (1)] ??= GetUnknownType (); @@ -747,8 +732,8 @@ int this[[DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicField get => throw new NotImplementedException (); } - [ExpectedWarning ("IL2067", "this[Type].get", nameof (ParamDoesNotMeetRequirements), ProducedBy = Tool.Analyzer)] - [ExpectedWarning ("IL2067", "Item.get", nameof (ParamDoesNotMeetRequirements), ProducedBy = Tool.Trimmer | Tool.NativeAot)] + [ExpectedWarning ("IL2067", ["this[Type].get", nameof (ParamDoesNotMeetRequirements)], Tool.Analyzer, "")] + [ExpectedWarning ("IL2067", ["Item.get", nameof (ParamDoesNotMeetRequirements)], Tool.Trimmer | Tool.NativeAot, "")] static void ParamDoesNotMeetRequirements (Type t) { var x = new IndexWithTypeWithDam (); @@ -761,8 +746,8 @@ static void ParamDoesMeetRequirements ([DynamicallyAccessedMembers (DynamicallyA _ = x[t]; } - [ExpectedWarning ("IL2087", "this[Type].get", nameof (TypeParamDoesNotMeetRequirements), ProducedBy = Tool.Analyzer)] - [ExpectedWarning ("IL2087", "Item.get", nameof (TypeParamDoesNotMeetRequirements), ProducedBy = Tool.Trimmer | Tool.NativeAot)] + [ExpectedWarning ("IL2087", ["this[Type].get", nameof (TypeParamDoesNotMeetRequirements)], Tool.Analyzer, "")] + [ExpectedWarning ("IL2087", ["Item.get", nameof (TypeParamDoesNotMeetRequirements)], Tool.Trimmer | Tool.NativeAot, "")] static void TypeParamDoesNotMeetRequirements () { var x = new IndexWithTypeWithDam (); @@ -802,8 +787,8 @@ Type this[[DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicFiel [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] static Type fieldWithMethods; - [ExpectedWarning ("IL2067", "this[Type].get", nameof (ParamDoesNotMeetRequirements), ProducedBy = Tool.Analyzer)] - [ExpectedWarning ("IL2067", "Item.get", nameof (ParamDoesNotMeetRequirements), ProducedBy = Tool.Trimmer | Tool.NativeAot)] + [ExpectedWarning ("IL2067", ["this[Type].get", nameof (ParamDoesNotMeetRequirements)], Tool.Analyzer, "")] + [ExpectedWarning ("IL2067", ["Item.get", nameof (ParamDoesNotMeetRequirements)], Tool.Trimmer | Tool.NativeAot, "")] static void ParamDoesNotMeetRequirements (Type t) { var x = new IndexWithTypeWithDam (); @@ -816,8 +801,8 @@ static void ParamDoesMeetRequirements ([DynamicallyAccessedMembers (DynamicallyA fieldWithMethods = x[t]; } - [ExpectedWarning ("IL2087", "this[Type].get", nameof (TypeParamDoesNotMeetRequirements), ProducedBy = Tool.Analyzer)] - [ExpectedWarning ("IL2087", "Item.get", nameof (TypeParamDoesNotMeetRequirements), ProducedBy = Tool.Trimmer | Tool.NativeAot)] + [ExpectedWarning ("IL2087", ["this[Type].get", nameof (TypeParamDoesNotMeetRequirements)], Tool.Analyzer, "")] + [ExpectedWarning ("IL2087", ["Item.get", nameof (TypeParamDoesNotMeetRequirements)], Tool.Trimmer | Tool.NativeAot, "")] static void TypeParamDoesNotMeetRequirements () { var x = new IndexWithTypeWithDam (); @@ -839,16 +824,16 @@ static void KnownTypeDoesMeetRequirements () fieldWithMethods = x[t]; } - [ExpectedWarning ("IL2067", "this[Type].set", nameof (t), "idx", ProducedBy = Tool.Analyzer)] - [ExpectedWarning ("IL2067", "Item.set", nameof (t), "idx", ProducedBy = Tool.Trimmer | Tool.NativeAot)] + [ExpectedWarning ("IL2067", ["this[Type].set", nameof (t), "idx"], Tool.Analyzer, "")] + [ExpectedWarning ("IL2067", ["Item.set", nameof (t), "idx"], Tool.Trimmer | Tool.NativeAot, "")] static void ValueMeetsRequirementsIndexDoesNot (Type t) { var x = new IndexWithTypeWithDam (); x[t] = fieldWithMethods; } - [ExpectedWarning ("IL2067", "this[Type].set", nameof (tUnannotated), "value", ProducedBy = Tool.Analyzer)] - [ExpectedWarning ("IL2067", "Item.set", nameof (tUnannotated), "value", ProducedBy = Tool.Trimmer | Tool.NativeAot)] + [ExpectedWarning ("IL2067", ["this[Type].set", nameof (tUnannotated), "value"], Tool.Analyzer, "")] + [ExpectedWarning ("IL2067", ["Item.set", nameof (tUnannotated), "value"], Tool.Trimmer | Tool.NativeAot, "")] static void ValueDoesNotMeetRequirementsIndexDoes ([DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicFields)] Type t, Type tUnannotated) { var x = new IndexWithTypeWithDam (); diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/RefFieldDataFlow.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/RefFieldDataFlow.cs index 415dff13582ba6..983fc35c0b11eb 100644 --- a/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/RefFieldDataFlow.cs +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/RefFieldDataFlow.cs @@ -14,10 +14,10 @@ class RefFieldDataFlow { [Kept] // Bug for the IL2069's here: https://github.com/dotnet/runtime/issues/85464 - [ExpectedWarning ("IL2069", ProducedBy = Tool.Trimmer | Tool.NativeAot)] - [ExpectedWarning ("IL2069", ProducedBy = Tool.Trimmer | Tool.NativeAot)] - [ExpectedWarning ("IL2069", ProducedBy = Tool.Trimmer | Tool.NativeAot)] - [ExpectedWarning ("IL2069", ProducedBy = Tool.Trimmer | Tool.NativeAot)] + [ExpectedWarning ("IL2069", Tool.Trimmer | Tool.NativeAot, "")] + [ExpectedWarning ("IL2069", Tool.Trimmer | Tool.NativeAot, "")] + [ExpectedWarning ("IL2069", Tool.Trimmer | Tool.NativeAot, "")] + [ExpectedWarning ("IL2069", Tool.Trimmer | Tool.NativeAot, "")] public static void Main () { RefFieldWithMethods withMethods = new (ref fieldWithMethods); @@ -96,11 +96,11 @@ static void AssignRefToLocals< tmf = typeof (TF); // This is a hole that doesn't warn but assigns a misannotated value to target.T } - [ExpectedWarning ("IL2089", "RefFieldWithMethods", "T", ProducedBy = Tool.Trimmer | Tool.NativeAot)] - [ExpectedWarning ("IL2089", "RefFieldWithFields", "T", ProducedBy = Tool.Trimmer | Tool.NativeAot)] - [ExpectedWarning ("IL2089", "RefFieldWithMethodsAndFields", "T", ProducedBy = Tool.Trimmer | Tool.NativeAot)] - [ExpectedWarning ("IL2089", "RefFieldWithMethodsAndFields", "T", ProducedBy = Tool.Trimmer | Tool.NativeAot)] - [ExpectedWarning ("IL2089", "RefFieldWithFields", "T", ProducedBy = Tool.Trimmer | Tool.NativeAot)] + [ExpectedWarning ("IL2089", "RefFieldWithMethods", "T", Tool.Trimmer | Tool.NativeAot, "")] + [ExpectedWarning ("IL2089", "RefFieldWithFields", "T", Tool.Trimmer | Tool.NativeAot, "")] + [ExpectedWarning ("IL2089", "RefFieldWithMethodsAndFields", "T", Tool.Trimmer | Tool.NativeAot, "")] + [ExpectedWarning ("IL2089", "RefFieldWithMethodsAndFields", "T", Tool.Trimmer | Tool.NativeAot, "")] + [ExpectedWarning ("IL2089", "RefFieldWithFields", "T", Tool.Trimmer | Tool.NativeAot, "")] static void AssignRefLocals< T, [DAM (DAMT.PublicMethods)] TM, @@ -176,13 +176,13 @@ static void AssignParameters (scoped RefFieldWithMethods target, // ILLink doesn't recognize ldind.ref // https://github.com/dotnet/runtime/issues/85465 // IL2064's are bugs - shouldn't be unknown values - [ExpectedWarning ("IL2064", ProducedBy = Tool.Trimmer | Tool.NativeAot)] - [ExpectedWarning ("IL2064", ProducedBy = Tool.Trimmer | Tool.NativeAot)] - [ExpectedWarning ("IL2064", ProducedBy = Tool.Trimmer | Tool.NativeAot)] - [ExpectedWarning ("IL2064", ProducedBy = Tool.Trimmer | Tool.NativeAot)] - [ExpectedWarning ("IL2064", ProducedBy = Tool.Trimmer | Tool.NativeAot)] - [ExpectedWarning ("IL2069", "RefFieldWithMethods.T", "param", ProducedBy = Tool.Analyzer)] - [ExpectedWarning ("IL2069", "RefFieldWithMethods.T", "paramWithFields", ProducedBy = Tool.Analyzer)] + [ExpectedWarning ("IL2064", Tool.Trimmer | Tool.NativeAot, "")] + [ExpectedWarning ("IL2064", Tool.Trimmer | Tool.NativeAot, "")] + [ExpectedWarning ("IL2064", Tool.Trimmer | Tool.NativeAot, "")] + [ExpectedWarning ("IL2064", Tool.Trimmer | Tool.NativeAot, "")] + [ExpectedWarning ("IL2064", Tool.Trimmer | Tool.NativeAot, "")] + [ExpectedWarning ("IL2069", "RefFieldWithMethods.T", "param", Tool.Analyzer, "")] + [ExpectedWarning ("IL2069", "RefFieldWithMethods.T", "paramWithFields", Tool.Analyzer, "")] static void AssignRefParameters< T, [DAM (DAMT.PublicMethods)] TM, @@ -233,15 +233,15 @@ static void AssignFields (RefFieldWithMethods target, UnannotatedField unannotat [ExpectedWarning ("IL2079", "RefFieldWithMethods.T", "RefFieldUnannotated.T")] [ExpectedWarning ("IL2079", "RefFieldWithMethods.T", "RefFieldWithFields.T")] - [ExpectedWarning ("IL2079", "RefFieldWithMethods.T", "RefFieldUnannotated.T", ProducedBy = Tool.Analyzer)] - [ExpectedWarning ("IL2079", "RefFieldWithMethods.T", "RefFieldWithFields.T", ProducedBy = Tool.Analyzer)] + [ExpectedWarning ("IL2079", "RefFieldWithMethods.T", "RefFieldUnannotated.T", Tool.Analyzer, "")] + [ExpectedWarning ("IL2079", "RefFieldWithMethods.T", "RefFieldWithFields.T", Tool.Analyzer, "")] // IL2064's are bugs - shouldn't be unknown values // https://github.com/dotnet/runtime/issues/85465 - [ExpectedWarning ("IL2064", "RefFieldWithMethods.T", ProducedBy = Tool.Trimmer | Tool.NativeAot)] // target.T = unannotated.T; - [ExpectedWarning ("IL2064", "RefFieldWithMethods.T", ProducedBy = Tool.Trimmer | Tool.NativeAot)] // target.T = withMethods.T; - [ExpectedWarning ("IL2064", "RefFieldWithMethods.T", ProducedBy = Tool.Trimmer | Tool.NativeAot)] // target.T = withFields.T; - [ExpectedWarning ("IL2064", "RefFieldWithMethods.T", ProducedBy = Tool.Trimmer | Tool.NativeAot)] // target.T = withMethodsAndFields.T; - [ExpectedWarning ("IL2064", "RefFieldWithMethods.T", ProducedBy = Tool.Trimmer | Tool.NativeAot)] // target.T = withMethodsAndFields.T; + [ExpectedWarning ("IL2064", "RefFieldWithMethods.T", Tool.Trimmer | Tool.NativeAot, "")] // target.T = unannotated.T; + [ExpectedWarning ("IL2064", "RefFieldWithMethods.T", Tool.Trimmer | Tool.NativeAot, "")] // target.T = withMethods.T; + [ExpectedWarning ("IL2064", "RefFieldWithMethods.T", Tool.Trimmer | Tool.NativeAot, "")] // target.T = withFields.T; + [ExpectedWarning ("IL2064", "RefFieldWithMethods.T", Tool.Trimmer | Tool.NativeAot, "")] // target.T = withMethodsAndFields.T; + [ExpectedWarning ("IL2064", "RefFieldWithMethods.T", Tool.Trimmer | Tool.NativeAot, "")] // target.T = withMethodsAndFields.T; static void AssignRefFields ( RefFieldWithMethods target, RefFieldUnannotated unannotated, @@ -265,14 +265,14 @@ static void AssignRefFields ( [ExpectedWarning ("IL2074", "RefFieldWithMethods.T", "GetRefWithFields")] [ExpectedWarning ("IL2074", "RefFieldWithMethods.T", "GetRefUnannotated")] [ExpectedWarning ("IL2074", "RefFieldWithMethods.T", "GetRefWithFields")] - [ExpectedWarning ("IL2074", "RefFieldWithMethods.T", "GetRefUnannotated", ProducedBy = Tool.Analyzer)] - [ExpectedWarning ("IL2074", "RefFieldWithMethods.T", "GetRefWithFields", ProducedBy = Tool.Analyzer)] + [ExpectedWarning ("IL2074", "RefFieldWithMethods.T", "GetRefUnannotated", Tool.Analyzer, "")] + [ExpectedWarning ("IL2074", "RefFieldWithMethods.T", "GetRefWithFields", Tool.Analyzer, "")] // IL2064's are bugs - shouldn't be unknown values // https://github.com/dotnet/runtime/issues/85465 - [ExpectedWarning ("IL2064", "RefFieldWithMethods.T", ProducedBy = Tool.Trimmer | Tool.NativeAot)] // target.T = t; - [ExpectedWarning ("IL2064", "RefFieldWithMethods.T", ProducedBy = Tool.Trimmer | Tool.NativeAot)] // target.T = t; - [ExpectedWarning ("IL2064", "RefFieldWithMethods.T", ProducedBy = Tool.Trimmer | Tool.NativeAot)] // target.T = t; - [ExpectedWarning ("IL2064", "RefFieldWithMethods.T", ProducedBy = Tool.Trimmer | Tool.NativeAot)] // target.T = t; + [ExpectedWarning ("IL2064", "RefFieldWithMethods.T", Tool.Trimmer | Tool.NativeAot, "")] // target.T = t; + [ExpectedWarning ("IL2064", "RefFieldWithMethods.T", Tool.Trimmer | Tool.NativeAot, "")] // target.T = t; + [ExpectedWarning ("IL2064", "RefFieldWithMethods.T", Tool.Trimmer | Tool.NativeAot, "")] // target.T = t; + [ExpectedWarning ("IL2064", "RefFieldWithMethods.T", Tool.Trimmer | Tool.NativeAot, "")] // target.T = t; static void AssignRefReturns< T, [DAM (DAMT.PublicMethods)] TM, @@ -348,26 +348,26 @@ static void AssignProperties (RefFieldWithMethods target, } // target.T = x.T - [ExpectedWarning ("IL2074", "RefFieldWithMethods.T", "RefPropUnannotated.T", ProducedBy = Tool.Analyzer)] - [ExpectedWarning ("IL2074", "RefFieldWithMethods.T", "RefPropWithFields.T", ProducedBy = Tool.Analyzer)] + [ExpectedWarning ("IL2074", "RefFieldWithMethods.T", "RefPropUnannotated.T", Tool.Analyzer, "")] + [ExpectedWarning ("IL2074", "RefFieldWithMethods.T", "RefPropWithFields.T", Tool.Analyzer, "")] // target.T = t; - [ExpectedWarning ("IL2074", "RefFieldWithMethods.T", "RefPropUnannotated.T", ProducedBy = Tool.Analyzer)] - [ExpectedWarning ("IL2074", "RefFieldWithMethods.T", "RefPropWithFields.T", ProducedBy = Tool.Analyzer)] + [ExpectedWarning ("IL2074", "RefFieldWithMethods.T", "RefPropUnannotated.T", Tool.Analyzer, "")] + [ExpectedWarning ("IL2074", "RefFieldWithMethods.T", "RefPropWithFields.T", Tool.Analyzer, "")] // target.T = ref x.T [ExpectedWarning ("IL2074", "RefFieldWithMethods.T", "RefPropUnannotated.T")] [ExpectedWarning ("IL2074", "RefFieldWithMethods.T", "RefPropWithFields.T")] // ref Type t = ref x.T; target.T = t; // IL2064's are bugs - shouldn't be unknown values // https://github.com/dotnet/runtime/issues/85465 - [ExpectedWarning ("IL2064", "RefFieldWithMethods.T", ProducedBy = Tool.Trimmer | Tool.NativeAot)] // target.T = unannotated.T; - [ExpectedWarning ("IL2064", "RefFieldWithMethods.T", ProducedBy = Tool.Trimmer | Tool.NativeAot)] // target.T = withMethods.T; - [ExpectedWarning ("IL2064", "RefFieldWithMethods.T", ProducedBy = Tool.Trimmer | Tool.NativeAot)] // target.T = withFields.T; - [ExpectedWarning ("IL2064", "RefFieldWithMethods.T", ProducedBy = Tool.Trimmer | Tool.NativeAot)] // target.T = withMethodsAndFieldswithMtho.T; - [ExpectedWarning ("IL2064", "RefFieldWithMethods.T", ProducedBy = Tool.Trimmer | Tool.NativeAot)] // target.T = withMethods.T; - [ExpectedWarning ("IL2064", "RefFieldWithMethods.T", ProducedBy = Tool.Trimmer | Tool.NativeAot)] // target.T = t; - [ExpectedWarning ("IL2064", "RefFieldWithMethods.T", ProducedBy = Tool.Trimmer | Tool.NativeAot)] // target.T = t; - [ExpectedWarning ("IL2064", "RefFieldWithMethods.T", ProducedBy = Tool.Trimmer | Tool.NativeAot)] // target.T = t; - [ExpectedWarning ("IL2064", "RefFieldWithMethods.T", ProducedBy = Tool.Trimmer | Tool.NativeAot)] // target.T = t; + [ExpectedWarning ("IL2064", "RefFieldWithMethods.T", Tool.Trimmer | Tool.NativeAot, "")] // target.T = unannotated.T; + [ExpectedWarning ("IL2064", "RefFieldWithMethods.T", Tool.Trimmer | Tool.NativeAot, "")] // target.T = withMethods.T; + [ExpectedWarning ("IL2064", "RefFieldWithMethods.T", Tool.Trimmer | Tool.NativeAot, "")] // target.T = withFields.T; + [ExpectedWarning ("IL2064", "RefFieldWithMethods.T", Tool.Trimmer | Tool.NativeAot, "")] // target.T = withMethodsAndFieldswithMtho.T; + [ExpectedWarning ("IL2064", "RefFieldWithMethods.T", Tool.Trimmer | Tool.NativeAot, "")] // target.T = withMethods.T; + [ExpectedWarning ("IL2064", "RefFieldWithMethods.T", Tool.Trimmer | Tool.NativeAot, "")] // target.T = t; + [ExpectedWarning ("IL2064", "RefFieldWithMethods.T", Tool.Trimmer | Tool.NativeAot, "")] // target.T = t; + [ExpectedWarning ("IL2064", "RefFieldWithMethods.T", Tool.Trimmer | Tool.NativeAot, "")] // target.T = t; + [ExpectedWarning ("IL2064", "RefFieldWithMethods.T", Tool.Trimmer | Tool.NativeAot, "")] // target.T = t; static void AssignRefProperties (RefFieldWithMethods target, RefPropUnannotated unannotated = null, RefPropWithMethods withMethods = null, diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/TypeBaseTypeDataFlow.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/TypeBaseTypeDataFlow.cs index 8fc0362921be41..2933e51ba7768c 100644 --- a/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/TypeBaseTypeDataFlow.cs +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/TypeBaseTypeDataFlow.cs @@ -59,8 +59,7 @@ static void TestAllPropagated ([DynamicallyAccessedMembers (DynamicallyAccessedM class AllPropagatedWithDerivedClass { // https://github.com/dotnet/linker/issues/2673 - [ExpectedWarning ("IL2072", nameof (DataFlowTypeExtensions.RequiresAll) + "(Type)", nameof (TestSystemTypeBase.BaseType) + ".get", - ProducedBy = Tool.Analyzer)] + [ExpectedWarning ("IL2072", nameof (DataFlowTypeExtensions.RequiresAll) + "(Type)", nameof (TestSystemTypeBase.BaseType) + ".get", Tool.Analyzer, "")] static void TestAllPropagated ([DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.All)] TestSystemTypeBase derivedType) { derivedType.BaseType.RequiresAll (); @@ -284,7 +283,7 @@ static void EnumerateInterfacesOnBaseTypes ([DynamicallyAccessedMembers (Dynamic } [ExpectedWarning ("IL2070")] - [ExpectedWarning ("IL2075", ProducedBy = Tool.Analyzer)] // ILLink doesn't implement backward branches data flow yet + [ExpectedWarning ("IL2075", Tool.Analyzer, "")] // ILLink doesn't implement backward branches data flow yet static void EnumerateInterfacesOnBaseTypes_Unannotated (Type type) { Type? t = type; diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/UnresolvedMembers.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/UnresolvedMembers.cs index e32c8727f91e09..130f7ade7aa150 100644 --- a/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/UnresolvedMembers.cs +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/UnresolvedMembers.cs @@ -45,9 +45,9 @@ static void MethodWithUnresolvedGenericArgument< { } [Kept] - [ExpectedWarning ("IL2066", "TypeWithUnresolvedGenericArgument", ProducedBy = Tool.Trimmer | Tool.Analyzer)] // Local variable type - [ExpectedWarning ("IL2066", "TypeWithUnresolvedGenericArgument", ProducedBy = Tool.Trimmer | Tool.Analyzer)] // Called method declaring type - [ExpectedWarning ("IL2066", nameof (MethodWithUnresolvedGenericArgument), ProducedBy = Tool.Trimmer | Tool.Analyzer)] + [ExpectedWarning ("IL2066", "TypeWithUnresolvedGenericArgument", Tool.Trimmer | Tool.Analyzer, "")] // Local variable type + [ExpectedWarning ("IL2066", "TypeWithUnresolvedGenericArgument", Tool.Trimmer | Tool.Analyzer, "")] // Called method declaring type + [ExpectedWarning ("IL2066", nameof (MethodWithUnresolvedGenericArgument), Tool.Trimmer | Tool.Analyzer, "")] static void UnresolvedGenericArgument () { var a = new TypeWithUnresolvedGenericArgument (); @@ -77,7 +77,7 @@ public AttributeWithRequirements ( } [Kept] - [ExpectedWarning ("IL2062", nameof (AttributeWithRequirements), ProducedBy = Tool.Trimmer | Tool.Analyzer)] + [ExpectedWarning ("IL2062", nameof (AttributeWithRequirements), Tool.Trimmer | Tool.Analyzer, "")] [KeptAttributeAttribute (typeof (AttributeWithRequirements))] [AttributeWithRequirements (typeof (Dependencies.UnresolvedType))] static void UnresolvedAttributeArgument () @@ -85,7 +85,7 @@ static void UnresolvedAttributeArgument () } [Kept] - [ExpectedWarning ("IL2062", nameof (AttributeWithRequirements.PropertyWithRequirements), ProducedBy = Tool.Trimmer | Tool.Analyzer)] + [ExpectedWarning ("IL2062", nameof (AttributeWithRequirements.PropertyWithRequirements), Tool.Trimmer | Tool.Analyzer, "")] [KeptAttributeAttribute (typeof (AttributeWithRequirements))] [AttributeWithRequirements (typeof (EmptyType), PropertyWithRequirements = typeof (Dependencies.UnresolvedType))] static void UnresolvedAttributePropertyValue () @@ -93,7 +93,7 @@ static void UnresolvedAttributePropertyValue () } [Kept] - [ExpectedWarning ("IL2064", nameof (AttributeWithRequirements.FieldWithRequirements), ProducedBy = Tool.Trimmer | Tool.Analyzer)] + [ExpectedWarning ("IL2064", nameof (AttributeWithRequirements.FieldWithRequirements), Tool.Trimmer | Tool.Analyzer, "")] [KeptAttributeAttribute (typeof (AttributeWithRequirements))] [AttributeWithRequirements (typeof (EmptyType), FieldWithRequirements = typeof (Dependencies.UnresolvedType))] static void UnresolvedAttributeFieldValue () @@ -104,14 +104,14 @@ static void UnresolvedAttributeFieldValue () static Dependencies.UnresolvedType _unresolvedField; [Kept] - [ExpectedWarning ("IL2072", nameof (Object.GetType), ProducedBy = Tool.Trimmer | Tool.Analyzer)] + [ExpectedWarning ("IL2072", nameof (Object.GetType), Tool.Trimmer | Tool.Analyzer, "")] static void UnresolvedObjectGetType () { RequirePublicMethods (_unresolvedField.GetType ()); } [Kept] - [ExpectedWarning ("IL2072", nameof (Object.GetType), ProducedBy = Tool.Trimmer | Tool.Analyzer)] + [ExpectedWarning ("IL2072", nameof (Object.GetType), Tool.Trimmer | Tool.Analyzer, "")] static void UnresolvedMethodParameter () { RequirePublicMethods (typeof (Dependencies.UnresolvedType)); diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/VirtualMethodHierarchyDataflowAnnotationValidation.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/VirtualMethodHierarchyDataflowAnnotationValidation.cs index 4b73a662347916..7cd16f88aaee6d 100644 --- a/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/VirtualMethodHierarchyDataflowAnnotationValidation.cs +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/VirtualMethodHierarchyDataflowAnnotationValidation.cs @@ -633,24 +633,24 @@ class ImplIDamOnAllMissing : IDamOnAll // NativeAOT doesn't validate overrides when accessed through reflection because it's a direct call (non-virtual) // So it doesn't matter that the annotations are not in-sync since the access will validate // the annotations on the implementation method - it doesn't even see the base method in this case. - [ExpectedWarning ("IL2092", ProducedBy = Tool.Trimmer | Tool.Analyzer)] - [ExpectedWarning ("IL2093", ProducedBy = Tool.Trimmer | Tool.Analyzer)] - [ExpectedWarning ("IL2095", ProducedBy = Tool.Trimmer | Tool.Analyzer)] + [ExpectedWarning ("IL2092", Tool.Trimmer | Tool.Analyzer, "")] + [ExpectedWarning ("IL2093", Tool.Trimmer | Tool.Analyzer, "")] + [ExpectedWarning ("IL2095", Tool.Trimmer | Tool.Analyzer, "")] public static Type AbstractMethod (Type type) => null; // NativeAOT doesn't validate overrides when accessed through reflection because it's a direct call (non-virtual) - [ExpectedWarning ("IL2092", ProducedBy = Tool.Trimmer | Tool.Analyzer)] - [ExpectedWarning ("IL2093", ProducedBy = Tool.Trimmer | Tool.Analyzer)] - [ExpectedWarning ("IL2095", ProducedBy = Tool.Trimmer | Tool.Analyzer)] + [ExpectedWarning ("IL2092", Tool.Trimmer | Tool.Analyzer, "")] + [ExpectedWarning ("IL2093", Tool.Trimmer | Tool.Analyzer, "")] + [ExpectedWarning ("IL2095", Tool.Trimmer | Tool.Analyzer, "")] public static Type VirtualMethod (Type type) => null; } class ImplIDamOnAllMismatch : IDamOnAll { // NativeAOT doesn't validate overrides when accessed through reflection because it's a direct call (non-virtual) - [ExpectedWarning ("IL2092", ProducedBy = Tool.Trimmer | Tool.Analyzer)] - [ExpectedWarning ("IL2093", ProducedBy = Tool.Trimmer | Tool.Analyzer)] - [ExpectedWarning ("IL2095", ProducedBy = Tool.Trimmer | Tool.Analyzer)] + [ExpectedWarning ("IL2092", Tool.Trimmer | Tool.Analyzer, "")] + [ExpectedWarning ("IL2093", Tool.Trimmer | Tool.Analyzer, "")] + [ExpectedWarning ("IL2095", Tool.Trimmer | Tool.Analyzer, "")] [return: DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicFields)] public static Type AbstractMethod <[DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] @@ -660,9 +660,9 @@ public static Type AbstractMethod { return null; } // NativeAOT doesn't validate overrides when accessed through reflection because it's a direct call (non-virtual) - [ExpectedWarning ("IL2092", ProducedBy = Tool.Trimmer | Tool.Analyzer)] - [ExpectedWarning ("IL2093", ProducedBy = Tool.Trimmer | Tool.Analyzer)] - [ExpectedWarning ("IL2095", ProducedBy = Tool.Trimmer | Tool.Analyzer)] + [ExpectedWarning ("IL2092", Tool.Trimmer | Tool.Analyzer, "")] + [ExpectedWarning ("IL2093", Tool.Trimmer | Tool.Analyzer, "")] + [ExpectedWarning ("IL2095", Tool.Trimmer | Tool.Analyzer, "")] [return: DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicFields)] public static Type VirtualMethod <[DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] @@ -706,9 +706,9 @@ class ImplIDamOnNoneMatch : IDamOnNone class ImplIDamOnNoneMismatch : IDamOnNone { // NativeAOT doesn't validate overrides when accessed through reflection because it's a direct call (non-virtual) - [ExpectedWarning ("IL2092", ProducedBy = Tool.Trimmer | Tool.Analyzer)] - [ExpectedWarning ("IL2093", ProducedBy = Tool.Trimmer | Tool.Analyzer)] - [ExpectedWarning ("IL2095", ProducedBy = Tool.Trimmer | Tool.Analyzer)] + [ExpectedWarning ("IL2092", Tool.Trimmer | Tool.Analyzer, "")] + [ExpectedWarning ("IL2093", Tool.Trimmer | Tool.Analyzer, "")] + [ExpectedWarning ("IL2095", Tool.Trimmer | Tool.Analyzer, "")] [return: DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicFields)] public static Type AbstractMethod <[DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] @@ -718,9 +718,9 @@ public static Type AbstractMethod { return null; } // NativeAOT doesn't validate overrides when accessed through reflection because it's a direct call (non-virtual) - [ExpectedWarning ("IL2092", ProducedBy = Tool.Trimmer | Tool.Analyzer)] - [ExpectedWarning ("IL2093", ProducedBy = Tool.Trimmer | Tool.Analyzer)] - [ExpectedWarning ("IL2095", ProducedBy = Tool.Trimmer | Tool.Analyzer)] + [ExpectedWarning ("IL2092", Tool.Trimmer | Tool.Analyzer, "")] + [ExpectedWarning ("IL2093", Tool.Trimmer | Tool.Analyzer, "")] + [ExpectedWarning ("IL2095", Tool.Trimmer | Tool.Analyzer, "")] [return: DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicFields)] public static Type VirtualMethod <[DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] @@ -749,7 +749,7 @@ class BaseInPreservedScope class ImplIAnnotatedMethodsMismatch : Library.IAnnotatedMethods { // NativeAOT doesn't always validate static overrides when accessed through reflection because it's a direct call (non-virtual) - [ExpectedWarning ("IL2095", ProducedBy = Tool.Trimmer | Tool.Analyzer)] + [ExpectedWarning ("IL2095", Tool.Trimmer | Tool.Analyzer, "")] public static void GenericWithMethodsStatic () { } [ExpectedWarning ("IL2092")] @@ -771,7 +771,7 @@ public void ParamWithMethods (Type t) { } class ImplIUnannotatedMethodsMismatch : Library.IUnannotatedMethods { // NativeAOT doesn't always validate static overrides when accessed through reflection because it's a direct call (non-virtual) - [ExpectedWarning ("IL2095", ProducedBy = Tool.Trimmer | Tool.Analyzer)] + [ExpectedWarning ("IL2095", Tool.Trimmer | Tool.Analyzer, "")] public static void GenericStatic<[DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] T> () { } [ExpectedWarning ("IL2092")] @@ -947,7 +947,7 @@ interface IBaseWithDefault interface IDerivedWithDefault : IBaseWithDefault { [ExpectedWarning ("IL2092")] - [ExpectedWarning ("IL2092", ProducedBy = Tool.Analyzer)] // https://github.com/dotnet/linker/issues/3121 + [ExpectedWarning ("IL2092", Tool.Analyzer, "")] // https://github.com/dotnet/linker/issues/3121 void IBaseWithDefault.DefaultMethod ([DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] Type type) { } } @@ -969,9 +969,9 @@ interface IGvmBase class ImplIGvmBase : IGvmBase { // NativeAOT doesn't validate overrides when it can resolve them as direct calls - [ExpectedWarning ("IL2092", ProducedBy = Tool.Trimmer | Tool.Analyzer)] - [ExpectedWarning ("IL2093", ProducedBy = Tool.Trimmer | Tool.Analyzer)] - [ExpectedWarning ("IL2095", ProducedBy = Tool.Trimmer | Tool.Analyzer)] + [ExpectedWarning ("IL2092", Tool.Trimmer | Tool.Analyzer, "")] + [ExpectedWarning ("IL2093", Tool.Trimmer | Tool.Analyzer, "")] + [ExpectedWarning ("IL2095", Tool.Trimmer | Tool.Analyzer, "")] [return: DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] public Type UnannotatedGvm<[DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] T> ([DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] Type type) => null; @@ -1045,8 +1045,8 @@ public override void MethodWithRequires ([DynamicallyAccessedMembers (Dynamicall [ExpectedWarning ("IL2026", nameof (DerivedTypeWithRequires_BaseMethodWithRequires))] [ExpectedWarning ("IL2026", nameof (DerivedTypeWithRequires_BaseMethodWithRequires.MethodWithRequires))] - [ExpectedWarning ("IL3050", nameof (DerivedTypeWithRequires_BaseMethodWithRequires), ProducedBy = Tool.NativeAot | Tool.Analyzer)] - [ExpectedWarning ("IL3050", nameof (DerivedTypeWithRequires_BaseMethodWithRequires.MethodWithRequires), ProducedBy = Tool.NativeAot | Tool.Analyzer)] + [ExpectedWarning ("IL3050", nameof (DerivedTypeWithRequires_BaseMethodWithRequires), Tool.NativeAot | Tool.Analyzer, "")] + [ExpectedWarning ("IL3050", nameof (DerivedTypeWithRequires_BaseMethodWithRequires.MethodWithRequires), Tool.NativeAot | Tool.Analyzer, "")] static void Test_DerivedTypeWithRequires_BaseMethodWithRequires () { new DerivedTypeWithRequires_BaseMethodWithRequires ().MethodWithRequires (typeof (int)); diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/Extensibility/CustomWarningUsage.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/Extensibility/CustomWarningUsage.cs index 063038c93eadde..941f6c59e543fa 100644 --- a/src/tools/illink/test/Mono.Linker.Tests.Cases/Extensibility/CustomWarningUsage.cs +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/Extensibility/CustomWarningUsage.cs @@ -10,7 +10,7 @@ namespace Mono.Linker.Tests.Cases.Extensibility [ExpectedNoWarnings] public class CustomWarningUsage { - [ExpectedWarning ("IL2026", "--RUCMethod--", ProducedBy = Tool.Analyzer)] + [ExpectedWarning ("IL2026", "--RUCMethod--", Tool.Analyzer, "")] public static void Main () { new KnownTypeThatShouldWarn (); diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/LinkXml/LinkXmlErrorCases.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/LinkXml/LinkXmlErrorCases.cs index 074216595ed306..467831cbb69fcd 100644 --- a/src/tools/illink/test/Mono.Linker.Tests.Cases/LinkXml/LinkXmlErrorCases.cs +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/LinkXml/LinkXmlErrorCases.cs @@ -17,13 +17,13 @@ namespace Mono.Linker.Tests.Cases.LinkXml [ExpectedWarning ("IL2017", "NonExistentProperty", "TypeWithNoProperties", FileName = "LinkXmlErrorCases.xml", SourceLine = 21, SourceColumn = 8)] [ExpectedWarning ("IL2018", "SetOnlyProperty", "TypeWithProperties", FileName = "LinkXmlErrorCases.xml", SourceLine = 25, SourceColumn = 8)] [ExpectedWarning ("IL2019", "GetOnlyProperty", "TypeWithProperties", FileName = "LinkXmlErrorCases.xml", SourceLine = 26, SourceColumn = 8)] - [ExpectedWarning ("IL2025", "Method", FileName = "LinkXmlErrorCases.xml", SourceLine = 39, SourceColumn = 8, ProducedBy = Tool.Trimmer)] - [ExpectedWarning ("IL2025", "Event", FileName = "LinkXmlErrorCases.xml", SourceLine = 40, SourceColumn = 8, ProducedBy = Tool.Trimmer)] - [ExpectedWarning ("IL2025", "Field", FileName = "LinkXmlErrorCases.xml", SourceLine = 41, SourceColumn = 8, ProducedBy = Tool.Trimmer)] - [ExpectedWarning ("IL2025", "Property", FileName = "LinkXmlErrorCases.xml", SourceLine = 42, SourceColumn = 8, ProducedBy = Tool.Trimmer)] + [ExpectedWarning ("IL2025", "Method", Tool.Trimmer, "", FileName = "LinkXmlErrorCases.xml", SourceLine = 39, SourceColumn = 8)] + [ExpectedWarning ("IL2025", "Event", Tool.Trimmer, "", FileName = "LinkXmlErrorCases.xml", SourceLine = 40, SourceColumn = 8)] + [ExpectedWarning ("IL2025", "Field", Tool.Trimmer, "", FileName = "LinkXmlErrorCases.xml", SourceLine = 41, SourceColumn = 8)] + [ExpectedWarning ("IL2025", "Property", Tool.Trimmer, "", FileName = "LinkXmlErrorCases.xml", SourceLine = 42, SourceColumn = 8)] // NativeAOT doesn't support wildcard * and will skip usages of it, including if they would warn // https://github.com/dotnet/runtime/issues/80466 - [ExpectedWarning ("IL2100", FileName = "LinkXmlErrorCases.xml", SourceLine = 50, SourceColumn = 4, ProducedBy = Tool.Trimmer)] + [ExpectedWarning ("IL2100", Tool.Trimmer, "", FileName = "LinkXmlErrorCases.xml", SourceLine = 50, SourceColumn = 4)] class LinkXmlErrorCases { public static void Main () diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/Logging/SourceLines.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/Logging/SourceLines.cs index 4da189cced1f87..e6f445dfaca24b 100644 --- a/src/tools/illink/test/Mono.Linker.Tests.Cases/Logging/SourceLines.cs +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/Logging/SourceLines.cs @@ -31,16 +31,16 @@ static Type GetUnknownType () // Analyzer test infrastructure doesn't support ExpectedWarning at the top-level. // This is OK because the test is meant to validate that the ILLink infrastructure produces the right line numbers, // and we have separate tests to check the line number of analyzer warnings. - [ExpectedWarning ("IL2074", nameof (SourceLines) + "." + nameof (type), nameof (SourceLines) + "." + nameof (GetUnknownType) + "()", ProducedBy = Tool.Analyzer)] - [ExpectedWarning ("IL2074", nameof (SourceLines) + "." + nameof (type), nameof (SourceLines) + "." + nameof (GetUnknownType) + "()", ProducedBy = Tool.Analyzer)] + [ExpectedWarning ("IL2074", nameof (SourceLines) + "." + nameof (type), nameof (SourceLines) + "." + nameof (GetUnknownType) + "()", Tool.Analyzer, "")] + [ExpectedWarning ("IL2074", nameof (SourceLines) + "." + nameof (type), nameof (SourceLines) + "." + nameof (GetUnknownType) + "()", Tool.Analyzer, "")] static void UnrecognizedReflectionPattern () { type = GetUnknownType (); // IL2074 type = GetUnknownType (); // IL2074 } - [ExpectedWarning ("IL2091", "LocalFunction()", ProducedBy = Tool.Analyzer)] - [ExpectedWarning ("IL2089", nameof (SourceLines) + "." + nameof (type), "TOuterMethod", ProducedBy = Tool.Analyzer)] + [ExpectedWarning ("IL2091", "LocalFunction()", Tool.Analyzer, "")] + [ExpectedWarning ("IL2089", nameof (SourceLines) + "." + nameof (type), "TOuterMethod", Tool.Analyzer, "")] static IEnumerable GenericMethodIteratorWithRequirement<[DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] TOuterMethod> () { LocalFunction (); diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/Reflection/ActivatorCreateInstance.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/Reflection/ActivatorCreateInstance.cs index a14030d90ad164..4aca2d51861850 100644 --- a/src/tools/illink/test/Mono.Linker.Tests.Cases/Reflection/ActivatorCreateInstance.cs +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/Reflection/ActivatorCreateInstance.cs @@ -171,8 +171,8 @@ public FromParameterOnStaticMethodTypeB (int arg) { } } // Small formatting difference - [ExpectedWarning ("IL2067", nameof (Activator) + "." + nameof (Activator.CreateInstance) + "(Type, Object[])", ProducedBy = Tool.Trimmer)] - [ExpectedWarning ("IL2067", nameof (Activator) + "." + nameof (Activator.CreateInstance) + "(Type, params Object[])", ProducedBy = Tool.Analyzer)] + [ExpectedWarning ("IL2067", nameof (Activator) + "." + nameof (Activator.CreateInstance) + "(Type, Object[])", Tool.Trimmer, "")] + [ExpectedWarning ("IL2067", nameof (Activator) + "." + nameof (Activator.CreateInstance) + "(Type, params Object[])", Tool.Analyzer, "")] [ExpectedWarning ("IL2067", nameof (Activator) + "." + nameof (Activator.CreateInstance), nameof (CultureInfo))] [Kept] private void FromParameterOnInstanceMethod ( @@ -197,8 +197,8 @@ public FromParameterOnInstanceMethodType (int arg, int arg2) { } [ExpectedWarning ("IL2067", nameof (Activator) + "." + nameof (Activator.CreateInstance) + "(Type)")] // Small formatting difference - [ExpectedWarning ("IL2067", nameof (Activator) + "." + nameof (Activator.CreateInstance) + "(Type, Object[])", ProducedBy = Tool.Trimmer)] - [ExpectedWarning ("IL2067", nameof (Activator) + "." + nameof (Activator.CreateInstance) + "(Type, params Object[])", ProducedBy = Tool.Analyzer)] + [ExpectedWarning ("IL2067", nameof (Activator) + "." + nameof (Activator.CreateInstance) + "(Type, Object[])", Tool.Trimmer, "")] + [ExpectedWarning ("IL2067", nameof (Activator) + "." + nameof (Activator.CreateInstance) + "(Type, params Object[])", Tool.Analyzer, "")] [Kept] private static void FromParameterWithNonPublicConstructors ( [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.NonPublicConstructors)] @@ -375,7 +375,7 @@ private static void WithAssemblyAndNoValueTypeName () [Kept] // Analyzer doesn't handle assembly resolution - [ExpectedWarning ("IL2061", nameof (Activator) + "." + nameof (Activator.CreateInstance), "NonExistingAssembly", ProducedBy = Tool.Trimmer)] + [ExpectedWarning ("IL2061", nameof (Activator) + "." + nameof (Activator.CreateInstance), "NonExistingAssembly", Tool.Trimmer, "")] private static void WithNonExistingAssemblyName () { Activator.CreateInstance ("NonExistingAssembly", "Mono.Linker.Tests.Cases.Reflection.ActivatorCreateInstance+WithAssemblyNameParameterless1"); diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/Reflection/ExpressionPropertyMethodInfo.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/Reflection/ExpressionPropertyMethodInfo.cs index 5fa8b48caddcbe..fadd361a58cef2 100644 --- a/src/tools/illink/test/Mono.Linker.Tests.Cases/Reflection/ExpressionPropertyMethodInfo.cs +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/Reflection/ExpressionPropertyMethodInfo.cs @@ -84,11 +84,11 @@ public int InstancePropertyViaReflection { [Kept] // https://github.com/dotnet/linker/issues/2669 - [ExpectedWarning ("IL2026", nameof (StaticPropertyExpressionAccess), ProducedBy = Tool.Trimmer)] + [ExpectedWarning ("IL2026", nameof (StaticPropertyExpressionAccess), Tool.Trimmer, "")] [ExpectedWarning ("IL2026", nameof (StaticPropertyViaReflection))] [ExpectedWarning ("IL2026", nameof (StaticPropertyViaRuntimeMethod))] // https://github.com/dotnet/linker/issues/2669 - [ExpectedWarning ("IL2026", nameof (InstancePropertyExpressionAccess), ProducedBy = Tool.Trimmer)] + [ExpectedWarning ("IL2026", nameof (InstancePropertyExpressionAccess), Tool.Trimmer, "")] [ExpectedWarning ("IL2026", nameof (InstancePropertyViaReflection))] public static void Test () { diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/Reflection/MethodsUsedViaReflection.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/Reflection/MethodsUsedViaReflection.cs index c91fb020f7feae..01717db24f5662 100644 --- a/src/tools/illink/test/Mono.Linker.Tests.Cases/Reflection/MethodsUsedViaReflection.cs +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/Reflection/MethodsUsedViaReflection.cs @@ -338,7 +338,7 @@ private void PrivateMethodWithRUC () { } [Kept] // https://github.com/dotnet/linker/issues/2638 - [ExpectedWarning ("IL2026", ProducedBy = Tool.Trimmer)] + [ExpectedWarning ("IL2026", Tool.Trimmer, "")] public static void Test () { BindingFlags left = BindingFlags.Instance | BindingFlags.Static; diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/Reflection/ObjectGetType.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/Reflection/ObjectGetType.cs index 5d21f678b1dbd5..af03ac42590ff7 100644 --- a/src/tools/illink/test/Mono.Linker.Tests.Cases/Reflection/ObjectGetType.cs +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/Reflection/ObjectGetType.cs @@ -297,7 +297,7 @@ public void UnusedMethod () { } [Kept] // https://github.com/dotnet/runtime/issues/93718 // This should not warn - [ExpectedWarning ("IL2075", "GetMethod", ProducedBy = Tool.Trimmer | Tool.NativeAot)] + [ExpectedWarning ("IL2075", "GetMethod", Tool.Trimmer | Tool.NativeAot, "")] static void TestStruct (BasicAnnotatedStruct instance) { instance.GetType ().GetMethod ("UsedMethod"); @@ -1409,7 +1409,7 @@ public void Method () { } [Kept] // https://github.com/dotnet/runtime/issues/93719 - [ExpectedWarning ("IL2075", nameof (Type.GetType), ProducedBy = Tool.Trimmer | Tool.NativeAot)] + [ExpectedWarning ("IL2075", nameof (Type.GetType), Tool.Trimmer | Tool.NativeAot, "")] public static void Test () { foreach (var instance in GetInstances ()) { diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/Reflection/TypeHierarchyReflectionWarnings.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/Reflection/TypeHierarchyReflectionWarnings.cs index 13ecc2ec29068c..c1f0b37ebaab54 100644 --- a/src/tools/illink/test/Mono.Linker.Tests.Cases/Reflection/TypeHierarchyReflectionWarnings.cs +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/Reflection/TypeHierarchyReflectionWarnings.cs @@ -250,7 +250,7 @@ public event MyEventHandler RUCEvent { [Kept] [ExpectedWarning ("IL2112", nameof (AnnotatedPublicEvents), "--RUC on add_RUCEvent--")] // https://github.com/dotnet/runtime/issues/100499 - [ExpectedWarning ("IL2112", nameof (AnnotatedPublicEvents), "--RUC on add_RUCEvent--", ProducedBy = Tool.Trimmer)] + [ExpectedWarning ("IL2112", [nameof (AnnotatedPublicEvents), "--RUC on add_RUCEvent--"], Tool.Trimmer, "")] [KeptAttributeAttribute (typeof (RequiresUnreferencedCodeAttribute))] [RequiresUnreferencedCode ("--RUC on add_RUCEvent--")] add { } @@ -313,7 +313,7 @@ class DerivedFromAnnotatedPublicParameterlessConstructor : AnnotatedPublicParame [Kept] [KeptAttributeAttribute (typeof (RequiresUnreferencedCodeAttribute))] [ExpectedWarning ("IL2112", "--RUC on DerivedFromAnnotatedPublicParameterlessConstructor()--")] - [ExpectedWarning ("IL2112", "--RUC on DerivedFromAnnotatedPublicParameterlessConstructor()--", ProducedBy = Tool.Trimmer | Tool.NativeAot)] + [ExpectedWarning ("IL2112", "--RUC on DerivedFromAnnotatedPublicParameterlessConstructor()--", Tool.Trimmer | Tool.NativeAot, "")] [RequiresUnreferencedCode ("--RUC on DerivedFromAnnotatedPublicParameterlessConstructor()--")] public DerivedFromAnnotatedPublicParameterlessConstructor () { } @@ -704,7 +704,7 @@ public class Base // https://github.com/dotnet/runtime/issues/86580 // Compare to the case above - the only difference is the type of the field // and it causes different warnings to be produced. - // [ExpectedWarning ("IL2112", "--RUCOnVirtualMethodDerivedAnnotated.Base.RUCVirtualMethod--")] + // [ExpectedSharedWarning ("IL2112", "--RUCOnVirtualMethodDerivedAnnotated.Base.RUCVirtualMethod--")] public virtual void RUCVirtualMethod () { } } @@ -712,7 +712,7 @@ public virtual void RUCVirtualMethod () { } [KeptMember (".ctor()")] [KeptBaseType (typeof (Base))] // https://github.com/dotnet/runtime/issues/86580 - [ExpectedWarning ("IL2113", "--RUCOnVirtualMethodDerivedAnnotated.Base.RUCVirtualMethod--", ProducedBy = Tool.Trimmer)] + [ExpectedWarning ("IL2113", "--RUCOnVirtualMethodDerivedAnnotated.Base.RUCVirtualMethod--", Tool.Trimmer, "")] public class Derived : Base { [Kept] @@ -756,7 +756,7 @@ public virtual void VirtualMethodWithRequires () { } [KeptBaseType (typeof (AnnotatedBase))] [KeptMember (".ctor()")] // https://github.com/dotnet/runtime/issues/86580 - [ExpectedWarning ("IL2113", "--AnnotatedBase.VirtualMethodWithRequires--", ProducedBy = Tool.Trimmer)] + [ExpectedWarning ("IL2113", "--AnnotatedBase.VirtualMethodWithRequires--", Tool.Trimmer, "")] class Derived : AnnotatedBase { [Kept] @@ -956,7 +956,7 @@ static void LocalFunctionWithDAMInner ([DynamicallyAccessedMembers(DynamicallyAc [Kept] [KeptAttributeAttribute (typeof (IteratorStateMachineAttribute))] - [ExpectedWarning ("IL2119", nameof (IteratorWithGenericDAM), CompilerGeneratedCode = true, ProducedBy = Tool.Trimmer)] + [ExpectedWarning ("IL2119", nameof (IteratorWithGenericDAM), Tool.Trimmer, "", CompilerGeneratedCode = true)] static IEnumerable IteratorWithGenericDAM< [KeptAttributeAttribute(typeof(DynamicallyAccessedMembersAttribute))] [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] T> () @@ -968,7 +968,7 @@ static IEnumerable IteratorWithGenericDAM< [Kept] [KeptAttributeAttribute (typeof (AsyncStateMachineAttribute))] [KeptAttributeAttribute (typeof (DebuggerStepThroughAttribute))] - [ExpectedWarning ("IL2119", nameof (AsyncWithGenericDAM), CompilerGeneratedCode = true, ProducedBy = Tool.Trimmer)] + [ExpectedWarning ("IL2119", nameof (AsyncWithGenericDAM), Tool.Trimmer, "", CompilerGeneratedCode = true)] static async Task AsyncWithGenericDAM< [KeptAttributeAttribute (typeof (DynamicallyAccessedMembersAttribute))] [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] T>() @@ -979,7 +979,7 @@ static async Task AsyncWithGenericDAM< [Kept] [KeptAttributeAttribute (typeof (AsyncIteratorStateMachineAttribute))] - [ExpectedWarning("IL2119", nameof(AsyncIteratorWithGenericDAM), CompilerGeneratedCode = true, ProducedBy = Tool.Trimmer)] + [ExpectedWarning("IL2119", nameof(AsyncIteratorWithGenericDAM), Tool.Trimmer, "", CompilerGeneratedCode = true)] static async IAsyncEnumerable AsyncIteratorWithGenericDAM< [KeptAttributeAttribute(typeof(DynamicallyAccessedMembersAttribute))] [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] T>() diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/Reflection/TypeUsedViaReflection.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/Reflection/TypeUsedViaReflection.cs index 352be76d77910b..981ad6227ceb8d 100644 --- a/src/tools/illink/test/Mono.Linker.Tests.Cases/Reflection/TypeUsedViaReflection.cs +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/Reflection/TypeUsedViaReflection.cs @@ -331,9 +331,9 @@ public class OverloadWith5ParametersWithIgnoreCase { } [Kept] // Small difference in formatting between analyzer/NativeAOT/linker - [ExpectedWarning ("IL2096", "'System.Type.GetType(String, Func, Func, Boolean, Boolean)'", ProducedBy = Tool.Trimmer)] - [ExpectedWarning ("IL2096", "'System.Type.GetType(String,Func`2,Func`4,Boolean,Boolean)'", ProducedBy = Tool.NativeAot)] - [ExpectedWarning ("IL2096", "'System.Type.GetType(String, Func, Func, Boolean, Boolean)'", ProducedBy = Tool.Analyzer)] + [ExpectedWarning ("IL2096", "'System.Type.GetType(String, Func, Func, Boolean, Boolean)'", Tool.Trimmer, "")] + [ExpectedWarning ("IL2096", "'System.Type.GetType(String,Func`2,Func`4,Boolean,Boolean)'", Tool.NativeAot, "")] + [ExpectedWarning ("IL2096", "'System.Type.GetType(String, Func, Func, Boolean, Boolean)'", Tool.Analyzer, "")] static void TestTypeOverloadWith5ParametersWithIgnoreCase () { const string reflectionTypeKeptString = "Mono.Linker.Tests.Cases.Reflection.TypeUsedViaReflection+OverloadWith5ParametersWithIgnoreCase"; @@ -384,9 +384,9 @@ static void TestUnknownIgnoreCase3Params (int num) [Kept] // Small difference in formatting between analyzer/NativeAOT/linker - [ExpectedWarning ("IL2096", "'System.Type.GetType(String, Func, Func, Boolean, Boolean)'", ProducedBy = Tool.Trimmer)] - [ExpectedWarning ("IL2096", "'System.Type.GetType(String,Func`2,Func`4,Boolean,Boolean)'", ProducedBy = Tool.NativeAot)] - [ExpectedWarning ("IL2096", "'System.Type.GetType(String, Func, Func, Boolean, Boolean)'", ProducedBy = Tool.Analyzer)] + [ExpectedWarning ("IL2096", "'System.Type.GetType(String, Func, Func, Boolean, Boolean)'", Tool.Trimmer, "")] + [ExpectedWarning ("IL2096", "'System.Type.GetType(String,Func`2,Func`4,Boolean,Boolean)'", Tool.NativeAot, "")] + [ExpectedWarning ("IL2096", "'System.Type.GetType(String, Func, Func, Boolean, Boolean)'", Tool.Analyzer, "")] static void TestUnknownIgnoreCase5Params (int num) { const string reflectionTypeKeptString = "mono.linker.tests.cases.reflection.TypeUsedViaReflection+CaseUnknown2, test, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null"; diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/RequiresCapability/BasicRequires.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/RequiresCapability/BasicRequires.cs index d9536b9358109a..453f5661502ff2 100644 --- a/src/tools/illink/test/Mono.Linker.Tests.Cases/RequiresCapability/BasicRequires.cs +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/RequiresCapability/BasicRequires.cs @@ -28,8 +28,8 @@ public static void Main () } [ExpectedWarning ("IL2026", "Message for --RequiresWithMessageOnly--.")] - [ExpectedWarning ("IL3002", "Message for --RequiresWithMessageOnly--.", ProducedBy = Tool.Analyzer | Tool.NativeAot)] - [ExpectedWarning ("IL3050", "Message for --RequiresWithMessageOnly--.", ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3002", "Message for --RequiresWithMessageOnly--.", Tool.Analyzer | Tool.NativeAot, "")] + [ExpectedWarning ("IL3050", "Message for --RequiresWithMessageOnly--.", Tool.Analyzer | Tool.NativeAot, "")] static void TestRequiresWithMessageOnlyOnMethod () { RequiresWithMessageOnly (); @@ -43,8 +43,8 @@ static void RequiresWithMessageOnly () } [ExpectedWarning ("IL2026", "Message for --RequiresWithMessageAndUrl--.", "https://helpurl")] - [ExpectedWarning ("IL3002", "Message for --RequiresWithMessageAndUrl--.", "https://helpurl", ProducedBy = Tool.Analyzer | Tool.NativeAot)] - [ExpectedWarning ("IL3050", "Message for --RequiresWithMessageAndUrl--.", "https://helpurl", ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3002", "Message for --RequiresWithMessageAndUrl--.", "https://helpurl", Tool.Analyzer | Tool.NativeAot, "")] + [ExpectedWarning ("IL3050", "Message for --RequiresWithMessageAndUrl--.", "https://helpurl", Tool.Analyzer | Tool.NativeAot, "")] static void TestRequiresWithMessageAndUrlOnMethod () { RequiresWithMessageAndUrl (); @@ -58,8 +58,8 @@ static void RequiresWithMessageAndUrl () } [ExpectedWarning ("IL2026", "Message for --ConstructorRequires--.")] - [ExpectedWarning ("IL3002", "Message for --ConstructorRequires--.", ProducedBy = Tool.Analyzer | Tool.NativeAot)] - [ExpectedWarning ("IL3050", "Message for --ConstructorRequires--.", ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3002", "Message for --ConstructorRequires--.", Tool.Analyzer | Tool.NativeAot, "")] + [ExpectedWarning ("IL3050", "Message for --ConstructorRequires--.", Tool.Analyzer | Tool.NativeAot, "")] static void TestRequiresOnConstructor () { new ConstructorRequires (); @@ -77,10 +77,10 @@ public ConstructorRequires () [ExpectedWarning ("IL2026", "Message for --getter PropertyRequires--.")] [ExpectedWarning ("IL2026", "Message for --setter PropertyRequires--.")] - [ExpectedWarning ("IL3002", "Message for --getter PropertyRequires--.", ProducedBy = Tool.Analyzer | Tool.NativeAot)] - [ExpectedWarning ("IL3002", "Message for --setter PropertyRequires--.", ProducedBy = Tool.Analyzer | Tool.NativeAot)] - [ExpectedWarning ("IL3050", "Message for --getter PropertyRequires--.", ProducedBy = Tool.Analyzer | Tool.NativeAot)] - [ExpectedWarning ("IL3050", "Message for --setter PropertyRequires--.", ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3002", "Message for --getter PropertyRequires--.", Tool.Analyzer | Tool.NativeAot, "")] + [ExpectedWarning ("IL3002", "Message for --setter PropertyRequires--.", Tool.Analyzer | Tool.NativeAot, "")] + [ExpectedWarning ("IL3050", "Message for --getter PropertyRequires--.", Tool.Analyzer | Tool.NativeAot, "")] + [ExpectedWarning ("IL3050", "Message for --setter PropertyRequires--.", Tool.Analyzer | Tool.NativeAot, "")] static void TestRequiresOnPropertyGetterAndSetter () { _ = PropertyRequires; @@ -107,8 +107,8 @@ static void WarningMessageWithoutEndingPeriod () } [ExpectedWarning ("IL2026", "Adds a trailing period to this message.")] - [ExpectedWarning ("IL3002", "Adds a trailing period to this message.", ProducedBy = Tool.Analyzer | Tool.NativeAot)] - [ExpectedWarning ("IL3050", "Adds a trailing period to this message.", ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3002", "Adds a trailing period to this message.", Tool.Analyzer | Tool.NativeAot, "")] + [ExpectedWarning ("IL3050", "Adds a trailing period to this message.", Tool.Analyzer | Tool.NativeAot, "")] static void TestThatTrailingPeriodIsAddedToMessage () { WarningMessageWithoutEndingPeriod (); @@ -123,8 +123,8 @@ static void WarningMessageEndsWithPeriod () [LogDoesNotContain ("Does not add a period to this message..")] [ExpectedWarning ("IL2026", "Does not add a period to this message.")] - [ExpectedWarning ("IL3002", "Does not add a period to this message.", ProducedBy = Tool.Analyzer | Tool.NativeAot)] - [ExpectedWarning ("IL3050", "Does not add a period to this message.", ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3002", "Does not add a period to this message.", Tool.Analyzer | Tool.NativeAot, "")] + [ExpectedWarning ("IL3050", "Does not add a period to this message.", Tool.Analyzer | Tool.NativeAot, "")] static void TestThatTrailingPeriodIsNotDuplicatedInWarningMessage () { WarningMessageEndsWithPeriod (); @@ -157,11 +157,11 @@ static event EventHandler EventToTestAdd { static event EventHandler AnnotatedEvent; [ExpectedWarning ("IL2026", "--EventToTestRemove.remove--")] - [ExpectedWarning ("IL3002", "--EventToTestRemove.remove--", ProducedBy = Tool.Analyzer | Tool.NativeAot)] - [ExpectedWarning ("IL3050", "--EventToTestRemove.remove--", ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3002", "--EventToTestRemove.remove--", Tool.Analyzer | Tool.NativeAot, "")] + [ExpectedWarning ("IL3050", "--EventToTestRemove.remove--", Tool.Analyzer | Tool.NativeAot, "")] [ExpectedWarning ("IL2026", "--EventToTestAdd.add--")] - [ExpectedWarning ("IL3002", "--EventToTestAdd.add--", ProducedBy = Tool.Analyzer | Tool.NativeAot)] - [ExpectedWarning ("IL3050", "--EventToTestAdd.add--", ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3002", "--EventToTestAdd.add--", Tool.Analyzer | Tool.NativeAot, "")] + [ExpectedWarning ("IL3050", "--EventToTestAdd.add--", Tool.Analyzer | Tool.NativeAot, "")] public static void Test () { EventToTestRemove -= (sender, e) => { }; @@ -181,8 +181,8 @@ public static void GenericTypeWithStaticMethodWhichRequires () { } } [ExpectedWarning ("IL2026", "--GenericTypeWithStaticMethodWhichRequires--")] - [ExpectedWarning ("IL3002", "--GenericTypeWithStaticMethodWhichRequires--", ProducedBy = Tool.Analyzer | Tool.NativeAot)] - [ExpectedWarning ("IL3050", "--GenericTypeWithStaticMethodWhichRequires--", ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3002", "--GenericTypeWithStaticMethodWhichRequires--", Tool.Analyzer | Tool.NativeAot, "")] + [ExpectedWarning ("IL3050", "--GenericTypeWithStaticMethodWhichRequires--", Tool.Analyzer | Tool.NativeAot, "")] public static void GenericTypeWithStaticMethodViaLdftn () { var _ = new Action (GenericWithStaticMethod.GenericTypeWithStaticMethodWhichRequires); @@ -208,8 +208,8 @@ static void Requires () { } [RequiresAssemblyFiles ("--PropertyRequires--")] static int PropertyRequires { get; set; } - [ExpectedWarning ("IL3002", "--PropertyRequires--", ProducedBy = Tool.Analyzer | Tool.NativeAot)] - [ExpectedWarning ("IL3002", "--PropertyRequires--", ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3002", "--PropertyRequires--", Tool.Analyzer | Tool.NativeAot, "")] + [ExpectedWarning ("IL3002", "--PropertyRequires--", Tool.Analyzer | Tool.NativeAot, "")] static void TestProperty () { var a = PropertyRequires; @@ -219,11 +219,11 @@ static void TestProperty () [RequiresAssemblyFiles ("--EventRequires--")] static event EventHandler EventRequires; - [ExpectedWarning ("IL3002", "--EventRequires--", ProducedBy = Tool.Analyzer | Tool.NativeAot)] - [ExpectedWarning ("IL3002", "--EventRequires--", ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3002", "--EventRequires--", Tool.Analyzer | Tool.NativeAot, "")] + [ExpectedWarning ("IL3002", "--EventRequires--", Tool.Analyzer | Tool.NativeAot, "")] [ExpectedWarning ("IL2026", "--RequiresOnEventLambda--")] - [ExpectedWarning ("IL3002", "--RequiresOnEventLambda--", ProducedBy = Tool.Analyzer | Tool.NativeAot)] - [ExpectedWarning ("IL3050", "--RequiresOnEventLambda--", ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3002", "--RequiresOnEventLambda--", Tool.Analyzer | Tool.NativeAot, "")] + [ExpectedWarning ("IL3050", "--RequiresOnEventLambda--", Tool.Analyzer | Tool.NativeAot, "")] static void TestEvent () { EventRequires += (object sender, EventArgs e) => throw new NotImplementedException (); @@ -237,7 +237,7 @@ static void TestEvent () EventRequires (null, null); // no warning on invocation } - [ExpectedWarning("IL3002", "--Requires--", ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning("IL3002", "--Requires--", Tool.Analyzer | Tool.NativeAot, "")] public static void Test() { Requires (); @@ -251,7 +251,7 @@ class DynamicCodeOnly [RequiresDynamicCode ("--Requires--")] static void Requires () { } - [ExpectedWarning ("IL3050", "--Requires--", ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3050", "--Requires--", Tool.Analyzer | Tool.NativeAot, "")] public static void Test () { Requires (); diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/RequiresCapability/ReflectionAccessFromCompilerGeneratedCode.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/RequiresCapability/ReflectionAccessFromCompilerGeneratedCode.cs index 2b2c0438c1d01d..71af8ce1374138 100644 --- a/src/tools/illink/test/Mono.Linker.Tests.Cases/RequiresCapability/ReflectionAccessFromCompilerGeneratedCode.cs +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/RequiresCapability/ReflectionAccessFromCompilerGeneratedCode.cs @@ -24,10 +24,9 @@ public static void Main () class ReflectionAccessFromStateMachine { [ExpectedWarning ("IL2026", "--TypeWithMethodWithRequires.MethodWithRequires--", CompilerGeneratedCode = true)] - [ExpectedWarning ("IL3002", "--TypeWithMethodWithRequires.MethodWithRequires--", CompilerGeneratedCode = true, ProducedBy = Tool.NativeAot)] - [ExpectedWarning ("IL3050", "--TypeWithMethodWithRequires.MethodWithRequires--", CompilerGeneratedCode = true, ProducedBy = Tool.NativeAot)] - [ExpectedWarning ("IL2118", nameof (TypeWithMethodWithRequires.MethodWithLocalFunctionCallsRUC), "LocalFunction", CompilerGeneratedCode = true, - ProducedBy = Tool.Trimmer)] + [ExpectedWarning ("IL3002", "--TypeWithMethodWithRequires.MethodWithRequires--", Tool.NativeAot, "", CompilerGeneratedCode = true)] + [ExpectedWarning ("IL3050", "--TypeWithMethodWithRequires.MethodWithRequires--", Tool.NativeAot, "", CompilerGeneratedCode = true)] + [ExpectedWarning ("IL2118", nameof (TypeWithMethodWithRequires.MethodWithLocalFunctionCallsRUC), "LocalFunction", Tool.Trimmer, "", CompilerGeneratedCode = true)] [ExpectedWarning ("IL2111", nameof (TypeWithMethodWithRequires.MethodWithAnnotations), CompilerGeneratedCode = true)] static IEnumerable TestIterator () { @@ -45,10 +44,9 @@ static IEnumerable TestIteratorWithRUC () } [ExpectedWarning ("IL2026", "--TypeWithMethodWithRequires.MethodWithRequires--", CompilerGeneratedCode = true)] - [ExpectedWarning ("IL3002", "--TypeWithMethodWithRequires.MethodWithRequires--", CompilerGeneratedCode = true, ProducedBy = Tool.NativeAot)] - [ExpectedWarning ("IL3050", "--TypeWithMethodWithRequires.MethodWithRequires--", CompilerGeneratedCode = true, ProducedBy = Tool.NativeAot)] - [ExpectedWarning ("IL2118", nameof (TypeWithMethodWithRequires.MethodWithLocalFunctionCallsRUC), "LocalFunction", CompilerGeneratedCode = true, - ProducedBy = Tool.Trimmer)] + [ExpectedWarning ("IL3002", "--TypeWithMethodWithRequires.MethodWithRequires--", Tool.NativeAot, "", CompilerGeneratedCode = true)] + [ExpectedWarning ("IL3050", "--TypeWithMethodWithRequires.MethodWithRequires--", Tool.NativeAot, "", CompilerGeneratedCode = true)] + [ExpectedWarning ("IL2118", nameof (TypeWithMethodWithRequires.MethodWithLocalFunctionCallsRUC), "LocalFunction", Tool.Trimmer, "", CompilerGeneratedCode = true)] [ExpectedWarning ("IL2111", nameof (TypeWithMethodWithRequires.MethodWithAnnotations), CompilerGeneratedCode = true)] static async void TestAsync () { @@ -66,11 +64,11 @@ static async void TestAsyncWithRUC () } [ExpectedWarning ("IL2026", "--TestIteratorWithRUC--")] - [ExpectedWarning ("IL3002", "--TestIteratorWithRUC--", ProducedBy = Tool.NativeAot | Tool.Analyzer)] - [ExpectedWarning ("IL3050", "--TestIteratorWithRUC--", ProducedBy = Tool.NativeAot | Tool.Analyzer)] + [ExpectedWarning ("IL3002", "--TestIteratorWithRUC--", Tool.NativeAot | Tool.Analyzer, "")] + [ExpectedWarning ("IL3050", "--TestIteratorWithRUC--", Tool.NativeAot | Tool.Analyzer, "")] [ExpectedWarning ("IL2026", "--TestAsyncWithRUC--")] - [ExpectedWarning ("IL3002", "--TestAsyncWithRUC--", ProducedBy = Tool.NativeAot | Tool.Analyzer)] - [ExpectedWarning ("IL3050", "--TestAsyncWithRUC--", ProducedBy = Tool.NativeAot | Tool.Analyzer)] + [ExpectedWarning ("IL3002", "--TestAsyncWithRUC--", Tool.NativeAot | Tool.Analyzer, "")] + [ExpectedWarning ("IL3050", "--TestAsyncWithRUC--", Tool.NativeAot | Tool.Analyzer, "")] public static void Test () { TestIterator ().GetEnumerator ().MoveNext (); // Must actually use the enumerator, otherwise NativeAOT will trim the implementation @@ -85,10 +83,9 @@ class ReflectionAccessFromLocalFunction static void TestLocalFunction () { [ExpectedWarning ("IL2026", "--TypeWithMethodWithRequires.MethodWithRequires--")] - [ExpectedWarning ("IL3002", "--TypeWithMethodWithRequires.MethodWithRequires--", ProducedBy = Tool.NativeAot)] - [ExpectedWarning ("IL3050", "--TypeWithMethodWithRequires.MethodWithRequires--", ProducedBy = Tool.NativeAot)] - [ExpectedWarning ("IL2118", nameof (TypeWithMethodWithRequires.MethodWithLocalFunctionCallsRUC), "LocalFunction", - ProducedBy = Tool.Trimmer)] + [ExpectedWarning ("IL3002", "--TypeWithMethodWithRequires.MethodWithRequires--", Tool.NativeAot, "")] + [ExpectedWarning ("IL3050", "--TypeWithMethodWithRequires.MethodWithRequires--", Tool.NativeAot, "")] + [ExpectedWarning ("IL2118", nameof (TypeWithMethodWithRequires.MethodWithLocalFunctionCallsRUC), "LocalFunction", Tool.Trimmer, "")] [ExpectedWarning ("IL2111", nameof (TypeWithMethodWithRequires.MethodWithAnnotations))] void LocalFunction () { @@ -98,8 +95,8 @@ void LocalFunction () } [ExpectedWarning ("IL2026", "--LocalFunction--")] - [ExpectedWarning ("IL3002", "--LocalFunction--", ProducedBy = Tool.NativeAot | Tool.Analyzer)] - [ExpectedWarning ("IL3050", "--LocalFunction--", ProducedBy = Tool.NativeAot | Tool.Analyzer)] + [ExpectedWarning ("IL3002", "--LocalFunction--", Tool.NativeAot | Tool.Analyzer, "")] + [ExpectedWarning ("IL3050", "--LocalFunction--", Tool.NativeAot | Tool.Analyzer, "")] static void TestLocalFunctionWithRUC () { [RequiresUnreferencedCode ("--LocalFunction--")] @@ -125,8 +122,8 @@ void LocalFunction () } [ExpectedWarning ("IL2026", "--TestLocalFunctionInMethodWithRUC--")] - [ExpectedWarning ("IL3002", "--TestLocalFunctionInMethodWithRUC--", ProducedBy = Tool.NativeAot | Tool.Analyzer)] - [ExpectedWarning ("IL3050", "--TestLocalFunctionInMethodWithRUC--", ProducedBy = Tool.NativeAot | Tool.Analyzer)] + [ExpectedWarning ("IL3002", "--TestLocalFunctionInMethodWithRUC--", Tool.NativeAot | Tool.Analyzer, "")] + [ExpectedWarning ("IL3050", "--TestLocalFunctionInMethodWithRUC--", Tool.NativeAot | Tool.Analyzer, "")] public static void Test () { TestLocalFunction (); @@ -141,10 +138,9 @@ static void TestLambda () { var lambda = [ExpectedWarning ("IL2026", "--TypeWithMethodWithRequires.MethodWithRequires--")] - [ExpectedWarning ("IL3002", "--TypeWithMethodWithRequires.MethodWithRequires--", ProducedBy = Tool.NativeAot)] - [ExpectedWarning ("IL3050", "--TypeWithMethodWithRequires.MethodWithRequires--", ProducedBy = Tool.NativeAot)] - [ExpectedWarning ("IL2118", nameof (TypeWithMethodWithRequires.MethodWithLocalFunctionCallsRUC), "LocalFunction", - ProducedBy = Tool.Trimmer)] + [ExpectedWarning ("IL3002", "--TypeWithMethodWithRequires.MethodWithRequires--", Tool.NativeAot, "")] + [ExpectedWarning ("IL3050", "--TypeWithMethodWithRequires.MethodWithRequires--", Tool.NativeAot, "")] + [ExpectedWarning ("IL2118", nameof (TypeWithMethodWithRequires.MethodWithLocalFunctionCallsRUC), "LocalFunction", Tool.Trimmer, "")] [ExpectedWarning ("IL2111", nameof (TypeWithMethodWithRequires.MethodWithAnnotations))] () => { typeof (TypeWithMethodWithRequires).RequiresAll (); @@ -153,8 +149,8 @@ static void TestLambda () } [ExpectedWarning ("IL2026", "--TestLambdaInMethodWithRUC--")] - [ExpectedWarning ("IL3002", "--TestLambdaInMethodWithRUC--", ProducedBy = Tool.NativeAot | Tool.Analyzer)] - [ExpectedWarning ("IL3050", "--TestLambdaInMethodWithRUC--", ProducedBy = Tool.NativeAot | Tool.Analyzer)] + [ExpectedWarning ("IL3002", "--TestLambdaInMethodWithRUC--", Tool.NativeAot | Tool.Analyzer, "")] + [ExpectedWarning ("IL3050", "--TestLambdaInMethodWithRUC--", Tool.NativeAot | Tool.Analyzer, "")] static void TestLambdaWithRUC () { var lambda = @@ -168,8 +164,8 @@ static void TestLambdaWithRUC () } [ExpectedWarning ("IL2026", "--TestLambdaWithRUCLdftn--")] - [ExpectedWarning ("IL3002", "--TestLambdaWithRUCLdftn--", ProducedBy = Tool.NativeAot | Tool.Analyzer)] - [ExpectedWarning ("IL3050", "--TestLambdaWithRUCLdftn--", ProducedBy = Tool.NativeAot | Tool.Analyzer)] + [ExpectedWarning ("IL3002", "--TestLambdaWithRUCLdftn--", Tool.NativeAot | Tool.Analyzer, "")] + [ExpectedWarning ("IL3050", "--TestLambdaWithRUCLdftn--", Tool.NativeAot | Tool.Analyzer, "")] static void TestLambdaWithRUCLdftn () { var lambda = @@ -196,8 +192,8 @@ static void TestLambdaInMethodWithRUC () } [ExpectedWarning ("IL2026", "--TestLambdaInMethodWithRUC--")] - [ExpectedWarning ("IL3002", "--TestLambdaInMethodWithRUC--", ProducedBy = Tool.NativeAot | Tool.Analyzer)] - [ExpectedWarning ("IL3050", "--TestLambdaInMethodWithRUC--", ProducedBy = Tool.NativeAot | Tool.Analyzer)] + [ExpectedWarning ("IL3002", "--TestLambdaInMethodWithRUC--", Tool.NativeAot | Tool.Analyzer, "")] + [ExpectedWarning ("IL3050", "--TestLambdaInMethodWithRUC--", Tool.NativeAot | Tool.Analyzer, "")] public static void Test () { TestLambda (); @@ -224,8 +220,8 @@ public static void MethodWithRequires () public static void MethodWithAnnotations ([DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.All)] Type t) { } [ExpectedWarning ("IL2026", "--MethodWithLocalFunctionWithRUC.LocalFunction--")] - [ExpectedWarning ("IL3002", "--MethodWithLocalFunctionWithRUC.LocalFunction--", ProducedBy = Tool.NativeAot | Tool.Analyzer)] - [ExpectedWarning ("IL3050", "--MethodWithLocalFunctionWithRUC.LocalFunction--", ProducedBy = Tool.NativeAot | Tool.Analyzer)] + [ExpectedWarning ("IL3002", "--MethodWithLocalFunctionWithRUC.LocalFunction--", Tool.NativeAot | Tool.Analyzer, "")] + [ExpectedWarning ("IL3050", "--MethodWithLocalFunctionWithRUC.LocalFunction--", Tool.NativeAot | Tool.Analyzer, "")] public static void MethodWithLocalFunctionWithRUC () { [RequiresUnreferencedCode ("--MethodWithLocalFunctionWithRUC.LocalFunction--")] @@ -239,8 +235,8 @@ void LocalFunction () public static void MethodWithLocalFunctionCallsRUC () { [ExpectedWarning ("IL2026", "--MethodWithRUC--")] - [ExpectedWarning ("IL3002", "--MethodWithRUC--", ProducedBy = Tool.NativeAot | Tool.Analyzer)] - [ExpectedWarning ("IL3050", "--MethodWithRUC--", ProducedBy = Tool.NativeAot | Tool.Analyzer)] + [ExpectedWarning ("IL3002", "--MethodWithRUC--", Tool.NativeAot | Tool.Analyzer, "")] + [ExpectedWarning ("IL3050", "--MethodWithRUC--", Tool.NativeAot | Tool.Analyzer, "")] void LocalFunction () => MethodWithRUC (); LocalFunction (); } diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/RequiresCapability/RequiresAccessedThrough.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/RequiresCapability/RequiresAccessedThrough.cs index 727463e800801e..8a43183e35ec68 100644 --- a/src/tools/illink/test/Mono.Linker.Tests.Cases/RequiresCapability/RequiresAccessedThrough.cs +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/RequiresCapability/RequiresAccessedThrough.cs @@ -43,8 +43,8 @@ static void RequiresOnlyThroughReflection () // https://github.com/dotnet/linker/issues/2739 - the discussion there explains why (at least for now) we don't produce // RAF and RDC warnings from the analyzer in these cases. [ExpectedWarning ("IL2026", "--RequiresOnlyThroughReflection--")] - [ExpectedWarning ("IL3002", "--RequiresOnlyThroughReflection--", ProducedBy = Tool.NativeAot)] - [ExpectedWarning ("IL3050", "--RequiresOnlyThroughReflection--", ProducedBy = Tool.NativeAot)] + [ExpectedWarning ("IL3002", "--RequiresOnlyThroughReflection--", Tool.NativeAot, "")] + [ExpectedWarning ("IL3050", "--RequiresOnlyThroughReflection--", Tool.NativeAot, "")] static void TestRequiresOnlyThroughReflection () { typeof (RequiresAccessedThrough) @@ -62,8 +62,8 @@ public static void RequiresOnlyThroughReflection () } [ExpectedWarning ("IL2026", "--GenericType.RequiresOnlyThroughReflection--")] - [ExpectedWarning ("IL3002", "--GenericType.RequiresOnlyThroughReflection--", ProducedBy = Tool.NativeAot)] - [ExpectedWarning ("IL3050", "--GenericType.RequiresOnlyThroughReflection--", ProducedBy = Tool.NativeAot)] + [ExpectedWarning ("IL3002", "--GenericType.RequiresOnlyThroughReflection--", Tool.NativeAot, "")] + [ExpectedWarning ("IL3050", "--GenericType.RequiresOnlyThroughReflection--", Tool.NativeAot, "")] public static void Test () { typeof (AccessedThroughReflectionOnGenericType) @@ -75,7 +75,7 @@ public static void Test () class AccessThroughSpecialAttribute { // https://github.com/dotnet/linker/issues/1873 - // [ExpectedWarning ("IL2026", "--DebuggerProxyType.Method--")] + // [ExpectedSharedWarning ("IL2026", "--DebuggerProxyType.Method--")] [DebuggerDisplay ("Some{*}value")] class TypeWithDebuggerDisplay { @@ -104,12 +104,12 @@ public PInvokeReturnType () { } } // https://github.com/mono/linker/issues/2116 - [ExpectedWarning ("IL2026", "--PInvokeReturnType.ctor--", ProducedBy = Tool.Trimmer)] + [ExpectedWarning ("IL2026", "--PInvokeReturnType.ctor--", Tool.Trimmer, "")] [DllImport ("nonexistent")] static extern PInvokeReturnType PInvokeReturnsType (); // Analyzer doesn't support IL2050 yet - [ExpectedWarning ("IL2050", ProducedBy = Tool.Trimmer | Tool.NativeAot)] + [ExpectedWarning ("IL2050", Tool.Trimmer | Tool.NativeAot, "")] public static void Test () { PInvokeReturnsType (); @@ -136,8 +136,8 @@ class NewConstraintTestAnnotatedType [ExpectedWarning ("IL2026", "--NewConstraintTestType.ctor--")] [ExpectedWarning ("IL2026", "--NewConstraintTestAnnotatedType--")] - [ExpectedWarning ("IL3002", "--NewConstraintTestType.ctor--", ProducedBy = Tool.Analyzer | Tool.NativeAot)] - [ExpectedWarning ("IL3050", "--NewConstraintTestType.ctor--", ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3002", "--NewConstraintTestType.ctor--", Tool.Analyzer | Tool.NativeAot, "")] + [ExpectedWarning ("IL3050", "--NewConstraintTestType.ctor--", Tool.Analyzer | Tool.NativeAot, "")] public static void Test () where T : new() { GenericMethod (); @@ -156,8 +156,8 @@ public static void DoNothing () { } [ExpectedWarning ("IL2026", "--NewConstraintTestType.ctor--")] [ExpectedWarning ("IL2026", "--NewConstraintTestAnnotatedType--")] - [ExpectedWarning ("IL3002", "--NewConstraintTestType.ctor--", ProducedBy = Tool.Analyzer | Tool.NativeAot)] - [ExpectedWarning ("IL3050", "--NewConstraintTestType.ctor--", ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3002", "--NewConstraintTestType.ctor--", Tool.Analyzer | Tool.NativeAot, "")] + [ExpectedWarning ("IL3050", "--NewConstraintTestType.ctor--", Tool.Analyzer | Tool.NativeAot, "")] public static void TestNewConstraintOnTypeParameter () where T : new() { _ = new NewConstraintOnTypeParameter (); @@ -166,8 +166,8 @@ public static void DoNothing () { } } [ExpectedWarning ("IL2026", "--AnnotatedMethod--")] - [ExpectedWarning ("IL3002", "--AnnotatedMethod--", ProducedBy = Tool.Analyzer | Tool.NativeAot)] - [ExpectedWarning ("IL3050", "--AnnotatedMethod--", ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3002", "--AnnotatedMethod--", Tool.Analyzer | Tool.NativeAot, "")] + [ExpectedWarning ("IL3050", "--AnnotatedMethod--", Tool.Analyzer | Tool.NativeAot, "")] public static void TestNewConstraintOnTypeParameterInAnnotatedMethod () { AnnotatedMethod (); @@ -191,8 +191,8 @@ public static void TestNewConstraintOnTypeParameterInAnnotatedType () [RequiresUnreferencedCode ("--AnnotatedType--")] class AnnotatedType { - [ExpectedWarning ("IL3002", "--NewConstraintTestType.ctor--", ProducedBy = Tool.Analyzer | Tool.NativeAot)] - [ExpectedWarning ("IL3050", "--NewConstraintTestType.ctor--", ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3002", "--NewConstraintTestType.ctor--", Tool.Analyzer | Tool.NativeAot, "")] + [ExpectedWarning ("IL3050", "--NewConstraintTestType.ctor--", Tool.Analyzer | Tool.NativeAot, "")] public static void Method () { _ = new NewConstraintOnTypeParameter (); @@ -202,8 +202,8 @@ public static void Method () [ExpectedWarning ("IL2026", "--NewConstraintTestType.ctor--")] [ExpectedWarning ("IL2026", "--NewConstraintTestAnnotatedType--")] - [ExpectedWarning ("IL3002", "--NewConstraintTestType.ctor--", ProducedBy = Tool.Analyzer | Tool.NativeAot)] - [ExpectedWarning ("IL3050", "--NewConstraintTestType.ctor--", ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3002", "--NewConstraintTestType.ctor--", Tool.Analyzer | Tool.NativeAot, "")] + [ExpectedWarning ("IL3050", "--NewConstraintTestType.ctor--", Tool.Analyzer | Tool.NativeAot, "")] public static void TestNewConstraintOnTypeParameterOfStaticType () where T : new() { NewConstraintOnTypeParameterOfStaticType.DoNothing (); @@ -224,11 +224,11 @@ static bool PropertyWithLdToken { } [ExpectedWarning ("IL2026", "--PropertyWithLdToken.get--")] - [ExpectedWarning ("IL2026", "--PropertyWithLdToken.get--", ProducedBy = Tool.Trimmer | Tool.NativeAot)] - [ExpectedWarning ("IL3002", "--PropertyWithLdToken.get--", ProducedBy = Tool.Analyzer | Tool.NativeAot)] - [ExpectedWarning ("IL3002", "--PropertyWithLdToken.get--", ProducedBy = Tool.NativeAot)] - [ExpectedWarning ("IL3050", "--PropertyWithLdToken.get--", ProducedBy = Tool.Analyzer | Tool.NativeAot)] - [ExpectedWarning ("IL3050", "--PropertyWithLdToken.get--", ProducedBy = Tool.NativeAot)] + [ExpectedWarning ("IL2026", "--PropertyWithLdToken.get--", Tool.Trimmer | Tool.NativeAot, "")] + [ExpectedWarning ("IL3002", "--PropertyWithLdToken.get--", Tool.Analyzer | Tool.NativeAot, "")] + [ExpectedWarning ("IL3002", "--PropertyWithLdToken.get--", Tool.NativeAot, "")] + [ExpectedWarning ("IL3050", "--PropertyWithLdToken.get--", Tool.Analyzer | Tool.NativeAot, "")] + [ExpectedWarning ("IL3050", "--PropertyWithLdToken.get--", Tool.NativeAot, "")] static void TestPropertyLdToken () { Expression> getter = () => PropertyWithLdToken; @@ -242,8 +242,8 @@ static void MethodWithLdToken () } [ExpectedWarning ("IL2026", "--MethodWithLdToken--")] - [ExpectedWarning ("IL3002", "--MethodWithLdToken--", ProducedBy = Tool.Analyzer | Tool.NativeAot)] - [ExpectedWarning ("IL3050", "--MethodWithLdToken--", ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3002", "--MethodWithLdToken--", Tool.Analyzer | Tool.NativeAot, "")] + [ExpectedWarning ("IL3050", "--MethodWithLdToken--", Tool.Analyzer | Tool.NativeAot, "")] static void TestMethodLdToken () { Expression e = () => MethodWithLdToken (); @@ -257,7 +257,7 @@ class FieldWithLdTokenType } [ExpectedWarning ("IL2026", "--FieldWithLdToken--")] - [ExpectedWarning ("IL3050", "--FieldWithLdToken--", ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3050", "--FieldWithLdToken--", Tool.Analyzer | Tool.NativeAot, "")] static void TestFieldLdToken () { Expression> f = () => FieldWithLdTokenType.Field; @@ -281,16 +281,16 @@ static void MethodWithDelegate () } [ExpectedWarning ("IL2026", "--MethodWithDelegate--")] - [ExpectedWarning ("IL3002", "--MethodWithDelegate--", ProducedBy = Tool.Analyzer | Tool.NativeAot)] - [ExpectedWarning ("IL3050", "--MethodWithDelegate--", ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3002", "--MethodWithDelegate--", Tool.Analyzer | Tool.NativeAot, "")] + [ExpectedWarning ("IL3050", "--MethodWithDelegate--", Tool.Analyzer | Tool.NativeAot, "")] static void TestMethodWithDelegate () { Action a = MethodWithDelegate; } [ExpectedWarning ("IL2026", "--LambdaThroughDelegate--")] - [ExpectedWarning ("IL3002", "--LambdaThroughDelegate--", ProducedBy = Tool.Analyzer | Tool.NativeAot)] - [ExpectedWarning ("IL3050", "--LambdaThroughDelegate--", ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3002", "--LambdaThroughDelegate--", Tool.Analyzer | Tool.NativeAot, "")] + [ExpectedWarning ("IL3050", "--LambdaThroughDelegate--", Tool.Analyzer | Tool.NativeAot, "")] static void LambdaThroughDelegate () { Action a = @@ -303,8 +303,8 @@ static void LambdaThroughDelegate () } [ExpectedWarning ("IL2026", "--LocalFunctionThroughDelegate--")] - [ExpectedWarning ("IL3002", "--LocalFunctionThroughDelegate--", ProducedBy = Tool.Analyzer | Tool.NativeAot)] - [ExpectedWarning ("IL3050", "--LocalFunctionThroughDelegate--", ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3002", "--LocalFunctionThroughDelegate--", Tool.Analyzer | Tool.NativeAot, "")] + [ExpectedWarning ("IL3050", "--LocalFunctionThroughDelegate--", Tool.Analyzer | Tool.NativeAot, "")] static void LocalFunctionThroughDelegate () { Action a = Local; @@ -341,15 +341,15 @@ private Target (int i) { } private static void MethodRequires () { } } - [ExpectedWarning ("IL2026", "--Target.MethodRequires--", ProducedBy = Tool.Trimmer | Tool.NativeAot)] - [ExpectedWarning ("IL3002", "--Target.MethodRequires--", ProducedBy = Tool.NativeAot)] - [ExpectedWarning ("IL3050", "--Target.MethodRequires--", ProducedBy = Tool.NativeAot)] + [ExpectedWarning ("IL2026", "--Target.MethodRequires--", Tool.Trimmer | Tool.NativeAot, "")] + [ExpectedWarning ("IL3002", "--Target.MethodRequires--", Tool.NativeAot, "")] + [ExpectedWarning ("IL3050", "--Target.MethodRequires--", Tool.NativeAot, "")] [UnsafeAccessor (UnsafeAccessorKind.StaticMethod)] extern static void MethodRequires (Target target); - [ExpectedWarning ("IL2026", "--Target..ctor--", ProducedBy = Tool.Trimmer | Tool.NativeAot)] - [ExpectedWarning ("IL3002", "--Target..ctor--", ProducedBy = Tool.NativeAot)] - [ExpectedWarning ("IL3050", "--Target..ctor--", ProducedBy = Tool.NativeAot)] + [ExpectedWarning ("IL2026", "--Target..ctor--", Tool.Trimmer | Tool.NativeAot, "")] + [ExpectedWarning ("IL3002", "--Target..ctor--", Tool.NativeAot, "")] + [ExpectedWarning ("IL3050", "--Target..ctor--", Tool.NativeAot, "")] [UnsafeAccessor (UnsafeAccessorKind.Constructor)] extern static Target Constructor (int i); @@ -367,22 +367,22 @@ private void InstanceMethod () { } private int InstanceField; } - [ExpectedWarning ("IL2026", "--TargetWitRequires--", ProducedBy = Tool.Trimmer | Tool.NativeAot)] + [ExpectedWarning ("IL2026", "--TargetWitRequires--", Tool.Trimmer | Tool.NativeAot, "")] [UnsafeAccessor (UnsafeAccessorKind.Constructor)] extern static TargetWithRequires TargetRequiresConstructor (); - [ExpectedWarning ("IL2026", "--TargetWitRequires--", ProducedBy = Tool.Trimmer | Tool.NativeAot)] + [ExpectedWarning ("IL2026", "--TargetWitRequires--", Tool.Trimmer | Tool.NativeAot, "")] [UnsafeAccessor (UnsafeAccessorKind.StaticMethod, Name = "StaticMethod")] extern static void TargetRequiresStaticMethod (TargetWithRequires target); // For trimmer this is a reflection access to an instance method - and as such it must warn (since it's in theory possible // to invoke the method via reflection on a null instance) // For NativeAOT this is a direct call to an instance method (there's no reflection involved) and as such it doesn't need to warn - [ExpectedWarning ("IL2026", "--TargetWitRequires--", ProducedBy = Tool.Trimmer)] + [ExpectedWarning ("IL2026", "--TargetWitRequires--", Tool.Trimmer, "")] [UnsafeAccessor (UnsafeAccessorKind.Method, Name = "InstanceMethod")] extern static void TargetRequiresInstanceMethod (TargetWithRequires target); - [ExpectedWarning ("IL2026", "--TargetWitRequires--", ProducedBy = Tool.Trimmer | Tool.NativeAot)] + [ExpectedWarning ("IL2026", "--TargetWitRequires--", Tool.Trimmer | Tool.NativeAot, "")] [UnsafeAccessor (UnsafeAccessorKind.StaticField, Name = "StaticField")] extern static ref int TargetRequiresStaticField (TargetWithRequires target); diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/RequiresCapability/RequiresAttributeMismatch.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/RequiresCapability/RequiresAttributeMismatch.cs index 4653f445cabb39..94249d6af5b6f0 100644 --- a/src/tools/illink/test/Mono.Linker.Tests.Cases/RequiresCapability/RequiresAttributeMismatch.cs +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/RequiresCapability/RequiresAttributeMismatch.cs @@ -26,87 +26,87 @@ class RequiresAttributeMismatch // The analyzer matches this behavior, treating the get/set methods as annotated if the property is annotated, // and warning only on the get/set methods. [ExpectedWarning ("IL2026", "BaseClassWithRequires.VirtualPropertyAnnotationInAccesor.get")] - [ExpectedWarning ("IL3002", "BaseClassWithRequires.VirtualPropertyAnnotationInAccesor.get", ProducedBy = Tool.NativeAot)] - [ExpectedWarning ("IL3050", "BaseClassWithRequires.VirtualPropertyAnnotationInAccesor.get", ProducedBy = Tool.NativeAot)] + [ExpectedWarning ("IL3002", "BaseClassWithRequires.VirtualPropertyAnnotationInAccesor.get", Tool.NativeAot, "")] + [ExpectedWarning ("IL3050", "BaseClassWithRequires.VirtualPropertyAnnotationInAccesor.get", Tool.NativeAot, "")] [ExpectedWarning ("IL2026", "BaseClassWithRequires.VirtualPropertyAnnotationInAccesor.get")] - [ExpectedWarning ("IL3002", "BaseClassWithRequires.VirtualPropertyAnnotationInAccesor.get", ProducedBy = Tool.NativeAot)] - [ExpectedWarning ("IL3050", "BaseClassWithRequires.VirtualPropertyAnnotationInAccesor.get", ProducedBy = Tool.NativeAot)] + [ExpectedWarning ("IL3002", "BaseClassWithRequires.VirtualPropertyAnnotationInAccesor.get", Tool.NativeAot, "")] + [ExpectedWarning ("IL3050", "BaseClassWithRequires.VirtualPropertyAnnotationInAccesor.get", Tool.NativeAot, "")] [ExpectedWarning ("IL2026", "BaseClassWithRequires.VirtualPropertyAnnotationInAccesor.get")] - [ExpectedWarning ("IL3002", "BaseClassWithRequires.VirtualPropertyAnnotationInAccesor.get", ProducedBy = Tool.NativeAot)] - [ExpectedWarning ("IL3050", "BaseClassWithRequires.VirtualPropertyAnnotationInAccesor.get", ProducedBy = Tool.NativeAot)] + [ExpectedWarning ("IL3002", "BaseClassWithRequires.VirtualPropertyAnnotationInAccesor.get", Tool.NativeAot, "")] + [ExpectedWarning ("IL3050", "BaseClassWithRequires.VirtualPropertyAnnotationInAccesor.get", Tool.NativeAot, "")] [ExpectedWarning ("IL2026", "DerivedClassWithRequires.VirtualPropertyAnnotationInAccesor.get")] - [ExpectedWarning ("IL3002", "DerivedClassWithRequires.VirtualPropertyAnnotationInAccesor.get", ProducedBy = Tool.NativeAot)] - [ExpectedWarning ("IL3050", "DerivedClassWithRequires.VirtualPropertyAnnotationInAccesor.get", ProducedBy = Tool.NativeAot)] - [ExpectedWarning ("IL3002", "DerivedClassWithRequires.VirtualPropertyAnnotationInProperty.get", ProducedBy = Tool.NativeAot)] - [ExpectedWarning ("IL3002", "DerivedClassWithRequires.VirtualPropertyAnnotationInProperty.set", ProducedBy = Tool.NativeAot)] - [ExpectedWarning ("IL3002", "DerivedClassWithAllWarnings.VirtualPropertyAnnotationInAccesor.get", ProducedBy = Tool.NativeAot)] + [ExpectedWarning ("IL3002", "DerivedClassWithRequires.VirtualPropertyAnnotationInAccesor.get", Tool.NativeAot, "")] + [ExpectedWarning ("IL3050", "DerivedClassWithRequires.VirtualPropertyAnnotationInAccesor.get", Tool.NativeAot, "")] + [ExpectedWarning ("IL3002", "DerivedClassWithRequires.VirtualPropertyAnnotationInProperty.get", Tool.NativeAot, "")] + [ExpectedWarning ("IL3002", "DerivedClassWithRequires.VirtualPropertyAnnotationInProperty.set", Tool.NativeAot, "")] + [ExpectedWarning ("IL3002", "DerivedClassWithAllWarnings.VirtualPropertyAnnotationInAccesor.get", Tool.NativeAot, "")] [ExpectedWarning ("IL2026", "DerivedClassWithAllWarnings.VirtualPropertyAnnotationInAccesor.set")] - [ExpectedWarning ("IL3002", "DerivedClassWithAllWarnings.VirtualPropertyAnnotationInAccesor.set", ProducedBy = Tool.NativeAot)] + [ExpectedWarning ("IL3002", "DerivedClassWithAllWarnings.VirtualPropertyAnnotationInAccesor.set", Tool.NativeAot, "")] [ExpectedWarning ("IL2026", "DerivedClassWithAllWarnings.VirtualPropertyAnnotationInProperty.get")] - [ExpectedWarning ("IL3002", "DerivedClassWithAllWarnings.VirtualPropertyAnnotationInProperty.get", ProducedBy = Tool.NativeAot)] + [ExpectedWarning ("IL3002", "DerivedClassWithAllWarnings.VirtualPropertyAnnotationInProperty.get", Tool.NativeAot, "")] [ExpectedWarning ("IL2026", "DerivedClassWithAllWarnings.VirtualPropertyAnnotationInProperty.set")] - [ExpectedWarning ("IL3002", "DerivedClassWithAllWarnings.VirtualPropertyAnnotationInProperty.set", ProducedBy = Tool.NativeAot)] + [ExpectedWarning ("IL3002", "DerivedClassWithAllWarnings.VirtualPropertyAnnotationInProperty.set", Tool.NativeAot, "")] [ExpectedWarning ("IL2026", "DerivedClassWithAllWarnings.VirtualPropertyAnnotationInPropertyAndAccessor.set")] - [ExpectedWarning ("IL3002", "DerivedClassWithAllWarnings.VirtualPropertyAnnotationInPropertyAndAccessor.set", ProducedBy = Tool.NativeAot)] + [ExpectedWarning ("IL3002", "DerivedClassWithAllWarnings.VirtualPropertyAnnotationInPropertyAndAccessor.set", Tool.NativeAot, "")] [ExpectedWarning ("IL2026", "BaseClassWithRequires.VirtualMethod()")] - [ExpectedWarning ("IL3002", "BaseClassWithRequires.VirtualMethod()", ProducedBy = Tool.NativeAot)] - [ExpectedWarning ("IL3050", "BaseClassWithRequires.VirtualMethod()", ProducedBy = Tool.NativeAot)] + [ExpectedWarning ("IL3002", "BaseClassWithRequires.VirtualMethod()", Tool.NativeAot, "")] + [ExpectedWarning ("IL3050", "BaseClassWithRequires.VirtualMethod()", Tool.NativeAot, "")] [ExpectedWarning ("IL2026", "BaseClassWithRequires.VirtualMethod()")] - [ExpectedWarning ("IL3002", "BaseClassWithRequires.VirtualMethod()", ProducedBy = Tool.NativeAot)] - [ExpectedWarning ("IL3050", "BaseClassWithRequires.VirtualMethod()", ProducedBy = Tool.NativeAot)] + [ExpectedWarning ("IL3002", "BaseClassWithRequires.VirtualMethod()", Tool.NativeAot, "")] + [ExpectedWarning ("IL3050", "BaseClassWithRequires.VirtualMethod()", Tool.NativeAot, "")] [ExpectedWarning ("IL2026", "BaseClassWithRequires.VirtualMethod()")] - [ExpectedWarning ("IL3002", "BaseClassWithRequires.VirtualMethod()", ProducedBy = Tool.NativeAot)] - [ExpectedWarning ("IL3050", "BaseClassWithRequires.VirtualMethod()", ProducedBy = Tool.NativeAot)] + [ExpectedWarning ("IL3002", "BaseClassWithRequires.VirtualMethod()", Tool.NativeAot, "")] + [ExpectedWarning ("IL3050", "BaseClassWithRequires.VirtualMethod()", Tool.NativeAot, "")] [ExpectedWarning ("IL2026", "DerivedClassWithRequires.VirtualMethod()")] - [ExpectedWarning ("IL3002", "DerivedClassWithRequires.VirtualMethod()", ProducedBy = Tool.NativeAot)] - [ExpectedWarning ("IL3050", "DerivedClassWithRequires.VirtualMethod()", ProducedBy = Tool.NativeAot)] + [ExpectedWarning ("IL3002", "DerivedClassWithRequires.VirtualMethod()", Tool.NativeAot, "")] + [ExpectedWarning ("IL3050", "DerivedClassWithRequires.VirtualMethod()", Tool.NativeAot, "")] [ExpectedWarning ("IL2026", "IBaseWithRequires.PropertyAnnotationInAccesor.get")] - [ExpectedWarning ("IL3002", "IBaseWithRequires.PropertyAnnotationInAccesor.get", ProducedBy = Tool.NativeAot)] - [ExpectedWarning ("IL3050", "IBaseWithRequires.PropertyAnnotationInAccesor.get", ProducedBy = Tool.NativeAot)] + [ExpectedWarning ("IL3002", "IBaseWithRequires.PropertyAnnotationInAccesor.get", Tool.NativeAot, "")] + [ExpectedWarning ("IL3050", "IBaseWithRequires.PropertyAnnotationInAccesor.get", Tool.NativeAot, "")] [ExpectedWarning ("IL2026", "IBaseWithRequires.PropertyAnnotationInPropertyAndAccessor.set")] - [ExpectedWarning ("IL3002", "IBaseWithRequires.PropertyAnnotationInPropertyAndAccessor.set", ProducedBy = Tool.NativeAot)] - [ExpectedWarning ("IL3002", "IBaseWithRequires.PropertyAnnotationInPropertyAndAccessor.get", ProducedBy = Tool.NativeAot)] - [ExpectedWarning ("IL3002", "IBaseWithRequires.PropertyAnnotationInProperty.get", ProducedBy = Tool.NativeAot)] - [ExpectedWarning ("IL3002", "IBaseWithRequires.PropertyAnnotationInProperty.set", ProducedBy = Tool.NativeAot)] + [ExpectedWarning ("IL3002", "IBaseWithRequires.PropertyAnnotationInPropertyAndAccessor.set", Tool.NativeAot, "")] + [ExpectedWarning ("IL3002", "IBaseWithRequires.PropertyAnnotationInPropertyAndAccessor.get", Tool.NativeAot, "")] + [ExpectedWarning ("IL3002", "IBaseWithRequires.PropertyAnnotationInProperty.get", Tool.NativeAot, "")] + [ExpectedWarning ("IL3002", "IBaseWithRequires.PropertyAnnotationInProperty.set", Tool.NativeAot, "")] [ExpectedWarning ("IL2026", "IBaseWithRequires.Method()")] - [ExpectedWarning ("IL3002", "IBaseWithRequires.Method()", ProducedBy = Tool.NativeAot)] - [ExpectedWarning ("IL3050", "IBaseWithRequires.Method()", ProducedBy = Tool.NativeAot)] + [ExpectedWarning ("IL3002", "IBaseWithRequires.Method()", Tool.NativeAot, "")] + [ExpectedWarning ("IL3050", "IBaseWithRequires.Method()", Tool.NativeAot, "")] [ExpectedWarning ("IL2026", "ImplementationClassWithRequires.Method()")] - [ExpectedWarning ("IL3002", "ImplementationClassWithRequires.Method()", ProducedBy = Tool.NativeAot)] - [ExpectedWarning ("IL3050", "ImplementationClassWithRequires.Method()", ProducedBy = Tool.NativeAot)] + [ExpectedWarning ("IL3002", "ImplementationClassWithRequires.Method()", Tool.NativeAot, "")] + [ExpectedWarning ("IL3050", "ImplementationClassWithRequires.Method()", Tool.NativeAot, "")] [ExpectedWarning ("IL2026", "ImplementationClassWithRequires.PropertyAnnotationInAccesor.get")] - [ExpectedWarning ("IL3002", "ImplementationClassWithRequires.PropertyAnnotationInAccesor.get", ProducedBy = Tool.NativeAot)] - [ExpectedWarning ("IL3050", "ImplementationClassWithRequires.PropertyAnnotationInAccesor.get", ProducedBy = Tool.NativeAot)] + [ExpectedWarning ("IL3002", "ImplementationClassWithRequires.PropertyAnnotationInAccesor.get", Tool.NativeAot, "")] + [ExpectedWarning ("IL3050", "ImplementationClassWithRequires.PropertyAnnotationInAccesor.get", Tool.NativeAot, "")] [ExpectedWarning ("IL2026", "ImplementationClassWithRequires.PropertyAnnotationInPropertyAndAccessor.get")] - [ExpectedWarning ("IL3002", "ImplementationClassWithRequires.PropertyAnnotationInPropertyAndAccessor.get", ProducedBy = Tool.NativeAot)] - [ExpectedWarning ("IL3002", "ImplementationClassWithRequires.PropertyAnnotationInPropertyAndAccessor.set", ProducedBy = Tool.NativeAot)] - [ExpectedWarning ("IL3002", "ImplementationClassWithRequires.PropertyAnnotationInProperty.get", ProducedBy = Tool.NativeAot)] - [ExpectedWarning ("IL3002", "ImplementationClassWithRequires.PropertyAnnotationInProperty.set", ProducedBy = Tool.NativeAot)] + [ExpectedWarning ("IL3002", "ImplementationClassWithRequires.PropertyAnnotationInPropertyAndAccessor.get", Tool.NativeAot, "")] + [ExpectedWarning ("IL3002", "ImplementationClassWithRequires.PropertyAnnotationInPropertyAndAccessor.set", Tool.NativeAot, "")] + [ExpectedWarning ("IL3002", "ImplementationClassWithRequires.PropertyAnnotationInProperty.get", Tool.NativeAot, "")] + [ExpectedWarning ("IL3002", "ImplementationClassWithRequires.PropertyAnnotationInProperty.set", Tool.NativeAot, "")] [ExpectedWarning ("IL2026", "ImplementationClassWithoutRequires.PropertyAnnotationInPropertyAndAccessor.get")] - [ExpectedWarning ("IL3002", "ImplementationClassWithoutRequires.PropertyAnnotationInPropertyAndAccessor.get", ProducedBy = Tool.NativeAot)] + [ExpectedWarning ("IL3002", "ImplementationClassWithoutRequires.PropertyAnnotationInPropertyAndAccessor.get", Tool.NativeAot, "")] [ExpectedWarning ("IL2026", "ImplementationClassWithRequiresInSource.Method()")] - [ExpectedWarning ("IL3002", "ImplementationClassWithRequiresInSource.Method()", ProducedBy = Tool.NativeAot)] - [ExpectedWarning ("IL3050", "ImplementationClassWithRequiresInSource.Method()", ProducedBy = Tool.NativeAot)] + [ExpectedWarning ("IL3002", "ImplementationClassWithRequiresInSource.Method()", Tool.NativeAot, "")] + [ExpectedWarning ("IL3050", "ImplementationClassWithRequiresInSource.Method()", Tool.NativeAot, "")] [ExpectedWarning ("IL2026", "ImplementationClassWithRequiresInSource.PropertyAnnotationInAccesor.get")] - [ExpectedWarning ("IL3002", "ImplementationClassWithRequiresInSource.PropertyAnnotationInAccesor.get", ProducedBy = Tool.NativeAot)] - [ExpectedWarning ("IL3050", "ImplementationClassWithRequiresInSource.PropertyAnnotationInAccesor.get", ProducedBy = Tool.NativeAot)] - [ExpectedWarning ("IL3002", "ImplementationClassWithRequiresInSource.PropertyAnnotationInProperty.get", ProducedBy = Tool.NativeAot)] - [ExpectedWarning ("IL3002", "ImplementationClassWithRequiresInSource.PropertyAnnotationInProperty.set", ProducedBy = Tool.NativeAot)] + [ExpectedWarning ("IL3002", "ImplementationClassWithRequiresInSource.PropertyAnnotationInAccesor.get", Tool.NativeAot, "")] + [ExpectedWarning ("IL3050", "ImplementationClassWithRequiresInSource.PropertyAnnotationInAccesor.get", Tool.NativeAot, "")] + [ExpectedWarning ("IL3002", "ImplementationClassWithRequiresInSource.PropertyAnnotationInProperty.get", Tool.NativeAot, "")] + [ExpectedWarning ("IL3002", "ImplementationClassWithRequiresInSource.PropertyAnnotationInProperty.set", Tool.NativeAot, "")] [ExpectedWarning ("IL2026", "BaseClassWithRequires.VirtualPropertyAnnotationInPropertyAndAccessor.get")] - [ExpectedWarning ("IL3002", "BaseClassWithRequires.VirtualPropertyAnnotationInPropertyAndAccessor.get", ProducedBy = Tool.NativeAot)] + [ExpectedWarning ("IL3002", "BaseClassWithRequires.VirtualPropertyAnnotationInPropertyAndAccessor.get", Tool.NativeAot, "")] [ExpectedWarning ("IL2026", "BaseClassWithRequires.VirtualPropertyAnnotationInPropertyAndAccessor.get")] - [ExpectedWarning ("IL3002", "BaseClassWithRequires.VirtualPropertyAnnotationInPropertyAndAccessor.get", ProducedBy = Tool.NativeAot)] + [ExpectedWarning ("IL3002", "BaseClassWithRequires.VirtualPropertyAnnotationInPropertyAndAccessor.get", Tool.NativeAot, "")] [ExpectedWarning ("IL2026", "BaseClassWithRequires.VirtualPropertyAnnotationInPropertyAndAccessor.get")] - [ExpectedWarning ("IL3002", "BaseClassWithRequires.VirtualPropertyAnnotationInPropertyAndAccessor.get", ProducedBy = Tool.NativeAot)] - [ExpectedWarning ("IL3002", "BaseClassWithRequires.VirtualPropertyAnnotationInPropertyAndAccessor.set", ProducedBy = Tool.NativeAot)] - [ExpectedWarning ("IL3002", "BaseClassWithRequires.VirtualPropertyAnnotationInPropertyAndAccessor.set", ProducedBy = Tool.NativeAot)] - [ExpectedWarning ("IL3002", "BaseClassWithRequires.VirtualPropertyAnnotationInPropertyAndAccessor.set", ProducedBy = Tool.NativeAot)] - [ExpectedWarning ("IL3002", "BaseClassWithRequires.VirtualPropertyAnnotationInProperty.get", ProducedBy = Tool.NativeAot)] - [ExpectedWarning ("IL3002", "BaseClassWithRequires.VirtualPropertyAnnotationInProperty.get", ProducedBy = Tool.NativeAot)] - [ExpectedWarning ("IL3002", "BaseClassWithRequires.VirtualPropertyAnnotationInProperty.get", ProducedBy = Tool.NativeAot)] - [ExpectedWarning ("IL3002", "BaseClassWithRequires.VirtualPropertyAnnotationInProperty.set", ProducedBy = Tool.NativeAot)] - [ExpectedWarning ("IL3002", "BaseClassWithRequires.VirtualPropertyAnnotationInProperty.set", ProducedBy = Tool.NativeAot)] - [ExpectedWarning ("IL3002", "BaseClassWithRequires.VirtualPropertyAnnotationInProperty.set", ProducedBy = Tool.NativeAot)] + [ExpectedWarning ("IL3002", "BaseClassWithRequires.VirtualPropertyAnnotationInPropertyAndAccessor.get", Tool.NativeAot, "")] + [ExpectedWarning ("IL3002", "BaseClassWithRequires.VirtualPropertyAnnotationInPropertyAndAccessor.set", Tool.NativeAot, "")] + [ExpectedWarning ("IL3002", "BaseClassWithRequires.VirtualPropertyAnnotationInPropertyAndAccessor.set", Tool.NativeAot, "")] + [ExpectedWarning ("IL3002", "BaseClassWithRequires.VirtualPropertyAnnotationInPropertyAndAccessor.set", Tool.NativeAot, "")] + [ExpectedWarning ("IL3002", "BaseClassWithRequires.VirtualPropertyAnnotationInProperty.get", Tool.NativeAot, "")] + [ExpectedWarning ("IL3002", "BaseClassWithRequires.VirtualPropertyAnnotationInProperty.get", Tool.NativeAot, "")] + [ExpectedWarning ("IL3002", "BaseClassWithRequires.VirtualPropertyAnnotationInProperty.get", Tool.NativeAot, "")] + [ExpectedWarning ("IL3002", "BaseClassWithRequires.VirtualPropertyAnnotationInProperty.set", Tool.NativeAot, "")] + [ExpectedWarning ("IL3002", "BaseClassWithRequires.VirtualPropertyAnnotationInProperty.set", Tool.NativeAot, "")] + [ExpectedWarning ("IL3002", "BaseClassWithRequires.VirtualPropertyAnnotationInProperty.set", Tool.NativeAot, "")] public static void Main () { @@ -174,8 +174,8 @@ class DerivedClassWithRequires : BaseClassWithoutRequires [RequiresAssemblyFiles ("Message")] [RequiresDynamicCode ("Message")] [ExpectedWarning ("IL2046", "DerivedClassWithRequires.VirtualMethod()", "BaseClassWithoutRequires.VirtualMethod()")] - [ExpectedWarning ("IL3003", "DerivedClassWithRequires.VirtualMethod()", "BaseClassWithoutRequires.VirtualMethod()", ProducedBy = Tool.Analyzer | Tool.NativeAot)] - [ExpectedWarning ("IL3051", "DerivedClassWithRequires.VirtualMethod()", "BaseClassWithoutRequires.VirtualMethod()", ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3003", "DerivedClassWithRequires.VirtualMethod()", "BaseClassWithoutRequires.VirtualMethod()", Tool.Analyzer | Tool.NativeAot, "")] + [ExpectedWarning ("IL3051", "DerivedClassWithRequires.VirtualMethod()", "BaseClassWithoutRequires.VirtualMethod()", Tool.Analyzer | Tool.NativeAot, "")] public override void VirtualMethod () { } @@ -183,8 +183,8 @@ public override void VirtualMethod () private string name; public override string VirtualPropertyAnnotationInAccesor { [ExpectedWarning ("IL2046", "DerivedClassWithRequires.VirtualPropertyAnnotationInAccesor.get", "BaseClassWithoutRequires.VirtualPropertyAnnotationInAccesor.get")] - [ExpectedWarning ("IL3003", "DerivedClassWithRequires.VirtualPropertyAnnotationInAccesor.get", "BaseClassWithoutRequires.VirtualPropertyAnnotationInAccesor.get", ProducedBy = Tool.Analyzer | Tool.NativeAot)] - [ExpectedWarning ("IL3051", "DerivedClassWithRequires.VirtualPropertyAnnotationInAccesor.get", "BaseClassWithoutRequires.VirtualPropertyAnnotationInAccesor.get", ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3003", "DerivedClassWithRequires.VirtualPropertyAnnotationInAccesor.get", "BaseClassWithoutRequires.VirtualPropertyAnnotationInAccesor.get", Tool.Analyzer | Tool.NativeAot, "")] + [ExpectedWarning ("IL3051", "DerivedClassWithRequires.VirtualPropertyAnnotationInAccesor.get", "BaseClassWithoutRequires.VirtualPropertyAnnotationInAccesor.get", Tool.Analyzer | Tool.NativeAot, "")] [RequiresUnreferencedCode ("Message")] [RequiresAssemblyFiles ("Message")] [RequiresDynamicCode ("Message")] @@ -194,9 +194,9 @@ public override string VirtualPropertyAnnotationInAccesor { [RequiresAssemblyFiles ("Message")] public override string VirtualPropertyAnnotationInProperty { - [ExpectedWarning ("IL3003", "DerivedClassWithRequires.VirtualPropertyAnnotationInProperty", "BaseClassWithoutRequires.VirtualPropertyAnnotationInProperty", ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3003", "DerivedClassWithRequires.VirtualPropertyAnnotationInProperty", "BaseClassWithoutRequires.VirtualPropertyAnnotationInProperty", Tool.Analyzer | Tool.NativeAot, "")] get; - [ExpectedWarning ("IL3003", "DerivedClassWithRequires.VirtualPropertyAnnotationInProperty", "BaseClassWithoutRequires.VirtualPropertyAnnotationInProperty", ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3003", "DerivedClassWithRequires.VirtualPropertyAnnotationInProperty", "BaseClassWithoutRequires.VirtualPropertyAnnotationInProperty", Tool.Analyzer | Tool.NativeAot, "")] set; } } @@ -237,8 +237,8 @@ public static void Test() class DerivedClassWithoutRequires : BaseClassWithRequires { [ExpectedWarning ("IL2046", "DerivedClassWithoutRequires.VirtualMethod()", "BaseClassWithRequires.VirtualMethod()")] - [ExpectedWarning ("IL3003", "DerivedClassWithoutRequires.VirtualMethod()", "BaseClassWithRequires.VirtualMethod()", ProducedBy = Tool.Analyzer | Tool.NativeAot)] - [ExpectedWarning ("IL3051", "DerivedClassWithoutRequires.VirtualMethod()", "BaseClassWithRequires.VirtualMethod()", ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3003", "DerivedClassWithoutRequires.VirtualMethod()", "BaseClassWithRequires.VirtualMethod()", Tool.Analyzer | Tool.NativeAot, "")] + [ExpectedWarning ("IL3051", "DerivedClassWithoutRequires.VirtualMethod()", "BaseClassWithRequires.VirtualMethod()", Tool.Analyzer | Tool.NativeAot, "")] public override void VirtualMethod () { } @@ -246,24 +246,24 @@ public override void VirtualMethod () private string name; public override string VirtualPropertyAnnotationInAccesor { [ExpectedWarning ("IL2046", "DerivedClassWithoutRequires.VirtualPropertyAnnotationInAccesor.get", "BaseClassWithRequires.VirtualPropertyAnnotationInAccesor.get")] - [ExpectedWarning ("IL3003", "DerivedClassWithoutRequires.VirtualPropertyAnnotationInAccesor.get", "BaseClassWithRequires.VirtualPropertyAnnotationInAccesor.get", ProducedBy = Tool.Analyzer | Tool.NativeAot)] - [ExpectedWarning ("IL3051", "DerivedClassWithoutRequires.VirtualPropertyAnnotationInAccesor.get", "BaseClassWithRequires.VirtualPropertyAnnotationInAccesor.get", ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3003", "DerivedClassWithoutRequires.VirtualPropertyAnnotationInAccesor.get", "BaseClassWithRequires.VirtualPropertyAnnotationInAccesor.get", Tool.Analyzer | Tool.NativeAot, "")] + [ExpectedWarning ("IL3051", "DerivedClassWithoutRequires.VirtualPropertyAnnotationInAccesor.get", "BaseClassWithRequires.VirtualPropertyAnnotationInAccesor.get", Tool.Analyzer | Tool.NativeAot, "")] get { return name; } set { name = value; } } public override string VirtualPropertyAnnotationInProperty { - [ExpectedWarning ("IL3003", "DerivedClassWithoutRequires.VirtualPropertyAnnotationInProperty", "BaseClassWithRequires.VirtualPropertyAnnotationInProperty", ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3003", "DerivedClassWithoutRequires.VirtualPropertyAnnotationInProperty", "BaseClassWithRequires.VirtualPropertyAnnotationInProperty", Tool.Analyzer | Tool.NativeAot, "")] get; - [ExpectedWarning ("IL3003", "DerivedClassWithoutRequires.VirtualPropertyAnnotationInProperty", "BaseClassWithRequires.VirtualPropertyAnnotationInProperty", ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3003", "DerivedClassWithoutRequires.VirtualPropertyAnnotationInProperty", "BaseClassWithRequires.VirtualPropertyAnnotationInProperty", Tool.Analyzer | Tool.NativeAot, "")] set; } public override string VirtualPropertyAnnotationInPropertyAndAccessor { [ExpectedWarning ("IL2046", "VirtualPropertyAnnotationInPropertyAndAccessor.get", "BaseClassWithRequires.VirtualPropertyAnnotationInPropertyAndAccessor.get")] - [ExpectedWarning ("IL3003", "DerivedClassWithoutRequires.VirtualPropertyAnnotationInPropertyAndAccessor.get", "BaseClassWithRequires.VirtualPropertyAnnotationInPropertyAndAccessor.get", ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3003", "DerivedClassWithoutRequires.VirtualPropertyAnnotationInPropertyAndAccessor.get", "BaseClassWithRequires.VirtualPropertyAnnotationInPropertyAndAccessor.get", Tool.Analyzer | Tool.NativeAot, "")] get; - [ExpectedWarning ("IL3003", "DerivedClassWithoutRequires.VirtualPropertyAnnotationInPropertyAndAccessor", "BaseClassWithRequires.VirtualPropertyAnnotationInPropertyAndAccessor", ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3003", "DerivedClassWithoutRequires.VirtualPropertyAnnotationInPropertyAndAccessor", "BaseClassWithRequires.VirtualPropertyAnnotationInPropertyAndAccessor", Tool.Analyzer | Tool.NativeAot, "")] set; } } @@ -271,8 +271,8 @@ public override string VirtualPropertyAnnotationInPropertyAndAccessor { class DerivedClassWithAllWarnings : BaseClassWithRequires { [ExpectedWarning ("IL2046", "DerivedClassWithAllWarnings.VirtualMethod()", "BaseClassWithRequires.VirtualMethod()")] - [ExpectedWarning ("IL3003", "DerivedClassWithAllWarnings.VirtualMethod()", "BaseClassWithRequires.VirtualMethod()", ProducedBy = Tool.Analyzer | Tool.NativeAot)] - [ExpectedWarning ("IL3051", "DerivedClassWithAllWarnings.VirtualMethod()", "BaseClassWithRequires.VirtualMethod()", ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3003", "DerivedClassWithAllWarnings.VirtualMethod()", "BaseClassWithRequires.VirtualMethod()", Tool.Analyzer | Tool.NativeAot, "")] + [ExpectedWarning ("IL3051", "DerivedClassWithAllWarnings.VirtualMethod()", "BaseClassWithRequires.VirtualMethod()", Tool.Analyzer | Tool.NativeAot, "")] public override void VirtualMethod () { } @@ -282,12 +282,12 @@ public override void VirtualMethod () [RequiresAssemblyFiles ("Message")] public override string VirtualPropertyAnnotationInAccesor { [ExpectedWarning ("IL2046", "DerivedClassWithAllWarnings.VirtualPropertyAnnotationInAccesor.get", "BaseClassWithRequires.VirtualPropertyAnnotationInAccesor.get")] - [ExpectedWarning ("IL3051", "DerivedClassWithAllWarnings.VirtualPropertyAnnotationInAccesor.get", "BaseClassWithRequires.VirtualPropertyAnnotationInAccesor.get", ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3051", "DerivedClassWithAllWarnings.VirtualPropertyAnnotationInAccesor.get", "BaseClassWithRequires.VirtualPropertyAnnotationInAccesor.get", Tool.Analyzer | Tool.NativeAot, "")] get { return name; } [RequiresAssemblyFiles ("Message")] [RequiresUnreferencedCode ("Message")] [ExpectedWarning ("IL2046", "VirtualPropertyAnnotationInAccesor.set", "BaseClassWithRequires.VirtualPropertyAnnotationInAccesor.set")] - [ExpectedWarning ("IL3003", "DerivedClassWithAllWarnings.VirtualPropertyAnnotationInAccesor.set", "BaseClassWithRequires.VirtualPropertyAnnotationInAccesor.set", ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3003", "DerivedClassWithAllWarnings.VirtualPropertyAnnotationInAccesor.set", "BaseClassWithRequires.VirtualPropertyAnnotationInAccesor.set", Tool.Analyzer | Tool.NativeAot, "")] set { name = value; } } @@ -304,7 +304,7 @@ public override string VirtualPropertyAnnotationInProperty { public override string VirtualPropertyAnnotationInPropertyAndAccessor { [ExpectedWarning ("IL2046", "VirtualPropertyAnnotationInPropertyAndAccessor.get", "BaseClassWithRequires.VirtualPropertyAnnotationInPropertyAndAccessor.get")] - [ExpectedWarning ("IL3003", "DerivedClassWithAllWarnings.VirtualPropertyAnnotationInPropertyAndAccessor.get", "BaseClassWithRequires.VirtualPropertyAnnotationInPropertyAndAccessor.get", ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3003", "DerivedClassWithAllWarnings.VirtualPropertyAnnotationInPropertyAndAccessor.get", "BaseClassWithRequires.VirtualPropertyAnnotationInPropertyAndAccessor.get", Tool.Analyzer | Tool.NativeAot, "")] get; [RequiresAssemblyFiles ("Message")] [RequiresUnreferencedCode ("Message")] @@ -357,8 +357,8 @@ class ImplementationClassWithRequires : IBaseWithoutRequires [RequiresAssemblyFiles ("Message")] [RequiresDynamicCode ("Message")] [ExpectedWarning ("IL2046", "ImplementationClassWithRequires.Method()", "IBaseWithoutRequires.Method()")] - [ExpectedWarning ("IL3003", "ImplementationClassWithRequires.Method()", "IBaseWithoutRequires.Method()", ProducedBy = Tool.Analyzer | Tool.NativeAot)] - [ExpectedWarning ("IL3051", "ImplementationClassWithRequires.Method()", "IBaseWithoutRequires.Method()", ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3003", "ImplementationClassWithRequires.Method()", "IBaseWithoutRequires.Method()", Tool.Analyzer | Tool.NativeAot, "")] + [ExpectedWarning ("IL3051", "ImplementationClassWithRequires.Method()", "IBaseWithoutRequires.Method()", Tool.Analyzer | Tool.NativeAot, "")] public void Method () { } @@ -366,8 +366,8 @@ public void Method () private string name; public string PropertyAnnotationInAccesor { [ExpectedWarning ("IL2046", "ImplementationClassWithRequires.PropertyAnnotationInAccesor.get", "IBaseWithoutRequires.PropertyAnnotationInAccesor.get")] - [ExpectedWarning ("IL3003", "ImplementationClassWithRequires.PropertyAnnotationInAccesor.get", "IBaseWithoutRequires.PropertyAnnotationInAccesor.get", ProducedBy = Tool.Analyzer | Tool.NativeAot)] - [ExpectedWarning ("IL3051", "ImplementationClassWithRequires.PropertyAnnotationInAccesor.get", "IBaseWithoutRequires.PropertyAnnotationInAccesor.get", ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3003", "ImplementationClassWithRequires.PropertyAnnotationInAccesor.get", "IBaseWithoutRequires.PropertyAnnotationInAccesor.get", Tool.Analyzer | Tool.NativeAot, "")] + [ExpectedWarning ("IL3051", "ImplementationClassWithRequires.PropertyAnnotationInAccesor.get", "IBaseWithoutRequires.PropertyAnnotationInAccesor.get", Tool.Analyzer | Tool.NativeAot, "")] [RequiresUnreferencedCode ("Message")] [RequiresAssemblyFiles ("Message")] [RequiresDynamicCode ("Message")] @@ -376,23 +376,23 @@ public string PropertyAnnotationInAccesor { } [RequiresAssemblyFiles ("Message")] - [ExpectedWarning ("IL3003", "ImplementationClassWithRequires.PropertyAnnotationInProperty", "IBaseWithoutRequires.PropertyAnnotationInProperty", ProducedBy = Tool.Analyzer)] + [ExpectedWarning ("IL3003", "ImplementationClassWithRequires.PropertyAnnotationInProperty", "IBaseWithoutRequires.PropertyAnnotationInProperty", Tool.Analyzer, "")] public string PropertyAnnotationInProperty { - [ExpectedWarning ("IL3003", "ImplementationClassWithRequires.PropertyAnnotationInProperty", "IBaseWithoutRequires.PropertyAnnotationInProperty", ProducedBy = Tool.NativeAot | Tool.Analyzer)] + [ExpectedWarning ("IL3003", "ImplementationClassWithRequires.PropertyAnnotationInProperty", "IBaseWithoutRequires.PropertyAnnotationInProperty", Tool.NativeAot | Tool.Analyzer, "")] get; - [ExpectedWarning ("IL3003", "ImplementationClassWithRequires.PropertyAnnotationInProperty", "IBaseWithoutRequires.PropertyAnnotationInProperty", ProducedBy = Tool.NativeAot | Tool.Analyzer)] + [ExpectedWarning ("IL3003", "ImplementationClassWithRequires.PropertyAnnotationInProperty", "IBaseWithoutRequires.PropertyAnnotationInProperty", Tool.NativeAot | Tool.Analyzer, "")] set; } [RequiresAssemblyFiles ("Message")] - [ExpectedWarning ("IL3003", "ImplementationClassWithRequires.PropertyAnnotationInPropertyAndAccessor", "IBaseWithoutRequires.PropertyAnnotationInPropertyAndAccessor", ProducedBy = Tool.Analyzer)] + [ExpectedWarning ("IL3003", "ImplementationClassWithRequires.PropertyAnnotationInPropertyAndAccessor", "IBaseWithoutRequires.PropertyAnnotationInPropertyAndAccessor", Tool.Analyzer, "")] public string PropertyAnnotationInPropertyAndAccessor { [RequiresAssemblyFiles ("Message")] [RequiresUnreferencedCode ("Message")] [ExpectedWarning ("IL2046", "ImplementationClassWithRequires.PropertyAnnotationInPropertyAndAccessor.get", "IBaseWithoutRequires.PropertyAnnotationInPropertyAndAccessor.get")] - [ExpectedWarning ("IL3003", "ImplementationClassWithRequires.PropertyAnnotationInPropertyAndAccessor.get", "IBaseWithoutRequires.PropertyAnnotationInPropertyAndAccessor.get", ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3003", "ImplementationClassWithRequires.PropertyAnnotationInPropertyAndAccessor.get", "IBaseWithoutRequires.PropertyAnnotationInPropertyAndAccessor.get", Tool.Analyzer | Tool.NativeAot, "")] get; - [ExpectedWarning ("IL3003", "ImplementationClassWithRequires.PropertyAnnotationInPropertyAndAccessor", "IBaseWithoutRequires.PropertyAnnotationInPropertyAndAccessor", ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3003", "ImplementationClassWithRequires.PropertyAnnotationInPropertyAndAccessor", "IBaseWithoutRequires.PropertyAnnotationInPropertyAndAccessor", Tool.Analyzer | Tool.NativeAot, "")] set; } } @@ -403,12 +403,12 @@ class ExplicitImplementationClassWithRequires : IBaseWithoutRequires [RequiresAssemblyFiles ("Message")] [RequiresDynamicCode ("Message")] // ILLink member string format includes namespace of explicit interface method. - [ExpectedWarning ("IL2046", "ExplicitImplementationClassWithRequires.Mono.Linker.Tests.Cases.RequiresCapability.RequiresAttributeMismatch.IBaseWithoutRequires.Method()", "IBaseWithoutRequires.Method()", ProducedBy = Tool.Trimmer | Tool.NativeAot)] - [ExpectedWarning ("IL3003", "ExplicitImplementationClassWithRequires.Mono.Linker.Tests.Cases.RequiresCapability.RequiresAttributeMismatch.IBaseWithoutRequires.Method()", "IBaseWithoutRequires.Method()", ProducedBy = Tool.NativeAot)] - [ExpectedWarning ("IL3051", "ExplicitImplementationClassWithRequires.Mono.Linker.Tests.Cases.RequiresCapability.RequiresAttributeMismatch.IBaseWithoutRequires.Method()", "IBaseWithoutRequires.Method()", ProducedBy = Tool.NativeAot)] - [ExpectedWarning ("IL2046", "ExplicitImplementationClassWithRequires.IBaseWithoutRequires.Method()", "IBaseWithoutRequires.Method()", ProducedBy = Tool.Analyzer)] - [ExpectedWarning ("IL3003", "ExplicitImplementationClassWithRequires.IBaseWithoutRequires.Method()", "IBaseWithoutRequires.Method()", ProducedBy = Tool.Analyzer)] - [ExpectedWarning ("IL3051", "IBaseWithoutRequires.Method()", "ExplicitImplementationClassWithRequires.IBaseWithoutRequires.Method()", ProducedBy = Tool.Analyzer)] + [ExpectedWarning ("IL2046", "ExplicitImplementationClassWithRequires.Mono.Linker.Tests.Cases.RequiresCapability.RequiresAttributeMismatch.IBaseWithoutRequires.Method()", "IBaseWithoutRequires.Method()", Tool.Trimmer | Tool.NativeAot, "")] + [ExpectedWarning ("IL3003", "ExplicitImplementationClassWithRequires.Mono.Linker.Tests.Cases.RequiresCapability.RequiresAttributeMismatch.IBaseWithoutRequires.Method()", "IBaseWithoutRequires.Method()", Tool.NativeAot, "")] + [ExpectedWarning ("IL3051", "ExplicitImplementationClassWithRequires.Mono.Linker.Tests.Cases.RequiresCapability.RequiresAttributeMismatch.IBaseWithoutRequires.Method()", "IBaseWithoutRequires.Method()", Tool.NativeAot, "")] + [ExpectedWarning ("IL2046", "ExplicitImplementationClassWithRequires.IBaseWithoutRequires.Method()", "IBaseWithoutRequires.Method()", Tool.Analyzer, "")] + [ExpectedWarning ("IL3003", "ExplicitImplementationClassWithRequires.IBaseWithoutRequires.Method()", "IBaseWithoutRequires.Method()", Tool.Analyzer, "")] + [ExpectedWarning ("IL3051", "IBaseWithoutRequires.Method()", "ExplicitImplementationClassWithRequires.IBaseWithoutRequires.Method()", Tool.Analyzer, "")] void IBaseWithoutRequires.Method () { } @@ -416,8 +416,8 @@ void IBaseWithoutRequires.Method () private string name; string IBaseWithoutRequires.PropertyAnnotationInAccesor { [ExpectedWarning ("IL2046", "PropertyAnnotationInAccesor.get", "IBaseWithoutRequires.PropertyAnnotationInAccesor.get")] - [ExpectedWarning ("IL3003", "PropertyAnnotationInAccesor.get", "IBaseWithoutRequires.PropertyAnnotationInAccesor.get", ProducedBy = Tool.Analyzer | Tool.NativeAot)] - [ExpectedWarning ("IL3051", "PropertyAnnotationInAccesor.get", "IBaseWithoutRequires.PropertyAnnotationInAccesor.get", ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3003", "PropertyAnnotationInAccesor.get", "IBaseWithoutRequires.PropertyAnnotationInAccesor.get", Tool.Analyzer | Tool.NativeAot, "")] + [ExpectedWarning ("IL3051", "PropertyAnnotationInAccesor.get", "IBaseWithoutRequires.PropertyAnnotationInAccesor.get", Tool.Analyzer | Tool.NativeAot, "")] [RequiresUnreferencedCode ("Message")] [RequiresAssemblyFiles ("Message")] [RequiresDynamicCode ("Message")] @@ -426,23 +426,23 @@ string IBaseWithoutRequires.PropertyAnnotationInAccesor { } [RequiresAssemblyFiles ("Message")] - [ExpectedWarning ("IL3003", "ExplicitImplementationClassWithRequires.Mono.Linker.Tests.Cases.RequiresCapability.RequiresAttributeMismatch.IBaseWithoutRequires.PropertyAnnotationInProperty", "IBaseWithoutRequires.PropertyAnnotationInProperty", ProducedBy = Tool.Analyzer)] + [ExpectedWarning ("IL3003", "ExplicitImplementationClassWithRequires.Mono.Linker.Tests.Cases.RequiresCapability.RequiresAttributeMismatch.IBaseWithoutRequires.PropertyAnnotationInProperty", "IBaseWithoutRequires.PropertyAnnotationInProperty", Tool.Analyzer, "")] string IBaseWithoutRequires.PropertyAnnotationInProperty { - [ExpectedWarning ("IL3003", "Mono.Linker.Tests.Cases.RequiresCapability.RequiresAttributeMismatch.IBaseWithoutRequires.PropertyAnnotationInProperty", "IBaseWithoutRequires.PropertyAnnotationInProperty", ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3003", "Mono.Linker.Tests.Cases.RequiresCapability.RequiresAttributeMismatch.IBaseWithoutRequires.PropertyAnnotationInProperty", "IBaseWithoutRequires.PropertyAnnotationInProperty", Tool.Analyzer | Tool.NativeAot, "")] get; - [ExpectedWarning ("IL3003", "Mono.Linker.Tests.Cases.RequiresCapability.RequiresAttributeMismatch.IBaseWithoutRequires.PropertyAnnotationInProperty", "IBaseWithoutRequires.PropertyAnnotationInProperty", ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3003", "Mono.Linker.Tests.Cases.RequiresCapability.RequiresAttributeMismatch.IBaseWithoutRequires.PropertyAnnotationInProperty", "IBaseWithoutRequires.PropertyAnnotationInProperty", Tool.Analyzer | Tool.NativeAot, "")] set; } [RequiresAssemblyFiles ("Message")] - [ExpectedWarning ("IL3003", "PropertyAnnotationInPropertyAndAccessor", "IBaseWithoutRequires.PropertyAnnotationInPropertyAndAccessor", ProducedBy = Tool.Analyzer)] + [ExpectedWarning ("IL3003", "PropertyAnnotationInPropertyAndAccessor", "IBaseWithoutRequires.PropertyAnnotationInPropertyAndAccessor", Tool.Analyzer, "")] string IBaseWithoutRequires.PropertyAnnotationInPropertyAndAccessor { [RequiresAssemblyFiles ("Message")] [RequiresUnreferencedCode ("Message")] [ExpectedWarning ("IL2046", "PropertyAnnotationInPropertyAndAccessor.get", "IBaseWithoutRequires.PropertyAnnotationInPropertyAndAccessor.get")] - [ExpectedWarning ("IL3003", "PropertyAnnotationInPropertyAndAccessor.get", "IBaseWithoutRequires.PropertyAnnotationInPropertyAndAccessor.get", ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3003", "PropertyAnnotationInPropertyAndAccessor.get", "IBaseWithoutRequires.PropertyAnnotationInPropertyAndAccessor.get", Tool.Analyzer | Tool.NativeAot, "")] get; - [ExpectedWarning ("IL3003", "PropertyAnnotationInPropertyAndAccessor", "IBaseWithoutRequires.PropertyAnnotationInPropertyAndAccessor", ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3003", "PropertyAnnotationInPropertyAndAccessor", "IBaseWithoutRequires.PropertyAnnotationInPropertyAndAccessor", Tool.Analyzer | Tool.NativeAot, "")] set; } } @@ -450,8 +450,8 @@ string IBaseWithoutRequires.PropertyAnnotationInPropertyAndAccessor { class ImplementationClassWithoutRequires : IBaseWithRequires { [ExpectedWarning ("IL2046", "ImplementationClassWithoutRequires.Method()", "IBaseWithRequires.Method()")] - [ExpectedWarning ("IL3003", "ImplementationClassWithoutRequires.Method()", "IBaseWithRequires.Method()", ProducedBy = Tool.Analyzer | Tool.NativeAot)] - [ExpectedWarning ("IL3051", "ImplementationClassWithoutRequires.Method()", "IBaseWithRequires.Method()", ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3003", "ImplementationClassWithoutRequires.Method()", "IBaseWithRequires.Method()", Tool.Analyzer | Tool.NativeAot, "")] + [ExpectedWarning ("IL3051", "ImplementationClassWithoutRequires.Method()", "IBaseWithRequires.Method()", Tool.Analyzer | Tool.NativeAot, "")] public void Method () { } @@ -459,28 +459,28 @@ public void Method () private string name; public string PropertyAnnotationInAccesor { [ExpectedWarning ("IL2046", "ImplementationClassWithoutRequires.PropertyAnnotationInAccesor.get", "IBaseWithRequires.PropertyAnnotationInAccesor.get")] - [ExpectedWarning ("IL3003", "ImplementationClassWithoutRequires.PropertyAnnotationInAccesor.get", "IBaseWithRequires.PropertyAnnotationInAccesor.get", ProducedBy = Tool.Analyzer | Tool.NativeAot)] - [ExpectedWarning ("IL3051", "ImplementationClassWithoutRequires.PropertyAnnotationInAccesor.get", "IBaseWithRequires.PropertyAnnotationInAccesor.get", ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3003", "ImplementationClassWithoutRequires.PropertyAnnotationInAccesor.get", "IBaseWithRequires.PropertyAnnotationInAccesor.get", Tool.Analyzer | Tool.NativeAot, "")] + [ExpectedWarning ("IL3051", "ImplementationClassWithoutRequires.PropertyAnnotationInAccesor.get", "IBaseWithRequires.PropertyAnnotationInAccesor.get", Tool.Analyzer | Tool.NativeAot, "")] get { return name; } set { name = value; } } - [ExpectedWarning ("IL3003", "ImplementationClassWithoutRequires.PropertyAnnotationInProperty", "IBaseWithRequires.PropertyAnnotationInProperty", ProducedBy = Tool.Analyzer)] + [ExpectedWarning ("IL3003", "ImplementationClassWithoutRequires.PropertyAnnotationInProperty", "IBaseWithRequires.PropertyAnnotationInProperty", Tool.Analyzer, "")] public string PropertyAnnotationInProperty { - [ExpectedWarning ("IL3003", "ImplementationClassWithoutRequires.PropertyAnnotationInProperty", "IBaseWithRequires.PropertyAnnotationInProperty", ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3003", "ImplementationClassWithoutRequires.PropertyAnnotationInProperty", "IBaseWithRequires.PropertyAnnotationInProperty", Tool.Analyzer | Tool.NativeAot, "")] get; - [ExpectedWarning ("IL3003", "ImplementationClassWithoutRequires.PropertyAnnotationInProperty", "IBaseWithRequires.PropertyAnnotationInProperty", ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3003", "ImplementationClassWithoutRequires.PropertyAnnotationInProperty", "IBaseWithRequires.PropertyAnnotationInProperty", Tool.Analyzer | Tool.NativeAot, "")] set; } - [ExpectedWarning ("IL3003", "ImplementationClassWithoutRequires.PropertyAnnotationInPropertyAndAccessor", "IBaseWithRequires.PropertyAnnotationInPropertyAndAccessor", ProducedBy = Tool.Analyzer)] + [ExpectedWarning ("IL3003", "ImplementationClassWithoutRequires.PropertyAnnotationInPropertyAndAccessor", "IBaseWithRequires.PropertyAnnotationInPropertyAndAccessor", Tool.Analyzer, "")] public string PropertyAnnotationInPropertyAndAccessor { [RequiresAssemblyFiles ("Message")] [RequiresUnreferencedCode ("Message")] [ExpectedWarning ("IL2046", "ImplementationClassWithoutRequires.PropertyAnnotationInPropertyAndAccessor.get", "IBaseWithRequires.PropertyAnnotationInPropertyAndAccessor.get")] get; [ExpectedWarning ("IL2046", "ImplementationClassWithoutRequires.PropertyAnnotationInPropertyAndAccessor.set", "IBaseWithRequires.PropertyAnnotationInPropertyAndAccessor.set")] - [ExpectedWarning ("IL3003", "ImplementationClassWithoutRequires.PropertyAnnotationInPropertyAndAccessor.set", "IBaseWithRequires.PropertyAnnotationInPropertyAndAccessor.set", ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3003", "ImplementationClassWithoutRequires.PropertyAnnotationInPropertyAndAccessor.set", "IBaseWithRequires.PropertyAnnotationInPropertyAndAccessor.set", Tool.Analyzer | Tool.NativeAot, "")] set; } } @@ -488,12 +488,12 @@ public string PropertyAnnotationInPropertyAndAccessor { class ExplicitImplementationClassWithoutRequires : IBaseWithRequires { // ILLink member string format includes namespace of explicit interface method. - [ExpectedWarning ("IL2046", "IBaseWithRequires.Method()", "ExplicitImplementationClassWithoutRequires.Mono.Linker.Tests.Cases.RequiresCapability.RequiresAttributeMismatch.IBaseWithRequires.Method()", ProducedBy = Tool.Trimmer | Tool.NativeAot)] - [ExpectedWarning ("IL3003", "IBaseWithRequires.Method()", "ExplicitImplementationClassWithoutRequires.Mono.Linker.Tests.Cases.RequiresCapability.RequiresAttributeMismatch.IBaseWithRequires.Method()", ProducedBy = Tool.NativeAot)] - [ExpectedWarning ("IL3051", "IBaseWithRequires.Method()", "ExplicitImplementationClassWithoutRequires.Mono.Linker.Tests.Cases.RequiresCapability.RequiresAttributeMismatch.IBaseWithRequires.Method()", ProducedBy = Tool.NativeAot)] - [ExpectedWarning ("IL2046", "IBaseWithRequires.Method()", "ExplicitImplementationClassWithoutRequires.IBaseWithRequires.Method()", ProducedBy = Tool.Analyzer)] - [ExpectedWarning ("IL3003", "IBaseWithRequires.Method()", "ExplicitImplementationClassWithoutRequires.IBaseWithRequires.Method()", ProducedBy = Tool.Analyzer)] - [ExpectedWarning ("IL3051", "IBaseWithRequires.Method()", "ExplicitImplementationClassWithoutRequires.IBaseWithRequires.Method()", ProducedBy = Tool.Analyzer)] + [ExpectedWarning ("IL2046", "IBaseWithRequires.Method()", "ExplicitImplementationClassWithoutRequires.Mono.Linker.Tests.Cases.RequiresCapability.RequiresAttributeMismatch.IBaseWithRequires.Method()", Tool.Trimmer | Tool.NativeAot, "")] + [ExpectedWarning ("IL3003", "IBaseWithRequires.Method()", "ExplicitImplementationClassWithoutRequires.Mono.Linker.Tests.Cases.RequiresCapability.RequiresAttributeMismatch.IBaseWithRequires.Method()", Tool.NativeAot, "")] + [ExpectedWarning ("IL3051", "IBaseWithRequires.Method()", "ExplicitImplementationClassWithoutRequires.Mono.Linker.Tests.Cases.RequiresCapability.RequiresAttributeMismatch.IBaseWithRequires.Method()", Tool.NativeAot, "")] + [ExpectedWarning ("IL2046", "IBaseWithRequires.Method()", "ExplicitImplementationClassWithoutRequires.IBaseWithRequires.Method()", Tool.Analyzer, "")] + [ExpectedWarning ("IL3003", "IBaseWithRequires.Method()", "ExplicitImplementationClassWithoutRequires.IBaseWithRequires.Method()", Tool.Analyzer, "")] + [ExpectedWarning ("IL3051", "IBaseWithRequires.Method()", "ExplicitImplementationClassWithoutRequires.IBaseWithRequires.Method()", Tool.Analyzer, "")] void IBaseWithRequires.Method () { } @@ -501,26 +501,26 @@ void IBaseWithRequires.Method () private string name; string IBaseWithRequires.PropertyAnnotationInAccesor { [ExpectedWarning ("IL2046", "PropertyAnnotationInAccesor.get", "IBaseWithRequires.PropertyAnnotationInAccesor.get")] - [ExpectedWarning ("IL3003", "PropertyAnnotationInAccesor.get", "IBaseWithRequires.PropertyAnnotationInAccesor.get", ProducedBy = Tool.Analyzer | Tool.NativeAot)] - [ExpectedWarning ("IL3051", "PropertyAnnotationInAccesor.get", "IBaseWithRequires.PropertyAnnotationInAccesor.get", ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3003", "PropertyAnnotationInAccesor.get", "IBaseWithRequires.PropertyAnnotationInAccesor.get", Tool.Analyzer | Tool.NativeAot, "")] + [ExpectedWarning ("IL3051", "PropertyAnnotationInAccesor.get", "IBaseWithRequires.PropertyAnnotationInAccesor.get", Tool.Analyzer | Tool.NativeAot, "")] get { return name; } set { name = value; } } - [ExpectedWarning ("IL3003", "ExplicitImplementationClassWithoutRequires.Mono.Linker.Tests.Cases.RequiresCapability.RequiresAttributeMismatch.IBaseWithRequires.PropertyAnnotationInProperty", "IBaseWithRequires.PropertyAnnotationInProperty", ProducedBy = Tool.Analyzer)] + [ExpectedWarning ("IL3003", "ExplicitImplementationClassWithoutRequires.Mono.Linker.Tests.Cases.RequiresCapability.RequiresAttributeMismatch.IBaseWithRequires.PropertyAnnotationInProperty", "IBaseWithRequires.PropertyAnnotationInProperty", Tool.Analyzer, "")] string IBaseWithRequires.PropertyAnnotationInProperty { - [ExpectedWarning ("IL3003", "Mono.Linker.Tests.Cases.RequiresCapability.RequiresAttributeMismatch.IBaseWithRequires.PropertyAnnotationInProperty", "IBaseWithRequires.PropertyAnnotationInProperty", ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3003", "Mono.Linker.Tests.Cases.RequiresCapability.RequiresAttributeMismatch.IBaseWithRequires.PropertyAnnotationInProperty", "IBaseWithRequires.PropertyAnnotationInProperty", Tool.Analyzer | Tool.NativeAot, "")] get; - [ExpectedWarning ("IL3003", "Mono.Linker.Tests.Cases.RequiresCapability.RequiresAttributeMismatch.IBaseWithRequires.PropertyAnnotationInProperty", "IBaseWithRequires.PropertyAnnotationInProperty", ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3003", "Mono.Linker.Tests.Cases.RequiresCapability.RequiresAttributeMismatch.IBaseWithRequires.PropertyAnnotationInProperty", "IBaseWithRequires.PropertyAnnotationInProperty", Tool.Analyzer | Tool.NativeAot, "")] set; } - [ExpectedWarning ("IL3003", "ExplicitImplementationClassWithoutRequires.Mono.Linker.Tests.Cases.RequiresCapability.RequiresAttributeMismatch.IBaseWithRequires.PropertyAnnotationInPropertyAndAccessor", "IBaseWithRequires.PropertyAnnotationInPropertyAndAccessor", ProducedBy = Tool.Analyzer)] + [ExpectedWarning ("IL3003", "ExplicitImplementationClassWithoutRequires.Mono.Linker.Tests.Cases.RequiresCapability.RequiresAttributeMismatch.IBaseWithRequires.PropertyAnnotationInPropertyAndAccessor", "IBaseWithRequires.PropertyAnnotationInPropertyAndAccessor", Tool.Analyzer, "")] string IBaseWithRequires.PropertyAnnotationInPropertyAndAccessor { - [ExpectedWarning ("IL3003", "Mono.Linker.Tests.Cases.RequiresCapability.RequiresAttributeMismatch.IBaseWithRequires.PropertyAnnotationInPropertyAndAccessor", "IBaseWithRequires.PropertyAnnotationInPropertyAndAccessor", ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3003", "Mono.Linker.Tests.Cases.RequiresCapability.RequiresAttributeMismatch.IBaseWithRequires.PropertyAnnotationInPropertyAndAccessor", "IBaseWithRequires.PropertyAnnotationInPropertyAndAccessor", Tool.Analyzer | Tool.NativeAot, "")] get; [ExpectedWarning ("IL2046", "PropertyAnnotationInPropertyAndAccessor.set", "IBaseWithRequires.PropertyAnnotationInPropertyAndAccessor.set")] - [ExpectedWarning ("IL3003", "PropertyAnnotationInPropertyAndAccessor.set", "IBaseWithRequires.PropertyAnnotationInPropertyAndAccessor.set", ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3003", "PropertyAnnotationInPropertyAndAccessor.set", "IBaseWithRequires.PropertyAnnotationInPropertyAndAccessor.set", Tool.Analyzer | Tool.NativeAot, "")] set; } } @@ -528,8 +528,8 @@ string IBaseWithRequires.PropertyAnnotationInPropertyAndAccessor { class ImplementationClassWithoutRequiresInSource : ReferenceInterfaces.IBaseWithRequiresInReference { [ExpectedWarning ("IL2046", "ImplementationClassWithoutRequiresInSource.Method()", "IBaseWithRequiresInReference.Method()")] - [ExpectedWarning ("IL3003", "ImplementationClassWithoutRequiresInSource.Method()", "IBaseWithRequiresInReference.Method()", ProducedBy = Tool.Analyzer | Tool.NativeAot)] - [ExpectedWarning ("IL3051", "ImplementationClassWithoutRequiresInSource.Method()", "IBaseWithRequiresInReference.Method()", ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3003", "ImplementationClassWithoutRequiresInSource.Method()", "IBaseWithRequiresInReference.Method()", Tool.Analyzer | Tool.NativeAot, "")] + [ExpectedWarning ("IL3051", "ImplementationClassWithoutRequiresInSource.Method()", "IBaseWithRequiresInReference.Method()", Tool.Analyzer | Tool.NativeAot, "")] public void Method () { } @@ -537,17 +537,17 @@ public void Method () private string name; public string PropertyAnnotationInAccesor { [ExpectedWarning ("IL2046", "ImplementationClassWithoutRequiresInSource.PropertyAnnotationInAccesor.get", "IBaseWithRequiresInReference.PropertyAnnotationInAccesor.get")] - [ExpectedWarning ("IL3003", "ImplementationClassWithoutRequiresInSource.PropertyAnnotationInAccesor.get", "IBaseWithRequiresInReference.PropertyAnnotationInAccesor.get", ProducedBy = Tool.Analyzer | Tool.NativeAot)] - [ExpectedWarning ("IL3051", "ImplementationClassWithoutRequiresInSource.PropertyAnnotationInAccesor.get", "IBaseWithRequiresInReference.PropertyAnnotationInAccesor.get", ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3003", "ImplementationClassWithoutRequiresInSource.PropertyAnnotationInAccesor.get", "IBaseWithRequiresInReference.PropertyAnnotationInAccesor.get", Tool.Analyzer | Tool.NativeAot, "")] + [ExpectedWarning ("IL3051", "ImplementationClassWithoutRequiresInSource.PropertyAnnotationInAccesor.get", "IBaseWithRequiresInReference.PropertyAnnotationInAccesor.get", Tool.Analyzer | Tool.NativeAot, "")] get { return name; } set { name = value; } } - [ExpectedWarning ("IL3003", "ImplementationClassWithoutRequiresInSource.PropertyAnnotationInProperty", "IBaseWithRequiresInReference.PropertyAnnotationInProperty", ProducedBy = Tool.Analyzer)] + [ExpectedWarning ("IL3003", "ImplementationClassWithoutRequiresInSource.PropertyAnnotationInProperty", "IBaseWithRequiresInReference.PropertyAnnotationInProperty", Tool.Analyzer, "")] public string PropertyAnnotationInProperty { - [ExpectedWarning ("IL3003", "ImplementationClassWithoutRequiresInSource.PropertyAnnotationInProperty.get", "IBaseWithRequiresInReference.PropertyAnnotationInProperty.get", ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3003", "ImplementationClassWithoutRequiresInSource.PropertyAnnotationInProperty.get", "IBaseWithRequiresInReference.PropertyAnnotationInProperty.get", Tool.Analyzer | Tool.NativeAot, "")] get; - [ExpectedWarning ("IL3003", "ImplementationClassWithoutRequiresInSource.PropertyAnnotationInProperty.set", "IBaseWithRequiresInReference.PropertyAnnotationInProperty.set", ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3003", "ImplementationClassWithoutRequiresInSource.PropertyAnnotationInProperty.set", "IBaseWithRequiresInReference.PropertyAnnotationInProperty.set", Tool.Analyzer | Tool.NativeAot, "")] set; } } @@ -555,8 +555,8 @@ public string PropertyAnnotationInProperty { class ImplementationClassWithRequiresInSource : ReferenceInterfaces.IBaseWithoutRequiresInReference { [ExpectedWarning ("IL2046", "ImplementationClassWithRequiresInSource.Method()", "IBaseWithoutRequiresInReference.Method()")] - [ExpectedWarning ("IL3003", "ImplementationClassWithRequiresInSource.Method()", "IBaseWithoutRequiresInReference.Method()", ProducedBy = Tool.Analyzer | Tool.NativeAot)] - [ExpectedWarning ("IL3051", "ImplementationClassWithRequiresInSource.Method()", "IBaseWithoutRequiresInReference.Method()", ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3003", "ImplementationClassWithRequiresInSource.Method()", "IBaseWithoutRequiresInReference.Method()", Tool.Analyzer | Tool.NativeAot, "")] + [ExpectedWarning ("IL3051", "ImplementationClassWithRequiresInSource.Method()", "IBaseWithoutRequiresInReference.Method()", Tool.Analyzer | Tool.NativeAot, "")] [RequiresUnreferencedCode ("Message")] [RequiresAssemblyFiles ("Message")] [RequiresDynamicCode ("Message")] @@ -567,8 +567,8 @@ public void Method () private string name; public string PropertyAnnotationInAccesor { [ExpectedWarning ("IL2046", "ImplementationClassWithRequiresInSource.PropertyAnnotationInAccesor.get", "IBaseWithoutRequiresInReference.PropertyAnnotationInAccesor.get")] - [ExpectedWarning ("IL3003", "ImplementationClassWithRequiresInSource.PropertyAnnotationInAccesor.get", "IBaseWithoutRequiresInReference.PropertyAnnotationInAccesor.get", ProducedBy = Tool.Analyzer | Tool.NativeAot)] - [ExpectedWarning ("IL3051", "ImplementationClassWithRequiresInSource.PropertyAnnotationInAccesor.get", "IBaseWithoutRequiresInReference.PropertyAnnotationInAccesor.get", ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3003", "ImplementationClassWithRequiresInSource.PropertyAnnotationInAccesor.get", "IBaseWithoutRequiresInReference.PropertyAnnotationInAccesor.get", Tool.Analyzer | Tool.NativeAot, "")] + [ExpectedWarning ("IL3051", "ImplementationClassWithRequiresInSource.PropertyAnnotationInAccesor.get", "IBaseWithoutRequiresInReference.PropertyAnnotationInAccesor.get", Tool.Analyzer | Tool.NativeAot, "")] [RequiresUnreferencedCode ("Message")] [RequiresAssemblyFiles ("Message")] [RequiresDynamicCode ("Message")] @@ -576,12 +576,12 @@ public string PropertyAnnotationInAccesor { set { name = value; } } - [ExpectedWarning ("IL3003", "ImplementationClassWithRequiresInSource.PropertyAnnotationInProperty", "IBaseWithoutRequiresInReference.PropertyAnnotationInProperty", ProducedBy = Tool.Analyzer)] + [ExpectedWarning ("IL3003", "ImplementationClassWithRequiresInSource.PropertyAnnotationInProperty", "IBaseWithoutRequiresInReference.PropertyAnnotationInProperty", Tool.Analyzer, "")] [RequiresAssemblyFiles ("Message")] public string PropertyAnnotationInProperty { - [ExpectedWarning ("IL3003", "ImplementationClassWithRequiresInSource.PropertyAnnotationInProperty", "IBaseWithoutRequiresInReference.PropertyAnnotationInProperty", ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3003", "ImplementationClassWithRequiresInSource.PropertyAnnotationInProperty", "IBaseWithoutRequiresInReference.PropertyAnnotationInProperty", Tool.Analyzer | Tool.NativeAot, "")] get; - [ExpectedWarning ("IL3003", "ImplementationClassWithRequiresInSource.PropertyAnnotationInProperty", "IBaseWithoutRequiresInReference.PropertyAnnotationInProperty", ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3003", "ImplementationClassWithRequiresInSource.PropertyAnnotationInProperty", "IBaseWithoutRequiresInReference.PropertyAnnotationInProperty", Tool.Analyzer | Tool.NativeAot, "")] set; } } @@ -589,23 +589,23 @@ public string PropertyAnnotationInProperty { class StaticInterfaceMethods { [ExpectedWarning ("IL2026")] - [ExpectedWarning ("IL3002", ProducedBy = Tool.NativeAot)] - [ExpectedWarning ("IL3050", ProducedBy = Tool.NativeAot)] + [ExpectedWarning ("IL3002", Tool.NativeAot, "")] + [ExpectedWarning ("IL3050", Tool.NativeAot, "")] [ExpectedWarning ("IL2026")] - [ExpectedWarning ("IL3002", ProducedBy = Tool.NativeAot)] - [ExpectedWarning ("IL3050", ProducedBy = Tool.NativeAot)] + [ExpectedWarning ("IL3002", Tool.NativeAot, "")] + [ExpectedWarning ("IL3050", Tool.NativeAot, "")] [ExpectedWarning ("IL2026")] - [ExpectedWarning ("IL3002", ProducedBy = Tool.NativeAot)] - [ExpectedWarning ("IL3050", ProducedBy = Tool.NativeAot)] + [ExpectedWarning ("IL3002", Tool.NativeAot, "")] + [ExpectedWarning ("IL3050", Tool.NativeAot, "")] [ExpectedWarning ("IL2026")] - [ExpectedWarning ("IL3002", ProducedBy = Tool.NativeAot)] - [ExpectedWarning ("IL3050", ProducedBy = Tool.NativeAot)] + [ExpectedWarning ("IL3002", Tool.NativeAot, "")] + [ExpectedWarning ("IL3050", Tool.NativeAot, "")] [ExpectedWarning ("IL2026")] - [ExpectedWarning ("IL3002", ProducedBy = Tool.NativeAot)] - [ExpectedWarning ("IL3050", ProducedBy = Tool.NativeAot)] + [ExpectedWarning ("IL3002", Tool.NativeAot, "")] + [ExpectedWarning ("IL3050", Tool.NativeAot, "")] [ExpectedWarning ("IL2026")] - [ExpectedWarning ("IL3002", ProducedBy = Tool.NativeAot)] - [ExpectedWarning ("IL3050", ProducedBy = Tool.NativeAot)] + [ExpectedWarning ("IL3002", Tool.NativeAot, "")] + [ExpectedWarning ("IL3050", Tool.NativeAot, "")] public static void Test () { typeof (IRequires).RequiresPublicMethods (); @@ -650,13 +650,13 @@ public static void AbstractMethod () { } class ImplIRequiresMismatching : IRequires { [ExpectedWarning ("IL2046", "ImplIRequiresMismatching.VirtualMethod", "IRequires.VirtualMethod")] - [ExpectedWarning ("IL3003", "ImplIRequiresMismatching.VirtualMethod", "IRequires.VirtualMethod", ProducedBy = Tool.Analyzer | Tool.NativeAot)] - [ExpectedWarning ("IL3051", "ImplIRequiresMismatching.VirtualMethod", "IRequires.VirtualMethod", ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3003", "ImplIRequiresMismatching.VirtualMethod", "IRequires.VirtualMethod", Tool.Analyzer | Tool.NativeAot, "")] + [ExpectedWarning ("IL3051", "ImplIRequiresMismatching.VirtualMethod", "IRequires.VirtualMethod", Tool.Analyzer | Tool.NativeAot, "")] public static void VirtualMethod () { } [ExpectedWarning ("IL2046", "ImplIRequiresMismatching.AbstractMethod", "IRequires.AbstractMethod")] - [ExpectedWarning ("IL3003", "ImplIRequiresMismatching.AbstractMethod", "IRequires.AbstractMethod", ProducedBy = Tool.Analyzer | Tool.NativeAot)] - [ExpectedWarning ("IL3051", "ImplIRequiresMismatching.AbstractMethod", "IRequires.AbstractMethod", ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3003", "ImplIRequiresMismatching.AbstractMethod", "IRequires.AbstractMethod", Tool.Analyzer | Tool.NativeAot, "")] + [ExpectedWarning ("IL3051", "ImplIRequiresMismatching.AbstractMethod", "IRequires.AbstractMethod", Tool.Analyzer | Tool.NativeAot, "")] public static void AbstractMethod () { } } class ImplINoRequiresMatching : INoRequires @@ -669,16 +669,16 @@ public static void AbstractMethod () { } class ImplINoRequiresMismatching : INoRequires { [ExpectedWarning ("IL2046", "ImplINoRequiresMismatching.VirtualMethod", "INoRequires.VirtualMethod")] - [ExpectedWarning ("IL3003", "ImplINoRequiresMismatching.VirtualMethod", "INoRequires.VirtualMethod", ProducedBy = Tool.Analyzer | Tool.NativeAot)] - [ExpectedWarning ("IL3051", "ImplINoRequiresMismatching.VirtualMethod", "INoRequires.VirtualMethod", ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3003", "ImplINoRequiresMismatching.VirtualMethod", "INoRequires.VirtualMethod", Tool.Analyzer | Tool.NativeAot, "")] + [ExpectedWarning ("IL3051", "ImplINoRequiresMismatching.VirtualMethod", "INoRequires.VirtualMethod", Tool.Analyzer | Tool.NativeAot, "")] [RequiresUnreferencedCode ("Message for --StaticInterfaceMethods.ImplINoRequiresMatching.VirtualMethod--")] [RequiresAssemblyFiles ("Message for --StaticInterfaceMethods.ImplINoRequiresMatching.VirtualMethod--")] [RequiresDynamicCode ("Message for --StaticInterfaceMethods.ImplINoRequiresMatching.VirtualMethod--")] public static void VirtualMethod () { } [ExpectedWarning ("IL2046", "ImplINoRequiresMismatching.AbstractMethod", "INoRequires.AbstractMethod")] - [ExpectedWarning ("IL3003", "ImplINoRequiresMismatching.AbstractMethod", "INoRequires.AbstractMethod", ProducedBy = Tool.Analyzer | Tool.NativeAot)] - [ExpectedWarning ("IL3051", "ImplINoRequiresMismatching.AbstractMethod", "INoRequires.AbstractMethod", ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3003", "ImplINoRequiresMismatching.AbstractMethod", "INoRequires.AbstractMethod", Tool.Analyzer | Tool.NativeAot, "")] + [ExpectedWarning ("IL3051", "ImplINoRequiresMismatching.AbstractMethod", "INoRequires.AbstractMethod", Tool.Analyzer | Tool.NativeAot, "")] [RequiresUnreferencedCode ("Message for --StaticInterfaceMethods.ImplINoRequiresMatching.AbstractMethod--")] [RequiresAssemblyFiles ("Message for --StaticInterfaceMethods.ImplINoRequiresMatching.AbstractMethod--")] [RequiresDynamicCode ("Message for --StaticInterfaceMethods.ImplINoRequiresMatching.AbstractMethod--")] diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/RequiresCapability/RequiresInCompilerGeneratedCode.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/RequiresCapability/RequiresInCompilerGeneratedCode.cs index 3def1ee762beaf..a2f38e46486ad1 100644 --- a/src/tools/illink/test/Mono.Linker.Tests.Cases/RequiresCapability/RequiresInCompilerGeneratedCode.cs +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/RequiresCapability/RequiresInCompilerGeneratedCode.cs @@ -50,8 +50,8 @@ public static void Main () class WarnInIteratorBody { [ExpectedWarning ("IL2026", "--MethodWithRequires--", CompilerGeneratedCode = true)] - [ExpectedWarning ("IL3002", "--MethodWithRequires--", ProducedBy = Tool.Analyzer | Tool.NativeAot, CompilerGeneratedCode = true)] - [ExpectedWarning ("IL3050", "--MethodWithRequires--", ProducedBy = Tool.Analyzer | Tool.NativeAot, CompilerGeneratedCode = true)] + [ExpectedWarning ("IL3002", "--MethodWithRequires--", Tool.Analyzer | Tool.NativeAot, "", CompilerGeneratedCode = true)] + [ExpectedWarning ("IL3050", "--MethodWithRequires--", Tool.Analyzer | Tool.NativeAot, "", CompilerGeneratedCode = true)] static IEnumerable TestCallBeforeYieldReturn () { MethodWithRequires (); @@ -59,8 +59,8 @@ static IEnumerable TestCallBeforeYieldReturn () } [ExpectedWarning ("IL2026", "--MethodWithRequires--", CompilerGeneratedCode = true)] - [ExpectedWarning ("IL3002", "--MethodWithRequires--", ProducedBy = Tool.Analyzer | Tool.NativeAot, CompilerGeneratedCode = true)] - [ExpectedWarning ("IL3050", "--MethodWithRequires--", ProducedBy = Tool.Analyzer | Tool.NativeAot, CompilerGeneratedCode = true)] + [ExpectedWarning ("IL3002", "--MethodWithRequires--", Tool.Analyzer | Tool.NativeAot, "", CompilerGeneratedCode = true)] + [ExpectedWarning ("IL3050", "--MethodWithRequires--", Tool.Analyzer | Tool.NativeAot, "", CompilerGeneratedCode = true)] static IEnumerable TestCallAfterYieldReturn () { yield return 0; @@ -68,8 +68,8 @@ static IEnumerable TestCallAfterYieldReturn () } [ExpectedWarning ("IL2026", "--MethodWithRequires--", CompilerGeneratedCode = true)] - [ExpectedWarning ("IL3002", "--MethodWithRequires--", CompilerGeneratedCode = true, ProducedBy = Tool.NativeAot)] - [ExpectedWarning ("IL3050", "--MethodWithRequires--", CompilerGeneratedCode = true, ProducedBy = Tool.NativeAot)] + [ExpectedWarning ("IL3002", "--MethodWithRequires--", Tool.NativeAot, "", CompilerGeneratedCode = true)] + [ExpectedWarning ("IL3050", "--MethodWithRequires--", Tool.NativeAot, "", CompilerGeneratedCode = true)] static IEnumerable TestReflectionAccess () { yield return 0; @@ -80,15 +80,15 @@ static IEnumerable TestReflectionAccess () } #if !RELEASE - [ExpectedWarning ("IL2026", "--MethodWithRequires--", CompilerGeneratedCode = true, ProducedBy = Tool.Trimmer | Tool.NativeAot)] - [ExpectedWarning ("IL3002", "--MethodWithRequires--", CompilerGeneratedCode = true, ProducedBy = Tool.NativeAot)] - [ExpectedWarning ("IL3050", "--MethodWithRequires--", CompilerGeneratedCode = true, ProducedBy = Tool.NativeAot)] + [ExpectedWarning ("IL2026", "--MethodWithRequires--", Tool.Trimmer | Tool.NativeAot, "", CompilerGeneratedCode = true)] + [ExpectedWarning ("IL3002", "--MethodWithRequires--", Tool.NativeAot, "", CompilerGeneratedCode = true)] + [ExpectedWarning ("IL3050", "--MethodWithRequires--", Tool.NativeAot, "", CompilerGeneratedCode = true)] #else // In release mode, the compiler optimizes away the unused Action (and reference to MethodWithRequires) #endif - [ExpectedWarning ("IL2026", "--MethodWithRequires--", ProducedBy = Tool.Analyzer)] - [ExpectedWarning ("IL3002", "--MethodWithRequires--", ProducedBy = Tool.Analyzer)] - [ExpectedWarning ("IL3050", "--MethodWithRequires--", ProducedBy = Tool.Analyzer)] + [ExpectedWarning ("IL2026", "--MethodWithRequires--", Tool.Analyzer, "")] + [ExpectedWarning ("IL3002", "--MethodWithRequires--", Tool.Analyzer, "")] + [ExpectedWarning ("IL3050", "--MethodWithRequires--", Tool.Analyzer, "")] static IEnumerable TestLdftn () { yield return 0; @@ -98,8 +98,8 @@ static IEnumerable TestLdftn () // Cannot annotate fields either with RUC nor RAF therefore the warning persists [ExpectedWarning ("IL2026", "Message from --MethodWithRequiresAndReturns--", CompilerGeneratedCode = true)] - [ExpectedWarning ("IL3002", "Message from --MethodWithRequiresAndReturns--", CompilerGeneratedCode = true, ProducedBy = Tool.Analyzer | Tool.NativeAot)] - [ExpectedWarning ("IL3050", "Message from --MethodWithRequiresAndReturns--", CompilerGeneratedCode = true, ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3002", "Message from --MethodWithRequiresAndReturns--", Tool.Analyzer | Tool.NativeAot, "", CompilerGeneratedCode = true)] + [ExpectedWarning ("IL3050", "Message from --MethodWithRequiresAndReturns--", Tool.Analyzer | Tool.NativeAot, "", CompilerGeneratedCode = true)] public static Lazy _default = new Lazy (MethodWithRequiresAndReturns); static IEnumerable TestLazyDelegate () @@ -110,8 +110,8 @@ static IEnumerable TestLazyDelegate () } [ExpectedWarning ("IL2026", "--TypeWithMethodWithRequires.MethodWithRequires--", CompilerGeneratedCode = true)] - [ExpectedWarning ("IL3002", "--TypeWithMethodWithRequires.MethodWithRequires--", CompilerGeneratedCode = true, ProducedBy = Tool.NativeAot)] - [ExpectedWarning ("IL3050", "--TypeWithMethodWithRequires.MethodWithRequires--", CompilerGeneratedCode = true, ProducedBy = Tool.NativeAot)] + [ExpectedWarning ("IL3002", "--TypeWithMethodWithRequires.MethodWithRequires--", Tool.NativeAot, "", CompilerGeneratedCode = true)] + [ExpectedWarning ("IL3050", "--TypeWithMethodWithRequires.MethodWithRequires--", Tool.NativeAot, "", CompilerGeneratedCode = true)] static IEnumerable TestDynamicallyAccessedMethod () { typeof (TypeWithMethodWithRequires).RequiresNonPublicMethods (); @@ -167,8 +167,8 @@ static IEnumerable TestLdftn () // Cannot annotate fields either with RUC nor RAF therefore the warning persists [ExpectedWarning ("IL2026", "Message from --MethodWithRequiresAndReturns--", CompilerGeneratedCode = true)] - [ExpectedWarning ("IL3002", "Message from --MethodWithRequiresAndReturns--", CompilerGeneratedCode = true, ProducedBy = Tool.Analyzer | Tool.NativeAot)] - [ExpectedWarning ("IL3050", "Message from --MethodWithRequiresAndReturns--", CompilerGeneratedCode = true, ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3002", "Message from --MethodWithRequiresAndReturns--", Tool.Analyzer | Tool.NativeAot, "", CompilerGeneratedCode = true)] + [ExpectedWarning ("IL3050", "Message from --MethodWithRequiresAndReturns--", Tool.Analyzer | Tool.NativeAot, "", CompilerGeneratedCode = true)] public static Lazy _default = new Lazy (MethodWithRequiresAndReturns); static IEnumerable TestLazyDelegate () @@ -234,8 +234,8 @@ public static void Test () class WarnInAsyncBody { [ExpectedWarning ("IL2026", "--MethodWithRequires--", CompilerGeneratedCode = true)] - [ExpectedWarning ("IL3002", "--MethodWithRequires--", ProducedBy = Tool.Analyzer | Tool.NativeAot, CompilerGeneratedCode = true)] - [ExpectedWarning ("IL3050", "--MethodWithRequires--", ProducedBy = Tool.Analyzer | Tool.NativeAot, CompilerGeneratedCode = true)] + [ExpectedWarning ("IL3002", "--MethodWithRequires--", Tool.Analyzer | Tool.NativeAot, "", CompilerGeneratedCode = true)] + [ExpectedWarning ("IL3050", "--MethodWithRequires--", Tool.Analyzer | Tool.NativeAot, "", CompilerGeneratedCode = true)] static async void TestCallBeforeYieldReturn () { MethodWithRequires (); @@ -243,8 +243,8 @@ static async void TestCallBeforeYieldReturn () } [ExpectedWarning ("IL2026", "--MethodWithRequires--", CompilerGeneratedCode = true)] - [ExpectedWarning ("IL3002", "--MethodWithRequires--", ProducedBy = Tool.Analyzer | Tool.NativeAot, CompilerGeneratedCode = true)] - [ExpectedWarning ("IL3050", "--MethodWithRequires--", ProducedBy = Tool.Analyzer | Tool.NativeAot, CompilerGeneratedCode = true)] + [ExpectedWarning ("IL3002", "--MethodWithRequires--", Tool.Analyzer | Tool.NativeAot, "", CompilerGeneratedCode = true)] + [ExpectedWarning ("IL3050", "--MethodWithRequires--", Tool.Analyzer | Tool.NativeAot, "", CompilerGeneratedCode = true)] static async void TestCallAfterYieldReturn () { await MethodAsync (); @@ -252,8 +252,8 @@ static async void TestCallAfterYieldReturn () } [ExpectedWarning ("IL2026", "--MethodWithRequires--", CompilerGeneratedCode = true)] - [ExpectedWarning ("IL3002", "--MethodWithRequires--", CompilerGeneratedCode = true, ProducedBy = Tool.NativeAot)] - [ExpectedWarning ("IL3050", "--MethodWithRequires--", CompilerGeneratedCode = true, ProducedBy = Tool.NativeAot)] + [ExpectedWarning ("IL3002", "--MethodWithRequires--", Tool.NativeAot, "", CompilerGeneratedCode = true)] + [ExpectedWarning ("IL3050", "--MethodWithRequires--", Tool.NativeAot, "", CompilerGeneratedCode = true)] static async void TestReflectionAccess () { await MethodAsync (); @@ -264,13 +264,13 @@ static async void TestReflectionAccess () } #if !RELEASE - [ExpectedWarning ("IL2026", "--MethodWithRequires--", CompilerGeneratedCode = true, ProducedBy = Tool.Trimmer | Tool.NativeAot)] - [ExpectedWarning ("IL3002", "--MethodWithRequires--", CompilerGeneratedCode = true, ProducedBy = Tool.NativeAot)] - [ExpectedWarning ("IL3050", "--MethodWithRequires--", CompilerGeneratedCode = true, ProducedBy = Tool.NativeAot)] + [ExpectedWarning ("IL2026", "--MethodWithRequires--", Tool.Trimmer | Tool.NativeAot, "", CompilerGeneratedCode = true)] + [ExpectedWarning ("IL3002", "--MethodWithRequires--", Tool.NativeAot, "", CompilerGeneratedCode = true)] + [ExpectedWarning ("IL3050", "--MethodWithRequires--", Tool.NativeAot, "", CompilerGeneratedCode = true)] #endif - [ExpectedWarning ("IL2026", "--MethodWithRequires--", ProducedBy = Tool.Analyzer)] - [ExpectedWarning ("IL3002", "--MethodWithRequires--", ProducedBy = Tool.Analyzer)] - [ExpectedWarning ("IL3050", "--MethodWithRequires--", ProducedBy = Tool.Analyzer)] + [ExpectedWarning ("IL2026", "--MethodWithRequires--", Tool.Analyzer, "")] + [ExpectedWarning ("IL3002", "--MethodWithRequires--", Tool.Analyzer, "")] + [ExpectedWarning ("IL3050", "--MethodWithRequires--", Tool.Analyzer, "")] static async void TestLdftn () { await MethodAsync (); @@ -278,8 +278,8 @@ static async void TestLdftn () } [ExpectedWarning ("IL2026", "Message from --MethodWithRequiresAndReturns--", CompilerGeneratedCode = true)] - [ExpectedWarning ("IL3002", "Message from --MethodWithRequiresAndReturns--", CompilerGeneratedCode = true, ProducedBy = Tool.Analyzer | Tool.NativeAot)] - [ExpectedWarning ("IL3050", "Message from --MethodWithRequiresAndReturns--", CompilerGeneratedCode = true, ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3002", "Message from --MethodWithRequiresAndReturns--", Tool.Analyzer | Tool.NativeAot, "", CompilerGeneratedCode = true)] + [ExpectedWarning ("IL3050", "Message from --MethodWithRequiresAndReturns--", Tool.Analyzer | Tool.NativeAot, "", CompilerGeneratedCode = true)] public static Lazy _default = new Lazy (MethodWithRequiresAndReturns); static async void TestLazyDelegate () @@ -289,8 +289,8 @@ static async void TestLazyDelegate () } [ExpectedWarning ("IL2026", "--TypeWithMethodWithRequires.MethodWithRequires--", CompilerGeneratedCode = true)] - [ExpectedWarning ("IL3002", "--TypeWithMethodWithRequires.MethodWithRequires--", CompilerGeneratedCode = true, ProducedBy = Tool.NativeAot)] - [ExpectedWarning ("IL3050", "--TypeWithMethodWithRequires.MethodWithRequires--", CompilerGeneratedCode = true, ProducedBy = Tool.NativeAot)] + [ExpectedWarning ("IL3002", "--TypeWithMethodWithRequires.MethodWithRequires--", Tool.NativeAot, "", CompilerGeneratedCode = true)] + [ExpectedWarning ("IL3050", "--TypeWithMethodWithRequires.MethodWithRequires--", Tool.NativeAot, "", CompilerGeneratedCode = true)] static async void TestDynamicallyAccessedMethod () { typeof (TypeWithMethodWithRequires).RequiresNonPublicMethods (); @@ -344,8 +344,8 @@ static async void TestLdftn () // Cannot annotate fields either with RUC nor RAF therefore the warning persists [ExpectedWarning ("IL2026", "Message from --MethodWithRequiresAndReturns--", CompilerGeneratedCode = true)] - [ExpectedWarning ("IL3002", "Message from --MethodWithRequiresAndReturns--", CompilerGeneratedCode = true, ProducedBy = Tool.Analyzer | Tool.NativeAot)] - [ExpectedWarning ("IL3050", "Message from --MethodWithRequiresAndReturns--", CompilerGeneratedCode = true, ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3002", "Message from --MethodWithRequiresAndReturns--", Tool.Analyzer | Tool.NativeAot, "", CompilerGeneratedCode = true)] + [ExpectedWarning ("IL3050", "Message from --MethodWithRequiresAndReturns--", Tool.Analyzer | Tool.NativeAot, "", CompilerGeneratedCode = true)] public static Lazy _default = new Lazy (MethodWithRequiresAndReturns); static async void TestLazyDelegate () @@ -409,8 +409,8 @@ public static void Test () class WarnInAsyncIteratorBody { [ExpectedWarning ("IL2026", "--MethodWithRequires--", CompilerGeneratedCode = true)] - [ExpectedWarning ("IL3002", "--MethodWithRequires--", ProducedBy = Tool.Analyzer | Tool.NativeAot, CompilerGeneratedCode = true)] - [ExpectedWarning ("IL3050", "--MethodWithRequires--", ProducedBy = Tool.Analyzer | Tool.NativeAot, CompilerGeneratedCode = true)] + [ExpectedWarning ("IL3002", "--MethodWithRequires--", Tool.Analyzer | Tool.NativeAot, "", CompilerGeneratedCode = true)] + [ExpectedWarning ("IL3050", "--MethodWithRequires--", Tool.Analyzer | Tool.NativeAot, "", CompilerGeneratedCode = true)] static async IAsyncEnumerable TestCallBeforeYieldReturn () { await MethodAsync (); @@ -419,8 +419,8 @@ static async IAsyncEnumerable TestCallBeforeYieldReturn () } [ExpectedWarning ("IL2026", "--MethodWithRequires--", CompilerGeneratedCode = true)] - [ExpectedWarning ("IL3002", "--MethodWithRequires--", ProducedBy = Tool.Analyzer | Tool.NativeAot, CompilerGeneratedCode = true)] - [ExpectedWarning ("IL3050", "--MethodWithRequires--", ProducedBy = Tool.Analyzer | Tool.NativeAot, CompilerGeneratedCode = true)] + [ExpectedWarning ("IL3002", "--MethodWithRequires--", Tool.Analyzer | Tool.NativeAot, "", CompilerGeneratedCode = true)] + [ExpectedWarning ("IL3050", "--MethodWithRequires--", Tool.Analyzer | Tool.NativeAot, "", CompilerGeneratedCode = true)] static async IAsyncEnumerable TestCallAfterYieldReturn () { yield return 0; @@ -429,8 +429,8 @@ static async IAsyncEnumerable TestCallAfterYieldReturn () } [ExpectedWarning ("IL2026", "--MethodWithRequires--", CompilerGeneratedCode = true)] - [ExpectedWarning ("IL3002", "--MethodWithRequires--", CompilerGeneratedCode = true, ProducedBy = Tool.NativeAot)] - [ExpectedWarning ("IL3050", "--MethodWithRequires--", CompilerGeneratedCode = true, ProducedBy = Tool.NativeAot)] + [ExpectedWarning ("IL3002", "--MethodWithRequires--", Tool.NativeAot, "", CompilerGeneratedCode = true)] + [ExpectedWarning ("IL3050", "--MethodWithRequires--", Tool.NativeAot, "", CompilerGeneratedCode = true)] static async IAsyncEnumerable TestReflectionAccess () { yield return 0; @@ -443,13 +443,13 @@ static async IAsyncEnumerable TestReflectionAccess () } #if !RELEASE - [ExpectedWarning ("IL2026", "--MethodWithRequires--", ProducedBy = Tool.Trimmer | Tool.NativeAot, CompilerGeneratedCode = true)] - [ExpectedWarning ("IL3002", "--MethodWithRequires--", CompilerGeneratedCode = true, ProducedBy = Tool.NativeAot)] - [ExpectedWarning ("IL3050", "--MethodWithRequires--", CompilerGeneratedCode = true, ProducedBy = Tool.NativeAot)] + [ExpectedWarning ("IL2026", "--MethodWithRequires--", Tool.Trimmer | Tool.NativeAot, "", CompilerGeneratedCode = true)] + [ExpectedWarning ("IL3002", "--MethodWithRequires--", Tool.NativeAot, "", CompilerGeneratedCode = true)] + [ExpectedWarning ("IL3050", "--MethodWithRequires--", Tool.NativeAot, "", CompilerGeneratedCode = true)] #endif - [ExpectedWarning ("IL2026", "--MethodWithRequires--", ProducedBy = Tool.Analyzer)] - [ExpectedWarning ("IL3002", "--MethodWithRequires--", ProducedBy = Tool.Analyzer)] - [ExpectedWarning ("IL3050", "--MethodWithRequires--", ProducedBy = Tool.Analyzer)] + [ExpectedWarning ("IL2026", "--MethodWithRequires--", Tool.Analyzer, "")] + [ExpectedWarning ("IL3002", "--MethodWithRequires--", Tool.Analyzer, "")] + [ExpectedWarning ("IL3050", "--MethodWithRequires--", Tool.Analyzer, "")] static async IAsyncEnumerable TestLdftn () { await MethodAsync (); @@ -458,8 +458,8 @@ static async IAsyncEnumerable TestLdftn () } [ExpectedWarning ("IL2026", "Message from --MethodWithRequiresAndReturns--", CompilerGeneratedCode = true)] - [ExpectedWarning ("IL3002", "Message from --MethodWithRequiresAndReturns--", CompilerGeneratedCode = true, ProducedBy = Tool.Analyzer | Tool.NativeAot)] - [ExpectedWarning ("IL3050", "Message from --MethodWithRequiresAndReturns--", CompilerGeneratedCode = true, ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3002", "Message from --MethodWithRequiresAndReturns--", Tool.Analyzer | Tool.NativeAot, "", CompilerGeneratedCode = true)] + [ExpectedWarning ("IL3050", "Message from --MethodWithRequiresAndReturns--", Tool.Analyzer | Tool.NativeAot, "", CompilerGeneratedCode = true)] public static Lazy _default = new Lazy (MethodWithRequiresAndReturns); static async IAsyncEnumerable TestLazyDelegate () @@ -470,8 +470,8 @@ static async IAsyncEnumerable TestLazyDelegate () } [ExpectedWarning ("IL2026", "--TypeWithMethodWithRequires.MethodWithRequires--", CompilerGeneratedCode = true)] - [ExpectedWarning ("IL3002", "--TypeWithMethodWithRequires.MethodWithRequires--", CompilerGeneratedCode = true, ProducedBy = Tool.NativeAot)] - [ExpectedWarning ("IL3050", "--TypeWithMethodWithRequires.MethodWithRequires--", CompilerGeneratedCode = true, ProducedBy = Tool.NativeAot)] + [ExpectedWarning ("IL3002", "--TypeWithMethodWithRequires.MethodWithRequires--", Tool.NativeAot, "", CompilerGeneratedCode = true)] + [ExpectedWarning ("IL3050", "--TypeWithMethodWithRequires.MethodWithRequires--", Tool.NativeAot, "", CompilerGeneratedCode = true)] static async IAsyncEnumerable TestDynamicallyAccessedMethod () { typeof (TypeWithMethodWithRequires).RequiresNonPublicMethods (); @@ -530,8 +530,8 @@ static async IAsyncEnumerable TestLdftn () // Cannot annotate fields either with RUC nor RAF therefore the warning persists [ExpectedWarning ("IL2026", "Message from --MethodWithRequiresAndReturns--", CompilerGeneratedCode = true)] - [ExpectedWarning ("IL3002", "Message from --MethodWithRequiresAndReturns--", CompilerGeneratedCode = true, ProducedBy = Tool.Analyzer | Tool.NativeAot)] - [ExpectedWarning ("IL3050", "Message from --MethodWithRequiresAndReturns--", CompilerGeneratedCode = true, ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3002", "Message from --MethodWithRequiresAndReturns--", Tool.Analyzer | Tool.NativeAot, "", CompilerGeneratedCode = true)] + [ExpectedWarning ("IL3050", "Message from --MethodWithRequiresAndReturns--", Tool.Analyzer | Tool.NativeAot, "", CompilerGeneratedCode = true)] public static Lazy _default = new Lazy (MethodWithRequiresAndReturns); static async IAsyncEnumerable TestLazyDelegate () @@ -604,14 +604,14 @@ static void TestCall () LocalFunction (); [ExpectedWarning ("IL2026", "--MethodWithRequires--")] - [ExpectedWarning ("IL3002", "--MethodWithRequires--", ProducedBy = Tool.Analyzer | Tool.NativeAot)] - [ExpectedWarning ("IL3050", "--MethodWithRequires--", ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3002", "--MethodWithRequires--", Tool.Analyzer | Tool.NativeAot, "")] + [ExpectedWarning ("IL3050", "--MethodWithRequires--", Tool.Analyzer | Tool.NativeAot, "")] void LocalFunction () => MethodWithRequires (); } [ExpectedWarning ("IL2026", "--LocalFunctionWithRequires--")] - [ExpectedWarning ("IL3002", "--LocalFunctionWithRequires--", ProducedBy = Tool.Analyzer | Tool.NativeAot)] - [ExpectedWarning ("IL3050", "--LocalFunctionWithRequires--", ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3002", "--LocalFunctionWithRequires--", Tool.Analyzer | Tool.NativeAot, "")] + [ExpectedWarning ("IL3050", "--LocalFunctionWithRequires--", Tool.Analyzer | Tool.NativeAot, "")] static void TestLocalFunctionWithRequires () { LocalFunction (); @@ -633,8 +633,8 @@ static void TestCallWithClosure (int p = 0) LocalFunction (); [ExpectedWarning ("IL2026", "--MethodWithRequires--")] - [ExpectedWarning ("IL3002", "--MethodWithRequires--", ProducedBy = Tool.Analyzer | Tool.NativeAot)] - [ExpectedWarning ("IL3050", "--MethodWithRequires--", ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3002", "--MethodWithRequires--", Tool.Analyzer | Tool.NativeAot, "")] + [ExpectedWarning ("IL3050", "--MethodWithRequires--", Tool.Analyzer | Tool.NativeAot, "")] void LocalFunction () { p++; @@ -657,8 +657,8 @@ static void TestReflectionAccess () LocalFunction (); [ExpectedWarning ("IL2026", "--MethodWithRequires--")] - [ExpectedWarning ("IL3002", "--MethodWithRequires--", ProducedBy = Tool.NativeAot)] - [ExpectedWarning ("IL3050", "--MethodWithRequires--", ProducedBy = Tool.NativeAot)] + [ExpectedWarning ("IL3002", "--MethodWithRequires--", Tool.NativeAot, "")] + [ExpectedWarning ("IL3050", "--MethodWithRequires--", Tool.NativeAot, "")] void LocalFunction () => typeof (RequiresInCompilerGeneratedCode) .GetMethod ("MethodWithRequires", System.Reflection.BindingFlags.NonPublic) .Invoke (null, new object[] { }); @@ -669,13 +669,13 @@ static void TestLdftn () LocalFunction (); #if !RELEASE - [ExpectedWarning ("IL2026", "--MethodWithRequires--", ProducedBy = Tool.Trimmer | Tool.NativeAot)] - [ExpectedWarning ("IL3002", "--MethodWithRequires--", ProducedBy = Tool.NativeAot)] - [ExpectedWarning ("IL3050", "--MethodWithRequires--", ProducedBy = Tool.NativeAot)] + [ExpectedWarning ("IL2026", "--MethodWithRequires--", Tool.Trimmer | Tool.NativeAot, "")] + [ExpectedWarning ("IL3002", "--MethodWithRequires--", Tool.NativeAot, "")] + [ExpectedWarning ("IL3050", "--MethodWithRequires--", Tool.NativeAot, "")] #endif - [ExpectedWarning ("IL2026", "--MethodWithRequires--", ProducedBy = Tool.Analyzer)] - [ExpectedWarning ("IL3002", "--MethodWithRequires--", ProducedBy = Tool.Analyzer)] - [ExpectedWarning ("IL3050", "--MethodWithRequires--", ProducedBy = Tool.Analyzer)] + [ExpectedWarning ("IL2026", "--MethodWithRequires--", Tool.Analyzer, "")] + [ExpectedWarning ("IL3002", "--MethodWithRequires--", Tool.Analyzer, "")] + [ExpectedWarning ("IL3050", "--MethodWithRequires--", Tool.Analyzer, "")] void LocalFunction () { var action = new Action (MethodWithRequires); @@ -683,8 +683,8 @@ void LocalFunction () } [ExpectedWarning ("IL2026", "Message from --MethodWithRequiresAndReturns--", CompilerGeneratedCode = true)] - [ExpectedWarning ("IL3002", "Message from --MethodWithRequiresAndReturns--", CompilerGeneratedCode = true, ProducedBy = Tool.Analyzer | Tool.NativeAot)] - [ExpectedWarning ("IL3050", "Message from --MethodWithRequiresAndReturns--", CompilerGeneratedCode = true, ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3002", "Message from --MethodWithRequiresAndReturns--", Tool.Analyzer | Tool.NativeAot, "", CompilerGeneratedCode = true)] + [ExpectedWarning ("IL3050", "Message from --MethodWithRequiresAndReturns--", Tool.Analyzer | Tool.NativeAot, "", CompilerGeneratedCode = true)] public static Lazy _default = new Lazy (MethodWithRequiresAndReturns); static void TestLazyDelegate () @@ -702,8 +702,8 @@ static void TestDynamicallyAccessedMethod () LocalFunction (); [ExpectedWarning ("IL2026", "--TypeWithMethodWithRequires.MethodWithRequires--")] - [ExpectedWarning ("IL3002", "--TypeWithMethodWithRequires.MethodWithRequires--", ProducedBy = Tool.NativeAot)] - [ExpectedWarning ("IL3050", "--TypeWithMethodWithRequires.MethodWithRequires--", ProducedBy = Tool.NativeAot)] + [ExpectedWarning ("IL3002", "--TypeWithMethodWithRequires.MethodWithRequires--", Tool.NativeAot, "")] + [ExpectedWarning ("IL3050", "--TypeWithMethodWithRequires.MethodWithRequires--", Tool.NativeAot, "")] void LocalFunction () => typeof (TypeWithMethodWithRequires).RequiresNonPublicMethods (); } @@ -788,8 +788,8 @@ void LocalFunction () } [ExpectedWarning ("IL2026", "Message from --MethodWithRequiresAndReturns--", CompilerGeneratedCode = true)] - [ExpectedWarning ("IL3002", "Message from --MethodWithRequiresAndReturns--", CompilerGeneratedCode = true, ProducedBy = Tool.Analyzer | Tool.NativeAot)] - [ExpectedWarning ("IL3050", "Message from --MethodWithRequiresAndReturns--", CompilerGeneratedCode = true, ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3002", "Message from --MethodWithRequiresAndReturns--", Tool.Analyzer | Tool.NativeAot, "", CompilerGeneratedCode = true)] + [ExpectedWarning ("IL3050", "Message from --MethodWithRequiresAndReturns--", Tool.Analyzer | Tool.NativeAot, "", CompilerGeneratedCode = true)] public static Lazy _default = new Lazy (MethodWithRequiresAndReturns); static void TestLazyDelegate () @@ -919,7 +919,7 @@ public static void TestCallMethodWithRequiresInDynamicallyAccessedLocalFunction class DynamicallyAccessedLocalFunctionUnusedShouldWarn { - [ExpectedWarning ("IL2118", nameof (TestCallMethodWithRequiresInDynamicallyAccessedLocalFunction), "LocalFunction", ProducedBy = Tool.Trimmer)] + [ExpectedWarning ("IL2118", [nameof (TestCallMethodWithRequiresInDynamicallyAccessedLocalFunction), "LocalFunction"], Tool.Trimmer, "")] public static void TestCallMethodWithRequiresInDynamicallyAccessedLocalFunction () { typeof (DynamicallyAccessedLocalFunctionUnusedShouldWarn).RequiresNonPublicMethods (); @@ -949,8 +949,8 @@ public static void TestCallMethodWithRequiresInDynamicallyAccessedLocalFunction } [ExpectedWarning ("IL2026")] - [ExpectedWarning ("IL3002", ProducedBy = Tool.Analyzer | Tool.NativeAot)] - [ExpectedWarning ("IL3050", ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3002", Tool.Analyzer | Tool.NativeAot, "")] + [ExpectedWarning ("IL3050", Tool.Analyzer | Tool.NativeAot, "")] static void TestSuppressionOnLocalFunction () { LocalFunction (); // This will produce a warning since the local function has Requires on it @@ -966,8 +966,8 @@ void LocalFunction (Type unknownType = null) } [ExpectedWarning ("IL2026")] - [ExpectedWarning ("IL3002", ProducedBy = Tool.Analyzer | Tool.NativeAot)] - [ExpectedWarning ("IL3050", ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3002", Tool.Analyzer | Tool.NativeAot, "")] + [ExpectedWarning ("IL3050", Tool.Analyzer | Tool.NativeAot, "")] static void TestSuppressionOnLocalFunctionWithAssignment () { LocalFunction (); // This will produce a warning since the local function has Requires on it @@ -986,8 +986,8 @@ void LocalFunction (Type unknownType = null) static Type typeWithNonPublicMethods; [ExpectedWarning ("IL2026")] - [ExpectedWarning ("IL3002", ProducedBy = Tool.Analyzer | Tool.NativeAot)] - [ExpectedWarning ("IL3050", ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3002", Tool.Analyzer | Tool.NativeAot, "")] + [ExpectedWarning ("IL3050", Tool.Analyzer | Tool.NativeAot, "")] static void TestSuppressionOnLocalFunctionWithNestedLocalFunction () { LocalFunction (); // This will produce a warning since the local function has Requires on it @@ -1001,9 +1001,9 @@ void LocalFunction () // ILLink doesn't have enough information to associate the Requires on LocalFunction // with this nested local function. - [ExpectedWarning ("IL2026", ProducedBy = Tool.Trimmer | Tool.NativeAot)] - [ExpectedWarning ("IL3002", ProducedBy = Tool.NativeAot)] - [ExpectedWarning ("IL3050", ProducedBy = Tool.NativeAot)] + [ExpectedWarning ("IL2026", Tool.Trimmer | Tool.NativeAot, "")] + [ExpectedWarning ("IL3002", Tool.NativeAot, "")] + [ExpectedWarning ("IL3050", Tool.NativeAot, "")] void NestedLocalFunction () => MethodWithRequires (); } } @@ -1028,8 +1028,8 @@ void LocalFunction (Type unknownType = null) class TestSuppressionOnOuterWithSameName { [ExpectedWarning ("IL2026", nameof (Outer) + "()")] - [ExpectedWarning ("IL3002", nameof (Outer) + "()", ProducedBy = Tool.Analyzer | Tool.NativeAot)] - [ExpectedWarning ("IL3050", nameof (Outer) + "()", ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3002", nameof (Outer) + "()", Tool.Analyzer | Tool.NativeAot, "")] + [ExpectedWarning ("IL3050", nameof (Outer) + "()", Tool.Analyzer | Tool.NativeAot, "")] public static void Test () { Outer (); @@ -1051,8 +1051,8 @@ static void Outer (int i) LocalFunction (); [ExpectedWarning ("IL2026", "--MethodWithRequires--")] - [ExpectedWarning ("IL3002", ProducedBy = Tool.Analyzer | Tool.NativeAot)] - [ExpectedWarning ("IL3050", ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3002", Tool.Analyzer | Tool.NativeAot, "")] + [ExpectedWarning ("IL3050", Tool.Analyzer | Tool.NativeAot, "")] void LocalFunction () => MethodWithRequires (); } } @@ -1093,14 +1093,14 @@ static void WarnInNonNestedLocalFunctionTest () LocalFunction (); [ExpectedWarning ("IL2026", "--MethodWithRequires--")] - [ExpectedWarning ("IL3002", "--MethodWithRequires--", ProducedBy = Tool.Analyzer | Tool.NativeAot)] - [ExpectedWarning ("IL3050", "--MethodWithRequires--", ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3002", "--MethodWithRequires--", Tool.Analyzer | Tool.NativeAot, "")] + [ExpectedWarning ("IL3050", "--MethodWithRequires--", Tool.Analyzer | Tool.NativeAot, "")] static void LocalFunction () => MethodWithRequires (); } [ExpectedWarning ("IL2026", "--MethodWithNonNestedLocalFunction--")] - [ExpectedWarning ("IL3002", "--MethodWithNonNestedLocalFunction--", ProducedBy = Tool.Analyzer | Tool.NativeAot)] - [ExpectedWarning ("IL3050", "--MethodWithNonNestedLocalFunction--", ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3002", "--MethodWithNonNestedLocalFunction--", Tool.Analyzer | Tool.NativeAot, "")] + [ExpectedWarning ("IL3050", "--MethodWithNonNestedLocalFunction--", Tool.Analyzer | Tool.NativeAot, "")] static void SuppressInNonNestedLocalFunctionTest () { MethodWithNonNestedLocalFunction (); @@ -1122,16 +1122,16 @@ static void TestCall () { Action lambda = [ExpectedWarning ("IL2026", "--MethodWithRequires--")] - [ExpectedWarning ("IL3002", "--MethodWithRequires--", ProducedBy = Tool.Analyzer | Tool.NativeAot)] - [ExpectedWarning ("IL3050", "--MethodWithRequires--", ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3002", "--MethodWithRequires--", Tool.Analyzer | Tool.NativeAot, "")] + [ExpectedWarning ("IL3050", "--MethodWithRequires--", Tool.Analyzer | Tool.NativeAot, "")] () => MethodWithRequires (); lambda (); } [ExpectedWarning ("IL2026", "--LambdaWithRequires--")] - [ExpectedWarning ("IL3002", "--LambdaWithRequires--", ProducedBy = Tool.Analyzer | Tool.NativeAot)] - [ExpectedWarning ("IL3050", "--LambdaWithRequires--", ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3002", "--LambdaWithRequires--", Tool.Analyzer | Tool.NativeAot, "")] + [ExpectedWarning ("IL3050", "--LambdaWithRequires--", Tool.Analyzer | Tool.NativeAot, "")] static void TestLambdaWithRequires () { Action lambda = @@ -1147,14 +1147,14 @@ static void TestCallUnused () { Action _ = [ExpectedWarning ("IL2026", "--MethodWithRequires--")] - [ExpectedWarning ("IL3002", "--MethodWithRequires--", ProducedBy = Tool.Analyzer | Tool.NativeAot)] - [ExpectedWarning ("IL3050", "--MethodWithRequires--", ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3002", "--MethodWithRequires--", Tool.Analyzer | Tool.NativeAot, "")] + [ExpectedWarning ("IL3050", "--MethodWithRequires--", Tool.Analyzer | Tool.NativeAot, "")] () => MethodWithRequires (); } [ExpectedWarning ("IL2026", "--LambdaWithRequires--")] - [ExpectedWarning ("IL3002", "--LambdaWithRequires--", ProducedBy = Tool.Analyzer | Tool.NativeAot)] - [ExpectedWarning ("IL3050", "--LambdaWithRequires--", ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3002", "--LambdaWithRequires--", Tool.Analyzer | Tool.NativeAot, "")] + [ExpectedWarning ("IL3050", "--LambdaWithRequires--", Tool.Analyzer | Tool.NativeAot, "")] static void TestLambdaWithRequiresUnused () { Action _ = @@ -1168,8 +1168,8 @@ static void TestCallWithClosure (int p = 0) { Action lambda = [ExpectedWarning ("IL2026", "--MethodWithRequires--")] - [ExpectedWarning ("IL3002", "--MethodWithRequires--", ProducedBy = Tool.Analyzer | Tool.NativeAot)] - [ExpectedWarning ("IL3050", "--MethodWithRequires--", ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3002", "--MethodWithRequires--", Tool.Analyzer | Tool.NativeAot, "")] + [ExpectedWarning ("IL3050", "--MethodWithRequires--", Tool.Analyzer | Tool.NativeAot, "")] () => { p++; MethodWithRequires (); @@ -1182,13 +1182,13 @@ static void TestCallWithClosureUnused (int p = 0) { Action _ = #if !RELEASE - [ExpectedWarning ("IL2026", "--MethodWithRequires--", ProducedBy = Tool.Trimmer | Tool.NativeAot)] - [ExpectedWarning ("IL3002", "--MethodWithRequires--", ProducedBy = Tool.NativeAot)] - [ExpectedWarning ("IL3050", "--MethodWithRequires--", ProducedBy = Tool.NativeAot)] + [ExpectedWarning ("IL2026", "--MethodWithRequires--", Tool.Trimmer | Tool.NativeAot, "")] + [ExpectedWarning ("IL3002", "--MethodWithRequires--", Tool.NativeAot, "")] + [ExpectedWarning ("IL3050", "--MethodWithRequires--", Tool.NativeAot, "")] #endif - [ExpectedWarning ("IL2026", "--MethodWithRequires--", ProducedBy = Tool.Analyzer)] - [ExpectedWarning ("IL3002", "--MethodWithRequires--", ProducedBy = Tool.Analyzer)] - [ExpectedWarning ("IL3050", "--MethodWithRequires--", ProducedBy = Tool.Analyzer)] + [ExpectedWarning ("IL2026", "--MethodWithRequires--", Tool.Analyzer, "")] + [ExpectedWarning ("IL3002", "--MethodWithRequires--", Tool.Analyzer, "")] + [ExpectedWarning ("IL3050", "--MethodWithRequires--", Tool.Analyzer, "")] () => { p++; MethodWithRequires (); @@ -1199,8 +1199,8 @@ static void TestReflectionAccess () { Action _ = [ExpectedWarning ("IL2026", "--MethodWithRequires--")] - [ExpectedWarning ("IL3002", "--MethodWithRequires--", ProducedBy = Tool.NativeAot)] - [ExpectedWarning ("IL3050", "--MethodWithRequires--", ProducedBy = Tool.NativeAot)] + [ExpectedWarning ("IL3002", "--MethodWithRequires--", Tool.NativeAot, "")] + [ExpectedWarning ("IL3050", "--MethodWithRequires--", Tool.NativeAot, "")] () => { typeof (RequiresInCompilerGeneratedCode) .GetMethod ("MethodWithRequires", System.Reflection.BindingFlags.NonPublic) @@ -1212,21 +1212,21 @@ static void TestLdftn () { Action _ = #if !RELEASE - [ExpectedWarning ("IL2026", "--MethodWithRequires--", ProducedBy = Tool.Trimmer | Tool.NativeAot)] - [ExpectedWarning ("IL3002", "--MethodWithRequires--", ProducedBy = Tool.NativeAot)] - [ExpectedWarning ("IL3050", "--MethodWithRequires--", ProducedBy = Tool.NativeAot)] + [ExpectedWarning ("IL2026", "--MethodWithRequires--", Tool.Trimmer | Tool.NativeAot, "")] + [ExpectedWarning ("IL3002", "--MethodWithRequires--", Tool.NativeAot, "")] + [ExpectedWarning ("IL3050", "--MethodWithRequires--", Tool.NativeAot, "")] #endif - [ExpectedWarning ("IL2026", "--MethodWithRequires--", ProducedBy = Tool.Analyzer)] - [ExpectedWarning ("IL3002", "--MethodWithRequires--", ProducedBy = Tool.Analyzer)] - [ExpectedWarning ("IL3050", "--MethodWithRequires--", ProducedBy = Tool.Analyzer)] + [ExpectedWarning ("IL2026", "--MethodWithRequires--", Tool.Analyzer, "")] + [ExpectedWarning ("IL3002", "--MethodWithRequires--", Tool.Analyzer, "")] + [ExpectedWarning ("IL3050", "--MethodWithRequires--", Tool.Analyzer, "")] () => { var action = new Action (MethodWithRequires); }; } [ExpectedWarning ("IL2026", "--MethodWithRequiresAndReturns--", CompilerGeneratedCode = true)] - [ExpectedWarning ("IL3002", "--MethodWithRequiresAndReturns--", CompilerGeneratedCode = true, ProducedBy = Tool.Analyzer | Tool.NativeAot)] - [ExpectedWarning ("IL3050", "--MethodWithRequiresAndReturns--", CompilerGeneratedCode = true, ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3002", "--MethodWithRequiresAndReturns--", Tool.Analyzer | Tool.NativeAot, "", CompilerGeneratedCode = true)] + [ExpectedWarning ("IL3050", "--MethodWithRequiresAndReturns--", Tool.Analyzer | Tool.NativeAot, "", CompilerGeneratedCode = true)] public static Lazy _default = new Lazy (MethodWithRequiresAndReturns); static void TestLazyDelegate () @@ -1240,8 +1240,8 @@ static void TestDynamicallyAccessedMethod () { Action _ = [ExpectedWarning ("IL2026", "--TypeWithMethodWithRequires.MethodWithRequires--")] - [ExpectedWarning ("IL3002", "--TypeWithMethodWithRequires.MethodWithRequires--", ProducedBy = Tool.NativeAot)] - [ExpectedWarning ("IL3050", "--TypeWithMethodWithRequires.MethodWithRequires--", ProducedBy = Tool.NativeAot)] + [ExpectedWarning ("IL3002", "--TypeWithMethodWithRequires.MethodWithRequires--", Tool.NativeAot, "")] + [ExpectedWarning ("IL3050", "--TypeWithMethodWithRequires.MethodWithRequires--", Tool.NativeAot, "")] () => { typeof (TypeWithMethodWithRequires).RequiresNonPublicMethods (); }; @@ -1330,8 +1330,8 @@ static void TestLdftn () } [ExpectedWarning ("IL2026", "--MethodWithRequiresAndReturns--", CompilerGeneratedCode = true)] - [ExpectedWarning ("IL3002", "--MethodWithRequiresAndReturns--", CompilerGeneratedCode = true, ProducedBy = Tool.Analyzer | Tool.NativeAot)] - [ExpectedWarning ("IL3050", "--MethodWithRequiresAndReturns--", CompilerGeneratedCode = true, ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3002", "--MethodWithRequiresAndReturns--", Tool.Analyzer | Tool.NativeAot, "", CompilerGeneratedCode = true)] + [ExpectedWarning ("IL3050", "--MethodWithRequiresAndReturns--", Tool.Analyzer | Tool.NativeAot, "", CompilerGeneratedCode = true)] public static Lazy _default = new Lazy (MethodWithRequiresAndReturns); static void TestLazyDelegate () @@ -1383,8 +1383,8 @@ static void TestGenericTypeParameterRequirement () } [ExpectedWarning ("IL2026")] - [ExpectedWarning ("IL3002", ProducedBy = Tool.Analyzer | Tool.NativeAot)] - [ExpectedWarning ("IL3050", ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3002", Tool.Analyzer | Tool.NativeAot, "")] + [ExpectedWarning ("IL3050", Tool.Analyzer | Tool.NativeAot, "")] static void TestSuppressionOnLambda () { var lambda = @@ -1397,8 +1397,8 @@ static void TestSuppressionOnLambda () } [ExpectedWarning ("IL2026")] - [ExpectedWarning ("IL3002", ProducedBy = Tool.Analyzer | Tool.NativeAot)] - [ExpectedWarning ("IL3050", ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3002", Tool.Analyzer | Tool.NativeAot, "")] + [ExpectedWarning ("IL3050", Tool.Analyzer | Tool.NativeAot, "")] static void TestSuppressionOnLambdaWithNestedLambda () { var lambda = @@ -1411,9 +1411,9 @@ static void TestSuppressionOnLambdaWithNestedLambda () // an IL reference to the generated lambda method, unlike local functions. // However, we don't make this association, for consistency with local functions. var nestedLambda = - [ExpectedWarning ("IL2026", ProducedBy = Tool.Trimmer | Tool.NativeAot)] - [ExpectedWarning ("IL3002", ProducedBy = Tool.NativeAot | Tool.NativeAot)] - [ExpectedWarning ("IL3050", ProducedBy = Tool.NativeAot | Tool.NativeAot)] + [ExpectedWarning ("IL2026", Tool.Trimmer | Tool.NativeAot, "")] + [ExpectedWarning ("IL3002", Tool.NativeAot | Tool.NativeAot, "")] + [ExpectedWarning ("IL3050", Tool.NativeAot | Tool.NativeAot, "")] () => MethodWithRequires (); }; @@ -1440,8 +1440,8 @@ static void TestSuppressionOnOuterAndLambda () class TestSuppressionOnOuterWithSameName { [ExpectedWarning ("IL2026", nameof (Outer) + "()")] - [ExpectedWarning ("IL3002", nameof (Outer) + "()", ProducedBy = Tool.Analyzer | Tool.NativeAot)] - [ExpectedWarning ("IL3050", nameof (Outer) + "()", ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3002", nameof (Outer) + "()", Tool.Analyzer | Tool.NativeAot, "")] + [ExpectedWarning ("IL3050", nameof (Outer) + "()", Tool.Analyzer | Tool.NativeAot, "")] public static void Test () { Outer (); @@ -1462,8 +1462,8 @@ static void Outer (int i) { var lambda = [ExpectedWarning ("IL2026", "--MethodWithRequires--")] - [ExpectedWarning ("IL3002", ProducedBy = Tool.Analyzer | Tool.NativeAot)] - [ExpectedWarning ("IL3050", ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3002", Tool.Analyzer | Tool.NativeAot, "")] + [ExpectedWarning ("IL3050", Tool.Analyzer | Tool.NativeAot, "")] () => MethodWithRequires (); lambda (); @@ -1503,8 +1503,8 @@ static async void TestIteratorLocalFunctionInAsync () await MethodAsync (); [ExpectedWarning ("IL2026", "--MethodWithRequires--", CompilerGeneratedCode = true)] - [ExpectedWarning ("IL3002", "--MethodWithRequires--", ProducedBy = Tool.Analyzer | Tool.NativeAot, CompilerGeneratedCode = true)] - [ExpectedWarning ("IL3050", "--MethodWithRequires--", ProducedBy = Tool.Analyzer | Tool.NativeAot, CompilerGeneratedCode = true)] + [ExpectedWarning ("IL3002", "--MethodWithRequires--", Tool.Analyzer | Tool.NativeAot, "", CompilerGeneratedCode = true)] + [ExpectedWarning ("IL3050", "--MethodWithRequires--", Tool.Analyzer | Tool.NativeAot, "", CompilerGeneratedCode = true)] IEnumerable LocalFunction () { yield return 0; @@ -1543,8 +1543,8 @@ IEnumerable IteratorLocalFunction () yield return 1; [ExpectedWarning ("IL2026", "--MethodWithRequires--")] - [ExpectedWarning ("IL3002", "--MethodWithRequires--", ProducedBy = Tool.Analyzer | Tool.NativeAot)] - [ExpectedWarning ("IL3050", "--MethodWithRequires--", ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3002", "--MethodWithRequires--", Tool.Analyzer | Tool.NativeAot, "")] + [ExpectedWarning ("IL3050", "--MethodWithRequires--", Tool.Analyzer | Tool.NativeAot, "")] void LocalFunction () => MethodWithRequires (); } } @@ -1561,8 +1561,8 @@ IEnumerable IteratorLocalFunction () } [ExpectedWarning ("IL2026", "--MethodWithRequires--")] - [ExpectedWarning ("IL3002", "--MethodWithRequires--", ProducedBy = Tool.Analyzer | Tool.NativeAot)] - [ExpectedWarning ("IL3050", "--MethodWithRequires--", ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3002", "--MethodWithRequires--", Tool.Analyzer | Tool.NativeAot, "")] + [ExpectedWarning ("IL3050", "--MethodWithRequires--", Tool.Analyzer | Tool.NativeAot, "")] void LocalFunction () => MethodWithRequires (); } @@ -1754,8 +1754,8 @@ static IEnumerable TestDynamicallyAccessedMethodViaGenericMethodParameterIn #endif [ExpectedWarning ("IL2026", "--IteratorLocalFunction--")] - [ExpectedWarning ("IL3002", "--IteratorLocalFunction--", ProducedBy = Tool.Analyzer | Tool.NativeAot)] - [ExpectedWarning ("IL3050", "--IteratorLocalFunction--", ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3002", "--IteratorLocalFunction--", Tool.Analyzer | Tool.NativeAot, "")] + [ExpectedWarning ("IL3050", "--IteratorLocalFunction--", Tool.Analyzer | Tool.NativeAot, "")] static void TestLocalFunctionInIteratorLocalFunction () { IteratorLocalFunction (); @@ -1771,16 +1771,16 @@ IEnumerable IteratorLocalFunction () yield return 1; // Trimmer doesn't try to associate LocalFunction with IteratorLocalFunction - [ExpectedWarning ("IL2026", "--MethodWithRequires--", ProducedBy = Tool.Trimmer | Tool.NativeAot)] - [ExpectedWarning ("IL3002", "--MethodWithRequires--", ProducedBy = Tool.NativeAot)] - [ExpectedWarning ("IL3050", "--MethodWithRequires--", ProducedBy = Tool.NativeAot)] + [ExpectedWarning ("IL2026", "--MethodWithRequires--", Tool.Trimmer | Tool.NativeAot, "")] + [ExpectedWarning ("IL3002", "--MethodWithRequires--", Tool.NativeAot, "")] + [ExpectedWarning ("IL3050", "--MethodWithRequires--", Tool.NativeAot, "")] void LocalFunction () => MethodWithRequires (); } } [ExpectedWarning ("IL2026", "--IteratorLocalFunction--")] - [ExpectedWarning ("IL3002", "--IteratorLocalFunction--", ProducedBy = Tool.Analyzer | Tool.NativeAot)] - [ExpectedWarning ("IL3050", "--IteratorLocalFunction--", ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3002", "--IteratorLocalFunction--", Tool.Analyzer | Tool.NativeAot, "")] + [ExpectedWarning ("IL3050", "--IteratorLocalFunction--", Tool.Analyzer | Tool.NativeAot, "")] static void TestLocalFunctionCalledFromIteratorLocalFunctionAndMethod () { IteratorLocalFunction (); @@ -1798,8 +1798,8 @@ IEnumerable IteratorLocalFunction () } [ExpectedWarning ("IL2026", "--MethodWithRequires--")] - [ExpectedWarning ("IL3002", "--MethodWithRequires--", ProducedBy = Tool.Analyzer | Tool.NativeAot)] - [ExpectedWarning ("IL3050", "--MethodWithRequires--", ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3002", "--MethodWithRequires--", Tool.Analyzer | Tool.NativeAot, "")] + [ExpectedWarning ("IL3050", "--MethodWithRequires--", Tool.Analyzer | Tool.NativeAot, "")] void LocalFunction () => MethodWithRequires (); } @@ -1847,8 +1847,8 @@ static async void TestAsyncOnlyReferencedViaReflectionWhichShouldSuppress () } [ExpectedWarning ("IL2026", CompilerGeneratedCode = true)] - [ExpectedWarning ("IL3002", ProducedBy = Tool.Analyzer | Tool.NativeAot, CompilerGeneratedCode = true)] - [ExpectedWarning ("IL3050", ProducedBy = Tool.Analyzer | Tool.NativeAot, CompilerGeneratedCode = true)] + [ExpectedWarning ("IL3002", Tool.Analyzer | Tool.NativeAot, "", CompilerGeneratedCode = true)] + [ExpectedWarning ("IL3050", Tool.Analyzer | Tool.NativeAot, "", CompilerGeneratedCode = true)] static IEnumerable TestIteratorOnlyReferencedViaReflectionWhichShouldWarn () { yield return 0; @@ -1856,8 +1856,8 @@ static IEnumerable TestIteratorOnlyReferencedViaReflectionWhichShouldWarn ( } [ExpectedWarning ("IL2026", CompilerGeneratedCode = true)] - [ExpectedWarning ("IL3002", ProducedBy = Tool.Analyzer | Tool.NativeAot, CompilerGeneratedCode = true)] - [ExpectedWarning ("IL3050", ProducedBy = Tool.Analyzer | Tool.NativeAot, CompilerGeneratedCode = true)] + [ExpectedWarning ("IL3002", Tool.Analyzer | Tool.NativeAot, "", CompilerGeneratedCode = true)] + [ExpectedWarning ("IL3050", Tool.Analyzer | Tool.NativeAot, "", CompilerGeneratedCode = true)] static async void TestAsyncOnlyReferencedViaReflectionWhichShouldWarn () { await MethodAsync (); @@ -1865,26 +1865,24 @@ static async void TestAsyncOnlyReferencedViaReflectionWhichShouldWarn () } [ExpectedWarning ("IL2026", "--TestIteratorOnlyReferencedViaReflectionWhichShouldSuppress--")] - [ExpectedWarning ("IL3002", "--TestIteratorOnlyReferencedViaReflectionWhichShouldSuppress--", ProducedBy = Tool.NativeAot)] - [ExpectedWarning ("IL3050", "--TestIteratorOnlyReferencedViaReflectionWhichShouldSuppress--", ProducedBy = Tool.NativeAot)] + [ExpectedWarning ("IL3002", "--TestIteratorOnlyReferencedViaReflectionWhichShouldSuppress--", Tool.NativeAot, "")] + [ExpectedWarning ("IL3050", "--TestIteratorOnlyReferencedViaReflectionWhichShouldSuppress--", Tool.NativeAot, "")] [ExpectedWarning ("IL2026", "--TestAsyncOnlyReferencedViaReflectionWhichShouldSuppress--")] - [ExpectedWarning ("IL3002", "--TestAsyncOnlyReferencedViaReflectionWhichShouldSuppress--", ProducedBy = Tool.NativeAot)] - [ExpectedWarning ("IL3050", "--TestAsyncOnlyReferencedViaReflectionWhichShouldSuppress--", ProducedBy = Tool.NativeAot)] - [ExpectedWarning ("IL2118", nameof (StateMachinesOnlyReferencedViaReflection), "<" + nameof (TestAsyncOnlyReferencedViaReflectionWhichShouldWarn) + ">", "MoveNext()", - ProducedBy = Tool.Trimmer)] - [ExpectedWarning ("IL2118", nameof (StateMachinesOnlyReferencedViaReflection), "<" + nameof (TestIteratorOnlyReferencedViaReflectionWhichShouldWarn) + ">", "MoveNext()", - ProducedBy = Tool.Trimmer)] + [ExpectedWarning ("IL3002", "--TestAsyncOnlyReferencedViaReflectionWhichShouldSuppress--", Tool.NativeAot, "")] + [ExpectedWarning ("IL3050", "--TestAsyncOnlyReferencedViaReflectionWhichShouldSuppress--", Tool.NativeAot, "")] + [ExpectedWarning ("IL2118", [nameof (StateMachinesOnlyReferencedViaReflection), "<" + nameof (TestAsyncOnlyReferencedViaReflectionWhichShouldWarn) + ">", "MoveNext()"], Tool.Trimmer, "")] + [ExpectedWarning ("IL2118", [nameof (StateMachinesOnlyReferencedViaReflection), "<" + nameof (TestIteratorOnlyReferencedViaReflectionWhichShouldWarn) + ">", "MoveNext()"], Tool.Trimmer, "")] static void TestAll () { typeof (StateMachinesOnlyReferencedViaReflection).RequiresAll (); } [ExpectedWarning ("IL2026", "--TestIteratorOnlyReferencedViaReflectionWhichShouldSuppress--")] - [ExpectedWarning ("IL3002", "--TestIteratorOnlyReferencedViaReflectionWhichShouldSuppress--", ProducedBy = Tool.NativeAot)] - [ExpectedWarning ("IL3050", "--TestIteratorOnlyReferencedViaReflectionWhichShouldSuppress--", ProducedBy = Tool.NativeAot)] + [ExpectedWarning ("IL3002", "--TestIteratorOnlyReferencedViaReflectionWhichShouldSuppress--", Tool.NativeAot, "")] + [ExpectedWarning ("IL3050", "--TestIteratorOnlyReferencedViaReflectionWhichShouldSuppress--", Tool.NativeAot, "")] [ExpectedWarning ("IL2026", "--TestAsyncOnlyReferencedViaReflectionWhichShouldSuppress--")] - [ExpectedWarning ("IL3002", "--TestAsyncOnlyReferencedViaReflectionWhichShouldSuppress--", ProducedBy = Tool.NativeAot)] - [ExpectedWarning ("IL3050", "--TestAsyncOnlyReferencedViaReflectionWhichShouldSuppress--", ProducedBy = Tool.NativeAot)] + [ExpectedWarning ("IL3002", "--TestAsyncOnlyReferencedViaReflectionWhichShouldSuppress--", Tool.NativeAot, "")] + [ExpectedWarning ("IL3050", "--TestAsyncOnlyReferencedViaReflectionWhichShouldSuppress--", Tool.NativeAot, "")] // NonPublicMethods doesn't warn for members emitted into compiler-generated state machine types. static void TestNonPublicMethods () { @@ -1901,8 +1899,8 @@ public static void Test () class LocalFunctionsReferencedViaReflection { [ExpectedWarning ("IL2026", "--TestLocalFunctionWithRequires--")] - [ExpectedWarning ("IL3002", "--TestLocalFunctionWithRequires--", ProducedBy = Tool.Analyzer | Tool.NativeAot)] - [ExpectedWarning ("IL3050", "--TestLocalFunctionWithRequires--", ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3002", "--TestLocalFunctionWithRequires--", Tool.Analyzer | Tool.NativeAot, "")] + [ExpectedWarning ("IL3050", "--TestLocalFunctionWithRequires--", Tool.Analyzer | Tool.NativeAot, "")] static void TestLocalFunctionWithRequires () { LocalFunction (); @@ -1922,8 +1920,8 @@ static void TestLocalFunctionWithRequiresOnlyAccessedViaReflection () } [ExpectedWarning ("IL2026", "LocalFunction")] - [ExpectedWarning ("IL3002", "LocalFunction", ProducedBy = Tool.Analyzer | Tool.NativeAot)] - [ExpectedWarning ("IL3050", "LocalFunction", ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3002", "LocalFunction", Tool.Analyzer | Tool.NativeAot, "")] + [ExpectedWarning ("IL3050", "LocalFunction", Tool.Analyzer | Tool.NativeAot, "")] static void TestLocalFunctionWithClosureWithRequires (int p = 0) { LocalFunction (); @@ -1974,16 +1972,15 @@ void LocalFunction () // Warnings for Reflection access to methods with Requires [ExpectedWarning ("IL2026", "--TestLocalFunctionInMethodWithRequires--")] - [ExpectedWarning ("IL3002", "--TestLocalFunctionInMethodWithRequires--", ProducedBy = Tool.NativeAot)] - [ExpectedWarning ("IL3050", "--TestLocalFunctionInMethodWithRequires--", ProducedBy = Tool.NativeAot)] + [ExpectedWarning ("IL3002", "--TestLocalFunctionInMethodWithRequires--", Tool.NativeAot, "")] + [ExpectedWarning ("IL3050", "--TestLocalFunctionInMethodWithRequires--", Tool.NativeAot, "")] [ExpectedWarning ("IL2026", "--TestLocalFunctionWithClosureInMethodWithRequires--")] - [ExpectedWarning ("IL3002", "--TestLocalFunctionWithClosureInMethodWithRequires--", ProducedBy = Tool.NativeAot)] - [ExpectedWarning ("IL3050", "--TestLocalFunctionWithClosureInMethodWithRequires--", ProducedBy = Tool.NativeAot)] + [ExpectedWarning ("IL3002", "--TestLocalFunctionWithClosureInMethodWithRequires--", Tool.NativeAot, "")] + [ExpectedWarning ("IL3050", "--TestLocalFunctionWithClosureInMethodWithRequires--", Tool.NativeAot, "")] [ExpectedWarning ("IL2026", "--TestLocalFunctionInMethodWithRequiresOnlyAccessedViaReflection--")] - [ExpectedWarning ("IL3002", "--TestLocalFunctionInMethodWithRequiresOnlyAccessedViaReflection--", ProducedBy = Tool.NativeAot)] - [ExpectedWarning ("IL3050", "--TestLocalFunctionInMethodWithRequiresOnlyAccessedViaReflection--", ProducedBy = Tool.NativeAot)] - [ExpectedWarning ("IL2118", nameof (LocalFunctionsReferencedViaReflection), nameof (TestLocalFunctionInMethodWithRequiresOnlyAccessedViaReflection), - ProducedBy = Tool.Trimmer)] + [ExpectedWarning ("IL3002", "--TestLocalFunctionInMethodWithRequiresOnlyAccessedViaReflection--", Tool.NativeAot, "")] + [ExpectedWarning ("IL3050", "--TestLocalFunctionInMethodWithRequiresOnlyAccessedViaReflection--", Tool.NativeAot, "")] + [ExpectedWarning ("IL2118", nameof (LocalFunctionsReferencedViaReflection), nameof (TestLocalFunctionInMethodWithRequiresOnlyAccessedViaReflection), Tool.Trimmer, "")] static void TestAll () { typeof (LocalFunctionsReferencedViaReflection).RequiresAll (); @@ -1991,16 +1988,15 @@ static void TestAll () // Warnings for Reflection access to methods with Requires [ExpectedWarning ("IL2026", "--TestLocalFunctionInMethodWithRequires--")] - [ExpectedWarning ("IL3002", "--TestLocalFunctionInMethodWithRequires--", ProducedBy = Tool.NativeAot)] - [ExpectedWarning ("IL3050", "--TestLocalFunctionInMethodWithRequires--", ProducedBy = Tool.NativeAot)] + [ExpectedWarning ("IL3002", "--TestLocalFunctionInMethodWithRequires--", Tool.NativeAot, "")] + [ExpectedWarning ("IL3050", "--TestLocalFunctionInMethodWithRequires--", Tool.NativeAot, "")] [ExpectedWarning ("IL2026", "--TestLocalFunctionWithClosureInMethodWithRequires--")] - [ExpectedWarning ("IL3002", "--TestLocalFunctionWithClosureInMethodWithRequires--", ProducedBy = Tool.NativeAot)] - [ExpectedWarning ("IL3050", "--TestLocalFunctionWithClosureInMethodWithRequires--", ProducedBy = Tool.NativeAot)] + [ExpectedWarning ("IL3002", "--TestLocalFunctionWithClosureInMethodWithRequires--", Tool.NativeAot, "")] + [ExpectedWarning ("IL3050", "--TestLocalFunctionWithClosureInMethodWithRequires--", Tool.NativeAot, "")] [ExpectedWarning ("IL2026", "--TestLocalFunctionInMethodWithRequiresOnlyAccessedViaReflection--")] - [ExpectedWarning ("IL3002", "--TestLocalFunctionInMethodWithRequiresOnlyAccessedViaReflection--", ProducedBy = Tool.NativeAot)] - [ExpectedWarning ("IL3050", "--TestLocalFunctionInMethodWithRequiresOnlyAccessedViaReflection--", ProducedBy = Tool.NativeAot)] - [ExpectedWarning ("IL2118", nameof (LocalFunctionsReferencedViaReflection), "<" + nameof (TestLocalFunctionInMethodWithRequiresOnlyAccessedViaReflection) + ">", - ProducedBy = Tool.Trimmer)] + [ExpectedWarning ("IL3002", "--TestLocalFunctionInMethodWithRequiresOnlyAccessedViaReflection--", Tool.NativeAot, "")] + [ExpectedWarning ("IL3050", "--TestLocalFunctionInMethodWithRequiresOnlyAccessedViaReflection--", Tool.NativeAot, "")] + [ExpectedWarning ("IL2118", nameof (LocalFunctionsReferencedViaReflection), "<" + nameof (TestLocalFunctionInMethodWithRequiresOnlyAccessedViaReflection) + ">", Tool.Trimmer, "")] static void TestNonPublicMethods () { typeof (LocalFunctionsReferencedViaReflection).RequiresNonPublicMethods (); @@ -2016,8 +2012,8 @@ public static void Test () class LambdasReferencedViaReflection { [ExpectedWarning ("IL2026", "--TestLambdaWithRequires--")] - [ExpectedWarning ("IL3002", "--TestLambdaWithRequires--", ProducedBy = Tool.Analyzer | Tool.NativeAot)] - [ExpectedWarning ("IL3050", "--TestLambdaWithRequires--", ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3002", "--TestLambdaWithRequires--", Tool.Analyzer | Tool.NativeAot, "")] + [ExpectedWarning ("IL3050", "--TestLambdaWithRequires--", Tool.Analyzer | Tool.NativeAot, "")] static void TestLambdaWithRequires () { var lambda = @@ -2030,8 +2026,8 @@ static void TestLambdaWithRequires () } [ExpectedWarning ("IL2026", "Lambda")] - [ExpectedWarning ("IL3002", "Lambda", ProducedBy = Tool.Analyzer | Tool.NativeAot)] - [ExpectedWarning ("IL3050", "Lambda", ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3002", "Lambda", Tool.Analyzer | Tool.NativeAot, "")] + [ExpectedWarning ("IL3050", "Lambda", Tool.Analyzer | Tool.NativeAot, "")] static void TestLambdaWithClosureWithRequires (int p = 0) { var lambda = @@ -2071,11 +2067,11 @@ static void TestLambdaWithClosureInMethodWithRequires (int p = 0) // Warnings for Reflection access to methods with Requires [ExpectedWarning ("IL2026", "--TestLambdaInMethodWithRequires--")] - [ExpectedWarning ("IL3002", "--TestLambdaInMethodWithRequires--", ProducedBy = Tool.NativeAot)] - [ExpectedWarning ("IL3050", "--TestLambdaInMethodWithRequires--", ProducedBy = Tool.NativeAot)] + [ExpectedWarning ("IL3002", "--TestLambdaInMethodWithRequires--", Tool.NativeAot, "")] + [ExpectedWarning ("IL3050", "--TestLambdaInMethodWithRequires--", Tool.NativeAot, "")] [ExpectedWarning ("IL2026", "--TestLambdaWithClosureInMethodWithRequires--")] - [ExpectedWarning ("IL3002", "--TestLambdaWithClosureInMethodWithRequires--", ProducedBy = Tool.NativeAot)] - [ExpectedWarning ("IL3050", "--TestLambdaWithClosureInMethodWithRequires--", ProducedBy = Tool.NativeAot)] + [ExpectedWarning ("IL3002", "--TestLambdaWithClosureInMethodWithRequires--", Tool.NativeAot, "")] + [ExpectedWarning ("IL3050", "--TestLambdaWithClosureInMethodWithRequires--", Tool.NativeAot, "")] static void TestAll () { typeof (LambdasReferencedViaReflection).RequiresAll (); @@ -2083,11 +2079,11 @@ static void TestAll () // Warnings for Reflection access to methods with Requires [ExpectedWarning ("IL2026", "--TestLambdaInMethodWithRequires--")] - [ExpectedWarning ("IL3002", "--TestLambdaInMethodWithRequires--", ProducedBy = Tool.NativeAot)] - [ExpectedWarning ("IL3050", "--TestLambdaInMethodWithRequires--", ProducedBy = Tool.NativeAot)] + [ExpectedWarning ("IL3002", "--TestLambdaInMethodWithRequires--", Tool.NativeAot, "")] + [ExpectedWarning ("IL3050", "--TestLambdaInMethodWithRequires--", Tool.NativeAot, "")] [ExpectedWarning ("IL2026", "--TestLambdaWithClosureInMethodWithRequires--")] - [ExpectedWarning ("IL3002", "--TestLambdaWithClosureInMethodWithRequires--", ProducedBy = Tool.NativeAot)] - [ExpectedWarning ("IL3050", "--TestLambdaWithClosureInMethodWithRequires--", ProducedBy = Tool.NativeAot)] + [ExpectedWarning ("IL3002", "--TestLambdaWithClosureInMethodWithRequires--", Tool.NativeAot, "")] + [ExpectedWarning ("IL3050", "--TestLambdaWithClosureInMethodWithRequires--", Tool.NativeAot, "")] static void TestNonPublicMethods () { typeof (LambdasReferencedViaReflection).RequiresNonPublicMethods (); @@ -2123,8 +2119,8 @@ static async Task AsyncMethodCallingRequires (Type type) } [ExpectedWarning ("IL2026", "ParentSuppression")] - [ExpectedWarning ("IL3002", "ParentSuppression", ProducedBy = Tool.Analyzer | Tool.NativeAot)] - [ExpectedWarning ("IL3050", "ParentSuppression", ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3002", "ParentSuppression", Tool.Analyzer | Tool.NativeAot, "")] + [ExpectedWarning ("IL3050", "ParentSuppression", Tool.Analyzer | Tool.NativeAot, "")] public static void Test () { AsyncMethodCallingRequires (typeof (object)); @@ -2152,8 +2148,8 @@ static async Task AsyncMethodCallingRequires () } [ExpectedWarning ("IL2026", "ParentSuppression")] - [ExpectedWarning ("IL3002", "ParentSuppression", ProducedBy = Tool.Analyzer | Tool.NativeAot)] - [ExpectedWarning ("IL3050", "ParentSuppression", ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3002", "ParentSuppression", Tool.Analyzer | Tool.NativeAot, "")] + [ExpectedWarning ("IL3050", "ParentSuppression", Tool.Analyzer | Tool.NativeAot, "")] public static void Test () { AsyncMethodCallingRequires (); @@ -2192,8 +2188,8 @@ static async IAsyncEnumerable CreateAsync () } [ExpectedWarning ("IL2026", "ParentSuppression")] - [ExpectedWarning ("IL3002", "ParentSuppression", ProducedBy = Tool.Analyzer | Tool.NativeAot)] - [ExpectedWarning ("IL3050", "ParentSuppression", ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3002", "ParentSuppression", Tool.Analyzer | Tool.NativeAot, "")] + [ExpectedWarning ("IL3050", "ParentSuppression", Tool.Analyzer | Tool.NativeAot, "")] public static void Test () { AsyncEnumMethodCallingRequires (); diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/RequiresCapability/RequiresOnAttribute.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/RequiresCapability/RequiresOnAttribute.cs index 8710ed0e45cf82..a8f5ab60dd0578 100644 --- a/src/tools/illink/test/Mono.Linker.Tests.Cases/RequiresCapability/RequiresOnAttribute.cs +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/RequiresCapability/RequiresOnAttribute.cs @@ -61,16 +61,16 @@ public bool PropertyWhichRequires { } [ExpectedWarning ("IL2026", "--AttributeWhichRequiresAttribute.ctor--")] - [ExpectedWarning ("IL3002", "--AttributeWhichRequiresAttribute.ctor--", ProducedBy = Tool.Analyzer | Tool.NativeAot)] - [ExpectedWarning ("IL3050", "--AttributeWhichRequiresAttribute.ctor--", ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3002", "--AttributeWhichRequiresAttribute.ctor--", Tool.Analyzer | Tool.NativeAot, "")] + [ExpectedWarning ("IL3050", "--AttributeWhichRequiresAttribute.ctor--", Tool.Analyzer | Tool.NativeAot, "")] class GenericTypeWithAttributedParameter<[AttributeWhichRequires] T> { public static void TestMethod () { } } [ExpectedWarning ("IL2026", "--AttributeWhichRequiresAttribute.ctor--")] - [ExpectedWarning ("IL3002", "--AttributeWhichRequiresAttribute.ctor--", ProducedBy = Tool.Analyzer | Tool.NativeAot)] - [ExpectedWarning ("IL3050", "--AttributeWhichRequiresAttribute.ctor--", ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3002", "--AttributeWhichRequiresAttribute.ctor--", Tool.Analyzer | Tool.NativeAot, "")] + [ExpectedWarning ("IL3050", "--AttributeWhichRequiresAttribute.ctor--", Tool.Analyzer | Tool.NativeAot, "")] static void GenericMethodWithAttributedParameter<[AttributeWhichRequires] T> () { } static void TestRequiresOnAttributeOnGenericParameter () @@ -80,11 +80,11 @@ static void TestRequiresOnAttributeOnGenericParameter () } [ExpectedWarning ("IL2026", "--AttributeWhichRequiresAttribute.ctor--")] - [ExpectedWarning ("IL3002", "--AttributeWhichRequiresAttribute.ctor--", ProducedBy = Tool.Analyzer | Tool.NativeAot)] - [ExpectedWarning ("IL3050", "--AttributeWhichRequiresAttribute.ctor--", ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3002", "--AttributeWhichRequiresAttribute.ctor--", Tool.Analyzer | Tool.NativeAot, "")] + [ExpectedWarning ("IL3050", "--AttributeWhichRequiresAttribute.ctor--", Tool.Analyzer | Tool.NativeAot, "")] [ExpectedWarning ("IL2026", "--AttributeWhichRequiresOnPropertyAttribute.PropertyWhichRequires--")] - [ExpectedWarning ("IL3002", "--AttributeWhichRequiresOnPropertyAttribute.PropertyWhichRequires--", ProducedBy = Tool.Analyzer | Tool.NativeAot)] - [ExpectedWarning ("IL3050", "--AttributeWhichRequiresOnPropertyAttribute.PropertyWhichRequires--", ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3002", "--AttributeWhichRequiresOnPropertyAttribute.PropertyWhichRequires--", Tool.Analyzer | Tool.NativeAot, "")] + [ExpectedWarning ("IL3050", "--AttributeWhichRequiresOnPropertyAttribute.PropertyWhichRequires--", Tool.Analyzer | Tool.NativeAot, "")] [AttributeWhichRequires] [AttributeWhichRequiresOnProperty (PropertyWhichRequires = true)] class TypeWithAttributeWhichRequires @@ -92,31 +92,31 @@ class TypeWithAttributeWhichRequires } [ExpectedWarning ("IL2026", "--AttributeWhichRequiresAttribute.ctor--")] - [ExpectedWarning ("IL3002", "--AttributeWhichRequiresAttribute.ctor--", ProducedBy = Tool.Analyzer | Tool.NativeAot)] - [ExpectedWarning ("IL3050", "--AttributeWhichRequiresAttribute.ctor--", ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3002", "--AttributeWhichRequiresAttribute.ctor--", Tool.Analyzer | Tool.NativeAot, "")] + [ExpectedWarning ("IL3050", "--AttributeWhichRequiresAttribute.ctor--", Tool.Analyzer | Tool.NativeAot, "")] [ExpectedWarning ("IL2026", "--AttributeWhichRequiresOnPropertyAttribute.PropertyWhichRequires--")] - [ExpectedWarning ("IL3002", "--AttributeWhichRequiresOnPropertyAttribute.PropertyWhichRequires--", ProducedBy = Tool.Analyzer | Tool.NativeAot)] - [ExpectedWarning ("IL3050", "--AttributeWhichRequiresOnPropertyAttribute.PropertyWhichRequires--", ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3002", "--AttributeWhichRequiresOnPropertyAttribute.PropertyWhichRequires--", Tool.Analyzer | Tool.NativeAot, "")] + [ExpectedWarning ("IL3050", "--AttributeWhichRequiresOnPropertyAttribute.PropertyWhichRequires--", Tool.Analyzer | Tool.NativeAot, "")] [AttributeWhichRequires] [AttributeWhichRequiresOnProperty (PropertyWhichRequires = true)] static void MethodWithAttributeWhichRequires () { } [ExpectedWarning ("IL2026", "--AttributeWhichRequiresAttribute.ctor--")] - [ExpectedWarning ("IL3002", "--AttributeWhichRequiresAttribute.ctor--", ProducedBy = Tool.Analyzer | Tool.NativeAot)] - [ExpectedWarning ("IL3050", "--AttributeWhichRequiresAttribute.ctor--", ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3002", "--AttributeWhichRequiresAttribute.ctor--", Tool.Analyzer | Tool.NativeAot, "")] + [ExpectedWarning ("IL3050", "--AttributeWhichRequiresAttribute.ctor--", Tool.Analyzer | Tool.NativeAot, "")] [ExpectedWarning ("IL2026", "--AttributeWhichRequiresOnPropertyAttribute.PropertyWhichRequires--")] - [ExpectedWarning ("IL3002", "--AttributeWhichRequiresOnPropertyAttribute.PropertyWhichRequires--", ProducedBy = Tool.Analyzer | Tool.NativeAot)] - [ExpectedWarning ("IL3050", "--AttributeWhichRequiresOnPropertyAttribute.PropertyWhichRequires--", ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3002", "--AttributeWhichRequiresOnPropertyAttribute.PropertyWhichRequires--", Tool.Analyzer | Tool.NativeAot, "")] + [ExpectedWarning ("IL3050", "--AttributeWhichRequiresOnPropertyAttribute.PropertyWhichRequires--", Tool.Analyzer | Tool.NativeAot, "")] [AttributeWhichRequires] [AttributeWhichRequiresOnProperty (PropertyWhichRequires = true)] static int _fieldWithAttributeWhichRequires; [ExpectedWarning ("IL2026", "--AttributeWhichRequiresAttribute.ctor--")] - [ExpectedWarning ("IL3002", "--AttributeWhichRequiresAttribute.ctor--", ProducedBy = Tool.Analyzer | Tool.NativeAot)] - [ExpectedWarning ("IL3050", "--AttributeWhichRequiresAttribute.ctor--", ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3002", "--AttributeWhichRequiresAttribute.ctor--", Tool.Analyzer | Tool.NativeAot, "")] + [ExpectedWarning ("IL3050", "--AttributeWhichRequiresAttribute.ctor--", Tool.Analyzer | Tool.NativeAot, "")] [ExpectedWarning ("IL2026", "--AttributeWhichRequiresOnPropertyAttribute.PropertyWhichRequires--")] - [ExpectedWarning ("IL3002", "--AttributeWhichRequiresOnPropertyAttribute.PropertyWhichRequires--", ProducedBy = Tool.Analyzer | Tool.NativeAot)] - [ExpectedWarning ("IL3050", "--AttributeWhichRequiresOnPropertyAttribute.PropertyWhichRequires--", ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3002", "--AttributeWhichRequiresOnPropertyAttribute.PropertyWhichRequires--", Tool.Analyzer | Tool.NativeAot, "")] + [ExpectedWarning ("IL3050", "--AttributeWhichRequiresOnPropertyAttribute.PropertyWhichRequires--", Tool.Analyzer | Tool.NativeAot, "")] [AttributeWhichRequires] [AttributeWhichRequiresOnProperty (PropertyWhichRequires = true)] static bool PropertyWithAttributeWhichRequires { get; set; } @@ -129,8 +129,8 @@ static void MethodWithAttributeWhichRequires () { } static void MethodWhichRequiresWithAttributeWhichRequires () { } [ExpectedWarning ("IL2026", "--MethodWhichRequiresWithAttributeWhichRequires--")] - [ExpectedWarning ("IL3002", "--MethodWhichRequiresWithAttributeWhichRequires--", ProducedBy = Tool.Analyzer | Tool.NativeAot)] - [ExpectedWarning ("IL3050", "--MethodWhichRequiresWithAttributeWhichRequires--", ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3002", "--MethodWhichRequiresWithAttributeWhichRequires--", Tool.Analyzer | Tool.NativeAot, "")] + [ExpectedWarning ("IL3050", "--MethodWhichRequiresWithAttributeWhichRequires--", Tool.Analyzer | Tool.NativeAot, "")] static void TestMethodWhichRequiresWithAttributeWhichRequires () { MethodWhichRequiresWithAttributeWhichRequires (); @@ -152,8 +152,8 @@ public void MethodWhichRequires () { } } [ExpectedWarning ("IL2026", "--TypeWithMethodWhichRequires--")] - [ExpectedWarning ("IL3002", "--TypeWithMethodWhichRequires--", ProducedBy = Tool.NativeAot)] - [ExpectedWarning ("IL3050", "--TypeWithMethodWhichRequires--", ProducedBy = Tool.NativeAot)] + [ExpectedWarning ("IL3002", "--TypeWithMethodWhichRequires--", Tool.NativeAot, "")] + [ExpectedWarning ("IL3050", "--TypeWithMethodWhichRequires--", Tool.NativeAot, "")] [AttributeWhichMarksPublicMethods (typeof(TypeWithMethodWhichRequires))] static void ShouldWarn() { diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/RequiresCapability/RequiresOnClass.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/RequiresCapability/RequiresOnClass.cs index f1faf7684750f3..dc9a49597e7d9b 100644 --- a/src/tools/illink/test/Mono.Linker.Tests.Cases/RequiresCapability/RequiresOnClass.cs +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/RequiresCapability/RequiresOnClass.cs @@ -59,7 +59,7 @@ public static void NestedStaticMethod () { } // This warning doesn't get suppressed since the declaring type NestedClass is not annotated with Requires [ExpectedWarning ("IL2026", "RequiresOnClass.RequiresOnMethod.MethodWithRequires()", "MethodWithRequires")] - [ExpectedWarning ("IL3050", "RequiresOnClass.RequiresOnMethod.MethodWithRequires()", "MethodWithRequires", ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3050", "RequiresOnClass.RequiresOnMethod.MethodWithRequires()", "MethodWithRequires", Tool.Analyzer | Tool.NativeAot, "")] public static void CallMethodWithRequires () => RequiresOnMethod.MethodWithRequires (); } @@ -101,7 +101,7 @@ private class DerivedWithoutRequires : ClassWithRequires { // This method contains implicit call to ClassWithRequires.ctor() [ExpectedWarning ("IL2026")] - [ExpectedWarning ("IL3050", ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3050", Tool.Analyzer | Tool.NativeAot, "")] public DerivedWithoutRequires () { } public static void StaticMethodInInheritedClass () { } @@ -155,7 +155,7 @@ static StaticCtor () } [ExpectedWarning ("IL2026", "RequiresOnClass.StaticCtor.StaticCtor()", "Message for --StaticCtor--")] - [ExpectedWarning ("IL3050", "RequiresOnClass.StaticCtor.StaticCtor()", "Message for --StaticCtor--", ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3050", "RequiresOnClass.StaticCtor.StaticCtor()", "Message for --StaticCtor--", Tool.Analyzer | Tool.NativeAot, "")] static void TestStaticCctorRequires () { _ = new StaticCtor (); @@ -174,14 +174,14 @@ static StaticCtorTriggeredByFieldAccess () } [ExpectedWarning ("IL2026", "StaticCtorTriggeredByFieldAccess.field", "Message for --StaticCtorTriggeredByFieldAccess--")] - [ExpectedWarning ("IL3050", "StaticCtorTriggeredByFieldAccess.field", "Message for --StaticCtorTriggeredByFieldAccess--", ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3050", "StaticCtorTriggeredByFieldAccess.field", "Message for --StaticCtorTriggeredByFieldAccess--", Tool.Analyzer | Tool.NativeAot, "")] static void TestStaticCtorMarkingIsTriggeredByFieldAccessWrite () { StaticCtorTriggeredByFieldAccess.field = 1; } [ExpectedWarning ("IL2026", "StaticCtorTriggeredByFieldAccess.field", "Message for --StaticCtorTriggeredByFieldAccess--")] - [ExpectedWarning ("IL3050", "StaticCtorTriggeredByFieldAccess.field", "Message for --StaticCtorTriggeredByFieldAccess--", ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3050", "StaticCtorTriggeredByFieldAccess.field", "Message for --StaticCtorTriggeredByFieldAccess--", Tool.Analyzer | Tool.NativeAot, "")] static void TestStaticCtorMarkingTriggeredOnSecondAccessWrite () { StaticCtorTriggeredByFieldAccess.field = 2; @@ -209,7 +209,7 @@ class StaticCCtorTriggeredByFieldAccessRead } [ExpectedWarning ("IL2026", "StaticCCtorTriggeredByFieldAccessRead.field", "Message for --StaticCCtorTriggeredByFieldAccessRead--")] - [ExpectedWarning ("IL3050", "StaticCCtorTriggeredByFieldAccessRead.field", "Message for --StaticCCtorTriggeredByFieldAccessRead--", ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3050", "StaticCCtorTriggeredByFieldAccessRead.field", "Message for --StaticCCtorTriggeredByFieldAccessRead--", Tool.Analyzer | Tool.NativeAot, "")] static void TestStaticCtorMarkingIsTriggeredByFieldAccessRead () { var _ = StaticCCtorTriggeredByFieldAccessRead.field; @@ -229,7 +229,7 @@ public void TriggerStaticCtorMarking () } [ExpectedWarning ("IL2026", "StaticCtorTriggeredByCtorCalls.StaticCtorTriggeredByCtorCalls()")] - [ExpectedWarning ("IL3050", "StaticCtorTriggeredByCtorCalls.StaticCtorTriggeredByCtorCalls()", ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3050", "StaticCtorTriggeredByCtorCalls.StaticCtorTriggeredByCtorCalls()", Tool.Analyzer | Tool.NativeAot, "")] static void TestStaticCtorTriggeredByCtorCall () { new StaticCtorTriggeredByCtorCalls (); @@ -243,7 +243,7 @@ class ClassWithInstanceField } [ExpectedWarning ("IL2026", "ClassWithInstanceField.ClassWithInstanceField()")] - [ExpectedWarning ("IL3050", "ClassWithInstanceField.ClassWithInstanceField()", ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3050", "ClassWithInstanceField.ClassWithInstanceField()", Tool.Analyzer | Tool.NativeAot, "")] static void TestInstanceFieldCallDontWarn () { ClassWithInstanceField instance = new ClassWithInstanceField (); @@ -260,7 +260,7 @@ public ClassWithInstanceFieldWhichInitsDangerousClass () { } } [ExpectedWarning ("IL2026", "Calling the constructor is dangerous")] - [ExpectedWarning ("IL3050", "Calling the constructor is dangerous", ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3050", "Calling the constructor is dangerous", Tool.Analyzer | Tool.NativeAot, "")] static void TestInstanceFieldSuppression () { _ = new ClassWithInstanceFieldWhichInitsDangerousClass (); @@ -310,7 +310,7 @@ public class DerivedNestedClass : ClassWithRequires { // This method contains implicit call to ClassWithRequires.ctor() [ExpectedWarning ("IL2026")] - [ExpectedWarning ("IL3050", ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3050", Tool.Analyzer | Tool.NativeAot, "")] public DerivedNestedClass () { } public static void NestedStaticMethod () { } @@ -389,14 +389,14 @@ public int Method (int a) } [ExpectedWarning ("IL2026", "RequiresOnClass.ClassWithRequires.StaticMethod()", "--ClassWithRequires--")] - [ExpectedWarning ("IL3050", "RequiresOnClass.ClassWithRequires.StaticMethod()", "--ClassWithRequires--", ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3050", "RequiresOnClass.ClassWithRequires.StaticMethod()", "--ClassWithRequires--", Tool.Analyzer | Tool.NativeAot, "")] static void TestRequiresInClassAccessedByStaticMethod () { ClassWithRequires.StaticMethod (); } [ExpectedWarning ("IL2026", "RequiresOnClass.ClassWithRequires", "--ClassWithRequires--")] - [ExpectedWarning ("IL3050", "RequiresOnClass.ClassWithRequires", "--ClassWithRequires--", ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3050", "RequiresOnClass.ClassWithRequires", "--ClassWithRequires--", Tool.Analyzer | Tool.NativeAot, "")] static void TestRequiresInClassAccessedByCctor () { var classObject = new ClassWithRequires (); @@ -408,12 +408,12 @@ static void TestRequiresInParentClassAccesedByStaticMethod () } [ExpectedWarning ("IL2026", "RequiresOnClass.ClassWithRequires.StaticMethod()", "--ClassWithRequires--")] - [ExpectedWarning ("IL3050", "RequiresOnClass.ClassWithRequires.StaticMethod()", "--ClassWithRequires--", ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3050", "RequiresOnClass.ClassWithRequires.StaticMethod()", "--ClassWithRequires--", Tool.Analyzer | Tool.NativeAot, "")] // Although we suppress the warning from RequiresOnMethod.MethodWithRequires () we still get a warning because we call CallRequiresMethod() which is an static method on a type with RUC [ExpectedWarning ("IL2026", "RequiresOnClass.ClassWithRequires.CallMethodWithRequires()", "--ClassWithRequires--")] - [ExpectedWarning ("IL3050", "RequiresOnClass.ClassWithRequires.CallMethodWithRequires()", "--ClassWithRequires--", ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3050", "RequiresOnClass.ClassWithRequires.CallMethodWithRequires()", "--ClassWithRequires--", Tool.Analyzer | Tool.NativeAot, "")] [ExpectedWarning ("IL2026", "ClassWithRequires.Instance", "--ClassWithRequires--")] - [ExpectedWarning ("IL3050", "ClassWithRequires.Instance", "--ClassWithRequires--", ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3050", "ClassWithRequires.Instance", "--ClassWithRequires--", Tool.Analyzer | Tool.NativeAot, "")] static void TestRequiresOnBaseButNotOnDerived () { var a = new DerivedWithoutRequires (); // Must instantiate to force checks on the base type (otherwise base type is non-interesting) @@ -429,7 +429,7 @@ static void TestRequiresOnBaseButNotOnDerived () } [ExpectedWarning ("IL2026", "RequiresOnClass.DerivedWithRequires.StaticMethodInInheritedClass()", "--DerivedWithRequires--")] - [ExpectedWarning ("IL3050", "RequiresOnClass.DerivedWithRequires.StaticMethodInInheritedClass()", "--DerivedWithRequires--", ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3050", "RequiresOnClass.DerivedWithRequires.StaticMethodInInheritedClass()", "--DerivedWithRequires--", Tool.Analyzer | Tool.NativeAot, "")] static void TestRequiresOnDerivedButNotOnBase () { DerivedWithRequires.StaticMethodInInheritedClass (); @@ -439,9 +439,9 @@ static void TestRequiresOnDerivedButNotOnBase () } [ExpectedWarning ("IL2026", "RequiresOnClass.DerivedWithRequires2.StaticMethodInInheritedClass()", "--DerivedWithRequires2--")] - [ExpectedWarning ("IL3050", "RequiresOnClass.DerivedWithRequires2.StaticMethodInInheritedClass()", "--DerivedWithRequires2--", ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3050", "RequiresOnClass.DerivedWithRequires2.StaticMethodInInheritedClass()", "--DerivedWithRequires2--", Tool.Analyzer | Tool.NativeAot, "")] [ExpectedWarning ("IL2026", "RequiresOnClass.ClassWithRequires.StaticMethod()", "--ClassWithRequires--")] - [ExpectedWarning ("IL3050", "RequiresOnClass.ClassWithRequires.StaticMethod()", "--ClassWithRequires--", ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3050", "RequiresOnClass.ClassWithRequires.StaticMethod()", "--ClassWithRequires--", Tool.Analyzer | Tool.NativeAot, "")] static void TestRequiresOnBaseAndDerived () { DerivedWithRequires2.StaticMethodInInheritedClass (); @@ -452,7 +452,7 @@ static void TestRequiresOnBaseAndDerived () } [ExpectedWarning ("IL2026", "RequiresOnClass.ClassWithRequires.TestSuppressions(", "Type[])")] - [ExpectedWarning ("IL3050", "RequiresOnClass.ClassWithRequires.TestSuppressions(", "Type[])", ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3050", "RequiresOnClass.ClassWithRequires.TestSuppressions(", "Type[])", Tool.Analyzer | Tool.NativeAot, "")] static void TestSuppressionsOnClass () { ClassWithRequires.TestSuppressions (new[] { typeof (ClassWithRequires) }); @@ -496,11 +496,11 @@ class MemberTypesWithRequires } [ExpectedWarning ("IL2026", "MemberTypesWithRequires.field")] - [ExpectedWarning ("IL3050", "MemberTypesWithRequires.field", ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3050", "MemberTypesWithRequires.field", Tool.Analyzer | Tool.NativeAot, "")] [ExpectedWarning ("IL2026", "MemberTypesWithRequires.Property.set")] - [ExpectedWarning ("IL3050", "MemberTypesWithRequires.Property.set", ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3050", "MemberTypesWithRequires.Property.set", Tool.Analyzer | Tool.NativeAot, "")] [ExpectedWarning ("IL2026", "MemberTypesWithRequires.Event.remove")] - [ExpectedWarning ("IL3050", "MemberTypesWithRequires.Event.remove", ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3050", "MemberTypesWithRequires.Event.remove", Tool.Analyzer | Tool.NativeAot, "")] static void TestOtherMemberTypesWithRequires () { MemberTypesWithRequires.field = 1; @@ -519,25 +519,25 @@ static void TestNameOfDoesntWarn () class ReflectionAccessOnMethod { [ExpectedWarning ("IL2026", "BaseWithRequiresOnType.Method()")] - [ExpectedWarning ("IL3050", "BaseWithRequiresOnType.Method()", ProducedBy = Tool.NativeAot)] + [ExpectedWarning ("IL3050", "BaseWithRequiresOnType.Method()", Tool.NativeAot, "")] [ExpectedWarning ("IL2026", "BaseWithRequiresOnType.Method()")] - [ExpectedWarning ("IL3050", "BaseWithRequiresOnType.Method()", ProducedBy = Tool.NativeAot)] + [ExpectedWarning ("IL3050", "BaseWithRequiresOnType.Method()", Tool.NativeAot, "")] [ExpectedWarning ("IL2026", "BaseWithoutRequiresOnType.Method()")] - [ExpectedWarning ("IL3050", "BaseWithoutRequiresOnType.Method()", ProducedBy = Tool.NativeAot)] + [ExpectedWarning ("IL3050", "BaseWithoutRequiresOnType.Method()", Tool.NativeAot, "")] [ExpectedWarning ("IL2026", "BaseWithoutRequiresOnType.Method()")] - [ExpectedWarning ("IL3050", "BaseWithoutRequiresOnType.Method()", ProducedBy = Tool.NativeAot)] + [ExpectedWarning ("IL3050", "BaseWithoutRequiresOnType.Method()", Tool.NativeAot, "")] [ExpectedWarning ("IL2026", "DerivedWithRequiresOnType.Method()")] - [ExpectedWarning ("IL3050", "DerivedWithRequiresOnType.Method()", ProducedBy = Tool.NativeAot)] + [ExpectedWarning ("IL3050", "DerivedWithRequiresOnType.Method()", Tool.NativeAot, "")] [ExpectedWarning ("IL2026", "InterfaceWithoutRequires.Method(Int32)")] - [ExpectedWarning ("IL3050", "InterfaceWithoutRequires.Method(Int32)", ProducedBy = Tool.NativeAot)] + [ExpectedWarning ("IL3050", "InterfaceWithoutRequires.Method(Int32)", Tool.NativeAot, "")] [ExpectedWarning ("IL2026", "InterfaceWithoutRequires.Method()")] - [ExpectedWarning ("IL3050", "InterfaceWithoutRequires.Method()", ProducedBy = Tool.NativeAot)] + [ExpectedWarning ("IL3050", "InterfaceWithoutRequires.Method()", Tool.NativeAot, "")] [ExpectedWarning ("IL2026", "ImplementationWithRequiresOnType.Method()")] - [ExpectedWarning ("IL3050", "ImplementationWithRequiresOnType.Method()", ProducedBy = Tool.NativeAot)] + [ExpectedWarning ("IL3050", "ImplementationWithRequiresOnType.Method()", Tool.NativeAot, "")] [ExpectedWarning ("IL2026", "ImplementationWithRequiresOnType.Method(Int32)")] - [ExpectedWarning ("IL3050", "ImplementationWithRequiresOnType.Method(Int32)", ProducedBy = Tool.NativeAot)] + [ExpectedWarning ("IL3050", "ImplementationWithRequiresOnType.Method(Int32)", Tool.NativeAot, "")] [ExpectedWarning ("IL2026", "DerivedWithRequiresOnTypeOverBaseWithNoRequires.Method()")] - [ExpectedWarning ("IL3050", "DerivedWithRequiresOnTypeOverBaseWithNoRequires.Method()", ProducedBy = Tool.NativeAot)] + [ExpectedWarning ("IL3050", "DerivedWithRequiresOnTypeOverBaseWithNoRequires.Method()", Tool.NativeAot, "")] static void TestDAMAccess () { // Warns because BaseWithoutRequiresOnType.Method has Requires on the method @@ -563,17 +563,17 @@ static void TestDAMAccess () } [ExpectedWarning ("IL2026", "BaseWithRequiresOnType.Method()")] - [ExpectedWarning ("IL3050", "BaseWithRequiresOnType.Method()", ProducedBy = Tool.NativeAot)] + [ExpectedWarning ("IL3050", "BaseWithRequiresOnType.Method()", Tool.NativeAot, "")] [ExpectedWarning ("IL2026", "BaseWithoutRequiresOnType.Method()")] - [ExpectedWarning ("IL3050", "BaseWithoutRequiresOnType.Method()", ProducedBy = Tool.NativeAot)] + [ExpectedWarning ("IL3050", "BaseWithoutRequiresOnType.Method()", Tool.NativeAot, "")] [ExpectedWarning ("IL2026", "InterfaceWithoutRequires.Method(Int32)")] - [ExpectedWarning ("IL3050", "InterfaceWithoutRequires.Method(Int32)", ProducedBy = Tool.NativeAot)] + [ExpectedWarning ("IL3050", "InterfaceWithoutRequires.Method(Int32)", Tool.NativeAot, "")] [ExpectedWarning ("IL2026", "InterfaceWithoutRequires.Method()")] - [ExpectedWarning ("IL3050", "InterfaceWithoutRequires.Method()", ProducedBy = Tool.NativeAot)] + [ExpectedWarning ("IL3050", "InterfaceWithoutRequires.Method()", Tool.NativeAot, "")] [ExpectedWarning ("IL2026", "ImplementationWithRequiresOnType.Method()")] - [ExpectedWarning ("IL3050", "ImplementationWithRequiresOnType.Method()", ProducedBy = Tool.NativeAot)] + [ExpectedWarning ("IL3050", "ImplementationWithRequiresOnType.Method()", Tool.NativeAot, "")] [ExpectedWarning ("IL2026", "ImplementationWithRequiresOnType.Method(Int32)")] - [ExpectedWarning ("IL3050", "ImplementationWithRequiresOnType.Method(Int32)", ProducedBy = Tool.NativeAot)] + [ExpectedWarning ("IL3050", "ImplementationWithRequiresOnType.Method(Int32)", Tool.NativeAot, "")] static void TestDirectReflectionAccess () { // Requires on the method itself @@ -609,7 +609,7 @@ public BaseWithRequires () { } class DerivedWithoutRequires : BaseWithRequires { [ExpectedWarning ("IL2026", "--BaseWithRequires--")] // The body has direct call to the base.ctor() - [ExpectedWarning ("IL3050", "--BaseWithRequires--", ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3050", "--BaseWithRequires--", Tool.Analyzer | Tool.NativeAot, "")] public DerivedWithoutRequires () { } } @@ -631,15 +631,15 @@ public DerivedWithRequiresOnBaseWithoutRequires () { } } [ExpectedWarning ("IL2026", "BaseWithRequires.BaseWithRequires()")] - [ExpectedWarning ("IL3050", "BaseWithRequires.BaseWithRequires()", ProducedBy = Tool.NativeAot)] + [ExpectedWarning ("IL3050", "BaseWithRequires.BaseWithRequires()", Tool.NativeAot, "")] [ExpectedWarning ("IL2026", "BaseWithRequires.BaseWithRequires()")] - [ExpectedWarning ("IL3050", "BaseWithRequires.BaseWithRequires()", ProducedBy = Tool.NativeAot)] + [ExpectedWarning ("IL3050", "BaseWithRequires.BaseWithRequires()", Tool.NativeAot, "")] [ExpectedWarning ("IL2026", "DerivedWithRequiresOnBaseWithRequires.DerivedWithRequiresOnBaseWithRequires()")] - [ExpectedWarning ("IL3050", "DerivedWithRequiresOnBaseWithRequires.DerivedWithRequiresOnBaseWithRequires()", ProducedBy = Tool.NativeAot)] + [ExpectedWarning ("IL3050", "DerivedWithRequiresOnBaseWithRequires.DerivedWithRequiresOnBaseWithRequires()", Tool.NativeAot, "")] [ExpectedWarning ("IL2026", "DerivedWithRequiresOnBaseWithoutRequires.DerivedWithRequiresOnBaseWithoutRequires()")] - [ExpectedWarning ("IL3050", "DerivedWithRequiresOnBaseWithoutRequires.DerivedWithRequiresOnBaseWithoutRequires()", ProducedBy = Tool.NativeAot)] + [ExpectedWarning ("IL3050", "DerivedWithRequiresOnBaseWithoutRequires.DerivedWithRequiresOnBaseWithoutRequires()", Tool.NativeAot, "")] [ExpectedWarning ("IL2026", "DerivedWithRequiresOnBaseWithoutRequires.DerivedWithRequiresOnBaseWithoutRequires()")] - [ExpectedWarning ("IL3050", "DerivedWithRequiresOnBaseWithoutRequires.DerivedWithRequiresOnBaseWithoutRequires()", ProducedBy = Tool.NativeAot)] + [ExpectedWarning ("IL3050", "DerivedWithRequiresOnBaseWithoutRequires.DerivedWithRequiresOnBaseWithoutRequires()", Tool.NativeAot, "")] static void TestDAMAccess () { // Warns because the type has Requires @@ -656,11 +656,11 @@ static void TestDAMAccess () } [ExpectedWarning ("IL2026", "BaseWithRequires.BaseWithRequires()")] - [ExpectedWarning ("IL3050", "BaseWithRequires.BaseWithRequires()", ProducedBy = Tool.NativeAot)] + [ExpectedWarning ("IL3050", "BaseWithRequires.BaseWithRequires()", Tool.NativeAot, "")] [ExpectedWarning ("IL2026", "DerivedWithRequiresOnBaseWithRequires.DerivedWithRequiresOnBaseWithRequires()")] - [ExpectedWarning ("IL3050", "DerivedWithRequiresOnBaseWithRequires.DerivedWithRequiresOnBaseWithRequires()", ProducedBy = Tool.NativeAot)] + [ExpectedWarning ("IL3050", "DerivedWithRequiresOnBaseWithRequires.DerivedWithRequiresOnBaseWithRequires()", Tool.NativeAot, "")] [ExpectedWarning ("IL2026", "DerivedWithRequiresOnBaseWithoutRequires.DerivedWithRequiresOnBaseWithoutRequires()")] - [ExpectedWarning ("IL3050", "DerivedWithRequiresOnBaseWithoutRequires.DerivedWithRequiresOnBaseWithoutRequires()", ProducedBy = Tool.NativeAot)] + [ExpectedWarning ("IL3050", "DerivedWithRequiresOnBaseWithoutRequires.DerivedWithRequiresOnBaseWithoutRequires()", Tool.NativeAot, "")] static void TestDirectReflectionAccess () { typeof (BaseWithRequires).GetConstructor (Type.EmptyTypes); @@ -708,15 +708,15 @@ class DerivedWithRequires : WithRequires } [ExpectedWarning ("IL2026", "WithRequires.StaticField")] - [ExpectedWarning ("IL3050", "WithRequires.StaticField", ProducedBy = Tool.NativeAot)] + [ExpectedWarning ("IL3050", "WithRequires.StaticField", Tool.NativeAot, "")] [ExpectedWarning ("IL2026", "WithRequires.StaticField")] - [ExpectedWarning ("IL3050", "WithRequires.StaticField", ProducedBy = Tool.NativeAot)] + [ExpectedWarning ("IL3050", "WithRequires.StaticField", Tool.NativeAot, "")] [ExpectedWarning ("IL2026", "WithRequires.StaticField")] - [ExpectedWarning ("IL3050", "WithRequires.StaticField", ProducedBy = Tool.NativeAot)] + [ExpectedWarning ("IL3050", "WithRequires.StaticField", Tool.NativeAot, "")] [ExpectedWarning ("IL2026", "WithRequires.PrivateStaticField")] - [ExpectedWarning ("IL3050", "WithRequires.PrivateStaticField", ProducedBy = Tool.NativeAot)] + [ExpectedWarning ("IL3050", "WithRequires.PrivateStaticField", Tool.NativeAot, "")] [ExpectedWarning ("IL2026", "DerivedWithRequires.DerivedStaticField")] - [ExpectedWarning ("IL3050", "DerivedWithRequires.DerivedStaticField", ProducedBy = Tool.NativeAot)] + [ExpectedWarning ("IL3050", "DerivedWithRequires.DerivedStaticField", Tool.NativeAot, "")] static void TestDAMAccess () { typeof (WithRequires).RequiresPublicFields (); @@ -727,11 +727,11 @@ static void TestDAMAccess () } [ExpectedWarning ("IL2026", "WithRequires.StaticField")] - [ExpectedWarning ("IL3050", "WithRequires.StaticField", ProducedBy = Tool.NativeAot)] + [ExpectedWarning ("IL3050", "WithRequires.StaticField", Tool.NativeAot, "")] [ExpectedWarning ("IL2026", "WithRequires.PrivateStaticField")] - [ExpectedWarning ("IL3050", "WithRequires.PrivateStaticField", ProducedBy = Tool.NativeAot)] + [ExpectedWarning ("IL3050", "WithRequires.PrivateStaticField", Tool.NativeAot, "")] [ExpectedWarning ("IL2026", "DerivedWithRequires.DerivedStaticField")] - [ExpectedWarning ("IL3050", "DerivedWithRequires.DerivedStaticField", ProducedBy = Tool.NativeAot)] + [ExpectedWarning ("IL3050", "DerivedWithRequires.DerivedStaticField", Tool.NativeAot, "")] static void TestDirectReflectionAccess () { typeof (WithRequires).GetField (nameof (WithRequires.StaticField)); @@ -742,17 +742,17 @@ static void TestDirectReflectionAccess () typeof (DerivedWithRequires).GetField (nameof (DerivedWithRequires.DerivedStaticField)); } - [ExpectedWarning ("IL2026", "WithRequires.StaticField", ProducedBy = Tool.Trimmer | Tool.NativeAot)] - [ExpectedWarning ("IL3050", "WithRequires.StaticField", ProducedBy = Tool.NativeAot)] - [ExpectedWarning ("IL2026", "WithRequires.StaticField", ProducedBy = Tool.Trimmer | Tool.NativeAot)] - [ExpectedWarning ("IL3050", "WithRequires.StaticField", ProducedBy = Tool.NativeAot)] - [ExpectedWarning ("IL2026", "WithRequires.StaticField", ProducedBy = Tool.Trimmer | Tool.NativeAot)] - [ExpectedWarning ("IL3050", "WithRequires.StaticField", ProducedBy = Tool.NativeAot)] + [ExpectedWarning ("IL2026", "WithRequires.StaticField", Tool.Trimmer | Tool.NativeAot, "")] + [ExpectedWarning ("IL3050", "WithRequires.StaticField", Tool.NativeAot, "")] + [ExpectedWarning ("IL2026", "WithRequires.StaticField", Tool.Trimmer | Tool.NativeAot, "")] + [ExpectedWarning ("IL3050", "WithRequires.StaticField", Tool.NativeAot, "")] + [ExpectedWarning ("IL2026", "WithRequires.StaticField", Tool.Trimmer | Tool.NativeAot, "")] + [ExpectedWarning ("IL3050", "WithRequires.StaticField", Tool.NativeAot, "")] [DynamicDependency (nameof (WithRequires.StaticField), typeof (WithRequires))] [DynamicDependency (nameof (WithRequires.InstanceField), typeof (WithRequires))] // Doesn't warn [DynamicDependency (DynamicallyAccessedMemberTypes.PublicFields, typeof (DerivedWithoutRequires))] // Doesn't warn - [ExpectedWarning ("IL2026", "DerivedWithRequires.DerivedStaticField", ProducedBy = Tool.Trimmer | Tool.NativeAot)] - [ExpectedWarning ("IL3050", "DerivedWithRequires.DerivedStaticField", ProducedBy = Tool.NativeAot)] + [ExpectedWarning ("IL2026", "DerivedWithRequires.DerivedStaticField", Tool.Trimmer | Tool.NativeAot, "")] + [ExpectedWarning ("IL3050", "DerivedWithRequires.DerivedStaticField", Tool.NativeAot, "")] [DynamicDependency (DynamicallyAccessedMemberTypes.PublicFields, typeof (DerivedWithRequires))] static void TestDynamicDependencyAccess () { @@ -768,13 +768,13 @@ class BaseForDAMAnnotatedClass [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicFields | DynamicallyAccessedMemberTypes.NonPublicFields)] [RequiresUnreferencedCode ("This class is dangerous")] [RequiresDynamicCode ("This class is dangerous")] - [ExpectedWarning ("IL2113", "BaseForDAMAnnotatedClass.baseField", ProducedBy = Tool.Trimmer | Tool.NativeAot)] + [ExpectedWarning ("IL2113", "BaseForDAMAnnotatedClass.baseField", Tool.Trimmer | Tool.NativeAot, "")] class DAMAnnotatedClass : BaseForDAMAnnotatedClass { - [ExpectedWarning ("IL2112", "DAMAnnotatedClass.publicField", ProducedBy = Tool.Trimmer | Tool.NativeAot)] + [ExpectedWarning ("IL2112", "DAMAnnotatedClass.publicField", Tool.Trimmer | Tool.NativeAot, "")] public static int publicField; - [ExpectedWarning ("IL2112", "DAMAnnotatedClass.privatefield", ProducedBy = Tool.Trimmer | Tool.NativeAot)] + [ExpectedWarning ("IL2112", "DAMAnnotatedClass.privatefield", Tool.Trimmer | Tool.NativeAot, "")] static int privatefield; } @@ -786,7 +786,7 @@ static void TestDAMOnTypeAccess (DAMAnnotatedClass instance) [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.All)] class DAMAnnotatedClassAccessedFromRUCScope { - [ExpectedWarning ("IL2112", "DAMAnnotatedClassAccessedFromRUCScope.RUCMethod", ProducedBy = Tool.Trimmer | Tool.NativeAot)] + [ExpectedWarning ("IL2112", "DAMAnnotatedClassAccessedFromRUCScope.RUCMethod", Tool.Trimmer | Tool.NativeAot, "")] [RequiresUnreferencedCode ("--RUCMethod--")] public static void RUCMethod () { } } @@ -807,14 +807,14 @@ class GenericTypeWithRequires } [ExpectedWarning ("IL2026", "NonGenericField", "--GenericTypeWithRequires--")] - [ExpectedWarning ("IL3050", "NonGenericField", "--GenericTypeWithRequires--", ProducedBy = Tool.NativeAot)] + [ExpectedWarning ("IL3050", "NonGenericField", "--GenericTypeWithRequires--", Tool.NativeAot, "")] static void TestDAMAccessOnOpenGeneric () { typeof (GenericTypeWithRequires<>).RequiresPublicFields (); } [ExpectedWarning ("IL2026", "NonGenericField", "--GenericTypeWithRequires--")] - [ExpectedWarning ("IL3050", "NonGenericField", "--GenericTypeWithRequires--", ProducedBy = Tool.NativeAot)] + [ExpectedWarning ("IL3050", "NonGenericField", "--GenericTypeWithRequires--", Tool.NativeAot, "")] static void TestDAMAccessOnInstantiatedGeneric () { typeof (GenericTypeWithRequires).RequiresPublicFields (); @@ -846,11 +846,11 @@ class WithRequires } [ExpectedWarning ("IL2026", "StaticEvent.add")] - [ExpectedWarning ("IL3050", "StaticEvent.add", ProducedBy = Tool.NativeAot)] + [ExpectedWarning ("IL3050", "StaticEvent.add", Tool.NativeAot, "")] // https://github.com/dotnet/runtime/issues/100499 - [ExpectedWarning ("IL2026", "StaticEvent.add", ProducedBy = Tool.Trimmer)] + [ExpectedWarning ("IL2026", "StaticEvent.add", Tool.Trimmer, "")] [ExpectedWarning ("IL2026", "StaticEvent.remove")] - [ExpectedWarning ("IL3050", "StaticEvent.remove", ProducedBy = Tool.NativeAot)] + [ExpectedWarning ("IL3050", "StaticEvent.remove", Tool.NativeAot, "")] static void TestDirectReflectionAccess () { typeof (WithRequires).GetEvent (nameof (WithRequires.StaticEvent)); @@ -894,41 +894,41 @@ class DerivedWithRequires : WithRequires } [ExpectedWarning ("IL2026", "WithRequires.InstanceProperty.get")] - [ExpectedWarning ("IL3050", "WithRequires.InstanceProperty.get", ProducedBy = Tool.NativeAot)] + [ExpectedWarning ("IL3050", "WithRequires.InstanceProperty.get", Tool.NativeAot, "")] [ExpectedWarning ("IL2026", "WithRequires.InstanceProperty.get")] - [ExpectedWarning ("IL3050", "WithRequires.InstanceProperty.get", ProducedBy = Tool.NativeAot)] + [ExpectedWarning ("IL3050", "WithRequires.InstanceProperty.get", Tool.NativeAot, "")] [ExpectedWarning ("IL2026", "WithRequires.InstanceProperty.get")] - [ExpectedWarning ("IL3050", "WithRequires.InstanceProperty.get", ProducedBy = Tool.NativeAot)] + [ExpectedWarning ("IL3050", "WithRequires.InstanceProperty.get", Tool.NativeAot, "")] [ExpectedWarning ("IL2026", "WithRequires.InstanceProperty.set")] - [ExpectedWarning ("IL3050", "WithRequires.InstanceProperty.set", ProducedBy = Tool.NativeAot)] + [ExpectedWarning ("IL3050", "WithRequires.InstanceProperty.set", Tool.NativeAot, "")] [ExpectedWarning ("IL2026", "WithRequires.InstanceProperty.set")] - [ExpectedWarning ("IL3050", "WithRequires.InstanceProperty.set", ProducedBy = Tool.NativeAot)] + [ExpectedWarning ("IL3050", "WithRequires.InstanceProperty.set", Tool.NativeAot, "")] [ExpectedWarning ("IL2026", "WithRequires.InstanceProperty.set")] - [ExpectedWarning ("IL3050", "WithRequires.InstanceProperty.set", ProducedBy = Tool.NativeAot)] + [ExpectedWarning ("IL3050", "WithRequires.InstanceProperty.set", Tool.NativeAot, "")] [ExpectedWarning ("IL2026", "WithRequires.StaticProperty.get")] - [ExpectedWarning ("IL3050", "WithRequires.StaticProperty.get", ProducedBy = Tool.NativeAot)] + [ExpectedWarning ("IL3050", "WithRequires.StaticProperty.get", Tool.NativeAot, "")] [ExpectedWarning ("IL2026", "WithRequires.StaticProperty.get")] - [ExpectedWarning ("IL3050", "WithRequires.StaticProperty.get", ProducedBy = Tool.NativeAot)] + [ExpectedWarning ("IL3050", "WithRequires.StaticProperty.get", Tool.NativeAot, "")] [ExpectedWarning ("IL2026", "WithRequires.StaticProperty.get")] - [ExpectedWarning ("IL3050", "WithRequires.StaticProperty.get", ProducedBy = Tool.NativeAot)] + [ExpectedWarning ("IL3050", "WithRequires.StaticProperty.get", Tool.NativeAot, "")] [ExpectedWarning ("IL2026", "WithRequires.StaticProperty.set")] - [ExpectedWarning ("IL3050", "WithRequires.StaticProperty.set", ProducedBy = Tool.NativeAot)] + [ExpectedWarning ("IL3050", "WithRequires.StaticProperty.set", Tool.NativeAot, "")] [ExpectedWarning ("IL2026", "WithRequires.StaticProperty.set")] - [ExpectedWarning ("IL3050", "WithRequires.StaticProperty.set", ProducedBy = Tool.NativeAot)] + [ExpectedWarning ("IL3050", "WithRequires.StaticProperty.set", Tool.NativeAot, "")] [ExpectedWarning ("IL2026", "WithRequires.StaticProperty.set")] - [ExpectedWarning ("IL3050", "WithRequires.StaticProperty.set", ProducedBy = Tool.NativeAot)] + [ExpectedWarning ("IL3050", "WithRequires.StaticProperty.set", Tool.NativeAot, "")] [ExpectedWarning ("IL2026", "WithRequires.PrivateStaticProperty.get")] - [ExpectedWarning ("IL3050", "WithRequires.PrivateStaticProperty.get", ProducedBy = Tool.NativeAot)] + [ExpectedWarning ("IL3050", "WithRequires.PrivateStaticProperty.get", Tool.NativeAot, "")] [ExpectedWarning ("IL2026", "WithRequires.PrivateStaticProperty.set")] - [ExpectedWarning ("IL3050", "WithRequires.PrivateStaticProperty.set", ProducedBy = Tool.NativeAot)] + [ExpectedWarning ("IL3050", "WithRequires.PrivateStaticProperty.set", Tool.NativeAot, "")] [ExpectedWarning ("IL2026", "WithRequiresOnlyInstanceProperties.InstanceProperty.get")] - [ExpectedWarning ("IL3050", "WithRequiresOnlyInstanceProperties.InstanceProperty.get", ProducedBy = Tool.NativeAot)] + [ExpectedWarning ("IL3050", "WithRequiresOnlyInstanceProperties.InstanceProperty.get", Tool.NativeAot, "")] [ExpectedWarning ("IL2026", "WithRequiresOnlyInstanceProperties.InstanceProperty.set")] - [ExpectedWarning ("IL3050", "WithRequiresOnlyInstanceProperties.InstanceProperty.set", ProducedBy = Tool.NativeAot)] + [ExpectedWarning ("IL3050", "WithRequiresOnlyInstanceProperties.InstanceProperty.set", Tool.NativeAot, "")] [ExpectedWarning ("IL2026", "DerivedWithRequires.DerivedStaticProperty.get")] - [ExpectedWarning ("IL3050", "DerivedWithRequires.DerivedStaticProperty.get", ProducedBy = Tool.NativeAot)] + [ExpectedWarning ("IL3050", "DerivedWithRequires.DerivedStaticProperty.get", Tool.NativeAot, "")] [ExpectedWarning ("IL2026", "DerivedWithRequires.DerivedStaticProperty.set")] - [ExpectedWarning ("IL3050", "DerivedWithRequires.DerivedStaticProperty.set", ProducedBy = Tool.NativeAot)] + [ExpectedWarning ("IL3050", "DerivedWithRequires.DerivedStaticProperty.set", Tool.NativeAot, "")] static void TestDAMAccess () { typeof (WithRequires).RequiresPublicProperties (); @@ -939,25 +939,25 @@ static void TestDAMAccess () } [ExpectedWarning ("IL2026", "WithRequires.InstanceProperty.get")] - [ExpectedWarning ("IL3050", "WithRequires.InstanceProperty.get", ProducedBy = Tool.NativeAot)] + [ExpectedWarning ("IL3050", "WithRequires.InstanceProperty.get", Tool.NativeAot, "")] [ExpectedWarning ("IL2026", "WithRequires.InstanceProperty.set")] - [ExpectedWarning ("IL3050", "WithRequires.InstanceProperty.set", ProducedBy = Tool.NativeAot)] + [ExpectedWarning ("IL3050", "WithRequires.InstanceProperty.set", Tool.NativeAot, "")] [ExpectedWarning ("IL2026", "WithRequires.StaticProperty.get")] - [ExpectedWarning ("IL3050", "WithRequires.StaticProperty.get", ProducedBy = Tool.NativeAot)] + [ExpectedWarning ("IL3050", "WithRequires.StaticProperty.get", Tool.NativeAot, "")] [ExpectedWarning ("IL2026", "WithRequires.StaticProperty.set")] - [ExpectedWarning ("IL3050", "WithRequires.StaticProperty.set", ProducedBy = Tool.NativeAot)] + [ExpectedWarning ("IL3050", "WithRequires.StaticProperty.set", Tool.NativeAot, "")] [ExpectedWarning ("IL2026", "WithRequires.PrivateStaticProperty.get")] - [ExpectedWarning ("IL3050", "WithRequires.PrivateStaticProperty.get", ProducedBy = Tool.NativeAot)] + [ExpectedWarning ("IL3050", "WithRequires.PrivateStaticProperty.get", Tool.NativeAot, "")] [ExpectedWarning ("IL2026", "WithRequires.PrivateStaticProperty.set")] - [ExpectedWarning ("IL3050", "WithRequires.PrivateStaticProperty.set", ProducedBy = Tool.NativeAot)] + [ExpectedWarning ("IL3050", "WithRequires.PrivateStaticProperty.set", Tool.NativeAot, "")] [ExpectedWarning ("IL2026", "WithRequiresOnlyInstanceProperties.InstanceProperty.get")] - [ExpectedWarning ("IL3050", "WithRequiresOnlyInstanceProperties.InstanceProperty.get", ProducedBy = Tool.NativeAot)] + [ExpectedWarning ("IL3050", "WithRequiresOnlyInstanceProperties.InstanceProperty.get", Tool.NativeAot, "")] [ExpectedWarning ("IL2026", "WithRequiresOnlyInstanceProperties.InstanceProperty.set")] - [ExpectedWarning ("IL3050", "WithRequiresOnlyInstanceProperties.InstanceProperty.set", ProducedBy = Tool.NativeAot)] + [ExpectedWarning ("IL3050", "WithRequiresOnlyInstanceProperties.InstanceProperty.set", Tool.NativeAot, "")] [ExpectedWarning ("IL2026", "DerivedWithRequires.DerivedStaticProperty.get")] - [ExpectedWarning ("IL3050", "DerivedWithRequires.DerivedStaticProperty.get", ProducedBy = Tool.NativeAot)] + [ExpectedWarning ("IL3050", "DerivedWithRequires.DerivedStaticProperty.get", Tool.NativeAot, "")] [ExpectedWarning ("IL2026", "DerivedWithRequires.DerivedStaticProperty.set")] - [ExpectedWarning ("IL3050", "DerivedWithRequires.DerivedStaticProperty.set", ProducedBy = Tool.NativeAot)] + [ExpectedWarning ("IL3050", "DerivedWithRequires.DerivedStaticProperty.set", Tool.NativeAot, "")] static void TestDirectReflectionAccess () { typeof (WithRequires).GetProperty (nameof (WithRequires.StaticProperty)); @@ -968,37 +968,37 @@ static void TestDirectReflectionAccess () typeof (DerivedWithRequires).GetProperty (nameof (DerivedWithRequires.DerivedStaticProperty)); } - [ExpectedWarning ("IL2026", "WithRequires.InstanceProperty.get", ProducedBy = Tool.Trimmer | Tool.NativeAot)] - [ExpectedWarning ("IL3050", "WithRequires.InstanceProperty.get", ProducedBy = Tool.NativeAot)] - [ExpectedWarning ("IL2026", "WithRequires.InstanceProperty.get", ProducedBy = Tool.Trimmer | Tool.NativeAot)] - [ExpectedWarning ("IL3050", "WithRequires.InstanceProperty.get", ProducedBy = Tool.NativeAot)] - [ExpectedWarning ("IL2026", "WithRequires.InstanceProperty.get", ProducedBy = Tool.Trimmer | Tool.NativeAot)] - [ExpectedWarning ("IL3050", "WithRequires.InstanceProperty.get", ProducedBy = Tool.NativeAot)] - [ExpectedWarning ("IL2026", "WithRequires.InstanceProperty.set", ProducedBy = Tool.Trimmer | Tool.NativeAot)] - [ExpectedWarning ("IL3050", "WithRequires.InstanceProperty.set", ProducedBy = Tool.NativeAot)] - [ExpectedWarning ("IL2026", "WithRequires.InstanceProperty.set", ProducedBy = Tool.Trimmer | Tool.NativeAot)] - [ExpectedWarning ("IL3050", "WithRequires.InstanceProperty.set", ProducedBy = Tool.NativeAot)] - [ExpectedWarning ("IL2026", "WithRequires.InstanceProperty.set", ProducedBy = Tool.Trimmer | Tool.NativeAot)] - [ExpectedWarning ("IL3050", "WithRequires.InstanceProperty.set", ProducedBy = Tool.NativeAot)] - [ExpectedWarning ("IL2026", "WithRequires.StaticProperty.get", ProducedBy = Tool.Trimmer | Tool.NativeAot)] - [ExpectedWarning ("IL3050", "WithRequires.StaticProperty.get", ProducedBy = Tool.NativeAot)] - [ExpectedWarning ("IL2026", "WithRequires.StaticProperty.get", ProducedBy = Tool.Trimmer | Tool.NativeAot)] - [ExpectedWarning ("IL3050", "WithRequires.StaticProperty.get", ProducedBy = Tool.NativeAot)] - [ExpectedWarning ("IL2026", "WithRequires.StaticProperty.get", ProducedBy = Tool.Trimmer | Tool.NativeAot)] - [ExpectedWarning ("IL3050", "WithRequires.StaticProperty.get", ProducedBy = Tool.NativeAot)] - [ExpectedWarning ("IL2026", "WithRequires.StaticProperty.set", ProducedBy = Tool.Trimmer | Tool.NativeAot)] - [ExpectedWarning ("IL3050", "WithRequires.StaticProperty.set", ProducedBy = Tool.NativeAot)] - [ExpectedWarning ("IL2026", "WithRequires.StaticProperty.set", ProducedBy = Tool.Trimmer | Tool.NativeAot)] - [ExpectedWarning ("IL3050", "WithRequires.StaticProperty.set", ProducedBy = Tool.NativeAot)] - [ExpectedWarning ("IL2026", "WithRequires.StaticProperty.set", ProducedBy = Tool.Trimmer | Tool.NativeAot)] - [ExpectedWarning ("IL3050", "WithRequires.StaticProperty.set", ProducedBy = Tool.NativeAot)] + [ExpectedWarning ("IL2026", "WithRequires.InstanceProperty.get", Tool.Trimmer | Tool.NativeAot, "")] + [ExpectedWarning ("IL3050", "WithRequires.InstanceProperty.get", Tool.NativeAot, "")] + [ExpectedWarning ("IL2026", "WithRequires.InstanceProperty.get", Tool.Trimmer | Tool.NativeAot, "")] + [ExpectedWarning ("IL3050", "WithRequires.InstanceProperty.get", Tool.NativeAot, "")] + [ExpectedWarning ("IL2026", "WithRequires.InstanceProperty.get", Tool.Trimmer | Tool.NativeAot, "")] + [ExpectedWarning ("IL3050", "WithRequires.InstanceProperty.get", Tool.NativeAot, "")] + [ExpectedWarning ("IL2026", "WithRequires.InstanceProperty.set", Tool.Trimmer | Tool.NativeAot, "")] + [ExpectedWarning ("IL3050", "WithRequires.InstanceProperty.set", Tool.NativeAot, "")] + [ExpectedWarning ("IL2026", "WithRequires.InstanceProperty.set", Tool.Trimmer | Tool.NativeAot, "")] + [ExpectedWarning ("IL3050", "WithRequires.InstanceProperty.set", Tool.NativeAot, "")] + [ExpectedWarning ("IL2026", "WithRequires.InstanceProperty.set", Tool.Trimmer | Tool.NativeAot, "")] + [ExpectedWarning ("IL3050", "WithRequires.InstanceProperty.set", Tool.NativeAot, "")] + [ExpectedWarning ("IL2026", "WithRequires.StaticProperty.get", Tool.Trimmer | Tool.NativeAot, "")] + [ExpectedWarning ("IL3050", "WithRequires.StaticProperty.get", Tool.NativeAot, "")] + [ExpectedWarning ("IL2026", "WithRequires.StaticProperty.get", Tool.Trimmer | Tool.NativeAot, "")] + [ExpectedWarning ("IL3050", "WithRequires.StaticProperty.get", Tool.NativeAot, "")] + [ExpectedWarning ("IL2026", "WithRequires.StaticProperty.get", Tool.Trimmer | Tool.NativeAot, "")] + [ExpectedWarning ("IL3050", "WithRequires.StaticProperty.get", Tool.NativeAot, "")] + [ExpectedWarning ("IL2026", "WithRequires.StaticProperty.set", Tool.Trimmer | Tool.NativeAot, "")] + [ExpectedWarning ("IL3050", "WithRequires.StaticProperty.set", Tool.NativeAot, "")] + [ExpectedWarning ("IL2026", "WithRequires.StaticProperty.set", Tool.Trimmer | Tool.NativeAot, "")] + [ExpectedWarning ("IL3050", "WithRequires.StaticProperty.set", Tool.NativeAot, "")] + [ExpectedWarning ("IL2026", "WithRequires.StaticProperty.set", Tool.Trimmer | Tool.NativeAot, "")] + [ExpectedWarning ("IL3050", "WithRequires.StaticProperty.set", Tool.NativeAot, "")] [DynamicDependency (nameof (WithRequires.StaticProperty), typeof (WithRequires))] [DynamicDependency (nameof (WithRequires.InstanceProperty), typeof (WithRequires))] // Doesn't warn [DynamicDependency (DynamicallyAccessedMemberTypes.PublicProperties, typeof (DerivedWithoutRequires))] // Doesn't warn - [ExpectedWarning ("IL2026", "DerivedWithRequires.DerivedStaticProperty.get", ProducedBy = Tool.Trimmer | Tool.NativeAot)] - [ExpectedWarning ("IL3050", "DerivedWithRequires.DerivedStaticProperty.get", ProducedBy = Tool.NativeAot)] - [ExpectedWarning ("IL2026", "DerivedWithRequires.DerivedStaticProperty.set", ProducedBy = Tool.Trimmer | Tool.NativeAot)] - [ExpectedWarning ("IL3050", "DerivedWithRequires.DerivedStaticProperty.set", ProducedBy = Tool.NativeAot)] + [ExpectedWarning ("IL2026", "DerivedWithRequires.DerivedStaticProperty.get", Tool.Trimmer | Tool.NativeAot, "")] + [ExpectedWarning ("IL3050", "DerivedWithRequires.DerivedStaticProperty.get", Tool.NativeAot, "")] + [ExpectedWarning ("IL2026", "DerivedWithRequires.DerivedStaticProperty.set", Tool.Trimmer | Tool.NativeAot, "")] + [ExpectedWarning ("IL3050", "DerivedWithRequires.DerivedStaticProperty.set", Tool.NativeAot, "")] [DynamicDependency (DynamicallyAccessedMemberTypes.PublicProperties, typeof (DerivedWithRequires))] static void TestDynamicDependencyAccess () { @@ -1014,21 +1014,21 @@ class BaseForDAMAnnotatedClass [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicProperties | DynamicallyAccessedMemberTypes.NonPublicProperties)] [RequiresUnreferencedCode ("This class is dangerous")] [RequiresDynamicCode ("This class is dangerous")] - [ExpectedWarning ("IL2113", "BaseForDAMAnnotatedClass.baseProperty.get", ProducedBy = Tool.Trimmer | Tool.NativeAot)] - [ExpectedWarning ("IL2113", "BaseForDAMAnnotatedClass.baseProperty.set", ProducedBy = Tool.Trimmer | Tool.NativeAot)] + [ExpectedWarning ("IL2113", "BaseForDAMAnnotatedClass.baseProperty.get", Tool.Trimmer | Tool.NativeAot, "")] + [ExpectedWarning ("IL2113", "BaseForDAMAnnotatedClass.baseProperty.set", Tool.Trimmer | Tool.NativeAot, "")] class DAMAnnotatedClass : BaseForDAMAnnotatedClass { public static int publicProperty { - [ExpectedWarning ("IL2112", "DAMAnnotatedClass.publicProperty.get", ProducedBy = Tool.Trimmer | Tool.NativeAot)] + [ExpectedWarning ("IL2112", "DAMAnnotatedClass.publicProperty.get", Tool.Trimmer | Tool.NativeAot, "")] get; - [ExpectedWarning ("IL2112", "DAMAnnotatedClass.publicProperty.set", ProducedBy = Tool.Trimmer | Tool.NativeAot)] + [ExpectedWarning ("IL2112", "DAMAnnotatedClass.publicProperty.set", Tool.Trimmer | Tool.NativeAot, "")] set; } static int privateProperty { - [ExpectedWarning ("IL2112", "DAMAnnotatedClass.privateProperty.get", ProducedBy = Tool.Trimmer | Tool.NativeAot)] + [ExpectedWarning ("IL2112", "DAMAnnotatedClass.privateProperty.get", Tool.Trimmer | Tool.NativeAot, "")] get; - [ExpectedWarning ("IL2112", "DAMAnnotatedClass.privateProperty.set", ProducedBy = Tool.Trimmer | Tool.NativeAot)] + [ExpectedWarning ("IL2112", "DAMAnnotatedClass.privateProperty.set", Tool.Trimmer | Tool.NativeAot, "")] set; } } @@ -1064,7 +1064,7 @@ public int PropertyOnAttribute { [AttributeWithRequires (PropertyOnAttribute = 42)] [ExpectedWarning ("IL2026", "AttributeWithRequires.AttributeWithRequires()")] - [ExpectedWarning ("IL3050", "AttributeWithRequires.AttributeWithRequires()", ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3050", "AttributeWithRequires.AttributeWithRequires()", Tool.Analyzer | Tool.NativeAot, "")] static void KeepFieldOnAttributeInner () { } static void KeepFieldOnAttribute () @@ -1114,7 +1114,7 @@ public static void Test () { } } [ExpectedWarning ("IL2026")] - [ExpectedWarning ("IL3050", ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3050", Tool.Analyzer | Tool.NativeAot, "")] public static void Test () { TestClass.Test (); @@ -1142,7 +1142,7 @@ public class ClassWithRequires // https://github.com/dotnet/linker/issues/3142 // Instance fields get generic warnings but static fields don't. - [ExpectedWarning ("IL2091", ProducedBy = Tool.Trimmer)] + [ExpectedWarning ("IL2091", Tool.Trimmer, "")] public RequiresAll instanceField; [RequiresOnCtor] @@ -1150,7 +1150,7 @@ public class ClassWithRequires // https://github.com/dotnet/linker/issues/3140 // Instance fields get attribute warnings but static fields don't. - [ExpectedWarning ("IL2026", "--RequiresOnCtorAttribute--", ProducedBy = Tool.Trimmer)] + [ExpectedWarning ("IL2026", "--RequiresOnCtorAttribute--", Tool.Trimmer, "")] [RequiresOnCtor] public int instanceFieldWithAttribute; @@ -1212,7 +1212,7 @@ public class GenericAnnotatedWithWarningWithRequires<[DynamicallyAccessedMembers [ExpectedWarning ("IL2026", "--GenericClassWithWarningWithRequires--")] [ExpectedWarning ("IL2026", "--ClassWithWarningWithRequires--")] [ExpectedWarning ("IL2026", "--GenericAnnotatedWithWarningWithRequires--")] - [ExpectedWarning ("IL2091", ProducedBy = Tool.Trimmer)] + [ExpectedWarning ("IL2091", Tool.Trimmer, "")] public static void Test (ClassWithRequires inst = null) { var f = ClassWithRequires.field; @@ -1244,7 +1244,7 @@ public static void Method () { } } [ExpectedWarning ("IL2026", "--ConstClassWithRequires--", nameof (ConstClassWithRequires.Method))] - [ExpectedWarning ("IL3050", "--ConstClassWithRequires--", nameof (ConstClassWithRequires.Method), ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3050", "--ConstClassWithRequires--", nameof (ConstClassWithRequires.Method), Tool.Analyzer | Tool.NativeAot, "")] static void TestClassWithRequires () { var a = ConstClassWithRequires.Message; @@ -1263,7 +1263,7 @@ public static void Method () { } } [ExpectedWarning ("IL2026", "--ConstClassWithRequiresUsingField--", nameof (ConstClassWithRequiresUsingField.Method))] - [ExpectedWarning ("IL3050", "--ConstClassWithRequiresUsingField--", nameof (ConstClassWithRequiresUsingField.Method), ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3050", "--ConstClassWithRequiresUsingField--", nameof (ConstClassWithRequiresUsingField.Method), Tool.Analyzer | Tool.NativeAot, "")] static void TestClassUsingFieldInAttribute () { ConstClassWithRequiresUsingField.Method (); diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/RequiresCapability/RequiresOnStaticConstructor.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/RequiresCapability/RequiresOnStaticConstructor.cs index 98fbe6876f0aef..cfd8bfd9145f37 100644 --- a/src/tools/illink/test/Mono.Linker.Tests.Cases/RequiresCapability/RequiresOnStaticConstructor.cs +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/RequiresCapability/RequiresOnStaticConstructor.cs @@ -30,8 +30,8 @@ public static void Main () class StaticCtor { [ExpectedWarning ("IL2026", "--MethodWithRequires--")] - [ExpectedWarning ("IL3002", "--MethodWithRequires--", ProducedBy = Tool.Analyzer | Tool.NativeAot)] - [ExpectedWarning ("IL3050", "--MethodWithRequires--", ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3002", "--MethodWithRequires--", Tool.Analyzer | Tool.NativeAot, "")] + [ExpectedWarning ("IL3050", "--MethodWithRequires--", Tool.Analyzer | Tool.NativeAot, "")] [ExpectedWarning ("IL2116", "StaticCtor..cctor()")] [RequiresUnreferencedCode ("Message for --TestStaticCtor--")] static StaticCtor () @@ -48,8 +48,8 @@ static void TestStaticCctorRequires () [RequiresUnreferencedCode ("Message for --StaticCtorOnTypeWithRequires--")] class StaticCtorOnTypeWithRequires { - [ExpectedWarning ("IL3002", "--MethodWithRequires--", ProducedBy = Tool.Analyzer | Tool.NativeAot)] - [ExpectedWarning ("IL3050", "--MethodWithRequires--", ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3002", "--MethodWithRequires--", Tool.Analyzer | Tool.NativeAot, "")] + [ExpectedWarning ("IL3050", "--MethodWithRequires--", Tool.Analyzer | Tool.NativeAot, "")] static StaticCtorOnTypeWithRequires () => MethodWithRequires (); } @@ -70,8 +70,8 @@ static void TestRunClassConstructorOnTypeWithRequires () class StaticCtorForRunClassConstructorWithRequires { [ExpectedWarning ("IL2116")] - [ExpectedWarning ("IL3004", ProducedBy = Tool.Analyzer | Tool.NativeAot)] - [ExpectedWarning ("IL3056", ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3004", Tool.Analyzer | Tool.NativeAot, "")] + [ExpectedWarning ("IL3056", Tool.Analyzer | Tool.NativeAot, "")] [RequiresUnreferencedCode ("Message for --StaticCtorOnTypeWithRequires--")] [RequiresAssemblyFiles ("Message for --StaticCtorOnTypeWithRequires--")] [RequiresDynamicCode ("Message for --StaticCtorOnTypeWithRequires--")] @@ -118,8 +118,8 @@ static void TestStaticCtorMarkingIsTriggeredByFieldAccessOnExplicitLayout () class StaticCtorTriggeredByMethodCall { [ExpectedWarning ("IL2116", "StaticCtorTriggeredByMethodCall..cctor()")] - [ExpectedWarning ("IL3004", "StaticCtorTriggeredByMethodCall..cctor()", ProducedBy = Tool.Analyzer | Tool.NativeAot)] - [ExpectedWarning ("IL3056", "StaticCtorTriggeredByMethodCall..cctor()", ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3004", "StaticCtorTriggeredByMethodCall..cctor()", Tool.Analyzer | Tool.NativeAot, "")] + [ExpectedWarning ("IL3056", "StaticCtorTriggeredByMethodCall..cctor()", Tool.Analyzer | Tool.NativeAot, "")] [RequiresUnreferencedCode ("Message for --StaticCtorTriggeredByMethodCall.Cctor--")] [RequiresAssemblyFiles ("Message for --StaticCtorTriggeredByMethodCall.Cctor--")] [RequiresDynamicCode ("Message for --StaticCtorTriggeredByMethodCall.Cctor--")] @@ -137,8 +137,8 @@ public void TriggerStaticCtorMarking () [ExpectedWarning ("IL2026", "--StaticCtorTriggeredByMethodCall.TriggerStaticCtorMarking--")] - [ExpectedWarning ("IL3002", "--StaticCtorTriggeredByMethodCall.TriggerStaticCtorMarking--", ProducedBy = Tool.Analyzer | Tool.NativeAot)] - [ExpectedWarning ("IL3050", "--StaticCtorTriggeredByMethodCall.TriggerStaticCtorMarking--", ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3002", "--StaticCtorTriggeredByMethodCall.TriggerStaticCtorMarking--", Tool.Analyzer | Tool.NativeAot, "")] + [ExpectedWarning ("IL3050", "--StaticCtorTriggeredByMethodCall.TriggerStaticCtorMarking--", Tool.Analyzer | Tool.NativeAot, "")] static void TestStaticCtorTriggeredByMethodCall () { new StaticCtorTriggeredByMethodCall ().TriggerStaticCtorMarking (); @@ -146,9 +146,9 @@ static void TestStaticCtorTriggeredByMethodCall () class TypeIsBeforeFieldInit { - [ExpectedWarning ("IL2026", "Message from --TypeIsBeforeFieldInit.AnnotatedMethod--", ProducedBy = Tool.Analyzer)] - [ExpectedWarning ("IL3002", "Message from --TypeIsBeforeFieldInit.AnnotatedMethod--", ProducedBy = Tool.Analyzer)] - [ExpectedWarning ("IL3050", "Message from --TypeIsBeforeFieldInit.AnnotatedMethod--", ProducedBy = Tool.Analyzer)] + [ExpectedWarning ("IL2026", "Message from --TypeIsBeforeFieldInit.AnnotatedMethod--", Tool.Analyzer, "")] + [ExpectedWarning ("IL3002", "Message from --TypeIsBeforeFieldInit.AnnotatedMethod--", Tool.Analyzer, "")] + [ExpectedWarning ("IL3050", "Message from --TypeIsBeforeFieldInit.AnnotatedMethod--", Tool.Analyzer, "")] public static int field = AnnotatedMethod (); [RequiresUnreferencedCode ("Message from --TypeIsBeforeFieldInit.AnnotatedMethod--")] diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/RequiresCapability/RequiresOnVirtualsAndInterfaces.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/RequiresCapability/RequiresOnVirtualsAndInterfaces.cs index b9ac10e61c11aa..4623dd6355fc1f 100644 --- a/src/tools/illink/test/Mono.Linker.Tests.Cases/RequiresCapability/RequiresOnVirtualsAndInterfaces.cs +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/RequiresCapability/RequiresOnVirtualsAndInterfaces.cs @@ -46,8 +46,8 @@ public override void VirtualMethodRequires () } [ExpectedWarning ("IL2026", "--BaseType.VirtualMethodRequires--")] - [ExpectedWarning ("IL3002", "--BaseType.VirtualMethodRequires--", ProducedBy = Tool.Analyzer | Tool.NativeAot)] - [ExpectedWarning ("IL3050", "--BaseType.VirtualMethodRequires--", ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3002", "--BaseType.VirtualMethodRequires--", Tool.Analyzer | Tool.NativeAot, "")] + [ExpectedWarning ("IL3050", "--BaseType.VirtualMethodRequires--", Tool.Analyzer | Tool.NativeAot, "")] static void TestCallOnBase () { var tmp = new BaseType (); @@ -55,8 +55,8 @@ static void TestCallOnBase () } [ExpectedWarning ("IL2026", "--BaseType.VirtualMethodRequires--")] - [ExpectedWarning ("IL3002", "--BaseType.VirtualMethodRequires--", ProducedBy = Tool.Analyzer | Tool.NativeAot)] - [ExpectedWarning ("IL3050", "--BaseType.VirtualMethodRequires--", ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3002", "--BaseType.VirtualMethodRequires--", Tool.Analyzer | Tool.NativeAot, "")] + [ExpectedWarning ("IL3050", "--BaseType.VirtualMethodRequires--", Tool.Analyzer | Tool.NativeAot, "")] static void TestCallOnOverride () { var tmp = new TypeWhichOverridesMethod (); @@ -64,8 +64,8 @@ static void TestCallOnOverride () } [ExpectedWarning ("IL2026", "--BaseType.VirtualMethodRequires--")] - [ExpectedWarning ("IL3002", "--BaseType.VirtualMethodRequires--", ProducedBy = Tool.Analyzer | Tool.NativeAot)] - [ExpectedWarning ("IL3050", "--BaseType.VirtualMethodRequires--", ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3002", "--BaseType.VirtualMethodRequires--", Tool.Analyzer | Tool.NativeAot, "")] + [ExpectedWarning ("IL3050", "--BaseType.VirtualMethodRequires--", Tool.Analyzer | Tool.NativeAot, "")] static void TestCallOnOverrideViaBase () { BaseType tmp = new TypeWhichOverridesMethod (); @@ -73,11 +73,11 @@ static void TestCallOnOverrideViaBase () } [ExpectedWarning ("IL2026", "--BaseType.VirtualMethodRequires--")] - [ExpectedWarning ("IL3002", "--BaseType.VirtualMethodRequires--", ProducedBy = Tool.NativeAot)] - [ExpectedWarning ("IL3050", "--BaseType.VirtualMethodRequires--", ProducedBy = Tool.NativeAot)] + [ExpectedWarning ("IL3002", "--BaseType.VirtualMethodRequires--", Tool.NativeAot, "")] + [ExpectedWarning ("IL3050", "--BaseType.VirtualMethodRequires--", Tool.NativeAot, "")] [ExpectedWarning ("IL2026", "--TypeWhichOverridesMethod.VirtualMethodRequires--")] - [ExpectedWarning ("IL3002", "--TypeWhichOverridesMethod.VirtualMethodRequires--", ProducedBy = Tool.NativeAot)] - [ExpectedWarning ("IL3050", "--TypeWhichOverridesMethod.VirtualMethodRequires--", ProducedBy = Tool.NativeAot)] + [ExpectedWarning ("IL3002", "--TypeWhichOverridesMethod.VirtualMethodRequires--", Tool.NativeAot, "")] + [ExpectedWarning ("IL3050", "--TypeWhichOverridesMethod.VirtualMethodRequires--", Tool.NativeAot, "")] static void TestDirectReflectionAccess () { BaseType tmp = new TypeWhichOverridesMethod (); @@ -90,11 +90,11 @@ static void TestDirectReflectionAccess () } [ExpectedWarning ("IL2026", "--BaseType.VirtualMethodRequires--")] - [ExpectedWarning ("IL3002", "--BaseType.VirtualMethodRequires--", ProducedBy = Tool.NativeAot)] - [ExpectedWarning ("IL3050", "--BaseType.VirtualMethodRequires--", ProducedBy = Tool.NativeAot)] + [ExpectedWarning ("IL3002", "--BaseType.VirtualMethodRequires--", Tool.NativeAot, "")] + [ExpectedWarning ("IL3050", "--BaseType.VirtualMethodRequires--", Tool.NativeAot, "")] [ExpectedWarning ("IL2026", "--TypeWhichOverridesMethod.VirtualMethodRequires--")] - [ExpectedWarning ("IL3002", "--TypeWhichOverridesMethod.VirtualMethodRequires--", ProducedBy = Tool.NativeAot)] - [ExpectedWarning ("IL3050", "--TypeWhichOverridesMethod.VirtualMethodRequires--", ProducedBy = Tool.NativeAot)] + [ExpectedWarning ("IL3002", "--TypeWhichOverridesMethod.VirtualMethodRequires--", Tool.NativeAot, "")] + [ExpectedWarning ("IL3050", "--TypeWhichOverridesMethod.VirtualMethodRequires--", Tool.NativeAot, "")] static void TestAnnotatedReflectionAccess() { CallMethodWithRequiresOnInstance(new TypeWhichOverridesMethod ()); @@ -133,8 +133,8 @@ public override int VirtualPropertyRequires { } [ExpectedWarning ("IL2026", "--PropertyBaseType.VirtualPropertyRequires--")] - [ExpectedWarning ("IL3002", "--PropertyBaseType.VirtualPropertyRequires--", ProducedBy = Tool.Analyzer | Tool.NativeAot)] - [ExpectedWarning ("IL3050", "--PropertyBaseType.VirtualPropertyRequires--", ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3002", "--PropertyBaseType.VirtualPropertyRequires--", Tool.Analyzer | Tool.NativeAot, "")] + [ExpectedWarning ("IL3050", "--PropertyBaseType.VirtualPropertyRequires--", Tool.Analyzer | Tool.NativeAot, "")] static void CallOnDerived () { var tmp = new TypeWhichOverridesProperty (); @@ -171,8 +171,8 @@ public void MethodWithRequires () } [ExpectedWarning ("IL2026", "--IRequires.MethodWithRequires--")] - [ExpectedWarning ("IL3002", "--IRequires.MethodWithRequires--", ProducedBy = Tool.Analyzer | Tool.NativeAot)] - [ExpectedWarning ("IL3050", "--IRequires.MethodWithRequires--", ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3002", "--IRequires.MethodWithRequires--", Tool.Analyzer | Tool.NativeAot, "")] + [ExpectedWarning ("IL3050", "--IRequires.MethodWithRequires--", Tool.Analyzer | Tool.NativeAot, "")] static void TestCallViaInterface () { IRequires inst = new ImplementationClass (); @@ -180,8 +180,8 @@ static void TestCallViaInterface () } [ExpectedWarning ("IL2026", "--ImplementationClass.RequiresMethod--")] - [ExpectedWarning ("IL3002", "--ImplementationClass.RequiresMethod--", ProducedBy = Tool.Analyzer | Tool.NativeAot)] - [ExpectedWarning ("IL3050", "--ImplementationClass.RequiresMethod--", ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3002", "--ImplementationClass.RequiresMethod--", Tool.Analyzer | Tool.NativeAot, "")] + [ExpectedWarning ("IL3050", "--ImplementationClass.RequiresMethod--", Tool.Analyzer | Tool.NativeAot, "")] static void TestCallViaImplementationClass () { ImplementationClass inst = new ImplementationClass (); @@ -189,8 +189,8 @@ static void TestCallViaImplementationClass () } [ExpectedWarning ("IL2026", "--ImplementationClass.RequiresMethod--")] - [ExpectedWarning ("IL3002", "--ImplementationClass.RequiresMethod--", ProducedBy = Tool.NativeAot)] - [ExpectedWarning ("IL3050", "--ImplementationClass.RequiresMethod--", ProducedBy = Tool.NativeAot)] + [ExpectedWarning ("IL3002", "--ImplementationClass.RequiresMethod--", Tool.NativeAot, "")] + [ExpectedWarning ("IL3050", "--ImplementationClass.RequiresMethod--", Tool.NativeAot, "")] static void TestDirectReflectionAccess () { typeof (ImplementationClass).GetMethod ("MethodWithRequires").Invoke (new ImplementationClass (), Array.Empty ()); @@ -202,8 +202,8 @@ static void TestDirectReflectionAccess () } [ExpectedWarning ("IL2026", "--ImplementationClass.RequiresMethod--")] - [ExpectedWarning ("IL3002", "--ImplementationClass.RequiresMethod--", ProducedBy = Tool.NativeAot)] - [ExpectedWarning ("IL3050", "--ImplementationClass.RequiresMethod--", ProducedBy = Tool.NativeAot)] + [ExpectedWarning ("IL3002", "--ImplementationClass.RequiresMethod--", Tool.NativeAot, "")] + [ExpectedWarning ("IL3050", "--ImplementationClass.RequiresMethod--", Tool.NativeAot, "")] static void TestAnnotatedReflectionAccess () { CallMethodWithRequiresOnInstance (new ImplementationClass ()); @@ -240,8 +240,8 @@ public override DerivedReturnType GetRequires () } [ExpectedWarning ("IL2026", "--CovariantReturnDerived.GetRequires--")] - [ExpectedWarning ("IL3002", "--CovariantReturnDerived.GetRequires--", ProducedBy = Tool.Analyzer | Tool.NativeAot)] - [ExpectedWarning ("IL3050", "--CovariantReturnDerived.GetRequires--", ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3002", "--CovariantReturnDerived.GetRequires--", Tool.Analyzer | Tool.NativeAot, "")] + [ExpectedWarning ("IL3050", "--CovariantReturnDerived.GetRequires--", Tool.Analyzer | Tool.NativeAot, "")] static void CallOnDerived () { var tmp = new CovariantReturnDerived (); @@ -276,8 +276,8 @@ public override DerivedReturnType GetRequires () } [ExpectedWarning ("IL2026", "--CovariantReturnViaLdftn.Derived.GetRequires--")] - [ExpectedWarning ("IL3002", "--CovariantReturnViaLdftn.Derived.GetRequires--", ProducedBy = Tool.Analyzer | Tool.NativeAot)] - [ExpectedWarning ("IL3050", "--CovariantReturnViaLdftn.Derived.GetRequires--", ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3002", "--CovariantReturnViaLdftn.Derived.GetRequires--", Tool.Analyzer | Tool.NativeAot, "")] + [ExpectedWarning ("IL3050", "--CovariantReturnViaLdftn.Derived.GetRequires--", Tool.Analyzer | Tool.NativeAot, "")] public static void Test () { var tmp = new Derived (); @@ -305,12 +305,12 @@ public virtual void RUCMethod () { } [ExpectedWarning ("IL2026", "Message for --NewSlotVirtual.Base.RUCMethod--")] // Reflection triggered warnings are not produced by analyzer for RDC/RAS - [ExpectedWarning ("IL3002", "Message for --NewSlotVirtual.Base.RUCMethod--", ProducedBy = Tool.NativeAot)] - [ExpectedWarning ("IL3050", "Message for --NewSlotVirtual.Base.RUCMethod--", ProducedBy = Tool.NativeAot)] + [ExpectedWarning ("IL3002", "Message for --NewSlotVirtual.Base.RUCMethod--", Tool.NativeAot, "")] + [ExpectedWarning ("IL3050", "Message for --NewSlotVirtual.Base.RUCMethod--", Tool.NativeAot, "")] [ExpectedWarning ("IL2026", "Message for --NewSlotVirtual.Derived.RUCMethod--")] // Reflection triggered warnings are not produced by analyzer for RDC/RAS - [ExpectedWarning ("IL3002", "Message for --NewSlotVirtual.Derived.RUCMethod--", ProducedBy = Tool.NativeAot)] - [ExpectedWarning ("IL3050", "Message for --NewSlotVirtual.Derived.RUCMethod--", ProducedBy = Tool.NativeAot)] + [ExpectedWarning ("IL3002", "Message for --NewSlotVirtual.Derived.RUCMethod--", Tool.NativeAot, "")] + [ExpectedWarning ("IL3050", "Message for --NewSlotVirtual.Derived.RUCMethod--", Tool.NativeAot, "")] public static void Test () { typeof (Derived).RequiresPublicMethods (); @@ -343,11 +343,11 @@ public static void AbstractMethod () { } } [ExpectedWarning ("IL2026", "--StaticInterfaces.IRequires.VirtualMethod--")] - [ExpectedWarning ("IL3002", "--StaticInterfaces.IRequires.VirtualMethod--", ProducedBy = Tool.Analyzer | Tool.NativeAot)] - [ExpectedWarning ("IL3050", "--StaticInterfaces.IRequires.VirtualMethod--", ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3002", "--StaticInterfaces.IRequires.VirtualMethod--", Tool.Analyzer | Tool.NativeAot, "")] + [ExpectedWarning ("IL3050", "--StaticInterfaces.IRequires.VirtualMethod--", Tool.Analyzer | Tool.NativeAot, "")] [ExpectedWarning ("IL2026", "--StaticInterfaces.IRequires.AbstractMethod--")] - [ExpectedWarning ("IL3002", "--StaticInterfaces.IRequires.AbstractMethod--", ProducedBy = Tool.Analyzer | Tool.NativeAot)] - [ExpectedWarning ("IL3050", "--StaticInterfaces.IRequires.AbstractMethod--", ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3002", "--StaticInterfaces.IRequires.AbstractMethod--", Tool.Analyzer | Tool.NativeAot, "")] + [ExpectedWarning ("IL3050", "--StaticInterfaces.IRequires.AbstractMethod--", Tool.Analyzer | Tool.NativeAot, "")] static void UseRequiresMethods () where T : IRequires { T.AbstractMethod (); diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/RequiresCapability/RequiresViaDataflow.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/RequiresCapability/RequiresViaDataflow.cs index bec62cf5dbc49c..36720cf6a486c6 100644 --- a/src/tools/illink/test/Mono.Linker.Tests.Cases/RequiresCapability/RequiresViaDataflow.cs +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/RequiresCapability/RequiresViaDataflow.cs @@ -60,11 +60,11 @@ public override void VirtualMethodRequires () } [ExpectedWarning ("IL2026", "TypeWhichOverridesMethod.VirtualMethodRequires()", "--TypeWhichOverridesMethod.VirtualMethodRequires--")] - [ExpectedWarning ("IL3002", "TypeWhichOverridesMethod.VirtualMethodRequires()", "--TypeWhichOverridesMethod.VirtualMethodRequires--", ProducedBy = Tool.NativeAot)] - [ExpectedWarning ("IL3050", "TypeWhichOverridesMethod.VirtualMethodRequires()", "--TypeWhichOverridesMethod.VirtualMethodRequires--", ProducedBy = Tool.NativeAot)] + [ExpectedWarning ("IL3002", "TypeWhichOverridesMethod.VirtualMethodRequires()", "--TypeWhichOverridesMethod.VirtualMethodRequires--", Tool.NativeAot, "")] + [ExpectedWarning ("IL3050", "TypeWhichOverridesMethod.VirtualMethodRequires()", "--TypeWhichOverridesMethod.VirtualMethodRequires--", Tool.NativeAot, "")] [ExpectedWarning ("IL2026", "BaseType.VirtualMethodRequires()", "--BaseType.VirtualMethodRequires--")] - [ExpectedWarning ("IL3002", "BaseType.VirtualMethodRequires()", "--BaseType.VirtualMethodRequires--", ProducedBy = Tool.NativeAot)] - [ExpectedWarning ("IL3050", "BaseType.VirtualMethodRequires()", "--BaseType.VirtualMethodRequires--", ProducedBy = Tool.NativeAot)] + [ExpectedWarning ("IL3002", "BaseType.VirtualMethodRequires()", "--BaseType.VirtualMethodRequires--", Tool.NativeAot, "")] + [ExpectedWarning ("IL3050", "BaseType.VirtualMethodRequires()", "--BaseType.VirtualMethodRequires--", Tool.NativeAot, "")] static void TestOverriddenVirtualMethod () { MethodWithAnnotatedParameter (typeof (TypeWhichOverridesMethod)); @@ -93,8 +93,8 @@ public TypeWithPublicMethods () { } } [ExpectedWarning ("IL2026", "--AccessedThroughGenericParameterAnnotation.TypeWithRequiresMethod.MethodWhichRequires--")] - [ExpectedWarning ("IL3002", "--AccessedThroughGenericParameterAnnotation.TypeWithRequiresMethod.MethodWhichRequires--", ProducedBy = Tool.NativeAot)] - [ExpectedWarning ("IL3050", "--AccessedThroughGenericParameterAnnotation.TypeWithRequiresMethod.MethodWhichRequires--", ProducedBy = Tool.NativeAot)] + [ExpectedWarning ("IL3002", "--AccessedThroughGenericParameterAnnotation.TypeWithRequiresMethod.MethodWhichRequires--", Tool.NativeAot, "")] + [ExpectedWarning ("IL3050", "--AccessedThroughGenericParameterAnnotation.TypeWithRequiresMethod.MethodWhichRequires--", Tool.NativeAot, "")] static void TestAccessOnGenericType () { new TypeWithPublicMethods (); @@ -103,8 +103,8 @@ static void TestAccessOnGenericType () static void MethodWithPublicMethods<[DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] T> () { } [ExpectedWarning ("IL2026", "--AccessedThroughGenericParameterAnnotation.TypeWithRequiresMethod.MethodWhichRequires--")] - [ExpectedWarning ("IL3002", "--AccessedThroughGenericParameterAnnotation.TypeWithRequiresMethod.MethodWhichRequires--", ProducedBy = Tool.NativeAot)] - [ExpectedWarning ("IL3050", "--AccessedThroughGenericParameterAnnotation.TypeWithRequiresMethod.MethodWhichRequires--", ProducedBy = Tool.NativeAot)] + [ExpectedWarning ("IL3002", "--AccessedThroughGenericParameterAnnotation.TypeWithRequiresMethod.MethodWhichRequires--", Tool.NativeAot, "")] + [ExpectedWarning ("IL3050", "--AccessedThroughGenericParameterAnnotation.TypeWithRequiresMethod.MethodWhichRequires--", Tool.NativeAot, "")] static void TestAccessOnGenericMethod () { MethodWithPublicMethods (); @@ -113,8 +113,8 @@ static void TestAccessOnGenericMethod () static void MethodWithPublicMethodsInference<[DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] T> (T instance) { } [ExpectedWarning ("IL2026", "--AccessedThroughGenericParameterAnnotation.TypeWithRequiresMethod.MethodWhichRequires--")] - [ExpectedWarning ("IL3002", "--AccessedThroughGenericParameterAnnotation.TypeWithRequiresMethod.MethodWhichRequires--", ProducedBy = Tool.NativeAot)] - [ExpectedWarning ("IL3050", "--AccessedThroughGenericParameterAnnotation.TypeWithRequiresMethod.MethodWhichRequires--", ProducedBy = Tool.NativeAot)] + [ExpectedWarning ("IL3002", "--AccessedThroughGenericParameterAnnotation.TypeWithRequiresMethod.MethodWhichRequires--", Tool.NativeAot, "")] + [ExpectedWarning ("IL3050", "--AccessedThroughGenericParameterAnnotation.TypeWithRequiresMethod.MethodWhichRequires--", Tool.NativeAot, "")] static void TestAccessOnGenericMethodWithInferenceOnMethod () { MethodWithPublicMethodsInference (new TypeWithRequiresMethod ()); @@ -138,9 +138,9 @@ static void RequiresInDynamicDependency () } // https://github.com/dotnet/runtime/issues/83080 - Analyzer doesn't recognize DynamicDependency in any way - [ExpectedWarning ("IL2026", "--RequiresInDynamicDependency--", ProducedBy = Tool.Trimmer | Tool.NativeAot)] - [ExpectedWarning ("IL3002", "--RequiresInDynamicDependency--", ProducedBy = Tool.NativeAot)] - [ExpectedWarning ("IL3050", "--RequiresInDynamicDependency--", ProducedBy = Tool.NativeAot)] + [ExpectedWarning ("IL2026", "--RequiresInDynamicDependency--", Tool.Trimmer | Tool.NativeAot, "")] + [ExpectedWarning ("IL3002", "--RequiresInDynamicDependency--", Tool.NativeAot, "")] + [ExpectedWarning ("IL3050", "--RequiresInDynamicDependency--", Tool.NativeAot, "")] [DynamicDependency ("RequiresInDynamicDependency")] public static void Test () { diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/RequiresCapability/RequiresViaXml.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/RequiresCapability/RequiresViaXml.cs index ab0ecd81cab7ed..eb0c4fcde0a1af 100644 --- a/src/tools/illink/test/Mono.Linker.Tests.Cases/RequiresCapability/RequiresViaXml.cs +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/RequiresCapability/RequiresViaXml.cs @@ -17,7 +17,7 @@ class RequiresViaXml // The second attribute is added through link attribute XML [RequiresUnreferencedCode ("Message for --MethodWithDuplicateRequiresAttribute--")] - [ExpectedWarning ("IL2027", "RequiresUnreferencedCodeAttribute", nameof (MethodWithDuplicateRequiresAttribute), ProducedBy = Tool.Trimmer)] + [ExpectedWarning ("IL2027", "RequiresUnreferencedCodeAttribute", nameof (MethodWithDuplicateRequiresAttribute), Tool.Trimmer, "")] static void MethodWithDuplicateRequiresAttribute () { } diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/RequiresCapability/RequiresWithCopyAssembly.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/RequiresCapability/RequiresWithCopyAssembly.cs index 91485b261a5fdc..e935d941878588 100644 --- a/src/tools/illink/test/Mono.Linker.Tests.Cases/RequiresCapability/RequiresWithCopyAssembly.cs +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/RequiresCapability/RequiresWithCopyAssembly.cs @@ -29,11 +29,11 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability class RequiresWithCopyAssembly { [ExpectedWarning ("IL2026", "--IDerivedInterface.MethodInDerivedInterface--")] - [ExpectedWarning ("IL3002", "--IDerivedInterface.MethodInDerivedInterface--", ProducedBy = Tool.NativeAot)] - [ExpectedWarning ("IL3050", "--IDerivedInterface.MethodInDerivedInterface--", ProducedBy = Tool.NativeAot)] + [ExpectedWarning ("IL3002", "--IDerivedInterface.MethodInDerivedInterface--", Tool.NativeAot, "")] + [ExpectedWarning ("IL3050", "--IDerivedInterface.MethodInDerivedInterface--", Tool.NativeAot, "")] [ExpectedWarning ("IL2026", "--IBaseInterface.MethodInBaseInterface--")] - [ExpectedWarning ("IL3002", "--IBaseInterface.MethodInBaseInterface--", ProducedBy = Tool.NativeAot)] - [ExpectedWarning ("IL3050", "--IBaseInterface.MethodInBaseInterface--", ProducedBy = Tool.NativeAot)] + [ExpectedWarning ("IL3002", "--IBaseInterface.MethodInBaseInterface--", Tool.NativeAot, "")] + [ExpectedWarning ("IL3050", "--IBaseInterface.MethodInBaseInterface--", Tool.NativeAot, "")] public static void Main () { TestRequiresInMethodFromCopiedAssembly (); @@ -42,8 +42,8 @@ public static void Main () } [ExpectedWarning ("IL2026", "--Method--")] - [ExpectedWarning ("IL3002", "--Method--", ProducedBy = Tool.Analyzer | Tool.NativeAot)] - [ExpectedWarning ("IL3050", "--Method--", ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3002", "--Method--", Tool.Analyzer | Tool.NativeAot, "")] + [ExpectedWarning ("IL3050", "--Method--", Tool.Analyzer | Tool.NativeAot, "")] static void TestRequiresInMethodFromCopiedAssembly () { var tmp = new RequiresInCopyAssembly (); @@ -51,8 +51,8 @@ static void TestRequiresInMethodFromCopiedAssembly () } [ExpectedWarning ("IL2026", "--MethodCalledThroughReflection--")] - [ExpectedWarning ("IL3002", "--MethodCalledThroughReflection--", ProducedBy = Tool.NativeAot)] - [ExpectedWarning ("IL3050", "--MethodCalledThroughReflection--", ProducedBy = Tool.NativeAot)] + [ExpectedWarning ("IL3002", "--MethodCalledThroughReflection--", Tool.NativeAot, "")] + [ExpectedWarning ("IL3050", "--MethodCalledThroughReflection--", Tool.NativeAot, "")] static void TestRequiresThroughReflectionInMethodFromCopiedAssembly () { typeof (RequiresInCopyAssembly) diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/SingleFile/SingleFileIntrinsics.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/SingleFile/SingleFileIntrinsics.cs index 5273af0230c104..617e286e1e641d 100644 --- a/src/tools/illink/test/Mono.Linker.Tests.Cases/SingleFile/SingleFileIntrinsics.cs +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/SingleFile/SingleFileIntrinsics.cs @@ -27,7 +27,7 @@ public static void Main () TestAssemblyGetFilesSuppressedByRAF (); } - [ExpectedWarning("IL3000", ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning("IL3000", Tool.Analyzer | Tool.NativeAot, "")] static void TestAssemblyLocation() { var a = typeof (SingleFileIntrinsics).Assembly.Location; @@ -39,7 +39,7 @@ static void TestAssemblyLocationSuppressedByRAF() var a = typeof (SingleFileIntrinsics).Assembly.Location; } - [ExpectedWarning ("IL3000", ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3000", Tool.Analyzer | Tool.NativeAot, "")] static void TestAssemblyNameCodeBase() { var a = typeof (SingleFileIntrinsics).Assembly.GetName ().CodeBase; @@ -51,7 +51,7 @@ static void TestAssemblyNameCodeBaseSuppressedByRAF () var a = typeof (SingleFileIntrinsics).Assembly.GetName ().CodeBase; } - [ExpectedWarning ("IL3000", ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3000", Tool.Analyzer | Tool.NativeAot, "")] static void TestAssemblyNameEscapedCodeBase () { var a = typeof (SingleFileIntrinsics).Assembly.GetName ().EscapedCodeBase; @@ -63,7 +63,7 @@ static void TestAssemblyNameEscapedCodeBaseSuppressedByRAF () var a = typeof (SingleFileIntrinsics).Assembly.GetName ().EscapedCodeBase; } - [ExpectedWarning ("IL3001", ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3001", Tool.Analyzer | Tool.NativeAot, "")] static void TestAssemblyGetFile() { var a = typeof (SingleFileIntrinsics).Assembly.GetFile ("unknown"); @@ -75,8 +75,8 @@ static void TestAssemblyGetFileSuppressedByRAF () var a = typeof (SingleFileIntrinsics).Assembly.GetFile ("unknown"); } - [ExpectedWarning ("IL3001", ProducedBy = Tool.Analyzer | Tool.NativeAot)] - [ExpectedWarning ("IL3001", ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3001", Tool.Analyzer | Tool.NativeAot, "")] + [ExpectedWarning ("IL3001", Tool.Analyzer | Tool.NativeAot, "")] static void TestAssemblyGetFiles () { var a = typeof (SingleFileIntrinsics).Assembly.GetFiles (); diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/Substitutions/FeatureGuardSubstitutions.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/Substitutions/FeatureGuardSubstitutions.cs index e34f2b4bbfd3fc..b4723f3505437f 100644 --- a/src/tools/illink/test/Mono.Linker.Tests.Cases/Substitutions/FeatureGuardSubstitutions.cs +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/Substitutions/FeatureGuardSubstitutions.cs @@ -93,8 +93,8 @@ static void TestGuardAssemblyFiles () RequiresAssemblyFiles (); } - [ExpectedWarning ("IL4000", nameof (RequiresDynamicCodeAttribute), ProducedBy = Tool.Analyzer)] - [ExpectedWarning ("IL4000", nameof (RequiresUnreferencedCodeAttribute), ProducedBy = Tool.Analyzer)] + [ExpectedWarning ("IL4000", nameof (RequiresDynamicCodeAttribute), Tool.Analyzer, "")] + [ExpectedWarning ("IL4000", nameof (RequiresUnreferencedCodeAttribute), Tool.Analyzer, "")] [FeatureGuard (typeof (RequiresDynamicCodeAttribute))] [FeatureGuard (typeof (RequiresUnreferencedCodeAttribute))] static bool GuardDynamicCodeAndUnreferencedCode => RuntimeFeature.IsDynamicCodeSupported && TestFeatures.IsUnreferencedCodeSupported; @@ -152,7 +152,7 @@ static void TestIndirectGuard () [FeatureSwitchDefinition ("Mono.Linker.Tests.Cases.Substitutions.FeatureGuardSubstitutions.DefineFeatureGuard.FeatureSwitch")] static bool FeatureSwitch => AppContext.TryGetSwitch ("Mono.Linker.Tests.Cases.Substitutions.FeatureGuardSubstitutions.DefineFeatureGuard.FeatureSwitch", out bool isEnabled) && isEnabled; - [ExpectedWarning ("IL2026", ProducedBy = Tool.Analyzer)] // Analyzer doesn't respect FeatureSwitchDefinition or feature settings + [ExpectedWarning ("IL2026", Tool.Analyzer, "")] // Analyzer doesn't respect FeatureSwitchDefinition or feature settings [ExpectedInstructionSequence (new[] { "nop", "ldc.i4.0", @@ -169,7 +169,7 @@ static void TestFeatureSwitch () RequiresUnreferencedCode (); } - [ExpectedWarning ("IL4000", nameof (RequiresUnreferencedCodeAttribute), ProducedBy = Tool.Analyzer)] + [ExpectedWarning ("IL4000", nameof (RequiresUnreferencedCodeAttribute), Tool.Analyzer, "")] [FeatureSwitchDefinition ("Mono.Linker.Tests.Cases.Substitutions.FeatureGuardSubstitutions.DefineFeatureGuard.FeatureSwitchAndGuard")] [FeatureGuard (typeof (RequiresUnreferencedCodeAttribute))] static bool FeatureSwitchAndGuard => AppContext.TryGetSwitch ("Mono.Linker.Tests.Cases.Substitutions.FeatureGuardSubstitutions.DefineFeatureGuard.FeatureSwitchAndGuard", out bool isEnabled) && isEnabled; @@ -264,7 +264,7 @@ public static void Test () [Kept] class FeatureGuardPrecedence { - [ExpectedWarning ("IL4000", nameof (RequiresUnreferencedCodeAttribute), ProducedBy = Tool.Analyzer)] + [ExpectedWarning ("IL4000", nameof (RequiresUnreferencedCodeAttribute), Tool.Analyzer, "")] [FeatureSwitchDefinition ("Mono.Linker.Tests.Cases.Substitutions.FeatureGuardSubstitutions.FeatureGuardPrecedence.GuardAndSwitch")] [FeatureGuard (typeof (RequiresUnreferencedCodeAttribute))] static bool GuardAndSwitch => AppContext.TryGetSwitch ("Mono.Linker.Tests.Cases.Substitutions.FeatureGuardSubstitutions.FeatureGuardPrecedence.GuardAndSwitch", out bool isEnabled) && isEnabled; @@ -281,7 +281,7 @@ class FeatureGuardPrecedence { "ret" })] // ILLink/ILCompiler ignore FeatureGuard on properties that also have FeatureSwitchDefinition - [ExpectedWarning ("IL2026", ProducedBy = Tool.Trimmer | Tool.NativeAot)] + [ExpectedWarning ("IL2026", Tool.Trimmer | Tool.NativeAot, "")] static void TestSwitchWinsOverGuard () { if (GuardAndSwitch) @@ -291,7 +291,7 @@ static void TestSwitchWinsOverGuard () [Kept] [KeptAttributeAttribute (typeof (FeatureSwitchDefinitionAttribute))] [KeptAttributeAttribute (typeof (FeatureGuardAttribute))] - [ExpectedWarning ("IL4000", nameof (RequiresUnreferencedCodeAttribute), ProducedBy = Tool.Analyzer)] + [ExpectedWarning ("IL4000", nameof (RequiresUnreferencedCodeAttribute), Tool.Analyzer, "")] [FeatureSwitchDefinition ("Mono.Linker.Tests.Cases.Substitutions.FeatureGuardSubstitutions.FeatureGuardPrecedence.GuardAndSwitchNotSet")] [FeatureGuard (typeof (RequiresUnreferencedCodeAttribute))] static bool GuardAndSwitchNotSet { @@ -301,7 +301,7 @@ static bool GuardAndSwitchNotSet { [Kept] // No IL modifications because feature is not set, and FeatureGuard is ignored due to FeatureSwitchDefinition. - [ExpectedWarning ("IL2026", ProducedBy = Tool.Trimmer | Tool.NativeAot)] + [ExpectedWarning ("IL2026", Tool.Trimmer | Tool.NativeAot, "")] static void TestSwitchNotSetWinsOverGuard () { if (GuardAndSwitchNotSet) @@ -322,7 +322,7 @@ static void TestSwitchNotSetWinsOverGuard () "nop", "ret" })] - [ExpectedWarning ("IL2026", ProducedBy = Tool.Trimmer | Tool.NativeAot)] + [ExpectedWarning ("IL2026", Tool.Trimmer | Tool.NativeAot, "")] static void TestXmlWinsOverGuard () { if (GuardWithXml) @@ -331,7 +331,7 @@ static void TestXmlWinsOverGuard () [KeptAttributeAttribute (typeof (FeatureSwitchDefinitionAttribute))] [KeptAttributeAttribute (typeof (FeatureGuardAttribute))] - [ExpectedWarning ("IL4000", nameof (RequiresUnreferencedCodeAttribute), ProducedBy = Tool.Analyzer)] + [ExpectedWarning ("IL4000", nameof (RequiresUnreferencedCodeAttribute), Tool.Analyzer, "")] [FeatureSwitchDefinition ("Mono.Linker.Tests.Cases.Substitutions.FeatureGuardSubstitutions.FeatureGuardPrecedence.SwitchWithXml")] [FeatureGuard (typeof (RequiresUnreferencedCodeAttribute))] static bool SwitchWithXml => AppContext.TryGetSwitch ("Mono.Linker.Tests.Cases.Substitutions.FeatureGuardSubstitutions.FeatureGuardPrecedence.SwitchWithXml", out bool isEnabled) && isEnabled; @@ -348,7 +348,7 @@ static void TestXmlWinsOverGuard () "nop", "ret" })] - [ExpectedWarning ("IL2026", ProducedBy = Tool.Trimmer | Tool.NativeAot)] + [ExpectedWarning ("IL2026", Tool.Trimmer | Tool.NativeAot, "")] static void TestXmlWinsOverSwitch () { if (SwitchWithXml) RequiresUnreferencedCode (); @@ -356,7 +356,7 @@ static void TestXmlWinsOverSwitch () { [KeptAttributeAttribute (typeof (FeatureSwitchDefinitionAttribute))] [KeptAttributeAttribute (typeof (FeatureGuardAttribute))] - [ExpectedWarning ("IL4000", nameof (RequiresUnreferencedCodeAttribute), ProducedBy = Tool.Analyzer)] + [ExpectedWarning ("IL4000", nameof (RequiresUnreferencedCodeAttribute), Tool.Analyzer, "")] [FeatureSwitchDefinition ("Mono.Linker.Tests.Cases.Substitutions.FeatureGuardPrecedence.GuardAndSwitchWithXml")] [FeatureGuard (typeof (RequiresUnreferencedCodeAttribute))] static bool GuardAndSwitchWithXml => AppContext.TryGetSwitch ("Mono.Linker.Tests.Cases.Substitutions.FeatureGuardSubstitutions.FeatureGuardPrecedence.GuardAndSwitchWithXml", out bool isEnabled) && isEnabled; @@ -373,7 +373,7 @@ static void TestXmlWinsOverSwitch () { "nop", "ret" })] - [ExpectedWarning ("IL2026", ProducedBy = Tool.Trimmer | Tool.NativeAot)] + [ExpectedWarning ("IL2026", Tool.Trimmer | Tool.NativeAot, "")] static void TestXmlWinsOverGuardAndSwitch () { if (GuardAndSwitchWithXml) RequiresUnreferencedCode (); diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/Substitutions/FeatureGuardSubstitutionsDisabled.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/Substitutions/FeatureGuardSubstitutionsDisabled.cs index 198595d79394df..725f849d9093c2 100644 --- a/src/tools/illink/test/Mono.Linker.Tests.Cases/Substitutions/FeatureGuardSubstitutionsDisabled.cs +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/Substitutions/FeatureGuardSubstitutionsDisabled.cs @@ -25,7 +25,7 @@ public static void Main () } [Kept] - [ExpectedWarning ("IL4000", ProducedBy = Tool.Analyzer)] + [ExpectedWarning ("IL4000", Tool.Analyzer, "")] [KeptAttributeAttribute (typeof (FeatureGuardAttribute))] [FeatureGuard (typeof (RequiresUnreferencedCodeAttribute))] static bool GuardUnreferencedCode { @@ -46,7 +46,7 @@ static void TestGuard () static bool FeatureSwitch => throw null; [Kept] - [ExpectedWarning ("IL2026", ProducedBy = Tool.Analyzer)] + [ExpectedWarning ("IL2026", Tool.Analyzer, "")] // Feature switches are still substituted when feature guard substitutions are disabled [ExpectBodyModified] static void TestFeatureSwitch () diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/Substitutions/ResourceSubstitutions.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/Substitutions/ResourceSubstitutions.cs index 9bdf9075dae9bc..d52432adfb10db 100644 --- a/src/tools/illink/test/Mono.Linker.Tests.Cases/Substitutions/ResourceSubstitutions.cs +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/Substitutions/ResourceSubstitutions.cs @@ -15,4 +15,4 @@ public static void Main () { } } -} \ No newline at end of file +} diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/Warnings/WarningSuppression/DetectRedundantSuppressionsFeatureSubstitutions.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/Warnings/WarningSuppression/DetectRedundantSuppressionsFeatureSubstitutions.cs index 2f271f000919f2..ac8cf603419363 100644 --- a/src/tools/illink/test/Mono.Linker.Tests.Cases/Warnings/WarningSuppression/DetectRedundantSuppressionsFeatureSubstitutions.cs +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/Warnings/WarningSuppression/DetectRedundantSuppressionsFeatureSubstitutions.cs @@ -43,7 +43,7 @@ class ReportRedundantSuppressionWhenTrimmerIncompatibleCodeDisabled // With feature switched to false, the trimming tools see only the 'else' branch. // The 'else' branch contains trimmer-compatible code, the trimming tools identifies the suppression as redundant. - [ExpectedWarning ("IL2121", "IL2072", ProducedBy = Tool.Trimmer)] + [ExpectedWarning ("IL2121", "IL2072", Tool.Trimmer, "")] [UnconditionalSuppressMessage ("Test", "IL2072")] public static void Test () { diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/Warnings/WarningSuppression/DetectRedundantSuppressionsFromXML.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/Warnings/WarningSuppression/DetectRedundantSuppressionsFromXML.cs index 4d669f696fc225..aab9f007288864 100644 --- a/src/tools/illink/test/Mono.Linker.Tests.Cases/Warnings/WarningSuppression/DetectRedundantSuppressionsFromXML.cs +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/Warnings/WarningSuppression/DetectRedundantSuppressionsFromXML.cs @@ -8,8 +8,8 @@ namespace Mono.Linker.Tests.Cases.Warnings.WarningSuppression { [SkipKeptItemsValidation] [ExpectedNoWarnings] - [ExpectedWarning ("IL2121", "IL2026", ProducedBy = Tool.Trimmer, FileName = "DetectRedundantSuppressionsFromXML.xml", SourceLine = 7)] - [ExpectedWarning ("IL2121", "IL2109", ProducedBy = Tool.Trimmer, FileName = "DetectRedundantSuppressionsFromXML.xml", SourceLine = 12)] + [ExpectedWarning ("IL2121", "IL2026", Tool.Trimmer, "", FileName = "DetectRedundantSuppressionsFromXML.xml", SourceLine = 7)] + [ExpectedWarning ("IL2121", "IL2109", Tool.Trimmer, "", FileName = "DetectRedundantSuppressionsFromXML.xml", SourceLine = 12)] [SetupLinkAttributesFile ("DetectRedundantSuppressionsFromXML.xml")] public class DetectRedundantSuppressionsFromXML { @@ -32,4 +32,4 @@ static void DoNotTriggerWarning () { } class DoNotTriggerWarningType { } } } -} \ No newline at end of file +} diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/Warnings/WarningSuppression/DetectRedundantSuppressionsInAssembly.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/Warnings/WarningSuppression/DetectRedundantSuppressionsInAssembly.cs index b1b985278a0a56..38995365302402 100644 --- a/src/tools/illink/test/Mono.Linker.Tests.Cases/Warnings/WarningSuppression/DetectRedundantSuppressionsInAssembly.cs +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/Warnings/WarningSuppression/DetectRedundantSuppressionsInAssembly.cs @@ -4,7 +4,7 @@ using System.Diagnostics.CodeAnalysis; using Mono.Linker.Tests.Cases.Expectations.Assertions; -[assembly: ExpectedWarning ("IL2121", "IL2071", ProducedBy = Tool.Trimmer)] +[assembly: ExpectedWarning ("IL2121", "IL2071", Tool.Trimmer, "")] [assembly: UnconditionalSuppressMessage ("Test", "IL2071:Redundant suppression, warning is not issued in this assembly")] diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/Warnings/WarningSuppression/DetectRedundantSuppressionsInCompilerGeneratedCode.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/Warnings/WarningSuppression/DetectRedundantSuppressionsInCompilerGeneratedCode.cs index a707584bef3655..54082fccd74e5a 100644 --- a/src/tools/illink/test/Mono.Linker.Tests.Cases/Warnings/WarningSuppression/DetectRedundantSuppressionsInCompilerGeneratedCode.cs +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/Warnings/WarningSuppression/DetectRedundantSuppressionsInCompilerGeneratedCode.cs @@ -34,7 +34,7 @@ public class RedundantSuppressionOnLocalMethod { public static void Test () { - [ExpectedWarning ("IL2121", "IL2071", ProducedBy = Tool.Trimmer)] + [ExpectedWarning ("IL2121", "IL2071", Tool.Trimmer, "")] [UnconditionalSuppressMessage ("Test", "IL2071")] void LocalMethod () { @@ -52,7 +52,7 @@ public static void Test () Enumerable (); } - [ExpectedWarning ("IL2121", "IL2071", ProducedBy = Tool.Trimmer)] + [ExpectedWarning ("IL2121", "IL2071", Tool.Trimmer, "")] [UnconditionalSuppressMessage ("Test", "IL2071")] static IEnumerable Enumerable () { @@ -63,7 +63,7 @@ static IEnumerable Enumerable () public class RedundantSuppressionInAsyncBody { - [ExpectedWarning ("IL2121", "IL2071", ProducedBy = Tool.Trimmer)] + [ExpectedWarning ("IL2121", "IL2071", Tool.Trimmer, "")] [UnconditionalSuppressMessage ("Test", "IL2071")] public static async void Test () { @@ -71,7 +71,7 @@ public static async void Test () await MethodAsync (); } - [ExpectedWarning ("IL2121", "IL2070", ProducedBy = Tool.Trimmer)] + [ExpectedWarning ("IL2121", "IL2070", Tool.Trimmer, "")] [UnconditionalSuppressMessage ("Test", "IL2070")] static async Task MethodAsync () { diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/Warnings/WarningSuppression/DetectRedundantSuppressionsInMembersAndTypes.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/Warnings/WarningSuppression/DetectRedundantSuppressionsInMembersAndTypes.cs index 56998d29aee59a..884ceb4a6c81b5 100644 --- a/src/tools/illink/test/Mono.Linker.Tests.Cases/Warnings/WarningSuppression/DetectRedundantSuppressionsInMembersAndTypes.cs +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/Warnings/WarningSuppression/DetectRedundantSuppressionsInMembersAndTypes.cs @@ -50,7 +50,7 @@ public static string TrimmerCompatibleMethod () return "test"; } - [ExpectedWarning ("IL2121", "IL2071", ProducedBy = Tool.Trimmer)] + [ExpectedWarning ("IL2121", "IL2071", Tool.Trimmer, "")] [UnconditionalSuppressMessage ("Test", "IL2071")] public class RedundantSuppressionOnType { @@ -62,7 +62,7 @@ public static void Test () public class RedundantSuppressionOnMethod { - [ExpectedWarning ("IL2121", "IL2071", ProducedBy = Tool.Trimmer)] + [ExpectedWarning ("IL2121", "IL2071", Tool.Trimmer, "")] [UnconditionalSuppressMessage ("Test", "IL2071")] public static void Test () { @@ -77,7 +77,7 @@ public static void Test () NestedType.TrimmerCompatibleMethod (); } - [ExpectedWarning ("IL2121", "IL2071", ProducedBy = Tool.Trimmer)] + [ExpectedWarning ("IL2121", "IL2071", Tool.Trimmer, "")] [UnconditionalSuppressMessage ("Test", "IL2071")] public class NestedType { @@ -96,7 +96,7 @@ public static void Test () } public static string TrimmerCompatibleProperty { - [ExpectedWarning ("IL2121", "IL2071", ProducedBy = Tool.Trimmer)] + [ExpectedWarning ("IL2121", "IL2071", Tool.Trimmer, "")] [UnconditionalSuppressMessage ("Test", "IL2071")] get { return TrimmerCompatibleMethod (); @@ -112,7 +112,7 @@ public static void Test () TrimmerCompatibleProperty = "test"; } - [ExpectedWarning ("IL2121", "IL2071", ProducedBy = Tool.Trimmer)] + [ExpectedWarning ("IL2121", "IL2071", Tool.Trimmer, "")] [UnconditionalSuppressMessage ("Test", "IL2071")] public static string TrimmerCompatibleProperty { get { @@ -131,7 +131,7 @@ public static void Test () var property = TrimmerCompatibleProperty; } - [ExpectedWarning ("IL2121", "IL2071", ProducedBy = Tool.Trimmer)] + [ExpectedWarning ("IL2121", "IL2071", Tool.Trimmer, "")] [UnconditionalSuppressMessage ("Test", "IL2071")] public static string TrimmerCompatibleProperty { get { @@ -147,7 +147,7 @@ public static void Test () TrimmerCompatibleProperty = "test"; } - [ExpectedWarning ("IL2121", "IL2071", ProducedBy = Tool.Trimmer)] + [ExpectedWarning ("IL2121", "IL2071", Tool.Trimmer, "")] [UnconditionalSuppressMessage ("Test", "IL2071")] public static string TrimmerCompatibleProperty { set { @@ -163,7 +163,7 @@ public static void Test () typeof (RedundantSuppressionOnPropertyAccessedByReflection).GetProperty ("TrimmerCompatibleProperty"); } - [ExpectedWarning ("IL2121", "IL2071", ProducedBy = Tool.Trimmer)] + [ExpectedWarning ("IL2121", "IL2071", Tool.Trimmer, "")] [UnconditionalSuppressMessage ("Test", "IL2071")] public static string TrimmerCompatibleProperty { get { @@ -185,7 +185,7 @@ static void EventSubscriber (object sender, EventArgs e) } public static event EventHandler TrimmerCompatibleEvent { - [ExpectedWarning ("IL2121", "IL2072", ProducedBy = Tool.Trimmer)] + [ExpectedWarning ("IL2121", "IL2072", Tool.Trimmer, "")] [UnconditionalSuppressMessage ("Test", "IL2072")] add { TrimmerCompatibleMethod (); } remove { } @@ -204,7 +204,7 @@ static void EventSubscriber (object sender, EventArgs e) } - [ExpectedWarning ("IL2121", "IL2072", ProducedBy = Tool.Trimmer)] + [ExpectedWarning ("IL2121", "IL2072", Tool.Trimmer, "")] [UnconditionalSuppressMessage ("Test", "IL2072")] public static event EventHandler TrimmerCompatibleEvent { add { TrimmerCompatibleMethod (); } @@ -219,7 +219,7 @@ public static void Test () typeof (RedundantSuppressionOnEventAccessedByReflection).GetEvent ("TrimmerCompatibleEvent"); } - [ExpectedWarning ("IL2121", "IL2072", ProducedBy = Tool.Trimmer)] + [ExpectedWarning ("IL2121", "IL2072", Tool.Trimmer, "")] [UnconditionalSuppressMessage ("Test", "IL2072")] public static event EventHandler TrimmerCompatibleEvent { add { TrimmerCompatibleMethod (); } @@ -227,15 +227,15 @@ public static event EventHandler TrimmerCompatibleEvent { } } - [ExpectedWarning ("IL2121", "IL2072", ProducedBy = Tool.Trimmer)] + [ExpectedWarning ("IL2121", "IL2072", Tool.Trimmer, "")] [UnconditionalSuppressMessage ("Test", "IL2072")] - [ExpectedWarning ("IL2121", "IL2071", ProducedBy = Tool.Trimmer)] + [ExpectedWarning ("IL2121", "IL2071", Tool.Trimmer, "")] [UnconditionalSuppressMessage ("Test", "IL2071")] public class MultipleRedundantSuppressions { - [ExpectedWarning ("IL2121", "IL2072", ProducedBy = Tool.Trimmer)] + [ExpectedWarning ("IL2121", "IL2072", Tool.Trimmer, "")] [UnconditionalSuppressMessage ("Test", "IL2072")] - [ExpectedWarning ("IL2121", "IL2071", ProducedBy = Tool.Trimmer)] + [ExpectedWarning ("IL2121", "IL2071", Tool.Trimmer, "")] [UnconditionalSuppressMessage ("Test", "IL2071")] public static void Test () { @@ -245,7 +245,7 @@ public static void Test () public class RedundantAndUsedSuppressions { - [ExpectedWarning ("IL2121", "IL2071", ProducedBy = Tool.Trimmer)] + [ExpectedWarning ("IL2121", "IL2071", Tool.Trimmer, "")] [UnconditionalSuppressMessage ("Test", "IL2071")] [UnconditionalSuppressMessage ("Test", "IL2072")] public static void Test () @@ -317,7 +317,7 @@ public static void Test () MethodMarkedRUC (); } - [ExpectedWarning ("IL2121", "IL2072", ProducedBy = Tool.Trimmer)] + [ExpectedWarning ("IL2121", "IL2072", Tool.Trimmer, "")] [UnconditionalSuppressMessage ("Test", "IL2072")] [RequiresUnreferencedCode ("Test")] public static void MethodMarkedRUC () diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/Warnings/WarningSuppression/DetectRedundantSuppressionsInMembersAndTypesUsingTarget.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/Warnings/WarningSuppression/DetectRedundantSuppressionsInMembersAndTypesUsingTarget.cs index 5991e418197f08..6b6c3df46f5bf2 100644 --- a/src/tools/illink/test/Mono.Linker.Tests.Cases/Warnings/WarningSuppression/DetectRedundantSuppressionsInMembersAndTypesUsingTarget.cs +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/Warnings/WarningSuppression/DetectRedundantSuppressionsInMembersAndTypesUsingTarget.cs @@ -37,7 +37,7 @@ public static string TrimmerCompatibleMethod () return "test"; } - [ExpectedWarning ("IL2121", "IL2071", ProducedBy = Tool.Trimmer)] + [ExpectedWarning ("IL2121", "IL2071", Tool.Trimmer, "")] public class RedundantSuppressionOnType { public static void Test () @@ -48,7 +48,7 @@ public static void Test () public class RedundantSuppressionOnMethod { - [ExpectedWarning ("IL2121", "IL2071", ProducedBy = Tool.Trimmer)] + [ExpectedWarning ("IL2121", "IL2071", Tool.Trimmer, "")] public static void Test () { TrimmerCompatibleMethod (); @@ -62,7 +62,7 @@ public static void Test () NestedType.TrimmerCompatibleMethod (); } - [ExpectedWarning ("IL2121", "IL2071", ProducedBy = Tool.Trimmer)] + [ExpectedWarning ("IL2121", "IL2071", Tool.Trimmer, "")] public class NestedType { public static void TrimmerCompatibleMethod () @@ -80,7 +80,7 @@ public static void Test () } public static string TrimmerCompatibleProperty { - [ExpectedWarning ("IL2121", "IL2071", ProducedBy = Tool.Trimmer)] + [ExpectedWarning ("IL2121", "IL2071", Tool.Trimmer, "")] get { return TrimmerCompatibleMethod (); } diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/Warnings/WarningSuppression/DetectRedundantSuppressionsInModule.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/Warnings/WarningSuppression/DetectRedundantSuppressionsInModule.cs index 9dc15690107d39..da7717bc6c14b7 100644 --- a/src/tools/illink/test/Mono.Linker.Tests.Cases/Warnings/WarningSuppression/DetectRedundantSuppressionsInModule.cs +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/Warnings/WarningSuppression/DetectRedundantSuppressionsInModule.cs @@ -4,7 +4,7 @@ using System.Diagnostics.CodeAnalysis; using Mono.Linker.Tests.Cases.Expectations.Assertions; -[assembly: ExpectedWarning ("IL2121", "IL2071", ProducedBy = Tool.Trimmer)] +[assembly: ExpectedWarning ("IL2121", "IL2071", Tool.Trimmer, "")] [module: UnconditionalSuppressMessage ("Test", "IL2071:Redundant suppression, warning is not issued in this assembly")] diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/Warnings/WarningSuppression/SuppressWarningsInCompilerGeneratedCode.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/Warnings/WarningSuppression/SuppressWarningsInCompilerGeneratedCode.cs index 5e3d6023c3b1fa..8506a09edb66c6 100644 --- a/src/tools/illink/test/Mono.Linker.Tests.Cases/Warnings/WarningSuppression/SuppressWarningsInCompilerGeneratedCode.cs +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/Warnings/WarningSuppression/SuppressWarningsInCompilerGeneratedCode.cs @@ -278,7 +278,7 @@ static void TestCallRUCMethodInLtftnLocalFunction () class DynamicallyAccessedLocalFunction { - [ExpectedWarning ("IL2118", "LocalFunction", ProducedBy = Tool.Trimmer)] + [ExpectedWarning ("IL2118", "LocalFunction", Tool.Trimmer, "")] [UnconditionalSuppressMessage ("Test", "IL2026")] public static void TestCallRUCMethodInDynamicallyAccessedLocalFunction () { @@ -426,7 +426,7 @@ static void TestGenericTypeParameterRequirement () class DynamicallyAccessedLambda { - [ExpectedWarning ("IL2118", nameof (TestCallRUCMethodInDynamicallyAccessedLambda), ProducedBy = Tool.Trimmer)] + [ExpectedWarning ("IL2118", nameof (TestCallRUCMethodInDynamicallyAccessedLambda), Tool.Trimmer, "")] [UnconditionalSuppressMessage ("Test", "IL2026")] public static void TestCallRUCMethodInDynamicallyAccessedLambda () { @@ -440,7 +440,7 @@ public static void TestCallRUCMethodInDynamicallyAccessedLambda () class DynamicallyAccessedLambdaUnused { - [ExpectedWarning ("IL2118", nameof (TestCallRUCMethodInDynamicallyAccessedLambda), ProducedBy = Tool.Trimmer)] + [ExpectedWarning ("IL2118", nameof (TestCallRUCMethodInDynamicallyAccessedLambda), Tool.Trimmer, "")] [UnconditionalSuppressMessage ("Test", "IL2026")] public static void TestCallRUCMethodInDynamicallyAccessedLambda () { @@ -454,7 +454,7 @@ static void TestSuppressionOnLambda () { var lambda = // https://github.com/dotnet/roslyn/issues/59746 - [ExpectedWarning ("IL2026", ProducedBy = Tool.Analyzer)] + [ExpectedWarning ("IL2026", Tool.Analyzer, "")] [UnconditionalSuppressMessage ("Test", "IL2026")] () => RequiresUnreferencedCodeMethod (); @@ -466,7 +466,7 @@ static void TestSuppressionOnOuterAndLambda () { var lambda = // https://github.com/dotnet/roslyn/issues/59746 - [ExpectedWarning ("IL2026", ProducedBy = Tool.Analyzer)] + [ExpectedWarning ("IL2026", Tool.Analyzer, "")] [UnconditionalSuppressMessage ("Test", "IL2026")] (Type unknownType) => { RequiresUnreferencedCodeMethod (); @@ -577,8 +577,8 @@ static IEnumerable TestDynamicallyAccessedMethodViaGenericMethodParameterIn static event EventHandler TestEvent; // https://github.com/dotnet/runtime/issues/82956 - the suppression is ignored - [ExpectedWarning ("IL2026", CompilerGeneratedCode = true, ProducedBy = Tool.Trimmer | Tool.NativeAot)] - [ExpectedWarning ("IL2121", CompilerGeneratedCode = true, ProducedBy = Tool.Trimmer)] + [ExpectedWarning ("IL2026", Tool.Trimmer | Tool.NativeAot, "", CompilerGeneratedCode = true)] + [ExpectedWarning ("IL2121", Tool.Trimmer, "", CompilerGeneratedCode = true)] static void TestLambdaInLocalFunction () { LocalFunction (); @@ -595,7 +595,7 @@ void LocalFunction () // https://github.com/dotnet/runtime/issues/82956 - the suppression is ignored // https://github.com/dotnet/roslyn/issues/59746 [ExpectedWarning ("IL2026", CompilerGeneratedCode = true)] - [ExpectedWarning ("IL2121", CompilerGeneratedCode = true, ProducedBy = Tool.Trimmer)] + [ExpectedWarning ("IL2121", Tool.Trimmer, "", CompilerGeneratedCode = true)] static void TestLocalFunctionInLambda () { TestEvent += diff --git a/src/tools/illink/test/Mono.Linker.Tests/TestCasesRunner/ResultChecker.cs b/src/tools/illink/test/Mono.Linker.Tests/TestCasesRunner/ResultChecker.cs index 2f05eab1e4c666..8b4dd418554a5a 100644 --- a/src/tools/illink/test/Mono.Linker.Tests/TestCasesRunner/ResultChecker.cs +++ b/src/tools/illink/test/Mono.Linker.Tests/TestCasesRunner/ResultChecker.cs @@ -223,7 +223,7 @@ void VerifyExitCode (TrimmedTestCaseResult linkResult, AssemblyDefinition origin Assert.AreEqual (expectedExitCode, linkResult.ExitCode, $"Expected exit code {expectedExitCode} but got {linkResult.ExitCode}. Output was:\n{FormatLinkerOutput()}"); } else { if (linkResult.ExitCode != 0) { - Assert.Fail($"Linker exited with an unexpected non-zero exit code of {linkResult.ExitCode} and output:\n{FormatLinkerOutput()}"); + Assert.Fail ($"Linker exited with an unexpected non-zero exit code of {linkResult.ExitCode} and output:\n{FormatLinkerOutput()}"); } } @@ -734,6 +734,9 @@ void VerifyKeptAllTypesAndMembersInAssembly (AssemblyDefinition linked) static bool IsProducedByLinker (CustomAttribute attr) { + if (attr.Constructor.Parameters.Count > 2 && attr.ConstructorArguments[^2].Type.Name == "Tool") { + return ((Tool)attr.ConstructorArguments[^2].Value).HasFlag (Tool.Trimmer) == true; + } var producedBy = attr.GetPropertyValue ("ProducedBy"); return producedBy is null ? true : ((Tool) producedBy).HasFlag (Tool.Trimmer); } @@ -794,12 +797,29 @@ void VerifyLoggedMessages (AssemblyDefinition original, TrimmingTestLogger logge } break; - case nameof (ExpectedWarningAttribute): { + case nameof (ExpectedWarningAttribute) or nameof(UnexpectedWarningAttribute): { var expectedWarningCode = (string) attr.GetConstructorArgumentValue (0); if (!expectedWarningCode.StartsWith ("IL")) { - Assert.Fail ($"The warning code specified in {nameof (ExpectedWarningAttribute)} must start with the 'IL' prefix. Specified value: '{expectedWarningCode}'."); + Assert.Fail ($"The warning code specified in {attr.AttributeType.Name} must start with the 'IL' prefix. Specified value: '{expectedWarningCode}'."); } - var expectedMessageContains = ((CustomAttributeArgument[]) attr.GetConstructorArgumentValue (1)).Select (a => (string) a.Value).ToArray (); + IEnumerable expectedMessageContains = attr.Constructor.Parameters switch + { + // ExpectedWarningAttribute(string warningCode, params string[] expectedMessages) + // ExpectedWarningAttribute(string warningCode, string[] expectedMessages, Tool producedBy, string issueLink) + [_, { ParameterType.IsArray: true }, ..] + => ((CustomAttributeArgument[])attr.ConstructorArguments[1].Value) + .Select(caa => (string)caa.Value), + // ExpectedWarningAttribute(string warningCode, string expectedMessage1, string expectedMessage2, Tool producedBy, string issueLink) + [_, { ParameterType.Name: "String" }, { ParameterType.Name: "String" }, { ParameterType.Name: "Tool" }, _] + => [(string)attr.GetConstructorArgumentValue(1), (string)attr.GetConstructorArgumentValue(2)], + // ExpectedWarningAttribute(string warningCode, string expectedMessage, Tool producedBy, string issueLink) + [_, { ParameterType.Name: "String" }, { ParameterType.Name: "Tool" }, _] + => [(string)attr.GetConstructorArgumentValue(1)], + // ExpectedWarningAttribute(string warningCode, Tool producedBy, string issueLink) + [_, { ParameterType.Name: "Tool" }, _] + => [], + _ => throw new UnreachableException(), + }; string fileName = (string) attr.GetPropertyValue ("FileName"); int? sourceLine = (int?) attr.GetPropertyValue ("SourceLine"); int? sourceColumn = (int?) attr.GetPropertyValue ("SourceColumn"); From 6f549af4151409467ccf4d2d39ac11716b68d63c Mon Sep 17 00:00:00 2001 From: Fan Yang <52458914+fanyang-mono@users.noreply.github.com> Date: Fri, 26 Apr 2024 21:28:09 -0400 Subject: [PATCH 113/161] [mono] UnsafeAccessor: Add support for non-generic method instance (#101442) * Support non generic instance * Create helper function for shared code * Use an existing API * Add an assert --------- Co-authored-by: Larry Ewing --- src/mono/mono/metadata/class.c | 2 +- src/mono/mono/metadata/marshal-lightweight.c | 73 ++++++++++++++++--- src/mono/mono/metadata/unsafe-accessor.c | 22 ++---- src/mono/mono/mini/method-to-ir.c | 2 +- .../UnsafeAccessorsTests.Generics.cs | 4 - 5 files changed, 72 insertions(+), 31 deletions(-) diff --git a/src/mono/mono/metadata/class.c b/src/mono/mono/metadata/class.c index 6045628bf49e7f..01888dfbabd57b 100644 --- a/src/mono/mono/metadata/class.c +++ b/src/mono/mono/metadata/class.c @@ -5264,7 +5264,7 @@ mono_class_get_fields_internal (MonoClass *klass, gpointer *iter) * mono_class_get_methods: * \param klass the \c MonoClass to act on * - * This routine is an iterator routine for retrieving the fields in a class. + * This routine is an iterator routine for retrieving the methods in a class. * * You must pass a \c gpointer that points to zero and is treated as an opaque handle to * iterate over all of the elements. When no more values are diff --git a/src/mono/mono/metadata/marshal-lightweight.c b/src/mono/mono/metadata/marshal-lightweight.c index 6399b315cfd208..245b5dbe572507 100644 --- a/src/mono/mono/metadata/marshal-lightweight.c +++ b/src/mono/mono/metadata/marshal-lightweight.c @@ -2371,6 +2371,44 @@ emit_missing_method_error (MonoMethodBuilder *mb, MonoError *failure, const char } } +static MonoMethodSignature * +update_signature (MonoMethod *accessor_method) +{ + MonoClass *accessor_method_class_instance = accessor_method->klass; + MonoClass *accessor_method_class = mono_class_get_generic_type_definition (accessor_method_class_instance); + + const char *accessor_method_name = accessor_method->name; + + gpointer iter = NULL; + MonoMethod *m = NULL; + while ((m = mono_class_get_methods (accessor_method_class, &iter))) { + if (!m) + continue; + + if (strcmp (m->name, accessor_method_name)) + continue; + + return mono_metadata_signature_dup_full (get_method_image (m), mono_method_signature_internal (m)); + } + g_assert_not_reached (); +} + +static MonoMethod * +inflate_method (MonoClass *klass, MonoMethod *method, MonoMethod *accessor_method, MonoError *error) +{ + MonoMethod *result = method; + MonoGenericContext context = { NULL, NULL }; + if (mono_class_is_ginst (klass)) + context.class_inst = mono_class_get_generic_class (klass)->context.class_inst; + if (accessor_method->is_inflated) + context.method_inst = mono_method_get_context (accessor_method)->method_inst; + if ((context.class_inst != NULL) || (context.method_inst != NULL)) + result = mono_class_inflate_generic_method_checked (method, &context, error); + mono_error_assert_ok (error); + + return result; +} + static void emit_unsafe_accessor_ctor_wrapper (MonoMethodBuilder *mb, MonoMethod *accessor_method, MonoMethodSignature *sig, MonoGenericContext *ctx, MonoUnsafeAccessorKind kind, const char *member_name) { @@ -2389,12 +2427,17 @@ emit_unsafe_accessor_ctor_wrapper (MonoMethodBuilder *mb, MonoMethod *accessor_m return; } - MonoMethodSignature *member_sig = ctor_sig_from_accessor_sig (mb, sig, ctx); - MonoClass *target_class = mono_class_from_mono_type_internal (target_type); ERROR_DECL(find_method_error); - MonoClass *in_class = mono_class_is_ginst (target_class) ? mono_class_get_generic_class (target_class)->container_class : target_class; + if (accessor_method->is_inflated) { + sig = update_signature(accessor_method); + } + + MonoMethodSignature *member_sig = ctor_sig_from_accessor_sig (mb, sig, ctx); + + MonoClass *in_class = mono_class_get_generic_type_definition (target_class); + MonoMethod *target_method = mono_unsafe_accessor_find_ctor (in_class, member_sig, target_class, find_method_error); if (!is_ok (find_method_error) || target_method == NULL) { if (mono_error_get_error_code (find_method_error) == MONO_ERROR_GENERIC) @@ -2404,6 +2447,9 @@ emit_unsafe_accessor_ctor_wrapper (MonoMethodBuilder *mb, MonoMethod *accessor_m mono_error_cleanup (find_method_error); return; } + + target_method = inflate_method (target_class, target_method, accessor_method, find_method_error); + g_assert (target_method->klass == target_class); emit_unsafe_accessor_ldargs (mb, sig, 0); @@ -2425,11 +2471,9 @@ emit_unsafe_accessor_method_wrapper (MonoMethodBuilder *mb, MonoMethod *accessor mono_mb_emit_exception_full (mb, "System", "BadImageFormatException", "Invalid usage of UnsafeAccessorAttribute."); return; } - gboolean hasthis = kind == MONO_UNSAFE_ACCESSOR_METHOD; - MonoType *target_type = sig->params[0]; - - MonoMethodSignature *member_sig = method_sig_from_accessor_sig (mb, hasthis, sig, ctx); + MonoType *target_type = sig->params[0]; + gboolean hasthis = kind == MONO_UNSAFE_ACCESSOR_METHOD; MonoClass *target_class = mono_class_from_mono_type_internal (target_type); if (hasthis && m_class_is_valuetype (target_class) && !m_type_is_byref (target_type)) { @@ -2438,7 +2482,14 @@ emit_unsafe_accessor_method_wrapper (MonoMethodBuilder *mb, MonoMethod *accessor } ERROR_DECL(find_method_error); - MonoClass *in_class = mono_class_is_ginst (target_class) ? mono_class_get_generic_class (target_class)->container_class : target_class; + if (accessor_method->is_inflated) { + sig = update_signature(accessor_method); + } + + MonoMethodSignature *member_sig = method_sig_from_accessor_sig (mb, hasthis, sig, ctx); + + MonoClass *in_class = mono_class_get_generic_type_definition (target_class); + MonoMethod *target_method = NULL; if (!ctor_as_method) target_method = mono_unsafe_accessor_find_method (in_class, member_name, member_sig, target_class, find_method_error); @@ -2452,11 +2503,15 @@ emit_unsafe_accessor_method_wrapper (MonoMethodBuilder *mb, MonoMethod *accessor mono_error_cleanup (find_method_error); return; } + + target_method = inflate_method (target_class, target_method, accessor_method, find_method_error); + if (!hasthis && target_method->klass != target_class) { emit_missing_method_error (mb, find_method_error, member_name); return; } - g_assert (target_method->klass == target_class); // are instance methods allowed to be looked up using inheritance? + + g_assert (target_method->klass == target_class); emit_unsafe_accessor_ldargs (mb, sig, !hasthis ? 1 : 0); diff --git a/src/mono/mono/metadata/unsafe-accessor.c b/src/mono/mono/metadata/unsafe-accessor.c index e7287a00c46175..584b2914658699 100644 --- a/src/mono/mono/metadata/unsafe-accessor.c +++ b/src/mono/mono/metadata/unsafe-accessor.c @@ -14,7 +14,7 @@ #include "mono/metadata/class-internals.h" #include "mono/utils/mono-error-internals.h" #include "mono/metadata/unsafe-accessor.h" - +#include static MonoMethod * @@ -134,7 +134,10 @@ find_method_slow (MonoClass *klass, const char *name, const char *qname, const c return precise_match; } mono_error_set_generic_error (error, "System.Reflection", "AmbiguousMatchException", "Ambiguity in binding of UnsafeAccessorAttribute."); - return NULL; + result->i = -1; + result->m = NULL; + result->matched = FALSE; + return result; } matched = TRUE; result->i = i; @@ -176,23 +179,10 @@ find_method_in_class_unsafe_accessor (MonoClass *klass, const char *name, const if (!is_ok(error) && mono_error_get_error_code (error) == MONO_ERROR_GENERIC) return NULL; - int mcount = mono_class_get_method_count (klass); g_assert (result != NULL); if (result->matched) { - if (result->i < mcount) - return mono_class_get_method_by_index (from_class, result->i); - else if (result->m != NULL) { - // FIXME: metadata-update: hack - // it's from a metadata-update, probably - MonoMethod * m = mono_class_inflate_generic_method_full_checked ( - result->m, from_class, mono_class_get_context (from_class), error); - mono_error_assert_ok (error); - g_assert (m != NULL); - g_assert (m->klass == from_class); - g_assert (m->is_inflated); - return m; - } + return result->m; } g_free (result); diff --git a/src/mono/mono/mini/method-to-ir.c b/src/mono/mono/mini/method-to-ir.c index c8a4fade7d30fa..40905c0ceb48f5 100644 --- a/src/mono/mono/mini/method-to-ir.c +++ b/src/mono/mono/mini/method-to-ir.c @@ -7864,7 +7864,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b UNVERIFIED; if (!cfg->gshared) - g_assert (!mono_method_check_context_used (cmethod)); + g_assertf (!mono_method_check_context_used (cmethod), "cmethod is %s", mono_method_get_full_name (cmethod)); CHECK_STACK (n); diff --git a/src/tests/baseservices/compilerservices/UnsafeAccessors/UnsafeAccessorsTests.Generics.cs b/src/tests/baseservices/compilerservices/UnsafeAccessors/UnsafeAccessorsTests.Generics.cs index e4fb9593dd3ed6..fd867ef222b693 100644 --- a/src/tests/baseservices/compilerservices/UnsafeAccessors/UnsafeAccessorsTests.Generics.cs +++ b/src/tests/baseservices/compilerservices/UnsafeAccessors/UnsafeAccessorsTests.Generics.cs @@ -140,7 +140,6 @@ sealed class Derived2 : GenericBase } [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/89439", TestRuntimes.Mono)] public static void Verify_Generic_InheritanceMethodResolution() { string expect = "abc"; @@ -230,7 +229,6 @@ sealed class Accessors } [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/89439", TestRuntimes.Mono)] public static void Verify_Generic_CallCtor() { Console.WriteLine($"Running {nameof(Verify_Generic_CallCtor)}"); @@ -312,7 +310,6 @@ public static void Verify_Generic_GenericTypeNonGenericInstanceMethod() } [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/89439", TestRuntimes.Mono)] public static void Verify_Generic_GenericTypeGenericInstanceMethod() { Console.WriteLine($"Running {nameof(Verify_Generic_GenericTypeGenericInstanceMethod)}"); @@ -366,7 +363,6 @@ public static void Verify_Generic_GenericTypeNonGenericStaticMethod() } [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/89439", TestRuntimes.Mono)] public static void Verify_Generic_GenericTypeGenericStaticMethod() { Console.WriteLine($"Running {nameof(Verify_Generic_GenericTypeGenericStaticMethod)}"); From dad01daffc3fa4e257abe8e33cb9f80fbaff71d7 Mon Sep 17 00:00:00 2001 From: Fan Yang <52458914+fanyang-mono@users.noreply.github.com> Date: Fri, 26 Apr 2024 21:31:59 -0400 Subject: [PATCH 114/161] Intrinsify SpanHelper API's (#101622) --- src/mono/mono/mini/intrinsics.c | 37 ++++++++++++++++++++++++++++++++- src/mono/mono/mini/mini-llvm.c | 32 +++++++++++++++++++++------- src/mono/mono/mini/mini-ops.h | 1 + 3 files changed, 61 insertions(+), 9 deletions(-) diff --git a/src/mono/mono/mini/intrinsics.c b/src/mono/mono/mini/intrinsics.c index 4835a84e2c9115..2c629adf59662f 100644 --- a/src/mono/mono/mini/intrinsics.c +++ b/src/mono/mono/mini/intrinsics.c @@ -283,7 +283,7 @@ llvm_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSign } } - if (in_corlib && !strcmp (m_class_get_name (cmethod->klass), "Buffer")) { + if (in_corlib && !strcmp (m_class_get_name (cmethod->klass), "SpanHelpers")) { if (!strcmp (cmethod->name, "Memmove") && fsig->param_count == 3 && m_type_is_byref (fsig->params [0]) && m_type_is_byref (fsig->params [1]) && !cmethod->is_inflated) { MonoBasicBlock *end_bb; NEW_BBLOCK (cfg, end_bb); @@ -304,6 +304,41 @@ llvm_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSign ins->sreg3 = args [2]->dreg; // i32/i64 len MONO_ADD_INS (cfg->cbb, ins); MONO_START_BB (cfg, end_bb); + } else if (!strcmp (cmethod->name, "ClearWithoutReferences") && fsig->param_count == 2 && m_type_is_byref (fsig->params [0]) && !cmethod->is_inflated) { + MonoBasicBlock *end_bb; + NEW_BBLOCK (cfg, end_bb); + + // do nothing if len == 0 (even if src is null) + MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, args [1]->dreg, 0); + MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, end_bb); + + // throw NRE if src is null + MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, args [0]->dreg, 0); + MONO_EMIT_NEW_COND_EXC (cfg, EQ, "NullReferenceException"); + + MONO_INST_NEW (cfg, ins, OP_MEMSET_ZERO); + ins->sreg1 = args [0]->dreg; // i1* dst + ins->sreg2 = args [1]->dreg; // i32/i64 len + MONO_ADD_INS (cfg->cbb, ins); + MONO_START_BB (cfg, end_bb); + } else if (!strcmp (cmethod->name, "Fill") && fsig->param_count == 3 && m_type_is_byref (fsig->params [0]) && !cmethod->is_inflated) { + MonoBasicBlock *end_bb; + NEW_BBLOCK (cfg, end_bb); + + // do nothing if len == 0 (even if src is null) + MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, args [1]->dreg, 0); + MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, end_bb); + + // throw NRE if src is null + MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, args [0]->dreg, 0); + MONO_EMIT_NEW_COND_EXC (cfg, EQ, "NullReferenceException"); + + MONO_INST_NEW (cfg, ins, OP_MEMSET); + ins->sreg1 = args [0]->dreg; // i1* dst + ins->sreg2 = args [1]->dreg; // i8 value + ins->sreg3 = args [2]->dreg; // i32/i64 len + MONO_ADD_INS (cfg->cbb, ins); + MONO_START_BB (cfg, end_bb); } } diff --git a/src/mono/mono/mini/mini-llvm.c b/src/mono/mono/mini/mini-llvm.c index 07bbe7d4e0037a..0c0f4e0cb1f2e7 100644 --- a/src/mono/mono/mini/mini-llvm.c +++ b/src/mono/mono/mini/mini-llvm.c @@ -1427,15 +1427,18 @@ convert (EmitContext *ctx, LLVMValueRef v, LLVMTypeRef dtype) } static void -emit_memset (EmitContext *ctx, LLVMValueRef v, LLVMValueRef size, int alignment) +emit_memset (EmitContext *ctx, LLVMValueRef dest, LLVMValueRef val, LLVMValueRef size, int alignment) { LLVMValueRef args [5]; int aindex = 0; - args [aindex ++] = v; - args [aindex ++] = LLVMConstInt (LLVMInt8Type (), 0, FALSE); + args [aindex ++] = dest; + if (val) + args [aindex ++] = val; + else + args [aindex ++] = LLVMConstInt (LLVMInt8Type (), 0, FALSE); args [aindex ++] = size; - args [aindex ++] = LLVMConstInt (LLVMInt1Type (), 0, FALSE); + args [aindex ++] = LLVMConstInt (LLVMInt1Type (), 0, FALSE); // is_volatile call_intrins (ctx, INTRINS_MEMSET, args, ""); } @@ -6159,7 +6162,7 @@ process_bb (EmitContext *ctx, MonoBasicBlock *bb) * load it into registers. */ LLVMValueRef buf = build_alloca_llvm_type_name (ctx, pointer_type (ret_type), 0, "ret_buf"); - emit_memset (ctx, buf, LLVMSizeOf (ret_type), 1); + emit_memset (ctx, buf, NULL, LLVMSizeOf (ret_type), 1); int width = mono_type_size (sig->ret, NULL); LLVMValueRef args [] = { @@ -7000,7 +7003,7 @@ MONO_RESTORE_WARNING v = mono_llvm_build_alloca (builder, LLVMInt8Type (), const_int32 (size), MONO_ARCH_FRAME_ALIGNMENT, ""); if (ins->flags & MONO_INST_INIT) - emit_memset (ctx, v, const_int32 (size), MONO_ARCH_FRAME_ALIGNMENT); + emit_memset (ctx, v, NULL, const_int32 (size), MONO_ARCH_FRAME_ALIGNMENT); values [ins->dreg] = v; break; @@ -7013,7 +7016,7 @@ MONO_RESTORE_WARNING v = mono_llvm_build_alloca (builder, LLVMInt8Type (), size, MONO_ARCH_FRAME_ALIGNMENT, ""); if (ins->flags & MONO_INST_INIT) - emit_memset (ctx, v, size, MONO_ARCH_FRAME_ALIGNMENT); + emit_memset (ctx, v, NULL, size, MONO_ARCH_FRAME_ALIGNMENT); values [ins->dreg] = v; break; } @@ -7231,6 +7234,19 @@ MONO_RESTORE_WARNING call_intrins (ctx, INTRINS_MEMMOVE, args, ""); break; } + case OP_MEMSET_ZERO: { + LLVMValueRef dest = convert (ctx, values [ins->sreg1], pointer_type (LLVMInt8Type ())); + LLVMValueRef size = convert (ctx, values [ins->sreg2], LLVMInt64Type ()); + emit_memset (ctx, dest, NULL, size, MONO_ARCH_FRAME_ALIGNMENT); + break; + } + case OP_MEMSET: { + LLVMValueRef dest = convert (ctx, values [ins->sreg1], pointer_type (LLVMInt8Type ())); + LLVMValueRef val = convert (ctx, values [ins->sreg2], LLVMInt8Type ()); + LLVMValueRef size = convert (ctx, values [ins->sreg3], LLVMInt64Type ()); + emit_memset (ctx, dest, val, size, MONO_ARCH_FRAME_ALIGNMENT); + break; + } case OP_NOT_REACHED: LLVMBuildUnreachable (builder); has_terminator = TRUE; @@ -7863,7 +7879,7 @@ MONO_RESTORE_WARNING addresses [ins->dreg] = create_address (ctx, build_named_alloca (ctx, m_class_get_byval_arg (klass), "vzero"), etype); } LLVMValueRef ptr = build_ptr_cast (builder, addresses [ins->dreg]->value, pointer_type (LLVMInt8Type ())); - emit_memset (ctx, ptr, const_int32 (mono_class_value_size (klass, NULL)), 0); + emit_memset (ctx, ptr, NULL, const_int32 (mono_class_value_size (klass, NULL)), 0); break; } case OP_DUMMY_VZERO: diff --git a/src/mono/mono/mini/mini-ops.h b/src/mono/mono/mini/mini-ops.h index ec82dd5de8a8c2..edf7d1b3930db4 100644 --- a/src/mono/mono/mini/mini-ops.h +++ b/src/mono/mono/mini/mini-ops.h @@ -775,6 +775,7 @@ MINI_OP(OP_LDELEMA2D, "ldelema2d", NONE, NONE, NONE) MINI_OP(OP_MEMCPY, "memcpy", NONE, NONE, NONE) /* inlined small memset with constant length */ MINI_OP(OP_MEMSET, "memset", NONE, NONE, NONE) +MINI_OP(OP_MEMSET_ZERO, "memset_zero", NONE, IREG, IREG) /* * A RuntimeType object, the result ldtoken+GetTypeFromHandle. * inst_p0 is a MonoClass. From 09b983ed0d04fd61ee35a739d080f4e8fc04de1b Mon Sep 17 00:00:00 2001 From: Andy Ayers Date: Fri, 26 Apr 2024 22:47:39 -0700 Subject: [PATCH 115/161] Allow JIT to know if dynamic pgo is active (#101575) When dynamic PGO is active we would like for all methods to have some profile data, so we don't have to handle a mixture of profiled and unprofiled methods during or after inlining. But to reduce profiling overhead, the JIT will not instrument methods that have straight-line control flow, or flow where all branches lead to throws (aka "minimal profiling"). When the JIT tries to recover profile data for these methods it won't get any data back. SO there is a fairly high volume of these profiled/unprofiled mixtures today and they lead to various poor decisions in the JIT. This change enables the JIT to see if dynamic PGO is active. The JIT does not yet do anything with the information. A subsequent change will have the JIT synthesize data for methods with no profile data in this case. We could also solve this by creating a placeholder PGO schema for theswith no data, but it seems simpler and less resource intensive to have the runtime tell the JIT that dynamic PGO is active. This also changes the JIT GUID for the new API surface. Contributes to #93020. --- src/coreclr/inc/corjit.h | 3 ++- src/coreclr/inc/icorjitinfoimpl_generated.h | 3 ++- src/coreclr/inc/jiteeversionguid.h | 10 +++++----- .../jit/ICorJitInfo_wrapper_generated.hpp | 5 +++-- src/coreclr/jit/compiler.cpp | 7 +++++-- src/coreclr/jit/compiler.h | 1 + .../tools/Common/JitInterface/CorInfoImpl.cs | 3 ++- .../Common/JitInterface/CorInfoImpl_generated.cs | 6 +++--- .../JitInterface/ThunkGenerator/ThunkInput.txt | 2 +- .../aot/jitinterface/jitinterface_generated.h | 7 ++++--- .../tools/superpmi/superpmi-shared/agnostic.h | 1 + .../superpmi/superpmi-shared/methodcontext.cpp | 16 +++++++++++----- .../superpmi/superpmi-shared/methodcontext.h | 4 ++-- .../superpmi-shim-collector/icorjitinfo.cpp | 7 ++++--- .../icorjitinfo_generated.cpp | 5 +++-- .../icorjitinfo_generated.cpp | 5 +++-- .../tools/superpmi/superpmi/icorjitinfo.cpp | 5 +++-- src/coreclr/vm/jitinterface.cpp | 7 +++++-- src/coreclr/vm/jitinterface.h | 3 ++- 19 files changed, 62 insertions(+), 38 deletions(-) diff --git a/src/coreclr/inc/corjit.h b/src/coreclr/inc/corjit.h index 4c012a7b263bf7..18a5be23fdde2d 100644 --- a/src/coreclr/inc/corjit.h +++ b/src/coreclr/inc/corjit.h @@ -452,7 +452,8 @@ class ICorJitInfo : public ICorDynamicInfo uint32_t * pCountSchemaItems, // OUT: pointer to the count of schema items in `pSchema` array. uint8_t ** pInstrumentationData, // OUT: `*pInstrumentationData` is set to the address of the instrumentation data // (pointer will not remain valid after jit completes). - PgoSource * pPgoSource // OUT: value describing source of pgo data + PgoSource * pPgoSource, // OUT: value describing source of pgo data + bool * pDynamicPgo // OUT: dynamic PGO is enabled (valid even when return value is failure) ) = 0; // Allocate a profile buffer for use in the current process diff --git a/src/coreclr/inc/icorjitinfoimpl_generated.h b/src/coreclr/inc/icorjitinfoimpl_generated.h index 98b47dced2beb0..5572a044b9b0aa 100644 --- a/src/coreclr/inc/icorjitinfoimpl_generated.h +++ b/src/coreclr/inc/icorjitinfoimpl_generated.h @@ -711,7 +711,8 @@ JITINTERFACE_HRESULT getPgoInstrumentationResults( ICorJitInfo::PgoInstrumentationSchema** pSchema, uint32_t* pCountSchemaItems, uint8_t** pInstrumentationData, - ICorJitInfo::PgoSource* pgoSource) override; + ICorJitInfo::PgoSource* pPgoSource, + bool* pDynamicPgo) override; JITINTERFACE_HRESULT allocPgoInstrumentationBySchema( CORINFO_METHOD_HANDLE ftnHnd, diff --git a/src/coreclr/inc/jiteeversionguid.h b/src/coreclr/inc/jiteeversionguid.h index 743abdaff86aea..79b6397a9111e2 100644 --- a/src/coreclr/inc/jiteeversionguid.h +++ b/src/coreclr/inc/jiteeversionguid.h @@ -43,11 +43,11 @@ typedef const GUID *LPCGUID; #define GUID_DEFINED #endif // !GUID_DEFINED -constexpr GUID JITEEVersionIdentifier = { /* 8f046bcb-ca5f-4692-9277-898b71cb7938 */ - 0x8f046bcb, - 0xca5f, - 0x4692, - {0x92, 0x77, 0x89, 0x8b, 0x71, 0xcb, 0x79, 0x38} +constexpr GUID JITEEVersionIdentifier = { /* 32d71f8e-c1f5-41cb-88cc-4e8504cabf40 */ + 0x32d71f8e, + 0xc1f5, + 0x41cb, + {0x88, 0xcc, 0x4e, 0x85, 0x04, 0xca, 0xbf, 0x40} }; ////////////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/src/coreclr/jit/ICorJitInfo_wrapper_generated.hpp b/src/coreclr/jit/ICorJitInfo_wrapper_generated.hpp index 85db2ec5efffa5..e001c56c26dcbd 100644 --- a/src/coreclr/jit/ICorJitInfo_wrapper_generated.hpp +++ b/src/coreclr/jit/ICorJitInfo_wrapper_generated.hpp @@ -1666,10 +1666,11 @@ JITINTERFACE_HRESULT WrapICorJitInfo::getPgoInstrumentationResults( ICorJitInfo::PgoInstrumentationSchema** pSchema, uint32_t* pCountSchemaItems, uint8_t** pInstrumentationData, - ICorJitInfo::PgoSource* pgoSource) + ICorJitInfo::PgoSource* pPgoSource, + bool* pDynamicPgo) { API_ENTER(getPgoInstrumentationResults); - JITINTERFACE_HRESULT temp = wrapHnd->getPgoInstrumentationResults(ftnHnd, pSchema, pCountSchemaItems, pInstrumentationData, pgoSource); + JITINTERFACE_HRESULT temp = wrapHnd->getPgoInstrumentationResults(ftnHnd, pSchema, pCountSchemaItems, pInstrumentationData, pPgoSource, pDynamicPgo); API_LEAVE(getPgoInstrumentationResults); return temp; } diff --git a/src/coreclr/jit/compiler.cpp b/src/coreclr/jit/compiler.cpp index d0bda29cb30891..60f306307b90cd 100644 --- a/src/coreclr/jit/compiler.cpp +++ b/src/coreclr/jit/compiler.cpp @@ -2791,11 +2791,13 @@ void Compiler::compInitOptions(JitFlags* jitFlags) fgPgoHaveWeights = false; fgPgoSynthesized = false; fgPgoConsistent = false; + fgPgoDynamic = false; if (jitFlags->IsSet(JitFlags::JIT_FLAG_BBOPT)) { - fgPgoQueryResult = info.compCompHnd->getPgoInstrumentationResults(info.compMethodHnd, &fgPgoSchema, - &fgPgoSchemaCount, &fgPgoData, &fgPgoSource); + fgPgoQueryResult = + info.compCompHnd->getPgoInstrumentationResults(info.compMethodHnd, &fgPgoSchema, &fgPgoSchemaCount, + &fgPgoData, &fgPgoSource, &fgPgoDynamic); // a failed result that also has a non-NULL fgPgoSchema // indicates that the ILSize for the method no longer matches @@ -2818,6 +2820,7 @@ void Compiler::compInitOptions(JitFlags* jitFlags) fgPgoData = nullptr; fgPgoSchema = nullptr; fgPgoDisabled = true; + fgPgoDynamic = false; } #ifdef DEBUG // Optionally, enable use of profile data for only some methods. diff --git a/src/coreclr/jit/compiler.h b/src/coreclr/jit/compiler.h index 7949058066494d..deb7b97943dc81 100644 --- a/src/coreclr/jit/compiler.h +++ b/src/coreclr/jit/compiler.h @@ -6285,6 +6285,7 @@ class Compiler unsigned fgPgoInlineeNoPgoSingleBlock; bool fgPgoHaveWeights; bool fgPgoSynthesized; + bool fgPgoDynamic; bool fgPgoConsistent; #ifdef DEBUG diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs index ed04f8625d486e..31a5dd68927bd1 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs @@ -4261,7 +4261,7 @@ public static void ComputeJitPgoInstrumentationSchema(Func objec } private HRESULT getPgoInstrumentationResults(CORINFO_METHOD_STRUCT_* ftnHnd, ref PgoInstrumentationSchema* pSchema, ref uint countSchemaItems, byte** pInstrumentationData, - ref PgoSource pPgoSource) + ref PgoSource pPgoSource, ref bool pDynamicPgo) { MethodDesc methodDesc = HandleToObject(ftnHnd); @@ -4308,6 +4308,7 @@ private HRESULT getPgoInstrumentationResults(CORINFO_METHOD_STRUCT_* ftnHnd, ref countSchemaItems = pgoResults.countSchemaItems; *pInstrumentationData = pgoResults.pInstrumentationData; pPgoSource = PgoSource.Static; + pDynamicPgo = false; return pgoResults.hr; } diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoImpl_generated.cs b/src/coreclr/tools/Common/JitInterface/CorInfoImpl_generated.cs index 481c22864356c1..e4ef2264da2556 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoImpl_generated.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoImpl_generated.cs @@ -2489,12 +2489,12 @@ private static void _reportFatalError(IntPtr thisHandle, IntPtr* ppException, Co } [UnmanagedCallersOnly] - private static HRESULT _getPgoInstrumentationResults(IntPtr thisHandle, IntPtr* ppException, CORINFO_METHOD_STRUCT_* ftnHnd, PgoInstrumentationSchema** pSchema, uint* pCountSchemaItems, byte** pInstrumentationData, PgoSource* pgoSource) + private static HRESULT _getPgoInstrumentationResults(IntPtr thisHandle, IntPtr* ppException, CORINFO_METHOD_STRUCT_* ftnHnd, PgoInstrumentationSchema** pSchema, uint* pCountSchemaItems, byte** pInstrumentationData, PgoSource* pPgoSource, bool* pDynamicPgo) { var _this = GetThis(thisHandle); try { - return _this.getPgoInstrumentationResults(ftnHnd, ref *pSchema, ref *pCountSchemaItems, pInstrumentationData, ref *pgoSource); + return _this.getPgoInstrumentationResults(ftnHnd, ref *pSchema, ref *pCountSchemaItems, pInstrumentationData, ref *pPgoSource, ref *pDynamicPgo); } catch (Exception ex) { @@ -2764,7 +2764,7 @@ private static IntPtr GetUnmanagedCallbacks() callbacks[165] = (delegate* unmanaged)&_logMsg; callbacks[166] = (delegate* unmanaged)&_doAssert; callbacks[167] = (delegate* unmanaged)&_reportFatalError; - callbacks[168] = (delegate* unmanaged)&_getPgoInstrumentationResults; + callbacks[168] = (delegate* unmanaged)&_getPgoInstrumentationResults; callbacks[169] = (delegate* unmanaged)&_allocPgoInstrumentationBySchema; callbacks[170] = (delegate* unmanaged)&_recordCallSite; callbacks[171] = (delegate* unmanaged)&_recordRelocation; diff --git a/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt b/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt index 86674ab2b59244..2b78b23547432c 100644 --- a/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt +++ b/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt @@ -331,7 +331,7 @@ FUNCTIONS bool logMsg(unsigned level, const char* fmt, va_list args) int doAssert(const char* szFile, int iLine, const char* szExpr) void reportFatalError(CorJitResult result) - JITINTERFACE_HRESULT getPgoInstrumentationResults(CORINFO_METHOD_HANDLE ftnHnd, ICorJitInfo::PgoInstrumentationSchema** pSchema, uint32_t* pCountSchemaItems, uint8_t**pInstrumentationData, ICorJitInfo::PgoSource* pgoSource) + JITINTERFACE_HRESULT getPgoInstrumentationResults(CORINFO_METHOD_HANDLE ftnHnd, ICorJitInfo::PgoInstrumentationSchema** pSchema, uint32_t* pCountSchemaItems, uint8_t**pInstrumentationData, ICorJitInfo::PgoSource* pPgoSource, bool* pDynamicPgo) JITINTERFACE_HRESULT allocPgoInstrumentationBySchema(CORINFO_METHOD_HANDLE ftnHnd, ICorJitInfo::PgoInstrumentationSchema* pSchema, uint32_t countSchemaItems, uint8_t** pInstrumentationData) void recordCallSite(uint32_t instrOffset, CORINFO_SIG_INFO* callSig, CORINFO_METHOD_HANDLE methodHandle) void recordRelocation(void* location, void* locationRW, void* target, uint16_t fRelocType, int32_t addlDelta) diff --git a/src/coreclr/tools/aot/jitinterface/jitinterface_generated.h b/src/coreclr/tools/aot/jitinterface/jitinterface_generated.h index db1d0a721d1f15..905ddd41d82b5e 100644 --- a/src/coreclr/tools/aot/jitinterface/jitinterface_generated.h +++ b/src/coreclr/tools/aot/jitinterface/jitinterface_generated.h @@ -179,7 +179,7 @@ struct JitInterfaceCallbacks bool (* logMsg)(void * thisHandle, CorInfoExceptionClass** ppException, unsigned level, const char* fmt, va_list args); int (* doAssert)(void * thisHandle, CorInfoExceptionClass** ppException, const char* szFile, int iLine, const char* szExpr); void (* reportFatalError)(void * thisHandle, CorInfoExceptionClass** ppException, CorJitResult result); - JITINTERFACE_HRESULT (* getPgoInstrumentationResults)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_METHOD_HANDLE ftnHnd, ICorJitInfo::PgoInstrumentationSchema** pSchema, uint32_t* pCountSchemaItems, uint8_t** pInstrumentationData, ICorJitInfo::PgoSource* pgoSource); + JITINTERFACE_HRESULT (* getPgoInstrumentationResults)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_METHOD_HANDLE ftnHnd, ICorJitInfo::PgoInstrumentationSchema** pSchema, uint32_t* pCountSchemaItems, uint8_t** pInstrumentationData, ICorJitInfo::PgoSource* pPgoSource, bool* pDynamicPgo); JITINTERFACE_HRESULT (* allocPgoInstrumentationBySchema)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_METHOD_HANDLE ftnHnd, ICorJitInfo::PgoInstrumentationSchema* pSchema, uint32_t countSchemaItems, uint8_t** pInstrumentationData); void (* recordCallSite)(void * thisHandle, CorInfoExceptionClass** ppException, uint32_t instrOffset, CORINFO_SIG_INFO* callSig, CORINFO_METHOD_HANDLE methodHandle); void (* recordRelocation)(void * thisHandle, CorInfoExceptionClass** ppException, void* location, void* locationRW, void* target, uint16_t fRelocType, int32_t addlDelta); @@ -1843,10 +1843,11 @@ class JitInterfaceWrapper : public ICorJitInfo ICorJitInfo::PgoInstrumentationSchema** pSchema, uint32_t* pCountSchemaItems, uint8_t** pInstrumentationData, - ICorJitInfo::PgoSource* pgoSource) + ICorJitInfo::PgoSource* pPgoSource, + bool* pDynamicPgo) { CorInfoExceptionClass* pException = nullptr; - JITINTERFACE_HRESULT temp = _callbacks->getPgoInstrumentationResults(_thisHandle, &pException, ftnHnd, pSchema, pCountSchemaItems, pInstrumentationData, pgoSource); + JITINTERFACE_HRESULT temp = _callbacks->getPgoInstrumentationResults(_thisHandle, &pException, ftnHnd, pSchema, pCountSchemaItems, pInstrumentationData, pPgoSource, pDynamicPgo); if (pException != nullptr) throw pException; return temp; } diff --git a/src/coreclr/tools/superpmi/superpmi-shared/agnostic.h b/src/coreclr/tools/superpmi/superpmi-shared/agnostic.h index 104a7ae1fabd39..4e34350894ec79 100644 --- a/src/coreclr/tools/superpmi/superpmi-shared/agnostic.h +++ b/src/coreclr/tools/superpmi/superpmi-shared/agnostic.h @@ -519,6 +519,7 @@ struct Agnostic_GetPgoInstrumentationResults DWORD dataByteCount; DWORD result; DWORD pgoSource; + DWORD dynamicPgo; }; struct Agnostic_GetProfilingHandle diff --git a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp index 05ad1c23a6a2c9..4219aca7ca118b 100644 --- a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp @@ -5724,6 +5724,7 @@ void MethodContext::recGetPgoInstrumentationResults(CORINFO_METHOD_HANDLE ftnHnd UINT32* pCountSchemaItems, BYTE** pInstrumentationData, ICorJitInfo::PgoSource* pPgoSource, + bool* pDynamicPgo, HRESULT result) { if (GetPgoInstrumentationResults == nullptr) @@ -5754,6 +5755,7 @@ void MethodContext::recGetPgoInstrumentationResults(CORINFO_METHOD_HANDLE ftnHnd value.dataByteCount = (unsigned)maxOffset; value.result = (DWORD)result; value.pgoSource = (DWORD)*pPgoSource; + value.dynamicPgo = (DWORD)*pDynamicPgo; DWORDLONG key = CastHandle(ftnHnd); GetPgoInstrumentationResults->Add(key, value); @@ -5761,8 +5763,8 @@ void MethodContext::recGetPgoInstrumentationResults(CORINFO_METHOD_HANDLE ftnHnd } void MethodContext::dmpGetPgoInstrumentationResults(DWORDLONG key, const Agnostic_GetPgoInstrumentationResults& value) { - printf("GetPgoInstrumentationResults key ftn-%016" PRIX64 ", value res-%08X schemaCnt-%u profileBufSize-%u source-%u schema{", - key, value.result, value.countSchemaItems, value.dataByteCount, value.pgoSource); + printf("GetPgoInstrumentationResults key ftn-%016" PRIX64 ", value res-%08X schemaCnt-%u profileBufSize-%u source-%u dynamic-%u schema{", + key, value.result, value.countSchemaItems, value.dataByteCount, value.pgoSource, value.dynamicPgo); if (value.countSchemaItems > 0) { @@ -5838,7 +5840,8 @@ HRESULT MethodContext::repGetPgoInstrumentationResults(CORINFO_METHOD_HANDLE ftn ICorJitInfo::PgoInstrumentationSchema** pSchema, UINT32* pCountSchemaItems, BYTE** pInstrumentationData, - ICorJitInfo::PgoSource* pPgoSource) + ICorJitInfo::PgoSource* pPgoSource, + bool* pDynamicPgo) { DWORDLONG key = CastHandle(ftnHnd); Agnostic_GetPgoInstrumentationResults tempValue = LookupByKeyOrMiss(GetPgoInstrumentationResults, key, ": key %016" PRIX64 "", key); @@ -5848,6 +5851,7 @@ HRESULT MethodContext::repGetPgoInstrumentationResults(CORINFO_METHOD_HANDLE ftn *pCountSchemaItems = (UINT32)tempValue.countSchemaItems; *pInstrumentationData = (BYTE*)GetPgoInstrumentationResults->GetBuffer(tempValue.data_index); *pPgoSource = (ICorJitInfo::PgoSource)tempValue.pgoSource; + *pDynamicPgo = (bool)tempValue.dynamicPgo; ICorJitInfo::PgoInstrumentationSchema* pOutSchema = (ICorJitInfo::PgoInstrumentationSchema*)AllocJitTempBuffer(tempValue.countSchemaItems * sizeof(ICorJitInfo::PgoInstrumentationSchema)); @@ -7183,7 +7187,8 @@ int MethodContext::dumpMethodIdentityInfoToBuffer(char* buff, int len, bool igno UINT32 schemaCount = 0; BYTE* schemaData = nullptr; ICorJitInfo::PgoSource pgoSource = ICorJitInfo::PgoSource::Unknown; - HRESULT pgoHR = repGetPgoInstrumentationResults(pInfo->ftn, &schema, &schemaCount, &schemaData, &pgoSource); + bool dynamicPgo = false; + HRESULT pgoHR = repGetPgoInstrumentationResults(pInfo->ftn, &schema, &schemaCount, &schemaData, &pgoSource, &dynamicPgo); size_t minOffset = (size_t) ~0; size_t maxOffset = 0; @@ -7281,7 +7286,8 @@ bool MethodContext::hasPgoData(bool& hasEdgeProfile, bool& hasClassProfile, bool ICorJitInfo::PgoInstrumentationSchema* schema = nullptr; UINT32 schemaCount = 0; BYTE* schemaData = nullptr; - HRESULT pgoHR = repGetPgoInstrumentationResults(info.ftn, &schema, &schemaCount, &schemaData, &pgoSource); + bool dynamicPgo; + HRESULT pgoHR = repGetPgoInstrumentationResults(info.ftn, &schema, &schemaCount, &schemaData, &pgoSource, &dynamicPgo); if (SUCCEEDED(pgoHR)) { diff --git a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h index a530d2f58385be..2af344894e97d8 100644 --- a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h +++ b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h @@ -711,9 +711,9 @@ class MethodContext HRESULT repAllocPgoInstrumentationBySchema(CORINFO_METHOD_HANDLE ftnHnd, ICorJitInfo::PgoInstrumentationSchema* pSchema, UINT32 countSchemaItems, BYTE** pInstrumentationData); bool repAllocPgoInstrumentationBySchemaRecorded(CORINFO_METHOD_HANDLE ftnHnd, ICorJitInfo::PgoInstrumentationSchema* pSchema, UINT32 countSchemaItems, BYTE** pInstrumentationData); - void recGetPgoInstrumentationResults(CORINFO_METHOD_HANDLE ftnHnd, ICorJitInfo::PgoInstrumentationSchema** pSchema, UINT32* pCountSchemaItems, BYTE** pInstrumentationData, ICorJitInfo::PgoSource* pPgoSource, HRESULT result); + void recGetPgoInstrumentationResults(CORINFO_METHOD_HANDLE ftnHnd, ICorJitInfo::PgoInstrumentationSchema** pSchema, UINT32* pCountSchemaItems, BYTE** pInstrumentationData, ICorJitInfo::PgoSource* pPgoSource, bool* pDynamicPgo, HRESULT result); void dmpGetPgoInstrumentationResults(DWORDLONG key, const Agnostic_GetPgoInstrumentationResults& value); - HRESULT repGetPgoInstrumentationResults(CORINFO_METHOD_HANDLE ftnHnd, ICorJitInfo::PgoInstrumentationSchema** pSchema, UINT32* pCountSchemaItems, BYTE** pInstrumentationData, ICorJitInfo::PgoSource* pPgoSource); + HRESULT repGetPgoInstrumentationResults(CORINFO_METHOD_HANDLE ftnHnd, ICorJitInfo::PgoInstrumentationSchema** pSchema, UINT32* pCountSchemaItems, BYTE** pInstrumentationData, ICorJitInfo::PgoSource* pPgoSource, bool* pDynamicPgo); void recIsMoreSpecificType(CORINFO_CLASS_HANDLE cls1, CORINFO_CLASS_HANDLE cls2, bool result); void dmpIsMoreSpecificType(DLDL key, DWORD value); diff --git a/src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitinfo.cpp b/src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitinfo.cpp index d39379089794f5..ac8efbddcfeec5 100644 --- a/src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitinfo.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitinfo.cpp @@ -1947,11 +1947,12 @@ HRESULT interceptor_ICJI::getPgoInstrumentationResults(CORINFO_METHOD_HANDLE PgoInstrumentationSchema **pSchema, // pointer to the schema table which describes the instrumentation results (pointer will not remain valid after jit completes) uint32_t * pCountSchemaItems, // pointer to the count schema items uint8_t ** pInstrumentationData, // pointer to the actual instrumentation data (pointer will not remain valid after jit completes) - PgoSource* pPgoSource) + PgoSource* pPgoSource, + bool* pDynamicPgo) { mc->cr->AddCall("getPgoInstrumentationResults"); - HRESULT temp = original_ICorJitInfo->getPgoInstrumentationResults(ftnHnd, pSchema, pCountSchemaItems, pInstrumentationData, pPgoSource); - mc->recGetPgoInstrumentationResults(ftnHnd, pSchema, pCountSchemaItems, pInstrumentationData, pPgoSource, temp); + HRESULT temp = original_ICorJitInfo->getPgoInstrumentationResults(ftnHnd, pSchema, pCountSchemaItems, pInstrumentationData, pPgoSource, pDynamicPgo); + mc->recGetPgoInstrumentationResults(ftnHnd, pSchema, pCountSchemaItems, pInstrumentationData, pPgoSource, pDynamicPgo, temp); return temp; } diff --git a/src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitinfo_generated.cpp b/src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitinfo_generated.cpp index eebb80ab6b9dfa..a365cdb111e228 100644 --- a/src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitinfo_generated.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitinfo_generated.cpp @@ -1374,10 +1374,11 @@ JITINTERFACE_HRESULT interceptor_ICJI::getPgoInstrumentationResults( ICorJitInfo::PgoInstrumentationSchema** pSchema, uint32_t* pCountSchemaItems, uint8_t** pInstrumentationData, - ICorJitInfo::PgoSource* pgoSource) + ICorJitInfo::PgoSource* pPgoSource, + bool* pDynamicPgo) { mcs->AddCall("getPgoInstrumentationResults"); - return original_ICorJitInfo->getPgoInstrumentationResults(ftnHnd, pSchema, pCountSchemaItems, pInstrumentationData, pgoSource); + return original_ICorJitInfo->getPgoInstrumentationResults(ftnHnd, pSchema, pCountSchemaItems, pInstrumentationData, pPgoSource, pDynamicPgo); } JITINTERFACE_HRESULT interceptor_ICJI::allocPgoInstrumentationBySchema( diff --git a/src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitinfo_generated.cpp b/src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitinfo_generated.cpp index 6a2ca48d87cd79..0d80993f52b676 100644 --- a/src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitinfo_generated.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitinfo_generated.cpp @@ -1206,9 +1206,10 @@ JITINTERFACE_HRESULT interceptor_ICJI::getPgoInstrumentationResults( ICorJitInfo::PgoInstrumentationSchema** pSchema, uint32_t* pCountSchemaItems, uint8_t** pInstrumentationData, - ICorJitInfo::PgoSource* pgoSource) + ICorJitInfo::PgoSource* pPgoSource, + bool* pDynamicPgo) { - return original_ICorJitInfo->getPgoInstrumentationResults(ftnHnd, pSchema, pCountSchemaItems, pInstrumentationData, pgoSource); + return original_ICorJitInfo->getPgoInstrumentationResults(ftnHnd, pSchema, pCountSchemaItems, pInstrumentationData, pPgoSource, pDynamicPgo); } JITINTERFACE_HRESULT interceptor_ICJI::allocPgoInstrumentationBySchema( diff --git a/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp b/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp index 08814336a74b1f..b263c1cafdebc9 100644 --- a/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp +++ b/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp @@ -1806,11 +1806,12 @@ HRESULT MyICJI::getPgoInstrumentationResults(CORINFO_METHOD_HANDLE ftnHnd, PgoInstrumentationSchema **pSchema, // pointer to the schema table which describes the instrumentation results (pointer will not remain valid after jit completes) uint32_t * pCountSchemaItems, // pointer to the count schema items uint8_t ** pInstrumentationData, // pointer to the actual instrumentation data (pointer will not remain valid after jit completes) - PgoSource* pPgoSource) + PgoSource* pPgoSource, + bool* pDynamicPgo) { jitInstance->mc->cr->AddCall("getPgoInstrumentationResults"); - return jitInstance->mc->repGetPgoInstrumentationResults(ftnHnd, pSchema, pCountSchemaItems, pInstrumentationData, pPgoSource); + return jitInstance->mc->repGetPgoInstrumentationResults(ftnHnd, pSchema, pCountSchemaItems, pInstrumentationData, pPgoSource, pDynamicPgo); } // Associates a native call site, identified by its offset in the native code stream, with diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp index dd61fff1cf8870..d1926bd979434a 100644 --- a/src/coreclr/vm/jitinterface.cpp +++ b/src/coreclr/vm/jitinterface.cpp @@ -12111,7 +12111,8 @@ HRESULT CEEJitInfo::getPgoInstrumentationResults( PgoInstrumentationSchema **pSchema, // pointer to the schema table which describes the instrumentation results (pointer will not remain valid after jit completes) uint32_t * pCountSchemaItems, // pointer to the count schema items uint8_t ** pInstrumentationData, // pointer to the actual instrumentation data (pointer will not remain valid after jit completes) - PgoSource * pPgoSource // source of pgo data + PgoSource * pPgoSource, // source of pgo data + bool * pDynamicPgo // true if Dynamic PGO is enabled ) { CONTRACTL { @@ -12124,6 +12125,7 @@ HRESULT CEEJitInfo::getPgoInstrumentationResults( *pCountSchemaItems = 0; *pInstrumentationData = NULL; *pPgoSource = PgoSource::Unknown; + *pDynamicPgo = g_pConfig->TieredPGO(); JIT_TO_EE_TRANSITION(); @@ -14417,7 +14419,8 @@ HRESULT CEEInfo::getPgoInstrumentationResults( PgoInstrumentationSchema **pSchema, // pointer to the schema table which describes the instrumentation results (pointer will not remain valid after jit completes) uint32_t * pCountSchemaItems, // pointer to the count schema items uint8_t ** pInstrumentationData, // pointer to the actual instrumentation data (pointer will not remain valid after jit completes) - PgoSource * pPgoSource + PgoSource * pPgoSource, + bool * pDynamicPgo ) { LIMITED_METHOD_CONTRACT; diff --git a/src/coreclr/vm/jitinterface.h b/src/coreclr/vm/jitinterface.h index 754d04d5554279..a8266d6b79b275 100644 --- a/src/coreclr/vm/jitinterface.h +++ b/src/coreclr/vm/jitinterface.h @@ -643,7 +643,8 @@ class CEEJitInfo : public CEEInfo PgoInstrumentationSchema** pSchema, /* OUT */ uint32_t* pCountSchemaItems, /* OUT */ uint8_t**pInstrumentationData, /* OUT */ - PgoSource *pPgoSource /* OUT */ + PgoSource *pPgoSource, /* OUT */ + bool* pDynamicPgo /* OUT */ ) override final; void recordCallSite( From e1928e425ce45e8305fbd5edbef1a17e54c8d86f Mon Sep 17 00:00:00 2001 From: Katelyn Gadd Date: Fri, 26 Apr 2024 23:30:07 -0700 Subject: [PATCH 116/161] [wasm] Disable interp pgo recording by default since it adds startup overhead (#101566) * Disable interp pgo recording by default since it adds startup overhead * Make withRuntimeOptions not trample existing runtime options --- src/mono/browser/runtime/loader/run.ts | 11 ++++++++--- src/mono/mono/utils/options-def.h | 2 +- src/mono/sample/wasm/browser-bench/main.js | 5 ----- .../testassets/WasmBasicTestApp/App/wwwroot/main.js | 6 +++--- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/mono/browser/runtime/loader/run.ts b/src/mono/browser/runtime/loader/run.ts index 5c5010a2a5356f..0bd2dd60d80852 100644 --- a/src/mono/browser/runtime/loader/run.ts +++ b/src/mono/browser/runtime/loader/run.ts @@ -158,6 +158,10 @@ export class HostBuilder implements DotnetHostBuilder { interpreterPgo: value, interpreterPgoSaveDelay: autoSaveDelay }); + if (monoConfig.runtimeOptions) + monoConfig.runtimeOptions.push("--interp-pgo-recording"); + else + monoConfig.runtimeOptions = ["--interp-pgo-recording"]; return this; } catch (err) { mono_exit(1, err); @@ -268,9 +272,10 @@ export class HostBuilder implements DotnetHostBuilder { withRuntimeOptions (runtimeOptions: string[]): DotnetHostBuilder { try { mono_assert(runtimeOptions && Array.isArray(runtimeOptions), "must be array of strings"); - deep_merge_config(monoConfig, { - runtimeOptions - }); + if (monoConfig.runtimeOptions) + monoConfig.runtimeOptions.push(...runtimeOptions); + else + monoConfig.runtimeOptions = runtimeOptions; return this; } catch (err) { mono_exit(1, err); diff --git a/src/mono/mono/utils/options-def.h b/src/mono/mono/utils/options-def.h index 8cdbc942e1b851..3af994cb325b2b 100644 --- a/src/mono/mono/utils/options-def.h +++ b/src/mono/mono/utils/options-def.h @@ -61,7 +61,7 @@ DEFINE_BOOL(wasm_exceptions, "wasm-exceptions", FALSE, "Enable codegen for WASM DEFINE_BOOL(aot_lazy_assembly_load, "aot-lazy-assembly-load", FALSE, "Load assemblies referenced by AOT images lazily") #if HOST_BROWSER -DEFINE_BOOL(interp_pgo_recording, "interp-pgo-recording", TRUE, "Record interpreter tiering information for automatic PGO") +DEFINE_BOOL(interp_pgo_recording, "interp-pgo-recording", FALSE, "Record interpreter tiering information for automatic PGO") #else DEFINE_BOOL(interp_pgo_recording, "interp-pgo-recording", FALSE, "Record interpreter tiering information for automatic PGO") DEFINE_BOOL(wasm_gc_safepoints, "wasm-gc-safepoints", FALSE, "Use GC safepoints on WASM") diff --git a/src/mono/sample/wasm/browser-bench/main.js b/src/mono/sample/wasm/browser-bench/main.js index 0f1a6530491250..71e4a677ddcc7e 100644 --- a/src/mono/sample/wasm/browser-bench/main.js +++ b/src/mono/sample/wasm/browser-bench/main.js @@ -225,11 +225,6 @@ try { // console to see statistics on how much code it generated and whether any new opcodes // are causing traces to fail to compile .withRuntimeOptions(["--jiterpreter-stats-enabled"]) - // We enable interpreter PGO so that you can exercise it in local tests, i.e. - // run browser-bench one, then refresh the tab to measure the performance improvement - // on the second run of browser-bench. The overall speed of the benchmarks won't - // improve much, but the time spent generating code during the run will go down - .withInterpreterPgo(true, 30) .withElementOnExit() .withExitCodeLogging() .create(); diff --git a/src/mono/wasm/testassets/WasmBasicTestApp/App/wwwroot/main.js b/src/mono/wasm/testassets/WasmBasicTestApp/App/wwwroot/main.js index 7df0706d568193..3eb9e50aedeb32 100644 --- a/src/mono/wasm/testassets/WasmBasicTestApp/App/wwwroot/main.js +++ b/src/mono/wasm/testassets/WasmBasicTestApp/App/wwwroot/main.js @@ -37,7 +37,7 @@ switch (testCase) { let alreadyFailed = []; dotnet.withDiagnosticTracing(true).withResourceLoader((type, name, defaultUri, integrity, behavior) => { if (type === "dotnetjs") { - // loadBootResource could return string with unqualified name of resource. + // loadBootResource could return string with unqualified name of resource. // It assumes that we resolve it with document.baseURI // we test it here return `_framework/${name}`; @@ -131,8 +131,8 @@ try { } }); const iterationCount = params.get("iterationCount") ?? 70; - for (let i = 0; i < iterationCount; i++) { - exports.InterpPgoTest.Greeting(); + for (let i = 0; i < iterationCount; i++) { + exports.InterpPgoTest.Greeting(); }; await INTERNAL.interp_pgo_save_data(); exit(0); From 81c1d87dd777eddc4eff38d433077e2f20cdba79 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Sowi=C5=84ski?= Date: Sat, 27 Apr 2024 11:46:16 +0200 Subject: [PATCH 117/161] [RISC-V] Use common CodeGen::genHomeRegisterParams (#101288) * Code review from #101114 * Use common genHomeRegisterParams on RISC-V * Make passSlot integer-only because we know hardware floating-point calling convention passes in registers only * Make a RISC-V specific routine for homing stack parts of split parameters. * Move genHomeStackPartOfSplitParameter out of genHomeSwiftStructParameters, share stack segment homing with Swift code --- src/coreclr/jit/abi.cpp | 14 +- src/coreclr/jit/abi.h | 4 +- src/coreclr/jit/codegen.h | 2 + src/coreclr/jit/codegencommon.cpp | 154 ++++++---- src/coreclr/jit/codegenriscv64.cpp | 443 ----------------------------- src/coreclr/jit/targetriscv64.cpp | 62 ++-- 6 files changed, 141 insertions(+), 538 deletions(-) diff --git a/src/coreclr/jit/abi.cpp b/src/coreclr/jit/abi.cpp index c6dbd8aa9202fd..7a594f77f39121 100644 --- a/src/coreclr/jit/abi.cpp +++ b/src/coreclr/jit/abi.cpp @@ -258,14 +258,16 @@ bool ABIPassingInformation::HasExactlyOneStackSegment() const // bool ABIPassingInformation::IsSplitAcrossRegistersAndStack() const { - bool anyReg = false; - bool anyStack = false; - for (unsigned i = 0; i < NumSegments; i++) + if (NumSegments < 2) + return false; + + bool isFirstInReg = Segments[0].IsPassedInRegister(); + for (unsigned i = 1; i < NumSegments; i++) { - anyReg |= Segments[i].IsPassedInRegister(); - anyStack |= Segments[i].IsPassedOnStack(); + if (isFirstInReg != Segments[i].IsPassedInRegister()) + return true; } - return anyReg && anyStack; + return false; } //----------------------------------------------------------------------------- diff --git a/src/coreclr/jit/abi.h b/src/coreclr/jit/abi.h index ac0ad5090dcf2b..37268ce3effd9f 100644 --- a/src/coreclr/jit/abi.h +++ b/src/coreclr/jit/abi.h @@ -51,8 +51,8 @@ struct ABIPassingInformation // - On loongarch64/riscv64, structs can be passed in two registers or // can be split out over register and stack, giving // multiple register segments and a struct segment. - unsigned NumSegments = 0; - ABIPassingSegment* Segments = nullptr; + unsigned NumSegments; + ABIPassingSegment* Segments; ABIPassingInformation(unsigned numSegments = 0, ABIPassingSegment* segments = nullptr) : NumSegments(numSegments) diff --git a/src/coreclr/jit/codegen.h b/src/coreclr/jit/codegen.h index 441db5f6b50d47..2a2ede6bae9ac0 100644 --- a/src/coreclr/jit/codegen.h +++ b/src/coreclr/jit/codegen.h @@ -284,7 +284,9 @@ class CodeGen final : public CodeGenInterface void genEnregisterOSRArgsAndLocals(); #endif + void genHomeStackSegment(unsigned lclNum, const ABIPassingSegment& seg, regNumber initReg, bool* pInitRegZeroed); void genHomeSwiftStructParameters(bool handleStack); + void genHomeStackPartOfSplitParameter(regNumber initReg, bool* initRegStillZeroed); void genCheckUseBlockInit(); #if defined(UNIX_AMD64_ABI) && defined(FEATURE_SIMD) diff --git a/src/coreclr/jit/codegencommon.cpp b/src/coreclr/jit/codegencommon.cpp index 9f3120d274d57d..c3608402d27ec2 100644 --- a/src/coreclr/jit/codegencommon.cpp +++ b/src/coreclr/jit/codegencommon.cpp @@ -2802,7 +2802,6 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX */ -#if !defined(TARGET_RISCV64) struct RegNode; struct RegNodeEdge @@ -3346,8 +3345,6 @@ void CodeGen::genHomeRegisterParams(regNumber initReg, bool* initRegStillZeroed) } } -#endif - // ----------------------------------------------------------------------------- // genGetParameterHomingTempRegisterCandidates: Get the registers that are // usable during register homing. @@ -4122,15 +4119,69 @@ void CodeGen::genEnregisterOSRArgsAndLocals() } } +#if defined(SWIFT_SUPPORT) || defined(TARGET_RISCV64) +//----------------------------------------------------------------------------- +// genHomeSwiftStructParameters: Move the incoming segment to the local stack frame. +// +// Arguments: +// lclNum - Number of local variable to home +// seg - Stack segment of the local variable to home +// initReg - Scratch register to use if needed +// initRegStillZeroed - Set to false if the scratch register was needed +// +void CodeGen::genHomeStackSegment(unsigned lclNum, + const ABIPassingSegment& seg, + regNumber initReg, + bool* initRegStillZeroed) +{ + var_types loadType = TYP_UNDEF; + switch (seg.Size) + { + case 1: + loadType = TYP_UBYTE; + break; + case 2: + loadType = TYP_USHORT; + break; + case 3: + case 4: + loadType = TYP_INT; + break; + case 5: + case 6: + case 7: + case 8: + loadType = TYP_LONG; + break; + default: + assert(!"Unexpected segment size for struct parameter not passed implicitly by ref"); + return; + } + emitAttr size = emitTypeSize(loadType); + + int loadOffset = + -(isFramePointerUsed() ? genCallerSPtoFPdelta() : genCallerSPtoInitialSPdelta()) + (int)seg.GetStackOffset(); +#ifdef TARGET_XARCH + GetEmitter()->emitIns_R_AR(ins_Load(loadType), size, initReg, genFramePointerReg(), loadOffset); +#else + genInstrWithConstant(ins_Load(loadType), size, initReg, genFramePointerReg(), loadOffset, initReg); +#endif + GetEmitter()->emitIns_S_R(ins_Store(loadType), size, initReg, lclNum, seg.Offset); + + if (initRegStillZeroed) + *initRegStillZeroed = false; +} +#endif // defined(SWIFT_SUPPORT) || defined(TARGET_RISCV64) + #ifdef SWIFT_SUPPORT //----------------------------------------------------------------------------- // genHomeSwiftStructParameters: -// Reassemble Swift struct parameters if necessary. +// Reassemble Swift struct parameters if necessary. // -// Parameters: -// handleStack - If true, reassemble the segments that were passed on the stack. -// If false, reassemble the segments that were passed in registers. +// Arguments: +// handleStack - If true, reassemble the segments that were passed on the stack. +// If false, reassemble the segments that were passed in registers. // void CodeGen::genHomeSwiftStructParameters(bool handleStack) { @@ -4176,59 +4227,54 @@ void CodeGen::genHomeSwiftStructParameters(bool handleStack) } else { - var_types loadType = TYP_UNDEF; - switch (seg.Size) - { - case 1: - loadType = TYP_UBYTE; - break; - case 2: - loadType = TYP_USHORT; - break; - case 3: - case 4: - loadType = TYP_INT; - break; - case 5: - case 6: - case 7: - case 8: - loadType = TYP_LONG; - break; - default: - assert(!"Unexpected segment size for struct parameter not passed implicitly by ref"); - continue; - } + // We can use REG_SCRATCH as a temporary register here as we ensured that during LSRA build. + genHomeStackSegment(lclNum, seg, REG_SCRATCH, nullptr); + } + } + } +} +#endif - int offset; - if (isFramePointerUsed()) - { - offset = -genCallerSPtoFPdelta(); - } - else - { - offset = -genCallerSPtoInitialSPdelta(); - } +//----------------------------------------------------------------------------- +// genHomeStackPartOfSplitParameter: Home the tail (stack) portion of a split parameter next to where the head +// (register) portion is homed. +// +// Arguments: +// initReg - scratch register to use if needed +// initRegStillZeroed - set to false if scratch register was needed +// +// Notes: +// No-op on platforms where argument registers are already homed to form a contiguous space with incoming stack. +// +void CodeGen::genHomeStackPartOfSplitParameter(regNumber initReg, bool* initRegStillZeroed) +{ +#ifdef TARGET_RISCV64 + unsigned lclNum = 0; + for (; lclNum < compiler->info.compArgsCount; lclNum++) + { + LclVarDsc* var = compiler->lvaGetDesc(lclNum); + if (!var->lvIsSplit || !var->lvOnFrame) + continue; - offset += (int)seg.GetStackOffset(); + JITDUMP("Homing stack part of split parameter V%02u\n", lclNum); - // Move the incoming segment to the local stack frame. We can - // use REG_SCRATCH as a temporary register here as we ensured - // that during LSRA build. -#ifdef TARGET_XARCH - GetEmitter()->emitIns_R_AR(ins_Load(loadType), emitTypeSize(loadType), REG_SCRATCH, - genFramePointerReg(), offset); -#else - genInstrWithConstant(ins_Load(loadType), emitTypeSize(loadType), REG_SCRATCH, genFramePointerReg(), - offset, REG_SCRATCH); -#endif + assert(varTypeIsStruct(var)); + assert(!compiler->lvaIsImplicitByRefLocal(lclNum)); + const ABIPassingInformation& abiInfo = compiler->lvaGetParameterABIInfo(lclNum); + assert(abiInfo.NumSegments == 2); + assert(abiInfo.Segments[0].GetRegister() == REG_ARG_LAST); + const ABIPassingSegment& seg = abiInfo.Segments[1]; - GetEmitter()->emitIns_S_R(ins_Store(loadType), emitTypeSize(loadType), REG_SCRATCH, lclNum, seg.Offset); - } + genHomeStackSegment(lclNum, seg, initReg, initRegStillZeroed); + + for (lclNum += 1; lclNum < compiler->info.compArgsCount; lclNum++) + { + assert(!compiler->lvaGetDesc(lclNum)->lvIsSplit); // There should be only one split parameter } + break; } -} #endif +} /*----------------------------------------------------------------------------- * @@ -5547,6 +5593,8 @@ void CodeGen::genFnProlog() { compiler->lvaUpdateArgsWithInitialReg(); + genHomeStackPartOfSplitParameter(initReg, &initRegZeroed); + if ((intRegState.rsCalleeRegArgMaskLiveIn | floatRegState.rsCalleeRegArgMaskLiveIn) != RBM_NONE) { genHomeRegisterParams(initReg, &initRegZeroed); diff --git a/src/coreclr/jit/codegenriscv64.cpp b/src/coreclr/jit/codegenriscv64.cpp index b7c119be94987c..0fa8bdb5874f40 100644 --- a/src/coreclr/jit/codegenriscv64.cpp +++ b/src/coreclr/jit/codegenriscv64.cpp @@ -7962,449 +7962,6 @@ void CodeGen::genPopCalleeSavedRegisters(bool jmpEpilog) } } -void CodeGen::genHomeRegisterParams(regNumber initReg, bool* initRegStillZeroed) -{ - *initRegStillZeroed = false; - assert(!(intRegState.rsCalleeRegArgMaskLiveIn & floatRegState.rsCalleeRegArgMaskLiveIn)); - - regMaskTP regArgMaskLive = intRegState.rsCalleeRegArgMaskLiveIn | floatRegState.rsCalleeRegArgMaskLiveIn; - -#ifdef DEBUG - if (verbose) - { - printf("*************** In genFnPrologCalleeRegArgs() RISCV64:0x%llx.\n", regArgMaskLive); - } -#endif - - // We should be generating the prolog block when we are called - assert(compiler->compGeneratingProlog); - - // We expect to have some registers of the type we are doing, that are LiveIn, otherwise we don't need to be called. - noway_assert(regArgMaskLive != 0); - - unsigned varNum; - unsigned regArgNum = 0; - // Process any rearrangements including circular dependencies. - regNumber regArg[MAX_REG_ARG + MAX_FLOAT_REG_ARG]; - regNumber regArgInit[MAX_REG_ARG + MAX_FLOAT_REG_ARG]; - emitAttr regArgAttr[MAX_REG_ARG + MAX_FLOAT_REG_ARG]; - - for (int i = 0; i < MAX_REG_ARG + MAX_FLOAT_REG_ARG; i++) - { - regArg[i] = REG_NA; - -#ifdef DEBUG - regArgInit[i] = REG_NA; - regArgAttr[i] = EA_UNKNOWN; -#endif - } - - for (varNum = 0; varNum < compiler->lvaCount; ++varNum) - { - LclVarDsc* varDsc = compiler->lvaTable + varNum; - - // Is this variable a register arg? - if (!varDsc->lvIsParam) - { - continue; - } - - if (!varDsc->lvIsRegArg) - { - continue; - } - - if (varDsc->lvIsInReg()) - { - assert(genIsValidIntReg(varDsc->GetArgReg()) || genIsValidFloatReg(varDsc->GetArgReg())); - assert(!(genIsValidIntReg(varDsc->GetOtherArgReg()) || genIsValidFloatReg(varDsc->GetOtherArgReg()))); - if (varDsc->GetArgInitReg() != varDsc->GetArgReg()) - { - if (genIsValidIntReg(varDsc->GetArgInitReg())) - { - if (varDsc->GetArgInitReg() > REG_ARG_LAST) - { - bool isSkip; - instruction ins; - emitAttr size; - if (genIsValidIntReg(varDsc->GetArgReg())) - { - ins = INS_mov; - if (varDsc->TypeGet() == TYP_INT) - { - size = EA_4BYTE; - isSkip = false; - } - else - { - size = EA_PTRSIZE; - isSkip = true; - } - } - else - { - ins = INS_fmv_x_d; - size = EA_PTRSIZE; - isSkip = true; - } - GetEmitter()->emitIns_Mov(ins, size, varDsc->GetArgInitReg(), varDsc->GetArgReg(), isSkip); - regArgMaskLive &= ~genRegMask(varDsc->GetArgReg()); - } - else - { - if (genIsValidIntReg(varDsc->GetArgReg())) - { - assert(isValidIntArgReg(varDsc->GetArgReg(), compiler->info.compCallConv)); - regArg[varDsc->GetArgReg() - REG_ARG_FIRST] = varDsc->GetArgReg(); - regArgInit[varDsc->GetArgReg() - REG_ARG_FIRST] = varDsc->GetArgInitReg(); - regArgAttr[varDsc->GetArgReg() - REG_ARG_FIRST] = - varDsc->TypeGet() == TYP_INT ? EA_4BYTE : EA_PTRSIZE; - } - else - { - assert(isValidFloatArgReg(varDsc->GetArgReg())); - regArg[varDsc->GetArgReg() - REG_ARG_FP_FIRST + MAX_REG_ARG] = varDsc->GetArgReg(); - regArgInit[varDsc->GetArgReg() - REG_ARG_FP_FIRST + MAX_REG_ARG] = varDsc->GetArgInitReg(); - regArgAttr[varDsc->GetArgReg() - REG_ARG_FP_FIRST + MAX_REG_ARG] = - varDsc->TypeGet() == TYP_FLOAT ? EA_4BYTE : EA_PTRSIZE; - } - regArgNum++; - } - } - else - { - assert(genIsValidFloatReg(varDsc->GetArgInitReg())); - if (genIsValidIntReg(varDsc->GetArgReg())) - { - emitAttr size = (varDsc->TypeGet() == TYP_FLOAT) ? EA_4BYTE : EA_PTRSIZE; - GetEmitter()->emitIns_Mov(size, varDsc->GetArgInitReg(), varDsc->GetArgReg(), false); - regArgMaskLive &= ~genRegMask(varDsc->GetArgReg()); - } - else if (varDsc->GetArgInitReg() > REG_ARG_FP_LAST) - { - GetEmitter()->emitIns_Mov(INS_fsgnj_d, EA_PTRSIZE, varDsc->GetArgInitReg(), varDsc->GetArgReg(), - true); - regArgMaskLive &= ~genRegMask(varDsc->GetArgReg()); - } - else - { - assert(isValidFloatArgReg(varDsc->GetArgReg())); - regArg[varDsc->GetArgReg() - REG_ARG_FP_FIRST + MAX_REG_ARG] = varDsc->GetArgReg(); - regArgInit[varDsc->GetArgReg() - REG_ARG_FP_FIRST + MAX_REG_ARG] = varDsc->GetArgInitReg(); - regArgAttr[varDsc->GetArgReg() - REG_ARG_FP_FIRST + MAX_REG_ARG] = - varDsc->TypeGet() == TYP_FLOAT ? EA_4BYTE : EA_PTRSIZE; - regArgNum++; - } - } - } - else - { - // TODO-RISCV64: should delete this by optimization "struct {long a; int32_t b;};" - // liking AMD64_ABI within morph. - if (genIsValidIntReg(varDsc->GetArgReg()) && (varDsc->TypeGet() == TYP_INT)) - { - GetEmitter()->emitIns_Mov(INS_mov, EA_4BYTE, varDsc->GetArgInitReg(), varDsc->GetArgReg(), false); - } - regArgMaskLive &= ~genRegMask(varDsc->GetArgReg()); - } -#ifdef USING_SCOPE_INFO - psiMoveToReg(varNum); -#endif // USING_SCOPE_INFO - if (!varDsc->lvLiveInOutOfHndlr) - { - continue; - } - } - - // When we have a promoted struct we have two possible LclVars that can represent the incoming argument - // in the regArgTab[], either the original TYP_STRUCT argument or the introduced lvStructField. - // We will use the lvStructField if we have a TYPE_INDEPENDENT promoted struct field otherwise - // use the original TYP_STRUCT argument. - // - if (varDsc->lvPromoted || varDsc->lvIsStructField) - { - LclVarDsc* parentVarDsc = varDsc; - if (varDsc->lvIsStructField) - { - assert(!varDsc->lvPromoted); - parentVarDsc = &compiler->lvaTable[varDsc->lvParentLcl]; - } - - Compiler::lvaPromotionType promotionType = compiler->lvaGetPromotionType(parentVarDsc); - - if (promotionType == Compiler::PROMOTION_TYPE_INDEPENDENT) - { - // For register arguments that are independent promoted structs we put the promoted field varNum - // in the regArgTab[] - if (varDsc->lvPromoted) - { - continue; - } - } - else - { - // For register arguments that are not independent promoted structs we put the parent struct varNum - // in the regArgTab[] - if (varDsc->lvIsStructField) - { - continue; - } - } - } - - var_types storeType = TYP_UNDEF; - int slotSize = TARGET_POINTER_SIZE; - - if (varTypeIsStruct(varDsc)) - { - if (emitter::isFloatReg(varDsc->GetArgReg())) - { - storeType = varDsc->lvIs4Field1 ? TYP_FLOAT : TYP_DOUBLE; - } - else - { - assert(emitter::isGeneralRegister(varDsc->GetArgReg())); - if (varDsc->lvIs4Field1) - { - storeType = TYP_INT; - } - else - { - storeType = varDsc->GetLayout()->GetGCPtrType(0); - } - } - slotSize = (int)EA_SIZE(emitActualTypeSize(storeType)); - -#if FEATURE_MULTIREG_ARGS - // Must be <= MAX_PASS_MULTIREG_BYTES or else it wouldn't be passed in registers - noway_assert(varDsc->lvSize() <= MAX_PASS_MULTIREG_BYTES); -#endif - } - else // Not a struct type - { - storeType = compiler->mangleVarArgsType(genActualType(varDsc->TypeGet())); - if (emitter::isFloatReg(varDsc->GetArgReg()) != varTypeIsFloating(storeType)) - { - assert(varTypeIsFloating(storeType)); - storeType = storeType == TYP_DOUBLE ? TYP_I_IMPL : TYP_INT; - } - } - emitAttr size = emitActualTypeSize(storeType); - - regNumber srcRegNum = varDsc->GetArgReg(); - - // Stack argument - if the ref count is 0 don't care about it - if (!varDsc->lvOnFrame) - { - noway_assert(varDsc->lvRefCnt() == 0); - regArgMaskLive &= ~genRegMask(varDsc->GetArgReg()); - if (varDsc->GetOtherArgReg() < REG_STK) - { - regArgMaskLive &= ~genRegMask(varDsc->GetOtherArgReg()); - } - } - else - { - assert(srcRegNum != varDsc->GetOtherArgReg()); - - regNumber tmpReg = REG_NA; - - bool FPbased; - int baseOffset = compiler->lvaFrameAddress(varNum, &FPbased); - - // First store the `varDsc->GetArgReg()` on stack. - if (emitter::isValidSimm12(baseOffset)) - { - GetEmitter()->emitIns_S_R(ins_Store(storeType), size, srcRegNum, varNum, 0); - } - else - { - assert(tmpReg == REG_NA); - - tmpReg = REG_RA; - // Prepare tmpReg to possible future use - GetEmitter()->emitLoadImmediate(EA_PTRSIZE, tmpReg, baseOffset); - GetEmitter()->emitIns_R_R_R(INS_add, EA_PTRSIZE, tmpReg, tmpReg, FPbased ? REG_FPBASE : REG_SPBASE); - GetEmitter()->emitIns_S_R_R(ins_Store(storeType), size, srcRegNum, tmpReg, varNum, 0); - } - - regArgMaskLive &= ~genRegMask(srcRegNum); - - // Then check if varDsc is a struct arg - if (varTypeIsStruct(varDsc)) - { - if (emitter::isFloatReg(varDsc->GetOtherArgReg())) - { - srcRegNum = varDsc->GetOtherArgReg(); - storeType = varDsc->lvIs4Field2 ? TYP_FLOAT : TYP_DOUBLE; - size = EA_SIZE(emitActualTypeSize(storeType)); - - slotSize = slotSize < (int)size ? (int)size : slotSize; - } - else if (emitter::isGeneralRegister(varDsc->GetOtherArgReg())) - { - if (varDsc->lvIs4Field2) - { - storeType = TYP_INT; - } - else - { - storeType = varDsc->GetLayout()->GetGCPtrType(1); - } - - srcRegNum = varDsc->GetOtherArgReg(); - size = emitActualTypeSize(storeType); - - slotSize = slotSize < (int)EA_SIZE(size) ? (int)EA_SIZE(size) : slotSize; - } - baseOffset += slotSize; - - // if the struct passed by two register, then store the second register `varDsc->GetOtherArgReg()`. - if (srcRegNum == varDsc->GetOtherArgReg()) - { - GetEmitter()->emitIns_S_R_R(ins_Store(storeType), size, srcRegNum, tmpReg, varNum, slotSize); - regArgMaskLive &= ~genRegMask(srcRegNum); // maybe do this later is better! - } - else if (varDsc->lvIsSplit) - { - // the struct is a split struct. - assert(varDsc->GetArgReg() == REG_ARG_LAST && varDsc->GetOtherArgReg() == REG_STK); - - // For the RISCV64's ABI, the split struct arg will be passed via `A7` and a stack slot on caller. - // But if the `A7` is stored on stack on the callee side, the whole split struct should be - // stored continuous on the stack on the callee side. - // So, after we save `A7` on the stack in prolog, it has to copy the stack slot of the split struct - // which was passed by the caller. Here we load the stack slot to `REG_SCRATCH`, and save it - // on the stack following the `A7` in prolog. - if (emitter::isValidSimm12(genTotalFrameSize())) - { - GetEmitter()->emitIns_R_R_I(INS_ld, size, REG_SCRATCH, REG_SPBASE, genTotalFrameSize()); - } - else - { - assert(!EA_IS_RELOC(size)); - GetEmitter()->emitLoadImmediate(size, REG_SCRATCH, genTotalFrameSize()); - GetEmitter()->emitIns_R_R_R(INS_add, size, REG_SCRATCH, REG_SCRATCH, REG_SPBASE); - GetEmitter()->emitIns_R_R_I(INS_ld, size, REG_SCRATCH, REG_SCRATCH, 0); - } - - GetEmitter()->emitIns_S_R_R(ins_Store(storeType), size, REG_SCRATCH, tmpReg, varNum, slotSize); - } - } - -#ifdef USING_SCOPE_INFO - { - psiMoveToStack(varNum); - } -#endif // USING_SCOPE_INFO - } - } - - if (regArgNum > 0) - { - for (int i = MAX_REG_ARG + MAX_FLOAT_REG_ARG - 1; i >= 0; i--) - { - if (regArg[i] != REG_NA && !isValidIntArgReg(regArgInit[i], compiler->info.compCallConv) && - !isValidFloatArgReg(regArgInit[i])) - { - assert(regArg[i] != regArgInit[i]); - assert(isValidIntArgReg(regArg[i], compiler->info.compCallConv) || isValidFloatArgReg(regArg[i])); - - GetEmitter()->emitIns_Mov(regArgAttr[i], regArgInit[i], regArg[i], false); - - regArgMaskLive &= ~genRegMask(regArg[i]); - regArg[i] = REG_NA; - regArgNum -= 1; - } - } - } - - if (regArgNum > 0) - { - for (int i = MAX_REG_ARG + MAX_FLOAT_REG_ARG - 1; i >= 0; i--) - { - if (regArg[i] != REG_NA) - { - assert(regArg[i] != regArgInit[i]); - - // regArg indexes list - unsigned indexList[MAX_REG_ARG + MAX_FLOAT_REG_ARG]; - int count = 0; // Number of nodes in list - bool loop = false; // List has a loop - - for (unsigned cur = i; regArg[cur] != REG_NA; count++) - { - if (cur == i && count > 0) - { - loop = true; - break; - } - - indexList[count] = cur; - - for (int count2 = 0; count2 < count; count2++) - { - // The list could not have backlinks except last to first case which handled above. - assert(cur != indexList[count2] && "Attempt to move several values on same register."); - } - assert(cur < MAX_REG_ARG + MAX_FLOAT_REG_ARG); - assert(isValidIntArgReg(regArg[cur], compiler->info.compCallConv) || - isValidFloatArgReg(regArg[cur])); - - if (isValidIntArgReg(regArgInit[cur], compiler->info.compCallConv)) - { - cur = regArgInit[cur] - REG_ARG_FIRST; - } - else if (isValidFloatArgReg(regArgInit[cur])) - { - cur = regArgInit[cur] - REG_ARG_FP_FIRST + MAX_REG_ARG; - } - else - { - assert(!"Argument register is neither valid float nor valid int argument register"); - } - } - - if (loop) - { - unsigned tmpArg = indexList[count - 1]; - - GetEmitter()->emitIns_Mov(regArgAttr[tmpArg], rsGetRsvdReg(), regArg[tmpArg], false); - count--; // Decrease count to not access last node which regArgInit points to start node i - assert(count > 0); - } - - for (int cur = count - 1; cur >= 0; cur--) - { - unsigned tmpArg = indexList[cur]; - - GetEmitter()->emitIns_Mov(regArgAttr[tmpArg], regArgInit[tmpArg], regArg[tmpArg], false); - - regArgMaskLive &= ~genRegMask(regArg[tmpArg]); - regArg[tmpArg] = REG_NA; - regArgNum--; - assert(regArgNum >= 0); - }; - - if (loop) - { - unsigned tmpArg = indexList[count]; // count was decreased for loop case - - GetEmitter()->emitIns_Mov(regArgAttr[i], regArg[tmpArg], rsGetRsvdReg(), false); - - regArgMaskLive &= ~genRegMask(regArg[tmpArg]); - regArg[tmpArg] = REG_NA; - regArgNum--; - } - assert(regArgNum >= 0); - } - } - } - - assert(regArgNum == 0); - assert(!regArgMaskLive); -} - #ifdef PROFILING_SUPPORTED //----------------------------------------------------------------------------------- // genProfilingEnterCallback: Generate the profiling function enter callback. diff --git a/src/coreclr/jit/targetriscv64.cpp b/src/coreclr/jit/targetriscv64.cpp index 29f71dc76d8fa2..581087b5cc63f8 100644 --- a/src/coreclr/jit/targetriscv64.cpp +++ b/src/coreclr/jit/targetriscv64.cpp @@ -36,6 +36,7 @@ RiscV64Classifier::RiscV64Classifier(const ClassifierInfo& info) , m_intRegs(intArgRegs, ArrLen(intArgRegs)) , m_floatRegs(fltArgRegs, ArrLen(fltArgRegs)) { + assert(!m_info.IsVarArgs); // TODO: varargs currently not supported on RISC-V } //----------------------------------------------------------------------------- @@ -57,8 +58,6 @@ ABIPassingInformation RiscV64Classifier::Classify(Compiler* comp, ClassLayout* structLayout, WellKnownArg /*wellKnownParam*/) { - assert(!m_info.IsVarArgs); // TODO: varargs currently not supported on RISC-V - StructFloatFieldInfoFlags flags = STRUCT_NO_FLOAT_FIELD; unsigned intFields = 0, floatFields = 0; unsigned passedSize; @@ -93,36 +92,13 @@ ABIPassingInformation RiscV64Classifier::Classify(Compiler* comp, } else { - assert(genTypeSize(type) <= TARGET_POINTER_SIZE); - - if (varTypeIsFloating(type)) - floatFields = 1; - passedSize = genTypeSize(type); + assert(passedSize <= TARGET_POINTER_SIZE); + floatFields = varTypeIsFloating(type) ? 1 : 0; } assert((floatFields > 0) || (intFields == 0)); - auto PassSlot = [this](bool inFloatReg, unsigned offset, unsigned size) -> ABIPassingSegment { - assert(size > 0); - assert(size <= TARGET_POINTER_SIZE); - if (inFloatReg) - { - return ABIPassingSegment::InRegister(m_floatRegs.Dequeue(), offset, size); - } - else if (m_intRegs.Count() > 0) - { - return ABIPassingSegment::InRegister(m_intRegs.Dequeue(), offset, size); - } - else - { - assert((m_stackArgSize % TARGET_POINTER_SIZE) == 0); - ABIPassingSegment seg = ABIPassingSegment::OnStack(m_stackArgSize, offset, size); - m_stackArgSize += TARGET_POINTER_SIZE; - return seg; - } - }; - if ((floatFields > 0) && (m_floatRegs.Count() >= floatFields) && (m_intRegs.Count() >= intFields)) { // Hardware floating-point calling convention @@ -151,27 +127,45 @@ ABIPassingInformation RiscV64Classifier::Classify(Compiler* comp, bool isSecondFloat = (flags & (STRUCT_FLOAT_FIELD_ONLY_TWO | STRUCT_FLOAT_FIELD_SECOND)) != 0; assert(isFirstFloat || isSecondFloat); - return {2, new (comp, CMK_ABI) ABIPassingSegment[]{PassSlot(isFirstFloat, 0, firstSize), - PassSlot(isSecondFloat, offset, secondSize)}}; + regNumber firstReg = (isFirstFloat ? m_floatRegs : m_intRegs).Dequeue(); + regNumber secondReg = (isSecondFloat ? m_floatRegs : m_intRegs).Dequeue(); + + return {2, new (comp, CMK_ABI) + ABIPassingSegment[]{ABIPassingSegment::InRegister(firstReg, 0, firstSize), + ABIPassingSegment::InRegister(secondReg, offset, secondSize)}}; } } else { // Integer calling convention + auto passSlot = [this](unsigned offset, unsigned size) -> ABIPassingSegment { + assert(size > 0); + assert(size <= TARGET_POINTER_SIZE); + if (m_intRegs.Count() > 0) + { + return ABIPassingSegment::InRegister(m_intRegs.Dequeue(), offset, size); + } + else + { + assert((m_stackArgSize % TARGET_POINTER_SIZE) == 0); + ABIPassingSegment seg = ABIPassingSegment::OnStack(m_stackArgSize, offset, size); + m_stackArgSize += TARGET_POINTER_SIZE; + return seg; + } + }; + if (passedSize <= TARGET_POINTER_SIZE) { - return ABIPassingInformation::FromSegment(comp, PassSlot(false, 0, passedSize)); + return ABIPassingInformation::FromSegment(comp, passSlot(0, passedSize)); } else { assert(varTypeIsStruct(type)); return {2, new (comp, CMK_ABI) - ABIPassingSegment[]{PassSlot(false, 0, TARGET_POINTER_SIZE), - PassSlot(false, TARGET_POINTER_SIZE, passedSize - TARGET_POINTER_SIZE)}}; + ABIPassingSegment[]{passSlot(0, TARGET_POINTER_SIZE), + passSlot(TARGET_POINTER_SIZE, passedSize - TARGET_POINTER_SIZE)}}; } } - - unreached(); } #endif // TARGET_RISCV64 From 95306c760c08d922a1d4a7a0979c16fb40c4ac3f Mon Sep 17 00:00:00 2001 From: Aaron Robinson Date: Sat, 27 Apr 2024 11:03:46 -0700 Subject: [PATCH 118/161] Remove dead code in PGO scenarios. (#101648) --- src/coreclr/vm/jitinterface.cpp | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp index d1926bd979434a..394b87a1873965 100644 --- a/src/coreclr/vm/jitinterface.cpp +++ b/src/coreclr/vm/jitinterface.cpp @@ -12075,23 +12075,6 @@ HRESULT CEEJitInfo::allocPgoInstrumentationBySchema( JIT_TO_EE_TRANSITION(); - // We need to know the code size. Typically we can get the code size - // from m_ILHeader. For dynamic methods, m_ILHeader will be NULL, so - // for that case we need to use DynamicResolver to get the code size. - - unsigned codeSize = 0; - if (m_pMethodBeingCompiled->IsDynamicMethod()) - { - unsigned stackSize, ehSize; - CorInfoOptions options; - DynamicResolver * pResolver = m_pMethodBeingCompiled->AsDynamicMethodDesc()->GetResolver(); - pResolver->GetCodeInfo(&codeSize, &stackSize, &options, &ehSize); - } - else - { - codeSize = m_ILHeader->GetCodeSize(); - } - #ifdef FEATURE_PGO hr = PgoManager::allocPgoInstrumentationBySchema(m_pMethodBeingCompiled, pSchema, countSchemaItems, pInstrumentationData); #else From b9464f1a937232529baacac677bdb4617baf5fc7 Mon Sep 17 00:00:00 2001 From: t-mustafin <66252296+t-mustafin@users.noreply.github.com> Date: Sat, 27 Apr 2024 21:37:27 +0300 Subject: [PATCH 119/161] [RISC-V] Fix FEATURE_MULTIREG_RETURN definition (#101642) --- src/coreclr/clrdefinitions.cmake | 1 + 1 file changed, 1 insertion(+) diff --git a/src/coreclr/clrdefinitions.cmake b/src/coreclr/clrdefinitions.cmake index 4201c06692eeb5..1970b6c33c7544 100644 --- a/src/coreclr/clrdefinitions.cmake +++ b/src/coreclr/clrdefinitions.cmake @@ -16,6 +16,7 @@ elseif (CLR_CMAKE_TARGET_ARCH_ARM) add_definitions(-DFEATURE_EMULATE_SINGLESTEP) elseif (CLR_CMAKE_TARGET_ARCH_RISCV64) add_definitions(-DFEATURE_EMULATE_SINGLESTEP) + add_compile_definitions($<$>>:FEATURE_MULTIREG_RETURN>) endif (CLR_CMAKE_TARGET_ARCH_ARM64) if (CLR_CMAKE_TARGET_UNIX) From d96ce1a023732b8159ae756ee33534a2e00f5da6 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Sat, 27 Apr 2024 11:45:51 -0700 Subject: [PATCH 120/161] [main] Update dependencies from dotnet/arcade (#101329) * Update dependencies from https://github.com/dotnet/arcade build 20240419.5 Microsoft.SourceBuild.Intermediate.arcade , Microsoft.DotNet.Arcade.Sdk , Microsoft.DotNet.Build.Tasks.Archives , Microsoft.DotNet.Build.Tasks.Feed , Microsoft.DotNet.Build.Tasks.Installers , Microsoft.DotNet.Build.Tasks.Packaging , Microsoft.DotNet.Build.Tasks.TargetFramework , Microsoft.DotNet.Build.Tasks.Templating , Microsoft.DotNet.Build.Tasks.Workloads , Microsoft.DotNet.CodeAnalysis , Microsoft.DotNet.GenAPI , Microsoft.DotNet.GenFacades , Microsoft.DotNet.Helix.Sdk , Microsoft.DotNet.PackageTesting , Microsoft.DotNet.RemoteExecutor , Microsoft.DotNet.SharedFramework.Sdk , Microsoft.DotNet.VersionTools.Tasks , Microsoft.DotNet.XliffTasks , Microsoft.DotNet.XUnitAssert , Microsoft.DotNet.XUnitConsoleRunner , Microsoft.DotNet.XUnitExtensions From Version 9.0.0-beta.24219.1 -> To Version 9.0.0-beta.24219.5 * Update dependencies from https://github.com/dotnet/arcade build 20240419.5 Microsoft.SourceBuild.Intermediate.arcade , Microsoft.DotNet.Arcade.Sdk , Microsoft.DotNet.Build.Tasks.Archives , Microsoft.DotNet.Build.Tasks.Feed , Microsoft.DotNet.Build.Tasks.Installers , Microsoft.DotNet.Build.Tasks.Packaging , Microsoft.DotNet.Build.Tasks.TargetFramework , Microsoft.DotNet.Build.Tasks.Templating , Microsoft.DotNet.Build.Tasks.Workloads , Microsoft.DotNet.CodeAnalysis , Microsoft.DotNet.GenAPI , Microsoft.DotNet.GenFacades , Microsoft.DotNet.Helix.Sdk , Microsoft.DotNet.PackageTesting , Microsoft.DotNet.RemoteExecutor , Microsoft.DotNet.SharedFramework.Sdk , Microsoft.DotNet.VersionTools.Tasks , Microsoft.DotNet.XliffTasks , Microsoft.DotNet.XUnitAssert , Microsoft.DotNet.XUnitConsoleRunner , Microsoft.DotNet.XUnitExtensions From Version 9.0.0-beta.24219.1 -> To Version 9.0.0-beta.24219.5 * Update dependencies from https://github.com/dotnet/arcade build 20240419.5 Microsoft.SourceBuild.Intermediate.arcade , Microsoft.DotNet.Arcade.Sdk , Microsoft.DotNet.Build.Tasks.Archives , Microsoft.DotNet.Build.Tasks.Feed , Microsoft.DotNet.Build.Tasks.Installers , Microsoft.DotNet.Build.Tasks.Packaging , Microsoft.DotNet.Build.Tasks.TargetFramework , Microsoft.DotNet.Build.Tasks.Templating , Microsoft.DotNet.Build.Tasks.Workloads , Microsoft.DotNet.CodeAnalysis , Microsoft.DotNet.GenAPI , Microsoft.DotNet.GenFacades , Microsoft.DotNet.Helix.Sdk , Microsoft.DotNet.PackageTesting , Microsoft.DotNet.RemoteExecutor , Microsoft.DotNet.SharedFramework.Sdk , Microsoft.DotNet.VersionTools.Tasks , Microsoft.DotNet.XliffTasks , Microsoft.DotNet.XUnitAssert , Microsoft.DotNet.XUnitConsoleRunner , Microsoft.DotNet.XUnitExtensions From Version 9.0.0-beta.24219.1 -> To Version 9.0.0-beta.24219.5 * Update dependencies from https://github.com/dotnet/arcade build 20240423.1 Microsoft.SourceBuild.Intermediate.arcade , Microsoft.DotNet.Arcade.Sdk , Microsoft.DotNet.Build.Tasks.Archives , Microsoft.DotNet.Build.Tasks.Feed , Microsoft.DotNet.Build.Tasks.Installers , Microsoft.DotNet.Build.Tasks.Packaging , Microsoft.DotNet.Build.Tasks.TargetFramework , Microsoft.DotNet.Build.Tasks.Templating , Microsoft.DotNet.Build.Tasks.Workloads , Microsoft.DotNet.CodeAnalysis , Microsoft.DotNet.GenAPI , Microsoft.DotNet.GenFacades , Microsoft.DotNet.Helix.Sdk , Microsoft.DotNet.PackageTesting , Microsoft.DotNet.RemoteExecutor , Microsoft.DotNet.SharedFramework.Sdk , Microsoft.DotNet.VersionTools.Tasks , Microsoft.DotNet.XliffTasks , Microsoft.DotNet.XUnitAssert , Microsoft.DotNet.XUnitConsoleRunner , Microsoft.DotNet.XUnitExtensions From Version 9.0.0-beta.24219.1 -> To Version 9.0.0-beta.24223.1 * Update dependencies from https://github.com/dotnet/arcade build 20240423.8 Microsoft.SourceBuild.Intermediate.arcade , Microsoft.DotNet.Arcade.Sdk , Microsoft.DotNet.Build.Tasks.Archives , Microsoft.DotNet.Build.Tasks.Feed , Microsoft.DotNet.Build.Tasks.Installers , Microsoft.DotNet.Build.Tasks.Packaging , Microsoft.DotNet.Build.Tasks.TargetFramework , Microsoft.DotNet.Build.Tasks.Templating , Microsoft.DotNet.Build.Tasks.Workloads , Microsoft.DotNet.CodeAnalysis , Microsoft.DotNet.GenAPI , Microsoft.DotNet.GenFacades , Microsoft.DotNet.Helix.Sdk , Microsoft.DotNet.PackageTesting , Microsoft.DotNet.RemoteExecutor , Microsoft.DotNet.SharedFramework.Sdk , Microsoft.DotNet.VersionTools.Tasks , Microsoft.DotNet.XliffTasks , Microsoft.DotNet.XUnitAssert , Microsoft.DotNet.XUnitConsoleRunner , Microsoft.DotNet.XUnitExtensions From Version 9.0.0-beta.24219.1 -> To Version 9.0.0-beta.24223.8 * Update dependencies from https://github.com/dotnet/arcade build 20240423.8 Microsoft.SourceBuild.Intermediate.arcade , Microsoft.DotNet.Arcade.Sdk , Microsoft.DotNet.Build.Tasks.Archives , Microsoft.DotNet.Build.Tasks.Feed , Microsoft.DotNet.Build.Tasks.Installers , Microsoft.DotNet.Build.Tasks.Packaging , Microsoft.DotNet.Build.Tasks.TargetFramework , Microsoft.DotNet.Build.Tasks.Templating , Microsoft.DotNet.Build.Tasks.Workloads , Microsoft.DotNet.CodeAnalysis , Microsoft.DotNet.GenAPI , Microsoft.DotNet.GenFacades , Microsoft.DotNet.Helix.Sdk , Microsoft.DotNet.PackageTesting , Microsoft.DotNet.RemoteExecutor , Microsoft.DotNet.SharedFramework.Sdk , Microsoft.DotNet.VersionTools.Tasks , Microsoft.DotNet.XliffTasks , Microsoft.DotNet.XUnitAssert , Microsoft.DotNet.XUnitConsoleRunner , Microsoft.DotNet.XUnitExtensions From Version 9.0.0-beta.24219.1 -> To Version 9.0.0-beta.24223.8 * Update dependencies from https://github.com/dotnet/arcade build 20240423.8 Microsoft.SourceBuild.Intermediate.arcade , Microsoft.DotNet.Arcade.Sdk , Microsoft.DotNet.Build.Tasks.Archives , Microsoft.DotNet.Build.Tasks.Feed , Microsoft.DotNet.Build.Tasks.Installers , Microsoft.DotNet.Build.Tasks.Packaging , Microsoft.DotNet.Build.Tasks.TargetFramework , Microsoft.DotNet.Build.Tasks.Templating , Microsoft.DotNet.Build.Tasks.Workloads , Microsoft.DotNet.CodeAnalysis , Microsoft.DotNet.GenAPI , Microsoft.DotNet.GenFacades , Microsoft.DotNet.Helix.Sdk , Microsoft.DotNet.PackageTesting , Microsoft.DotNet.RemoteExecutor , Microsoft.DotNet.SharedFramework.Sdk , Microsoft.DotNet.VersionTools.Tasks , Microsoft.DotNet.XliffTasks , Microsoft.DotNet.XUnitAssert , Microsoft.DotNet.XUnitConsoleRunner , Microsoft.DotNet.XUnitExtensions From Version 9.0.0-beta.24219.1 -> To Version 9.0.0-beta.24223.8 * Update dependencies from https://github.com/dotnet/arcade build 20240424.2 Microsoft.SourceBuild.Intermediate.arcade , Microsoft.DotNet.Arcade.Sdk , Microsoft.DotNet.Build.Tasks.Archives , Microsoft.DotNet.Build.Tasks.Feed , Microsoft.DotNet.Build.Tasks.Installers , Microsoft.DotNet.Build.Tasks.Packaging , Microsoft.DotNet.Build.Tasks.TargetFramework , Microsoft.DotNet.Build.Tasks.Templating , Microsoft.DotNet.Build.Tasks.Workloads , Microsoft.DotNet.CodeAnalysis , Microsoft.DotNet.GenAPI , Microsoft.DotNet.GenFacades , Microsoft.DotNet.Helix.Sdk , Microsoft.DotNet.PackageTesting , Microsoft.DotNet.RemoteExecutor , Microsoft.DotNet.SharedFramework.Sdk , Microsoft.DotNet.VersionTools.Tasks , Microsoft.DotNet.XliffTasks , Microsoft.DotNet.XUnitAssert , Microsoft.DotNet.XUnitConsoleRunner , Microsoft.DotNet.XUnitExtensions From Version 9.0.0-beta.24219.1 -> To Version 9.0.0-beta.24224.2 * Update dependencies from https://github.com/dotnet/arcade build 20240426.3 Microsoft.SourceBuild.Intermediate.arcade , Microsoft.DotNet.Arcade.Sdk , Microsoft.DotNet.Build.Tasks.Archives , Microsoft.DotNet.Build.Tasks.Feed , Microsoft.DotNet.Build.Tasks.Installers , Microsoft.DotNet.Build.Tasks.Packaging , Microsoft.DotNet.Build.Tasks.TargetFramework , Microsoft.DotNet.Build.Tasks.Templating , Microsoft.DotNet.Build.Tasks.Workloads , Microsoft.DotNet.CodeAnalysis , Microsoft.DotNet.GenAPI , Microsoft.DotNet.GenFacades , Microsoft.DotNet.Helix.Sdk , Microsoft.DotNet.PackageTesting , Microsoft.DotNet.RemoteExecutor , Microsoft.DotNet.SharedFramework.Sdk , Microsoft.DotNet.VersionTools.Tasks , Microsoft.DotNet.XliffTasks , Microsoft.DotNet.XUnitAssert , Microsoft.DotNet.XUnitConsoleRunner , Microsoft.DotNet.XUnitExtensions From Version 9.0.0-beta.24219.1 -> To Version 9.0.0-beta.24226.3 --------- Co-authored-by: dotnet-maestro[bot] Co-authored-by: Larry Ewing --- eng/Version.Details.xml | 84 ++--- eng/Versions.props | 32 +- eng/common/core-templates/job/job.yml | 266 ++++++++++++++ eng/common/core-templates/job/onelocbuild.yml | 121 +++++++ .../job/publish-build-assets.yml | 172 ++++++++++ .../core-templates/job/source-build.yml | 80 +++++ .../job/source-index-stage1.yml | 73 ++++ .../core-templates/jobs/codeql-build.yml | 33 ++ eng/common/core-templates/jobs/jobs.yml | 119 +++++++ .../core-templates/jobs/source-build.yml | 50 +++ .../post-build/common-variables.yml | 24 ++ .../core-templates/post-build/post-build.yml | 298 ++++++++++++++++ .../post-build/setup-maestro-vars.yml | 74 ++++ .../post-build/trigger-subscription.yml | 13 + .../steps/add-build-to-channel.yml | 13 + .../steps/component-governance.yml | 14 + .../core-templates/steps/generate-sbom.yml | 54 +++ .../steps/publish-build-artifacts.yml | 20 ++ .../core-templates/steps/publish-logs.yml | 59 ++++ .../steps/publish-pipeline-artifacts.yml | 20 ++ .../core-templates/steps/retain-build.yml | 28 ++ .../core-templates/steps/send-to-helix.yml | 93 +++++ .../core-templates/steps/source-build.yml | 134 ++++++++ .../variables/pool-providers.yml | 8 + eng/common/cross/toolchain.cmake | 20 ++ eng/common/sdk-task.ps1 | 2 +- eng/common/template-guidance.md | 137 ++++++++ eng/common/templates-official/job/job.yml | 324 ++++-------------- .../templates-official/job/onelocbuild.yml | 115 +------ .../job/publish-build-assets.yml | 162 +-------- .../templates-official/job/source-build.yml | 70 +--- .../job/source-index-stage1.yml | 70 +--- .../templates-official/jobs/codeql-build.yml | 32 +- eng/common/templates-official/jobs/jobs.yml | 100 +----- .../templates-official/jobs/source-build.yml | 49 +-- .../post-build/common-variables.yml | 28 +- .../post-build/post-build.yml | 289 +--------------- .../post-build/setup-maestro-vars.yml | 74 +--- .../steps/add-build-to-channel.yml | 18 +- .../steps/component-governance.yml | 18 +- .../steps/generate-sbom.yml | 51 +-- .../steps/publish-build-artifacts.yml | 41 +++ .../templates-official/steps/publish-logs.yml | 54 +-- .../steps/publish-pipeline-artifacts.yml | 26 ++ .../templates-official/steps/retain-build.yml | 33 +- .../steps/send-to-helix.yml | 98 +----- .../templates-official/steps/source-build.yml | 134 +------- eng/common/templates/job/execute-sdl.yml | 139 -------- eng/common/templates/job/job.yml | 314 ++++------------- eng/common/templates/job/onelocbuild.yml | 112 +----- .../templates/job/publish-build-assets.yml | 158 +-------- eng/common/templates/job/source-build.yml | 69 +--- .../templates/job/source-index-stage1.yml | 70 +--- eng/common/templates/jobs/codeql-build.yml | 32 +- eng/common/templates/jobs/jobs.yml | 100 +----- eng/common/templates/jobs/source-build.yml | 49 +-- .../templates/post-build/common-variables.yml | 28 +- .../templates/post-build/post-build.yml | 286 +--------------- .../post-build/setup-maestro-vars.yml | 74 +--- .../templates/steps/add-build-to-channel.yml | 18 +- eng/common/templates/steps/build-reason.yml | 12 - .../templates/steps/component-governance.yml | 18 +- eng/common/templates/steps/execute-codeql.yml | 32 -- eng/common/templates/steps/execute-sdl.yml | 88 ----- eng/common/templates/steps/generate-sbom.yml | 51 +-- .../steps/publish-build-artifacts.yml | 40 +++ eng/common/templates/steps/publish-logs.yml | 54 +-- .../steps/publish-pipeline-artifacts.yml | 34 ++ eng/common/templates/steps/retain-build.yml | 33 +- eng/common/templates/steps/run-on-unix.yml | 7 - eng/common/templates/steps/run-on-windows.yml | 7 - .../steps/run-script-ifequalelse.yml | 33 -- eng/common/templates/steps/send-to-helix.yml | 98 +----- eng/common/templates/steps/source-build.yml | 134 +------- eng/common/templates/steps/telemetry-end.yml | 102 ------ .../templates/steps/telemetry-start.yml | 241 ------------- .../templates/variables/pool-providers.yml | 54 +-- .../templates/variables/sdl-variables.yml | 7 - eng/common/tools.ps1 | 4 +- global.json | 6 +- 80 files changed, 2459 insertions(+), 3872 deletions(-) create mode 100644 eng/common/core-templates/job/job.yml create mode 100644 eng/common/core-templates/job/onelocbuild.yml create mode 100644 eng/common/core-templates/job/publish-build-assets.yml create mode 100644 eng/common/core-templates/job/source-build.yml create mode 100644 eng/common/core-templates/job/source-index-stage1.yml create mode 100644 eng/common/core-templates/jobs/codeql-build.yml create mode 100644 eng/common/core-templates/jobs/jobs.yml create mode 100644 eng/common/core-templates/jobs/source-build.yml create mode 100644 eng/common/core-templates/post-build/common-variables.yml create mode 100644 eng/common/core-templates/post-build/post-build.yml create mode 100644 eng/common/core-templates/post-build/setup-maestro-vars.yml create mode 100644 eng/common/core-templates/post-build/trigger-subscription.yml create mode 100644 eng/common/core-templates/steps/add-build-to-channel.yml create mode 100644 eng/common/core-templates/steps/component-governance.yml create mode 100644 eng/common/core-templates/steps/generate-sbom.yml create mode 100644 eng/common/core-templates/steps/publish-build-artifacts.yml create mode 100644 eng/common/core-templates/steps/publish-logs.yml create mode 100644 eng/common/core-templates/steps/publish-pipeline-artifacts.yml create mode 100644 eng/common/core-templates/steps/retain-build.yml create mode 100644 eng/common/core-templates/steps/send-to-helix.yml create mode 100644 eng/common/core-templates/steps/source-build.yml create mode 100644 eng/common/core-templates/variables/pool-providers.yml create mode 100644 eng/common/template-guidance.md create mode 100644 eng/common/templates-official/steps/publish-build-artifacts.yml create mode 100644 eng/common/templates-official/steps/publish-pipeline-artifacts.yml delete mode 100644 eng/common/templates/job/execute-sdl.yml delete mode 100644 eng/common/templates/steps/build-reason.yml delete mode 100644 eng/common/templates/steps/execute-codeql.yml delete mode 100644 eng/common/templates/steps/execute-sdl.yml create mode 100644 eng/common/templates/steps/publish-build-artifacts.yml create mode 100644 eng/common/templates/steps/publish-pipeline-artifacts.yml delete mode 100644 eng/common/templates/steps/run-on-unix.yml delete mode 100644 eng/common/templates/steps/run-on-windows.yml delete mode 100644 eng/common/templates/steps/run-script-ifequalelse.yml delete mode 100644 eng/common/templates/steps/telemetry-end.yml delete mode 100644 eng/common/templates/steps/telemetry-start.yml delete mode 100644 eng/common/templates/variables/sdl-variables.yml diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index c35213b8ecadb5..9bcdac9884a810 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -92,87 +92,87 @@ - + https://github.com/dotnet/arcade - b4f4d40741f161e2c0d96c19c51a4013850ef65f + 97e2f41e909dcabb1103fe98ba4540a246662187 - + https://github.com/dotnet/arcade - b4f4d40741f161e2c0d96c19c51a4013850ef65f + 97e2f41e909dcabb1103fe98ba4540a246662187 - + https://github.com/dotnet/arcade - b4f4d40741f161e2c0d96c19c51a4013850ef65f + 97e2f41e909dcabb1103fe98ba4540a246662187 - + https://github.com/dotnet/arcade - b4f4d40741f161e2c0d96c19c51a4013850ef65f + 97e2f41e909dcabb1103fe98ba4540a246662187 - + https://github.com/dotnet/arcade - b4f4d40741f161e2c0d96c19c51a4013850ef65f + 97e2f41e909dcabb1103fe98ba4540a246662187 - + https://github.com/dotnet/arcade - b4f4d40741f161e2c0d96c19c51a4013850ef65f + 97e2f41e909dcabb1103fe98ba4540a246662187 - + https://github.com/dotnet/arcade - b4f4d40741f161e2c0d96c19c51a4013850ef65f + 97e2f41e909dcabb1103fe98ba4540a246662187 - + https://github.com/dotnet/arcade - b4f4d40741f161e2c0d96c19c51a4013850ef65f + 97e2f41e909dcabb1103fe98ba4540a246662187 - + https://github.com/dotnet/arcade - b4f4d40741f161e2c0d96c19c51a4013850ef65f + 97e2f41e909dcabb1103fe98ba4540a246662187 - + https://github.com/dotnet/arcade - b4f4d40741f161e2c0d96c19c51a4013850ef65f + 97e2f41e909dcabb1103fe98ba4540a246662187 - + https://github.com/dotnet/arcade - b4f4d40741f161e2c0d96c19c51a4013850ef65f + 97e2f41e909dcabb1103fe98ba4540a246662187 - + https://github.com/dotnet/arcade - b4f4d40741f161e2c0d96c19c51a4013850ef65f + 97e2f41e909dcabb1103fe98ba4540a246662187 - + https://github.com/dotnet/arcade - b4f4d40741f161e2c0d96c19c51a4013850ef65f + 97e2f41e909dcabb1103fe98ba4540a246662187 - + https://github.com/dotnet/arcade - b4f4d40741f161e2c0d96c19c51a4013850ef65f + 97e2f41e909dcabb1103fe98ba4540a246662187 - + https://github.com/dotnet/arcade - b4f4d40741f161e2c0d96c19c51a4013850ef65f + 97e2f41e909dcabb1103fe98ba4540a246662187 - + https://github.com/dotnet/arcade - b4f4d40741f161e2c0d96c19c51a4013850ef65f + 97e2f41e909dcabb1103fe98ba4540a246662187 - + https://github.com/dotnet/arcade - b4f4d40741f161e2c0d96c19c51a4013850ef65f + 97e2f41e909dcabb1103fe98ba4540a246662187 - + https://github.com/dotnet/arcade - b4f4d40741f161e2c0d96c19c51a4013850ef65f + 97e2f41e909dcabb1103fe98ba4540a246662187 - + https://github.com/dotnet/arcade - b4f4d40741f161e2c0d96c19c51a4013850ef65f + 97e2f41e909dcabb1103fe98ba4540a246662187 - + https://github.com/dotnet/arcade - b4f4d40741f161e2c0d96c19c51a4013850ef65f + 97e2f41e909dcabb1103fe98ba4540a246662187 https://github.com/dotnet/runtime-assets @@ -332,9 +332,9 @@ https://github.com/dotnet/xharness ec633d9ddbdb86dd3d772989889690821f790484 - + https://github.com/dotnet/arcade - b4f4d40741f161e2c0d96c19c51a4013850ef65f + 97e2f41e909dcabb1103fe98ba4540a246662187 https://dev.azure.com/dnceng/internal/_git/dotnet-optimization diff --git a/eng/Versions.props b/eng/Versions.props index 8ca09ea0685ae1..0ff857849146a1 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -83,22 +83,22 @@ 9.0.100-preview.4.24221.4 - 9.0.0-beta.24219.1 - 9.0.0-beta.24219.1 - 9.0.0-beta.24219.1 - 9.0.0-beta.24219.1 - 2.6.7-beta.24219.1 - 9.0.0-beta.24219.1 - 2.6.7-beta.24219.1 - 9.0.0-beta.24219.1 - 9.0.0-beta.24219.1 - 9.0.0-beta.24219.1 - 9.0.0-beta.24219.1 - 9.0.0-beta.24219.1 - 9.0.0-beta.24219.1 - 9.0.0-beta.24219.1 - 9.0.0-beta.24219.1 - 9.0.0-beta.24219.1 + 9.0.0-beta.24226.3 + 9.0.0-beta.24226.3 + 9.0.0-beta.24226.3 + 9.0.0-beta.24226.3 + 2.6.7-beta.24226.3 + 9.0.0-beta.24226.3 + 2.6.7-beta.24226.3 + 9.0.0-beta.24226.3 + 9.0.0-beta.24226.3 + 9.0.0-beta.24226.3 + 9.0.0-beta.24226.3 + 9.0.0-beta.24226.3 + 9.0.0-beta.24226.3 + 9.0.0-beta.24226.3 + 9.0.0-beta.24226.3 + 9.0.0-beta.24226.3 1.4.0 diff --git a/eng/common/core-templates/job/job.yml b/eng/common/core-templates/job/job.yml new file mode 100644 index 00000000000000..dc3bd560a50e24 --- /dev/null +++ b/eng/common/core-templates/job/job.yml @@ -0,0 +1,266 @@ +parameters: +# Job schema parameters - https://docs.microsoft.com/en-us/azure/devops/pipelines/yaml-schema?view=vsts&tabs=schema#job + cancelTimeoutInMinutes: '' + condition: '' + container: '' + continueOnError: false + dependsOn: '' + displayName: '' + pool: '' + steps: [] + strategy: '' + timeoutInMinutes: '' + variables: [] + workspace: '' + templateContext: {} + +# Job base template specific parameters + # See schema documentation - https://github.com/dotnet/arcade/blob/master/Documentation/AzureDevOps/TemplateSchema.md + # publishing defaults + artifacts: '' + enableMicrobuild: false + enablePublishBuildArtifacts: false + enablePublishBuildAssets: false + enablePublishTestResults: false + enablePublishUsingPipelines: false + enableBuildRetry: false + disableComponentGovernance: '' + componentGovernanceIgnoreDirectories: '' + mergeTestResults: false + testRunTitle: '' + testResultsFormat: '' + name: '' + preSteps: [] + artifactPublishSteps: [] + runAsPublic: false + +# Sbom related params + enableSbom: true + PackageVersion: 9.0.0 + BuildDropPath: '$(Build.SourcesDirectory)/artifacts' + +# 1es specific parameters + is1ESPipeline: '' + +jobs: +- job: ${{ parameters.name }} + + ${{ if ne(parameters.cancelTimeoutInMinutes, '') }}: + cancelTimeoutInMinutes: ${{ parameters.cancelTimeoutInMinutes }} + + ${{ if ne(parameters.condition, '') }}: + condition: ${{ parameters.condition }} + + ${{ if ne(parameters.container, '') }}: + container: ${{ parameters.container }} + + ${{ if ne(parameters.continueOnError, '') }}: + continueOnError: ${{ parameters.continueOnError }} + + ${{ if ne(parameters.dependsOn, '') }}: + dependsOn: ${{ parameters.dependsOn }} + + ${{ if ne(parameters.displayName, '') }}: + displayName: ${{ parameters.displayName }} + + ${{ if ne(parameters.pool, '') }}: + pool: ${{ parameters.pool }} + + ${{ if ne(parameters.strategy, '') }}: + strategy: ${{ parameters.strategy }} + + ${{ if ne(parameters.timeoutInMinutes, '') }}: + timeoutInMinutes: ${{ parameters.timeoutInMinutes }} + + ${{ if ne(parameters.templateContext, '') }}: + templateContext: ${{ parameters.templateContext }} + + variables: + - ${{ if ne(parameters.enableTelemetry, 'false') }}: + - name: DOTNET_CLI_TELEMETRY_PROFILE + value: '$(Build.Repository.Uri)' + - ${{ if eq(parameters.enableRichCodeNavigation, 'true') }}: + - name: EnableRichCodeNavigation + value: 'true' + # Retry signature validation up to three times, waiting 2 seconds between attempts. + # See https://learn.microsoft.com/en-us/nuget/reference/errors-and-warnings/nu3028#retry-untrusted-root-failures + - name: NUGET_EXPERIMENTAL_CHAIN_BUILD_RETRY_POLICY + value: 3,2000 + - ${{ each variable in parameters.variables }}: + # handle name-value variable syntax + # example: + # - name: [key] + # value: [value] + - ${{ if ne(variable.name, '') }}: + - name: ${{ variable.name }} + value: ${{ variable.value }} + + # handle variable groups + - ${{ if ne(variable.group, '') }}: + - group: ${{ variable.group }} + + # handle template variable syntax + # example: + # - template: path/to/template.yml + # parameters: + # [key]: [value] + - ${{ if ne(variable.template, '') }}: + - template: ${{ variable.template }} + ${{ if ne(variable.parameters, '') }}: + parameters: ${{ variable.parameters }} + + # handle key-value variable syntax. + # example: + # - [key]: [value] + - ${{ if and(eq(variable.name, ''), eq(variable.group, ''), eq(variable.template, '')) }}: + - ${{ each pair in variable }}: + - name: ${{ pair.key }} + value: ${{ pair.value }} + + # DotNet-HelixApi-Access provides 'HelixApiAccessToken' for internal builds + - ${{ if and(eq(parameters.enableTelemetry, 'true'), eq(parameters.runAsPublic, 'false'), ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest')) }}: + - group: DotNet-HelixApi-Access + + ${{ if ne(parameters.workspace, '') }}: + workspace: ${{ parameters.workspace }} + + steps: + - ${{ if eq(parameters.is1ESPipeline, '') }}: + - 'Illegal entry point, is1ESPipeline is not defined. Repository yaml should not directly reference templates in core-templates folder.': error + + - ${{ if ne(parameters.preSteps, '') }}: + - ${{ each preStep in parameters.preSteps }}: + - ${{ preStep }} + + - ${{ if and(eq(parameters.runAsPublic, 'false'), ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest')) }}: + - ${{ if eq(parameters.enableMicrobuild, 'true') }}: + - task: MicroBuildSigningPlugin@4 + displayName: Install MicroBuild plugin + inputs: + signType: $(_SignType) + zipSources: false + feedSource: https://dnceng.pkgs.visualstudio.com/_packaging/MicroBuildToolset/nuget/v3/index.json + env: + TeamName: $(_TeamName) + MicroBuildOutputFolderOverride: '$(Agent.TempDirectory)' + continueOnError: ${{ parameters.continueOnError }} + condition: and(succeeded(), in(variables['_SignType'], 'real', 'test'), eq(variables['Agent.Os'], 'Windows_NT')) + + - ${{ if and(eq(parameters.runAsPublic, 'false'), eq(variables['System.TeamProject'], 'internal')) }}: + - task: NuGetAuthenticate@1 + + - ${{ if and(ne(parameters.artifacts.download, 'false'), ne(parameters.artifacts.download, '')) }}: + - task: DownloadPipelineArtifact@2 + inputs: + buildType: current + artifactName: ${{ coalesce(parameters.artifacts.download.name, 'Artifacts_$(Agent.OS)_$(_BuildConfig)') }} + targetPath: ${{ coalesce(parameters.artifacts.download.path, 'artifacts') }} + itemPattern: ${{ coalesce(parameters.artifacts.download.pattern, '**') }} + + - ${{ each step in parameters.steps }}: + - ${{ step }} + + - ${{ if eq(parameters.enableRichCodeNavigation, true) }}: + - task: RichCodeNavIndexer@0 + displayName: RichCodeNav Upload + inputs: + languages: ${{ coalesce(parameters.richCodeNavigationLanguage, 'csharp') }} + environment: ${{ coalesce(parameters.richCodeNavigationEnvironment, 'internal') }} + richNavLogOutputDirectory: $(Build.SourcesDirectory)/artifacts/bin + uploadRichNavArtifacts: ${{ coalesce(parameters.richCodeNavigationUploadArtifacts, false) }} + continueOnError: true + + - template: /eng/common/core-templates/steps/component-governance.yml + parameters: + is1ESPipeline: ${{ parameters.is1ESPipeline }} + ${{ if eq(parameters.disableComponentGovernance, '') }}: + ${{ if and(ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest'), eq(parameters.runAsPublic, 'false'), or(startsWith(variables['Build.SourceBranch'], 'refs/heads/release/'), startsWith(variables['Build.SourceBranch'], 'refs/heads/dotnet/'), startsWith(variables['Build.SourceBranch'], 'refs/heads/microsoft/'), eq(variables['Build.SourceBranch'], 'refs/heads/main'))) }}: + disableComponentGovernance: false + ${{ else }}: + disableComponentGovernance: true + ${{ else }}: + disableComponentGovernance: ${{ parameters.disableComponentGovernance }} + componentGovernanceIgnoreDirectories: ${{ parameters.componentGovernanceIgnoreDirectories }} + + - ${{ if eq(parameters.enableMicrobuild, 'true') }}: + - ${{ if and(eq(parameters.runAsPublic, 'false'), ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest')) }}: + - task: MicroBuildCleanup@1 + displayName: Execute Microbuild cleanup tasks + condition: and(always(), in(variables['_SignType'], 'real', 'test'), eq(variables['Agent.Os'], 'Windows_NT')) + continueOnError: ${{ parameters.continueOnError }} + env: + TeamName: $(_TeamName) + - ${{ if and(eq(parameters.runAsPublic, 'false'), ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest'), eq(parameters.enableSbom, 'true')) }}: + - template: /eng/common/core-templates/steps/generate-sbom.yml + parameters: + is1ESPipeline: ${{ parameters.is1ESPipeline }} + PackageVersion: ${{ parameters.packageVersion}} + BuildDropPath: ${{ parameters.buildDropPath }} + IgnoreDirectories: ${{ parameters.componentGovernanceIgnoreDirectories }} + publishArtifacts: false + + # Publish test results + - ${{ if and(eq(parameters.enablePublishTestResults, 'true'), eq(parameters.testResultsFormat, '')) }}: + - ${{ if eq(parameters.testResultsFormat, 'xunit') }}: + - task: PublishTestResults@2 + displayName: Publish XUnit Test Results + inputs: + testResultsFormat: 'xUnit' + testResultsFiles: '*.xml' + searchFolder: '$(Build.SourcesDirectory)/artifacts/TestResults/$(_BuildConfig)' + testRunTitle: ${{ coalesce(parameters.testRunTitle, parameters.name, '$(System.JobName)') }}-xunit + mergeTestResults: ${{ parameters.mergeTestResults }} + continueOnError: true + condition: always() + - ${{ if eq(parameters.testResultsFormat, 'vstest') }}: + - task: PublishTestResults@2 + displayName: Publish TRX Test Results + inputs: + testResultsFormat: 'VSTest' + testResultsFiles: '*.trx' + searchFolder: '$(Build.SourcesDirectory)/artifacts/TestResults/$(_BuildConfig)' + testRunTitle: ${{ coalesce(parameters.testRunTitle, parameters.name, '$(System.JobName)') }}-trx + mergeTestResults: ${{ parameters.mergeTestResults }} + continueOnError: true + condition: always() + + # gather artifacts + - ${{ if ne(parameters.artifacts.publish, '') }}: + - ${{ if and(ne(parameters.artifacts.publish.artifacts, 'false'), ne(parameters.artifacts.publish.artifacts, '')) }}: + - task: CopyFiles@2 + displayName: Gather binaries for publish to artifacts + inputs: + SourceFolder: 'artifacts/bin' + Contents: '**' + TargetFolder: '$(Build.ArtifactStagingDirectory)/artifacts/bin' + - task: CopyFiles@2 + displayName: Gather packages for publish to artifacts + inputs: + SourceFolder: 'artifacts/packages' + Contents: '**' + TargetFolder: '$(Build.ArtifactStagingDirectory)/artifacts/packages' + - ${{ if and(ne(parameters.artifacts.publish.logs, 'false'), ne(parameters.artifacts.publish.logs, '')) }}: + - task: CopyFiles@2 + displayName: Gather logs for publish to artifacts + inputs: + SourceFolder: 'artifacts/log' + Contents: '**' + TargetFolder: '$(Build.ArtifactStagingDirectory)/artifacts/log' + + - ${{ if eq(parameters.enablePublishBuildArtifacts, 'true') }}: + - task: CopyFiles@2 + displayName: Gather logs for publish to artifacts + inputs: + SourceFolder: 'artifacts/log/$(_BuildConfig)' + Contents: '**' + TargetFolder: '$(Build.ArtifactStagingDirectory)/artifacts/log/$(_BuildConfig)' + - ${{ if eq(parameters.enableBuildRetry, 'true') }}: + - task: CopyFiles@2 + displayName: Gather buildconfiguration for build retry + inputs: + SourceFolder: '$(Build.SourcesDirectory)/eng/common/BuildConfiguration' + Contents: '**' + TargetFolder: '$(Build.ArtifactStagingDirectory)/eng/common/BuildConfiguration' + + - ${{ each step in parameters.artifactPublishSteps }}: + - ${{ step }} diff --git a/eng/common/core-templates/job/onelocbuild.yml b/eng/common/core-templates/job/onelocbuild.yml new file mode 100644 index 00000000000000..00feec8ebbc3ab --- /dev/null +++ b/eng/common/core-templates/job/onelocbuild.yml @@ -0,0 +1,121 @@ +parameters: + # Optional: dependencies of the job + dependsOn: '' + + # Optional: A defined YAML pool - https://docs.microsoft.com/en-us/azure/devops/pipelines/yaml-schema?view=vsts&tabs=schema#pool + pool: '' + + CeapexPat: $(dn-bot-ceapex-package-r) # PAT for the loc AzDO instance https://dev.azure.com/ceapex + GithubPat: $(BotAccount-dotnet-bot-repo-PAT) + + SourcesDirectory: $(Build.SourcesDirectory) + CreatePr: true + AutoCompletePr: false + ReusePr: true + UseLfLineEndings: true + UseCheckedInLocProjectJson: false + SkipLocProjectJsonGeneration: false + LanguageSet: VS_Main_Languages + LclSource: lclFilesInRepo + LclPackageId: '' + RepoType: gitHub + GitHubOrg: dotnet + MirrorRepo: '' + MirrorBranch: main + condition: '' + JobNameSuffix: '' + is1ESPipeline: '' +jobs: +- job: OneLocBuild${{ parameters.JobNameSuffix }} + + dependsOn: ${{ parameters.dependsOn }} + + displayName: OneLocBuild${{ parameters.JobNameSuffix }} + + variables: + - group: OneLocBuildVariables # Contains the CeapexPat and GithubPat + - name: _GenerateLocProjectArguments + value: -SourcesDirectory ${{ parameters.SourcesDirectory }} + -LanguageSet "${{ parameters.LanguageSet }}" + -CreateNeutralXlfs + - ${{ if eq(parameters.UseCheckedInLocProjectJson, 'true') }}: + - name: _GenerateLocProjectArguments + value: ${{ variables._GenerateLocProjectArguments }} -UseCheckedInLocProjectJson + - template: /eng/common/core-templates/variables/pool-providers.yml + parameters: + is1ESPipeline: ${{ parameters.is1ESPipeline }} + + ${{ if ne(parameters.pool, '') }}: + pool: ${{ parameters.pool }} + ${{ if eq(parameters.pool, '') }}: + pool: + # We don't use the collection uri here because it might vary (.visualstudio.com vs. dev.azure.com) + ${{ if eq(variables['System.TeamProject'], 'DevDiv') }}: + name: AzurePipelines-EO + image: 1ESPT-Windows2022 + demands: Cmd + os: windows + # If it's not devdiv, it's dnceng + ${{ if ne(variables['System.TeamProject'], 'DevDiv') }}: + name: $(DncEngInternalBuildPool) + image: 1es-windows-2022 + os: windows + + steps: + - ${{ if eq(parameters.is1ESPipeline, '') }}: + - 'Illegal entry point, is1ESPipeline is not defined. Repository yaml should not directly reference templates in core-templates folder.': error + + - ${{ if ne(parameters.SkipLocProjectJsonGeneration, 'true') }}: + - task: Powershell@2 + inputs: + filePath: $(Build.SourcesDirectory)/eng/common/generate-locproject.ps1 + arguments: $(_GenerateLocProjectArguments) + displayName: Generate LocProject.json + condition: ${{ parameters.condition }} + + - task: OneLocBuild@2 + displayName: OneLocBuild + env: + SYSTEM_ACCESSTOKEN: $(System.AccessToken) + inputs: + locProj: eng/Localize/LocProject.json + outDir: $(Build.ArtifactStagingDirectory) + lclSource: ${{ parameters.LclSource }} + lclPackageId: ${{ parameters.LclPackageId }} + isCreatePrSelected: ${{ parameters.CreatePr }} + isAutoCompletePrSelected: ${{ parameters.AutoCompletePr }} + ${{ if eq(parameters.CreatePr, true) }}: + isUseLfLineEndingsSelected: ${{ parameters.UseLfLineEndings }} + ${{ if eq(parameters.RepoType, 'gitHub') }}: + isShouldReusePrSelected: ${{ parameters.ReusePr }} + packageSourceAuth: patAuth + patVariable: ${{ parameters.CeapexPat }} + ${{ if eq(parameters.RepoType, 'gitHub') }}: + repoType: ${{ parameters.RepoType }} + gitHubPatVariable: "${{ parameters.GithubPat }}" + ${{ if ne(parameters.MirrorRepo, '') }}: + isMirrorRepoSelected: true + gitHubOrganization: ${{ parameters.GitHubOrg }} + mirrorRepo: ${{ parameters.MirrorRepo }} + mirrorBranch: ${{ parameters.MirrorBranch }} + condition: ${{ parameters.condition }} + + - template: /eng/common/core-templates/steps/publish-build-artifacts.yml + parameters: + is1ESPipeline: ${{ parameters.is1ESPipeline }} + args: + displayName: Publish Localization Files + pathToPublish: '$(Build.ArtifactStagingDirectory)/loc' + publishLocation: Container + artifactName: Loc + condition: ${{ parameters.condition }} + + - template: /eng/common/core-templates/steps/publish-build-artifacts.yml + parameters: + is1ESPipeline: ${{ parameters.is1ESPipeline }} + args: + displayName: Publish LocProject.json + pathToPublish: '$(Build.SourcesDirectory)/eng/Localize/' + publishLocation: Container + artifactName: Loc + condition: ${{ parameters.condition }} \ No newline at end of file diff --git a/eng/common/core-templates/job/publish-build-assets.yml b/eng/common/core-templates/job/publish-build-assets.yml new file mode 100644 index 00000000000000..8fe9299542c531 --- /dev/null +++ b/eng/common/core-templates/job/publish-build-assets.yml @@ -0,0 +1,172 @@ +parameters: + configuration: 'Debug' + + # Optional: condition for the job to run + condition: '' + + # Optional: 'true' if future jobs should run even if this job fails + continueOnError: false + + # Optional: dependencies of the job + dependsOn: '' + + # Optional: Include PublishBuildArtifacts task + enablePublishBuildArtifacts: false + + # Optional: A defined YAML pool - https://docs.microsoft.com/en-us/azure/devops/pipelines/yaml-schema?view=vsts&tabs=schema#pool + pool: {} + + # Optional: should run as a public build even in the internal project + # if 'true', the build won't run any of the internal only steps, even if it is running in non-public projects. + runAsPublic: false + + # Optional: whether the build's artifacts will be published using release pipelines or direct feed publishing + publishUsingPipelines: false + + # Optional: whether the build's artifacts will be published using release pipelines or direct feed publishing + publishAssetsImmediately: false + + artifactsPublishingAdditionalParameters: '' + + signingValidationAdditionalParameters: '' + + is1ESPipeline: '' + +jobs: +- job: Asset_Registry_Publish + + dependsOn: ${{ parameters.dependsOn }} + timeoutInMinutes: 150 + + ${{ if eq(parameters.publishAssetsImmediately, 'true') }}: + displayName: Publish Assets + ${{ else }}: + displayName: Publish to Build Asset Registry + + variables: + - template: /eng/common/core-templates/variables/pool-providers.yml + parameters: + is1ESPipeline: ${{ parameters.is1ESPipeline }} + - ${{ if and(eq(parameters.runAsPublic, 'false'), ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest')) }}: + - group: Publish-Build-Assets + - group: AzureDevOps-Artifact-Feeds-Pats + - name: runCodesignValidationInjection + value: false + # unconditional - needed for logs publishing (redactor tool version) + - template: /eng/common/core-templates/post-build/common-variables.yml + + pool: + # We don't use the collection uri here because it might vary (.visualstudio.com vs. dev.azure.com) + ${{ if eq(variables['System.TeamProject'], 'DevDiv') }}: + name: AzurePipelines-EO + image: 1ESPT-Windows2022 + demands: Cmd + os: windows + # If it's not devdiv, it's dnceng + ${{ if ne(variables['System.TeamProject'], 'DevDiv') }}: + name: NetCore1ESPool-Publishing-Internal + image: windows.vs2019.amd64 + os: windows + steps: + - ${{ if eq(parameters.is1ESPipeline, '') }}: + - 'Illegal entry point, is1ESPipeline is not defined. Repository yaml should not directly reference templates in core-templates folder.': error + + - ${{ if and(eq(parameters.runAsPublic, 'false'), ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest')) }}: + - checkout: self + fetchDepth: 3 + clean: true + + - task: DownloadBuildArtifacts@0 + displayName: Download artifact + inputs: + artifactName: AssetManifests + downloadPath: '$(Build.StagingDirectory)/Download' + checkDownloadedFiles: true + condition: ${{ parameters.condition }} + continueOnError: ${{ parameters.continueOnError }} + + - task: NuGetAuthenticate@1 + + - task: PowerShell@2 + displayName: Publish Build Assets + inputs: + filePath: eng\common\sdk-task.ps1 + arguments: -task PublishBuildAssets -restore -msbuildEngine dotnet + /p:ManifestsPath='$(Build.StagingDirectory)/Download/AssetManifests' + /p:BuildAssetRegistryToken=$(MaestroAccessToken) + /p:MaestroApiEndpoint=https://maestro.dot.net + /p:PublishUsingPipelines=${{ parameters.publishUsingPipelines }} + /p:OfficialBuildId=$(Build.BuildNumber) + condition: ${{ parameters.condition }} + continueOnError: ${{ parameters.continueOnError }} + + - task: powershell@2 + displayName: Create ReleaseConfigs Artifact + inputs: + targetType: inline + script: | + New-Item -Path "$(Build.StagingDirectory)/ReleaseConfigs" -ItemType Directory -Force + $filePath = "$(Build.StagingDirectory)/ReleaseConfigs/ReleaseConfigs.txt" + Add-Content -Path $filePath -Value $(BARBuildId) + Add-Content -Path $filePath -Value "$(DefaultChannels)" + Add-Content -Path $filePath -Value $(IsStableBuild) + + - template: /eng/common/core-templates/steps/publish-build-artifacts.yml + parameters: + is1ESPipeline: ${{ parameters.is1ESPipeline }} + args: + displayName: Publish ReleaseConfigs Artifact + pathToPublish: '$(Build.StagingDirectory)/ReleaseConfigs' + publishLocation: Container + artifactName: ReleaseConfigs + + - task: powershell@2 + displayName: Check if SymbolPublishingExclusionsFile.txt exists + inputs: + targetType: inline + script: | + $symbolExclusionfile = "$(Build.SourcesDirectory)/eng/SymbolPublishingExclusionsFile.txt" + if(Test-Path -Path $symbolExclusionfile) + { + Write-Host "SymbolExclusionFile exists" + Write-Host "##vso[task.setvariable variable=SymbolExclusionFile]true" + } + else{ + Write-Host "Symbols Exclusion file does not exist" + Write-Host "##vso[task.setvariable variable=SymbolExclusionFile]false" + } + + - template: /eng/common/core-templates/steps/publish-build-artifacts.yml + parameters: + is1ESPipeline: ${{ parameters.is1ESPipeline }} + args: + displayName: Publish SymbolPublishingExclusionsFile Artifact + condition: eq(variables['SymbolExclusionFile'], 'true') + pathToPublish: '$(Build.SourcesDirectory)/eng/SymbolPublishingExclusionsFile.txt' + publishLocation: Container + artifactName: ReleaseConfigs + + - ${{ if eq(parameters.publishAssetsImmediately, 'true') }}: + - template: /eng/common/core-templates/post-build/setup-maestro-vars.yml + parameters: + BARBuildId: ${{ parameters.BARBuildId }} + PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }} + is1ESPipeline: ${{ parameters.is1ESPipeline }} + + - task: PowerShell@2 + displayName: Publish Using Darc + inputs: + filePath: $(Build.SourcesDirectory)/eng/common/post-build/publish-using-darc.ps1 + arguments: -BuildId $(BARBuildId) + -PublishingInfraVersion 3 + -AzdoToken '$(publishing-dnceng-devdiv-code-r-build-re)' + -MaestroToken '$(MaestroApiAccessToken)' + -WaitPublishingFinish true + -ArtifactsPublishingAdditionalParameters '${{ parameters.artifactsPublishingAdditionalParameters }}' + -SymbolPublishingAdditionalParameters '${{ parameters.symbolPublishingAdditionalParameters }}' + + - ${{ if eq(parameters.enablePublishBuildArtifacts, 'true') }}: + - template: /eng/common/core-templates/steps/publish-logs.yml + parameters: + is1ESPipeline: ${{ parameters.is1ESPipeline }} + JobLabel: 'Publish_Artifacts_Logs' diff --git a/eng/common/core-templates/job/source-build.yml b/eng/common/core-templates/job/source-build.yml new file mode 100644 index 00000000000000..c0ce4b3c861861 --- /dev/null +++ b/eng/common/core-templates/job/source-build.yml @@ -0,0 +1,80 @@ +parameters: + # This template adds arcade-powered source-build to CI. The template produces a server job with a + # default ID 'Source_Build_Complete' to put in a dependency list if necessary. + + # Specifies the prefix for source-build jobs added to pipeline. Use this if disambiguation needed. + jobNamePrefix: 'Source_Build' + + # Defines the platform on which to run the job. By default, a linux-x64 machine, suitable for + # managed-only repositories. This is an object with these properties: + # + # name: '' + # The name of the job. This is included in the job ID. + # targetRID: '' + # The name of the target RID to use, instead of the one auto-detected by Arcade. + # nonPortable: false + # Enables non-portable mode. This means a more specific RID (e.g. fedora.32-x64 rather than + # linux-x64), and compiling against distro-provided packages rather than portable ones. + # skipPublishValidation: false + # Disables publishing validation. By default, a check is performed to ensure no packages are + # published by source-build. + # container: '' + # A container to use. Runs in docker. + # pool: {} + # A pool to use. Runs directly on an agent. + # buildScript: '' + # Specifies the build script to invoke to perform the build in the repo. The default + # './build.sh' should work for typical Arcade repositories, but this is customizable for + # difficult situations. + # jobProperties: {} + # A list of job properties to inject at the top level, for potential extensibility beyond + # container and pool. + platform: {} + + is1ESPipeline: '' + +jobs: +- job: ${{ parameters.jobNamePrefix }}_${{ parameters.platform.name }} + displayName: Source-Build (${{ parameters.platform.name }}) + + ${{ each property in parameters.platform.jobProperties }}: + ${{ property.key }}: ${{ property.value }} + + ${{ if ne(parameters.platform.container, '') }}: + container: ${{ parameters.platform.container }} + + ${{ if eq(parameters.platform.pool, '') }}: + # The default VM host AzDO pool. This should be capable of running Docker containers: almost all + # source-build builds run in Docker, including the default managed platform. + # /eng/common/core-templates/variables/pool-providers.yml can't be used here (some customers declare variables already), so duplicate its logic + ${{ if eq(parameters.is1ESPipeline, 'true') }}: + pool: + ${{ if eq(variables['System.TeamProject'], 'public') }}: + name: $[replace(replace(eq(contains(coalesce(variables['System.PullRequest.TargetBranch'], variables['Build.SourceBranch'], 'refs/heads/main'), 'release'), 'true'), True, 'NetCore-Svc-Public' ), False, 'NetCore-Public')] + demands: ImageOverride -equals build.ubuntu.2004.amd64 + ${{ if eq(variables['System.TeamProject'], 'internal') }}: + name: $[replace(replace(eq(contains(coalesce(variables['System.PullRequest.TargetBranch'], variables['Build.SourceBranch'], 'refs/heads/main'), 'release'), 'true'), True, 'NetCore1ESPool-Svc-Internal'), False, 'NetCore1ESPool-Internal')] + image: 1es-mariner-2 + os: linux + ${{ else }}: + pool: + ${{ if eq(variables['System.TeamProject'], 'public') }}: + name: $[replace(replace(eq(contains(coalesce(variables['System.PullRequest.TargetBranch'], variables['Build.SourceBranch'], 'refs/heads/main'), 'release'), 'true'), True, 'NetCore-Svc-Public' ), False, 'NetCore-Public')] + demands: ImageOverride -equals Build.Ubuntu.2204.Amd64.Open + ${{ if eq(variables['System.TeamProject'], 'internal') }}: + name: $[replace(replace(eq(contains(coalesce(variables['System.PullRequest.TargetBranch'], variables['Build.SourceBranch'], 'refs/heads/main'), 'release'), 'true'), True, 'NetCore1ESPool-Svc-Internal'), False, 'NetCore1ESPool-Internal')] + demands: ImageOverride -equals Build.Ubuntu.2204.Amd64 + ${{ if ne(parameters.platform.pool, '') }}: + pool: ${{ parameters.platform.pool }} + + workspace: + clean: all + + steps: + - ${{ if eq(parameters.is1ESPipeline, '') }}: + - 'Illegal entry point, is1ESPipeline is not defined. Repository yaml should not directly reference templates in core-templates folder.': error + + - template: /eng/common/core-templates/steps/source-build.yml + parameters: + is1ESPipeline: ${{ parameters.is1ESPipeline }} + platform: ${{ parameters.platform }} diff --git a/eng/common/core-templates/job/source-index-stage1.yml b/eng/common/core-templates/job/source-index-stage1.yml new file mode 100644 index 00000000000000..9c6e5ae3c3e45a --- /dev/null +++ b/eng/common/core-templates/job/source-index-stage1.yml @@ -0,0 +1,73 @@ +parameters: + runAsPublic: false + sourceIndexPackageVersion: 1.0.1-20240129.2 + sourceIndexPackageSource: https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools/nuget/v3/index.json + sourceIndexBuildCommand: powershell -NoLogo -NoProfile -ExecutionPolicy Bypass -Command "eng/common/build.ps1 -restore -build -binarylog -ci" + preSteps: [] + binlogPath: artifacts/log/Debug/Build.binlog + condition: '' + dependsOn: '' + pool: '' + is1ESPipeline: '' + +jobs: +- job: SourceIndexStage1 + dependsOn: ${{ parameters.dependsOn }} + condition: ${{ parameters.condition }} + variables: + - name: SourceIndexPackageVersion + value: ${{ parameters.sourceIndexPackageVersion }} + - name: SourceIndexPackageSource + value: ${{ parameters.sourceIndexPackageSource }} + - name: BinlogPath + value: ${{ parameters.binlogPath }} + - ${{ if and(eq(parameters.runAsPublic, 'false'), ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest')) }}: + - group: source-dot-net stage1 variables + - template: /eng/common/core-templates/variables/pool-providers.yml + parameters: + is1ESPipeline: ${{ parameters.is1ESPipeline }} + + ${{ if ne(parameters.pool, '') }}: + pool: ${{ parameters.pool }} + ${{ if eq(parameters.pool, '') }}: + pool: + ${{ if eq(variables['System.TeamProject'], 'public') }}: + name: $(DncEngPublicBuildPool) + image: windows.vs2022.amd64.open + ${{ if eq(variables['System.TeamProject'], 'internal') }}: + name: $(DncEngInternalBuildPool) + image: windows.vs2022.amd64 + + steps: + - ${{ if eq(parameters.is1ESPipeline, '') }}: + - 'Illegal entry point, is1ESPipeline is not defined. Repository yaml should not directly reference templates in core-templates folder.': error + + - ${{ each preStep in parameters.preSteps }}: + - ${{ preStep }} + + - task: UseDotNet@2 + displayName: Use .NET 8 SDK + inputs: + packageType: sdk + version: 8.0.x + installationPath: $(Agent.TempDirectory)/dotnet + workingDirectory: $(Agent.TempDirectory) + + - script: | + $(Agent.TempDirectory)/dotnet/dotnet tool install BinLogToSln --version $(SourceIndexPackageVersion) --add-source $(SourceIndexPackageSource) --tool-path $(Agent.TempDirectory)/.source-index/tools + $(Agent.TempDirectory)/dotnet/dotnet tool install UploadIndexStage1 --version $(SourceIndexPackageVersion) --add-source $(SourceIndexPackageSource) --tool-path $(Agent.TempDirectory)/.source-index/tools + displayName: Download Tools + # Set working directory to temp directory so 'dotnet' doesn't try to use global.json and use the repo's sdk. + workingDirectory: $(Agent.TempDirectory) + + - script: ${{ parameters.sourceIndexBuildCommand }} + displayName: Build Repository + + - script: $(Agent.TempDirectory)/.source-index/tools/BinLogToSln -i $(BinlogPath) -r $(Build.SourcesDirectory) -n $(Build.Repository.Name) -o .source-index/stage1output + displayName: Process Binlog into indexable sln + + - ${{ if and(eq(parameters.runAsPublic, 'false'), ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest')) }}: + - script: $(Agent.TempDirectory)/.source-index/tools/UploadIndexStage1 -i .source-index/stage1output -n $(Build.Repository.Name) + displayName: Upload stage1 artifacts to source index + env: + BLOB_CONTAINER_URL: $(source-dot-net-stage1-blob-container-url) diff --git a/eng/common/core-templates/jobs/codeql-build.yml b/eng/common/core-templates/jobs/codeql-build.yml new file mode 100644 index 00000000000000..f2144252cc65c8 --- /dev/null +++ b/eng/common/core-templates/jobs/codeql-build.yml @@ -0,0 +1,33 @@ +parameters: + # See schema documentation in /Documentation/AzureDevOps/TemplateSchema.md + continueOnError: false + # Required: A collection of jobs to run - https://docs.microsoft.com/en-us/azure/devops/pipelines/yaml-schema?view=vsts&tabs=schema#job + jobs: [] + # Optional: if specified, restore and use this version of Guardian instead of the default. + overrideGuardianVersion: '' + is1ESPipeline: '' + +jobs: +- template: /eng/common/core-templates/jobs/jobs.yml + parameters: + is1ESPipeline: ${{ parameters.is1ESPipeline }} + enableMicrobuild: false + enablePublishBuildArtifacts: false + enablePublishTestResults: false + enablePublishBuildAssets: false + enablePublishUsingPipelines: false + enableTelemetry: true + + variables: + - group: Publish-Build-Assets + # The Guardian version specified in 'eng/common/sdl/packages.config'. This value must be kept in + # sync with the packages.config file. + - name: DefaultGuardianVersion + value: 0.109.0 + - name: GuardianPackagesConfigFile + value: $(Build.SourcesDirectory)\eng\common\sdl\packages.config + - name: GuardianVersion + value: ${{ coalesce(parameters.overrideGuardianVersion, '$(DefaultGuardianVersion)') }} + + jobs: ${{ parameters.jobs }} + diff --git a/eng/common/core-templates/jobs/jobs.yml b/eng/common/core-templates/jobs/jobs.yml new file mode 100644 index 00000000000000..ea69be4341c62f --- /dev/null +++ b/eng/common/core-templates/jobs/jobs.yml @@ -0,0 +1,119 @@ +parameters: + # See schema documentation in /Documentation/AzureDevOps/TemplateSchema.md + continueOnError: false + + # Optional: Include PublishBuildArtifacts task + enablePublishBuildArtifacts: false + + # Optional: Enable publishing using release pipelines + enablePublishUsingPipelines: false + + # Optional: Enable running the source-build jobs to build repo from source + enableSourceBuild: false + + # Optional: Parameters for source-build template. + # See /eng/common/core-templates/jobs/source-build.yml for options + sourceBuildParameters: [] + + graphFileGeneration: + # Optional: Enable generating the graph files at the end of the build + enabled: false + # Optional: Include toolset dependencies in the generated graph files + includeToolset: false + + # Required: A collection of jobs to run - https://docs.microsoft.com/en-us/azure/devops/pipelines/yaml-schema?view=vsts&tabs=schema#job + jobs: [] + + # Optional: Override automatically derived dependsOn value for "publish build assets" job + publishBuildAssetsDependsOn: '' + + # Optional: Publish the assets as soon as the publish to BAR stage is complete, rather doing so in a separate stage. + publishAssetsImmediately: false + + # Optional: If using publishAssetsImmediately and additional parameters are needed, can be used to send along additional parameters (normally sent to post-build.yml) + artifactsPublishingAdditionalParameters: '' + signingValidationAdditionalParameters: '' + + # Optional: should run as a public build even in the internal project + # if 'true', the build won't run any of the internal only steps, even if it is running in non-public projects. + runAsPublic: false + + enableSourceIndex: false + sourceIndexParams: {} + + artifacts: {} + is1ESPipeline: '' + +# Internal resources (telemetry, microbuild) can only be accessed from non-public projects, +# and some (Microbuild) should only be applied to non-PR cases for internal builds. + +jobs: +- ${{ each job in parameters.jobs }}: + - ${{ if eq(parameters.is1ESPipeline, 'true') }}: + - template: /eng/common/templates-official/job/job.yml + parameters: + # pass along parameters + ${{ each parameter in parameters }}: + ${{ if ne(parameter.key, 'jobs') }}: + ${{ parameter.key }}: ${{ parameter.value }} + + # pass along job properties + ${{ each property in job }}: + ${{ if ne(property.key, 'job') }}: + ${{ property.key }}: ${{ property.value }} + + name: ${{ job.job }} + + - ${{ else }}: + - template: /eng/common/templates/job/job.yml + parameters: + # pass along parameters + ${{ each parameter in parameters }}: + ${{ if ne(parameter.key, 'jobs') }}: + ${{ parameter.key }}: ${{ parameter.value }} + + # pass along job properties + ${{ each property in job }}: + ${{ if ne(property.key, 'job') }}: + ${{ property.key }}: ${{ property.value }} + + name: ${{ job.job }} + +- ${{ if eq(parameters.enableSourceBuild, true) }}: + - template: /eng/common/core-templates/jobs/source-build.yml + parameters: + is1ESPipeline: ${{ parameters.is1ESPipeline }} + allCompletedJobId: Source_Build_Complete + ${{ each parameter in parameters.sourceBuildParameters }}: + ${{ parameter.key }}: ${{ parameter.value }} + +- ${{ if eq(parameters.enableSourceIndex, 'true') }}: + - template: ../job/source-index-stage1.yml + parameters: + is1ESPipeline: ${{ parameters.is1ESPipeline }} + runAsPublic: ${{ parameters.runAsPublic }} + ${{ each parameter in parameters.sourceIndexParams }}: + ${{ parameter.key }}: ${{ parameter.value }} + +- ${{ if and(eq(parameters.runAsPublic, 'false'), ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest')) }}: + - ${{ if or(eq(parameters.enablePublishBuildAssets, true), eq(parameters.artifacts.publish.manifests, 'true'), ne(parameters.artifacts.publish.manifests, '')) }}: + - template: ../job/publish-build-assets.yml + parameters: + is1ESPipeline: ${{ parameters.is1ESPipeline }} + continueOnError: ${{ parameters.continueOnError }} + dependsOn: + - ${{ if ne(parameters.publishBuildAssetsDependsOn, '') }}: + - ${{ each job in parameters.publishBuildAssetsDependsOn }}: + - ${{ job.job }} + - ${{ if eq(parameters.publishBuildAssetsDependsOn, '') }}: + - ${{ each job in parameters.jobs }}: + - ${{ job.job }} + - ${{ if eq(parameters.enableSourceBuild, true) }}: + - Source_Build_Complete + + runAsPublic: ${{ parameters.runAsPublic }} + publishUsingPipelines: ${{ parameters.enablePublishUsingPipelines }} + publishAssetsImmediately: ${{ parameters.publishAssetsImmediately }} + enablePublishBuildArtifacts: ${{ parameters.enablePublishBuildArtifacts }} + artifactsPublishingAdditionalParameters: ${{ parameters.artifactsPublishingAdditionalParameters }} + signingValidationAdditionalParameters: ${{ parameters.signingValidationAdditionalParameters }} diff --git a/eng/common/core-templates/jobs/source-build.yml b/eng/common/core-templates/jobs/source-build.yml new file mode 100644 index 00000000000000..d8e5d008522682 --- /dev/null +++ b/eng/common/core-templates/jobs/source-build.yml @@ -0,0 +1,50 @@ +parameters: + # This template adds arcade-powered source-build to CI. A job is created for each platform, as + # well as an optional server job that completes when all platform jobs complete. + + # The name of the "join" job for all source-build platforms. If set to empty string, the job is + # not included. Existing repo pipelines can use this job depend on all source-build jobs + # completing without maintaining a separate list of every single job ID: just depend on this one + # server job. By default, not included. Recommended name if used: 'Source_Build_Complete'. + allCompletedJobId: '' + + # See /eng/common/core-templates/job/source-build.yml + jobNamePrefix: 'Source_Build' + + # This is the default platform provided by Arcade, intended for use by a managed-only repo. + defaultManagedPlatform: + name: 'Managed' + container: 'mcr.microsoft.com/dotnet-buildtools/prereqs:centos-stream9' + + # Defines the platforms on which to run build jobs. One job is created for each platform, and the + # object in this array is sent to the job template as 'platform'. If no platforms are specified, + # one job runs on 'defaultManagedPlatform'. + platforms: [] + + is1ESPipeline: '' + +jobs: + +- ${{ if ne(parameters.allCompletedJobId, '') }}: + - job: ${{ parameters.allCompletedJobId }} + displayName: Source-Build Complete + pool: server + dependsOn: + - ${{ each platform in parameters.platforms }}: + - ${{ parameters.jobNamePrefix }}_${{ platform.name }} + - ${{ if eq(length(parameters.platforms), 0) }}: + - ${{ parameters.jobNamePrefix }}_${{ parameters.defaultManagedPlatform.name }} + +- ${{ each platform in parameters.platforms }}: + - template: /eng/common/core-templates/job/source-build.yml + parameters: + is1ESPipeline: ${{ parameters.is1ESPipeline }} + jobNamePrefix: ${{ parameters.jobNamePrefix }} + platform: ${{ platform }} + +- ${{ if eq(length(parameters.platforms), 0) }}: + - template: /eng/common/core-templates/job/source-build.yml + parameters: + is1ESPipeline: ${{ parameters.is1ESPipeline }} + jobNamePrefix: ${{ parameters.jobNamePrefix }} + platform: ${{ parameters.defaultManagedPlatform }} diff --git a/eng/common/core-templates/post-build/common-variables.yml b/eng/common/core-templates/post-build/common-variables.yml new file mode 100644 index 00000000000000..b9ede10bf099ae --- /dev/null +++ b/eng/common/core-templates/post-build/common-variables.yml @@ -0,0 +1,24 @@ +variables: + - group: Publish-Build-Assets + + # Whether the build is internal or not + - name: IsInternalBuild + value: ${{ and(ne(variables['System.TeamProject'], 'public'), contains(variables['Build.SourceBranch'], 'internal')) }} + + # Default Maestro++ API Endpoint and API Version + - name: MaestroApiEndPoint + value: "https://maestro.dot.net" + - name: MaestroApiAccessToken + value: $(MaestroAccessToken) + - name: MaestroApiVersion + value: "2020-02-20" + + - name: SourceLinkCLIVersion + value: 3.0.0 + - name: SymbolToolVersion + value: 1.0.1 + - name: BinlogToolVersion + value: 1.0.11 + + - name: runCodesignValidationInjection + value: false diff --git a/eng/common/core-templates/post-build/post-build.yml b/eng/common/core-templates/post-build/post-build.yml new file mode 100644 index 00000000000000..ed1e6692f739b2 --- /dev/null +++ b/eng/common/core-templates/post-build/post-build.yml @@ -0,0 +1,298 @@ +parameters: + # Which publishing infra should be used. THIS SHOULD MATCH THE VERSION ON THE BUILD MANIFEST. + # Publishing V1 is no longer supported + # Publishing V2 is no longer supported + # Publishing V3 is the default + - name: publishingInfraVersion + displayName: Which version of publishing should be used to promote the build definition? + type: number + default: 3 + values: + - 3 + + - name: BARBuildId + displayName: BAR Build Id + type: number + default: 0 + + - name: PromoteToChannelIds + displayName: Channel to promote BARBuildId to + type: string + default: '' + + - name: enableSourceLinkValidation + displayName: Enable SourceLink validation + type: boolean + default: false + + - name: enableSigningValidation + displayName: Enable signing validation + type: boolean + default: true + + - name: enableSymbolValidation + displayName: Enable symbol validation + type: boolean + default: false + + - name: enableNugetValidation + displayName: Enable NuGet validation + type: boolean + default: true + + - name: publishInstallersAndChecksums + displayName: Publish installers and checksums + type: boolean + default: true + + - name: SDLValidationParameters + type: object + default: + enable: false + publishGdn: false + continueOnError: false + params: '' + artifactNames: '' + downloadArtifacts: true + + # These parameters let the user customize the call to sdk-task.ps1 for publishing + # symbols & general artifacts as well as for signing validation + - name: symbolPublishingAdditionalParameters + displayName: Symbol publishing additional parameters + type: string + default: '' + + - name: artifactsPublishingAdditionalParameters + displayName: Artifact publishing additional parameters + type: string + default: '' + + - name: signingValidationAdditionalParameters + displayName: Signing validation additional parameters + type: string + default: '' + + # Which stages should finish execution before post-build stages start + - name: validateDependsOn + type: object + default: + - build + + - name: publishDependsOn + type: object + default: + - Validate + + # Optional: Call asset publishing rather than running in a separate stage + - name: publishAssetsImmediately + type: boolean + default: false + + - name: is1ESPipeline + type: boolean + default: false + +stages: +- ${{ if or(eq( parameters.enableNugetValidation, 'true'), eq(parameters.enableSigningValidation, 'true'), eq(parameters.enableSourceLinkValidation, 'true'), eq(parameters.SDLValidationParameters.enable, 'true')) }}: + - stage: Validate + dependsOn: ${{ parameters.validateDependsOn }} + displayName: Validate Build Assets + variables: + - template: /eng/common/core-templates/post-build/common-variables.yml + - template: /eng/common/core-templates/variables/pool-providers.yml + parameters: + is1ESPipeline: ${{ parameters.is1ESPipeline }} + jobs: + - job: + displayName: NuGet Validation + condition: and(succeededOrFailed(), eq( ${{ parameters.enableNugetValidation }}, 'true')) + pool: + # We don't use the collection uri here because it might vary (.visualstudio.com vs. dev.azure.com) + ${{ if eq(variables['System.TeamProject'], 'DevDiv') }}: + name: AzurePipelines-EO + image: 1ESPT-Windows2022 + demands: Cmd + os: windows + # If it's not devdiv, it's dnceng + ${{ else }}: + name: $(DncEngInternalBuildPool) + image: 1es-windows-2022 + os: windows + + steps: + - template: /eng/common/core-templates/post-build/setup-maestro-vars.yml + parameters: + BARBuildId: ${{ parameters.BARBuildId }} + PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }} + is1ESPipeline: ${{ parameters.is1ESPipeline }} + + - task: DownloadBuildArtifacts@0 + displayName: Download Package Artifacts + inputs: + buildType: specific + buildVersionToDownload: specific + project: $(AzDOProjectName) + pipeline: $(AzDOPipelineId) + buildId: $(AzDOBuildId) + artifactName: PackageArtifacts + checkDownloadedFiles: true + + - task: PowerShell@2 + displayName: Validate + inputs: + filePath: $(Build.SourcesDirectory)/eng/common/post-build/nuget-validation.ps1 + arguments: -PackagesPath $(Build.ArtifactStagingDirectory)/PackageArtifacts/ + -ToolDestinationPath $(Agent.BuildDirectory)/Extract/ + + - job: + displayName: Signing Validation + condition: and( eq( ${{ parameters.enableSigningValidation }}, 'true'), ne( variables['PostBuildSign'], 'true')) + pool: + # We don't use the collection uri here because it might vary (.visualstudio.com vs. dev.azure.com) + ${{ if eq(variables['System.TeamProject'], 'DevDiv') }}: + name: AzurePipelines-EO + image: 1ESPT-Windows2022 + demands: Cmd + os: windows + # If it's not devdiv, it's dnceng + ${{ else }}: + name: $(DncEngInternalBuildPool) + image: 1es-windows-2022 + os: windows + steps: + - template: /eng/common/core-templates/post-build/setup-maestro-vars.yml + parameters: + BARBuildId: ${{ parameters.BARBuildId }} + PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }} + is1ESPipeline: ${{ parameters.is1ESPipeline }} + + - task: DownloadBuildArtifacts@0 + displayName: Download Package Artifacts + inputs: + buildType: specific + buildVersionToDownload: specific + project: $(AzDOProjectName) + pipeline: $(AzDOPipelineId) + buildId: $(AzDOBuildId) + artifactName: PackageArtifacts + checkDownloadedFiles: true + itemPattern: | + ** + !**/Microsoft.SourceBuild.Intermediate.*.nupkg + + # This is necessary whenever we want to publish/restore to an AzDO private feed + # Since sdk-task.ps1 tries to restore packages we need to do this authentication here + # otherwise it'll complain about accessing a private feed. + - task: NuGetAuthenticate@1 + displayName: 'Authenticate to AzDO Feeds' + + # Signing validation will optionally work with the buildmanifest file which is downloaded from + # Azure DevOps above. + - task: PowerShell@2 + displayName: Validate + inputs: + filePath: eng\common\sdk-task.ps1 + arguments: -task SigningValidation -restore -msbuildEngine vs + /p:PackageBasePath='$(Build.ArtifactStagingDirectory)/PackageArtifacts' + /p:SignCheckExclusionsFile='$(Build.SourcesDirectory)/eng/SignCheckExclusionsFile.txt' + ${{ parameters.signingValidationAdditionalParameters }} + + - template: /eng/common/core-templates/steps/publish-logs.yml + parameters: + is1ESPipeline: ${{ parameters.is1ESPipeline }} + StageLabel: 'Validation' + JobLabel: 'Signing' + BinlogToolVersion: $(BinlogToolVersion) + + - job: + displayName: SourceLink Validation + condition: eq( ${{ parameters.enableSourceLinkValidation }}, 'true') + pool: + # We don't use the collection uri here because it might vary (.visualstudio.com vs. dev.azure.com) + ${{ if eq(variables['System.TeamProject'], 'DevDiv') }}: + name: AzurePipelines-EO + image: 1ESPT-Windows2022 + demands: Cmd + os: windows + # If it's not devdiv, it's dnceng + ${{ else }}: + name: $(DncEngInternalBuildPool) + image: 1es-windows-2022 + os: windows + steps: + - template: /eng/common/core-templates/post-build/setup-maestro-vars.yml + parameters: + BARBuildId: ${{ parameters.BARBuildId }} + PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }} + is1ESPipeline: ${{ parameters.is1ESPipeline }} + + - task: DownloadBuildArtifacts@0 + displayName: Download Blob Artifacts + inputs: + buildType: specific + buildVersionToDownload: specific + project: $(AzDOProjectName) + pipeline: $(AzDOPipelineId) + buildId: $(AzDOBuildId) + artifactName: BlobArtifacts + checkDownloadedFiles: true + + - task: PowerShell@2 + displayName: Validate + inputs: + filePath: $(Build.SourcesDirectory)/eng/common/post-build/sourcelink-validation.ps1 + arguments: -InputPath $(Build.ArtifactStagingDirectory)/BlobArtifacts/ + -ExtractPath $(Agent.BuildDirectory)/Extract/ + -GHRepoName $(Build.Repository.Name) + -GHCommit $(Build.SourceVersion) + -SourcelinkCliVersion $(SourceLinkCLIVersion) + continueOnError: true + +- ${{ if ne(parameters.publishAssetsImmediately, 'true') }}: + - stage: publish_using_darc + ${{ if or(eq(parameters.enableNugetValidation, 'true'), eq(parameters.enableSigningValidation, 'true'), eq(parameters.enableSourceLinkValidation, 'true'), eq(parameters.SDLValidationParameters.enable, 'true')) }}: + dependsOn: ${{ parameters.publishDependsOn }} + ${{ else }}: + dependsOn: ${{ parameters.validateDependsOn }} + displayName: Publish using Darc + variables: + - template: /eng/common/core-templates/post-build/common-variables.yml + - template: /eng/common/core-templates/variables/pool-providers.yml + parameters: + is1ESPipeline: ${{ parameters.is1ESPipeline }} + jobs: + - job: + displayName: Publish Using Darc + timeoutInMinutes: 120 + pool: + # We don't use the collection uri here because it might vary (.visualstudio.com vs. dev.azure.com) + ${{ if eq(variables['System.TeamProject'], 'DevDiv') }}: + name: AzurePipelines-EO + image: 1ESPT-Windows2022 + demands: Cmd + os: windows + # If it's not devdiv, it's dnceng + ${{ else }}: + name: NetCore1ESPool-Publishing-Internal + image: windows.vs2019.amd64 + os: windows + steps: + - template: /eng/common/core-templates/post-build/setup-maestro-vars.yml + parameters: + BARBuildId: ${{ parameters.BARBuildId }} + PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }} + is1ESPipeline: ${{ parameters.is1ESPipeline }} + + - task: NuGetAuthenticate@1 + + - task: PowerShell@2 + displayName: Publish Using Darc + inputs: + filePath: $(Build.SourcesDirectory)/eng/common/post-build/publish-using-darc.ps1 + arguments: -BuildId $(BARBuildId) + -PublishingInfraVersion ${{ parameters.publishingInfraVersion }} + -AzdoToken '$(publishing-dnceng-devdiv-code-r-build-re)' + -MaestroToken '$(MaestroApiAccessToken)' + -WaitPublishingFinish true + -ArtifactsPublishingAdditionalParameters '${{ parameters.artifactsPublishingAdditionalParameters }}' + -SymbolPublishingAdditionalParameters '${{ parameters.symbolPublishingAdditionalParameters }}' diff --git a/eng/common/core-templates/post-build/setup-maestro-vars.yml b/eng/common/core-templates/post-build/setup-maestro-vars.yml new file mode 100644 index 00000000000000..8d56b5726793f8 --- /dev/null +++ b/eng/common/core-templates/post-build/setup-maestro-vars.yml @@ -0,0 +1,74 @@ +parameters: + BARBuildId: '' + PromoteToChannelIds: '' + is1ESPipeline: '' + +steps: + - ${{ if eq(parameters.is1ESPipeline, '') }}: + - 'Illegal entry point, is1ESPipeline is not defined. Repository yaml should not directly reference templates in core-templates folder.': error + + - ${{ if eq(coalesce(parameters.PromoteToChannelIds, 0), 0) }}: + - task: DownloadBuildArtifacts@0 + displayName: Download Release Configs + inputs: + buildType: current + artifactName: ReleaseConfigs + checkDownloadedFiles: true + + - task: PowerShell@2 + name: setReleaseVars + displayName: Set Release Configs Vars + inputs: + targetType: inline + pwsh: true + script: | + try { + if (!$Env:PromoteToMaestroChannels -or $Env:PromoteToMaestroChannels.Trim() -eq '') { + $Content = Get-Content $(Build.StagingDirectory)/ReleaseConfigs/ReleaseConfigs.txt + + $BarId = $Content | Select -Index 0 + $Channels = $Content | Select -Index 1 + $IsStableBuild = $Content | Select -Index 2 + + $AzureDevOpsProject = $Env:System_TeamProject + $AzureDevOpsBuildDefinitionId = $Env:System_DefinitionId + $AzureDevOpsBuildId = $Env:Build_BuildId + } + else { + $buildApiEndpoint = "${Env:MaestroApiEndPoint}/api/builds/${Env:BARBuildId}?api-version=${Env:MaestroApiVersion}" + + $apiHeaders = New-Object 'System.Collections.Generic.Dictionary[[String],[String]]' + $apiHeaders.Add('Accept', 'application/json') + $apiHeaders.Add('Authorization',"Bearer ${Env:MAESTRO_API_TOKEN}") + + $buildInfo = try { Invoke-WebRequest -Method Get -Uri $buildApiEndpoint -Headers $apiHeaders | ConvertFrom-Json } catch { Write-Host "Error: $_" } + + $BarId = $Env:BARBuildId + $Channels = $Env:PromoteToMaestroChannels -split "," + $Channels = $Channels -join "][" + $Channels = "[$Channels]" + + $IsStableBuild = $buildInfo.stable + $AzureDevOpsProject = $buildInfo.azureDevOpsProject + $AzureDevOpsBuildDefinitionId = $buildInfo.azureDevOpsBuildDefinitionId + $AzureDevOpsBuildId = $buildInfo.azureDevOpsBuildId + } + + Write-Host "##vso[task.setvariable variable=BARBuildId]$BarId" + Write-Host "##vso[task.setvariable variable=TargetChannels]$Channels" + Write-Host "##vso[task.setvariable variable=IsStableBuild]$IsStableBuild" + + Write-Host "##vso[task.setvariable variable=AzDOProjectName]$AzureDevOpsProject" + Write-Host "##vso[task.setvariable variable=AzDOPipelineId]$AzureDevOpsBuildDefinitionId" + Write-Host "##vso[task.setvariable variable=AzDOBuildId]$AzureDevOpsBuildId" + } + catch { + Write-Host $_ + Write-Host $_.Exception + Write-Host $_.ScriptStackTrace + exit 1 + } + env: + MAESTRO_API_TOKEN: $(MaestroApiAccessToken) + BARBuildId: ${{ parameters.BARBuildId }} + PromoteToMaestroChannels: ${{ parameters.PromoteToChannelIds }} diff --git a/eng/common/core-templates/post-build/trigger-subscription.yml b/eng/common/core-templates/post-build/trigger-subscription.yml new file mode 100644 index 00000000000000..da669030daf6e9 --- /dev/null +++ b/eng/common/core-templates/post-build/trigger-subscription.yml @@ -0,0 +1,13 @@ +parameters: + ChannelId: 0 + +steps: +- task: PowerShell@2 + displayName: Triggering subscriptions + inputs: + filePath: $(Build.SourcesDirectory)/eng/common/post-build/trigger-subscriptions.ps1 + arguments: -SourceRepo $(Build.Repository.Uri) + -ChannelId ${{ parameters.ChannelId }} + -MaestroApiAccessToken $(MaestroAccessToken) + -MaestroApiEndPoint $(MaestroApiEndPoint) + -MaestroApiVersion $(MaestroApiVersion) diff --git a/eng/common/core-templates/steps/add-build-to-channel.yml b/eng/common/core-templates/steps/add-build-to-channel.yml new file mode 100644 index 00000000000000..f67a210d62f3e5 --- /dev/null +++ b/eng/common/core-templates/steps/add-build-to-channel.yml @@ -0,0 +1,13 @@ +parameters: + ChannelId: 0 + +steps: +- task: PowerShell@2 + displayName: Add Build to Channel + inputs: + filePath: $(Build.SourcesDirectory)/eng/common/post-build/add-build-to-channel.ps1 + arguments: -BuildId $(BARBuildId) + -ChannelId ${{ parameters.ChannelId }} + -MaestroApiAccessToken $(MaestroApiAccessToken) + -MaestroApiEndPoint $(MaestroApiEndPoint) + -MaestroApiVersion $(MaestroApiVersion) diff --git a/eng/common/core-templates/steps/component-governance.yml b/eng/common/core-templates/steps/component-governance.yml new file mode 100644 index 00000000000000..df449a34c11207 --- /dev/null +++ b/eng/common/core-templates/steps/component-governance.yml @@ -0,0 +1,14 @@ +parameters: + disableComponentGovernance: false + componentGovernanceIgnoreDirectories: '' + is1ESPipeline: false + +steps: +- ${{ if eq(parameters.disableComponentGovernance, 'true') }}: + - script: echo "##vso[task.setvariable variable=skipComponentGovernanceDetection]true" + displayName: Set skipComponentGovernanceDetection variable +- ${{ if ne(parameters.disableComponentGovernance, 'true') }}: + - task: ComponentGovernanceComponentDetection@0 + continueOnError: true + inputs: + ignoreDirectories: ${{ parameters.componentGovernanceIgnoreDirectories }} \ No newline at end of file diff --git a/eng/common/core-templates/steps/generate-sbom.yml b/eng/common/core-templates/steps/generate-sbom.yml new file mode 100644 index 00000000000000..d938b60e1bb534 --- /dev/null +++ b/eng/common/core-templates/steps/generate-sbom.yml @@ -0,0 +1,54 @@ +# BuildDropPath - The root folder of the drop directory for which the manifest file will be generated. +# PackageName - The name of the package this SBOM represents. +# PackageVersion - The version of the package this SBOM represents. +# ManifestDirPath - The path of the directory where the generated manifest files will be placed +# IgnoreDirectories - Directories to ignore for SBOM generation. This will be passed through to the CG component detector. + +parameters: + PackageVersion: 9.0.0 + BuildDropPath: '$(Build.SourcesDirectory)/artifacts' + PackageName: '.NET' + ManifestDirPath: $(Build.ArtifactStagingDirectory)/sbom + IgnoreDirectories: '' + sbomContinueOnError: true + is1ESPipeline: false + # disable publishArtifacts if some other step is publishing the artifacts (like job.yml). + publishArtifacts: true + +steps: +- task: PowerShell@2 + displayName: Prep for SBOM generation in (Non-linux) + condition: or(eq(variables['Agent.Os'], 'Windows_NT'), eq(variables['Agent.Os'], 'Darwin')) + inputs: + filePath: ./eng/common/generate-sbom-prep.ps1 + arguments: ${{parameters.manifestDirPath}} + +# Chmodding is a workaround for https://github.com/dotnet/arcade/issues/8461 +- script: | + chmod +x ./eng/common/generate-sbom-prep.sh + ./eng/common/generate-sbom-prep.sh ${{parameters.manifestDirPath}} + displayName: Prep for SBOM generation in (Linux) + condition: eq(variables['Agent.Os'], 'Linux') + continueOnError: ${{ parameters.sbomContinueOnError }} + +- task: AzureArtifacts.manifest-generator-task.manifest-generator-task.ManifestGeneratorTask@0 + displayName: 'Generate SBOM manifest' + continueOnError: ${{ parameters.sbomContinueOnError }} + inputs: + PackageName: ${{ parameters.packageName }} + BuildDropPath: ${{ parameters.buildDropPath }} + PackageVersion: ${{ parameters.packageVersion }} + ManifestDirPath: ${{ parameters.manifestDirPath }} + ${{ if ne(parameters.IgnoreDirectories, '') }}: + AdditionalComponentDetectorArgs: '--IgnoreDirectories ${{ parameters.IgnoreDirectories }}' + +- ${{ if eq(parameters.publishArtifacts, 'true')}}: + - template: /eng/common/core-templates/steps/publish-pipeline-artifacts.yml + parameters: + is1ESPipeline: ${{ parameters.is1ESPipeline }} + args: + displayName: Publish SBOM manifest + continueOnError: ${{parameters.sbomContinueOnError}} + targetPath: '${{ parameters.manifestDirPath }}' + artifactName: $(ARTIFACT_NAME) + diff --git a/eng/common/core-templates/steps/publish-build-artifacts.yml b/eng/common/core-templates/steps/publish-build-artifacts.yml new file mode 100644 index 00000000000000..f24ce346684e60 --- /dev/null +++ b/eng/common/core-templates/steps/publish-build-artifacts.yml @@ -0,0 +1,20 @@ +parameters: +- name: is1ESPipeline + type: boolean + default: false +- name: args + type: object + default: {} +steps: +- ${{ if ne(parameters.is1ESPipeline, true) }}: + - template: /eng/common/templates/steps/publish-build-artifacts.yml + parameters: + is1ESPipeline: ${{ parameters.is1ESPipeline }} + ${{ each parameter in parameters.args }}: + ${{ parameter.key }}: ${{ parameter.value }} +- ${{ else }}: + - template: /eng/common/templates-official/steps/publish-build-artifacts.yml + parameters: + is1ESPipeline: ${{ parameters.is1ESPipeline }} + ${{ each parameter in parameters.args }}: + ${{ parameter.key }}: ${{ parameter.value }} \ No newline at end of file diff --git a/eng/common/core-templates/steps/publish-logs.yml b/eng/common/core-templates/steps/publish-logs.yml new file mode 100644 index 00000000000000..8c5ea77b586d27 --- /dev/null +++ b/eng/common/core-templates/steps/publish-logs.yml @@ -0,0 +1,59 @@ +parameters: + StageLabel: '' + JobLabel: '' + CustomSensitiveDataList: '' + # A default - in case value from eng/common/core-templates/post-build/common-variables.yml is not passed + BinlogToolVersion: '1.0.11' + is1ESPipeline: false + +steps: +- task: Powershell@2 + displayName: Prepare Binlogs to Upload + inputs: + targetType: inline + script: | + New-Item -ItemType Directory $(Build.SourcesDirectory)/PostBuildLogs/${{parameters.StageLabel}}/${{parameters.JobLabel}}/ + Move-Item -Path $(Build.SourcesDirectory)/artifacts/log/Debug/* $(Build.SourcesDirectory)/PostBuildLogs/${{parameters.StageLabel}}/${{parameters.JobLabel}}/ + continueOnError: true + condition: always() + +- task: PowerShell@2 + displayName: Redact Logs + inputs: + filePath: $(Build.SourcesDirectory)/eng/common/post-build/redact-logs.ps1 + # For now this needs to have explicit list of all sensitive data. Taken from eng/publishing/v3/publish.yml + # Sensitive data can as well be added to $(Build.SourcesDirectory)/eng/BinlogSecretsRedactionFile.txt' + # If the file exists - sensitive data for redaction will be sourced from it + # (single entry per line, lines starting with '# ' are considered comments and skipped) + arguments: -InputPath '$(Build.SourcesDirectory)/PostBuildLogs' + -BinlogToolVersion ${{parameters.BinlogToolVersion}} + -TokensFilePath '$(Build.SourcesDirectory)/eng/BinlogSecretsRedactionFile.txt' + '$(publishing-dnceng-devdiv-code-r-build-re)' + '$(MaestroAccessToken)' + '$(dn-bot-all-orgs-artifact-feeds-rw)' + '$(akams-client-id)' + '$(akams-client-secret)' + '$(microsoft-symbol-server-pat)' + '$(symweb-symbol-server-pat)' + '$(dn-bot-all-orgs-build-rw-code-rw)' + ${{parameters.CustomSensitiveDataList}} + continueOnError: true + condition: always() + +- task: CopyFiles@2 + displayName: Gather post build logs + inputs: + SourceFolder: '$(Build.SourcesDirectory)/PostBuildLogs' + Contents: '**' + TargetFolder: '$(Build.ArtifactStagingDirectory)/PostBuildLogs' + +- template: /eng/common/core-templates/steps/publish-build-artifacts.yml + parameters: + is1ESPipeline: ${{ parameters.is1ESPipeline }} + args: + displayName: Publish Logs + pathToPublish: '$(Build.ArtifactStagingDirectory)/PostBuildLogs' + publishLocation: Container + artifactName: PostBuildLogs + continueOnError: true + condition: always() diff --git a/eng/common/core-templates/steps/publish-pipeline-artifacts.yml b/eng/common/core-templates/steps/publish-pipeline-artifacts.yml new file mode 100644 index 00000000000000..2efec04dc2c163 --- /dev/null +++ b/eng/common/core-templates/steps/publish-pipeline-artifacts.yml @@ -0,0 +1,20 @@ +parameters: +- name: is1ESPipeline + type: boolean + default: false + +- name: args + type: object + default: {} + +steps: +- ${{ if ne(parameters.is1ESPipeline, true) }}: + - template: /eng/common/templates/steps/publish-pipeline-artifacts.yml + parameters: + ${{ each parameter in parameters }}: + ${{ parameter.key }}: ${{ parameter.value }} +- ${{ else }}: + - template: /eng/common/templates-official/steps/publish-pipeline-artifacts.yml + parameters: + ${{ each parameter in parameters }}: + ${{ parameter.key }}: ${{ parameter.value }} diff --git a/eng/common/core-templates/steps/retain-build.yml b/eng/common/core-templates/steps/retain-build.yml new file mode 100644 index 00000000000000..83d97a26a01ff9 --- /dev/null +++ b/eng/common/core-templates/steps/retain-build.yml @@ -0,0 +1,28 @@ +parameters: + # Optional azure devops PAT with build execute permissions for the build's organization, + # only needed if the build that should be retained ran on a different organization than + # the pipeline where this template is executing from + Token: '' + # Optional BuildId to retain, defaults to the current running build + BuildId: '' + # Azure devops Organization URI for the build in the https://dev.azure.com/ format. + # Defaults to the organization the current pipeline is running on + AzdoOrgUri: '$(System.CollectionUri)' + # Azure devops project for the build. Defaults to the project the current pipeline is running on + AzdoProject: '$(System.TeamProject)' + +steps: + - task: powershell@2 + inputs: + targetType: 'filePath' + filePath: eng/common/retain-build.ps1 + pwsh: true + arguments: > + -AzdoOrgUri: ${{parameters.AzdoOrgUri}} + -AzdoProject ${{parameters.AzdoProject}} + -Token ${{coalesce(parameters.Token, '$env:SYSTEM_ACCESSTOKEN') }} + -BuildId ${{coalesce(parameters.BuildId, '$env:BUILD_ID')}} + displayName: Enable permanent build retention + env: + SYSTEM_ACCESSTOKEN: $(System.AccessToken) + BUILD_ID: $(Build.BuildId) \ No newline at end of file diff --git a/eng/common/core-templates/steps/send-to-helix.yml b/eng/common/core-templates/steps/send-to-helix.yml new file mode 100644 index 00000000000000..68fa739c4ab215 --- /dev/null +++ b/eng/common/core-templates/steps/send-to-helix.yml @@ -0,0 +1,93 @@ +# Please remember to update the documentation if you make changes to these parameters! +parameters: + HelixSource: 'pr/default' # required -- sources must start with pr/, official/, prodcon/, or agent/ + HelixType: 'tests/default/' # required -- Helix telemetry which identifies what type of data this is; should include "test" for clarity and must end in '/' + HelixBuild: $(Build.BuildNumber) # required -- the build number Helix will use to identify this -- automatically set to the AzDO build number + HelixTargetQueues: '' # required -- semicolon-delimited list of Helix queues to test on; see https://helix.dot.net/ for a list of queues + HelixAccessToken: '' # required -- access token to make Helix API requests; should be provided by the appropriate variable group + HelixProjectPath: 'eng/common/helixpublish.proj' # optional -- path to the project file to build relative to BUILD_SOURCESDIRECTORY + HelixProjectArguments: '' # optional -- arguments passed to the build command + HelixConfiguration: '' # optional -- additional property attached to a job + HelixPreCommands: '' # optional -- commands to run before Helix work item execution + HelixPostCommands: '' # optional -- commands to run after Helix work item execution + WorkItemDirectory: '' # optional -- a payload directory to zip up and send to Helix; requires WorkItemCommand; incompatible with XUnitProjects + WorkItemCommand: '' # optional -- a command to execute on the payload; requires WorkItemDirectory; incompatible with XUnitProjects + WorkItemTimeout: '' # optional -- a timeout in TimeSpan.Parse-ready value (e.g. 00:02:00) for the work item command; requires WorkItemDirectory; incompatible with XUnitProjects + CorrelationPayloadDirectory: '' # optional -- a directory to zip up and send to Helix as a correlation payload + XUnitProjects: '' # optional -- semicolon-delimited list of XUnitProjects to parse and send to Helix; requires XUnitRuntimeTargetFramework, XUnitPublishTargetFramework, XUnitRunnerVersion, and IncludeDotNetCli=true + XUnitWorkItemTimeout: '' # optional -- the workitem timeout in seconds for all workitems created from the xUnit projects specified by XUnitProjects + XUnitPublishTargetFramework: '' # optional -- framework to use to publish your xUnit projects + XUnitRuntimeTargetFramework: '' # optional -- framework to use for the xUnit console runner + XUnitRunnerVersion: '' # optional -- version of the xUnit nuget package you wish to use on Helix; required for XUnitProjects + IncludeDotNetCli: false # optional -- true will download a version of the .NET CLI onto the Helix machine as a correlation payload; requires DotNetCliPackageType and DotNetCliVersion + DotNetCliPackageType: '' # optional -- either 'sdk', 'runtime' or 'aspnetcore-runtime'; determines whether the sdk or runtime will be sent to Helix; see https://raw.githubusercontent.com/dotnet/core/main/release-notes/releases-index.json + DotNetCliVersion: '' # optional -- version of the CLI to send to Helix; based on this: https://raw.githubusercontent.com/dotnet/core/main/release-notes/releases-index.json + WaitForWorkItemCompletion: true # optional -- true will make the task wait until work items have been completed and fail the build if work items fail. False is "fire and forget." + IsExternal: false # [DEPRECATED] -- doesn't do anything, jobs are external if HelixAccessToken is empty and Creator is set + HelixBaseUri: 'https://helix.dot.net/' # optional -- sets the Helix API base URI (allows targeting https://helix.int-dot.net ) + Creator: '' # optional -- if the build is external, use this to specify who is sending the job + DisplayNamePrefix: 'Run Tests' # optional -- rename the beginning of the displayName of the steps in AzDO + condition: succeeded() # optional -- condition for step to execute; defaults to succeeded() + continueOnError: false # optional -- determines whether to continue the build if the step errors; defaults to false + +steps: + - powershell: 'powershell "$env:BUILD_SOURCESDIRECTORY\eng\common\msbuild.ps1 $env:BUILD_SOURCESDIRECTORY/${{ parameters.HelixProjectPath }} /restore /p:TreatWarningsAsErrors=false ${{ parameters.HelixProjectArguments }} /t:Test /bl:$env:BUILD_SOURCESDIRECTORY\artifacts\log\$env:BuildConfig\SendToHelix.binlog"' + displayName: ${{ parameters.DisplayNamePrefix }} (Windows) + env: + BuildConfig: $(_BuildConfig) + HelixSource: ${{ parameters.HelixSource }} + HelixType: ${{ parameters.HelixType }} + HelixBuild: ${{ parameters.HelixBuild }} + HelixConfiguration: ${{ parameters.HelixConfiguration }} + HelixTargetQueues: ${{ parameters.HelixTargetQueues }} + HelixAccessToken: ${{ parameters.HelixAccessToken }} + HelixPreCommands: ${{ parameters.HelixPreCommands }} + HelixPostCommands: ${{ parameters.HelixPostCommands }} + WorkItemDirectory: ${{ parameters.WorkItemDirectory }} + WorkItemCommand: ${{ parameters.WorkItemCommand }} + WorkItemTimeout: ${{ parameters.WorkItemTimeout }} + CorrelationPayloadDirectory: ${{ parameters.CorrelationPayloadDirectory }} + XUnitProjects: ${{ parameters.XUnitProjects }} + XUnitWorkItemTimeout: ${{ parameters.XUnitWorkItemTimeout }} + XUnitPublishTargetFramework: ${{ parameters.XUnitPublishTargetFramework }} + XUnitRuntimeTargetFramework: ${{ parameters.XUnitRuntimeTargetFramework }} + XUnitRunnerVersion: ${{ parameters.XUnitRunnerVersion }} + IncludeDotNetCli: ${{ parameters.IncludeDotNetCli }} + DotNetCliPackageType: ${{ parameters.DotNetCliPackageType }} + DotNetCliVersion: ${{ parameters.DotNetCliVersion }} + WaitForWorkItemCompletion: ${{ parameters.WaitForWorkItemCompletion }} + HelixBaseUri: ${{ parameters.HelixBaseUri }} + Creator: ${{ parameters.Creator }} + SYSTEM_ACCESSTOKEN: $(System.AccessToken) + condition: and(${{ parameters.condition }}, eq(variables['Agent.Os'], 'Windows_NT')) + continueOnError: ${{ parameters.continueOnError }} + - script: $BUILD_SOURCESDIRECTORY/eng/common/msbuild.sh $BUILD_SOURCESDIRECTORY/${{ parameters.HelixProjectPath }} /restore /p:TreatWarningsAsErrors=false ${{ parameters.HelixProjectArguments }} /t:Test /bl:$BUILD_SOURCESDIRECTORY/artifacts/log/$BuildConfig/SendToHelix.binlog + displayName: ${{ parameters.DisplayNamePrefix }} (Unix) + env: + BuildConfig: $(_BuildConfig) + HelixSource: ${{ parameters.HelixSource }} + HelixType: ${{ parameters.HelixType }} + HelixBuild: ${{ parameters.HelixBuild }} + HelixConfiguration: ${{ parameters.HelixConfiguration }} + HelixTargetQueues: ${{ parameters.HelixTargetQueues }} + HelixAccessToken: ${{ parameters.HelixAccessToken }} + HelixPreCommands: ${{ parameters.HelixPreCommands }} + HelixPostCommands: ${{ parameters.HelixPostCommands }} + WorkItemDirectory: ${{ parameters.WorkItemDirectory }} + WorkItemCommand: ${{ parameters.WorkItemCommand }} + WorkItemTimeout: ${{ parameters.WorkItemTimeout }} + CorrelationPayloadDirectory: ${{ parameters.CorrelationPayloadDirectory }} + XUnitProjects: ${{ parameters.XUnitProjects }} + XUnitWorkItemTimeout: ${{ parameters.XUnitWorkItemTimeout }} + XUnitPublishTargetFramework: ${{ parameters.XUnitPublishTargetFramework }} + XUnitRuntimeTargetFramework: ${{ parameters.XUnitRuntimeTargetFramework }} + XUnitRunnerVersion: ${{ parameters.XUnitRunnerVersion }} + IncludeDotNetCli: ${{ parameters.IncludeDotNetCli }} + DotNetCliPackageType: ${{ parameters.DotNetCliPackageType }} + DotNetCliVersion: ${{ parameters.DotNetCliVersion }} + WaitForWorkItemCompletion: ${{ parameters.WaitForWorkItemCompletion }} + HelixBaseUri: ${{ parameters.HelixBaseUri }} + Creator: ${{ parameters.Creator }} + SYSTEM_ACCESSTOKEN: $(System.AccessToken) + condition: and(${{ parameters.condition }}, ne(variables['Agent.Os'], 'Windows_NT')) + continueOnError: ${{ parameters.continueOnError }} diff --git a/eng/common/core-templates/steps/source-build.yml b/eng/common/core-templates/steps/source-build.yml new file mode 100644 index 00000000000000..bdd725b496f91b --- /dev/null +++ b/eng/common/core-templates/steps/source-build.yml @@ -0,0 +1,134 @@ +parameters: + # This template adds arcade-powered source-build to CI. + + # This is a 'steps' template, and is intended for advanced scenarios where the existing build + # infra has a careful build methodology that must be followed. For example, a repo + # (dotnet/runtime) might choose to clone the GitHub repo only once and store it as a pipeline + # artifact for all subsequent jobs to use, to reduce dependence on a strong network connection to + # GitHub. Using this steps template leaves room for that infra to be included. + + # Defines the platform on which to run the steps. See 'eng/common/core-templates/job/source-build.yml' + # for details. The entire object is described in the 'job' template for simplicity, even though + # the usage of the properties on this object is split between the 'job' and 'steps' templates. + platform: {} + is1ESPipeline: false + +steps: +# Build. Keep it self-contained for simple reusability. (No source-build-specific job variables.) +- script: | + set -x + df -h + + # If building on the internal project, the artifact feeds variable may be available (usually only if needed) + # In that case, call the feed setup script to add internal feeds corresponding to public ones. + # In addition, add an msbuild argument to copy the WIP from the repo to the target build location. + # This is because SetupNuGetSources.sh will alter the current NuGet.config file, and we need to preserve those + # changes. + internalRestoreArgs= + if [ '$(dn-bot-dnceng-artifact-feeds-rw)' != '$''(dn-bot-dnceng-artifact-feeds-rw)' ]; then + # Temporarily work around https://github.com/dotnet/arcade/issues/7709 + chmod +x $(Build.SourcesDirectory)/eng/common/SetupNugetSources.sh + $(Build.SourcesDirectory)/eng/common/SetupNugetSources.sh $(Build.SourcesDirectory)/NuGet.config $(dn-bot-dnceng-artifact-feeds-rw) + internalRestoreArgs='/p:CopyWipIntoInnerSourceBuildRepo=true' + + # The 'Copy WIP' feature of source build uses git stash to apply changes from the original repo. + # This only works if there is a username/email configured, which won't be the case in most CI runs. + git config --get user.email + if [ $? -ne 0 ]; then + git config user.email dn-bot@microsoft.com + git config user.name dn-bot + fi + fi + + # If building on the internal project, the internal storage variable may be available (usually only if needed) + # In that case, add variables to allow the download of internal runtimes if the specified versions are not found + # in the default public locations. + internalRuntimeDownloadArgs= + if [ '$(dotnetbuilds-internal-container-read-token-base64)' != '$''(dotnetbuilds-internal-container-read-token-base64)' ]; then + internalRuntimeDownloadArgs='/p:DotNetRuntimeSourceFeed=https://dotnetbuilds.blob.core.windows.net/internal /p:DotNetRuntimeSourceFeedKey=$(dotnetbuilds-internal-container-read-token-base64) --runtimesourcefeed https://dotnetbuilds.blob.core.windows.net/internal --runtimesourcefeedkey $(dotnetbuilds-internal-container-read-token-base64)' + fi + + buildConfig=Release + # Check if AzDO substitutes in a build config from a variable, and use it if so. + if [ '$(_BuildConfig)' != '$''(_BuildConfig)' ]; then + buildConfig='$(_BuildConfig)' + fi + + officialBuildArgs= + if [ '${{ and(ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest')) }}' = 'True' ]; then + officialBuildArgs='/p:DotNetPublishUsingPipelines=true /p:OfficialBuildId=$(BUILD.BUILDNUMBER)' + fi + + targetRidArgs= + if [ '${{ parameters.platform.targetRID }}' != '' ]; then + targetRidArgs='/p:TargetRid=${{ parameters.platform.targetRID }}' + fi + + runtimeOsArgs= + if [ '${{ parameters.platform.runtimeOS }}' != '' ]; then + runtimeOsArgs='/p:RuntimeOS=${{ parameters.platform.runtimeOS }}' + fi + + baseOsArgs= + if [ '${{ parameters.platform.baseOS }}' != '' ]; then + baseOsArgs='/p:BaseOS=${{ parameters.platform.baseOS }}' + fi + + publishArgs= + if [ '${{ parameters.platform.skipPublishValidation }}' != 'true' ]; then + publishArgs='--publish' + fi + + assetManifestFileName=SourceBuild_RidSpecific.xml + if [ '${{ parameters.platform.name }}' != '' ]; then + assetManifestFileName=SourceBuild_${{ parameters.platform.name }}.xml + fi + + ${{ coalesce(parameters.platform.buildScript, './build.sh') }} --ci \ + --configuration $buildConfig \ + --restore --build --pack $publishArgs -bl \ + $officialBuildArgs \ + $internalRuntimeDownloadArgs \ + $internalRestoreArgs \ + $targetRidArgs \ + $runtimeOsArgs \ + $baseOsArgs \ + /p:SourceBuildNonPortable=${{ parameters.platform.nonPortable }} \ + /p:ArcadeBuildFromSource=true \ + /p:DotNetBuildSourceOnly=true \ + /p:DotNetBuildRepo=true \ + /p:AssetManifestFileName=$assetManifestFileName + displayName: Build + +# Upload build logs for diagnosis. +- task: CopyFiles@2 + displayName: Prepare BuildLogs staging directory + inputs: + SourceFolder: '$(Build.SourcesDirectory)' + Contents: | + **/*.log + **/*.binlog + artifacts/sb/prebuilt-report/** + TargetFolder: '$(Build.StagingDirectory)/BuildLogs' + CleanTargetFolder: true + continueOnError: true + condition: succeededOrFailed() + +- template: /eng/common/core-templates/steps/publish-pipeline-artifacts.yml + parameters: + is1ESPipeline: ${{ parameters.is1ESPipeline }} + args: + displayName: Publish BuildLogs + targetPath: '$(Build.StagingDirectory)/BuildLogs' + artifactName: BuildLogs_SourceBuild_${{ parameters.platform.name }}_Attempt$(System.JobAttempt) + continueOnError: true + condition: succeededOrFailed() + +# Manually inject component detection so that we can ignore the source build upstream cache, which contains +# a nupkg cache of input packages (a local feed). +# This path must match the upstream cache path in property 'CurrentRepoSourceBuiltNupkgCacheDir' +# in src\Microsoft.DotNet.Arcade.Sdk\tools\SourceBuild\SourceBuildArcade.targets +- task: ComponentGovernanceComponentDetection@0 + displayName: Component Detection (Exclude upstream cache) + inputs: + ignoreDirectories: '$(Build.SourcesDirectory)/artifacts/sb/src/artifacts/obj/source-built-upstream-cache' diff --git a/eng/common/core-templates/variables/pool-providers.yml b/eng/common/core-templates/variables/pool-providers.yml new file mode 100644 index 00000000000000..41053d382a2e10 --- /dev/null +++ b/eng/common/core-templates/variables/pool-providers.yml @@ -0,0 +1,8 @@ +parameters: + is1ESPipeline: false + +variables: + - ${{ if eq(parameters.is1ESPipeline, 'true') }}: + - template: /eng/common/templates-official/variables/pool-providers.yml + - ${{ else }}: + - template: /eng/common/templates/variables/pool-providers.yml \ No newline at end of file diff --git a/eng/common/cross/toolchain.cmake b/eng/common/cross/toolchain.cmake index 3762640fdcf792..9a4e285a5ae3f0 100644 --- a/eng/common/cross/toolchain.cmake +++ b/eng/common/cross/toolchain.cmake @@ -382,6 +382,26 @@ if(TARGET_ARCH_NAME MATCHES "^(arm|armel|x86)$") endif() endif() +# Set C++ standard library options if specified +set(CLR_CMAKE_CXX_STANDARD_LIBRARY "" CACHE STRING "Standard library flavor to link against. Only supported with the Clang compiler.") +if (CLR_CMAKE_CXX_STANDARD_LIBRARY) + add_compile_options($<$:--stdlib=${CLR_CMAKE_CXX_STANDARD_LIBRARY}>) + add_link_options($<$:--stdlib=${CLR_CMAKE_CXX_STANDARD_LIBRARY}>) +endif() + +option(CLR_CMAKE_CXX_STANDARD_LIBRARY_STATIC "Statically link against the C++ standard library" OFF) +if(CLR_CMAKE_CXX_STANDARD_LIBRARY_STATIC) + add_link_options($<$:-static-libstdc++>) +endif() + +set(CLR_CMAKE_CXX_ABI_LIBRARY "" CACHE STRING "C++ ABI implementation library to link against. Only supported with the Clang compiler.") +if (CLR_CMAKE_CXX_ABI_LIBRARY) + # The user may specify the ABI library with the 'lib' prefix, like 'libstdc++'. Strip the prefix here so the linker finds the right library. + string(REGEX REPLACE "^lib(.+)" "\\1" CLR_CMAKE_CXX_ABI_LIBRARY ${CLR_CMAKE_CXX_ABI_LIBRARY}) + # We need to specify this as a linker-backend option as Clang will filter this option out when linking to libc++. + add_link_options("LINKER:-l${CLR_CMAKE_CXX_ABI_LIBRARY}") +endif() + set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) diff --git a/eng/common/sdk-task.ps1 b/eng/common/sdk-task.ps1 index 091023970f1c9c..aab40de3fd9aca 100644 --- a/eng/common/sdk-task.ps1 +++ b/eng/common/sdk-task.ps1 @@ -64,7 +64,7 @@ try { $GlobalJson.tools | Add-Member -Name "vs" -Value (ConvertFrom-Json "{ `"version`": `"16.5`" }") -MemberType NoteProperty } if( -not ($GlobalJson.tools.PSObject.Properties.Name -match "xcopy-msbuild" )) { - $GlobalJson.tools | Add-Member -Name "xcopy-msbuild" -Value "17.8.5" -MemberType NoteProperty + $GlobalJson.tools | Add-Member -Name "xcopy-msbuild" -Value "17.10.0-pre.4.0" -MemberType NoteProperty } if ($GlobalJson.tools."xcopy-msbuild".Trim() -ine "none") { $xcopyMSBuildToolsFolder = InitializeXCopyMSBuild $GlobalJson.tools."xcopy-msbuild" -install $true diff --git a/eng/common/template-guidance.md b/eng/common/template-guidance.md new file mode 100644 index 00000000000000..c114bc28dcb95d --- /dev/null +++ b/eng/common/template-guidance.md @@ -0,0 +1,137 @@ +# Overview + +Arcade provides templates for public (`/templates`) and 1ES pipeline templates (`/templates-official`) scenarios. Pipelines which are required to be managed by 1ES pipeline templates should reference `/templates-offical`, all other pipelines may reference `/templates`. + +## How to use + +Basic guidance is: + +- 1ES Pipeline Template or 1ES Microbuild template runs should reference `eng/common/templates-official`. Any internal production-graded pipeline should use these templates. + +- All other runs should reference `eng/common/templates`. + +See [azure-pipelines.yml](../../azure-pipelines.yml) (templates-official example) or [azure-pipelines-pr.yml](../../azure-pipelines-pr.yml) (templates example) for examples. + +#### The `templateIs1ESManaged` parameter + +The `templateIs1ESManaged` is available on most templates and affects which of the variants is used for nested templates. See [Development Notes](#development-notes) below for more information on the `templateIs1ESManaged1 parameter. + +- For templates under `job/`, `jobs/`, `steps`, or `post-build/`, this parameter must be explicitly set. + +## Multiple outputs + +1ES pipeline templates impose a policy where every publish artifact execution results in additional security scans being injected into your pipeline. When using `templates-official/jobs/jobs.yml`, Arcade reduces the number of additional security injections by gathering all publishing outputs into the [Build.ArtifactStagingDirectory](https://learn.microsoft.com/en-us/azure/devops/pipelines/build/variables?view=azure-devops&tabs=yaml#build-variables-devops-services), and utilizing the [outputParentDirectory](https://eng.ms/docs/cloud-ai-platform/devdiv/one-engineering-system-1es/1es-docs/1es-pipeline-templates/features/outputs#multiple-outputs) feature of 1ES pipeline templates. When implementing your pipeline, if you ensure publish artifacts are located in the `$(Build.ArtifactStagingDirectory)`, and utilize the 1ES provided template context, then you can reduce the number of security scans for your pipeline. + +Example: +``` yaml +# azure-pipelines.yml +extends: + template: azure-pipelines/MicroBuild.1ES.Official.yml@MicroBuildTemplate + parameters: + stages: + - stage: build + jobs: + - template: /eng/common/templates-official/jobs/jobs.yml@self + parameters: + # 1ES makes use of outputs to reduce security task injection overhead + templateContext: + outputs: + - output: pipelineArtifact + displayName: 'Publish logs from source' + continueOnError: true + condition: always() + targetPath: $(Build.ArtifactStagingDirectory)/artifacts/log + artifactName: Logs + jobs: + - job: Windows + steps: + - script: echo "friendly neighborhood" > artifacts/marvel/spiderman.txt + # copy build outputs to artifact staging directory for publishing + - task: CopyFiles@2 + displayName: Gather build output + inputs: + SourceFolder: '$(Build.SourcesDirectory)/artifacts/marvel' + Contents: '**' + TargetFolder: '$(Build.ArtifactStagingDirectory)/artifacts/marvel' +``` + +Note: Multiple outputs are ONLY applicable to 1ES PT publishing (only usable when referencing `templates-official`). + +# Development notes + +**Folder / file structure** + +``` text +eng\common\ + [templates || templates-official]\ + job\ + job.yml (shim + artifact publishing logic) + onelocbuild.yml (shim) + publish-build-assets.yml (shim) + source-build.yml (shim) + source-index-stage1.yml (shim) + jobs\ + codeql-build.yml (shim) + jobs.yml (shim) + source-build.yml (shim) + post-build\ + post-build.yml (shim) + trigger-subscription.yml (shim) + common-variabls.yml (shim) + setup-maestro-vars.yml (shim) + steps\ + publish-build-artifacts.yml (logic) + publish-pipeline-artifacts.yml (logic) + add-build-channel.yml (shim) + component-governance.yml (shim) + generate-sbom.yml (shim) + publish-logs.yml (shim) + retain-build.yml (shim) + send-to-helix.yml (shim) + source-build.yml (shim) + variables\ + pool-providers.yml (logic + redirect) # templates/variables/pool-providers.yml will redirect to templates-official/variables/pool-providers.yml if you are running in the internal project + sdl-variables.yml (logic) + core-templates\ + job\ + job.yml (logic) + onelocbuild.yml (logic) + publish-build-assets.yml (logic) + source-build.yml (logic) + source-index-stage1.yml (logic) + jobs\ + codeql-build.yml (logic) + jobs.yml (logic) + source-build.yml (logic) + post-build\ + common-variabls.yml (logic) + post-build.yml (logic) + setup-maestro-vars.yml (logic) + trigger-subscription.yml (logic) + steps\ + add-build-to-channel.yml (logic) + component-governance.yml (logic) + generate-sbom.yml (logic) + publish-build-artifacts.yml (redirect) + publish-logs.yml (logic) + publish-pipeline-artifacts.yml (redirect) + retain-build.yml (logic) + send-to-helix.yml (logic) + source-build.yml (logic) + variables\ + pool-providers.yml (redirect) +``` + +In the table above, a file is designated as "shim", "logic", or "redirect". + +- shim - represents a yaml file which is an intermediate step between pipeline logic and .Net Core Engineering's templates (`core-templates`) and defines the `is1ESPipeline` parameter value. + +- logic - represents actual base template logic. + +- redirect- represents a file in `core-templates` which redirects to the "logic" file in either `templates` or `templates-official`. + +Logic for Arcade's templates live **primarily** in the `core-templates` folder. The exceptions to the location of the logic files are around artifact publishing, which is handled differently between 1es pipeline templates and standard templates. `templates` and `templates-official` provide shim entry points which redirect to `core-templates` while also defining the `is1ESPipeline` parameter. If a shim is referenced in `templates`, then `is1ESPipeline` is set to `false`. If a shim is referenced in `templates-official`, then `is1ESPipeline` is set to `true`. + +Within `templates` and `templates-official`, the templates at the "stages", and "jobs" / "job" level have been replaced with shims. Templates at the "steps" and "variables" level are typically too granular to be replaced with shims and instead persist logic which is directly applicable to either scenario. + +Within `core-templates`, there are a handful of places where logic is dependent on which shim entry point was used. In those places, we redirect back to the respective logic file in `templates` or `templates-official`. diff --git a/eng/common/templates-official/job/job.yml b/eng/common/templates-official/job/job.yml index 761acc5eb624c6..4724e9aaa80910 100644 --- a/eng/common/templates-official/job/job.yml +++ b/eng/common/templates-official/job/job.yml @@ -1,264 +1,62 @@ -# Internal resources (telemetry, microbuild) can only be accessed from non-public projects, -# and some (Microbuild) should only be applied to non-PR cases for internal builds. - -parameters: -# Job schema parameters - https://docs.microsoft.com/en-us/azure/devops/pipelines/yaml-schema?view=vsts&tabs=schema#job - cancelTimeoutInMinutes: '' - condition: '' - container: '' - continueOnError: false - dependsOn: '' - displayName: '' - pool: '' - steps: [] - strategy: '' - timeoutInMinutes: '' - variables: [] - workspace: '' - templateContext: '' - -# Job base template specific parameters - # See schema documentation - https://github.com/dotnet/arcade/blob/master/Documentation/AzureDevOps/TemplateSchema.md - artifacts: '' - enableMicrobuild: false - enablePublishBuildArtifacts: false - enablePublishBuildAssets: false - enablePublishTestResults: false - enablePublishUsingPipelines: false - enableBuildRetry: false - disableComponentGovernance: '' - componentGovernanceIgnoreDirectories: '' - mergeTestResults: false - testRunTitle: '' - testResultsFormat: '' - name: '' - preSteps: [] - runAsPublic: false -# Sbom related params - enableSbom: true - PackageVersion: 7.0.0 - BuildDropPath: '$(Build.SourcesDirectory)/artifacts' - jobs: -- job: ${{ parameters.name }} - - ${{ if ne(parameters.cancelTimeoutInMinutes, '') }}: - cancelTimeoutInMinutes: ${{ parameters.cancelTimeoutInMinutes }} - - ${{ if ne(parameters.condition, '') }}: - condition: ${{ parameters.condition }} - - ${{ if ne(parameters.container, '') }}: - container: ${{ parameters.container }} - - ${{ if ne(parameters.continueOnError, '') }}: - continueOnError: ${{ parameters.continueOnError }} - - ${{ if ne(parameters.dependsOn, '') }}: - dependsOn: ${{ parameters.dependsOn }} - - ${{ if ne(parameters.displayName, '') }}: - displayName: ${{ parameters.displayName }} - - ${{ if ne(parameters.pool, '') }}: - pool: ${{ parameters.pool }} - - ${{ if ne(parameters.strategy, '') }}: - strategy: ${{ parameters.strategy }} - - ${{ if ne(parameters.timeoutInMinutes, '') }}: - timeoutInMinutes: ${{ parameters.timeoutInMinutes }} - - ${{ if ne(parameters.templateContext, '') }}: - templateContext: ${{ parameters.templateContext }} - - variables: - - ${{ if ne(parameters.enableTelemetry, 'false') }}: - - name: DOTNET_CLI_TELEMETRY_PROFILE - value: '$(Build.Repository.Uri)' - - ${{ if eq(parameters.enableRichCodeNavigation, 'true') }}: - - name: EnableRichCodeNavigation - value: 'true' - # Retry signature validation up to three times, waiting 2 seconds between attempts. - # See https://learn.microsoft.com/en-us/nuget/reference/errors-and-warnings/nu3028#retry-untrusted-root-failures - - name: NUGET_EXPERIMENTAL_CHAIN_BUILD_RETRY_POLICY - value: 3,2000 - - ${{ each variable in parameters.variables }}: - # handle name-value variable syntax - # example: - # - name: [key] - # value: [value] - - ${{ if ne(variable.name, '') }}: - - name: ${{ variable.name }} - value: ${{ variable.value }} - - # handle variable groups - - ${{ if ne(variable.group, '') }}: - - group: ${{ variable.group }} - - # handle template variable syntax - # example: - # - template: path/to/template.yml - # parameters: - # [key]: [value] - - ${{ if ne(variable.template, '') }}: - - template: ${{ variable.template }} - ${{ if ne(variable.parameters, '') }}: - parameters: ${{ variable.parameters }} - - # handle key-value variable syntax. - # example: - # - [key]: [value] - - ${{ if and(eq(variable.name, ''), eq(variable.group, ''), eq(variable.template, '')) }}: - - ${{ each pair in variable }}: - - name: ${{ pair.key }} - value: ${{ pair.value }} - - # DotNet-HelixApi-Access provides 'HelixApiAccessToken' for internal builds - - ${{ if and(eq(parameters.enableTelemetry, 'true'), eq(parameters.runAsPublic, 'false'), ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest')) }}: - - group: DotNet-HelixApi-Access - - ${{ if ne(parameters.workspace, '') }}: - workspace: ${{ parameters.workspace }} - - steps: - - ${{ if ne(parameters.preSteps, '') }}: - - ${{ each preStep in parameters.preSteps }}: - - ${{ preStep }} - - - ${{ if and(eq(parameters.runAsPublic, 'false'), ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest')) }}: - - ${{ if eq(parameters.enableMicrobuild, 'true') }}: - - task: MicroBuildSigningPlugin@4 - displayName: Install MicroBuild plugin - inputs: - signType: $(_SignType) - zipSources: false - feedSource: https://dnceng.pkgs.visualstudio.com/_packaging/MicroBuildToolset/nuget/v3/index.json - env: - TeamName: $(_TeamName) - MicroBuildOutputFolderOverride: '$(Agent.TempDirectory)' - continueOnError: ${{ parameters.continueOnError }} - condition: and(succeeded(), in(variables['_SignType'], 'real', 'test'), eq(variables['Agent.Os'], 'Windows_NT')) - - - ${{ if and(eq(parameters.runAsPublic, 'false'), eq(variables['System.TeamProject'], 'internal')) }}: - - task: NuGetAuthenticate@1 - - - ${{ if and(ne(parameters.artifacts.download, 'false'), ne(parameters.artifacts.download, '')) }}: - - task: DownloadPipelineArtifact@2 - inputs: - buildType: current - artifactName: ${{ coalesce(parameters.artifacts.download.name, 'Artifacts_$(Agent.OS)_$(_BuildConfig)') }} - targetPath: ${{ coalesce(parameters.artifacts.download.path, 'artifacts') }} - itemPattern: ${{ coalesce(parameters.artifacts.download.pattern, '**') }} - - - ${{ each step in parameters.steps }}: - - ${{ step }} - - - ${{ if eq(parameters.enableRichCodeNavigation, true) }}: - - task: RichCodeNavIndexer@0 - displayName: RichCodeNav Upload - inputs: - languages: ${{ coalesce(parameters.richCodeNavigationLanguage, 'csharp') }} - environment: ${{ coalesce(parameters.richCodeNavigationEnvironment, 'internal') }} - richNavLogOutputDirectory: $(Build.SourcesDirectory)/artifacts/bin - uploadRichNavArtifacts: ${{ coalesce(parameters.richCodeNavigationUploadArtifacts, false) }} - continueOnError: true - - - template: /eng/common/templates-official/steps/component-governance.yml - parameters: - ${{ if eq(parameters.disableComponentGovernance, '') }}: - ${{ if and(ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest'), eq(parameters.runAsPublic, 'false'), or(startsWith(variables['Build.SourceBranch'], 'refs/heads/release/'), startsWith(variables['Build.SourceBranch'], 'refs/heads/dotnet/'), startsWith(variables['Build.SourceBranch'], 'refs/heads/microsoft/'), eq(variables['Build.SourceBranch'], 'refs/heads/main'))) }}: - disableComponentGovernance: false - ${{ else }}: - disableComponentGovernance: true - ${{ else }}: - disableComponentGovernance: ${{ parameters.disableComponentGovernance }} - componentGovernanceIgnoreDirectories: ${{ parameters.componentGovernanceIgnoreDirectories }} - - - ${{ if eq(parameters.enableMicrobuild, 'true') }}: - - ${{ if and(eq(parameters.runAsPublic, 'false'), ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest')) }}: - - task: MicroBuildCleanup@1 - displayName: Execute Microbuild cleanup tasks - condition: and(always(), in(variables['_SignType'], 'real', 'test'), eq(variables['Agent.Os'], 'Windows_NT')) - continueOnError: ${{ parameters.continueOnError }} - env: - TeamName: $(_TeamName) - - - ${{ if ne(parameters.artifacts.publish, '') }}: - - ${{ if and(ne(parameters.artifacts.publish.artifacts, 'false'), ne(parameters.artifacts.publish.artifacts, '')) }}: - - task: CopyFiles@2 - displayName: Gather binaries for publish to artifacts - inputs: - SourceFolder: 'artifacts/bin' - Contents: '**' - TargetFolder: '$(Build.ArtifactStagingDirectory)/artifacts/bin' - - task: CopyFiles@2 - displayName: Gather packages for publish to artifacts - inputs: - SourceFolder: 'artifacts/packages' - Contents: '**' - TargetFolder: '$(Build.ArtifactStagingDirectory)/artifacts/packages' - - task: 1ES.PublishBuildArtifacts@1 - displayName: Publish pipeline artifacts - inputs: - PathtoPublish: '$(Build.ArtifactStagingDirectory)/artifacts' - PublishLocation: Container - ArtifactName: ${{ coalesce(parameters.artifacts.publish.artifacts.name , 'Artifacts_$(Agent.Os)_$(_BuildConfig)') }} - continueOnError: true - condition: always() - - ${{ if and(ne(parameters.artifacts.publish.logs, 'false'), ne(parameters.artifacts.publish.logs, '')) }}: - - task: 1ES.PublishPipelineArtifact@1 - inputs: - targetPath: 'artifacts/log' - artifactName: ${{ coalesce(parameters.artifacts.publish.logs.name, 'Logs_Build_$(Agent.Os)_$(_BuildConfig)_Attempt$(System.JobAttempt)') }} - displayName: 'Publish logs' - continueOnError: true - condition: always() - - - ${{ if ne(parameters.enablePublishBuildArtifacts, 'false') }}: - - task: 1ES.PublishBuildArtifacts@1 - displayName: Publish Logs - inputs: - PathtoPublish: '$(Build.SourcesDirectory)/artifacts/log/$(_BuildConfig)' - PublishLocation: Container - ArtifactName: ${{ coalesce(parameters.enablePublishBuildArtifacts.artifactName, '$(Agent.Os)_$(Agent.JobName)' ) }} - continueOnError: true - condition: always() - - - ${{ if or(and(eq(parameters.enablePublishTestResults, 'true'), eq(parameters.testResultsFormat, '')), eq(parameters.testResultsFormat, 'xunit')) }}: - - task: PublishTestResults@2 - displayName: Publish XUnit Test Results - inputs: - testResultsFormat: 'xUnit' - testResultsFiles: '*.xml' - searchFolder: '$(Build.SourcesDirectory)/artifacts/TestResults/$(_BuildConfig)' - testRunTitle: ${{ coalesce(parameters.testRunTitle, parameters.name, '$(System.JobName)') }}-xunit - mergeTestResults: ${{ parameters.mergeTestResults }} - continueOnError: true - condition: always() - - ${{ if or(and(eq(parameters.enablePublishTestResults, 'true'), eq(parameters.testResultsFormat, '')), eq(parameters.testResultsFormat, 'vstest')) }}: - - task: PublishTestResults@2 - displayName: Publish TRX Test Results - inputs: - testResultsFormat: 'VSTest' - testResultsFiles: '*.trx' - searchFolder: '$(Build.SourcesDirectory)/artifacts/TestResults/$(_BuildConfig)' - testRunTitle: ${{ coalesce(parameters.testRunTitle, parameters.name, '$(System.JobName)') }}-trx - mergeTestResults: ${{ parameters.mergeTestResults }} - continueOnError: true - condition: always() - - - ${{ if and(eq(parameters.runAsPublic, 'false'), ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest'), eq(parameters.enableSbom, 'true')) }}: - - template: /eng/common/templates-official/steps/generate-sbom.yml - parameters: - PackageVersion: ${{ parameters.packageVersion}} - BuildDropPath: ${{ parameters.buildDropPath }} - IgnoreDirectories: ${{ parameters.componentGovernanceIgnoreDirectories }} - - - ${{ if eq(parameters.enableBuildRetry, 'true') }}: - - task: 1ES.PublishPipelineArtifact@1 - inputs: - targetPath: '$(Build.SourcesDirectory)\eng\common\BuildConfiguration' - artifactName: 'BuildConfiguration' - displayName: 'Publish build retry configuration' - continueOnError: true \ No newline at end of file +- template: /eng/common/core-templates/job/job.yml + parameters: + is1ESPipeline: true + + # publish artifacts + # for 1ES managed templates, use the templateContext.output to handle multiple outputs. + templateContext: + outputParentDirectory: $(Build.ArtifactStagingDirectory) + outputs: + - ${{ if ne(parameters.artifacts.publish, '') }}: + - ${{ if and(ne(parameters.artifacts.publish.artifacts, 'false'), ne(parameters.artifacts.publish.artifacts, '')) }}: + - output: buildArtifacts + displayName: Publish pipeline artifacts + PathtoPublish: '$(Build.ArtifactStagingDirectory)/artifacts' + ArtifactName: ${{ coalesce(parameters.artifacts.publish.artifacts.name , 'Artifacts_$(Agent.Os)_$(_BuildConfig)') }} + condition: always() + continueOnError: true + - ${{ if and(ne(parameters.artifacts.publish.logs, 'false'), ne(parameters.artifacts.publish.logs, '')) }}: + - output: pipelineArtifact + targetPath: '$(Build.ArtifactStagingDirectory)/artifacts/log' + artifactName: ${{ coalesce(parameters.artifacts.publish.logs.name, 'Logs_Build_$(Agent.Os)_$(_BuildConfig)_Attempt$(System.JobAttempt)') }} + displayName: 'Publish logs' + continueOnError: true + condition: always() + + - ${{ if eq(parameters.enablePublishBuildArtifacts, true) }}: + - output: buildArtifacts + displayName: Publish Logs + PathtoPublish: '$(Build.ArtifactStagingDirectory)/artifacts/log/$(_BuildConfig)' + publishLocation: Container + ArtifactName: ${{ coalesce(parameters.enablePublishBuildArtifacts.artifactName, '$(Agent.Os)_$(Agent.JobName)' ) }} + continueOnError: true + condition: always() + + - ${{ if eq(parameters.enableBuildRetry, 'true') }}: + - output: pipelineArtifact + targetPath: '$(Build.ArtifactStagingDirectory)/artifacts/eng/common/BuildConfiguration' + artifactName: 'BuildConfiguration' + displayName: 'Publish build retry configuration' + continueOnError: true + + - ${{ if and(eq(parameters.runAsPublic, 'false'), ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest'), eq(parameters.enableSbom, 'true')) }}: + - output: pipelineArtifact + displayName: Publish SBOM manifest + continueOnError: true + targetPath: $(Build.ArtifactStagingDirectory)/sbom + artifactName: $(ARTIFACT_NAME) + + # add any outputs provided via root yaml + - ${{ if ne(parameters.templateContext.outputs, '') }}: + - ${{ each output in parameters.templateContext.outputs }}: + - ${{ output }} + + # add any remaining templateContext properties + ${{ each context in parameters.templateContext }}: + ${{ if and(ne(context.key, 'outputParentDirectory'), ne(context.key, 'outputs')) }}: + ${{ context.key }}: ${{ context.value }} + + ${{ each parameter in parameters }}: + ${{ if and(ne(parameter.key, 'templateContext'), ne(parameter.key, 'is1ESPipeline')) }}: + ${{ parameter.key }}: ${{ parameter.value }} diff --git a/eng/common/templates-official/job/onelocbuild.yml b/eng/common/templates-official/job/onelocbuild.yml index 52b4d05d3f8dd6..0f0c514b912dfc 100644 --- a/eng/common/templates-official/job/onelocbuild.yml +++ b/eng/common/templates-official/job/onelocbuild.yml @@ -1,112 +1,7 @@ -parameters: - # Optional: dependencies of the job - dependsOn: '' - - # Optional: A defined YAML pool - https://docs.microsoft.com/en-us/azure/devops/pipelines/yaml-schema?view=vsts&tabs=schema#pool - pool: '' - - CeapexPat: $(dn-bot-ceapex-package-r) # PAT for the loc AzDO instance https://dev.azure.com/ceapex - GithubPat: $(BotAccount-dotnet-bot-repo-PAT) - - SourcesDirectory: $(Build.SourcesDirectory) - CreatePr: true - AutoCompletePr: false - ReusePr: true - UseLfLineEndings: true - UseCheckedInLocProjectJson: false - SkipLocProjectJsonGeneration: false - LanguageSet: VS_Main_Languages - LclSource: lclFilesInRepo - LclPackageId: '' - RepoType: gitHub - GitHubOrg: dotnet - MirrorRepo: '' - MirrorBranch: main - condition: '' - JobNameSuffix: '' - jobs: -- job: OneLocBuild${{ parameters.JobNameSuffix }} - - dependsOn: ${{ parameters.dependsOn }} - - displayName: OneLocBuild${{ parameters.JobNameSuffix }} - - variables: - - group: OneLocBuildVariables # Contains the CeapexPat and GithubPat - - name: _GenerateLocProjectArguments - value: -SourcesDirectory ${{ parameters.SourcesDirectory }} - -LanguageSet "${{ parameters.LanguageSet }}" - -CreateNeutralXlfs - - ${{ if eq(parameters.UseCheckedInLocProjectJson, 'true') }}: - - name: _GenerateLocProjectArguments - value: ${{ variables._GenerateLocProjectArguments }} -UseCheckedInLocProjectJson - - template: /eng/common/templates-official/variables/pool-providers.yml - - ${{ if ne(parameters.pool, '') }}: - pool: ${{ parameters.pool }} - ${{ if eq(parameters.pool, '') }}: - pool: - # We don't use the collection uri here because it might vary (.visualstudio.com vs. dev.azure.com) - ${{ if eq(variables['System.TeamProject'], 'DevDiv') }}: - name: AzurePipelines-EO - image: 1ESPT-Windows2022 - demands: Cmd - os: windows - # If it's not devdiv, it's dnceng - ${{ if ne(variables['System.TeamProject'], 'DevDiv') }}: - name: $(DncEngInternalBuildPool) - image: 1es-windows-2022 - os: windows - - steps: - - ${{ if ne(parameters.SkipLocProjectJsonGeneration, 'true') }}: - - task: Powershell@2 - inputs: - filePath: $(Build.SourcesDirectory)/eng/common/generate-locproject.ps1 - arguments: $(_GenerateLocProjectArguments) - displayName: Generate LocProject.json - condition: ${{ parameters.condition }} - - - task: OneLocBuild@2 - displayName: OneLocBuild - env: - SYSTEM_ACCESSTOKEN: $(System.AccessToken) - inputs: - locProj: eng/Localize/LocProject.json - outDir: $(Build.ArtifactStagingDirectory) - lclSource: ${{ parameters.LclSource }} - lclPackageId: ${{ parameters.LclPackageId }} - isCreatePrSelected: ${{ parameters.CreatePr }} - isAutoCompletePrSelected: ${{ parameters.AutoCompletePr }} - ${{ if eq(parameters.CreatePr, true) }}: - isUseLfLineEndingsSelected: ${{ parameters.UseLfLineEndings }} - ${{ if eq(parameters.RepoType, 'gitHub') }}: - isShouldReusePrSelected: ${{ parameters.ReusePr }} - packageSourceAuth: patAuth - patVariable: ${{ parameters.CeapexPat }} - ${{ if eq(parameters.RepoType, 'gitHub') }}: - repoType: ${{ parameters.RepoType }} - gitHubPatVariable: "${{ parameters.GithubPat }}" - ${{ if ne(parameters.MirrorRepo, '') }}: - isMirrorRepoSelected: true - gitHubOrganization: ${{ parameters.GitHubOrg }} - mirrorRepo: ${{ parameters.MirrorRepo }} - mirrorBranch: ${{ parameters.MirrorBranch }} - condition: ${{ parameters.condition }} - - - task: 1ES.PublishBuildArtifacts@1 - displayName: Publish Localization Files - inputs: - PathtoPublish: '$(Build.ArtifactStagingDirectory)/loc' - PublishLocation: Container - ArtifactName: Loc - condition: ${{ parameters.condition }} +- template: /eng/common/core-templates/job/onelocbuild.yml + parameters: + is1ESPipeline: true - - task: 1ES.PublishBuildArtifacts@1 - displayName: Publish LocProject.json - inputs: - PathtoPublish: '$(Build.SourcesDirectory)/eng/Localize/' - PublishLocation: Container - ArtifactName: Loc - condition: ${{ parameters.condition }} \ No newline at end of file + ${{ each parameter in parameters }}: + ${{ parameter.key }}: ${{ parameter.value }} diff --git a/eng/common/templates-official/job/publish-build-assets.yml b/eng/common/templates-official/job/publish-build-assets.yml index 38340d3e38614a..d667a70e8de743 100644 --- a/eng/common/templates-official/job/publish-build-assets.yml +++ b/eng/common/templates-official/job/publish-build-assets.yml @@ -1,159 +1,7 @@ -parameters: - configuration: 'Debug' - - # Optional: condition for the job to run - condition: '' - - # Optional: 'true' if future jobs should run even if this job fails - continueOnError: false - - # Optional: dependencies of the job - dependsOn: '' - - # Optional: Include PublishBuildArtifacts task - enablePublishBuildArtifacts: false - - # Optional: A defined YAML pool - https://docs.microsoft.com/en-us/azure/devops/pipelines/yaml-schema?view=vsts&tabs=schema#pool - pool: {} - - # Optional: should run as a public build even in the internal project - # if 'true', the build won't run any of the internal only steps, even if it is running in non-public projects. - runAsPublic: false - - # Optional: whether the build's artifacts will be published using release pipelines or direct feed publishing - publishUsingPipelines: false - - # Optional: whether the build's artifacts will be published using release pipelines or direct feed publishing - publishAssetsImmediately: false - - artifactsPublishingAdditionalParameters: '' - - signingValidationAdditionalParameters: '' - jobs: -- job: Asset_Registry_Publish - - dependsOn: ${{ parameters.dependsOn }} - timeoutInMinutes: 150 - - ${{ if eq(parameters.publishAssetsImmediately, 'true') }}: - displayName: Publish Assets - ${{ else }}: - displayName: Publish to Build Asset Registry - - variables: - - template: /eng/common/templates-official/variables/pool-providers.yml - - ${{ if and(eq(parameters.runAsPublic, 'false'), ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest')) }}: - - group: Publish-Build-Assets - - group: AzureDevOps-Artifact-Feeds-Pats - - name: runCodesignValidationInjection - value: false - # unconditional - needed for logs publishing (redactor tool version) - - template: /eng/common/templates-official/post-build/common-variables.yml - - pool: - # We don't use the collection uri here because it might vary (.visualstudio.com vs. dev.azure.com) - ${{ if eq(variables['System.TeamProject'], 'DevDiv') }}: - name: AzurePipelines-EO - image: 1ESPT-Windows2022 - demands: Cmd - os: windows - # If it's not devdiv, it's dnceng - ${{ if ne(variables['System.TeamProject'], 'DevDiv') }}: - name: NetCore1ESPool-Publishing-Internal - image: windows.vs2019.amd64 - os: windows - steps: - - ${{ if and(eq(parameters.runAsPublic, 'false'), ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest')) }}: - - checkout: self - fetchDepth: 3 - clean: true - - - task: DownloadBuildArtifacts@0 - displayName: Download artifact - inputs: - artifactName: AssetManifests - downloadPath: '$(Build.StagingDirectory)/Download' - checkDownloadedFiles: true - condition: ${{ parameters.condition }} - continueOnError: ${{ parameters.continueOnError }} - - - task: NuGetAuthenticate@1 - - - task: PowerShell@2 - displayName: Publish Build Assets - inputs: - filePath: eng\common\sdk-task.ps1 - arguments: -task PublishBuildAssets -restore -msbuildEngine dotnet - /p:ManifestsPath='$(Build.StagingDirectory)/Download/AssetManifests' - /p:BuildAssetRegistryToken=$(MaestroAccessToken) - /p:MaestroApiEndpoint=https://maestro.dot.net - /p:PublishUsingPipelines=${{ parameters.publishUsingPipelines }} - /p:OfficialBuildId=$(Build.BuildNumber) - condition: ${{ parameters.condition }} - continueOnError: ${{ parameters.continueOnError }} - - - task: powershell@2 - displayName: Create ReleaseConfigs Artifact - inputs: - targetType: inline - script: | - New-Item -Path "$(Build.StagingDirectory)/ReleaseConfigs" -ItemType Directory -Force - $filePath = "$(Build.StagingDirectory)/ReleaseConfigs/ReleaseConfigs.txt" - Add-Content -Path $filePath -Value $(BARBuildId) - Add-Content -Path $filePath -Value "$(DefaultChannels)" - Add-Content -Path $filePath -Value $(IsStableBuild) - - - task: 1ES.PublishBuildArtifacts@1 - displayName: Publish ReleaseConfigs Artifact - inputs: - PathtoPublish: '$(Build.StagingDirectory)/ReleaseConfigs' - PublishLocation: Container - ArtifactName: ReleaseConfigs - - - task: powershell@2 - displayName: Check if SymbolPublishingExclusionsFile.txt exists - inputs: - targetType: inline - script: | - $symbolExclusionfile = "$(Build.SourcesDirectory)/eng/SymbolPublishingExclusionsFile.txt" - if(Test-Path -Path $symbolExclusionfile) - { - Write-Host "SymbolExclusionFile exists" - Write-Host "##vso[task.setvariable variable=SymbolExclusionFile]true" - } - else{ - Write-Host "Symbols Exclusion file does not exists" - Write-Host "##vso[task.setvariable variable=SymbolExclusionFile]false" - } - - - task: 1ES.PublishBuildArtifacts@1 - displayName: Publish SymbolPublishingExclusionsFile Artifact - condition: eq(variables['SymbolExclusionFile'], 'true') - inputs: - PathtoPublish: '$(Build.SourcesDirectory)/eng/SymbolPublishingExclusionsFile.txt' - PublishLocation: Container - ArtifactName: ReleaseConfigs - - - ${{ if eq(parameters.publishAssetsImmediately, 'true') }}: - - template: /eng/common/templates-official/post-build/setup-maestro-vars.yml - parameters: - BARBuildId: ${{ parameters.BARBuildId }} - PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }} - - - task: PowerShell@2 - displayName: Publish Using Darc - inputs: - filePath: $(Build.SourcesDirectory)/eng/common/post-build/publish-using-darc.ps1 - arguments: -BuildId $(BARBuildId) - -PublishingInfraVersion 3 - -AzdoToken '$(publishing-dnceng-devdiv-code-r-build-re)' - -MaestroToken '$(MaestroApiAccessToken)' - -WaitPublishingFinish true - -ArtifactsPublishingAdditionalParameters '${{ parameters.artifactsPublishingAdditionalParameters }}' - -SymbolPublishingAdditionalParameters '${{ parameters.symbolPublishingAdditionalParameters }}' +- template: /eng/common/core-templates/job/publish-build-assets.yml + parameters: + is1ESPipeline: true - - ${{ if eq(parameters.enablePublishBuildArtifacts, 'true') }}: - - template: /eng/common/templates-official/steps/publish-logs.yml - parameters: - JobLabel: 'Publish_Artifacts_Logs' + ${{ each parameter in parameters }}: + ${{ parameter.key }}: ${{ parameter.value }} diff --git a/eng/common/templates-official/job/source-build.yml b/eng/common/templates-official/job/source-build.yml index 2180e97a284f84..1a480034b678eb 100644 --- a/eng/common/templates-official/job/source-build.yml +++ b/eng/common/templates-official/job/source-build.yml @@ -1,67 +1,7 @@ -parameters: - # This template adds arcade-powered source-build to CI. The template produces a server job with a - # default ID 'Source_Build_Complete' to put in a dependency list if necessary. - - # Specifies the prefix for source-build jobs added to pipeline. Use this if disambiguation needed. - jobNamePrefix: 'Source_Build' - - # Defines the platform on which to run the job. By default, a linux-x64 machine, suitable for - # managed-only repositories. This is an object with these properties: - # - # name: '' - # The name of the job. This is included in the job ID. - # targetRID: '' - # The name of the target RID to use, instead of the one auto-detected by Arcade. - # nonPortable: false - # Enables non-portable mode. This means a more specific RID (e.g. fedora.32-x64 rather than - # linux-x64), and compiling against distro-provided packages rather than portable ones. - # skipPublishValidation: false - # Disables publishing validation. By default, a check is performed to ensure no packages are - # published by source-build. - # container: '' - # A container to use. Runs in docker. - # pool: {} - # A pool to use. Runs directly on an agent. - # buildScript: '' - # Specifies the build script to invoke to perform the build in the repo. The default - # './build.sh' should work for typical Arcade repositories, but this is customizable for - # difficult situations. - # jobProperties: {} - # A list of job properties to inject at the top level, for potential extensibility beyond - # container and pool. - platform: {} - jobs: -- job: ${{ parameters.jobNamePrefix }}_${{ parameters.platform.name }} - displayName: Source-Build (${{ parameters.platform.name }}) - - ${{ each property in parameters.platform.jobProperties }}: - ${{ property.key }}: ${{ property.value }} - - ${{ if ne(parameters.platform.container, '') }}: - container: ${{ parameters.platform.container }} - - ${{ if eq(parameters.platform.pool, '') }}: - # The default VM host AzDO pool. This should be capable of running Docker containers: almost all - # source-build builds run in Docker, including the default managed platform. - # /eng/common/templates-official/variables/pool-providers.yml can't be used here (some customers declare variables already), so duplicate its logic - pool: - ${{ if eq(variables['System.TeamProject'], 'public') }}: - name: $[replace(replace(eq(contains(coalesce(variables['System.PullRequest.TargetBranch'], variables['Build.SourceBranch'], 'refs/heads/main'), 'release'), 'true'), True, 'NetCore-Svc-Public' ), False, 'NetCore-Public')] - demands: ImageOverride -equals build.ubuntu.2004.amd64 - - ${{ if eq(variables['System.TeamProject'], 'internal') }}: - name: $[replace(replace(eq(contains(coalesce(variables['System.PullRequest.TargetBranch'], variables['Build.SourceBranch'], 'refs/heads/main'), 'release'), 'true'), True, 'NetCore1ESPool-Svc-Internal'), False, 'NetCore1ESPool-Internal')] - image: 1es-mariner-2 - os: linux - - ${{ if ne(parameters.platform.pool, '') }}: - pool: ${{ parameters.platform.pool }} - - workspace: - clean: all +- template: /eng/common/core-templates/job/source-build.yml + parameters: + is1ESPipeline: true - steps: - - template: /eng/common/templates-official/steps/source-build.yml - parameters: - platform: ${{ parameters.platform }} + ${{ each parameter in parameters }}: + ${{ parameter.key }}: ${{ parameter.value }} diff --git a/eng/common/templates-official/job/source-index-stage1.yml b/eng/common/templates-official/job/source-index-stage1.yml index 53a9ef51fd82d2..6d5ead316f92b5 100644 --- a/eng/common/templates-official/job/source-index-stage1.yml +++ b/eng/common/templates-official/job/source-index-stage1.yml @@ -1,67 +1,7 @@ -parameters: - runAsPublic: false - sourceIndexPackageVersion: 1.0.1-20240129.2 - sourceIndexPackageSource: https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools/nuget/v3/index.json - sourceIndexBuildCommand: powershell -NoLogo -NoProfile -ExecutionPolicy Bypass -Command "eng/common/build.ps1 -restore -build -binarylog -ci" - preSteps: [] - binlogPath: artifacts/log/Debug/Build.binlog - condition: '' - dependsOn: '' - pool: '' - jobs: -- job: SourceIndexStage1 - dependsOn: ${{ parameters.dependsOn }} - condition: ${{ parameters.condition }} - variables: - - name: SourceIndexPackageVersion - value: ${{ parameters.sourceIndexPackageVersion }} - - name: SourceIndexPackageSource - value: ${{ parameters.sourceIndexPackageSource }} - - name: BinlogPath - value: ${{ parameters.binlogPath }} - - ${{ if and(eq(parameters.runAsPublic, 'false'), ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest')) }}: - - group: source-dot-net stage1 variables - - template: /eng/common/templates-official/variables/pool-providers.yml - - ${{ if ne(parameters.pool, '') }}: - pool: ${{ parameters.pool }} - ${{ if eq(parameters.pool, '') }}: - pool: - ${{ if eq(variables['System.TeamProject'], 'public') }}: - name: $(DncEngPublicBuildPool) - image: windows.vs2022.amd64.open - ${{ if eq(variables['System.TeamProject'], 'internal') }}: - name: $(DncEngInternalBuildPool) - image: windows.vs2022.amd64 - - steps: - - ${{ each preStep in parameters.preSteps }}: - - ${{ preStep }} - - - task: UseDotNet@2 - displayName: Use .NET 8 SDK - inputs: - packageType: sdk - version: 8.0.x - installationPath: $(Agent.TempDirectory)/dotnet - workingDirectory: $(Agent.TempDirectory) - - - script: | - $(Agent.TempDirectory)/dotnet/dotnet tool install BinLogToSln --version $(SourceIndexPackageVersion) --add-source $(SourceIndexPackageSource) --tool-path $(Agent.TempDirectory)/.source-index/tools - $(Agent.TempDirectory)/dotnet/dotnet tool install UploadIndexStage1 --version $(SourceIndexPackageVersion) --add-source $(SourceIndexPackageSource) --tool-path $(Agent.TempDirectory)/.source-index/tools - displayName: Download Tools - # Set working directory to temp directory so 'dotnet' doesn't try to use global.json and use the repo's sdk. - workingDirectory: $(Agent.TempDirectory) - - - script: ${{ parameters.sourceIndexBuildCommand }} - displayName: Build Repository - - - script: $(Agent.TempDirectory)/.source-index/tools/BinLogToSln -i $(BinlogPath) -r $(Build.SourcesDirectory) -n $(Build.Repository.Name) -o .source-index/stage1output - displayName: Process Binlog into indexable sln +- template: /eng/common/core-templates/job/source-index-stage1.yml + parameters: + is1ESPipeline: true - - ${{ if and(eq(parameters.runAsPublic, 'false'), ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest')) }}: - - script: $(Agent.TempDirectory)/.source-index/tools/UploadIndexStage1 -i .source-index/stage1output -n $(Build.Repository.Name) - displayName: Upload stage1 artifacts to source index - env: - BLOB_CONTAINER_URL: $(source-dot-net-stage1-blob-container-url) + ${{ each parameter in parameters }}: + ${{ parameter.key }}: ${{ parameter.value }} diff --git a/eng/common/templates-official/jobs/codeql-build.yml b/eng/common/templates-official/jobs/codeql-build.yml index b68d3c2f31990f..a726322ecfe016 100644 --- a/eng/common/templates-official/jobs/codeql-build.yml +++ b/eng/common/templates-official/jobs/codeql-build.yml @@ -1,31 +1,7 @@ -parameters: - # See schema documentation in /Documentation/AzureDevOps/TemplateSchema.md - continueOnError: false - # Required: A collection of jobs to run - https://docs.microsoft.com/en-us/azure/devops/pipelines/yaml-schema?view=vsts&tabs=schema#job - jobs: [] - # Optional: if specified, restore and use this version of Guardian instead of the default. - overrideGuardianVersion: '' - jobs: -- template: /eng/common/templates-official/jobs/jobs.yml +- template: /eng/common/core-templates/jobs/codeql-build.yml parameters: - enableMicrobuild: false - enablePublishBuildArtifacts: false - enablePublishTestResults: false - enablePublishBuildAssets: false - enablePublishUsingPipelines: false - enableTelemetry: true + is1ESPipeline: true - variables: - - group: Publish-Build-Assets - # The Guardian version specified in 'eng/common/sdl/packages.config'. This value must be kept in - # sync with the packages.config file. - - name: DefaultGuardianVersion - value: 0.109.0 - - name: GuardianPackagesConfigFile - value: $(Build.SourcesDirectory)\eng\common\sdl\packages.config - - name: GuardianVersion - value: ${{ coalesce(parameters.overrideGuardianVersion, '$(DefaultGuardianVersion)') }} - - jobs: ${{ parameters.jobs }} - + ${{ each parameter in parameters }}: + ${{ parameter.key }}: ${{ parameter.value }} diff --git a/eng/common/templates-official/jobs/jobs.yml b/eng/common/templates-official/jobs/jobs.yml index 857a0f8ba43e84..007deddaea0f53 100644 --- a/eng/common/templates-official/jobs/jobs.yml +++ b/eng/common/templates-official/jobs/jobs.yml @@ -1,97 +1,7 @@ -parameters: - # See schema documentation in /Documentation/AzureDevOps/TemplateSchema.md - continueOnError: false - - # Optional: Include PublishBuildArtifacts task - enablePublishBuildArtifacts: false - - # Optional: Enable publishing using release pipelines - enablePublishUsingPipelines: false - - # Optional: Enable running the source-build jobs to build repo from source - enableSourceBuild: false - - # Optional: Parameters for source-build template. - # See /eng/common/templates-official/jobs/source-build.yml for options - sourceBuildParameters: [] - - graphFileGeneration: - # Optional: Enable generating the graph files at the end of the build - enabled: false - # Optional: Include toolset dependencies in the generated graph files - includeToolset: false - - # Required: A collection of jobs to run - https://docs.microsoft.com/en-us/azure/devops/pipelines/yaml-schema?view=vsts&tabs=schema#job - jobs: [] - - # Optional: Override automatically derived dependsOn value for "publish build assets" job - publishBuildAssetsDependsOn: '' - - # Optional: Publish the assets as soon as the publish to BAR stage is complete, rather doing so in a separate stage. - publishAssetsImmediately: false - - # Optional: If using publishAssetsImmediately and additional parameters are needed, can be used to send along additional parameters (normally sent to post-build.yml) - artifactsPublishingAdditionalParameters: '' - signingValidationAdditionalParameters: '' - - # Optional: should run as a public build even in the internal project - # if 'true', the build won't run any of the internal only steps, even if it is running in non-public projects. - runAsPublic: false - - enableSourceIndex: false - sourceIndexParams: {} - -# Internal resources (telemetry, microbuild) can only be accessed from non-public projects, -# and some (Microbuild) should only be applied to non-PR cases for internal builds. - jobs: -- ${{ each job in parameters.jobs }}: - - template: ../job/job.yml - parameters: - # pass along parameters - ${{ each parameter in parameters }}: - ${{ if ne(parameter.key, 'jobs') }}: - ${{ parameter.key }}: ${{ parameter.value }} - - # pass along job properties - ${{ each property in job }}: - ${{ if ne(property.key, 'job') }}: - ${{ property.key }}: ${{ property.value }} - - name: ${{ job.job }} - -- ${{ if eq(parameters.enableSourceBuild, true) }}: - - template: /eng/common/templates-official/jobs/source-build.yml - parameters: - allCompletedJobId: Source_Build_Complete - ${{ each parameter in parameters.sourceBuildParameters }}: - ${{ parameter.key }}: ${{ parameter.value }} - -- ${{ if eq(parameters.enableSourceIndex, 'true') }}: - - template: ../job/source-index-stage1.yml - parameters: - runAsPublic: ${{ parameters.runAsPublic }} - ${{ each parameter in parameters.sourceIndexParams }}: - ${{ parameter.key }}: ${{ parameter.value }} - -- ${{ if and(eq(parameters.runAsPublic, 'false'), ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest')) }}: - - ${{ if or(eq(parameters.enablePublishBuildAssets, true), eq(parameters.artifacts.publish.manifests, 'true'), ne(parameters.artifacts.publish.manifests, '')) }}: - - template: ../job/publish-build-assets.yml - parameters: - continueOnError: ${{ parameters.continueOnError }} - dependsOn: - - ${{ if ne(parameters.publishBuildAssetsDependsOn, '') }}: - - ${{ each job in parameters.publishBuildAssetsDependsOn }}: - - ${{ job.job }} - - ${{ if eq(parameters.publishBuildAssetsDependsOn, '') }}: - - ${{ each job in parameters.jobs }}: - - ${{ job.job }} - - ${{ if eq(parameters.enableSourceBuild, true) }}: - - Source_Build_Complete +- template: /eng/common/core-templates/jobs/jobs.yml + parameters: + is1ESPipeline: true - runAsPublic: ${{ parameters.runAsPublic }} - publishUsingPipelines: ${{ parameters.enablePublishUsingPipelines }} - publishAssetsImmediately: ${{ parameters.publishAssetsImmediately }} - enablePublishBuildArtifacts: ${{ parameters.enablePublishBuildArtifacts }} - artifactsPublishingAdditionalParameters: ${{ parameters.artifactsPublishingAdditionalParameters }} - signingValidationAdditionalParameters: ${{ parameters.signingValidationAdditionalParameters }} + ${{ each parameter in parameters }}: + ${{ parameter.key }}: ${{ parameter.value }} diff --git a/eng/common/templates-official/jobs/source-build.yml b/eng/common/templates-official/jobs/source-build.yml index 2076f4e25b43c6..483e7b611f346b 100644 --- a/eng/common/templates-official/jobs/source-build.yml +++ b/eng/common/templates-official/jobs/source-build.yml @@ -1,46 +1,7 @@ -parameters: - # This template adds arcade-powered source-build to CI. A job is created for each platform, as - # well as an optional server job that completes when all platform jobs complete. - - # The name of the "join" job for all source-build platforms. If set to empty string, the job is - # not included. Existing repo pipelines can use this job depend on all source-build jobs - # completing without maintaining a separate list of every single job ID: just depend on this one - # server job. By default, not included. Recommended name if used: 'Source_Build_Complete'. - allCompletedJobId: '' - - # See /eng/common/templates-official/job/source-build.yml - jobNamePrefix: 'Source_Build' - - # This is the default platform provided by Arcade, intended for use by a managed-only repo. - defaultManagedPlatform: - name: 'Managed' - container: 'mcr.microsoft.com/dotnet-buildtools/prereqs:centos-stream9' - - # Defines the platforms on which to run build jobs. One job is created for each platform, and the - # object in this array is sent to the job template as 'platform'. If no platforms are specified, - # one job runs on 'defaultManagedPlatform'. - platforms: [] - jobs: +- template: /eng/common/core-templates/jobs/source-build.yml + parameters: + is1ESPipeline: true -- ${{ if ne(parameters.allCompletedJobId, '') }}: - - job: ${{ parameters.allCompletedJobId }} - displayName: Source-Build Complete - pool: server - dependsOn: - - ${{ each platform in parameters.platforms }}: - - ${{ parameters.jobNamePrefix }}_${{ platform.name }} - - ${{ if eq(length(parameters.platforms), 0) }}: - - ${{ parameters.jobNamePrefix }}_${{ parameters.defaultManagedPlatform.name }} - -- ${{ each platform in parameters.platforms }}: - - template: /eng/common/templates-official/job/source-build.yml - parameters: - jobNamePrefix: ${{ parameters.jobNamePrefix }} - platform: ${{ platform }} - -- ${{ if eq(length(parameters.platforms), 0) }}: - - template: /eng/common/templates-official/job/source-build.yml - parameters: - jobNamePrefix: ${{ parameters.jobNamePrefix }} - platform: ${{ parameters.defaultManagedPlatform }} + ${{ each parameter in parameters }}: + ${{ parameter.key }}: ${{ parameter.value }} \ No newline at end of file diff --git a/eng/common/templates-official/post-build/common-variables.yml b/eng/common/templates-official/post-build/common-variables.yml index b9ede10bf099ae..c32fc49233f8fd 100644 --- a/eng/common/templates-official/post-build/common-variables.yml +++ b/eng/common/templates-official/post-build/common-variables.yml @@ -1,24 +1,8 @@ variables: - - group: Publish-Build-Assets +- template: /eng/common/core-templates/post-build/common-variables.yml + parameters: + # Specifies whether to use 1ES + is1ESPipeline: true - # Whether the build is internal or not - - name: IsInternalBuild - value: ${{ and(ne(variables['System.TeamProject'], 'public'), contains(variables['Build.SourceBranch'], 'internal')) }} - - # Default Maestro++ API Endpoint and API Version - - name: MaestroApiEndPoint - value: "https://maestro.dot.net" - - name: MaestroApiAccessToken - value: $(MaestroAccessToken) - - name: MaestroApiVersion - value: "2020-02-20" - - - name: SourceLinkCLIVersion - value: 3.0.0 - - name: SymbolToolVersion - value: 1.0.1 - - name: BinlogToolVersion - value: 1.0.11 - - - name: runCodesignValidationInjection - value: false + ${{ each parameter in parameters }}: + ${{ parameter.key }}: ${{ parameter.value }} \ No newline at end of file diff --git a/eng/common/templates-official/post-build/post-build.yml b/eng/common/templates-official/post-build/post-build.yml index da1f40958b450d..2364c0fd4a527e 100644 --- a/eng/common/templates-official/post-build/post-build.yml +++ b/eng/common/templates-official/post-build/post-build.yml @@ -1,285 +1,8 @@ -parameters: - # Which publishing infra should be used. THIS SHOULD MATCH THE VERSION ON THE BUILD MANIFEST. - # Publishing V1 is no longer supported - # Publishing V2 is no longer supported - # Publishing V3 is the default - - name: publishingInfraVersion - displayName: Which version of publishing should be used to promote the build definition? - type: number - default: 3 - values: - - 3 - - - name: BARBuildId - displayName: BAR Build Id - type: number - default: 0 - - - name: PromoteToChannelIds - displayName: Channel to promote BARBuildId to - type: string - default: '' - - - name: enableSourceLinkValidation - displayName: Enable SourceLink validation - type: boolean - default: false - - - name: enableSigningValidation - displayName: Enable signing validation - type: boolean - default: true - - - name: enableSymbolValidation - displayName: Enable symbol validation - type: boolean - default: false - - - name: enableNugetValidation - displayName: Enable NuGet validation - type: boolean - default: true - - - name: publishInstallersAndChecksums - displayName: Publish installers and checksums - type: boolean - default: true - - - name: SDLValidationParameters - type: object - default: - enable: false - publishGdn: false - continueOnError: false - params: '' - artifactNames: '' - downloadArtifacts: true - - # These parameters let the user customize the call to sdk-task.ps1 for publishing - # symbols & general artifacts as well as for signing validation - - name: symbolPublishingAdditionalParameters - displayName: Symbol publishing additional parameters - type: string - default: '' - - - name: artifactsPublishingAdditionalParameters - displayName: Artifact publishing additional parameters - type: string - default: '' - - - name: signingValidationAdditionalParameters - displayName: Signing validation additional parameters - type: string - default: '' - - # Which stages should finish execution before post-build stages start - - name: validateDependsOn - type: object - default: - - build - - - name: publishDependsOn - type: object - default: - - Validate - - # Optional: Call asset publishing rather than running in a separate stage - - name: publishAssetsImmediately - type: boolean - default: false - stages: -- ${{ if or(eq( parameters.enableNugetValidation, 'true'), eq(parameters.enableSigningValidation, 'true'), eq(parameters.enableSourceLinkValidation, 'true'), eq(parameters.SDLValidationParameters.enable, 'true')) }}: - - stage: Validate - dependsOn: ${{ parameters.validateDependsOn }} - displayName: Validate Build Assets - variables: - - template: common-variables.yml - - template: /eng/common/templates-official/variables/pool-providers.yml - jobs: - - job: - displayName: NuGet Validation - condition: and(succeededOrFailed(), eq( ${{ parameters.enableNugetValidation }}, 'true')) - pool: - # We don't use the collection uri here because it might vary (.visualstudio.com vs. dev.azure.com) - ${{ if eq(variables['System.TeamProject'], 'DevDiv') }}: - name: AzurePipelines-EO - image: 1ESPT-Windows2022 - demands: Cmd - os: windows - # If it's not devdiv, it's dnceng - ${{ else }}: - name: $(DncEngInternalBuildPool) - image: 1es-windows-2022 - os: windows - - steps: - - template: setup-maestro-vars.yml - parameters: - BARBuildId: ${{ parameters.BARBuildId }} - PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }} - - - task: DownloadBuildArtifacts@0 - displayName: Download Package Artifacts - inputs: - buildType: specific - buildVersionToDownload: specific - project: $(AzDOProjectName) - pipeline: $(AzDOPipelineId) - buildId: $(AzDOBuildId) - artifactName: PackageArtifacts - checkDownloadedFiles: true - - - task: PowerShell@2 - displayName: Validate - inputs: - filePath: $(Build.SourcesDirectory)/eng/common/post-build/nuget-validation.ps1 - arguments: -PackagesPath $(Build.ArtifactStagingDirectory)/PackageArtifacts/ - -ToolDestinationPath $(Agent.BuildDirectory)/Extract/ - - - job: - displayName: Signing Validation - condition: and( eq( ${{ parameters.enableSigningValidation }}, 'true'), ne( variables['PostBuildSign'], 'true')) - pool: - # We don't use the collection uri here because it might vary (.visualstudio.com vs. dev.azure.com) - ${{ if eq(variables['System.TeamProject'], 'DevDiv') }}: - name: AzurePipelines-EO - image: 1ESPT-Windows2022 - demands: Cmd - os: windows - # If it's not devdiv, it's dnceng - ${{ else }}: - name: $(DncEngInternalBuildPool) - image: 1es-windows-2022 - os: windows - steps: - - template: setup-maestro-vars.yml - parameters: - BARBuildId: ${{ parameters.BARBuildId }} - PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }} - - - task: DownloadBuildArtifacts@0 - displayName: Download Package Artifacts - inputs: - buildType: specific - buildVersionToDownload: specific - project: $(AzDOProjectName) - pipeline: $(AzDOPipelineId) - buildId: $(AzDOBuildId) - artifactName: PackageArtifacts - checkDownloadedFiles: true - itemPattern: | - ** - !**/Microsoft.SourceBuild.Intermediate.*.nupkg - - # This is necessary whenever we want to publish/restore to an AzDO private feed - # Since sdk-task.ps1 tries to restore packages we need to do this authentication here - # otherwise it'll complain about accessing a private feed. - - task: NuGetAuthenticate@1 - displayName: 'Authenticate to AzDO Feeds' - - # Signing validation will optionally work with the buildmanifest file which is downloaded from - # Azure DevOps above. - - task: PowerShell@2 - displayName: Validate - inputs: - filePath: eng\common\sdk-task.ps1 - arguments: -task SigningValidation -restore -msbuildEngine vs - /p:PackageBasePath='$(Build.ArtifactStagingDirectory)/PackageArtifacts' - /p:SignCheckExclusionsFile='$(Build.SourcesDirectory)/eng/SignCheckExclusionsFile.txt' - ${{ parameters.signingValidationAdditionalParameters }} - - - template: ../steps/publish-logs.yml - parameters: - StageLabel: 'Validation' - JobLabel: 'Signing' - BinlogToolVersion: $(BinlogToolVersion) - - - job: - displayName: SourceLink Validation - condition: eq( ${{ parameters.enableSourceLinkValidation }}, 'true') - pool: - # We don't use the collection uri here because it might vary (.visualstudio.com vs. dev.azure.com) - ${{ if eq(variables['System.TeamProject'], 'DevDiv') }}: - name: AzurePipelines-EO - image: 1ESPT-Windows2022 - demands: Cmd - os: windows - # If it's not devdiv, it's dnceng - ${{ else }}: - name: $(DncEngInternalBuildPool) - image: 1es-windows-2022 - os: windows - steps: - - template: setup-maestro-vars.yml - parameters: - BARBuildId: ${{ parameters.BARBuildId }} - PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }} - - - task: DownloadBuildArtifacts@0 - displayName: Download Blob Artifacts - inputs: - buildType: specific - buildVersionToDownload: specific - project: $(AzDOProjectName) - pipeline: $(AzDOPipelineId) - buildId: $(AzDOBuildId) - artifactName: BlobArtifacts - checkDownloadedFiles: true - - - task: PowerShell@2 - displayName: Validate - inputs: - filePath: $(Build.SourcesDirectory)/eng/common/post-build/sourcelink-validation.ps1 - arguments: -InputPath $(Build.ArtifactStagingDirectory)/BlobArtifacts/ - -ExtractPath $(Agent.BuildDirectory)/Extract/ - -GHRepoName $(Build.Repository.Name) - -GHCommit $(Build.SourceVersion) - -SourcelinkCliVersion $(SourceLinkCLIVersion) - continueOnError: true - -- ${{ if ne(parameters.publishAssetsImmediately, 'true') }}: - - stage: publish_using_darc - ${{ if or(eq(parameters.enableNugetValidation, 'true'), eq(parameters.enableSigningValidation, 'true'), eq(parameters.enableSourceLinkValidation, 'true'), eq(parameters.SDLValidationParameters.enable, 'true')) }}: - dependsOn: ${{ parameters.publishDependsOn }} - ${{ else }}: - dependsOn: ${{ parameters.validateDependsOn }} - displayName: Publish using Darc - variables: - - template: common-variables.yml - - template: /eng/common/templates-official/variables/pool-providers.yml - jobs: - - job: - displayName: Publish Using Darc - timeoutInMinutes: 120 - pool: - # We don't use the collection uri here because it might vary (.visualstudio.com vs. dev.azure.com) - ${{ if eq(variables['System.TeamProject'], 'DevDiv') }}: - name: AzurePipelines-EO - image: 1ESPT-Windows2022 - demands: Cmd - os: windows - # If it's not devdiv, it's dnceng - ${{ else }}: - name: NetCore1ESPool-Publishing-Internal - image: windows.vs2019.amd64 - os: windows - steps: - - template: setup-maestro-vars.yml - parameters: - BARBuildId: ${{ parameters.BARBuildId }} - PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }} - - - task: NuGetAuthenticate@1 +- template: /eng/common/core-templates/post-build/post-build.yml + parameters: + # Specifies whether to use 1ES + is1ESPipeline: true - - task: PowerShell@2 - displayName: Publish Using Darc - inputs: - filePath: $(Build.SourcesDirectory)/eng/common/post-build/publish-using-darc.ps1 - arguments: -BuildId $(BARBuildId) - -PublishingInfraVersion ${{ parameters.publishingInfraVersion }} - -AzdoToken '$(publishing-dnceng-devdiv-code-r-build-re)' - -MaestroToken '$(MaestroApiAccessToken)' - -WaitPublishingFinish true - -ArtifactsPublishingAdditionalParameters '${{ parameters.artifactsPublishingAdditionalParameters }}' - -SymbolPublishingAdditionalParameters '${{ parameters.symbolPublishingAdditionalParameters }}' + ${{ each parameter in parameters }}: + ${{ parameter.key }}: ${{ parameter.value }} diff --git a/eng/common/templates-official/post-build/setup-maestro-vars.yml b/eng/common/templates-official/post-build/setup-maestro-vars.yml index 0c87f149a4ad77..024397d8786452 100644 --- a/eng/common/templates-official/post-build/setup-maestro-vars.yml +++ b/eng/common/templates-official/post-build/setup-maestro-vars.yml @@ -1,70 +1,8 @@ -parameters: - BARBuildId: '' - PromoteToChannelIds: '' - steps: - - ${{ if eq(coalesce(parameters.PromoteToChannelIds, 0), 0) }}: - - task: DownloadBuildArtifacts@0 - displayName: Download Release Configs - inputs: - buildType: current - artifactName: ReleaseConfigs - checkDownloadedFiles: true - - - task: PowerShell@2 - name: setReleaseVars - displayName: Set Release Configs Vars - inputs: - targetType: inline - pwsh: true - script: | - try { - if (!$Env:PromoteToMaestroChannels -or $Env:PromoteToMaestroChannels.Trim() -eq '') { - $Content = Get-Content $(Build.StagingDirectory)/ReleaseConfigs/ReleaseConfigs.txt - - $BarId = $Content | Select -Index 0 - $Channels = $Content | Select -Index 1 - $IsStableBuild = $Content | Select -Index 2 - - $AzureDevOpsProject = $Env:System_TeamProject - $AzureDevOpsBuildDefinitionId = $Env:System_DefinitionId - $AzureDevOpsBuildId = $Env:Build_BuildId - } - else { - $buildApiEndpoint = "${Env:MaestroApiEndPoint}/api/builds/${Env:BARBuildId}?api-version=${Env:MaestroApiVersion}" - - $apiHeaders = New-Object 'System.Collections.Generic.Dictionary[[String],[String]]' - $apiHeaders.Add('Accept', 'application/json') - $apiHeaders.Add('Authorization',"Bearer ${Env:MAESTRO_API_TOKEN}") - - $buildInfo = try { Invoke-WebRequest -Method Get -Uri $buildApiEndpoint -Headers $apiHeaders | ConvertFrom-Json } catch { Write-Host "Error: $_" } - - $BarId = $Env:BARBuildId - $Channels = $Env:PromoteToMaestroChannels -split "," - $Channels = $Channels -join "][" - $Channels = "[$Channels]" - - $IsStableBuild = $buildInfo.stable - $AzureDevOpsProject = $buildInfo.azureDevOpsProject - $AzureDevOpsBuildDefinitionId = $buildInfo.azureDevOpsBuildDefinitionId - $AzureDevOpsBuildId = $buildInfo.azureDevOpsBuildId - } - - Write-Host "##vso[task.setvariable variable=BARBuildId]$BarId" - Write-Host "##vso[task.setvariable variable=TargetChannels]$Channels" - Write-Host "##vso[task.setvariable variable=IsStableBuild]$IsStableBuild" +- template: /eng/common/core-templates/post-build/setup-maestro-vars.yml + parameters: + # Specifies whether to use 1ES + is1ESPipeline: true - Write-Host "##vso[task.setvariable variable=AzDOProjectName]$AzureDevOpsProject" - Write-Host "##vso[task.setvariable variable=AzDOPipelineId]$AzureDevOpsBuildDefinitionId" - Write-Host "##vso[task.setvariable variable=AzDOBuildId]$AzureDevOpsBuildId" - } - catch { - Write-Host $_ - Write-Host $_.Exception - Write-Host $_.ScriptStackTrace - exit 1 - } - env: - MAESTRO_API_TOKEN: $(MaestroApiAccessToken) - BARBuildId: ${{ parameters.BARBuildId }} - PromoteToMaestroChannels: ${{ parameters.PromoteToChannelIds }} + ${{ each parameter in parameters }}: + ${{ parameter.key }}: ${{ parameter.value }} \ No newline at end of file diff --git a/eng/common/templates-official/steps/add-build-to-channel.yml b/eng/common/templates-official/steps/add-build-to-channel.yml index f67a210d62f3e5..543dea8c6969a6 100644 --- a/eng/common/templates-official/steps/add-build-to-channel.yml +++ b/eng/common/templates-official/steps/add-build-to-channel.yml @@ -1,13 +1,7 @@ -parameters: - ChannelId: 0 - steps: -- task: PowerShell@2 - displayName: Add Build to Channel - inputs: - filePath: $(Build.SourcesDirectory)/eng/common/post-build/add-build-to-channel.ps1 - arguments: -BuildId $(BARBuildId) - -ChannelId ${{ parameters.ChannelId }} - -MaestroApiAccessToken $(MaestroApiAccessToken) - -MaestroApiEndPoint $(MaestroApiEndPoint) - -MaestroApiVersion $(MaestroApiVersion) +- template: /eng/common/core-templates/steps/add-build-to-channel.yml + parameters: + is1ESPipeline: true + + ${{ each parameter in parameters }}: + ${{ parameter.key }}: ${{ parameter.value }} diff --git a/eng/common/templates-official/steps/component-governance.yml b/eng/common/templates-official/steps/component-governance.yml index 0ecec47b0c9177..30bb3985ca2bf4 100644 --- a/eng/common/templates-official/steps/component-governance.yml +++ b/eng/common/templates-official/steps/component-governance.yml @@ -1,13 +1,7 @@ -parameters: - disableComponentGovernance: false - componentGovernanceIgnoreDirectories: '' - steps: -- ${{ if eq(parameters.disableComponentGovernance, 'true') }}: - - script: "echo ##vso[task.setvariable variable=skipComponentGovernanceDetection]true" - displayName: Set skipComponentGovernanceDetection variable -- ${{ if ne(parameters.disableComponentGovernance, 'true') }}: - - task: ComponentGovernanceComponentDetection@0 - continueOnError: true - inputs: - ignoreDirectories: ${{ parameters.componentGovernanceIgnoreDirectories }} \ No newline at end of file +- template: /eng/common/core-templates/steps/component-governance.yml + parameters: + is1ESPipeline: true + + ${{ each parameter in parameters }}: + ${{ parameter.key }}: ${{ parameter.value }} diff --git a/eng/common/templates-official/steps/generate-sbom.yml b/eng/common/templates-official/steps/generate-sbom.yml index 488b560e8ba4eb..9a89a4706d94e4 100644 --- a/eng/common/templates-official/steps/generate-sbom.yml +++ b/eng/common/templates-official/steps/generate-sbom.yml @@ -1,48 +1,7 @@ -# BuildDropPath - The root folder of the drop directory for which the manifest file will be generated. -# PackageName - The name of the package this SBOM represents. -# PackageVersion - The version of the package this SBOM represents. -# ManifestDirPath - The path of the directory where the generated manifest files will be placed -# IgnoreDirectories - Directories to ignore for SBOM generation. This will be passed through to the CG component detector. - -parameters: - PackageVersion: 7.0.0 - BuildDropPath: '$(Build.SourcesDirectory)/artifacts' - PackageName: '.NET' - ManifestDirPath: $(Build.ArtifactStagingDirectory)/sbom - IgnoreDirectories: '' - sbomContinueOnError: true - steps: -- task: PowerShell@2 - displayName: Prep for SBOM generation in (Non-linux) - condition: or(eq(variables['Agent.Os'], 'Windows_NT'), eq(variables['Agent.Os'], 'Darwin')) - inputs: - filePath: ./eng/common/generate-sbom-prep.ps1 - arguments: ${{parameters.manifestDirPath}} - -# Chmodding is a workaround for https://github.com/dotnet/arcade/issues/8461 -- script: | - chmod +x ./eng/common/generate-sbom-prep.sh - ./eng/common/generate-sbom-prep.sh ${{parameters.manifestDirPath}} - displayName: Prep for SBOM generation in (Linux) - condition: eq(variables['Agent.Os'], 'Linux') - continueOnError: ${{ parameters.sbomContinueOnError }} - -- task: AzureArtifacts.manifest-generator-task.manifest-generator-task.ManifestGeneratorTask@0 - displayName: 'Generate SBOM manifest' - continueOnError: ${{ parameters.sbomContinueOnError }} - inputs: - PackageName: ${{ parameters.packageName }} - BuildDropPath: ${{ parameters.buildDropPath }} - PackageVersion: ${{ parameters.packageVersion }} - ManifestDirPath: ${{ parameters.manifestDirPath }} - ${{ if ne(parameters.IgnoreDirectories, '') }}: - AdditionalComponentDetectorArgs: '--IgnoreDirectories ${{ parameters.IgnoreDirectories }}' - -- task: 1ES.PublishPipelineArtifact@1 - displayName: Publish SBOM manifest - continueOnError: ${{parameters.sbomContinueOnError}} - inputs: - targetPath: '${{parameters.manifestDirPath}}' - artifactName: $(ARTIFACT_NAME) +- template: /eng/common/core-templates/steps/generate-sbom.yml + parameters: + is1ESPipeline: true + ${{ each parameter in parameters }}: + ${{ parameter.key }}: ${{ parameter.value }} diff --git a/eng/common/templates-official/steps/publish-build-artifacts.yml b/eng/common/templates-official/steps/publish-build-artifacts.yml new file mode 100644 index 00000000000000..100a3fc98493cd --- /dev/null +++ b/eng/common/templates-official/steps/publish-build-artifacts.yml @@ -0,0 +1,41 @@ +parameters: +- name: displayName + type: string + default: 'Publish to Build Artifact' + +- name: condition + type: string + default: succeeded() + +- name: artifactName + type: string + +- name: pathToPublish + type: string + +- name: continueOnError + type: boolean + default: false + +- name: publishLocation + type: string + default: 'Container' + +- name: is1ESPipeline + type: boolean + default: true + +steps: +- ${{ if ne(parameters.is1ESPipeline, true) }}: + - 'eng/common/templates-official cannot be referenced from a non-1ES managed template': error +- task: 1ES.PublishBuildArtifacts@1 + displayName: ${{ parameters.displayName }} + condition: ${{ parameters.condition }} + ${{ if parameters.continueOnError }}: + continueOnError: ${{ parameters.continueOnError }} + inputs: + PublishLocation: ${{ parameters.publishLocation }} + PathtoPublish: ${{ parameters.pathToPublish }} + ${{ if parameters.artifactName }}: + ArtifactName: ${{ parameters.artifactName }} + diff --git a/eng/common/templates-official/steps/publish-logs.yml b/eng/common/templates-official/steps/publish-logs.yml index 84b2f559c56e40..579fd531e94c38 100644 --- a/eng/common/templates-official/steps/publish-logs.yml +++ b/eng/common/templates-official/steps/publish-logs.yml @@ -1,49 +1,7 @@ -parameters: - StageLabel: '' - JobLabel: '' - CustomSensitiveDataList: '' - # A default - in case value from eng/common/templates-official/post-build/common-variables.yml is not passed - BinlogToolVersion: '1.0.11' - steps: -- task: Powershell@2 - displayName: Prepare Binlogs to Upload - inputs: - targetType: inline - script: | - New-Item -ItemType Directory $(Build.SourcesDirectory)/PostBuildLogs/${{parameters.StageLabel}}/${{parameters.JobLabel}}/ - Move-Item -Path $(Build.SourcesDirectory)/artifacts/log/Debug/* $(Build.SourcesDirectory)/PostBuildLogs/${{parameters.StageLabel}}/${{parameters.JobLabel}}/ - continueOnError: true - condition: always() - -- task: PowerShell@2 - displayName: Redact Logs - inputs: - filePath: $(Build.SourcesDirectory)/eng/common/post-build/redact-logs.ps1 - # For now this needs to have explicit list of all sensitive data. Taken from eng/publishing/v3/publish.yml - # Sensitive data can as well be added to $(Build.SourcesDirectory)/eng/BinlogSecretsRedactionFile.txt' - # If the file exists - sensitive data for redaction will be sourced from it - # (single entry per line, lines starting with '# ' are considered comments and skipped) - arguments: -InputPath '$(Build.SourcesDirectory)/PostBuildLogs' - -BinlogToolVersion ${{parameters.BinlogToolVersion}} - -TokensFilePath '$(Build.SourcesDirectory)/eng/BinlogSecretsRedactionFile.txt' - '$(publishing-dnceng-devdiv-code-r-build-re)' - '$(MaestroAccessToken)' - '$(dn-bot-all-orgs-artifact-feeds-rw)' - '$(akams-client-id)' - '$(akams-client-secret)' - '$(microsoft-symbol-server-pat)' - '$(symweb-symbol-server-pat)' - '$(dn-bot-all-orgs-build-rw-code-rw)' - ${{parameters.CustomSensitiveDataList}} - continueOnError: true - condition: always() - -- task: 1ES.PublishBuildArtifacts@1 - displayName: Publish Logs - inputs: - PathtoPublish: '$(Build.SourcesDirectory)/PostBuildLogs' - PublishLocation: Container - ArtifactName: PostBuildLogs - continueOnError: true - condition: always() +- template: /eng/common/core-templates/steps/publish-logs.yml + parameters: + is1ESPipeline: true + + ${{ each parameter in parameters }}: + ${{ parameter.key }}: ${{ parameter.value }} diff --git a/eng/common/templates-official/steps/publish-pipeline-artifacts.yml b/eng/common/templates-official/steps/publish-pipeline-artifacts.yml new file mode 100644 index 00000000000000..15d74a9d91616d --- /dev/null +++ b/eng/common/templates-official/steps/publish-pipeline-artifacts.yml @@ -0,0 +1,26 @@ +parameters: +- name: is1ESPipeline + type: boolean + default: true + +- name: args + type: object + default: {} + +steps: +- ${{ if ne(parameters.is1ESPipeline, true) }}: + - 'eng/common/templates-official cannot be referenced from a non-1ES managed template': error +- task: 1ES.PublishPipelineArtifact@1 + displayName: ${{ coalesce(parameters.args.displayName, 'Publish to Build Artifact') }} + ${{ if parameters.args.condition }}: + condition: ${{ parameters.args.condition }} + ${{ else }}: + condition: succeeded() + ${{ if parameters.args.continueOnError }}: + continueOnError: ${{ parameters.args.continueOnError }} + inputs: + targetPath: ${{ parameters.args.targetPath }} + ${{ if parameters.args.artifactName }}: + artifactName: ${{ parameters.args.artifactName }} + ${{ if parameters.args.properties }}: + properties: ${{ properties.args.properties }} \ No newline at end of file diff --git a/eng/common/templates-official/steps/retain-build.yml b/eng/common/templates-official/steps/retain-build.yml index 83d97a26a01ff9..5594551508a3cf 100644 --- a/eng/common/templates-official/steps/retain-build.yml +++ b/eng/common/templates-official/steps/retain-build.yml @@ -1,28 +1,7 @@ -parameters: - # Optional azure devops PAT with build execute permissions for the build's organization, - # only needed if the build that should be retained ran on a different organization than - # the pipeline where this template is executing from - Token: '' - # Optional BuildId to retain, defaults to the current running build - BuildId: '' - # Azure devops Organization URI for the build in the https://dev.azure.com/ format. - # Defaults to the organization the current pipeline is running on - AzdoOrgUri: '$(System.CollectionUri)' - # Azure devops project for the build. Defaults to the project the current pipeline is running on - AzdoProject: '$(System.TeamProject)' - steps: - - task: powershell@2 - inputs: - targetType: 'filePath' - filePath: eng/common/retain-build.ps1 - pwsh: true - arguments: > - -AzdoOrgUri: ${{parameters.AzdoOrgUri}} - -AzdoProject ${{parameters.AzdoProject}} - -Token ${{coalesce(parameters.Token, '$env:SYSTEM_ACCESSTOKEN') }} - -BuildId ${{coalesce(parameters.BuildId, '$env:BUILD_ID')}} - displayName: Enable permanent build retention - env: - SYSTEM_ACCESSTOKEN: $(System.AccessToken) - BUILD_ID: $(Build.BuildId) \ No newline at end of file +- template: /eng/common/core-templates/steps/retain-build.yml + parameters: + is1ESPipeline: true + + ${{ each parameter in parameters }}: + ${{ parameter.key }}: ${{ parameter.value }} diff --git a/eng/common/templates-official/steps/send-to-helix.yml b/eng/common/templates-official/steps/send-to-helix.yml index 68fa739c4ab215..6500f21bf845ce 100644 --- a/eng/common/templates-official/steps/send-to-helix.yml +++ b/eng/common/templates-official/steps/send-to-helix.yml @@ -1,93 +1,7 @@ -# Please remember to update the documentation if you make changes to these parameters! -parameters: - HelixSource: 'pr/default' # required -- sources must start with pr/, official/, prodcon/, or agent/ - HelixType: 'tests/default/' # required -- Helix telemetry which identifies what type of data this is; should include "test" for clarity and must end in '/' - HelixBuild: $(Build.BuildNumber) # required -- the build number Helix will use to identify this -- automatically set to the AzDO build number - HelixTargetQueues: '' # required -- semicolon-delimited list of Helix queues to test on; see https://helix.dot.net/ for a list of queues - HelixAccessToken: '' # required -- access token to make Helix API requests; should be provided by the appropriate variable group - HelixProjectPath: 'eng/common/helixpublish.proj' # optional -- path to the project file to build relative to BUILD_SOURCESDIRECTORY - HelixProjectArguments: '' # optional -- arguments passed to the build command - HelixConfiguration: '' # optional -- additional property attached to a job - HelixPreCommands: '' # optional -- commands to run before Helix work item execution - HelixPostCommands: '' # optional -- commands to run after Helix work item execution - WorkItemDirectory: '' # optional -- a payload directory to zip up and send to Helix; requires WorkItemCommand; incompatible with XUnitProjects - WorkItemCommand: '' # optional -- a command to execute on the payload; requires WorkItemDirectory; incompatible with XUnitProjects - WorkItemTimeout: '' # optional -- a timeout in TimeSpan.Parse-ready value (e.g. 00:02:00) for the work item command; requires WorkItemDirectory; incompatible with XUnitProjects - CorrelationPayloadDirectory: '' # optional -- a directory to zip up and send to Helix as a correlation payload - XUnitProjects: '' # optional -- semicolon-delimited list of XUnitProjects to parse and send to Helix; requires XUnitRuntimeTargetFramework, XUnitPublishTargetFramework, XUnitRunnerVersion, and IncludeDotNetCli=true - XUnitWorkItemTimeout: '' # optional -- the workitem timeout in seconds for all workitems created from the xUnit projects specified by XUnitProjects - XUnitPublishTargetFramework: '' # optional -- framework to use to publish your xUnit projects - XUnitRuntimeTargetFramework: '' # optional -- framework to use for the xUnit console runner - XUnitRunnerVersion: '' # optional -- version of the xUnit nuget package you wish to use on Helix; required for XUnitProjects - IncludeDotNetCli: false # optional -- true will download a version of the .NET CLI onto the Helix machine as a correlation payload; requires DotNetCliPackageType and DotNetCliVersion - DotNetCliPackageType: '' # optional -- either 'sdk', 'runtime' or 'aspnetcore-runtime'; determines whether the sdk or runtime will be sent to Helix; see https://raw.githubusercontent.com/dotnet/core/main/release-notes/releases-index.json - DotNetCliVersion: '' # optional -- version of the CLI to send to Helix; based on this: https://raw.githubusercontent.com/dotnet/core/main/release-notes/releases-index.json - WaitForWorkItemCompletion: true # optional -- true will make the task wait until work items have been completed and fail the build if work items fail. False is "fire and forget." - IsExternal: false # [DEPRECATED] -- doesn't do anything, jobs are external if HelixAccessToken is empty and Creator is set - HelixBaseUri: 'https://helix.dot.net/' # optional -- sets the Helix API base URI (allows targeting https://helix.int-dot.net ) - Creator: '' # optional -- if the build is external, use this to specify who is sending the job - DisplayNamePrefix: 'Run Tests' # optional -- rename the beginning of the displayName of the steps in AzDO - condition: succeeded() # optional -- condition for step to execute; defaults to succeeded() - continueOnError: false # optional -- determines whether to continue the build if the step errors; defaults to false - steps: - - powershell: 'powershell "$env:BUILD_SOURCESDIRECTORY\eng\common\msbuild.ps1 $env:BUILD_SOURCESDIRECTORY/${{ parameters.HelixProjectPath }} /restore /p:TreatWarningsAsErrors=false ${{ parameters.HelixProjectArguments }} /t:Test /bl:$env:BUILD_SOURCESDIRECTORY\artifacts\log\$env:BuildConfig\SendToHelix.binlog"' - displayName: ${{ parameters.DisplayNamePrefix }} (Windows) - env: - BuildConfig: $(_BuildConfig) - HelixSource: ${{ parameters.HelixSource }} - HelixType: ${{ parameters.HelixType }} - HelixBuild: ${{ parameters.HelixBuild }} - HelixConfiguration: ${{ parameters.HelixConfiguration }} - HelixTargetQueues: ${{ parameters.HelixTargetQueues }} - HelixAccessToken: ${{ parameters.HelixAccessToken }} - HelixPreCommands: ${{ parameters.HelixPreCommands }} - HelixPostCommands: ${{ parameters.HelixPostCommands }} - WorkItemDirectory: ${{ parameters.WorkItemDirectory }} - WorkItemCommand: ${{ parameters.WorkItemCommand }} - WorkItemTimeout: ${{ parameters.WorkItemTimeout }} - CorrelationPayloadDirectory: ${{ parameters.CorrelationPayloadDirectory }} - XUnitProjects: ${{ parameters.XUnitProjects }} - XUnitWorkItemTimeout: ${{ parameters.XUnitWorkItemTimeout }} - XUnitPublishTargetFramework: ${{ parameters.XUnitPublishTargetFramework }} - XUnitRuntimeTargetFramework: ${{ parameters.XUnitRuntimeTargetFramework }} - XUnitRunnerVersion: ${{ parameters.XUnitRunnerVersion }} - IncludeDotNetCli: ${{ parameters.IncludeDotNetCli }} - DotNetCliPackageType: ${{ parameters.DotNetCliPackageType }} - DotNetCliVersion: ${{ parameters.DotNetCliVersion }} - WaitForWorkItemCompletion: ${{ parameters.WaitForWorkItemCompletion }} - HelixBaseUri: ${{ parameters.HelixBaseUri }} - Creator: ${{ parameters.Creator }} - SYSTEM_ACCESSTOKEN: $(System.AccessToken) - condition: and(${{ parameters.condition }}, eq(variables['Agent.Os'], 'Windows_NT')) - continueOnError: ${{ parameters.continueOnError }} - - script: $BUILD_SOURCESDIRECTORY/eng/common/msbuild.sh $BUILD_SOURCESDIRECTORY/${{ parameters.HelixProjectPath }} /restore /p:TreatWarningsAsErrors=false ${{ parameters.HelixProjectArguments }} /t:Test /bl:$BUILD_SOURCESDIRECTORY/artifacts/log/$BuildConfig/SendToHelix.binlog - displayName: ${{ parameters.DisplayNamePrefix }} (Unix) - env: - BuildConfig: $(_BuildConfig) - HelixSource: ${{ parameters.HelixSource }} - HelixType: ${{ parameters.HelixType }} - HelixBuild: ${{ parameters.HelixBuild }} - HelixConfiguration: ${{ parameters.HelixConfiguration }} - HelixTargetQueues: ${{ parameters.HelixTargetQueues }} - HelixAccessToken: ${{ parameters.HelixAccessToken }} - HelixPreCommands: ${{ parameters.HelixPreCommands }} - HelixPostCommands: ${{ parameters.HelixPostCommands }} - WorkItemDirectory: ${{ parameters.WorkItemDirectory }} - WorkItemCommand: ${{ parameters.WorkItemCommand }} - WorkItemTimeout: ${{ parameters.WorkItemTimeout }} - CorrelationPayloadDirectory: ${{ parameters.CorrelationPayloadDirectory }} - XUnitProjects: ${{ parameters.XUnitProjects }} - XUnitWorkItemTimeout: ${{ parameters.XUnitWorkItemTimeout }} - XUnitPublishTargetFramework: ${{ parameters.XUnitPublishTargetFramework }} - XUnitRuntimeTargetFramework: ${{ parameters.XUnitRuntimeTargetFramework }} - XUnitRunnerVersion: ${{ parameters.XUnitRunnerVersion }} - IncludeDotNetCli: ${{ parameters.IncludeDotNetCli }} - DotNetCliPackageType: ${{ parameters.DotNetCliPackageType }} - DotNetCliVersion: ${{ parameters.DotNetCliVersion }} - WaitForWorkItemCompletion: ${{ parameters.WaitForWorkItemCompletion }} - HelixBaseUri: ${{ parameters.HelixBaseUri }} - Creator: ${{ parameters.Creator }} - SYSTEM_ACCESSTOKEN: $(System.AccessToken) - condition: and(${{ parameters.condition }}, ne(variables['Agent.Os'], 'Windows_NT')) - continueOnError: ${{ parameters.continueOnError }} +- template: /eng/common/core-templates/steps/send-to-helix.yml + parameters: + is1ESPipeline: true + + ${{ each parameter in parameters }}: + ${{ parameter.key }}: ${{ parameter.value }} diff --git a/eng/common/templates-official/steps/source-build.yml b/eng/common/templates-official/steps/source-build.yml index 53ed57b6d48abc..8f92c49e7b06fc 100644 --- a/eng/common/templates-official/steps/source-build.yml +++ b/eng/common/templates-official/steps/source-build.yml @@ -1,131 +1,7 @@ -parameters: - # This template adds arcade-powered source-build to CI. - - # This is a 'steps' template, and is intended for advanced scenarios where the existing build - # infra has a careful build methodology that must be followed. For example, a repo - # (dotnet/runtime) might choose to clone the GitHub repo only once and store it as a pipeline - # artifact for all subsequent jobs to use, to reduce dependence on a strong network connection to - # GitHub. Using this steps template leaves room for that infra to be included. - - # Defines the platform on which to run the steps. See 'eng/common/templates-official/job/source-build.yml' - # for details. The entire object is described in the 'job' template for simplicity, even though - # the usage of the properties on this object is split between the 'job' and 'steps' templates. - platform: {} - steps: -# Build. Keep it self-contained for simple reusability. (No source-build-specific job variables.) -- script: | - set -x - df -h - - # If building on the internal project, the artifact feeds variable may be available (usually only if needed) - # In that case, call the feed setup script to add internal feeds corresponding to public ones. - # In addition, add an msbuild argument to copy the WIP from the repo to the target build location. - # This is because SetupNuGetSources.sh will alter the current NuGet.config file, and we need to preserve those - # changes. - internalRestoreArgs= - if [ '$(dn-bot-dnceng-artifact-feeds-rw)' != '$''(dn-bot-dnceng-artifact-feeds-rw)' ]; then - # Temporarily work around https://github.com/dotnet/arcade/issues/7709 - chmod +x $(Build.SourcesDirectory)/eng/common/SetupNugetSources.sh - $(Build.SourcesDirectory)/eng/common/SetupNugetSources.sh $(Build.SourcesDirectory)/NuGet.config $(dn-bot-dnceng-artifact-feeds-rw) - internalRestoreArgs='/p:CopyWipIntoInnerSourceBuildRepo=true' - - # The 'Copy WIP' feature of source build uses git stash to apply changes from the original repo. - # This only works if there is a username/email configured, which won't be the case in most CI runs. - git config --get user.email - if [ $? -ne 0 ]; then - git config user.email dn-bot@microsoft.com - git config user.name dn-bot - fi - fi - - # If building on the internal project, the internal storage variable may be available (usually only if needed) - # In that case, add variables to allow the download of internal runtimes if the specified versions are not found - # in the default public locations. - internalRuntimeDownloadArgs= - if [ '$(dotnetbuilds-internal-container-read-token-base64)' != '$''(dotnetbuilds-internal-container-read-token-base64)' ]; then - internalRuntimeDownloadArgs='/p:DotNetRuntimeSourceFeed=https://dotnetbuilds.blob.core.windows.net/internal /p:DotNetRuntimeSourceFeedKey=$(dotnetbuilds-internal-container-read-token-base64) --runtimesourcefeed https://dotnetbuilds.blob.core.windows.net/internal --runtimesourcefeedkey $(dotnetbuilds-internal-container-read-token-base64)' - fi - - buildConfig=Release - # Check if AzDO substitutes in a build config from a variable, and use it if so. - if [ '$(_BuildConfig)' != '$''(_BuildConfig)' ]; then - buildConfig='$(_BuildConfig)' - fi - - officialBuildArgs= - if [ '${{ and(ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest')) }}' = 'True' ]; then - officialBuildArgs='/p:DotNetPublishUsingPipelines=true /p:OfficialBuildId=$(BUILD.BUILDNUMBER)' - fi - - targetRidArgs= - if [ '${{ parameters.platform.targetRID }}' != '' ]; then - targetRidArgs='/p:TargetRid=${{ parameters.platform.targetRID }}' - fi - - runtimeOsArgs= - if [ '${{ parameters.platform.runtimeOS }}' != '' ]; then - runtimeOsArgs='/p:RuntimeOS=${{ parameters.platform.runtimeOS }}' - fi - - baseOsArgs= - if [ '${{ parameters.platform.baseOS }}' != '' ]; then - baseOsArgs='/p:BaseOS=${{ parameters.platform.baseOS }}' - fi - - publishArgs= - if [ '${{ parameters.platform.skipPublishValidation }}' != 'true' ]; then - publishArgs='--publish' - fi - - assetManifestFileName=SourceBuild_RidSpecific.xml - if [ '${{ parameters.platform.name }}' != '' ]; then - assetManifestFileName=SourceBuild_${{ parameters.platform.name }}.xml - fi - - ${{ coalesce(parameters.platform.buildScript, './build.sh') }} --ci \ - --configuration $buildConfig \ - --restore --build --pack $publishArgs -bl \ - $officialBuildArgs \ - $internalRuntimeDownloadArgs \ - $internalRestoreArgs \ - $targetRidArgs \ - $runtimeOsArgs \ - $baseOsArgs \ - /p:SourceBuildNonPortable=${{ parameters.platform.nonPortable }} \ - /p:ArcadeBuildFromSource=true \ - /p:DotNetBuildSourceOnly=true \ - /p:DotNetBuildRepo=true \ - /p:AssetManifestFileName=$assetManifestFileName - displayName: Build - -# Upload build logs for diagnosis. -- task: CopyFiles@2 - displayName: Prepare BuildLogs staging directory - inputs: - SourceFolder: '$(Build.SourcesDirectory)' - Contents: | - **/*.log - **/*.binlog - artifacts/sb/prebuilt-report/** - TargetFolder: '$(Build.StagingDirectory)/BuildLogs' - CleanTargetFolder: true - continueOnError: true - condition: succeededOrFailed() - -- task: 1ES.PublishPipelineArtifact@1 - displayName: Publish BuildLogs - inputs: - targetPath: '$(Build.StagingDirectory)/BuildLogs' - artifactName: BuildLogs_SourceBuild_${{ parameters.platform.name }}_Attempt$(System.JobAttempt) - continueOnError: true - condition: succeededOrFailed() +- template: /eng/common/core-templates/steps/source-build.yml + parameters: + is1ESPipeline: true -# Manually inject component detection so that we can ignore the source build upstream cache, which contains -# a nupkg cache of input packages (a local feed). -# This path must match the upstream cache path in property 'CurrentRepoSourceBuiltNupkgCacheDir' -# in src\Microsoft.DotNet.Arcade.Sdk\tools\SourceBuild\SourceBuildArcade.targets -- task: ComponentGovernanceComponentDetection@0 - displayName: Component Detection (Exclude upstream cache) - inputs: - ignoreDirectories: '$(Build.SourcesDirectory)/artifacts/sb/src/artifacts/obj/source-built-upstream-cache' + ${{ each parameter in parameters }}: + ${{ parameter.key }}: ${{ parameter.value }} diff --git a/eng/common/templates/job/execute-sdl.yml b/eng/common/templates/job/execute-sdl.yml deleted file mode 100644 index 7870f93bc17652..00000000000000 --- a/eng/common/templates/job/execute-sdl.yml +++ /dev/null @@ -1,139 +0,0 @@ -parameters: - enable: 'false' # Whether the SDL validation job should execute or not - overrideParameters: '' # Optional: to override values for parameters. - additionalParameters: '' # Optional: parameters that need user specific values eg: '-SourceToolsList @("abc","def") -ArtifactToolsList @("ghi","jkl")' - # Optional: if specified, restore and use this version of Guardian instead of the default. - overrideGuardianVersion: '' - # Optional: if true, publish the '.gdn' folder as a pipeline artifact. This can help with in-depth - # diagnosis of problems with specific tool configurations. - publishGuardianDirectoryToPipeline: false - # The script to run to execute all SDL tools. Use this if you want to use a script to define SDL - # parameters rather than relying on YAML. It may be better to use a local script, because you can - # reproduce results locally without piecing together a command based on the YAML. - executeAllSdlToolsScript: 'eng/common/sdl/execute-all-sdl-tools.ps1' - # There is some sort of bug (has been reported) in Azure DevOps where if this parameter is named - # 'continueOnError', the parameter value is not correctly picked up. - # This can also be remedied by the caller (post-build.yml) if it does not use a nested parameter - sdlContinueOnError: false # optional: determines whether to continue the build if the step errors; - # optional: determines if build artifacts should be downloaded. - downloadArtifacts: true - # optional: determines if this job should search the directory of downloaded artifacts for - # 'tar.gz' and 'zip' archive files and extract them before running SDL validation tasks. - extractArchiveArtifacts: false - dependsOn: '' # Optional: dependencies of the job - artifactNames: '' # Optional: patterns supplied to DownloadBuildArtifacts - # Usage: - # artifactNames: - # - 'BlobArtifacts' - # - 'Artifacts_Windows_NT_Release' - # Optional: download a list of pipeline artifacts. 'downloadArtifacts' controls build artifacts, - # not pipeline artifacts, so doesn't affect the use of this parameter. - pipelineArtifactNames: [] - -jobs: -- job: Run_SDL - dependsOn: ${{ parameters.dependsOn }} - displayName: Run SDL tool - condition: and(succeededOrFailed(), eq( ${{ parameters.enable }}, 'true')) - variables: - - group: DotNet-VSTS-Bot - - name: AzDOProjectName - value: ${{ parameters.AzDOProjectName }} - - name: AzDOPipelineId - value: ${{ parameters.AzDOPipelineId }} - - name: AzDOBuildId - value: ${{ parameters.AzDOBuildId }} - - template: /eng/common/templates/variables/sdl-variables.yml - - name: GuardianVersion - value: ${{ coalesce(parameters.overrideGuardianVersion, '$(DefaultGuardianVersion)') }} - - template: /eng/common/templates/variables/pool-providers.yml - pool: - # We don't use the collection uri here because it might vary (.visualstudio.com vs. dev.azure.com) - ${{ if eq(variables['System.TeamProject'], 'DevDiv') }}: - name: VSEngSS-MicroBuild2022-1ES - demands: Cmd - # If it's not devdiv, it's dnceng - ${{ if ne(variables['System.TeamProject'], 'DevDiv') }}: - name: $(DncEngInternalBuildPool) - demands: ImageOverride -equals windows.vs2019.amd64 - steps: - - checkout: self - clean: true - - # If the template caller didn't provide an AzDO parameter, set them all up as Maestro vars. - - ${{ if not(and(parameters.AzDOProjectName, parameters.AzDOPipelineId, parameters.AzDOBuildId)) }}: - - template: /eng/common/templates/post-build/setup-maestro-vars.yml - - - ${{ if ne(parameters.downloadArtifacts, 'false')}}: - - ${{ if ne(parameters.artifactNames, '') }}: - - ${{ each artifactName in parameters.artifactNames }}: - - task: DownloadBuildArtifacts@0 - displayName: Download Build Artifacts - inputs: - buildType: specific - buildVersionToDownload: specific - project: $(AzDOProjectName) - pipeline: $(AzDOPipelineId) - buildId: $(AzDOBuildId) - artifactName: ${{ artifactName }} - downloadPath: $(Build.ArtifactStagingDirectory)\artifacts - checkDownloadedFiles: true - - ${{ if eq(parameters.artifactNames, '') }}: - - task: DownloadBuildArtifacts@0 - displayName: Download Build Artifacts - inputs: - buildType: specific - buildVersionToDownload: specific - project: $(AzDOProjectName) - pipeline: $(AzDOPipelineId) - buildId: $(AzDOBuildId) - downloadType: specific files - itemPattern: "**" - downloadPath: $(Build.ArtifactStagingDirectory)\artifacts - checkDownloadedFiles: true - - - ${{ each artifactName in parameters.pipelineArtifactNames }}: - - task: DownloadPipelineArtifact@2 - displayName: Download Pipeline Artifacts - inputs: - buildType: specific - buildVersionToDownload: specific - project: $(AzDOProjectName) - pipeline: $(AzDOPipelineId) - buildId: $(AzDOBuildId) - artifactName: ${{ artifactName }} - downloadPath: $(Build.ArtifactStagingDirectory)\artifacts - checkDownloadedFiles: true - - - powershell: eng/common/sdl/trim-assets-version.ps1 - -InputPath $(Build.ArtifactStagingDirectory)\artifacts - displayName: Trim the version from the NuGet packages - continueOnError: ${{ parameters.sdlContinueOnError }} - - - powershell: eng/common/sdl/extract-artifact-packages.ps1 - -InputPath $(Build.ArtifactStagingDirectory)\artifacts\BlobArtifacts - -ExtractPath $(Build.ArtifactStagingDirectory)\artifacts\BlobArtifacts - displayName: Extract Blob Artifacts - continueOnError: ${{ parameters.sdlContinueOnError }} - - - powershell: eng/common/sdl/extract-artifact-packages.ps1 - -InputPath $(Build.ArtifactStagingDirectory)\artifacts\PackageArtifacts - -ExtractPath $(Build.ArtifactStagingDirectory)\artifacts\PackageArtifacts - displayName: Extract Package Artifacts - continueOnError: ${{ parameters.sdlContinueOnError }} - - - ${{ if ne(parameters.extractArchiveArtifacts, 'false') }}: - - powershell: eng/common/sdl/extract-artifact-archives.ps1 - -InputPath $(Build.ArtifactStagingDirectory)\artifacts - -ExtractPath $(Build.ArtifactStagingDirectory)\artifacts - displayName: Extract Archive Artifacts - continueOnError: ${{ parameters.sdlContinueOnError }} - - - template: /eng/common/templates/steps/execute-sdl.yml - parameters: - overrideGuardianVersion: ${{ parameters.overrideGuardianVersion }} - executeAllSdlToolsScript: ${{ parameters.executeAllSdlToolsScript }} - overrideParameters: ${{ parameters.overrideParameters }} - additionalParameters: ${{ parameters.additionalParameters }} - publishGuardianDirectoryToPipeline: ${{ parameters.publishGuardianDirectoryToPipeline }} - sdlContinueOnError: ${{ parameters.sdlContinueOnError }} diff --git a/eng/common/templates/job/job.yml b/eng/common/templates/job/job.yml index a3277bf15c51ff..1cf9a6d48127b6 100644 --- a/eng/common/templates/job/job.yml +++ b/eng/common/templates/job/job.yml @@ -1,259 +1,61 @@ -# Internal resources (telemetry, microbuild) can only be accessed from non-public projects, -# and some (Microbuild) should only be applied to non-PR cases for internal builds. - -parameters: -# Job schema parameters - https://docs.microsoft.com/en-us/azure/devops/pipelines/yaml-schema?view=vsts&tabs=schema#job - cancelTimeoutInMinutes: '' - condition: '' - container: '' - continueOnError: false - dependsOn: '' - displayName: '' - pool: '' - steps: [] - strategy: '' - timeoutInMinutes: '' - variables: [] - workspace: '' - templateContext: '' - -# Job base template specific parameters - # See schema documentation - https://github.com/dotnet/arcade/blob/master/Documentation/AzureDevOps/TemplateSchema.md - artifacts: '' - enableMicrobuild: false +parameters: enablePublishBuildArtifacts: false - enablePublishBuildAssets: false - enablePublishTestResults: false - enablePublishUsingPipelines: false - enableBuildRetry: false - disableComponentGovernance: '' - componentGovernanceIgnoreDirectories: '' - mergeTestResults: false - testRunTitle: '' - testResultsFormat: '' - name: '' - preSteps: [] - runAsPublic: false -# Sbom related params - enableSbom: true - PackageVersion: 7.0.0 - BuildDropPath: '$(Build.SourcesDirectory)/artifacts' jobs: -- job: ${{ parameters.name }} - - ${{ if ne(parameters.cancelTimeoutInMinutes, '') }}: - cancelTimeoutInMinutes: ${{ parameters.cancelTimeoutInMinutes }} - - ${{ if ne(parameters.condition, '') }}: - condition: ${{ parameters.condition }} - - ${{ if ne(parameters.container, '') }}: - container: ${{ parameters.container }} - - ${{ if ne(parameters.continueOnError, '') }}: - continueOnError: ${{ parameters.continueOnError }} - - ${{ if ne(parameters.dependsOn, '') }}: - dependsOn: ${{ parameters.dependsOn }} - - ${{ if ne(parameters.displayName, '') }}: - displayName: ${{ parameters.displayName }} - - ${{ if ne(parameters.pool, '') }}: - pool: ${{ parameters.pool }} - - ${{ if ne(parameters.strategy, '') }}: - strategy: ${{ parameters.strategy }} - - ${{ if ne(parameters.timeoutInMinutes, '') }}: - timeoutInMinutes: ${{ parameters.timeoutInMinutes }} - - ${{ if ne(parameters.templateContext, '') }}: - templateContext: ${{ parameters.templateContext }} - - variables: - - ${{ if ne(parameters.enableTelemetry, 'false') }}: - - name: DOTNET_CLI_TELEMETRY_PROFILE - value: '$(Build.Repository.Uri)' - - ${{ if eq(parameters.enableRichCodeNavigation, 'true') }}: - - name: EnableRichCodeNavigation - value: 'true' - # Retry signature validation up to three times, waiting 2 seconds between attempts. - # See https://learn.microsoft.com/en-us/nuget/reference/errors-and-warnings/nu3028#retry-untrusted-root-failures - - name: NUGET_EXPERIMENTAL_CHAIN_BUILD_RETRY_POLICY - value: 3,2000 - - ${{ each variable in parameters.variables }}: - # handle name-value variable syntax - # example: - # - name: [key] - # value: [value] - - ${{ if ne(variable.name, '') }}: - - name: ${{ variable.name }} - value: ${{ variable.value }} - - # handle variable groups - - ${{ if ne(variable.group, '') }}: - - group: ${{ variable.group }} - - # handle template variable syntax - # example: - # - template: path/to/template.yml - # parameters: - # [key]: [value] - - ${{ if ne(variable.template, '') }}: - - template: ${{ variable.template }} - ${{ if ne(variable.parameters, '') }}: - parameters: ${{ variable.parameters }} - - # handle key-value variable syntax. - # example: - # - [key]: [value] - - ${{ if and(eq(variable.name, ''), eq(variable.group, ''), eq(variable.template, '')) }}: - - ${{ each pair in variable }}: - - name: ${{ pair.key }} - value: ${{ pair.value }} - - # DotNet-HelixApi-Access provides 'HelixApiAccessToken' for internal builds - - ${{ if and(eq(parameters.enableTelemetry, 'true'), eq(parameters.runAsPublic, 'false'), ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest')) }}: - - group: DotNet-HelixApi-Access - - ${{ if ne(parameters.workspace, '') }}: - workspace: ${{ parameters.workspace }} - - steps: - - ${{ if ne(parameters.preSteps, '') }}: - - ${{ each preStep in parameters.preSteps }}: - - ${{ preStep }} - - - ${{ if and(eq(parameters.runAsPublic, 'false'), ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest')) }}: - - ${{ if eq(parameters.enableMicrobuild, 'true') }}: - - task: MicroBuildSigningPlugin@3 - displayName: Install MicroBuild plugin - inputs: - signType: $(_SignType) - zipSources: false - feedSource: https://dnceng.pkgs.visualstudio.com/_packaging/MicroBuildToolset/nuget/v3/index.json - env: - TeamName: $(_TeamName) - continueOnError: ${{ parameters.continueOnError }} - condition: and(succeeded(), in(variables['_SignType'], 'real', 'test'), eq(variables['Agent.Os'], 'Windows_NT')) - - - ${{ if and(eq(parameters.runAsPublic, 'false'), eq(variables['System.TeamProject'], 'internal')) }}: - - task: NuGetAuthenticate@1 - - - ${{ if and(ne(parameters.artifacts.download, 'false'), ne(parameters.artifacts.download, '')) }}: - - task: DownloadPipelineArtifact@2 - inputs: - buildType: current - artifactName: ${{ coalesce(parameters.artifacts.download.name, 'Artifacts_$(Agent.OS)_$(_BuildConfig)') }} - targetPath: ${{ coalesce(parameters.artifacts.download.path, 'artifacts') }} - itemPattern: ${{ coalesce(parameters.artifacts.download.pattern, '**') }} - - - ${{ each step in parameters.steps }}: - - ${{ step }} - - - ${{ if eq(parameters.enableRichCodeNavigation, true) }}: - - task: RichCodeNavIndexer@0 - displayName: RichCodeNav Upload - inputs: - languages: ${{ coalesce(parameters.richCodeNavigationLanguage, 'csharp') }} - environment: ${{ coalesce(parameters.richCodeNavigationEnvironment, 'internal') }} - richNavLogOutputDirectory: $(Build.SourcesDirectory)/artifacts/bin - uploadRichNavArtifacts: ${{ coalesce(parameters.richCodeNavigationUploadArtifacts, false) }} - continueOnError: true - - - template: /eng/common/templates/steps/component-governance.yml - parameters: - ${{ if eq(parameters.disableComponentGovernance, '') }}: - ${{ if and(ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest'), eq(parameters.runAsPublic, 'false'), or(startsWith(variables['Build.SourceBranch'], 'refs/heads/release/'), startsWith(variables['Build.SourceBranch'], 'refs/heads/dotnet/'), startsWith(variables['Build.SourceBranch'], 'refs/heads/microsoft/'), eq(variables['Build.SourceBranch'], 'refs/heads/main'))) }}: - disableComponentGovernance: false - ${{ else }}: - disableComponentGovernance: true - ${{ else }}: - disableComponentGovernance: ${{ parameters.disableComponentGovernance }} - componentGovernanceIgnoreDirectories: ${{ parameters.componentGovernanceIgnoreDirectories }} - - - ${{ if eq(parameters.enableMicrobuild, 'true') }}: - - ${{ if and(eq(parameters.runAsPublic, 'false'), ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest')) }}: - - task: MicroBuildCleanup@1 - displayName: Execute Microbuild cleanup tasks - condition: and(always(), in(variables['_SignType'], 'real', 'test'), eq(variables['Agent.Os'], 'Windows_NT')) - continueOnError: ${{ parameters.continueOnError }} - env: - TeamName: $(_TeamName) - - - ${{ if ne(parameters.artifacts.publish, '') }}: - - ${{ if and(ne(parameters.artifacts.publish.artifacts, 'false'), ne(parameters.artifacts.publish.artifacts, '')) }}: - - task: CopyFiles@2 - displayName: Gather binaries for publish to artifacts - inputs: - SourceFolder: 'artifacts/bin' - Contents: '**' - TargetFolder: '$(Build.ArtifactStagingDirectory)/artifacts/bin' - - task: CopyFiles@2 - displayName: Gather packages for publish to artifacts - inputs: - SourceFolder: 'artifacts/packages' - Contents: '**' - TargetFolder: '$(Build.ArtifactStagingDirectory)/artifacts/packages' - - task: PublishBuildArtifacts@1 - displayName: Publish pipeline artifacts - inputs: - PathtoPublish: '$(Build.ArtifactStagingDirectory)/artifacts' - PublishLocation: Container - ArtifactName: ${{ coalesce(parameters.artifacts.publish.artifacts.name , 'Artifacts_$(Agent.Os)_$(_BuildConfig)') }} - continueOnError: true - condition: always() - - ${{ if and(ne(parameters.artifacts.publish.logs, 'false'), ne(parameters.artifacts.publish.logs, '')) }}: - - publish: artifacts/log - artifact: ${{ coalesce(parameters.artifacts.publish.logs.name, 'Logs_Build_$(Agent.Os)_$(_BuildConfig)') }} - displayName: Publish logs - continueOnError: true - condition: always() - - - ${{ if ne(parameters.enablePublishBuildArtifacts, 'false') }}: - - task: PublishBuildArtifacts@1 - displayName: Publish Logs - inputs: - PathtoPublish: '$(Build.SourcesDirectory)/artifacts/log/$(_BuildConfig)' - PublishLocation: Container - ArtifactName: ${{ coalesce(parameters.enablePublishBuildArtifacts.artifactName, '$(Agent.Os)_$(Agent.JobName)' ) }} - continueOnError: true - condition: always() - - - ${{ if or(and(eq(parameters.enablePublishTestResults, 'true'), eq(parameters.testResultsFormat, '')), eq(parameters.testResultsFormat, 'xunit')) }}: - - task: PublishTestResults@2 - displayName: Publish XUnit Test Results - inputs: - testResultsFormat: 'xUnit' - testResultsFiles: '*.xml' - searchFolder: '$(Build.SourcesDirectory)/artifacts/TestResults/$(_BuildConfig)' - testRunTitle: ${{ coalesce(parameters.testRunTitle, parameters.name, '$(System.JobName)') }}-xunit - mergeTestResults: ${{ parameters.mergeTestResults }} - continueOnError: true - condition: always() - - ${{ if or(and(eq(parameters.enablePublishTestResults, 'true'), eq(parameters.testResultsFormat, '')), eq(parameters.testResultsFormat, 'vstest')) }}: - - task: PublishTestResults@2 - displayName: Publish TRX Test Results - inputs: - testResultsFormat: 'VSTest' - testResultsFiles: '*.trx' - searchFolder: '$(Build.SourcesDirectory)/artifacts/TestResults/$(_BuildConfig)' - testRunTitle: ${{ coalesce(parameters.testRunTitle, parameters.name, '$(System.JobName)') }}-trx - mergeTestResults: ${{ parameters.mergeTestResults }} - continueOnError: true - condition: always() - - - ${{ if and(eq(parameters.runAsPublic, 'false'), ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest'), eq(parameters.enableSbom, 'true')) }}: - - template: /eng/common/templates/steps/generate-sbom.yml - parameters: - PackageVersion: ${{ parameters.packageVersion}} - BuildDropPath: ${{ parameters.buildDropPath }} - IgnoreDirectories: ${{ parameters.componentGovernanceIgnoreDirectories }} - - - ${{ if eq(parameters.enableBuildRetry, 'true') }}: - - publish: $(Build.SourcesDirectory)\eng\common\BuildConfiguration - artifact: BuildConfiguration - displayName: Publish build retry configuration - continueOnError: true +- template: /eng/common/core-templates/job/job.yml + parameters: + is1ESPipeline: false + + ${{ each parameter in parameters }}: + ${{ if and(ne(parameter.key, 'steps'), ne(parameter.key, 'is1ESPipeline')) }}: + ${{ parameter.key }}: ${{ parameter.value }} + + steps: + - ${{ each step in parameters.steps }}: + - ${{ step }} + + artifactPublishSteps: + - ${{ if ne(parameters.artifacts.publish, '') }}: + - ${{ if and(ne(parameters.artifacts.publish.artifacts, 'false'), ne(parameters.artifacts.publish.artifacts, '')) }}: + - template: /eng/common/core-templates/steps/publish-build-artifacts.yml + parameters: + is1ESPipeline: false + args: + displayName: Publish pipeline artifacts + pathToPublish: '$(Build.ArtifactStagingDirectory)/artifacts' + publishLocation: Container + artifactName: ${{ coalesce(parameters.artifacts.publish.artifacts.name , 'Artifacts_$(Agent.Os)_$(_BuildConfig)') }} + continueOnError: true + condition: always() + - ${{ if and(ne(parameters.artifacts.publish.logs, 'false'), ne(parameters.artifacts.publish.logs, '')) }}: + - template: /eng/common/core-templates/steps/publish-pipeline-artifacts.yml + parameters: + is1ESPipeline: false + args: + targetPath: '$(Build.ArtifactStagingDirectory)/artifacts/log' + artifactName: ${{ coalesce(parameters.artifacts.publish.logs.name, 'Logs_Build_$(Agent.Os)_$(_BuildConfig)') }} + displayName: 'Publish logs' + continueOnError: true + condition: always() + + - ${{ if ne(parameters.enablePublishBuildArtifacts, 'false') }}: + - template: /eng/common/core-templates/steps/publish-build-artifacts.yml + parameters: + is1ESPipeline: false + args: + displayName: Publish Logs + pathToPublish: '$(Build.ArtifactStagingDirectory)/artifacts/log/$(_BuildConfig)' + publishLocation: Container + artifactName: ${{ coalesce(parameters.enablePublishBuildArtifacts.artifactName, '$(Agent.Os)_$(Agent.JobName)' ) }} + continueOnError: true + condition: always() + + - ${{ if eq(parameters.enableBuildRetry, 'true') }}: + - template: /eng/common/core-templates/steps/publish-pipeline-artifacts.yml + parameters: + is1ESPipeline: false + args: + targetPath: '$(Build.SourcesDirectory)\eng\common\BuildConfiguration' + artifactName: 'BuildConfiguration' + displayName: 'Publish build retry configuration' + continueOnError: true diff --git a/eng/common/templates/job/onelocbuild.yml b/eng/common/templates/job/onelocbuild.yml index 60ab00c4de3acd..ff829dc4c700c6 100644 --- a/eng/common/templates/job/onelocbuild.yml +++ b/eng/common/templates/job/onelocbuild.yml @@ -1,109 +1,7 @@ -parameters: - # Optional: dependencies of the job - dependsOn: '' - - # Optional: A defined YAML pool - https://docs.microsoft.com/en-us/azure/devops/pipelines/yaml-schema?view=vsts&tabs=schema#pool - pool: '' - - CeapexPat: $(dn-bot-ceapex-package-r) # PAT for the loc AzDO instance https://dev.azure.com/ceapex - GithubPat: $(BotAccount-dotnet-bot-repo-PAT) - - SourcesDirectory: $(Build.SourcesDirectory) - CreatePr: true - AutoCompletePr: false - ReusePr: true - UseLfLineEndings: true - UseCheckedInLocProjectJson: false - SkipLocProjectJsonGeneration: false - LanguageSet: VS_Main_Languages - LclSource: lclFilesInRepo - LclPackageId: '' - RepoType: gitHub - GitHubOrg: dotnet - MirrorRepo: '' - MirrorBranch: main - condition: '' - JobNameSuffix: '' - jobs: -- job: OneLocBuild${{ parameters.JobNameSuffix }} - - dependsOn: ${{ parameters.dependsOn }} - - displayName: OneLocBuild${{ parameters.JobNameSuffix }} - - variables: - - group: OneLocBuildVariables # Contains the CeapexPat and GithubPat - - name: _GenerateLocProjectArguments - value: -SourcesDirectory ${{ parameters.SourcesDirectory }} - -LanguageSet "${{ parameters.LanguageSet }}" - -CreateNeutralXlfs - - ${{ if eq(parameters.UseCheckedInLocProjectJson, 'true') }}: - - name: _GenerateLocProjectArguments - value: ${{ variables._GenerateLocProjectArguments }} -UseCheckedInLocProjectJson - - template: /eng/common/templates/variables/pool-providers.yml - - ${{ if ne(parameters.pool, '') }}: - pool: ${{ parameters.pool }} - ${{ if eq(parameters.pool, '') }}: - pool: - # We don't use the collection uri here because it might vary (.visualstudio.com vs. dev.azure.com) - ${{ if eq(variables['System.TeamProject'], 'DevDiv') }}: - name: VSEngSS-MicroBuild2022-1ES - demands: Cmd - # If it's not devdiv, it's dnceng - ${{ if ne(variables['System.TeamProject'], 'DevDiv') }}: - name: $(DncEngInternalBuildPool) - demands: ImageOverride -equals windows.vs2019.amd64 - - steps: - - ${{ if ne(parameters.SkipLocProjectJsonGeneration, 'true') }}: - - task: Powershell@2 - inputs: - filePath: $(Build.SourcesDirectory)/eng/common/generate-locproject.ps1 - arguments: $(_GenerateLocProjectArguments) - displayName: Generate LocProject.json - condition: ${{ parameters.condition }} - - - task: OneLocBuild@2 - displayName: OneLocBuild - env: - SYSTEM_ACCESSTOKEN: $(System.AccessToken) - inputs: - locProj: eng/Localize/LocProject.json - outDir: $(Build.ArtifactStagingDirectory) - lclSource: ${{ parameters.LclSource }} - lclPackageId: ${{ parameters.LclPackageId }} - isCreatePrSelected: ${{ parameters.CreatePr }} - isAutoCompletePrSelected: ${{ parameters.AutoCompletePr }} - ${{ if eq(parameters.CreatePr, true) }}: - isUseLfLineEndingsSelected: ${{ parameters.UseLfLineEndings }} - ${{ if eq(parameters.RepoType, 'gitHub') }}: - isShouldReusePrSelected: ${{ parameters.ReusePr }} - packageSourceAuth: patAuth - patVariable: ${{ parameters.CeapexPat }} - ${{ if eq(parameters.RepoType, 'gitHub') }}: - repoType: ${{ parameters.RepoType }} - gitHubPatVariable: "${{ parameters.GithubPat }}" - ${{ if ne(parameters.MirrorRepo, '') }}: - isMirrorRepoSelected: true - gitHubOrganization: ${{ parameters.GitHubOrg }} - mirrorRepo: ${{ parameters.MirrorRepo }} - mirrorBranch: ${{ parameters.MirrorBranch }} - condition: ${{ parameters.condition }} - - - task: PublishBuildArtifacts@1 - displayName: Publish Localization Files - inputs: - PathtoPublish: '$(Build.ArtifactStagingDirectory)/loc' - PublishLocation: Container - ArtifactName: Loc - condition: ${{ parameters.condition }} +- template: /eng/common/core-templates/job/onelocbuild.yml + parameters: + is1ESPipeline: false - - task: PublishBuildArtifacts@1 - displayName: Publish LocProject.json - inputs: - PathtoPublish: '$(Build.SourcesDirectory)/eng/Localize/' - PublishLocation: Container - ArtifactName: Loc - condition: ${{ parameters.condition }} \ No newline at end of file + ${{ each parameter in parameters }}: + ${{ parameter.key }}: ${{ parameter.value }} diff --git a/eng/common/templates/job/publish-build-assets.yml b/eng/common/templates/job/publish-build-assets.yml index bb42240f865b56..ab2edec2adb541 100644 --- a/eng/common/templates/job/publish-build-assets.yml +++ b/eng/common/templates/job/publish-build-assets.yml @@ -1,155 +1,7 @@ -parameters: - configuration: 'Debug' - - # Optional: condition for the job to run - condition: '' - - # Optional: 'true' if future jobs should run even if this job fails - continueOnError: false - - # Optional: dependencies of the job - dependsOn: '' - - # Optional: Include PublishBuildArtifacts task - enablePublishBuildArtifacts: false - - # Optional: A defined YAML pool - https://docs.microsoft.com/en-us/azure/devops/pipelines/yaml-schema?view=vsts&tabs=schema#pool - pool: {} - - # Optional: should run as a public build even in the internal project - # if 'true', the build won't run any of the internal only steps, even if it is running in non-public projects. - runAsPublic: false - - # Optional: whether the build's artifacts will be published using release pipelines or direct feed publishing - publishUsingPipelines: false - - # Optional: whether the build's artifacts will be published using release pipelines or direct feed publishing - publishAssetsImmediately: false - - artifactsPublishingAdditionalParameters: '' - - signingValidationAdditionalParameters: '' - jobs: -- job: Asset_Registry_Publish - - dependsOn: ${{ parameters.dependsOn }} - timeoutInMinutes: 150 - - ${{ if eq(parameters.publishAssetsImmediately, 'true') }}: - displayName: Publish Assets - ${{ else }}: - displayName: Publish to Build Asset Registry - - variables: - - template: /eng/common/templates/variables/pool-providers.yml - - ${{ if and(eq(parameters.runAsPublic, 'false'), ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest')) }}: - - group: Publish-Build-Assets - - group: AzureDevOps-Artifact-Feeds-Pats - - name: runCodesignValidationInjection - value: false - # unconditional - needed for logs publishing (redactor tool version) - - template: /eng/common/templates/post-build/common-variables.yml - - pool: - # We don't use the collection uri here because it might vary (.visualstudio.com vs. dev.azure.com) - ${{ if eq(variables['System.TeamProject'], 'DevDiv') }}: - name: VSEngSS-MicroBuild2022-1ES - demands: Cmd - # If it's not devdiv, it's dnceng - ${{ if ne(variables['System.TeamProject'], 'DevDiv') }}: - name: NetCore1ESPool-Publishing-Internal - demands: ImageOverride -equals windows.vs2019.amd64 - - steps: - - ${{ if and(eq(parameters.runAsPublic, 'false'), ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest')) }}: - - checkout: self - fetchDepth: 3 - clean: true - - - task: DownloadBuildArtifacts@0 - displayName: Download artifact - inputs: - artifactName: AssetManifests - downloadPath: '$(Build.StagingDirectory)/Download' - checkDownloadedFiles: true - condition: ${{ parameters.condition }} - continueOnError: ${{ parameters.continueOnError }} - - - task: NuGetAuthenticate@1 - - - task: PowerShell@2 - displayName: Publish Build Assets - inputs: - filePath: eng\common\sdk-task.ps1 - arguments: -task PublishBuildAssets -restore -msbuildEngine dotnet - /p:ManifestsPath='$(Build.StagingDirectory)/Download/AssetManifests' - /p:BuildAssetRegistryToken=$(MaestroAccessToken) - /p:MaestroApiEndpoint=https://maestro.dot.net - /p:PublishUsingPipelines=${{ parameters.publishUsingPipelines }} - /p:OfficialBuildId=$(Build.BuildNumber) - condition: ${{ parameters.condition }} - continueOnError: ${{ parameters.continueOnError }} - - - task: powershell@2 - displayName: Create ReleaseConfigs Artifact - inputs: - targetType: inline - script: | - Add-Content -Path "$(Build.StagingDirectory)/ReleaseConfigs.txt" -Value $(BARBuildId) - Add-Content -Path "$(Build.StagingDirectory)/ReleaseConfigs.txt" -Value "$(DefaultChannels)" - Add-Content -Path "$(Build.StagingDirectory)/ReleaseConfigs.txt" -Value $(IsStableBuild) - - - task: PublishBuildArtifacts@1 - displayName: Publish ReleaseConfigs Artifact - inputs: - PathtoPublish: '$(Build.StagingDirectory)/ReleaseConfigs.txt' - PublishLocation: Container - ArtifactName: ReleaseConfigs - - - task: powershell@2 - displayName: Check if SymbolPublishingExclusionsFile.txt exists - inputs: - targetType: inline - script: | - $symbolExclusionfile = "$(Build.SourcesDirectory)/eng/SymbolPublishingExclusionsFile.txt" - if(Test-Path -Path $symbolExclusionfile) - { - Write-Host "SymbolExclusionFile exists" - Write-Host "##vso[task.setvariable variable=SymbolExclusionFile]true" - } - else{ - Write-Host "Symbols Exclusion file does not exists" - Write-Host "##vso[task.setvariable variable=SymbolExclusionFile]false" - } - - - task: PublishBuildArtifacts@1 - displayName: Publish SymbolPublishingExclusionsFile Artifact - condition: eq(variables['SymbolExclusionFile'], 'true') - inputs: - PathtoPublish: '$(Build.SourcesDirectory)/eng/SymbolPublishingExclusionsFile.txt' - PublishLocation: Container - ArtifactName: ReleaseConfigs - - - ${{ if eq(parameters.publishAssetsImmediately, 'true') }}: - - template: /eng/common/templates/post-build/setup-maestro-vars.yml - parameters: - BARBuildId: ${{ parameters.BARBuildId }} - PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }} - - - task: PowerShell@2 - displayName: Publish Using Darc - inputs: - filePath: $(Build.SourcesDirectory)/eng/common/post-build/publish-using-darc.ps1 - arguments: -BuildId $(BARBuildId) - -PublishingInfraVersion 3 - -AzdoToken '$(publishing-dnceng-devdiv-code-r-build-re)' - -MaestroToken '$(MaestroApiAccessToken)' - -WaitPublishingFinish true - -ArtifactsPublishingAdditionalParameters '${{ parameters.artifactsPublishingAdditionalParameters }}' - -SymbolPublishingAdditionalParameters '${{ parameters.symbolPublishingAdditionalParameters }}' +- template: /eng/common/core-templates/job/publish-build-assets.yml + parameters: + is1ESPipeline: false - - ${{ if eq(parameters.enablePublishBuildArtifacts, 'true') }}: - - template: /eng/common/templates/steps/publish-logs.yml - parameters: - JobLabel: 'Publish_Artifacts_Logs' + ${{ each parameter in parameters }}: + ${{ parameter.key }}: ${{ parameter.value }} diff --git a/eng/common/templates/job/source-build.yml b/eng/common/templates/job/source-build.yml index d7ed209494c7be..e44d47b1d760c4 100644 --- a/eng/common/templates/job/source-build.yml +++ b/eng/common/templates/job/source-build.yml @@ -1,66 +1,7 @@ -parameters: - # This template adds arcade-powered source-build to CI. The template produces a server job with a - # default ID 'Source_Build_Complete' to put in a dependency list if necessary. - - # Specifies the prefix for source-build jobs added to pipeline. Use this if disambiguation needed. - jobNamePrefix: 'Source_Build' - - # Defines the platform on which to run the job. By default, a linux-x64 machine, suitable for - # managed-only repositories. This is an object with these properties: - # - # name: '' - # The name of the job. This is included in the job ID. - # targetRID: '' - # The name of the target RID to use, instead of the one auto-detected by Arcade. - # nonPortable: false - # Enables non-portable mode. This means a more specific RID (e.g. fedora.32-x64 rather than - # linux-x64), and compiling against distro-provided packages rather than portable ones. - # skipPublishValidation: false - # Disables publishing validation. By default, a check is performed to ensure no packages are - # published by source-build. - # container: '' - # A container to use. Runs in docker. - # pool: {} - # A pool to use. Runs directly on an agent. - # buildScript: '' - # Specifies the build script to invoke to perform the build in the repo. The default - # './build.sh' should work for typical Arcade repositories, but this is customizable for - # difficult situations. - # jobProperties: {} - # A list of job properties to inject at the top level, for potential extensibility beyond - # container and pool. - platform: {} - jobs: -- job: ${{ parameters.jobNamePrefix }}_${{ parameters.platform.name }} - displayName: Source-Build (${{ parameters.platform.name }}) - - ${{ each property in parameters.platform.jobProperties }}: - ${{ property.key }}: ${{ property.value }} - - ${{ if ne(parameters.platform.container, '') }}: - container: ${{ parameters.platform.container }} - - ${{ if eq(parameters.platform.pool, '') }}: - # The default VM host AzDO pool. This should be capable of running Docker containers: almost all - # source-build builds run in Docker, including the default managed platform. - # /eng/common/templates/variables/pool-providers.yml can't be used here (some customers declare variables already), so duplicate its logic - pool: - ${{ if eq(variables['System.TeamProject'], 'public') }}: - name: $[replace(replace(eq(contains(coalesce(variables['System.PullRequest.TargetBranch'], variables['Build.SourceBranch'], 'refs/heads/main'), 'release'), 'true'), True, 'NetCore-Svc-Public' ), False, 'NetCore-Public')] - demands: ImageOverride -equals Build.Ubuntu.2204.Amd64.Open - - ${{ if eq(variables['System.TeamProject'], 'internal') }}: - name: $[replace(replace(eq(contains(coalesce(variables['System.PullRequest.TargetBranch'], variables['Build.SourceBranch'], 'refs/heads/main'), 'release'), 'true'), True, 'NetCore1ESPool-Svc-Internal'), False, 'NetCore1ESPool-Internal')] - demands: ImageOverride -equals Build.Ubuntu.2204.Amd64 - - ${{ if ne(parameters.platform.pool, '') }}: - pool: ${{ parameters.platform.pool }} - - workspace: - clean: all +- template: /eng/common/core-templates/job/source-build.yml + parameters: + is1ESPipeline: false - steps: - - template: /eng/common/templates/steps/source-build.yml - parameters: - platform: ${{ parameters.platform }} + ${{ each parameter in parameters }}: + ${{ parameter.key }}: ${{ parameter.value }} diff --git a/eng/common/templates/job/source-index-stage1.yml b/eng/common/templates/job/source-index-stage1.yml index b5a3e5c4a6c847..89f3291593cb78 100644 --- a/eng/common/templates/job/source-index-stage1.yml +++ b/eng/common/templates/job/source-index-stage1.yml @@ -1,67 +1,7 @@ -parameters: - runAsPublic: false - sourceIndexPackageVersion: 1.0.1-20240129.2 - sourceIndexPackageSource: https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools/nuget/v3/index.json - sourceIndexBuildCommand: powershell -NoLogo -NoProfile -ExecutionPolicy Bypass -Command "eng/common/build.ps1 -restore -build -binarylog -ci" - preSteps: [] - binlogPath: artifacts/log/Debug/Build.binlog - condition: '' - dependsOn: '' - pool: '' - jobs: -- job: SourceIndexStage1 - dependsOn: ${{ parameters.dependsOn }} - condition: ${{ parameters.condition }} - variables: - - name: SourceIndexPackageVersion - value: ${{ parameters.sourceIndexPackageVersion }} - - name: SourceIndexPackageSource - value: ${{ parameters.sourceIndexPackageSource }} - - name: BinlogPath - value: ${{ parameters.binlogPath }} - - ${{ if and(eq(parameters.runAsPublic, 'false'), ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest')) }}: - - group: source-dot-net stage1 variables - - template: /eng/common/templates/variables/pool-providers.yml - - ${{ if ne(parameters.pool, '') }}: - pool: ${{ parameters.pool }} - ${{ if eq(parameters.pool, '') }}: - pool: - ${{ if eq(variables['System.TeamProject'], 'public') }}: - name: $(DncEngPublicBuildPool) - demands: ImageOverride -equals windows.vs2022.amd64.open - ${{ if eq(variables['System.TeamProject'], 'internal') }}: - name: $(DncEngInternalBuildPool) - demands: ImageOverride -equals windows.vs2022.amd64 - - steps: - - ${{ each preStep in parameters.preSteps }}: - - ${{ preStep }} - - - task: UseDotNet@2 - displayName: Use .NET 8 SDK - inputs: - packageType: sdk - version: 8.0.x - installationPath: $(Agent.TempDirectory)/dotnet - workingDirectory: $(Agent.TempDirectory) - - - script: | - $(Agent.TempDirectory)/dotnet/dotnet tool install BinLogToSln --version $(SourceIndexPackageVersion) --add-source $(SourceIndexPackageSource) --tool-path $(Agent.TempDirectory)/.source-index/tools - $(Agent.TempDirectory)/dotnet/dotnet tool install UploadIndexStage1 --version $(SourceIndexPackageVersion) --add-source $(SourceIndexPackageSource) --tool-path $(Agent.TempDirectory)/.source-index/tools - displayName: Download Tools - # Set working directory to temp directory so 'dotnet' doesn't try to use global.json and use the repo's sdk. - workingDirectory: $(Agent.TempDirectory) - - - script: ${{ parameters.sourceIndexBuildCommand }} - displayName: Build Repository - - - script: $(Agent.TempDirectory)/.source-index/tools/BinLogToSln -i $(BinlogPath) -r $(Build.SourcesDirectory) -n $(Build.Repository.Name) -o .source-index/stage1output - displayName: Process Binlog into indexable sln +- template: /eng/common/core-templates/job/source-index-stage1.yml + parameters: + is1ESPipeline: false - - ${{ if and(eq(parameters.runAsPublic, 'false'), ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest')) }}: - - script: $(Agent.TempDirectory)/.source-index/tools/UploadIndexStage1 -i .source-index/stage1output -n $(Build.Repository.Name) - displayName: Upload stage1 artifacts to source index - env: - BLOB_CONTAINER_URL: $(source-dot-net-stage1-blob-container-url) + ${{ each parameter in parameters }}: + ${{ parameter.key }}: ${{ parameter.value }} diff --git a/eng/common/templates/jobs/codeql-build.yml b/eng/common/templates/jobs/codeql-build.yml index f7dc5ea4aaa63c..517f24d6a52ce7 100644 --- a/eng/common/templates/jobs/codeql-build.yml +++ b/eng/common/templates/jobs/codeql-build.yml @@ -1,31 +1,7 @@ -parameters: - # See schema documentation in /Documentation/AzureDevOps/TemplateSchema.md - continueOnError: false - # Required: A collection of jobs to run - https://docs.microsoft.com/en-us/azure/devops/pipelines/yaml-schema?view=vsts&tabs=schema#job - jobs: [] - # Optional: if specified, restore and use this version of Guardian instead of the default. - overrideGuardianVersion: '' - jobs: -- template: /eng/common/templates/jobs/jobs.yml +- template: /eng/common/core-templates/jobs/codeql-build.yml parameters: - enableMicrobuild: false - enablePublishBuildArtifacts: false - enablePublishTestResults: false - enablePublishBuildAssets: false - enablePublishUsingPipelines: false - enableTelemetry: true + is1ESPipeline: false - variables: - - group: Publish-Build-Assets - # The Guardian version specified in 'eng/common/sdl/packages.config'. This value must be kept in - # sync with the packages.config file. - - name: DefaultGuardianVersion - value: 0.109.0 - - name: GuardianPackagesConfigFile - value: $(Build.SourcesDirectory)\eng\common\sdl\packages.config - - name: GuardianVersion - value: ${{ coalesce(parameters.overrideGuardianVersion, '$(DefaultGuardianVersion)') }} - - jobs: ${{ parameters.jobs }} - + ${{ each parameter in parameters }}: + ${{ parameter.key }}: ${{ parameter.value }} diff --git a/eng/common/templates/jobs/jobs.yml b/eng/common/templates/jobs/jobs.yml index 289bb2396ce83e..388e9037b3e601 100644 --- a/eng/common/templates/jobs/jobs.yml +++ b/eng/common/templates/jobs/jobs.yml @@ -1,97 +1,7 @@ -parameters: - # See schema documentation in /Documentation/AzureDevOps/TemplateSchema.md - continueOnError: false - - # Optional: Include PublishBuildArtifacts task - enablePublishBuildArtifacts: false - - # Optional: Enable publishing using release pipelines - enablePublishUsingPipelines: false - - # Optional: Enable running the source-build jobs to build repo from source - enableSourceBuild: false - - # Optional: Parameters for source-build template. - # See /eng/common/templates/jobs/source-build.yml for options - sourceBuildParameters: [] - - graphFileGeneration: - # Optional: Enable generating the graph files at the end of the build - enabled: false - # Optional: Include toolset dependencies in the generated graph files - includeToolset: false - - # Required: A collection of jobs to run - https://docs.microsoft.com/en-us/azure/devops/pipelines/yaml-schema?view=vsts&tabs=schema#job - jobs: [] - - # Optional: Override automatically derived dependsOn value for "publish build assets" job - publishBuildAssetsDependsOn: '' - - # Optional: Publish the assets as soon as the publish to BAR stage is complete, rather doing so in a separate stage. - publishAssetsImmediately: false - - # Optional: If using publishAssetsImmediately and additional parameters are needed, can be used to send along additional parameters (normally sent to post-build.yml) - artifactsPublishingAdditionalParameters: '' - signingValidationAdditionalParameters: '' - - # Optional: should run as a public build even in the internal project - # if 'true', the build won't run any of the internal only steps, even if it is running in non-public projects. - runAsPublic: false - - enableSourceIndex: false - sourceIndexParams: {} - -# Internal resources (telemetry, microbuild) can only be accessed from non-public projects, -# and some (Microbuild) should only be applied to non-PR cases for internal builds. - jobs: -- ${{ each job in parameters.jobs }}: - - template: ../job/job.yml - parameters: - # pass along parameters - ${{ each parameter in parameters }}: - ${{ if ne(parameter.key, 'jobs') }}: - ${{ parameter.key }}: ${{ parameter.value }} - - # pass along job properties - ${{ each property in job }}: - ${{ if ne(property.key, 'job') }}: - ${{ property.key }}: ${{ property.value }} - - name: ${{ job.job }} - -- ${{ if eq(parameters.enableSourceBuild, true) }}: - - template: /eng/common/templates/jobs/source-build.yml - parameters: - allCompletedJobId: Source_Build_Complete - ${{ each parameter in parameters.sourceBuildParameters }}: - ${{ parameter.key }}: ${{ parameter.value }} - -- ${{ if eq(parameters.enableSourceIndex, 'true') }}: - - template: ../job/source-index-stage1.yml - parameters: - runAsPublic: ${{ parameters.runAsPublic }} - ${{ each parameter in parameters.sourceIndexParams }}: - ${{ parameter.key }}: ${{ parameter.value }} - -- ${{ if and(eq(parameters.runAsPublic, 'false'), ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest')) }}: - - ${{ if or(eq(parameters.enablePublishBuildAssets, true), eq(parameters.artifacts.publish.manifests, 'true'), ne(parameters.artifacts.publish.manifests, '')) }}: - - template: ../job/publish-build-assets.yml - parameters: - continueOnError: ${{ parameters.continueOnError }} - dependsOn: - - ${{ if ne(parameters.publishBuildAssetsDependsOn, '') }}: - - ${{ each job in parameters.publishBuildAssetsDependsOn }}: - - ${{ job.job }} - - ${{ if eq(parameters.publishBuildAssetsDependsOn, '') }}: - - ${{ each job in parameters.jobs }}: - - ${{ job.job }} - - ${{ if eq(parameters.enableSourceBuild, true) }}: - - Source_Build_Complete +- template: /eng/common/core-templates/jobs/jobs.yml + parameters: + is1ESPipeline: false - runAsPublic: ${{ parameters.runAsPublic }} - publishUsingPipelines: ${{ parameters.enablePublishUsingPipelines }} - publishAssetsImmediately: ${{ parameters.publishAssetsImmediately }} - enablePublishBuildArtifacts: ${{ parameters.enablePublishBuildArtifacts }} - artifactsPublishingAdditionalParameters: ${{ parameters.artifactsPublishingAdditionalParameters }} - signingValidationAdditionalParameters: ${{ parameters.signingValidationAdditionalParameters }} + ${{ each parameter in parameters }}: + ${{ parameter.key }}: ${{ parameter.value }} diff --git a/eng/common/templates/jobs/source-build.yml b/eng/common/templates/jobs/source-build.yml index da91481ff1d286..818d4c326dbbf1 100644 --- a/eng/common/templates/jobs/source-build.yml +++ b/eng/common/templates/jobs/source-build.yml @@ -1,46 +1,7 @@ -parameters: - # This template adds arcade-powered source-build to CI. A job is created for each platform, as - # well as an optional server job that completes when all platform jobs complete. - - # The name of the "join" job for all source-build platforms. If set to empty string, the job is - # not included. Existing repo pipelines can use this job depend on all source-build jobs - # completing without maintaining a separate list of every single job ID: just depend on this one - # server job. By default, not included. Recommended name if used: 'Source_Build_Complete'. - allCompletedJobId: '' - - # See /eng/common/templates/job/source-build.yml - jobNamePrefix: 'Source_Build' - - # This is the default platform provided by Arcade, intended for use by a managed-only repo. - defaultManagedPlatform: - name: 'Managed' - container: 'mcr.microsoft.com/dotnet-buildtools/prereqs:centos-stream9' - - # Defines the platforms on which to run build jobs. One job is created for each platform, and the - # object in this array is sent to the job template as 'platform'. If no platforms are specified, - # one job runs on 'defaultManagedPlatform'. - platforms: [] - jobs: +- template: /eng/common/core-templates/jobs/source-build.yml + parameters: + is1ESPipeline: false -- ${{ if ne(parameters.allCompletedJobId, '') }}: - - job: ${{ parameters.allCompletedJobId }} - displayName: Source-Build Complete - pool: server - dependsOn: - - ${{ each platform in parameters.platforms }}: - - ${{ parameters.jobNamePrefix }}_${{ platform.name }} - - ${{ if eq(length(parameters.platforms), 0) }}: - - ${{ parameters.jobNamePrefix }}_${{ parameters.defaultManagedPlatform.name }} - -- ${{ each platform in parameters.platforms }}: - - template: /eng/common/templates/job/source-build.yml - parameters: - jobNamePrefix: ${{ parameters.jobNamePrefix }} - platform: ${{ platform }} - -- ${{ if eq(length(parameters.platforms), 0) }}: - - template: /eng/common/templates/job/source-build.yml - parameters: - jobNamePrefix: ${{ parameters.jobNamePrefix }} - platform: ${{ parameters.defaultManagedPlatform }} + ${{ each parameter in parameters }}: + ${{ parameter.key }}: ${{ parameter.value }} \ No newline at end of file diff --git a/eng/common/templates/post-build/common-variables.yml b/eng/common/templates/post-build/common-variables.yml index b9ede10bf099ae..7fa105875592c8 100644 --- a/eng/common/templates/post-build/common-variables.yml +++ b/eng/common/templates/post-build/common-variables.yml @@ -1,24 +1,8 @@ variables: - - group: Publish-Build-Assets +- template: /eng/common/core-templates/post-build/common-variables.yml + parameters: + # Specifies whether to use 1ES + is1ESPipeline: false - # Whether the build is internal or not - - name: IsInternalBuild - value: ${{ and(ne(variables['System.TeamProject'], 'public'), contains(variables['Build.SourceBranch'], 'internal')) }} - - # Default Maestro++ API Endpoint and API Version - - name: MaestroApiEndPoint - value: "https://maestro.dot.net" - - name: MaestroApiAccessToken - value: $(MaestroAccessToken) - - name: MaestroApiVersion - value: "2020-02-20" - - - name: SourceLinkCLIVersion - value: 3.0.0 - - name: SymbolToolVersion - value: 1.0.1 - - name: BinlogToolVersion - value: 1.0.11 - - - name: runCodesignValidationInjection - value: false + ${{ each parameter in parameters }}: + ${{ parameter.key }}: ${{ parameter.value }} \ No newline at end of file diff --git a/eng/common/templates/post-build/post-build.yml b/eng/common/templates/post-build/post-build.yml index ee70e2b399c5a9..53ede714bdd207 100644 --- a/eng/common/templates/post-build/post-build.yml +++ b/eng/common/templates/post-build/post-build.yml @@ -1,282 +1,8 @@ -parameters: - # Which publishing infra should be used. THIS SHOULD MATCH THE VERSION ON THE BUILD MANIFEST. - # Publishing V1 is no longer supported - # Publishing V2 is no longer supported - # Publishing V3 is the default - - name: publishingInfraVersion - displayName: Which version of publishing should be used to promote the build definition? - type: number - default: 3 - values: - - 3 - - - name: BARBuildId - displayName: BAR Build Id - type: number - default: 0 - - - name: PromoteToChannelIds - displayName: Channel to promote BARBuildId to - type: string - default: '' - - - name: enableSourceLinkValidation - displayName: Enable SourceLink validation - type: boolean - default: false - - - name: enableSigningValidation - displayName: Enable signing validation - type: boolean - default: true - - - name: enableSymbolValidation - displayName: Enable symbol validation - type: boolean - default: false - - - name: enableNugetValidation - displayName: Enable NuGet validation - type: boolean - default: true - - - name: publishInstallersAndChecksums - displayName: Publish installers and checksums - type: boolean - default: true - - - name: SDLValidationParameters - type: object - default: - enable: false - publishGdn: false - continueOnError: false - params: '' - artifactNames: '' - downloadArtifacts: true - - # These parameters let the user customize the call to sdk-task.ps1 for publishing - # symbols & general artifacts as well as for signing validation - - name: symbolPublishingAdditionalParameters - displayName: Symbol publishing additional parameters - type: string - default: '' - - - name: artifactsPublishingAdditionalParameters - displayName: Artifact publishing additional parameters - type: string - default: '' - - - name: signingValidationAdditionalParameters - displayName: Signing validation additional parameters - type: string - default: '' - - # Which stages should finish execution before post-build stages start - - name: validateDependsOn - type: object - default: - - build - - - name: publishDependsOn - type: object - default: - - Validate - - # Optional: Call asset publishing rather than running in a separate stage - - name: publishAssetsImmediately - type: boolean - default: false - stages: -- ${{ if or(eq( parameters.enableNugetValidation, 'true'), eq(parameters.enableSigningValidation, 'true'), eq(parameters.enableSourceLinkValidation, 'true'), eq(parameters.SDLValidationParameters.enable, 'true')) }}: - - stage: Validate - dependsOn: ${{ parameters.validateDependsOn }} - displayName: Validate Build Assets - variables: - - template: common-variables.yml - - template: /eng/common/templates/variables/pool-providers.yml - jobs: - - job: - displayName: NuGet Validation - condition: and(succeededOrFailed(), eq( ${{ parameters.enableNugetValidation }}, 'true')) - pool: - # We don't use the collection uri here because it might vary (.visualstudio.com vs. dev.azure.com) - ${{ if eq(variables['System.TeamProject'], 'DevDiv') }}: - name: VSEngSS-MicroBuild2022-1ES - demands: Cmd - # If it's not devdiv, it's dnceng - ${{ else }}: - name: $(DncEngInternalBuildPool) - demands: ImageOverride -equals windows.vs2019.amd64 - - steps: - - template: setup-maestro-vars.yml - parameters: - BARBuildId: ${{ parameters.BARBuildId }} - PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }} - - - task: DownloadBuildArtifacts@0 - displayName: Download Package Artifacts - inputs: - buildType: specific - buildVersionToDownload: specific - project: $(AzDOProjectName) - pipeline: $(AzDOPipelineId) - buildId: $(AzDOBuildId) - artifactName: PackageArtifacts - checkDownloadedFiles: true - - - task: PowerShell@2 - displayName: Validate - inputs: - filePath: $(Build.SourcesDirectory)/eng/common/post-build/nuget-validation.ps1 - arguments: -PackagesPath $(Build.ArtifactStagingDirectory)/PackageArtifacts/ - -ToolDestinationPath $(Agent.BuildDirectory)/Extract/ - - - job: - displayName: Signing Validation - condition: and( eq( ${{ parameters.enableSigningValidation }}, 'true'), ne( variables['PostBuildSign'], 'true')) - pool: - # We don't use the collection uri here because it might vary (.visualstudio.com vs. dev.azure.com) - ${{ if eq(variables['System.TeamProject'], 'DevDiv') }}: - name: VSEngSS-MicroBuild2022-1ES - demands: Cmd - # If it's not devdiv, it's dnceng - ${{ else }}: - name: $(DncEngInternalBuildPool) - demands: ImageOverride -equals windows.vs2019.amd64 - steps: - - template: setup-maestro-vars.yml - parameters: - BARBuildId: ${{ parameters.BARBuildId }} - PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }} - - - task: DownloadBuildArtifacts@0 - displayName: Download Package Artifacts - inputs: - buildType: specific - buildVersionToDownload: specific - project: $(AzDOProjectName) - pipeline: $(AzDOPipelineId) - buildId: $(AzDOBuildId) - artifactName: PackageArtifacts - checkDownloadedFiles: true - itemPattern: | - ** - !**/Microsoft.SourceBuild.Intermediate.*.nupkg - - # This is necessary whenever we want to publish/restore to an AzDO private feed - # Since sdk-task.ps1 tries to restore packages we need to do this authentication here - # otherwise it'll complain about accessing a private feed. - - task: NuGetAuthenticate@1 - displayName: 'Authenticate to AzDO Feeds' - - # Signing validation will optionally work with the buildmanifest file which is downloaded from - # Azure DevOps above. - - task: PowerShell@2 - displayName: Validate - inputs: - filePath: eng\common\sdk-task.ps1 - arguments: -task SigningValidation -restore -msbuildEngine vs - /p:PackageBasePath='$(Build.ArtifactStagingDirectory)/PackageArtifacts' - /p:SignCheckExclusionsFile='$(Build.SourcesDirectory)/eng/SignCheckExclusionsFile.txt' - ${{ parameters.signingValidationAdditionalParameters }} - - - template: ../steps/publish-logs.yml - parameters: - StageLabel: 'Validation' - JobLabel: 'Signing' - BinlogToolVersion: $(BinlogToolVersion) - - - job: - displayName: SourceLink Validation - condition: eq( ${{ parameters.enableSourceLinkValidation }}, 'true') - pool: - # We don't use the collection uri here because it might vary (.visualstudio.com vs. dev.azure.com) - ${{ if eq(variables['System.TeamProject'], 'DevDiv') }}: - name: VSEngSS-MicroBuild2022-1ES - demands: Cmd - # If it's not devdiv, it's dnceng - ${{ else }}: - name: $(DncEngInternalBuildPool) - demands: ImageOverride -equals windows.vs2019.amd64 - steps: - - template: setup-maestro-vars.yml - parameters: - BARBuildId: ${{ parameters.BARBuildId }} - PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }} - - - task: DownloadBuildArtifacts@0 - displayName: Download Blob Artifacts - inputs: - buildType: specific - buildVersionToDownload: specific - project: $(AzDOProjectName) - pipeline: $(AzDOPipelineId) - buildId: $(AzDOBuildId) - artifactName: BlobArtifacts - checkDownloadedFiles: true - - - task: PowerShell@2 - displayName: Validate - inputs: - filePath: $(Build.SourcesDirectory)/eng/common/post-build/sourcelink-validation.ps1 - arguments: -InputPath $(Build.ArtifactStagingDirectory)/BlobArtifacts/ - -ExtractPath $(Agent.BuildDirectory)/Extract/ - -GHRepoName $(Build.Repository.Name) - -GHCommit $(Build.SourceVersion) - -SourcelinkCliVersion $(SourceLinkCLIVersion) - continueOnError: true - - - template: /eng/common/templates/job/execute-sdl.yml - parameters: - enable: ${{ parameters.SDLValidationParameters.enable }} - publishGuardianDirectoryToPipeline: ${{ parameters.SDLValidationParameters.publishGdn }} - additionalParameters: ${{ parameters.SDLValidationParameters.params }} - continueOnError: ${{ parameters.SDLValidationParameters.continueOnError }} - artifactNames: ${{ parameters.SDLValidationParameters.artifactNames }} - downloadArtifacts: ${{ parameters.SDLValidationParameters.downloadArtifacts }} - -- ${{ if ne(parameters.publishAssetsImmediately, 'true') }}: - - stage: publish_using_darc - ${{ if or(eq(parameters.enableNugetValidation, 'true'), eq(parameters.enableSigningValidation, 'true'), eq(parameters.enableSourceLinkValidation, 'true'), eq(parameters.SDLValidationParameters.enable, 'true')) }}: - dependsOn: ${{ parameters.publishDependsOn }} - ${{ else }}: - dependsOn: ${{ parameters.validateDependsOn }} - displayName: Publish using Darc - variables: - - template: common-variables.yml - - template: /eng/common/templates/variables/pool-providers.yml - jobs: - - job: - displayName: Publish Using Darc - timeoutInMinutes: 120 - pool: - # We don't use the collection uri here because it might vary (.visualstudio.com vs. dev.azure.com) - ${{ if eq(variables['System.TeamProject'], 'DevDiv') }}: - name: VSEngSS-MicroBuild2022-1ES - demands: Cmd - # If it's not devdiv, it's dnceng - ${{ else }}: - name: NetCore1ESPool-Publishing-Internal - demands: ImageOverride -equals windows.vs2019.amd64 - steps: - - template: setup-maestro-vars.yml - parameters: - BARBuildId: ${{ parameters.BARBuildId }} - PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }} - - - task: NuGetAuthenticate@1 +- template: /eng/common/core-templates/post-build/post-build.yml + parameters: + # Specifies whether to use 1ES + is1ESPipeline: false - - task: PowerShell@2 - displayName: Publish Using Darc - inputs: - filePath: $(Build.SourcesDirectory)/eng/common/post-build/publish-using-darc.ps1 - arguments: -BuildId $(BARBuildId) - -PublishingInfraVersion ${{ parameters.publishingInfraVersion }} - -AzdoToken '$(publishing-dnceng-devdiv-code-r-build-re)' - -MaestroToken '$(MaestroApiAccessToken)' - -WaitPublishingFinish true - -ArtifactsPublishingAdditionalParameters '${{ parameters.artifactsPublishingAdditionalParameters }}' - -SymbolPublishingAdditionalParameters '${{ parameters.symbolPublishingAdditionalParameters }}' + ${{ each parameter in parameters }}: + ${{ parameter.key }}: ${{ parameter.value }} \ No newline at end of file diff --git a/eng/common/templates/post-build/setup-maestro-vars.yml b/eng/common/templates/post-build/setup-maestro-vars.yml index 0c87f149a4ad77..a79fab5b441e84 100644 --- a/eng/common/templates/post-build/setup-maestro-vars.yml +++ b/eng/common/templates/post-build/setup-maestro-vars.yml @@ -1,70 +1,8 @@ -parameters: - BARBuildId: '' - PromoteToChannelIds: '' - steps: - - ${{ if eq(coalesce(parameters.PromoteToChannelIds, 0), 0) }}: - - task: DownloadBuildArtifacts@0 - displayName: Download Release Configs - inputs: - buildType: current - artifactName: ReleaseConfigs - checkDownloadedFiles: true - - - task: PowerShell@2 - name: setReleaseVars - displayName: Set Release Configs Vars - inputs: - targetType: inline - pwsh: true - script: | - try { - if (!$Env:PromoteToMaestroChannels -or $Env:PromoteToMaestroChannels.Trim() -eq '') { - $Content = Get-Content $(Build.StagingDirectory)/ReleaseConfigs/ReleaseConfigs.txt - - $BarId = $Content | Select -Index 0 - $Channels = $Content | Select -Index 1 - $IsStableBuild = $Content | Select -Index 2 - - $AzureDevOpsProject = $Env:System_TeamProject - $AzureDevOpsBuildDefinitionId = $Env:System_DefinitionId - $AzureDevOpsBuildId = $Env:Build_BuildId - } - else { - $buildApiEndpoint = "${Env:MaestroApiEndPoint}/api/builds/${Env:BARBuildId}?api-version=${Env:MaestroApiVersion}" - - $apiHeaders = New-Object 'System.Collections.Generic.Dictionary[[String],[String]]' - $apiHeaders.Add('Accept', 'application/json') - $apiHeaders.Add('Authorization',"Bearer ${Env:MAESTRO_API_TOKEN}") - - $buildInfo = try { Invoke-WebRequest -Method Get -Uri $buildApiEndpoint -Headers $apiHeaders | ConvertFrom-Json } catch { Write-Host "Error: $_" } - - $BarId = $Env:BARBuildId - $Channels = $Env:PromoteToMaestroChannels -split "," - $Channels = $Channels -join "][" - $Channels = "[$Channels]" - - $IsStableBuild = $buildInfo.stable - $AzureDevOpsProject = $buildInfo.azureDevOpsProject - $AzureDevOpsBuildDefinitionId = $buildInfo.azureDevOpsBuildDefinitionId - $AzureDevOpsBuildId = $buildInfo.azureDevOpsBuildId - } - - Write-Host "##vso[task.setvariable variable=BARBuildId]$BarId" - Write-Host "##vso[task.setvariable variable=TargetChannels]$Channels" - Write-Host "##vso[task.setvariable variable=IsStableBuild]$IsStableBuild" +- template: /eng/common/core-templates/post-build/setup-maestro-vars.yml + parameters: + # Specifies whether to use 1ES + is1ESPipeline: false - Write-Host "##vso[task.setvariable variable=AzDOProjectName]$AzureDevOpsProject" - Write-Host "##vso[task.setvariable variable=AzDOPipelineId]$AzureDevOpsBuildDefinitionId" - Write-Host "##vso[task.setvariable variable=AzDOBuildId]$AzureDevOpsBuildId" - } - catch { - Write-Host $_ - Write-Host $_.Exception - Write-Host $_.ScriptStackTrace - exit 1 - } - env: - MAESTRO_API_TOKEN: $(MaestroApiAccessToken) - BARBuildId: ${{ parameters.BARBuildId }} - PromoteToMaestroChannels: ${{ parameters.PromoteToChannelIds }} + ${{ each parameter in parameters }}: + ${{ parameter.key }}: ${{ parameter.value }} \ No newline at end of file diff --git a/eng/common/templates/steps/add-build-to-channel.yml b/eng/common/templates/steps/add-build-to-channel.yml index f67a210d62f3e5..42bbba161b9b6a 100644 --- a/eng/common/templates/steps/add-build-to-channel.yml +++ b/eng/common/templates/steps/add-build-to-channel.yml @@ -1,13 +1,7 @@ -parameters: - ChannelId: 0 - steps: -- task: PowerShell@2 - displayName: Add Build to Channel - inputs: - filePath: $(Build.SourcesDirectory)/eng/common/post-build/add-build-to-channel.ps1 - arguments: -BuildId $(BARBuildId) - -ChannelId ${{ parameters.ChannelId }} - -MaestroApiAccessToken $(MaestroApiAccessToken) - -MaestroApiEndPoint $(MaestroApiEndPoint) - -MaestroApiVersion $(MaestroApiVersion) +- template: /eng/common/core-templates/steps/add-build-to-channel.yml + parameters: + is1ESPipeline: false + + ${{ each parameter in parameters }}: + ${{ parameter.key }}: ${{ parameter.value }} diff --git a/eng/common/templates/steps/build-reason.yml b/eng/common/templates/steps/build-reason.yml deleted file mode 100644 index eba58109b52c9d..00000000000000 --- a/eng/common/templates/steps/build-reason.yml +++ /dev/null @@ -1,12 +0,0 @@ -# build-reason.yml -# Description: runs steps if build.reason condition is valid. conditions is a string of valid build reasons -# to include steps (',' separated). -parameters: - conditions: '' - steps: [] - -steps: - - ${{ if and( not(startsWith(parameters.conditions, 'not')), contains(parameters.conditions, variables['build.reason'])) }}: - - ${{ parameters.steps }} - - ${{ if and( startsWith(parameters.conditions, 'not'), not(contains(parameters.conditions, variables['build.reason']))) }}: - - ${{ parameters.steps }} diff --git a/eng/common/templates/steps/component-governance.yml b/eng/common/templates/steps/component-governance.yml index 0ecec47b0c9177..c12a5f8d21d765 100644 --- a/eng/common/templates/steps/component-governance.yml +++ b/eng/common/templates/steps/component-governance.yml @@ -1,13 +1,7 @@ -parameters: - disableComponentGovernance: false - componentGovernanceIgnoreDirectories: '' - steps: -- ${{ if eq(parameters.disableComponentGovernance, 'true') }}: - - script: "echo ##vso[task.setvariable variable=skipComponentGovernanceDetection]true" - displayName: Set skipComponentGovernanceDetection variable -- ${{ if ne(parameters.disableComponentGovernance, 'true') }}: - - task: ComponentGovernanceComponentDetection@0 - continueOnError: true - inputs: - ignoreDirectories: ${{ parameters.componentGovernanceIgnoreDirectories }} \ No newline at end of file +- template: /eng/common/core-templates/steps/component-governance.yml + parameters: + is1ESPipeline: false + + ${{ each parameter in parameters }}: + ${{ parameter.key }}: ${{ parameter.value }} diff --git a/eng/common/templates/steps/execute-codeql.yml b/eng/common/templates/steps/execute-codeql.yml deleted file mode 100644 index 3930b1630214b3..00000000000000 --- a/eng/common/templates/steps/execute-codeql.yml +++ /dev/null @@ -1,32 +0,0 @@ -parameters: - # Language that should be analyzed. Defaults to csharp - language: csharp - # Build Commands - buildCommands: '' - overrideParameters: '' # Optional: to override values for parameters. - additionalParameters: '' # Optional: parameters that need user specific values eg: '-SourceToolsList @("abc","def") -ArtifactToolsList @("ghi","jkl")' - # Optional: if specified, restore and use this version of Guardian instead of the default. - overrideGuardianVersion: '' - # Optional: if true, publish the '.gdn' folder as a pipeline artifact. This can help with in-depth - # diagnosis of problems with specific tool configurations. - publishGuardianDirectoryToPipeline: false - # The script to run to execute all SDL tools. Use this if you want to use a script to define SDL - # parameters rather than relying on YAML. It may be better to use a local script, because you can - # reproduce results locally without piecing together a command based on the YAML. - executeAllSdlToolsScript: 'eng/common/sdl/execute-all-sdl-tools.ps1' - # There is some sort of bug (has been reported) in Azure DevOps where if this parameter is named - # 'continueOnError', the parameter value is not correctly picked up. - # This can also be remedied by the caller (post-build.yml) if it does not use a nested parameter - # optional: determines whether to continue the build if the step errors; - sdlContinueOnError: false - -steps: -- template: /eng/common/templates/steps/execute-sdl.yml - parameters: - overrideGuardianVersion: ${{ parameters.overrideGuardianVersion }} - executeAllSdlToolsScript: ${{ parameters.executeAllSdlToolsScript }} - overrideParameters: ${{ parameters.overrideParameters }} - additionalParameters: '${{ parameters.additionalParameters }} - -CodeQLAdditionalRunConfigParams @("BuildCommands < ${{ parameters.buildCommands }}", "Language < ${{ parameters.language }}")' - publishGuardianDirectoryToPipeline: ${{ parameters.publishGuardianDirectoryToPipeline }} - sdlContinueOnError: ${{ parameters.sdlContinueOnError }} \ No newline at end of file diff --git a/eng/common/templates/steps/execute-sdl.yml b/eng/common/templates/steps/execute-sdl.yml deleted file mode 100644 index 07426fde05d824..00000000000000 --- a/eng/common/templates/steps/execute-sdl.yml +++ /dev/null @@ -1,88 +0,0 @@ -parameters: - overrideGuardianVersion: '' - executeAllSdlToolsScript: '' - overrideParameters: '' - additionalParameters: '' - publishGuardianDirectoryToPipeline: false - sdlContinueOnError: false - condition: '' - -steps: -- task: NuGetAuthenticate@1 - inputs: - nuGetServiceConnections: GuardianConnect - -- task: NuGetToolInstaller@1 - displayName: 'Install NuGet.exe' - -- ${{ if ne(parameters.overrideGuardianVersion, '') }}: - - pwsh: | - Set-Location -Path $(Build.SourcesDirectory)\eng\common\sdl - . .\sdl.ps1 - $guardianCliLocation = Install-Gdn -Path $(Build.SourcesDirectory)\.artifacts -Version ${{ parameters.overrideGuardianVersion }} - Write-Host "##vso[task.setvariable variable=GuardianCliLocation]$guardianCliLocation" - displayName: Install Guardian (Overridden) - -- ${{ if eq(parameters.overrideGuardianVersion, '') }}: - - pwsh: | - Set-Location -Path $(Build.SourcesDirectory)\eng\common\sdl - . .\sdl.ps1 - $guardianCliLocation = Install-Gdn -Path $(Build.SourcesDirectory)\.artifacts - Write-Host "##vso[task.setvariable variable=GuardianCliLocation]$guardianCliLocation" - displayName: Install Guardian - -- ${{ if ne(parameters.overrideParameters, '') }}: - - powershell: ${{ parameters.executeAllSdlToolsScript }} ${{ parameters.overrideParameters }} - displayName: Execute SDL (Overridden) - continueOnError: ${{ parameters.sdlContinueOnError }} - condition: ${{ parameters.condition }} - -- ${{ if eq(parameters.overrideParameters, '') }}: - - powershell: ${{ parameters.executeAllSdlToolsScript }} - -GuardianCliLocation $(GuardianCliLocation) - -NugetPackageDirectory $(Build.SourcesDirectory)\.packages - -AzureDevOpsAccessToken $(dn-bot-dotnet-build-rw-code-rw) - ${{ parameters.additionalParameters }} - displayName: Execute SDL - continueOnError: ${{ parameters.sdlContinueOnError }} - condition: ${{ parameters.condition }} - -- ${{ if ne(parameters.publishGuardianDirectoryToPipeline, 'false') }}: - # We want to publish the Guardian results and configuration for easy diagnosis. However, the - # '.gdn' dir is a mix of configuration, results, extracted dependencies, and Guardian default - # tooling files. Some of these files are large and aren't useful during an investigation, so - # exclude them by simply deleting them before publishing. (As of writing, there is no documented - # way to selectively exclude a dir from the pipeline artifact publish task.) - - task: DeleteFiles@1 - displayName: Delete Guardian dependencies to avoid uploading - inputs: - SourceFolder: $(Agent.BuildDirectory)/.gdn - Contents: | - c - i - condition: succeededOrFailed() - - - publish: $(Agent.BuildDirectory)/.gdn - artifact: GuardianConfiguration - displayName: Publish GuardianConfiguration - condition: succeededOrFailed() - - # Publish the SARIF files in a container named CodeAnalysisLogs to enable integration - # with the "SARIF SAST Scans Tab" Azure DevOps extension - - task: CopyFiles@2 - displayName: Copy SARIF files - inputs: - flattenFolders: true - sourceFolder: $(Agent.BuildDirectory)/.gdn/rc/ - contents: '**/*.sarif' - targetFolder: $(Build.SourcesDirectory)/CodeAnalysisLogs - condition: succeededOrFailed() - - # Use PublishBuildArtifacts because the SARIF extension only checks this case - # see microsoft/sarif-azuredevops-extension#4 - - task: PublishBuildArtifacts@1 - displayName: Publish SARIF files to CodeAnalysisLogs container - inputs: - pathToPublish: $(Build.SourcesDirectory)/CodeAnalysisLogs - artifactName: CodeAnalysisLogs - condition: succeededOrFailed() \ No newline at end of file diff --git a/eng/common/templates/steps/generate-sbom.yml b/eng/common/templates/steps/generate-sbom.yml index a06373f38fa5d5..26dc00a2e0f31e 100644 --- a/eng/common/templates/steps/generate-sbom.yml +++ b/eng/common/templates/steps/generate-sbom.yml @@ -1,48 +1,7 @@ -# BuildDropPath - The root folder of the drop directory for which the manifest file will be generated. -# PackageName - The name of the package this SBOM represents. -# PackageVersion - The version of the package this SBOM represents. -# ManifestDirPath - The path of the directory where the generated manifest files will be placed -# IgnoreDirectories - Directories to ignore for SBOM generation. This will be passed through to the CG component detector. - -parameters: - PackageVersion: 7.0.0 - BuildDropPath: '$(Build.SourcesDirectory)/artifacts' - PackageName: '.NET' - ManifestDirPath: $(Build.ArtifactStagingDirectory)/sbom - IgnoreDirectories: '' - sbomContinueOnError: true - steps: -- task: PowerShell@2 - displayName: Prep for SBOM generation in (Non-linux) - condition: or(eq(variables['Agent.Os'], 'Windows_NT'), eq(variables['Agent.Os'], 'Darwin')) - inputs: - filePath: ./eng/common/generate-sbom-prep.ps1 - arguments: ${{parameters.manifestDirPath}} - -# Chmodding is a workaround for https://github.com/dotnet/arcade/issues/8461 -- script: | - chmod +x ./eng/common/generate-sbom-prep.sh - ./eng/common/generate-sbom-prep.sh ${{parameters.manifestDirPath}} - displayName: Prep for SBOM generation in (Linux) - condition: eq(variables['Agent.Os'], 'Linux') - continueOnError: ${{ parameters.sbomContinueOnError }} - -- task: AzureArtifacts.manifest-generator-task.manifest-generator-task.ManifestGeneratorTask@0 - displayName: 'Generate SBOM manifest' - continueOnError: ${{ parameters.sbomContinueOnError }} - inputs: - PackageName: ${{ parameters.packageName }} - BuildDropPath: ${{ parameters.buildDropPath }} - PackageVersion: ${{ parameters.packageVersion }} - ManifestDirPath: ${{ parameters.manifestDirPath }} - ${{ if ne(parameters.IgnoreDirectories, '') }}: - AdditionalComponentDetectorArgs: '--IgnoreDirectories ${{ parameters.IgnoreDirectories }}' - -- task: PublishPipelineArtifact@1 - displayName: Publish SBOM manifest - continueOnError: ${{parameters.sbomContinueOnError}} - inputs: - targetPath: '${{parameters.manifestDirPath}}' - artifactName: $(ARTIFACT_NAME) +- template: /eng/common/core-templates/steps/generate-sbom.yml + parameters: + is1ESPipeline: false + ${{ each parameter in parameters }}: + ${{ parameter.key }}: ${{ parameter.value }} diff --git a/eng/common/templates/steps/publish-build-artifacts.yml b/eng/common/templates/steps/publish-build-artifacts.yml new file mode 100644 index 00000000000000..6428a98dfef68e --- /dev/null +++ b/eng/common/templates/steps/publish-build-artifacts.yml @@ -0,0 +1,40 @@ +parameters: +- name: is1ESPipeline + type: boolean + default: false + +- name: displayName + type: string + default: 'Publish to Build Artifact' + +- name: condition + type: string + default: succeeded() + +- name: artifactName + type: string + +- name: pathToPublish + type: string + +- name: continueOnError + type: boolean + default: false + +- name: publishLocation + type: string + default: 'Container' + +steps: +- ${{ if eq(parameters.is1ESPipeline, true) }}: + - 'eng/common/templates cannot be referenced from a 1ES managed template': error +- task: PublishBuildArtifacts@1 + displayName: ${{ parameters.displayName }} + condition: ${{ parameters.condition }} + ${{ if parameters.continueOnError }}: + continueOnError: ${{ parameters.continueOnError }} + inputs: + PublishLocation: ${{ parameters.publishLocation }} + PathtoPublish: ${{ parameters.pathToPublish }} + ${{ if parameters.artifactName }}: + ArtifactName: ${{ parameters.artifactName }} \ No newline at end of file diff --git a/eng/common/templates/steps/publish-logs.yml b/eng/common/templates/steps/publish-logs.yml index 80861297ddc074..4ea86bd8823555 100644 --- a/eng/common/templates/steps/publish-logs.yml +++ b/eng/common/templates/steps/publish-logs.yml @@ -1,49 +1,7 @@ -parameters: - StageLabel: '' - JobLabel: '' - CustomSensitiveDataList: '' - # A default - in case value from eng/common/templates/post-build/common-variables.yml is not passed - BinlogToolVersion: '1.0.11' - steps: -- task: Powershell@2 - displayName: Prepare Binlogs to Upload - inputs: - targetType: inline - script: | - New-Item -ItemType Directory $(Build.SourcesDirectory)/PostBuildLogs/${{parameters.StageLabel}}/${{parameters.JobLabel}}/ - Move-Item -Path $(Build.SourcesDirectory)/artifacts/log/Debug/* $(Build.SourcesDirectory)/PostBuildLogs/${{parameters.StageLabel}}/${{parameters.JobLabel}}/ - continueOnError: true - condition: always() - -- task: PowerShell@2 - displayName: Redact Logs - inputs: - filePath: $(Build.SourcesDirectory)/eng/common/post-build/redact-logs.ps1 - # For now this needs to have explicit list of all sensitive data. Taken from eng/publishing/v3/publish.yml - # Sensitive data can as well be added to $(Build.SourcesDirectory)/eng/BinlogSecretsRedactionFile.txt' - # If the file exists - sensitive data for redaction will be sourced from it - # (single entry per line, lines starting with '# ' are considered comments and skipped) - arguments: -InputPath '$(Build.SourcesDirectory)/PostBuildLogs' - -BinlogToolVersion ${{parameters.BinlogToolVersion}} - -TokensFilePath '$(Build.SourcesDirectory)/eng/BinlogSecretsRedactionFile.txt' - '$(publishing-dnceng-devdiv-code-r-build-re)' - '$(MaestroAccessToken)' - '$(dn-bot-all-orgs-artifact-feeds-rw)' - '$(akams-client-id)' - '$(akams-client-secret)' - '$(microsoft-symbol-server-pat)' - '$(symweb-symbol-server-pat)' - '$(dn-bot-all-orgs-build-rw-code-rw)' - ${{parameters.CustomSensitiveDataList}} - continueOnError: true - condition: always() - -- task: PublishBuildArtifacts@1 - displayName: Publish Logs - inputs: - PathtoPublish: '$(Build.SourcesDirectory)/PostBuildLogs' - PublishLocation: Container - ArtifactName: PostBuildLogs - continueOnError: true - condition: always() +- template: /eng/common/core-templates/steps/publish-logs.yml + parameters: + is1ESPipeline: false + + ${{ each parameter in parameters }}: + ${{ parameter.key }}: ${{ parameter.value }} diff --git a/eng/common/templates/steps/publish-pipeline-artifacts.yml b/eng/common/templates/steps/publish-pipeline-artifacts.yml new file mode 100644 index 00000000000000..88c56354128c06 --- /dev/null +++ b/eng/common/templates/steps/publish-pipeline-artifacts.yml @@ -0,0 +1,34 @@ +parameters: +- name: is1ESPipeline + type: boolean + default: false + +- name: args + type: object + default: {} + +steps: +- ${{ if eq(parameters.is1ESPipeline, true) }}: + - 'eng/common/templates cannot be referenced from a 1ES managed template': error +- task: PublishPipelineArtifact@1 + displayName: ${{ coalesce(parameters.args.displayName, 'Publish to Build Artifact') }} + ${{ if parameters.args.condition }}: + condition: ${{ parameters.args.condition }} + ${{ else }}: + condition: succeeded() + ${{ if parameters.args.continueOnError }}: + continueOnError: ${{ parameters.args.continueOnError }} + inputs: + TargetPath: ${{ parameters.args.TargetPath }} + ${{ if parameters.args.ArtifactName }}: + ArtifactName: ${{ parameters.args.ArtifactName }} + ${{ if parameters.args.PublishLocation }}: + PublishLocation: ${{ parameters.args.PublishLocation }} + ${{ if parameters.args.FileSharePath }}: + FileSharePath: ${{ parameters.args.FileSharePath }} + ${{ if parameters.args.Parallel }}: + Parallel: ${{ parameters.args.Parallel }} + ${{ if parameters.args.ParallelCount }}: + ParallelCount: ${{ parameters.args.ParallelCount }} + ${{ if parameters.args.Properties }}: + Properties: ${{ properties.args.Properties }} \ No newline at end of file diff --git a/eng/common/templates/steps/retain-build.yml b/eng/common/templates/steps/retain-build.yml index 83d97a26a01ff9..8e841ace3d293f 100644 --- a/eng/common/templates/steps/retain-build.yml +++ b/eng/common/templates/steps/retain-build.yml @@ -1,28 +1,7 @@ -parameters: - # Optional azure devops PAT with build execute permissions for the build's organization, - # only needed if the build that should be retained ran on a different organization than - # the pipeline where this template is executing from - Token: '' - # Optional BuildId to retain, defaults to the current running build - BuildId: '' - # Azure devops Organization URI for the build in the https://dev.azure.com/ format. - # Defaults to the organization the current pipeline is running on - AzdoOrgUri: '$(System.CollectionUri)' - # Azure devops project for the build. Defaults to the project the current pipeline is running on - AzdoProject: '$(System.TeamProject)' - steps: - - task: powershell@2 - inputs: - targetType: 'filePath' - filePath: eng/common/retain-build.ps1 - pwsh: true - arguments: > - -AzdoOrgUri: ${{parameters.AzdoOrgUri}} - -AzdoProject ${{parameters.AzdoProject}} - -Token ${{coalesce(parameters.Token, '$env:SYSTEM_ACCESSTOKEN') }} - -BuildId ${{coalesce(parameters.BuildId, '$env:BUILD_ID')}} - displayName: Enable permanent build retention - env: - SYSTEM_ACCESSTOKEN: $(System.AccessToken) - BUILD_ID: $(Build.BuildId) \ No newline at end of file +- template: /eng/common/core-templates/steps/retain-build.yml + parameters: + is1ESPipeline: false + + ${{ each parameter in parameters }}: + ${{ parameter.key }}: ${{ parameter.value }} diff --git a/eng/common/templates/steps/run-on-unix.yml b/eng/common/templates/steps/run-on-unix.yml deleted file mode 100644 index e1733814f65dcc..00000000000000 --- a/eng/common/templates/steps/run-on-unix.yml +++ /dev/null @@ -1,7 +0,0 @@ -parameters: - agentOs: '' - steps: [] - -steps: -- ${{ if ne(parameters.agentOs, 'Windows_NT') }}: - - ${{ parameters.steps }} diff --git a/eng/common/templates/steps/run-on-windows.yml b/eng/common/templates/steps/run-on-windows.yml deleted file mode 100644 index 73e7e9c275a1f1..00000000000000 --- a/eng/common/templates/steps/run-on-windows.yml +++ /dev/null @@ -1,7 +0,0 @@ -parameters: - agentOs: '' - steps: [] - -steps: -- ${{ if eq(parameters.agentOs, 'Windows_NT') }}: - - ${{ parameters.steps }} diff --git a/eng/common/templates/steps/run-script-ifequalelse.yml b/eng/common/templates/steps/run-script-ifequalelse.yml deleted file mode 100644 index 3d1242f5587c82..00000000000000 --- a/eng/common/templates/steps/run-script-ifequalelse.yml +++ /dev/null @@ -1,33 +0,0 @@ -parameters: - # if parameter1 equals parameter 2, run 'ifScript' command, else run 'elsescript' command - parameter1: '' - parameter2: '' - ifScript: '' - elseScript: '' - - # name of script step - name: Script - - # display name of script step - displayName: If-Equal-Else Script - - # environment - env: {} - - # conditional expression for step execution - condition: '' - -steps: -- ${{ if and(ne(parameters.ifScript, ''), eq(parameters.parameter1, parameters.parameter2)) }}: - - script: ${{ parameters.ifScript }} - name: ${{ parameters.name }} - displayName: ${{ parameters.displayName }} - env: ${{ parameters.env }} - condition: ${{ parameters.condition }} - -- ${{ if and(ne(parameters.elseScript, ''), ne(parameters.parameter1, parameters.parameter2)) }}: - - script: ${{ parameters.elseScript }} - name: ${{ parameters.name }} - displayName: ${{ parameters.displayName }} - env: ${{ parameters.env }} - condition: ${{ parameters.condition }} \ No newline at end of file diff --git a/eng/common/templates/steps/send-to-helix.yml b/eng/common/templates/steps/send-to-helix.yml index 68fa739c4ab215..39f99fc2762d01 100644 --- a/eng/common/templates/steps/send-to-helix.yml +++ b/eng/common/templates/steps/send-to-helix.yml @@ -1,93 +1,7 @@ -# Please remember to update the documentation if you make changes to these parameters! -parameters: - HelixSource: 'pr/default' # required -- sources must start with pr/, official/, prodcon/, or agent/ - HelixType: 'tests/default/' # required -- Helix telemetry which identifies what type of data this is; should include "test" for clarity and must end in '/' - HelixBuild: $(Build.BuildNumber) # required -- the build number Helix will use to identify this -- automatically set to the AzDO build number - HelixTargetQueues: '' # required -- semicolon-delimited list of Helix queues to test on; see https://helix.dot.net/ for a list of queues - HelixAccessToken: '' # required -- access token to make Helix API requests; should be provided by the appropriate variable group - HelixProjectPath: 'eng/common/helixpublish.proj' # optional -- path to the project file to build relative to BUILD_SOURCESDIRECTORY - HelixProjectArguments: '' # optional -- arguments passed to the build command - HelixConfiguration: '' # optional -- additional property attached to a job - HelixPreCommands: '' # optional -- commands to run before Helix work item execution - HelixPostCommands: '' # optional -- commands to run after Helix work item execution - WorkItemDirectory: '' # optional -- a payload directory to zip up and send to Helix; requires WorkItemCommand; incompatible with XUnitProjects - WorkItemCommand: '' # optional -- a command to execute on the payload; requires WorkItemDirectory; incompatible with XUnitProjects - WorkItemTimeout: '' # optional -- a timeout in TimeSpan.Parse-ready value (e.g. 00:02:00) for the work item command; requires WorkItemDirectory; incompatible with XUnitProjects - CorrelationPayloadDirectory: '' # optional -- a directory to zip up and send to Helix as a correlation payload - XUnitProjects: '' # optional -- semicolon-delimited list of XUnitProjects to parse and send to Helix; requires XUnitRuntimeTargetFramework, XUnitPublishTargetFramework, XUnitRunnerVersion, and IncludeDotNetCli=true - XUnitWorkItemTimeout: '' # optional -- the workitem timeout in seconds for all workitems created from the xUnit projects specified by XUnitProjects - XUnitPublishTargetFramework: '' # optional -- framework to use to publish your xUnit projects - XUnitRuntimeTargetFramework: '' # optional -- framework to use for the xUnit console runner - XUnitRunnerVersion: '' # optional -- version of the xUnit nuget package you wish to use on Helix; required for XUnitProjects - IncludeDotNetCli: false # optional -- true will download a version of the .NET CLI onto the Helix machine as a correlation payload; requires DotNetCliPackageType and DotNetCliVersion - DotNetCliPackageType: '' # optional -- either 'sdk', 'runtime' or 'aspnetcore-runtime'; determines whether the sdk or runtime will be sent to Helix; see https://raw.githubusercontent.com/dotnet/core/main/release-notes/releases-index.json - DotNetCliVersion: '' # optional -- version of the CLI to send to Helix; based on this: https://raw.githubusercontent.com/dotnet/core/main/release-notes/releases-index.json - WaitForWorkItemCompletion: true # optional -- true will make the task wait until work items have been completed and fail the build if work items fail. False is "fire and forget." - IsExternal: false # [DEPRECATED] -- doesn't do anything, jobs are external if HelixAccessToken is empty and Creator is set - HelixBaseUri: 'https://helix.dot.net/' # optional -- sets the Helix API base URI (allows targeting https://helix.int-dot.net ) - Creator: '' # optional -- if the build is external, use this to specify who is sending the job - DisplayNamePrefix: 'Run Tests' # optional -- rename the beginning of the displayName of the steps in AzDO - condition: succeeded() # optional -- condition for step to execute; defaults to succeeded() - continueOnError: false # optional -- determines whether to continue the build if the step errors; defaults to false - steps: - - powershell: 'powershell "$env:BUILD_SOURCESDIRECTORY\eng\common\msbuild.ps1 $env:BUILD_SOURCESDIRECTORY/${{ parameters.HelixProjectPath }} /restore /p:TreatWarningsAsErrors=false ${{ parameters.HelixProjectArguments }} /t:Test /bl:$env:BUILD_SOURCESDIRECTORY\artifacts\log\$env:BuildConfig\SendToHelix.binlog"' - displayName: ${{ parameters.DisplayNamePrefix }} (Windows) - env: - BuildConfig: $(_BuildConfig) - HelixSource: ${{ parameters.HelixSource }} - HelixType: ${{ parameters.HelixType }} - HelixBuild: ${{ parameters.HelixBuild }} - HelixConfiguration: ${{ parameters.HelixConfiguration }} - HelixTargetQueues: ${{ parameters.HelixTargetQueues }} - HelixAccessToken: ${{ parameters.HelixAccessToken }} - HelixPreCommands: ${{ parameters.HelixPreCommands }} - HelixPostCommands: ${{ parameters.HelixPostCommands }} - WorkItemDirectory: ${{ parameters.WorkItemDirectory }} - WorkItemCommand: ${{ parameters.WorkItemCommand }} - WorkItemTimeout: ${{ parameters.WorkItemTimeout }} - CorrelationPayloadDirectory: ${{ parameters.CorrelationPayloadDirectory }} - XUnitProjects: ${{ parameters.XUnitProjects }} - XUnitWorkItemTimeout: ${{ parameters.XUnitWorkItemTimeout }} - XUnitPublishTargetFramework: ${{ parameters.XUnitPublishTargetFramework }} - XUnitRuntimeTargetFramework: ${{ parameters.XUnitRuntimeTargetFramework }} - XUnitRunnerVersion: ${{ parameters.XUnitRunnerVersion }} - IncludeDotNetCli: ${{ parameters.IncludeDotNetCli }} - DotNetCliPackageType: ${{ parameters.DotNetCliPackageType }} - DotNetCliVersion: ${{ parameters.DotNetCliVersion }} - WaitForWorkItemCompletion: ${{ parameters.WaitForWorkItemCompletion }} - HelixBaseUri: ${{ parameters.HelixBaseUri }} - Creator: ${{ parameters.Creator }} - SYSTEM_ACCESSTOKEN: $(System.AccessToken) - condition: and(${{ parameters.condition }}, eq(variables['Agent.Os'], 'Windows_NT')) - continueOnError: ${{ parameters.continueOnError }} - - script: $BUILD_SOURCESDIRECTORY/eng/common/msbuild.sh $BUILD_SOURCESDIRECTORY/${{ parameters.HelixProjectPath }} /restore /p:TreatWarningsAsErrors=false ${{ parameters.HelixProjectArguments }} /t:Test /bl:$BUILD_SOURCESDIRECTORY/artifacts/log/$BuildConfig/SendToHelix.binlog - displayName: ${{ parameters.DisplayNamePrefix }} (Unix) - env: - BuildConfig: $(_BuildConfig) - HelixSource: ${{ parameters.HelixSource }} - HelixType: ${{ parameters.HelixType }} - HelixBuild: ${{ parameters.HelixBuild }} - HelixConfiguration: ${{ parameters.HelixConfiguration }} - HelixTargetQueues: ${{ parameters.HelixTargetQueues }} - HelixAccessToken: ${{ parameters.HelixAccessToken }} - HelixPreCommands: ${{ parameters.HelixPreCommands }} - HelixPostCommands: ${{ parameters.HelixPostCommands }} - WorkItemDirectory: ${{ parameters.WorkItemDirectory }} - WorkItemCommand: ${{ parameters.WorkItemCommand }} - WorkItemTimeout: ${{ parameters.WorkItemTimeout }} - CorrelationPayloadDirectory: ${{ parameters.CorrelationPayloadDirectory }} - XUnitProjects: ${{ parameters.XUnitProjects }} - XUnitWorkItemTimeout: ${{ parameters.XUnitWorkItemTimeout }} - XUnitPublishTargetFramework: ${{ parameters.XUnitPublishTargetFramework }} - XUnitRuntimeTargetFramework: ${{ parameters.XUnitRuntimeTargetFramework }} - XUnitRunnerVersion: ${{ parameters.XUnitRunnerVersion }} - IncludeDotNetCli: ${{ parameters.IncludeDotNetCli }} - DotNetCliPackageType: ${{ parameters.DotNetCliPackageType }} - DotNetCliVersion: ${{ parameters.DotNetCliVersion }} - WaitForWorkItemCompletion: ${{ parameters.WaitForWorkItemCompletion }} - HelixBaseUri: ${{ parameters.HelixBaseUri }} - Creator: ${{ parameters.Creator }} - SYSTEM_ACCESSTOKEN: $(System.AccessToken) - condition: and(${{ parameters.condition }}, ne(variables['Agent.Os'], 'Windows_NT')) - continueOnError: ${{ parameters.continueOnError }} +- template: /eng/common/core-templates/steps/send-to-helix.yml + parameters: + is1ESPipeline: false + + ${{ each parameter in parameters }}: + ${{ parameter.key }}: ${{ parameter.value }} diff --git a/eng/common/templates/steps/source-build.yml b/eng/common/templates/steps/source-build.yml index 32738aa938013e..23c1d6f4e9f8d4 100644 --- a/eng/common/templates/steps/source-build.yml +++ b/eng/common/templates/steps/source-build.yml @@ -1,131 +1,7 @@ -parameters: - # This template adds arcade-powered source-build to CI. - - # This is a 'steps' template, and is intended for advanced scenarios where the existing build - # infra has a careful build methodology that must be followed. For example, a repo - # (dotnet/runtime) might choose to clone the GitHub repo only once and store it as a pipeline - # artifact for all subsequent jobs to use, to reduce dependence on a strong network connection to - # GitHub. Using this steps template leaves room for that infra to be included. - - # Defines the platform on which to run the steps. See 'eng/common/templates/job/source-build.yml' - # for details. The entire object is described in the 'job' template for simplicity, even though - # the usage of the properties on this object is split between the 'job' and 'steps' templates. - platform: {} - steps: -# Build. Keep it self-contained for simple reusability. (No source-build-specific job variables.) -- script: | - set -x - df -h - - # If building on the internal project, the artifact feeds variable may be available (usually only if needed) - # In that case, call the feed setup script to add internal feeds corresponding to public ones. - # In addition, add an msbuild argument to copy the WIP from the repo to the target build location. - # This is because SetupNuGetSources.sh will alter the current NuGet.config file, and we need to preserve those - # changes. - internalRestoreArgs= - if [ '$(dn-bot-dnceng-artifact-feeds-rw)' != '$''(dn-bot-dnceng-artifact-feeds-rw)' ]; then - # Temporarily work around https://github.com/dotnet/arcade/issues/7709 - chmod +x $(Build.SourcesDirectory)/eng/common/SetupNugetSources.sh - $(Build.SourcesDirectory)/eng/common/SetupNugetSources.sh $(Build.SourcesDirectory)/NuGet.config $(dn-bot-dnceng-artifact-feeds-rw) - internalRestoreArgs='/p:CopyWipIntoInnerSourceBuildRepo=true' - - # The 'Copy WIP' feature of source build uses git stash to apply changes from the original repo. - # This only works if there is a username/email configured, which won't be the case in most CI runs. - git config --get user.email - if [ $? -ne 0 ]; then - git config user.email dn-bot@microsoft.com - git config user.name dn-bot - fi - fi - - # If building on the internal project, the internal storage variable may be available (usually only if needed) - # In that case, add variables to allow the download of internal runtimes if the specified versions are not found - # in the default public locations. - internalRuntimeDownloadArgs= - if [ '$(dotnetbuilds-internal-container-read-token-base64)' != '$''(dotnetbuilds-internal-container-read-token-base64)' ]; then - internalRuntimeDownloadArgs='/p:DotNetRuntimeSourceFeed=https://dotnetbuilds.blob.core.windows.net/internal /p:DotNetRuntimeSourceFeedKey=$(dotnetbuilds-internal-container-read-token-base64) --runtimesourcefeed https://dotnetbuilds.blob.core.windows.net/internal --runtimesourcefeedkey $(dotnetbuilds-internal-container-read-token-base64)' - fi - - buildConfig=Release - # Check if AzDO substitutes in a build config from a variable, and use it if so. - if [ '$(_BuildConfig)' != '$''(_BuildConfig)' ]; then - buildConfig='$(_BuildConfig)' - fi - - officialBuildArgs= - if [ '${{ and(ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest')) }}' = 'True' ]; then - officialBuildArgs='/p:DotNetPublishUsingPipelines=true /p:OfficialBuildId=$(BUILD.BUILDNUMBER)' - fi - - targetRidArgs= - if [ '${{ parameters.platform.targetRID }}' != '' ]; then - targetRidArgs='/p:TargetRid=${{ parameters.platform.targetRID }}' - fi - - runtimeOsArgs= - if [ '${{ parameters.platform.runtimeOS }}' != '' ]; then - runtimeOsArgs='/p:RuntimeOS=${{ parameters.platform.runtimeOS }}' - fi - - baseOsArgs= - if [ '${{ parameters.platform.baseOS }}' != '' ]; then - baseOsArgs='/p:BaseOS=${{ parameters.platform.baseOS }}' - fi - - publishArgs= - if [ '${{ parameters.platform.skipPublishValidation }}' != 'true' ]; then - publishArgs='--publish' - fi - - assetManifestFileName=SourceBuild_RidSpecific.xml - if [ '${{ parameters.platform.name }}' != '' ]; then - assetManifestFileName=SourceBuild_${{ parameters.platform.name }}.xml - fi - - ${{ coalesce(parameters.platform.buildScript, './build.sh') }} --ci \ - --configuration $buildConfig \ - --restore --build --pack $publishArgs -bl \ - $officialBuildArgs \ - $internalRuntimeDownloadArgs \ - $internalRestoreArgs \ - $targetRidArgs \ - $runtimeOsArgs \ - $baseOsArgs \ - /p:SourceBuildNonPortable=${{ parameters.platform.nonPortable }} \ - /p:ArcadeBuildFromSource=true \ - /p:DotNetBuildSourceOnly=true \ - /p:DotNetBuildRepo=true \ - /p:AssetManifestFileName=$assetManifestFileName - displayName: Build - -# Upload build logs for diagnosis. -- task: CopyFiles@2 - displayName: Prepare BuildLogs staging directory - inputs: - SourceFolder: '$(Build.SourcesDirectory)' - Contents: | - **/*.log - **/*.binlog - artifacts/sb/prebuilt-report/** - TargetFolder: '$(Build.StagingDirectory)/BuildLogs' - CleanTargetFolder: true - continueOnError: true - condition: succeededOrFailed() - -- task: PublishPipelineArtifact@1 - displayName: Publish BuildLogs - inputs: - targetPath: '$(Build.StagingDirectory)/BuildLogs' - artifactName: BuildLogs_SourceBuild_${{ parameters.platform.name }}_Attempt$(System.JobAttempt) - continueOnError: true - condition: succeededOrFailed() +- template: /eng/common/core-templates/steps/source-build.yml + parameters: + is1ESPipeline: false -# Manually inject component detection so that we can ignore the source build upstream cache, which contains -# a nupkg cache of input packages (a local feed). -# This path must match the upstream cache path in property 'CurrentRepoSourceBuiltNupkgCacheDir' -# in src\Microsoft.DotNet.Arcade.Sdk\tools\SourceBuild\SourceBuildArcade.targets -- task: ComponentGovernanceComponentDetection@0 - displayName: Component Detection (Exclude upstream cache) - inputs: - ignoreDirectories: '$(Build.SourcesDirectory)/artifacts/sb/src/artifacts/obj/source-built-upstream-cache' + ${{ each parameter in parameters }}: + ${{ parameter.key }}: ${{ parameter.value }} diff --git a/eng/common/templates/steps/telemetry-end.yml b/eng/common/templates/steps/telemetry-end.yml deleted file mode 100644 index fadc04ca1b9a3e..00000000000000 --- a/eng/common/templates/steps/telemetry-end.yml +++ /dev/null @@ -1,102 +0,0 @@ -parameters: - maxRetries: 5 - retryDelay: 10 # in seconds - -steps: -- bash: | - if [ "$AGENT_JOBSTATUS" = "Succeeded" ] || [ "$AGENT_JOBSTATUS" = "PartiallySucceeded" ]; then - errorCount=0 - else - errorCount=1 - fi - warningCount=0 - - curlStatus=1 - retryCount=0 - # retry loop to harden against spotty telemetry connections - # we don't retry successes and 4xx client errors - until [[ $curlStatus -eq 0 || ( $curlStatus -ge 400 && $curlStatus -le 499 ) || $retryCount -ge $MaxRetries ]] - do - if [ $retryCount -gt 0 ]; then - echo "Failed to send telemetry to Helix; waiting $RetryDelay seconds before retrying..." - sleep $RetryDelay - fi - - # create a temporary file for curl output - res=`mktemp` - - curlResult=` - curl --verbose --output $res --write-out "%{http_code}"\ - -H 'Content-Type: application/json' \ - -H "X-Helix-Job-Token: $Helix_JobToken" \ - -H 'Content-Length: 0' \ - -X POST -G "https://helix.dot.net/api/2018-03-14/telemetry/job/build/$Helix_WorkItemId/finish" \ - --data-urlencode "errorCount=$errorCount" \ - --data-urlencode "warningCount=$warningCount"` - curlStatus=$? - - if [ $curlStatus -eq 0 ]; then - if [ $curlResult -gt 299 ] || [ $curlResult -lt 200 ]; then - curlStatus=$curlResult - fi - fi - - let retryCount++ - done - - if [ $curlStatus -ne 0 ]; then - echo "Failed to Send Build Finish information after $retryCount retries" - vstsLogOutput="vso[task.logissue type=error;sourcepath=templates/steps/telemetry-end.yml;code=1;]Failed to Send Build Finish information: $curlStatus" - echo "##$vstsLogOutput" - exit 1 - fi - displayName: Send Unix Build End Telemetry - env: - # defined via VSTS variables in start-job.sh - Helix_JobToken: $(Helix_JobToken) - Helix_WorkItemId: $(Helix_WorkItemId) - MaxRetries: ${{ parameters.maxRetries }} - RetryDelay: ${{ parameters.retryDelay }} - condition: and(always(), ne(variables['Agent.Os'], 'Windows_NT')) -- powershell: | - if (($env:Agent_JobStatus -eq 'Succeeded') -or ($env:Agent_JobStatus -eq 'PartiallySucceeded')) { - $ErrorCount = 0 - } else { - $ErrorCount = 1 - } - $WarningCount = 0 - - # Basic retry loop to harden against server flakiness - $retryCount = 0 - while ($retryCount -lt $env:MaxRetries) { - try { - Invoke-RestMethod -Uri "https://helix.dot.net/api/2018-03-14/telemetry/job/build/$env:Helix_WorkItemId/finish?errorCount=$ErrorCount&warningCount=$WarningCount" -Method Post -ContentType "application/json" -Body "" ` - -Headers @{ 'X-Helix-Job-Token'=$env:Helix_JobToken } - break - } - catch { - $statusCode = $_.Exception.Response.StatusCode.value__ - if ($statusCode -ge 400 -and $statusCode -le 499) { - Write-Host "##vso[task.logissue]error Failed to send telemetry to Helix (status code $statusCode); not retrying (4xx client error)" - Write-Host "##vso[task.logissue]error ", $_.Exception.GetType().FullName, $_.Exception.Message - exit 1 - } - Write-Host "Failed to send telemetry to Helix (status code $statusCode); waiting $env:RetryDelay seconds before retrying..." - $retryCount++ - sleep $env:RetryDelay - continue - } - } - - if ($retryCount -ge $env:MaxRetries) { - Write-Host "##vso[task.logissue]error Failed to send telemetry to Helix after $retryCount retries." - exit 1 - } - displayName: Send Windows Build End Telemetry - env: - # defined via VSTS variables in start-job.ps1 - Helix_JobToken: $(Helix_JobToken) - Helix_WorkItemId: $(Helix_WorkItemId) - MaxRetries: ${{ parameters.maxRetries }} - RetryDelay: ${{ parameters.retryDelay }} - condition: and(always(),eq(variables['Agent.Os'], 'Windows_NT')) diff --git a/eng/common/templates/steps/telemetry-start.yml b/eng/common/templates/steps/telemetry-start.yml deleted file mode 100644 index 32c01ef0b553b4..00000000000000 --- a/eng/common/templates/steps/telemetry-start.yml +++ /dev/null @@ -1,241 +0,0 @@ -parameters: - helixSource: 'undefined_defaulted_in_telemetry.yml' - helixType: 'undefined_defaulted_in_telemetry.yml' - buildConfig: '' - runAsPublic: false - maxRetries: 5 - retryDelay: 10 # in seconds - -steps: -- ${{ if and(eq(parameters.runAsPublic, 'false'), not(eq(variables['System.TeamProject'], 'public'))) }}: - - task: AzureKeyVault@1 - inputs: - azureSubscription: 'HelixProd_KeyVault' - KeyVaultName: HelixProdKV - SecretsFilter: 'HelixApiAccessToken' - condition: always() -- bash: | - # create a temporary file - jobInfo=`mktemp` - - # write job info content to temporary file - cat > $jobInfo < Date: Sat, 27 Apr 2024 12:22:16 -0700 Subject: [PATCH 121/161] [WASM] Fix third parameter marshaling on callbacks (#101638) * Fix typo with get_signature_arg3_type incrorrecty arg2 instead of arg3 get_signature_arg3_type method is expected to read argument type by Arg3MarshalerType (=28) offset instead of Arg2MarshalerType (=24) * Add another callback tests to cover different parameter types --- .../InteropServices/JavaScript/JSImportTest.cs | 17 +++++++++++++++++ .../JavaScript/JavaScriptTestHelper.cs | 2 ++ .../JavaScript/JavaScriptTestHelper.mjs | 17 ++++++++++++++++- src/mono/browser/runtime/marshal.ts | 2 +- 4 files changed, 36 insertions(+), 2 deletions(-) diff --git a/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/JSImportTest.cs b/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/JSImportTest.cs index b4c220519da097..632b27b105c945 100644 --- a/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/JSImportTest.cs +++ b/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/JSImportTest.cs @@ -1337,6 +1337,23 @@ public void JsImportCallback_ActionIntLong() Assert.Equal(43, calledB); } + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotWasmThreadingSupported))] + public void JsImportCallback_ActionIntLongDouble() + { + int calledA = -1; + long calledB = -1; + double calledC = -1; + JavaScriptTestHelper.back4_ActionIntLongDouble((a, b, c) => + { + calledA = a; + calledB = b; + calledC = c; + }, 42, 43, 44.5); + Assert.Equal(42, calledA); + Assert.Equal(43, calledB); + Assert.Equal(44.5, calledC); + } + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotWasmThreadingSupported))] public void JsImportCallback_ActionIntThrow() { diff --git a/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/JavaScriptTestHelper.cs b/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/JavaScriptTestHelper.cs index b2127558a15206..c64be2635a56ec 100644 --- a/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/JavaScriptTestHelper.cs +++ b/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/JavaScriptTestHelper.cs @@ -493,6 +493,8 @@ public static async Task AwaitTaskOfObject([JSMarshalAs] internal static partial int back3_FunctionIntInt([JSMarshalAs>] Func? fun, [JSMarshalAs] int a); + [JSImport("back4", "JavaScriptTestHelper")] + internal static partial void back4_ActionIntLongDouble([JSMarshalAs>] Action? action, [JSMarshalAs] int a, [JSMarshalAs] long b, [JSMarshalAs] double c); [JSImport("invoke1", "JavaScriptTestHelper")] [return: JSMarshalAs>] diff --git a/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/JavaScriptTestHelper.mjs b/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/JavaScriptTestHelper.mjs index e0cf11376d8d34..9d4851575bf34a 100644 --- a/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/JavaScriptTestHelper.mjs +++ b/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/JavaScriptTestHelper.mjs @@ -383,6 +383,21 @@ export function back3(arg1, arg2, arg3) { } } +export function back4(arg1, arg2, arg3, arg4) { + if (globalThis.gc) { + // console.log('globalThis.gc'); + globalThis.gc(); + } + try { + if (!(arg1 instanceof Function)) throw new Error('expecting Function!') + + return arg1(arg2, arg3, arg4); + } + catch (ex) { + throw ex; + } +} + export function backback(arg1, arg2, arg3) { if (globalThis.gc) { // console.log('globalThis.gc'); @@ -432,4 +447,4 @@ export async function setup() { export function delay(ms) { return new Promise(resolve => globalThis.setTimeout(resolve, ms)); -} \ No newline at end of file +} diff --git a/src/mono/browser/runtime/marshal.ts b/src/mono/browser/runtime/marshal.ts index e49387cc51eef9..b26a94926f88e7 100644 --- a/src/mono/browser/runtime/marshal.ts +++ b/src/mono/browser/runtime/marshal.ts @@ -143,7 +143,7 @@ export function get_signature_arg2_type (sig: JSMarshalerType): MarshalerType { export function get_signature_arg3_type (sig: JSMarshalerType): MarshalerType { mono_assert(sig, "Null sig"); - return getU8(sig + JSBindingTypeOffsets.Arg2MarshalerType); + return getU8(sig + JSBindingTypeOffsets.Arg3MarshalerType); } export function get_signature_argument_count (signature: JSFunctionSignature): number { From b8fe1d0ccb60926d6e7ef5d42e2398c178c9ee5c Mon Sep 17 00:00:00 2001 From: Jan Kotas Date: Sat, 27 Apr 2024 15:04:08 -0700 Subject: [PATCH 122/161] Revert "Make mutable generic collection interfaces implement read-only collection interfaces (#95830)" (#101644) * Revert "Update ICollection usage to IReadOnlyCollection where applicable (#101469)" This reverts commit e92b7d0074adcdb026408bc862f11ac484edeba8. * Revert "Make mutable generic collection interfaces implement read-only collection interfaces (#95830)" This reverts commit a2bd5830ce09cd81d834afd5571bc6c9e5ad879b. * Update src/coreclr/System.Private.CoreLib/src/System/Array.CoreCLR.cs --- src/coreclr/vm/array.cpp | 19 +- .../System/Diagnostics/DiagnosticsHelper.cs | 8 - .../System/Collections/CollectionAsserts.cs | 152 --------------- .../Collections/ICollection.Generic.Tests.cs | 43 ++--- .../Collections/IDictionary.Generic.Tests.cs | 180 +++--------------- .../System/Collections/IList.Generic.Tests.cs | 75 ++++---- .../System/Collections/ISet.Generic.Tests.cs | 53 +++--- .../Frozen/FrozenSetInternalBase.cs | 12 -- .../Immutable/ImmutableExtensions.Minimal.cs | 2 - .../Collections/Generic/PriorityQueue.cs | 2 +- .../System/Collections/Generic/SortedSet.cs | 2 +- .../Generic/CollectionExtensionsTests.cs | 12 -- .../src/System/Dynamic/ExpandoObject.cs | 32 +--- .../src/System/Linq/ParallelEnumerable.cs | 4 +- .../System.Linq/src/System/Linq/AnyAll.cs | 2 +- .../src/System/Linq/AppendPrepend.SpeedOpt.cs | 4 +- .../System.Linq/src/System/Linq/Count.cs | 4 +- .../System/Linq/DefaultIfEmpty.SpeedOpt.cs | 2 +- .../System.Linq/src/System/Linq/ElementAt.cs | 4 +- .../System.Linq/src/System/Linq/First.cs | 2 +- .../System.Linq/src/System/Linq/Grouping.cs | 17 +- .../System.Linq/src/System/Linq/Last.cs | 4 +- .../System/Linq/OrderedEnumerable.SpeedOpt.cs | 2 +- .../src/System/Linq/Reverse.SpeedOpt.cs | 6 +- .../src/System/Linq/SequenceEqual.cs | 4 +- .../System.Linq/src/System/Linq/Single.cs | 2 +- .../ServiceNameCollection.cs | 2 +- .../Collections/Concurrent/ConcurrentQueue.cs | 2 +- .../System/Collections/Generic/Dictionary.cs | 2 +- .../src/System/Collections/Generic/HashSet.cs | 12 +- .../System/Collections/Generic/ICollection.cs | 6 +- .../System/Collections/Generic/IDictionary.cs | 22 +-- .../src/System/Collections/Generic/IList.cs | 6 +- .../src/System/Collections/Generic/ISet.cs | 35 +--- .../Xml/Xsl/Runtime/XmlQuerySequence.cs | 17 +- .../System.Runtime/ref/System.Runtime.cs | 49 ++--- .../src/System/Text/Json/Nodes/JsonObject.cs | 7 +- 37 files changed, 199 insertions(+), 610 deletions(-) diff --git a/src/coreclr/vm/array.cpp b/src/coreclr/vm/array.cpp index e1e2b31e4df647..ffb6e6def99ce0 100644 --- a/src/coreclr/vm/array.cpp +++ b/src/coreclr/vm/array.cpp @@ -1210,14 +1210,29 @@ MethodDesc* GetActualImplementationForArrayGenericIListOrIReadOnlyListMethod(Met } CONTRACTL_END + int slot = pItfcMeth->GetSlot(); + + // We need to pick the right starting method depending on the depth of the inheritance chain + static const BinderMethodID startingMethod[] = { + METHOD__SZARRAYHELPER__GETENUMERATOR, // First method of IEnumerable`1 + METHOD__SZARRAYHELPER__GET_COUNT, // First method of ICollection`1/IReadOnlyCollection`1 + METHOD__SZARRAYHELPER__GET_ITEM // First method of IList`1/IReadOnlyList`1 + }; + // Subtract one for the non-generic IEnumerable that the generic enumerable inherits from unsigned int inheritanceDepth = pItfcMeth->GetMethodTable()->GetNumInterfaces() - 1; + PREFIX_ASSUME(0 <= inheritanceDepth && inheritanceDepth < ARRAY_SIZE(startingMethod)); + + MethodDesc *pGenericImplementor = CoreLibBinder::GetMethod((BinderMethodID)(startingMethod[inheritanceDepth] + slot)); - MethodDesc *pGenericImplementor = MemberLoader::FindMethodByName(g_pSZArrayHelperClass, pItfcMeth->GetName()); + // The most common reason for this assert is that the order of the SZArrayHelper methods in + // corelib.h does not match the order they are implemented on the generic interfaces. + _ASSERTE(pGenericImplementor == MemberLoader::FindMethodByName(g_pSZArrayHelperClass, pItfcMeth->GetName())); // OPTIMIZATION: For any method other than GetEnumerator(), we can safely substitute // "Object" for reference-type theT's. This causes fewer methods to be instantiated. - if (inheritanceDepth != 0 && !theT.IsValueType()) + if (startingMethod[inheritanceDepth] != METHOD__SZARRAYHELPER__GETENUMERATOR && + !theT.IsValueType()) { theT = TypeHandle(g_pObjectClass); } diff --git a/src/libraries/Common/src/System/Diagnostics/DiagnosticsHelper.cs b/src/libraries/Common/src/System/Diagnostics/DiagnosticsHelper.cs index dcc9de3e4ad654..ce7f345b0ea9cd 100644 --- a/src/libraries/Common/src/System/Diagnostics/DiagnosticsHelper.cs +++ b/src/libraries/Common/src/System/Diagnostics/DiagnosticsHelper.cs @@ -35,22 +35,14 @@ internal static bool CompareTags(List>? sortedTags int size = count / (sizeof(ulong) * 8) + 1; BitMapper bitMapper = new BitMapper(size <= 100 ? stackalloc ulong[size] : new ulong[size]); -#if NET9_0_OR_GREATER // ICollection : IReadOnlyCollection on .NET 9+ - if (tags2 is IReadOnlyCollection> tagsCol) -#else if (tags2 is ICollection> tagsCol) -#endif { if (tagsCol.Count != count) { return false; } -#if NET9_0_OR_GREATER // IList : IReadOnlyList on .NET 9+ - if (tagsCol is IReadOnlyList> secondList) -#else if (tagsCol is IList> secondList) -#endif { for (int i = 0; i < count; i++) { diff --git a/src/libraries/Common/tests/System/Collections/CollectionAsserts.cs b/src/libraries/Common/tests/System/Collections/CollectionAsserts.cs index 1e76d40ebb411f..2de26be1737fdc 100644 --- a/src/libraries/Common/tests/System/Collections/CollectionAsserts.cs +++ b/src/libraries/Common/tests/System/Collections/CollectionAsserts.cs @@ -1,7 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System; using System.Collections.Generic; using System.Linq; using Xunit; @@ -10,151 +9,6 @@ namespace System.Collections.Tests { internal static class CollectionAsserts { - public static void HasCount(ICollection collection, int count) - { - Assert.Equal(count, collection.Count); -#if !NETFRAMEWORK - IReadOnlyCollection readOnlyCollection = collection; - Assert.Equal(count, readOnlyCollection.Count); -#endif - } - - public static void EqualAt(IList list, int index, T expected) - { - Assert.Equal(expected, list[index]); -#if !NETFRAMEWORK - IReadOnlyList readOnlyList = list; - Assert.Equal(expected, readOnlyList[index]); -#endif - } - - public static void NotEqualAt(IList list, int index, T expected) - { - Assert.NotEqual(expected, list[index]); -#if !NETFRAMEWORK - IReadOnlyList readOnlyList = list; - Assert.NotEqual(expected, readOnlyList[index]); -#endif - } - - public static void ThrowsElementAt(IList list, int index, Type exceptionType) - { - Assert.Throws(exceptionType, () => list[index]); -#if !NETFRAMEWORK - IReadOnlyList readOnlyList = list; - Assert.Throws(exceptionType, () => readOnlyList[index]); -#endif - } - - public static void ElementAtSucceeds(IList list, int index) - { - T result = list[index]; -#if !NETFRAMEWORK - IReadOnlyList readOnlyList = list; - Assert.Equal(result, readOnlyList[index]); -#endif - } - - public static void EqualAt(IDictionary dictionary, TKey key, TValue expected) - { - Assert.Equal(expected, dictionary[key]); -#if !NETFRAMEWORK - IReadOnlyDictionary readOnlyDictionary = dictionary; - Assert.Equal(expected, readOnlyDictionary[key]); -#endif - } - - public static void ContainsKey(IDictionary dictionary, TKey key, bool expected) - { - Assert.Equal(expected, dictionary.ContainsKey(key)); -#if !NETFRAMEWORK - IReadOnlyDictionary readOnlyDictionary = dictionary; - Assert.Equal(expected, readOnlyDictionary.ContainsKey(key)); -#endif - } - - public static void TryGetValue(IDictionary dictionary, TKey key, bool expected, TValue expectedValue = default) - { - Assert.Equal(expected, dictionary.TryGetValue(key, out TValue value)); - if (expected) - { - Assert.Equal(expectedValue, value); - } -#if !NETFRAMEWORK - IReadOnlyDictionary readOnlyDictionary = dictionary; - Assert.Equal(expected, readOnlyDictionary.TryGetValue(key, out value)); - if (expected) - { - Assert.Equal(expectedValue, value); - } -#endif - } - - public static void Contains(ISet set, T expected) - { - Assert.True(set.Contains(expected)); -#if !NETFRAMEWORK - ICollection collection = set; - Assert.True(collection.Contains(expected)); - IReadOnlySet readOnlySet = set; - Assert.True(readOnlySet.Contains(expected)); -#endif - } - - public static void IsProperSubsetOf(ISet set, IEnumerable enumerable, bool expected) - { - Assert.Equal(expected, set.IsProperSubsetOf(enumerable)); -#if !NETFRAMEWORK - IReadOnlySet readOnlySet = set; - Assert.Equal(expected, readOnlySet.IsProperSubsetOf(enumerable)); -#endif - } - - public static void IsProperSupersetOf(ISet set, IEnumerable enumerable, bool expected) - { - Assert.Equal(expected, set.IsProperSupersetOf(enumerable)); -#if !NETFRAMEWORK - IReadOnlySet readOnlySet = set; - Assert.Equal(expected, readOnlySet.IsProperSupersetOf(enumerable)); -#endif - } - - public static void IsSubsetOf(ISet set, IEnumerable enumerable, bool expected) - { - Assert.Equal(expected, set.IsSubsetOf(enumerable)); -#if !NETFRAMEWORK - IReadOnlySet readOnlySet = set; - Assert.Equal(expected, readOnlySet.IsSubsetOf(enumerable)); -#endif - } - - public static void IsSupersetOf(ISet set, IEnumerable enumerable, bool expected) - { - Assert.Equal(expected, set.IsSupersetOf(enumerable)); -#if !NETFRAMEWORK - IReadOnlySet readOnlySet = set; - Assert.Equal(expected, readOnlySet.IsSupersetOf(enumerable)); -#endif - } - - public static void Overlaps(ISet set, IEnumerable enumerable, bool expected) - { - Assert.Equal(expected, set.Overlaps(enumerable)); -#if !NETFRAMEWORK - IReadOnlySet readOnlySet = set; - Assert.Equal(expected, readOnlySet.Overlaps(enumerable)); -#endif - } - - public static void SetEquals(ISet set, IEnumerable enumerable, bool expected) - { - Assert.Equal(expected, set.SetEquals(enumerable)); -#if !NETFRAMEWORK - IReadOnlySet readOnlySet = set; - Assert.Equal(expected, readOnlySet.SetEquals(enumerable)); -#endif - } - public static void Equal(ICollection expected, ICollection actual) { Assert.Equal(expected == null, actual == null); @@ -189,12 +43,6 @@ public static void Equal(ICollection expected, ICollection actual) return; } Assert.Equal(expected.Count, actual.Count); -#if !NETFRAMEWORK - IReadOnlyCollection readOnlyExpected = expected; - Assert.Equal(expected.Count, readOnlyExpected.Count); - IReadOnlyCollection readOnlyActual = actual; - Assert.Equal(actual.Count, readOnlyActual.Count); -#endif IEnumerator e = expected.GetEnumerator(); IEnumerator a = actual.GetEnumerator(); while (e.MoveNext()) diff --git a/src/libraries/Common/tests/System/Collections/ICollection.Generic.Tests.cs b/src/libraries/Common/tests/System/Collections/ICollection.Generic.Tests.cs index 8ae72dea074ab0..a94a9308b99ab4 100644 --- a/src/libraries/Common/tests/System/Collections/ICollection.Generic.Tests.cs +++ b/src/libraries/Common/tests/System/Collections/ICollection.Generic.Tests.cs @@ -130,7 +130,7 @@ public void ICollection_Generic_IsReadOnly_Validity(int count) public void ICollection_Generic_Count_Validity(int count) { ICollection collection = GenericICollectionFactory(count); - CollectionAsserts.HasCount(collection, count); + Assert.Equal(count, collection.Count); } #endregion @@ -145,7 +145,7 @@ public virtual void ICollection_Generic_Add_DefaultValue(int count) { ICollection collection = GenericICollectionFactory(count); collection.Add(default(T)); - CollectionAsserts.HasCount(collection, count + 1); + Assert.Equal(count + 1, collection.Count); } } @@ -161,7 +161,7 @@ public void ICollection_Generic_Add_InvalidValueToMiddleOfCollection(int count) collection.Add(invalidValue); for (int i = 0; i < count; i++) collection.Add(CreateT(i)); - CollectionAsserts.HasCount(collection, count * 2); + Assert.Equal(count * 2, collection.Count); }); } } @@ -178,7 +178,7 @@ public void ICollection_Generic_Add_InvalidValueToBeginningOfCollection(int coun collection.Add(invalidValue); for (int i = 0; i < count; i++) collection.Add(CreateT(i)); - CollectionAsserts.HasCount(collection, count); + Assert.Equal(count, collection.Count); }); } } @@ -192,9 +192,8 @@ public void ICollection_Generic_Add_InvalidValueToEndOfCollection(int count) Assert.All(InvalidValues, invalidValue => { ICollection collection = GenericICollectionFactory(count); - collection.Add(invalidValue); - CollectionAsserts.HasCount(collection, count); + Assert.Equal(count, collection.Count); }); } } @@ -209,7 +208,7 @@ public void ICollection_Generic_Add_DuplicateValue(int count) T duplicateValue = CreateT(700); collection.Add(duplicateValue); collection.Add(duplicateValue); - CollectionAsserts.HasCount(collection, count + 2); + Assert.Equal(count + 2, collection.Count); } } @@ -222,7 +221,7 @@ public void ICollection_Generic_Add_AfterCallingClear(int count) ICollection collection = GenericICollectionFactory(count); collection.Clear(); AddToCollection(collection, 5); - CollectionAsserts.HasCount(collection, 5); + Assert.Equal(5, collection.Count); } } @@ -262,7 +261,7 @@ public void ICollection_Generic_Add_AfterRemovingAllItems(int count) for (int i = 0; i < count; i++) collection.Remove(collection.ElementAt(0)); collection.Add(CreateT(254)); - CollectionAsserts.HasCount(collection, 1); + Assert.Equal(1, collection.Count); } } @@ -274,7 +273,7 @@ public void ICollection_Generic_Add_ToReadOnlyCollection(int count) { ICollection collection = GenericICollectionFactory(count); Assert.Throws(() => collection.Add(CreateT(0))); - CollectionAsserts.HasCount(collection, count); + Assert.Equal(count, collection.Count); } } @@ -307,12 +306,12 @@ public void ICollection_Generic_Clear(int count) if (IsReadOnly || AddRemoveClear_ThrowsNotSupported) { Assert.Throws(() => collection.Clear()); - CollectionAsserts.HasCount(collection, count); + Assert.Equal(count, collection.Count); } else { collection.Clear(); - CollectionAsserts.HasCount(collection, 0); + Assert.Equal(0, collection.Count); } } @@ -326,14 +325,14 @@ public void ICollection_Generic_Clear_Repeatedly(int count) Assert.Throws(() => collection.Clear()); Assert.Throws(() => collection.Clear()); Assert.Throws(() => collection.Clear()); - CollectionAsserts.HasCount(collection, count); + Assert.Equal(count, collection.Count); } else { collection.Clear(); collection.Clear(); collection.Clear(); - CollectionAsserts.HasCount(collection, 0); + Assert.Equal(0, collection.Count); } } @@ -435,7 +434,7 @@ public void ICollection_Generic_Contains_ValidValueThatExistsTwiceInTheCollectio T item = CreateT(12); collection.Add(item); collection.Add(item); - CollectionAsserts.HasCount(collection, count + 2); + Assert.Equal(count + 2, collection.Count); } } @@ -568,7 +567,7 @@ public void ICollection_Generic_Remove_DefaultValueNotContainedInCollection(int count--; } Assert.False(collection.Remove(value)); - CollectionAsserts.HasCount(collection, count); + Assert.Equal(count, collection.Count); } } @@ -584,7 +583,7 @@ public void ICollection_Generic_Remove_NonDefaultValueNotContainedInCollection(i while (collection.Contains(value) || Enumerable.Contains(InvalidValues, value)) value = CreateT(seed++); Assert.False(collection.Remove(value)); - CollectionAsserts.HasCount(collection, count); + Assert.Equal(count, collection.Count); } } @@ -603,7 +602,7 @@ public virtual void ICollection_Generic_Remove_DefaultValueContainedInCollection count++; } Assert.True(collection.Remove(value)); - CollectionAsserts.HasCount(collection, count - 1); + Assert.Equal(count - 1, collection.Count); } } @@ -622,7 +621,7 @@ public void ICollection_Generic_Remove_NonDefaultValueContainedInCollection(int count++; } Assert.True(collection.Remove(value)); - CollectionAsserts.HasCount(collection, count - 1); + Assert.Equal(count - 1, collection.Count); } } @@ -640,7 +639,7 @@ public void ICollection_Generic_Remove_ValueThatExistsTwiceInCollection(int coun count += 2; Assert.True(collection.Remove(value)); Assert.True(collection.Contains(value)); - CollectionAsserts.HasCount(collection, count - 1); + Assert.Equal(count - 1, collection.Count); } } @@ -655,7 +654,7 @@ public void ICollection_Generic_Remove_EveryValue(int count) { Assert.True(collection.Remove(value)); }); - CollectionAsserts.HasCount(collection, 0); + Assert.Empty(collection); } } @@ -668,7 +667,7 @@ public void ICollection_Generic_Remove_InvalidValue_ThrowsArgumentException(int { Assert.Throws(() => collection.Remove(value)); }); - CollectionAsserts.HasCount(collection, count); + Assert.Equal(count, collection.Count); } [Theory] diff --git a/src/libraries/Common/tests/System/Collections/IDictionary.Generic.Tests.cs b/src/libraries/Common/tests/System/Collections/IDictionary.Generic.Tests.cs index e6311ec89b4fc1..df92ab206f6686 100644 --- a/src/libraries/Common/tests/System/Collections/IDictionary.Generic.Tests.cs +++ b/src/libraries/Common/tests/System/Collections/IDictionary.Generic.Tests.cs @@ -266,16 +266,12 @@ public void IDictionary_Generic_ItemGet_DefaultKey(int count) if (!DefaultValueAllowed) { Assert.Throws(() => dictionary[default(TKey)]); -#if !NETFRAMEWORK - IReadOnlyDictionary readOnlyDictionary = dictionary; - Assert.Throws(() => readOnlyDictionary[default(TKey)]); -#endif } else { TValue value = CreateTValue(3452); dictionary[default(TKey)] = value; - CollectionAsserts.EqualAt(dictionary, default(TKey), value); + Assert.Equal(value, dictionary[default(TKey)]); } } } @@ -287,10 +283,6 @@ public void IDictionary_Generic_ItemGet_MissingNonDefaultKey_ThrowsKeyNotFoundEx IDictionary dictionary = GenericIDictionaryFactory(count); TKey missingKey = GetNewKey(dictionary); Assert.Throws(() => dictionary[missingKey]); -#if !NETFRAMEWORK - IReadOnlyDictionary readOnlyDictionary = dictionary; - Assert.Throws(() => readOnlyDictionary[missingKey]); -#endif } [Theory] @@ -304,10 +296,6 @@ public void IDictionary_Generic_ItemGet_MissingDefaultKey_ThrowsKeyNotFoundExcep while (dictionary.ContainsKey(missingKey)) dictionary.Remove(missingKey); Assert.Throws(() => dictionary[missingKey]); -#if !NETFRAMEWORK - IReadOnlyDictionary readOnlyDictionary = dictionary; - Assert.Throws(() => readOnlyDictionary[missingKey]); -#endif } } @@ -318,7 +306,7 @@ public void IDictionary_Generic_ItemGet_PresentKeyReturnsCorrectValue(int count) IDictionary dictionary = GenericIDictionaryFactory(count); foreach (KeyValuePair pair in dictionary) { - CollectionAsserts.EqualAt(dictionary, pair.Key, pair.Value); + Assert.Equal(pair.Value, dictionary[pair.Key]); } } @@ -341,7 +329,7 @@ public void IDictionary_Generic_ItemSet_DefaultKey(int count) { TValue value = CreateTValue(3452); dictionary[default(TKey)] = value; - CollectionAsserts.EqualAt(dictionary, default(TKey), value); + Assert.Equal(value, dictionary[default(TKey)]); } } } @@ -367,7 +355,7 @@ public void IDictionary_Generic_ItemSet_AddsNewValueWhenNotPresent(int count) IDictionary dictionary = GenericIDictionaryFactory(count); TKey missingKey = GetNewKey(dictionary); dictionary[missingKey] = CreateTValue(543); - CollectionAsserts.HasCount(dictionary, count + 1); + Assert.Equal(count + 1, dictionary.Count); } } @@ -382,8 +370,8 @@ public void IDictionary_Generic_ItemSet_ReplacesExistingValueWhenPresent(int cou dictionary.Add(existingKey, CreateTValue(5342)); TValue newValue = CreateTValue(1234); dictionary[existingKey] = newValue; - CollectionAsserts.HasCount(dictionary, count + 1); - CollectionAsserts.EqualAt(dictionary, existingKey, newValue); + Assert.Equal(count + 1, dictionary.Count); + Assert.Equal(newValue, dictionary[existingKey]); } } @@ -398,10 +386,6 @@ public void IDictionary_Generic_Keys_ContainsAllCorrectKeys(int count) IDictionary dictionary = GenericIDictionaryFactory(count); IEnumerable expected = dictionary.Select((pair) => pair.Key); Assert.True(expected.SequenceEqual(dictionary.Keys)); -#if !NETFRAMEWORK - IReadOnlyDictionary readOnlyDictionary = dictionary; - Assert.True(expected.SequenceEqual(readOnlyDictionary.Keys)); -#endif } [Theory] @@ -412,10 +396,6 @@ public void IDictionary_Generic_Keys_ModifyingTheDictionaryUpdatesTheCollection( { IDictionary dictionary = GenericIDictionaryFactory(count); ICollection keys = dictionary.Keys; -#if !NETFRAMEWORK - IReadOnlyDictionary readOnlyDictionary = dictionary; - IEnumerable readOnlyKeys = readOnlyDictionary.Keys; -#endif int previousCount = keys.Count; if (count > 0) Assert.NotEmpty(keys); @@ -423,16 +403,10 @@ public void IDictionary_Generic_Keys_ModifyingTheDictionaryUpdatesTheCollection( if (IDictionary_Generic_Keys_Values_ModifyingTheDictionaryUpdatesTheCollection) { Assert.Empty(keys); -#if !NETFRAMEWORK - Assert.Empty(readOnlyKeys); -#endif } else { Assert.Equal(previousCount, keys.Count); -#if !NETFRAMEWORK - Assert.Equal(previousCount, readOnlyKeys.Count()); -#endif } } } @@ -446,20 +420,11 @@ public void IDictionary_Generic_Keys_Enumeration_ParentDictionaryModifiedInvalid IDictionary dictionary = GenericIDictionaryFactory(count); ICollection keys = dictionary.Keys; IEnumerator keysEnum = keys.GetEnumerator(); -#if !NETFRAMEWORK - IReadOnlyDictionary readOnlyDictionary = dictionary; - IEnumerable readOnlyKeys = readOnlyDictionary.Keys; - IEnumerator readOnlyKeysEnum = readOnlyKeys.GetEnumerator(); -#endif dictionary.Add(GetNewKey(dictionary), CreateTValue(3432)); if (count == 0 ? Enumerator_Empty_ModifiedDuringEnumeration_ThrowsInvalidOperationException : IDictionary_Generic_Keys_Values_Enumeration_ThrowsInvalidOperation_WhenParentModified) { Assert.Throws(() => keysEnum.MoveNext()); Assert.Throws(() => keysEnum.Reset()); -#if !NETFRAMEWORK - Assert.Throws(() => readOnlyKeysEnum.MoveNext()); - Assert.Throws(() => readOnlyKeysEnum.Reset()); -#endif } else { @@ -468,13 +433,6 @@ public void IDictionary_Generic_Keys_Enumeration_ParentDictionaryModifiedInvalid _ = keysEnum.Current; } keysEnum.Reset(); -#if !NETFRAMEWORK - if (readOnlyKeysEnum.MoveNext()) - { - _ = readOnlyKeysEnum.Current; - } - readOnlyKeysEnum.Reset(); -#endif } } } @@ -498,25 +456,10 @@ public void IDictionary_Generic_Keys_Enumeration_Reset(int count) IDictionary dictionary = GenericIDictionaryFactory(count); ICollection keys = dictionary.Keys; IEnumerator enumerator = keys.GetEnumerator(); -#if !NETFRAMEWORK - IReadOnlyDictionary readOnlyDictionary = dictionary; - IEnumerable readOnlyKeys = readOnlyDictionary.Keys; - IEnumerator readOnlyEnumerator = readOnlyKeys.GetEnumerator(); -#endif if (IDictionary_Generic_Keys_Values_Enumeration_ResetImplemented) - { enumerator.Reset(); -#if !NETFRAMEWORK - readOnlyEnumerator.Reset(); -#endif - } else - { Assert.Throws(() => enumerator.Reset()); -#if !NETFRAMEWORK - Assert.Throws(() => readOnlyEnumerator.Reset()); -#endif - } } #endregion @@ -530,10 +473,6 @@ public void IDictionary_Generic_Values_ContainsAllCorrectValues(int count) IDictionary dictionary = GenericIDictionaryFactory(count); IEnumerable expected = dictionary.Select((pair) => pair.Value); Assert.True(expected.SequenceEqual(dictionary.Values)); -#if !NETFRAMEWORK - IReadOnlyDictionary readOnlyDictionary = dictionary; - Assert.True(expected.SequenceEqual(readOnlyDictionary.Values)); -#endif } [Theory] @@ -552,10 +491,6 @@ public void IDictionary_Generic_Values_IncludeDuplicatesMultipleTimes(int count) dictionary.Add(missingKey, pair.Value); } Assert.Equal(count * 2, dictionary.Values.Count); -#if !NETFRAMEWORK - IReadOnlyDictionary readOnlyDictionary = dictionary; - Assert.Equal(count * 2, readOnlyDictionary.Values.Count()); -#endif } } @@ -565,18 +500,9 @@ public void IDictionary_Generic_Values_ModifyingTheDictionaryUpdatesTheCollectio { IDictionary dictionary = GenericIDictionaryFactory(count); ICollection values = dictionary.Values; -#if !NETFRAMEWORK - IReadOnlyDictionary readOnlyDictionary = dictionary; - IEnumerable readOnlyValues = readOnlyDictionary.Values; -#endif int previousCount = values.Count; if (count > 0) - { Assert.NotEmpty(values); -#if !NETFRAMEWORK - Assert.NotEmpty(readOnlyValues); -#endif - } if (!IsReadOnly) { @@ -584,16 +510,10 @@ public void IDictionary_Generic_Values_ModifyingTheDictionaryUpdatesTheCollectio if (IDictionary_Generic_Keys_Values_ModifyingTheDictionaryUpdatesTheCollection) { Assert.Empty(values); -#if !NETFRAMEWORK - Assert.Empty(readOnlyValues); -#endif } else { Assert.Equal(previousCount, values.Count); -#if !NETFRAMEWORK - Assert.Equal(previousCount, readOnlyValues.Count()); -#endif } } } @@ -607,20 +527,11 @@ public void IDictionary_Generic_Values_Enumeration_ParentDictionaryModifiedInval IDictionary dictionary = GenericIDictionaryFactory(count); ICollection values = dictionary.Values; IEnumerator valuesEnum = values.GetEnumerator(); -#if !NETFRAMEWORK - IReadOnlyDictionary readOnlyDictionary = dictionary; - IEnumerable readOnlyValues = readOnlyDictionary.Values; - IEnumerator readOnlyValuesEnum = readOnlyValues.GetEnumerator(); -#endif dictionary.Add(GetNewKey(dictionary), CreateTValue(3432)); if (count == 0 ? Enumerator_Empty_ModifiedDuringEnumeration_ThrowsInvalidOperationException : IDictionary_Generic_Keys_Values_Enumeration_ThrowsInvalidOperation_WhenParentModified) { Assert.Throws(() => valuesEnum.MoveNext()); Assert.Throws(() => valuesEnum.Reset()); -#if !NETFRAMEWORK - Assert.Throws(() => readOnlyValuesEnum.MoveNext()); - Assert.Throws(() => readOnlyValuesEnum.Reset()); -#endif } else { @@ -629,13 +540,6 @@ public void IDictionary_Generic_Values_Enumeration_ParentDictionaryModifiedInval _ = valuesEnum.Current; } valuesEnum.Reset(); -#if !NETFRAMEWORK - if (readOnlyValuesEnum.MoveNext()) - { - _ = readOnlyValuesEnum.Current; - } - readOnlyValuesEnum.Reset(); -#endif } } } @@ -659,25 +563,10 @@ public void IDictionary_Generic_Values_Enumeration_Reset(int count) IDictionary dictionary = GenericIDictionaryFactory(count); ICollection values = dictionary.Values; IEnumerator enumerator = values.GetEnumerator(); -#if !NETFRAMEWORK - IReadOnlyDictionary readOnlyDictionary = dictionary; - IEnumerable readOnlyValues = readOnlyDictionary.Values; - IEnumerator readOnlyEnumerator = readOnlyValues.GetEnumerator(); -#endif if (IDictionary_Generic_Keys_Values_Enumeration_ResetImplemented) - { enumerator.Reset(); -#if !NETFRAMEWORK - readOnlyEnumerator.Reset(); -#endif - } else - { Assert.Throws(() => enumerator.Reset()); -#if !NETFRAMEWORK - Assert.Throws(() => readOnlyEnumerator.Reset()); -#endif - } } #endregion @@ -705,8 +594,8 @@ public void IDictionary_Generic_Add_DefaultKey_DefaultValue(int count) if (DefaultValueAllowed && !IsReadOnly) { dictionary.Add(missingKey, value); - CollectionAsserts.HasCount(dictionary, count + 1); - CollectionAsserts.EqualAt(dictionary, missingKey, value); + Assert.Equal(count + 1, dictionary.Count); + Assert.Equal(value, dictionary[missingKey]); } else if (!IsReadOnly) { @@ -724,8 +613,8 @@ public void IDictionary_Generic_Add_DefaultKey_NonDefaultValue(int count) if (DefaultValueAllowed && !IsReadOnly) { dictionary.Add(missingKey, value); - CollectionAsserts.HasCount(dictionary, count + 1); - CollectionAsserts.EqualAt(dictionary, missingKey, value); + Assert.Equal(count + 1, dictionary.Count); + Assert.Equal(value, dictionary[missingKey]); } else if (!IsReadOnly) { @@ -743,8 +632,8 @@ public void IDictionary_Generic_Add_NonDefaultKey_DefaultValue(int count) TKey missingKey = GetNewKey(dictionary); TValue value = default(TValue); dictionary.Add(missingKey, value); - CollectionAsserts.HasCount(dictionary, count + 1); - CollectionAsserts.EqualAt(dictionary, missingKey, value); + Assert.Equal(count + 1, dictionary.Count); + Assert.Equal(value, dictionary[missingKey]); } } @@ -758,8 +647,8 @@ public void IDictionary_Generic_Add_NonDefaultKey_NonDefaultValue(int count) TKey missingKey = GetNewKey(dictionary); TValue value = CreateTValue(1342); dictionary.Add(missingKey, value); - CollectionAsserts.HasCount(dictionary, count + 1); - CollectionAsserts.EqualAt(dictionary, missingKey, value); + Assert.Equal(count + 1, dictionary.Count); + Assert.Equal(value, dictionary[missingKey]); } } @@ -777,10 +666,6 @@ public void IDictionary_Generic_Add_DuplicateValue(int count) dictionary.Add(GetNewKey(dictionary), duplicate); dictionary.Add(GetNewKey(dictionary), duplicate); Assert.Equal(2, dictionary.Values.Count((value) => value.Equals(duplicate))); -#if !NETFRAMEWORK - IReadOnlyDictionary readOnlyDictionary = dictionary; - Assert.Equal(2, readOnlyDictionary.Values.Count((value) => value.Equals(duplicate))); -#endif } } @@ -807,7 +692,7 @@ public void IDictionary_Generic_Add_DistinctValuesWithHashCollisions(int count) if (dictionary != null) { AddToCollection(dictionary, count); - CollectionAsserts.HasCount(dictionary, count); + Assert.Equal(count, dictionary.Count); } } } @@ -824,7 +709,7 @@ public void IDictionary_Generic_ContainsKey_ValidKeyNotContainedInDictionary(int { IDictionary dictionary = GenericIDictionaryFactory(count); TKey missingKey = GetNewKey(dictionary); - CollectionAsserts.ContainsKey(dictionary, missingKey, false); + Assert.False(dictionary.ContainsKey(missingKey)); } } @@ -837,7 +722,7 @@ public void IDictionary_Generic_ContainsKey_ValidKeyContainedInDictionary(int co IDictionary dictionary = GenericIDictionaryFactory(count); TKey missingKey = GetNewKey(dictionary); dictionary.Add(missingKey, CreateTValue(34251)); - CollectionAsserts.ContainsKey(dictionary, missingKey, true); + Assert.True(dictionary.ContainsKey(missingKey)); } } @@ -854,17 +739,13 @@ public void IDictionary_Generic_ContainsKey_DefaultKeyNotContainedInDictionary(i TKey missingKey = default(TKey); while (dictionary.ContainsKey(missingKey)) dictionary.Remove(missingKey); - CollectionAsserts.ContainsKey(dictionary, missingKey, false); + Assert.False(dictionary.ContainsKey(missingKey)); } } else { // throws ArgumentNullException Assert.Throws(() => dictionary.ContainsKey(default(TKey))); -#if !NETFRAMEWORK - IReadOnlyDictionary readOnlyDictionary = dictionary; - Assert.Throws(() => readOnlyDictionary.ContainsKey(default(TKey))); -#endif } } @@ -878,7 +759,7 @@ public void IDictionary_Generic_ContainsKey_DefaultKeyContainedInDictionary(int TKey missingKey = default(TKey); if (!dictionary.ContainsKey(missingKey)) dictionary.Add(missingKey, CreateTValue(5341)); - CollectionAsserts.ContainsKey(dictionary, missingKey, true); + Assert.True(dictionary.ContainsKey(missingKey)); } } @@ -908,7 +789,7 @@ public void IDictionary_Generic_RemoveKey_EveryKey(int count) { Assert.True(dictionary.Remove(key)); }); - CollectionAsserts.HasCount(dictionary, 0); + Assert.Empty(dictionary); } } @@ -921,7 +802,7 @@ public void IDictionary_Generic_RemoveKey_ValidKeyNotContainedInDictionary(int c IDictionary dictionary = GenericIDictionaryFactory(count); TKey missingKey = GetNewKey(dictionary); Assert.False(dictionary.Remove(missingKey)); - CollectionAsserts.HasCount(dictionary, count); + Assert.Equal(count, dictionary.Count); } } @@ -935,7 +816,7 @@ public void IDictionary_Generic_RemoveKey_ValidKeyContainedInDictionary(int coun TKey missingKey = GetNewKey(dictionary); dictionary.Add(missingKey, CreateTValue(34251)); Assert.True(dictionary.Remove(missingKey)); - CollectionAsserts.HasCount(dictionary, count); + Assert.Equal(count, dictionary.Count); } } @@ -1028,7 +909,8 @@ public void IDictionary_Generic_TryGetValue_ValidKeyNotContainedInDictionary(int IDictionary dictionary = GenericIDictionaryFactory(count); TKey missingKey = GetNewKey(dictionary); TValue value = CreateTValue(5123); - CollectionAsserts.TryGetValue(dictionary, missingKey, false); + TValue outValue; + Assert.False(dictionary.TryGetValue(missingKey, out outValue)); } [Theory] @@ -1040,8 +922,10 @@ public void IDictionary_Generic_TryGetValue_ValidKeyContainedInDictionary(int co IDictionary dictionary = GenericIDictionaryFactory(count); TKey missingKey = GetNewKey(dictionary); TValue value = CreateTValue(5123); + TValue outValue; dictionary.TryAdd(missingKey, value); - CollectionAsserts.TryGetValue(dictionary, missingKey, true, value); + Assert.True(dictionary.TryGetValue(missingKey, out outValue)); + Assert.Equal(value, outValue); } } @@ -1058,16 +942,12 @@ public void IDictionary_Generic_TryGetValue_DefaultKeyNotContainedInDictionary(i TKey missingKey = default(TKey); while (dictionary.ContainsKey(missingKey)) dictionary.Remove(missingKey); - CollectionAsserts.TryGetValue(dictionary, missingKey, false); + Assert.False(dictionary.TryGetValue(missingKey, out outValue)); } } else { Assert.Throws(() => dictionary.TryGetValue(default(TKey), out outValue)); -#if !NETFRAMEWORK - IReadOnlyDictionary readOnlyDictionary = dictionary; - Assert.Throws(() => readOnlyDictionary.TryGetValue(default(TKey), out outValue)); -#endif } } @@ -1080,8 +960,10 @@ public void IDictionary_Generic_TryGetValue_DefaultKeyContainedInDictionary(int IDictionary dictionary = GenericIDictionaryFactory(count); TKey missingKey = default(TKey); TValue value = CreateTValue(5123); + TValue outValue; dictionary.TryAdd(missingKey, value); - CollectionAsserts.TryGetValue(dictionary, missingKey, true, value); + Assert.True(dictionary.TryGetValue(missingKey, out outValue)); + Assert.Equal(value, outValue); } } diff --git a/src/libraries/Common/tests/System/Collections/IList.Generic.Tests.cs b/src/libraries/Common/tests/System/Collections/IList.Generic.Tests.cs index 6d66f143f18d65..44f67e0ca24f83 100644 --- a/src/libraries/Common/tests/System/Collections/IList.Generic.Tests.cs +++ b/src/libraries/Common/tests/System/Collections/IList.Generic.Tests.cs @@ -103,8 +103,8 @@ protected override IEnumerable GetModifyEnumerables(ModifyOper public void IList_Generic_ItemGet_NegativeIndex_ThrowsException(int count) { IList list = GenericIListFactory(count); - CollectionAsserts.ThrowsElementAt(list, -1, IList_Generic_Item_InvalidIndex_ThrowType); - CollectionAsserts.ThrowsElementAt(list, int.MinValue, IList_Generic_Item_InvalidIndex_ThrowType); + Assert.Throws(IList_Generic_Item_InvalidIndex_ThrowType, () => list[-1]); + Assert.Throws(IList_Generic_Item_InvalidIndex_ThrowType, () => list[int.MinValue]); } [Theory] @@ -112,8 +112,8 @@ public void IList_Generic_ItemGet_NegativeIndex_ThrowsException(int count) public void IList_Generic_ItemGet_IndexGreaterThanListCount_ThrowsException(int count) { IList list = GenericIListFactory(count); - CollectionAsserts.ThrowsElementAt(list, count, IList_Generic_Item_InvalidIndex_ThrowType); - CollectionAsserts.ThrowsElementAt(list, count + 1, IList_Generic_Item_InvalidIndex_ThrowType); + Assert.Throws(IList_Generic_Item_InvalidIndex_ThrowType, () => list[count]); + Assert.Throws(IList_Generic_Item_InvalidIndex_ThrowType, () => list[count + 1]); } [Theory] @@ -121,7 +121,8 @@ public void IList_Generic_ItemGet_IndexGreaterThanListCount_ThrowsException(int public void IList_Generic_ItemGet_ValidGetWithinListBounds(int count) { IList list = GenericIListFactory(count); - Assert.All(Enumerable.Range(0, count), index => CollectionAsserts.ElementAtSucceeds(list, index)); + T result; + Assert.All(Enumerable.Range(0, count), index => result = list[index]); } #endregion @@ -138,7 +139,7 @@ public void IList_Generic_ItemSet_NegativeIndex_ThrowsException(int count) T validAdd = CreateT(0); Assert.Throws(IList_Generic_Item_InvalidIndex_ThrowType, () => list[-1] = validAdd); Assert.Throws(IList_Generic_Item_InvalidIndex_ThrowType, () => list[int.MinValue] = validAdd); - CollectionAsserts.HasCount(list, count); + Assert.Equal(count, list.Count); } } @@ -152,7 +153,7 @@ public void IList_Generic_ItemSet_IndexGreaterThanListCount_ThrowsException(int T validAdd = CreateT(0); Assert.Throws(IList_Generic_Item_InvalidIndex_ThrowType, () => list[count] = validAdd); Assert.Throws(IList_Generic_Item_InvalidIndex_ThrowType, () => list[count + 1] = validAdd); - CollectionAsserts.HasCount(list, count); + Assert.Equal(count, list.Count); } } @@ -165,7 +166,7 @@ public void IList_Generic_ItemSet_OnReadOnlyList(int count) IList list = GenericIListFactory(count); T before = list[count / 2]; Assert.Throws(() => list[count / 2] = CreateT(321432)); - CollectionAsserts.EqualAt(list, count / 2, before); + Assert.Equal(before, list[count / 2]); } } @@ -178,7 +179,7 @@ public void IList_Generic_ItemSet_FirstItemToNonDefaultValue(int count) IList list = GenericIListFactory(count); T value = CreateT(123452); list[0] = value; - CollectionAsserts.EqualAt(list, 0, value); + Assert.Equal(value, list[0]); } } @@ -192,12 +193,12 @@ public void IList_Generic_ItemSet_FirstItemToDefaultValue(int count) if (DefaultValueAllowed) { list[0] = default(T); - CollectionAsserts.EqualAt(list, 0, default(T)); + Assert.Equal(default(T), list[0]); } else { Assert.Throws(() => list[0] = default(T)); - CollectionAsserts.NotEqualAt(list, 0, default(T)); + Assert.NotEqual(default(T), list[0]); } } } @@ -212,7 +213,7 @@ public void IList_Generic_ItemSet_LastItemToNonDefaultValue(int count) T value = CreateT(123452); int lastIndex = count > 0 ? count - 1 : 0; list[lastIndex] = value; - CollectionAsserts.EqualAt(list, lastIndex, value); + Assert.Equal(value, list[lastIndex]); } } @@ -227,12 +228,12 @@ public void IList_Generic_ItemSet_LastItemToDefaultValue(int count) if (DefaultValueAllowed) { list[lastIndex] = default(T); - CollectionAsserts.EqualAt(list, lastIndex, default(T)); + Assert.Equal(default(T), list[lastIndex]); } else { Assert.Throws(() => list[lastIndex] = default(T)); - CollectionAsserts.NotEqualAt(list, lastIndex, default(T)); + Assert.NotEqual(default(T), list[lastIndex]); } } } @@ -247,8 +248,8 @@ public void IList_Generic_ItemSet_DuplicateValues(int count) T value = CreateT(123452); list[0] = value; list[1] = value; - CollectionAsserts.EqualAt(list, 0, value); - CollectionAsserts.EqualAt(list, 1, value); + Assert.Equal(value, list[0]); + Assert.Equal(value, list[1]); } } @@ -395,7 +396,7 @@ public void IList_Generic_Insert_NegativeIndex_ThrowsArgumentOutOfRangeException T validAdd = CreateT(0); Assert.Throws(() => list.Insert(-1, validAdd)); Assert.Throws(() => list.Insert(int.MinValue, validAdd)); - CollectionAsserts.HasCount(list, count); + Assert.Equal(count, list.Count); } } @@ -408,8 +409,8 @@ public void IList_Generic_Insert_IndexGreaterThanListCount_Appends(int count) IList list = GenericIListFactory(count); T validAdd = CreateT(12350); list.Insert(count, validAdd); - CollectionAsserts.HasCount(list, count + 1); - CollectionAsserts.EqualAt(list, count, validAdd); + Assert.Equal(count + 1, list.Count); + Assert.Equal(validAdd, list[count]); } } @@ -421,7 +422,7 @@ public void IList_Generic_Insert_ToReadOnlyList(int count) { IList list = GenericIListFactory(count); Assert.Throws(() => list.Insert(count / 2, CreateT(321432))); - CollectionAsserts.HasCount(list, count); + Assert.Equal(count, list.Count); } } @@ -434,8 +435,8 @@ public void IList_Generic_Insert_FirstItemToNonDefaultValue(int count) IList list = GenericIListFactory(count); T value = CreateT(123452); list.Insert(0, value); - CollectionAsserts.EqualAt(list, 0, value); - CollectionAsserts.HasCount(list, count + 1); + Assert.Equal(value, list[0]); + Assert.Equal(count + 1, list.Count); } } @@ -448,8 +449,8 @@ public void IList_Generic_Insert_FirstItemToDefaultValue(int count) IList list = GenericIListFactory(count); T value = default(T); list.Insert(0, value); - CollectionAsserts.EqualAt(list, 0, value); - CollectionAsserts.HasCount(list, count + 1); + Assert.Equal(value, list[0]); + Assert.Equal(count + 1, list.Count); } } @@ -463,8 +464,8 @@ public void IList_Generic_Insert_LastItemToNonDefaultValue(int count) T value = CreateT(123452); int lastIndex = count > 0 ? count - 1 : 0; list.Insert(lastIndex, value); - CollectionAsserts.EqualAt(list, lastIndex, value); - CollectionAsserts.HasCount(list, count + 1); + Assert.Equal(value, list[lastIndex]); + Assert.Equal(count + 1, list.Count); } } @@ -478,8 +479,8 @@ public void IList_Generic_Insert_LastItemToDefaultValue(int count) T value = default(T); int lastIndex = count > 0 ? count - 1 : 0; list.Insert(lastIndex, value); - CollectionAsserts.EqualAt(list, lastIndex, value); - CollectionAsserts.HasCount(list, count + 1); + Assert.Equal(value, list[lastIndex]); + Assert.Equal(count + 1, list.Count); } } @@ -499,9 +500,9 @@ public void IList_Generic_Insert_DuplicateValues(int count) { list.Insert(0, value); list.Insert(1, value); - CollectionAsserts.EqualAt(list, 0, value); - CollectionAsserts.EqualAt(list, 1, value); - CollectionAsserts.HasCount(list, count + 2); + Assert.Equal(value, list[0]); + Assert.Equal(value, list[1]); + Assert.Equal(count + 2, list.Count); } } } @@ -534,7 +535,7 @@ public void IList_Generic_RemoveAt_NegativeIndex_ThrowsArgumentOutOfRangeExcepti T validAdd = CreateT(0); Assert.Throws(() => list.RemoveAt(-1)); Assert.Throws(() => list.RemoveAt(int.MinValue)); - CollectionAsserts.HasCount(list, count); + Assert.Equal(count, list.Count); } } @@ -548,7 +549,7 @@ public void IList_Generic_RemoveAt_IndexGreaterThanListCount_ThrowsArgumentOutOf T validAdd = CreateT(0); Assert.Throws(() => list.RemoveAt(count)); Assert.Throws(() => list.RemoveAt(count + 1)); - CollectionAsserts.HasCount(list, count); + Assert.Equal(count, list.Count); } } @@ -560,7 +561,7 @@ public void IList_Generic_RemoveAt_OnReadOnlyList(int count) { IList list = GenericIListFactory(count); Assert.Throws(() => list.RemoveAt(count / 2)); - CollectionAsserts.HasCount(list, count); + Assert.Equal(count, list.Count); } } @@ -571,11 +572,11 @@ public void IList_Generic_RemoveAt_AllValidIndices(int count) if (!IsReadOnly && !AddRemoveClear_ThrowsNotSupported) { IList list = GenericIListFactory(count); - CollectionAsserts.HasCount(list, count); + Assert.Equal(count, list.Count); Assert.All(Enumerable.Range(0, count).Reverse(), index => { list.RemoveAt(index); - CollectionAsserts.HasCount(list, index); + Assert.Equal(index, list.Count); }); } } @@ -590,7 +591,7 @@ public void IList_Generic_RemoveAt_ZeroMultipleTimes(int count) Assert.All(Enumerable.Range(0, count), index => { list.RemoveAt(0); - CollectionAsserts.HasCount(list, count - index - 1); + Assert.Equal(count - index - 1, list.Count); }); } } diff --git a/src/libraries/Common/tests/System/Collections/ISet.Generic.Tests.cs b/src/libraries/Common/tests/System/Collections/ISet.Generic.Tests.cs index 350faab6f44cb7..303001e8bd1443 100644 --- a/src/libraries/Common/tests/System/Collections/ISet.Generic.Tests.cs +++ b/src/libraries/Common/tests/System/Collections/ISet.Generic.Tests.cs @@ -84,8 +84,8 @@ public void ICollection_Generic_Add_ReturnValue(int count) Assert.True(set.Add(newValue)); if (!DuplicateValuesAllowed) Assert.False(set.Add(newValue)); - CollectionAsserts.HasCount(set, count + 1); - CollectionAsserts.Contains(set, newValue); + Assert.Equal(count + 1, set.Count); + Assert.True(set.Contains(newValue)); } } @@ -104,7 +104,7 @@ public void ICollection_Generic_Add_DuplicateValue_DoesNothing(int count) duplicateValue = CreateT(seed++); collection.Add(duplicateValue); collection.Add(duplicateValue); - CollectionAsserts.HasCount(collection, count + 1); + Assert.Equal(count + 1, collection.Count); } } } @@ -118,7 +118,7 @@ private void Validate_ExceptWith(ISet set, IEnumerable enumerable) if (set.Count == 0 || enumerable == set) { set.ExceptWith(enumerable); - CollectionAsserts.HasCount(set, 0); + Assert.Equal(0, set.Count); } else { @@ -126,7 +126,7 @@ private void Validate_ExceptWith(ISet set, IEnumerable enumerable) foreach (T element in enumerable) expected.Remove(element); set.ExceptWith(enumerable); - CollectionAsserts.HasCount(set, expected.Count); + Assert.Equal(expected.Count, set.Count); Assert.True(expected.SetEquals(set)); } } @@ -136,7 +136,7 @@ private void Validate_IntersectWith(ISet set, IEnumerable enumerable) if (set.Count == 0 || Enumerable.Count(enumerable) == 0) { set.IntersectWith(enumerable); - CollectionAsserts.HasCount(set, 0); + Assert.Equal(0, set.Count); } else if (set == enumerable) { @@ -152,7 +152,7 @@ private void Validate_IntersectWith(ISet set, IEnumerable enumerable) if (enumerable.Contains(value, comparer)) expected.Add(value); set.IntersectWith(enumerable); - CollectionAsserts.HasCount(set, expected.Count); + Assert.Equal(expected.Count, set.Count); Assert.True(expected.SetEquals(set)); } } @@ -178,7 +178,7 @@ private void Validate_IsProperSubsetOf(ISet set, IEnumerable enumerable) break; } } - CollectionAsserts.IsProperSubsetOf(set, enumerable, !setContainsValueNotInEnumerable && enumerableContainsValueNotInSet); + Assert.Equal(!setContainsValueNotInEnumerable && enumerableContainsValueNotInSet, set.IsProperSubsetOf(enumerable)); } private void Validate_IsProperSupersetOf(ISet set, IEnumerable enumerable) @@ -203,7 +203,7 @@ private void Validate_IsProperSupersetOf(ISet set, IEnumerable enumerable) } } isProperSuperset = isProperSuperset && setContainsElementsNotInEnumerable; - CollectionAsserts.IsProperSupersetOf(set, enumerable, isProperSuperset); + Assert.Equal(isProperSuperset, set.IsProperSupersetOf(enumerable)); } private void Validate_IsSubsetOf(ISet set, IEnumerable enumerable) @@ -212,10 +212,10 @@ private void Validate_IsSubsetOf(ISet set, IEnumerable enumerable) foreach (T value in set) if (!enumerable.Contains(value, comparer)) { - CollectionAsserts.IsSubsetOf(set, enumerable, false); + Assert.False(set.IsSubsetOf(enumerable)); return; } - CollectionAsserts.IsSubsetOf(set, enumerable, true); + Assert.True(set.IsSubsetOf(enumerable)); } private void Validate_IsSupersetOf(ISet set, IEnumerable enumerable) @@ -224,10 +224,10 @@ private void Validate_IsSupersetOf(ISet set, IEnumerable enumerable) foreach (T value in enumerable) if (!set.Contains(value, comparer)) { - CollectionAsserts.IsSupersetOf(set, enumerable, false); + Assert.False(set.IsSupersetOf(enumerable)); return; } - CollectionAsserts.IsSupersetOf(set, enumerable, true); + Assert.True(set.IsSupersetOf(enumerable)); } private void Validate_Overlaps(ISet set, IEnumerable enumerable) @@ -237,11 +237,11 @@ private void Validate_Overlaps(ISet set, IEnumerable enumerable) { if (set.Contains(value, comparer)) { - CollectionAsserts.Overlaps(set, enumerable, true); + Assert.True(set.Overlaps(enumerable)); return; } } - CollectionAsserts.Overlaps(set, enumerable, false); + Assert.False(set.Overlaps(enumerable)); } private void Validate_SetEquals(ISet set, IEnumerable enumerable) @@ -251,7 +251,7 @@ private void Validate_SetEquals(ISet set, IEnumerable enumerable) { if (!enumerable.Contains(value, comparer)) { - CollectionAsserts.SetEquals(set, enumerable, false); + Assert.False(set.SetEquals(enumerable)); return; } } @@ -259,11 +259,11 @@ private void Validate_SetEquals(ISet set, IEnumerable enumerable) { if (!set.Contains(value, comparer)) { - CollectionAsserts.SetEquals(set, enumerable, false); + Assert.False(set.SetEquals(enumerable)); return; } } - CollectionAsserts.SetEquals(set, enumerable, true); + Assert.True(set.SetEquals(enumerable)); } private void Validate_SymmetricExceptWith(ISet set, IEnumerable enumerable) @@ -277,7 +277,7 @@ private void Validate_SymmetricExceptWith(ISet set, IEnumerable enumerable if (!enumerable.Contains(element, comparer)) expected.Add(element); set.SymmetricExceptWith(enumerable); - CollectionAsserts.HasCount(set, expected.Count); + Assert.Equal(expected.Count, set.Count); Assert.True(expected.SetEquals(set)); } @@ -289,7 +289,7 @@ private void Validate_UnionWith(ISet set, IEnumerable enumerable) if (!set.Contains(element, comparer)) expected.Add(element); set.UnionWith(enumerable); - CollectionAsserts.HasCount(set, expected.Count); + Assert.Equal(expected.Count, set.Count); Assert.True(expected.SetEquals(set)); } @@ -308,15 +308,6 @@ public void ISet_Generic_NullEnumerableArgument(int count) Assert.Throws(() => set.IsSupersetOf(null)); Assert.Throws(() => set.Overlaps(null)); Assert.Throws(() => set.SetEquals(null)); -#if !NETFRAMEWORK - IReadOnlySet readOnlySet = set; - Assert.Throws(() => readOnlySet.IsProperSubsetOf(null)); - Assert.Throws(() => readOnlySet.IsProperSupersetOf(null)); - Assert.Throws(() => readOnlySet.IsSubsetOf(null)); - Assert.Throws(() => readOnlySet.IsSupersetOf(null)); - Assert.Throws(() => readOnlySet.Overlaps(null)); - Assert.Throws(() => readOnlySet.SetEquals(null)); -#endif if (!IsReadOnly) { Assert.Throws(() => set.ExceptWith(null)); @@ -511,7 +502,7 @@ public void ISet_Generic_Overlaps_Itself(int setLength) public void ISet_Generic_SetEquals_Itself(int setLength) { ISet set = GenericISetFactory(setLength); - CollectionAsserts.SetEquals(set, set, true); + Assert.True(set.SetEquals(set)); } [Theory] @@ -669,7 +660,7 @@ public void ISet_Generic_SymmetricExceptWith_AfterRemovingElements(EnumerableTyp if (!enumerable.Contains(element, comparer)) expected.Add(element); set.SymmetricExceptWith(enumerable); - CollectionAsserts.HasCount(set, expected.Count); + Assert.Equal(expected.Count, set.Count); Assert.True(expected.SetEquals(set)); } } diff --git a/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/FrozenSetInternalBase.cs b/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/FrozenSetInternalBase.cs index 02e5e0cc07cb25..4afe1f7503e757 100644 --- a/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/FrozenSetInternalBase.cs +++ b/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/FrozenSetInternalBase.cs @@ -32,11 +32,7 @@ private protected override bool IsProperSubsetOfCore(IEnumerable other) { Debug.Assert(_thisSet.Count != 0, "EmptyFrozenSet should have been used."); -#if NET9_0_OR_GREATER // ICollection : IReadOnlyCollection on .NET 9+ - if (other is IReadOnlyCollection otherAsCollection) -#else if (other is ICollection otherAsCollection) -#endif { int otherCount = otherAsCollection.Count; @@ -63,11 +59,7 @@ private protected override bool IsProperSupersetOfCore(IEnumerable other) { Debug.Assert(_thisSet.Count != 0, "EmptyFrozenSet should have been used."); -#if NET9_0_OR_GREATER // ICollection : IReadOnlyCollection on .NET 9+ - if (other is IReadOnlyCollection otherAsCollection) -#else if (other is ICollection otherAsCollection) -#endif { int otherCount = otherAsCollection.Count; @@ -111,11 +103,7 @@ private protected override bool IsSupersetOfCore(IEnumerable other) Debug.Assert(_thisSet.Count != 0, "EmptyFrozenSet should have been used."); // Try to compute the answer based purely on counts. -#if NET9_0_OR_GREATER // ICollection : IReadOnlyCollection on .NET 9+ - if (other is IReadOnlyCollection otherAsCollection) -#else if (other is ICollection otherAsCollection) -#endif { int otherCount = otherAsCollection.Count; diff --git a/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableExtensions.Minimal.cs b/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableExtensions.Minimal.cs index dc9c7d26898b7e..66b365bad872b7 100644 --- a/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableExtensions.Minimal.cs +++ b/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableExtensions.Minimal.cs @@ -38,13 +38,11 @@ internal static bool TryGetCount(this IEnumerable sequence, out int count) return true; } -#if !NET9_0_OR_GREATER // ICollection : IReadOnlyCollection on .NET 9+ if (sequence is ICollection collectionOfT) { count = collectionOfT.Count; return true; } -#endif if (sequence is IReadOnlyCollection readOnlyCollection) { diff --git a/src/libraries/System.Collections/src/System/Collections/Generic/PriorityQueue.cs b/src/libraries/System.Collections/src/System/Collections/Generic/PriorityQueue.cs index 072e5ac34d605c..5047b764337389 100644 --- a/src/libraries/System.Collections/src/System/Collections/Generic/PriorityQueue.cs +++ b/src/libraries/System.Collections/src/System/Collections/Generic/PriorityQueue.cs @@ -462,7 +462,7 @@ public void EnqueueRange(IEnumerable elements, TPriority priority) ArgumentNullException.ThrowIfNull(elements); int count; - if (elements is IReadOnlyCollection collection && + if (elements is ICollection collection && (count = collection.Count) > _nodes.Length - _size) { Grow(checked(_size + count)); diff --git a/src/libraries/System.Collections/src/System/Collections/Generic/SortedSet.cs b/src/libraries/System.Collections/src/System/Collections/Generic/SortedSet.cs index fd0beccb28a77d..2f7406d0d7bf4c 100644 --- a/src/libraries/System.Collections/src/System/Collections/Generic/SortedSet.cs +++ b/src/libraries/System.Collections/src/System/Collections/Generic/SortedSet.cs @@ -1323,7 +1323,7 @@ public bool Overlaps(IEnumerable other) if (Count == 0) return false; - if (other is IReadOnlyCollection c && c.Count == 0) + if (other is ICollection c && c.Count == 0) return false; SortedSet? asSorted = other as SortedSet; diff --git a/src/libraries/System.Collections/tests/Generic/CollectionExtensionsTests.cs b/src/libraries/System.Collections/tests/Generic/CollectionExtensionsTests.cs index 6a5b458232fc5c..213d9d6faca996 100644 --- a/src/libraries/System.Collections/tests/Generic/CollectionExtensionsTests.cs +++ b/src/libraries/System.Collections/tests/Generic/CollectionExtensionsTests.cs @@ -61,10 +61,6 @@ public void TryAdd_KeyDoesntExistInIDictionary_ReturnsTrue() IDictionary dictionary = new SortedDictionary(); Assert.True(dictionary.TryAdd("key", "value")); Assert.Equal("value", dictionary["key"]); -#if !NETFRAMEWORK - IReadOnlyDictionary readOnlyDictionary = dictionary; - Assert.Equal("value", readOnlyDictionary["key"]); -#endif } [Fact] @@ -73,10 +69,6 @@ public void TryAdd_KeyExistsInIDictionary_ReturnsFalse() IDictionary dictionary = new SortedDictionary() { ["key"] = "value" }; Assert.False(dictionary.TryAdd("key", "value2")); Assert.Equal("value", dictionary["key"]); -#if !NETFRAMEWORK - IReadOnlyDictionary readOnlyDictionary = dictionary; - Assert.Equal("value", readOnlyDictionary["key"]); -#endif } [Fact] @@ -104,10 +96,6 @@ public void Remove_KeyExistsInIDictionary_ReturnsTrue() Assert.True(dictionary.Remove("key", out var value)); Assert.Equal("value", value); Assert.Throws(() => dictionary["key"]); -#if !NETFRAMEWORK - IReadOnlyDictionary readOnlyDictionary = dictionary; - Assert.Throws(() => readOnlyDictionary["key"]); -#endif } [Fact] diff --git a/src/libraries/System.Linq.Expressions/src/System/Dynamic/ExpandoObject.cs b/src/libraries/System.Linq.Expressions/src/System/Dynamic/ExpandoObject.cs index 906ee3fd84fc2f..288d01c185dbf5 100644 --- a/src/libraries/System.Linq.Expressions/src/System/Dynamic/ExpandoObject.cs +++ b/src/libraries/System.Linq.Expressions/src/System/Dynamic/ExpandoObject.cs @@ -17,7 +17,7 @@ namespace System.Dynamic /// /// Represents an object with members that can be dynamically added and removed at runtime. /// - public sealed class ExpandoObject : IDynamicMetaObjectProvider, IDictionary, IReadOnlyDictionary, INotifyPropertyChanged + public sealed class ExpandoObject : IDynamicMetaObjectProvider, IDictionary, INotifyPropertyChanged { private static readonly MethodInfo s_expandoTryGetValue = typeof(RuntimeOps).GetMethod(nameof(RuntimeOps.ExpandoTryGetValue))!; @@ -618,10 +618,6 @@ System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() ICollection IDictionary.Values => new ValueCollection(this); - IEnumerable IReadOnlyDictionary.Keys => new KeyCollection(this); - - IEnumerable IReadOnlyDictionary.Values => new ValueCollection(this); - object? IDictionary.this[string key] { get @@ -640,18 +636,6 @@ System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() } } - object? IReadOnlyDictionary.this[string key] - { - get - { - if (!TryGetValueForKey(key, out object? value)) - { - throw System.Linq.Expressions.Error.KeyDoesNotExistInExpando(key); - } - return value; - } - } - void IDictionary.Add(string key, object? value) { this.TryAddMember(key, value); @@ -666,15 +650,6 @@ System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() return index >= 0 && data[index] != Uninitialized; } - bool IReadOnlyDictionary.ContainsKey(string key) - { - ArgumentNullException.ThrowIfNull(key); - - ExpandoData data = _data; - int index = data.Class.GetValueIndexCaseSensitive(key); - return index >= 0 && data[index] != Uninitialized; - } - bool IDictionary.Remove(string key) { ArgumentNullException.ThrowIfNull(key); @@ -687,11 +662,6 @@ System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() return TryGetValueForKey(key, out value); } - bool IReadOnlyDictionary.TryGetValue(string key, out object? value) - { - return TryGetValueForKey(key, out value); - } - #endregion #region ICollection> Members diff --git a/src/libraries/System.Linq.Parallel/src/System/Linq/ParallelEnumerable.cs b/src/libraries/System.Linq.Parallel/src/System/Linq/ParallelEnumerable.cs index f0885d3d3e7d48..55ef371ea04226 100644 --- a/src/libraries/System.Linq.Parallel/src/System/Linq/ParallelEnumerable.cs +++ b/src/libraries/System.Linq.Parallel/src/System/Linq/ParallelEnumerable.cs @@ -1852,7 +1852,7 @@ public static int Count(this ParallelQuery source) // If the data source is a collection, we can just return the count right away. if (source is ParallelEnumerableWrapper sourceAsWrapper) { - if (sourceAsWrapper.WrappedEnumerable is IReadOnlyCollection sourceAsCollection) + if (sourceAsWrapper.WrappedEnumerable is ICollection sourceAsCollection) { return sourceAsCollection.Count; } @@ -1923,7 +1923,7 @@ public static long LongCount(this ParallelQuery source) // If the data source is a collection, we can just return the count right away. if (source is ParallelEnumerableWrapper sourceAsWrapper) { - if (sourceAsWrapper.WrappedEnumerable is IReadOnlyCollection sourceAsCollection) + if (sourceAsWrapper.WrappedEnumerable is ICollection sourceAsCollection) { return sourceAsCollection.Count; } diff --git a/src/libraries/System.Linq/src/System/Linq/AnyAll.cs b/src/libraries/System.Linq/src/System/Linq/AnyAll.cs index d6d6e4adccdeba..28a3783aa88297 100644 --- a/src/libraries/System.Linq/src/System/Linq/AnyAll.cs +++ b/src/libraries/System.Linq/src/System/Linq/AnyAll.cs @@ -15,7 +15,7 @@ public static bool Any(this IEnumerable source) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.source); } - if (source is IReadOnlyCollection gc) + if (source is ICollection gc) { return gc.Count != 0; } diff --git a/src/libraries/System.Linq/src/System/Linq/AppendPrepend.SpeedOpt.cs b/src/libraries/System.Linq/src/System/Linq/AppendPrepend.SpeedOpt.cs index cd6fb6fa171ad7..01adb0af01e456 100644 --- a/src/libraries/System.Linq/src/System/Linq/AppendPrepend.SpeedOpt.cs +++ b/src/libraries/System.Linq/src/System/Linq/AppendPrepend.SpeedOpt.cs @@ -127,7 +127,7 @@ public override int GetCount(bool onlyIfCheap) return count == -1 ? -1 : count + 1; } - return !onlyIfCheap || _source is IReadOnlyCollection ? _source.Count() + 1 : -1; + return !onlyIfCheap || _source is ICollection ? _source.Count() + 1 : -1; } public override TSource? TryGetFirst(out bool found) @@ -276,7 +276,7 @@ public override int GetCount(bool onlyIfCheap) return count == -1 ? -1 : count + _appendCount + _prependCount; } - return !onlyIfCheap || _source is IReadOnlyCollection ? _source.Count() + _appendCount + _prependCount : -1; + return !onlyIfCheap || _source is ICollection ? _source.Count() + _appendCount + _prependCount : -1; } } } diff --git a/src/libraries/System.Linq/src/System/Linq/Count.cs b/src/libraries/System.Linq/src/System/Linq/Count.cs index 9b2511e0563c5a..6b8819f8c3cbcb 100644 --- a/src/libraries/System.Linq/src/System/Linq/Count.cs +++ b/src/libraries/System.Linq/src/System/Linq/Count.cs @@ -15,7 +15,7 @@ public static int Count(this IEnumerable source) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.source); } - if (source is IReadOnlyCollection collectionoft) + if (source is ICollection collectionoft) { return collectionoft.Count; } @@ -101,7 +101,7 @@ public static bool TryGetNonEnumeratedCount(this IEnumerable s ThrowHelper.ThrowArgumentNullException(ExceptionArgument.source); } - if (source is IReadOnlyCollection collectionoft) + if (source is ICollection collectionoft) { count = collectionoft.Count; return true; diff --git a/src/libraries/System.Linq/src/System/Linq/DefaultIfEmpty.SpeedOpt.cs b/src/libraries/System.Linq/src/System/Linq/DefaultIfEmpty.SpeedOpt.cs index 45f673f73486ae..c89d6797581e9b 100644 --- a/src/libraries/System.Linq/src/System/Linq/DefaultIfEmpty.SpeedOpt.cs +++ b/src/libraries/System.Linq/src/System/Linq/DefaultIfEmpty.SpeedOpt.cs @@ -30,7 +30,7 @@ public override List ToList() public override int GetCount(bool onlyIfCheap) { int count; - if (!onlyIfCheap || _source is IReadOnlyCollection || _source is ICollection) + if (!onlyIfCheap || _source is ICollection || _source is ICollection) { count = _source.Count(); } diff --git a/src/libraries/System.Linq/src/System/Linq/ElementAt.cs b/src/libraries/System.Linq/src/System/Linq/ElementAt.cs index 824a152a7764c2..97b87f9eba9999 100644 --- a/src/libraries/System.Linq/src/System/Linq/ElementAt.cs +++ b/src/libraries/System.Linq/src/System/Linq/ElementAt.cs @@ -16,7 +16,7 @@ public static TSource ElementAt(this IEnumerable source, int i ThrowHelper.ThrowArgumentNullException(ExceptionArgument.source); } - if (source is IReadOnlyList list) + if (source is IList list) { return list[index]; } @@ -115,7 +115,7 @@ public static TSource ElementAt(this IEnumerable source, Index private static TSource? TryGetElementAt(this IEnumerable source, int index, out bool found) { - if (source is IReadOnlyList list) + if (source is IList list) { return (found = (uint)index < (uint)list.Count) ? list[index] : diff --git a/src/libraries/System.Linq/src/System/Linq/First.cs b/src/libraries/System.Linq/src/System/Linq/First.cs index 22532cdb18d13a..74ff81c2fec83b 100644 --- a/src/libraries/System.Linq/src/System/Linq/First.cs +++ b/src/libraries/System.Linq/src/System/Linq/First.cs @@ -78,7 +78,7 @@ public static TSource FirstOrDefault(this IEnumerable source, private static TSource? TryGetFirstNonIterator(IEnumerable source, out bool found) { - if (source is IReadOnlyList list) + if (source is IList list) { if (list.Count > 0) { diff --git a/src/libraries/System.Linq/src/System/Linq/Grouping.cs b/src/libraries/System.Linq/src/System/Linq/Grouping.cs index 47be36572acad0..6e19e4ab384e44 100644 --- a/src/libraries/System.Linq/src/System/Linq/Grouping.cs +++ b/src/libraries/System.Linq/src/System/Linq/Grouping.cs @@ -351,7 +351,7 @@ public interface IGrouping : IEnumerable [DebuggerDisplay("Key = {Key}")] [DebuggerTypeProxy(typeof(SystemLinq_GroupingDebugView<,>))] - internal sealed class Grouping : IGrouping, IList, IReadOnlyList + internal sealed class Grouping : IGrouping, IList { internal readonly TKey _key; internal readonly int _hashCode; @@ -398,8 +398,6 @@ public IEnumerator GetEnumerator() int ICollection.Count => _count; - int IReadOnlyCollection.Count => _count; - bool ICollection.IsReadOnly => true; void ICollection.Add(TElement item) => ThrowHelper.ThrowNotSupportedException(); @@ -433,18 +431,5 @@ TElement IList.this[int index] set => ThrowHelper.ThrowNotSupportedException(); } - - TElement IReadOnlyList.this[int index] - { - get - { - if ((uint)index >= (uint)_count) - { - ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.index); - } - - return _elements[index]; - } - } } } diff --git a/src/libraries/System.Linq/src/System/Linq/Last.cs b/src/libraries/System.Linq/src/System/Linq/Last.cs index e17e409e25e3f7..007ee1659c3f5f 100644 --- a/src/libraries/System.Linq/src/System/Linq/Last.cs +++ b/src/libraries/System.Linq/src/System/Linq/Last.cs @@ -77,7 +77,7 @@ public static TSource LastOrDefault(this IEnumerable source, F private static TSource? TryGetLastNonIterator(IEnumerable source, out bool found) { - if (source is IReadOnlyList list) + if (source is IList list) { int count = list.Count; if (count > 0) @@ -126,7 +126,7 @@ public static TSource LastOrDefault(this IEnumerable source, F return ordered.TryGetLast(predicate, out found); } - if (source is IReadOnlyList list) + if (source is IList list) { for (int i = list.Count - 1; i >= 0; --i) { diff --git a/src/libraries/System.Linq/src/System/Linq/OrderedEnumerable.SpeedOpt.cs b/src/libraries/System.Linq/src/System/Linq/OrderedEnumerable.SpeedOpt.cs index ac9225303b426f..bf65a34b06efa7 100644 --- a/src/libraries/System.Linq/src/System/Linq/OrderedEnumerable.SpeedOpt.cs +++ b/src/libraries/System.Linq/src/System/Linq/OrderedEnumerable.SpeedOpt.cs @@ -58,7 +58,7 @@ public override int GetCount(bool onlyIfCheap) return iterator.GetCount(onlyIfCheap); } - return !onlyIfCheap || _source is IReadOnlyCollection || _source is ICollection ? _source.Count() : -1; + return !onlyIfCheap || _source is ICollection || _source is ICollection ? _source.Count() : -1; } internal TElement[] ToArray(int minIdx, int maxIdx) diff --git a/src/libraries/System.Linq/src/System/Linq/Reverse.SpeedOpt.cs b/src/libraries/System.Linq/src/System/Linq/Reverse.SpeedOpt.cs index 168ca818c96119..d1ec26de879afd 100644 --- a/src/libraries/System.Linq/src/System/Linq/Reverse.SpeedOpt.cs +++ b/src/libraries/System.Linq/src/System/Linq/Reverse.SpeedOpt.cs @@ -30,7 +30,7 @@ public override int GetCount(bool onlyIfCheap) => public override TSource? TryGetElementAt(int index, out bool found) { - if (_source is IReadOnlyList list) + if (_source is IList list) { int count = list.Count; if ((uint)index < (uint)count) @@ -59,7 +59,7 @@ public override int GetCount(bool onlyIfCheap) => { return iterator.TryGetLast(out found); } - else if (_source is IReadOnlyList list) + else if (_source is IList list) { int count = list.Count; if (count > 0) @@ -95,7 +95,7 @@ public override int GetCount(bool onlyIfCheap) => { return iterator.TryGetFirst(out found); } - else if (_source is IReadOnlyList list) + else if (_source is IList list) { if (list.Count > 0) { diff --git a/src/libraries/System.Linq/src/System/Linq/SequenceEqual.cs b/src/libraries/System.Linq/src/System/Linq/SequenceEqual.cs index 2568721f1ce169..16bf60e686145e 100644 --- a/src/libraries/System.Linq/src/System/Linq/SequenceEqual.cs +++ b/src/libraries/System.Linq/src/System/Linq/SequenceEqual.cs @@ -22,7 +22,7 @@ public static bool SequenceEqual(this IEnumerable first, IEnum ThrowHelper.ThrowArgumentNullException(ExceptionArgument.second); } - if (first is IReadOnlyCollection firstCol && second is IReadOnlyCollection secondCol) + if (first is ICollection firstCol && second is ICollection secondCol) { if (first.TryGetSpan(out ReadOnlySpan firstSpan) && second.TryGetSpan(out ReadOnlySpan secondSpan)) { @@ -34,7 +34,7 @@ public static bool SequenceEqual(this IEnumerable first, IEnum return false; } - if (firstCol is IReadOnlyList firstList && secondCol is IReadOnlyList secondList) + if (firstCol is IList firstList && secondCol is IList secondList) { comparer ??= EqualityComparer.Default; diff --git a/src/libraries/System.Linq/src/System/Linq/Single.cs b/src/libraries/System.Linq/src/System/Linq/Single.cs index 78e548e680669f..9c7328cc3ff16e 100644 --- a/src/libraries/System.Linq/src/System/Linq/Single.cs +++ b/src/libraries/System.Linq/src/System/Linq/Single.cs @@ -69,7 +69,7 @@ public static TSource SingleOrDefault(this IEnumerable source, ThrowHelper.ThrowArgumentNullException(ExceptionArgument.source); } - if (source is IReadOnlyList list) + if (source is IList list) { switch (list.Count) { diff --git a/src/libraries/System.Net.Security/src/System/Security/Authentication/ExtendedProtection/ServiceNameCollection.cs b/src/libraries/System.Net.Security/src/System/Security/Authentication/ExtendedProtection/ServiceNameCollection.cs index 4abe58873916af..532f6e950d6b0d 100644 --- a/src/libraries/System.Net.Security/src/System/Security/Authentication/ExtendedProtection/ServiceNameCollection.cs +++ b/src/libraries/System.Net.Security/src/System/Security/Authentication/ExtendedProtection/ServiceNameCollection.cs @@ -147,7 +147,7 @@ private void AddIfNew(string serviceName) /// private static int GetCountOrOne(IEnumerable collection) { - IReadOnlyCollection? c = collection as IReadOnlyCollection; + ICollection? c = collection as ICollection; return c != null ? c.Count : 1; } diff --git a/src/libraries/System.Private.CoreLib/src/System/Collections/Concurrent/ConcurrentQueue.cs b/src/libraries/System.Private.CoreLib/src/System/Collections/Concurrent/ConcurrentQueue.cs index 2eff1c59b12ec4..bfa9fcf65469ed 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Collections/Concurrent/ConcurrentQueue.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Collections/Concurrent/ConcurrentQueue.cs @@ -89,7 +89,7 @@ public ConcurrentQueue(IEnumerable collection) // case we round its length up to a power of 2, as all segments must // be a power of 2 in length. int length = InitialSegmentLength; - if (collection is IReadOnlyCollection c) + if (collection is ICollection c) { int count = c.Count; if (count > length) diff --git a/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/Dictionary.cs b/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/Dictionary.cs index f20e3c5cfee211..9b18d4a125ed21 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/Dictionary.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/Dictionary.cs @@ -98,7 +98,7 @@ public Dictionary(IDictionary dictionary, IEqualityComparer? public Dictionary(IEnumerable> collection) : this(collection, null) { } public Dictionary(IEnumerable> collection, IEqualityComparer? comparer) : - this((collection as IReadOnlyCollection>)?.Count ?? 0, comparer) + this((collection as ICollection>)?.Count ?? 0, comparer) { if (collection == null) { diff --git a/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/HashSet.cs b/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/HashSet.cs index 6467164d6becbc..3b86548d20a7e4 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/HashSet.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/HashSet.cs @@ -99,7 +99,7 @@ public HashSet(IEnumerable collection, IEqualityComparer? comparer) : this { // To avoid excess resizes, first set size based on collection's count. The collection may // contain duplicates, so call TrimExcess if resulting HashSet is larger than the threshold. - if (collection is IReadOnlyCollection coll) + if (collection is ICollection coll) { int count = coll.Count; if (count > 0) @@ -513,7 +513,7 @@ public void IntersectWith(IEnumerable other) } // If other is known to be empty, intersection is empty set; remove all elements, and we're done. - if (other is IReadOnlyCollection otherAsCollection) + if (other is ICollection otherAsCollection) { if (otherAsCollection.Count == 0) { @@ -652,7 +652,7 @@ public bool IsProperSubsetOf(IEnumerable other) return false; } - if (other is IReadOnlyCollection otherAsCollection) + if (other is ICollection otherAsCollection) { // No set is a proper subset of an empty set. if (otherAsCollection.Count == 0) @@ -701,7 +701,7 @@ public bool IsSupersetOf(IEnumerable other) } // Try to fall out early based on counts. - if (other is IReadOnlyCollection otherAsCollection) + if (other is ICollection otherAsCollection) { // If other is the empty set then this is a superset. if (otherAsCollection.Count == 0) @@ -745,7 +745,7 @@ public bool IsProperSupersetOf(IEnumerable other) return false; } - if (other is IReadOnlyCollection otherAsCollection) + if (other is ICollection otherAsCollection) { // If other is the empty set then this is a superset. if (otherAsCollection.Count == 0) @@ -838,7 +838,7 @@ public bool SetEquals(IEnumerable other) { // If this count is 0 but other contains at least one element, they can't be equal. if (Count == 0 && - other is IReadOnlyCollection otherAsCollection && + other is ICollection otherAsCollection && otherAsCollection.Count > 0) { return false; diff --git a/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/ICollection.cs b/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/ICollection.cs index 24cf81efb2b440..1c1095f8a5cf75 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/ICollection.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/ICollection.cs @@ -9,9 +9,9 @@ namespace System.Collections.Generic { // Base interface for all collections, defining enumerators, size, and // synchronization methods. - public interface ICollection : IReadOnlyCollection + public interface ICollection : IEnumerable { - new int Count + int Count { #if MONO [DynamicDependency(nameof(Array.InternalArray__ICollection_get_Count), typeof(Array))] @@ -53,7 +53,5 @@ bool IsReadOnly [DynamicDependency(nameof(Array.InternalArray__ICollection_Remove) + "``1", typeof(Array))] #endif bool Remove(T item); - - int IReadOnlyCollection.Count => Count; } } diff --git a/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/IDictionary.cs b/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/IDictionary.cs index 7e3e30d8db0929..56a03106c205b6 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/IDictionary.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/IDictionary.cs @@ -9,32 +9,32 @@ namespace System.Collections.Generic // Keys can be any non-null object. Values can be any object. // You can look up a value in an IDictionary via the default indexed // property, Items. - public interface IDictionary : ICollection>, IReadOnlyDictionary + public interface IDictionary : ICollection> { // Interfaces are not serializable // The Item property provides methods to read and edit entries // in the Dictionary. - new TValue this[TKey key] + TValue this[TKey key] { get; set; } // Returns a collections of the keys in this dictionary. - new ICollection Keys + ICollection Keys { get; } // Returns a collections of the values in this dictionary. - new ICollection Values + ICollection Values { get; } // Returns whether this dictionary contains a particular key. // - new bool ContainsKey(TKey key); + bool ContainsKey(TKey key); // Adds a key-value pair to the dictionary. // @@ -44,16 +44,6 @@ public interface IDictionary : ICollection.this[TKey key] => this[key]; - - IEnumerable IReadOnlyDictionary.Keys => Keys; - - IEnumerable IReadOnlyDictionary.Values => Values; - - bool IReadOnlyDictionary.ContainsKey(TKey key) => ContainsKey(key); - - bool IReadOnlyDictionary.TryGetValue(TKey key, [MaybeNullWhen(false)] out TValue value) => TryGetValue(key, out value); + bool TryGetValue(TKey key, [MaybeNullWhen(false)] out TValue value); } } diff --git a/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/IList.cs b/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/IList.cs index ec8098c3ff7ea1..f45ae823daf650 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/IList.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/IList.cs @@ -10,10 +10,10 @@ namespace System.Collections.Generic // An IList is an ordered collection of objects. The exact ordering // is up to the implementation of the list, ranging from a sorted // order to insertion order. - public interface IList : ICollection, IReadOnlyList + public interface IList : ICollection { // The Item property provides methods to read and edit entries in the List. - new T this[int index] + T this[int index] { #if MONO [DynamicDependency(nameof(Array.InternalArray__get_Item) + "``1", typeof(Array))] @@ -46,7 +46,5 @@ public interface IList : ICollection, IReadOnlyList [DynamicDependency(nameof(Array.InternalArray__RemoveAt), typeof(Array))] #endif void RemoveAt(int index); - - T IReadOnlyList.this[int index] => this[index]; } } diff --git a/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/ISet.cs b/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/ISet.cs index ce2e8e7c5f4ff1..cee05d198cda07 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/ISet.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/ISet.cs @@ -8,7 +8,7 @@ namespace System.Collections.Generic /// by some comparer. It also supports basic set operations such as Union, Intersection, /// Complement and Exclusive Complement. /// - public interface ISet : ICollection, IReadOnlySet + public interface ISet : ICollection { //Add ITEM to the set, return true if added, false if duplicate new bool Add(T item); @@ -26,42 +26,21 @@ public interface ISet : ICollection, IReadOnlySet void SymmetricExceptWith(IEnumerable other); //Check if this set is a subset of other - new bool IsSubsetOf(IEnumerable other); + bool IsSubsetOf(IEnumerable other); //Check if this set is a superset of other - new bool IsSupersetOf(IEnumerable other); + bool IsSupersetOf(IEnumerable other); //Check if this set is a subset of other, but not the same as it - new bool IsProperSupersetOf(IEnumerable other); + bool IsProperSupersetOf(IEnumerable other); //Check if this set is a superset of other, but not the same as it - new bool IsProperSubsetOf(IEnumerable other); + bool IsProperSubsetOf(IEnumerable other); //Check if this set has any elements in common with other - new bool Overlaps(IEnumerable other); + bool Overlaps(IEnumerable other); //Check if this set contains the same and only the same elements as other - new bool SetEquals(IEnumerable other); - - /// - /// Determines if the set contains a specific item - /// - /// The item to check if the set contains. - /// if found; otherwise . - new bool Contains(T item) => ((ICollection)this).Contains(item); - - bool IReadOnlySet.IsSubsetOf(IEnumerable other) => IsSubsetOf(other); - - bool IReadOnlySet.IsSupersetOf(IEnumerable other) => IsSupersetOf(other); - - bool IReadOnlySet.IsProperSupersetOf(IEnumerable other) => IsProperSupersetOf(other); - - bool IReadOnlySet.IsProperSubsetOf(IEnumerable other) => IsProperSubsetOf(other); - - bool IReadOnlySet.Overlaps(IEnumerable other) => Overlaps(other); - - bool IReadOnlySet.SetEquals(IEnumerable other) => SetEquals(other); - - bool IReadOnlySet.Contains(T value) => ((ICollection)this).Contains(value); + bool SetEquals(IEnumerable other); } } diff --git a/src/libraries/System.Private.Xml/src/System/Xml/Xsl/Runtime/XmlQuerySequence.cs b/src/libraries/System.Private.Xml/src/System/Xml/Xsl/Runtime/XmlQuerySequence.cs index 23fc7a5c2e65a7..3c7e5b6ad25c32 100644 --- a/src/libraries/System.Private.Xml/src/System/Xml/Xsl/Runtime/XmlQuerySequence.cs +++ b/src/libraries/System.Private.Xml/src/System/Xml/Xsl/Runtime/XmlQuerySequence.cs @@ -19,7 +19,7 @@ namespace System.Xml.Xsl.Runtime /// A sequence of Xml values that dynamically expands and allows random access to items. /// [EditorBrowsable(EditorBrowsableState.Never)] - public class XmlQuerySequence : IList, IReadOnlyList, System.Collections.IList + public class XmlQuerySequence : IList, System.Collections.IList { public static readonly XmlQuerySequence Empty = new XmlQuerySequence(); @@ -489,7 +489,7 @@ public void AddClone(XPathItem item) /// A sequence of Xml nodes that dynamically expands and allows random access to items. /// [EditorBrowsable(EditorBrowsableState.Never)] - public sealed class XmlQueryNodeSequence : XmlQuerySequence, IList, IReadOnlyList + public sealed class XmlQueryNodeSequence : XmlQuerySequence, IList { public static new readonly XmlQueryNodeSequence Empty = new XmlQueryNodeSequence(); @@ -731,19 +731,6 @@ XPathItem IList.this[int index] set { throw new NotSupportedException(); } } - /// - /// Return item at the specified index. - /// - XPathItem IReadOnlyList.this[int index] - { - get - { - ArgumentOutOfRangeException.ThrowIfGreaterThanOrEqual(index, Count); - - return base[index]; - } - } - /// /// Returns the index of the specified value in the sequence. /// diff --git a/src/libraries/System.Runtime/ref/System.Runtime.cs b/src/libraries/System.Runtime/ref/System.Runtime.cs index c2f175247dc9b6..a3f2a4b07e2f48 100644 --- a/src/libraries/System.Runtime/ref/System.Runtime.cs +++ b/src/libraries/System.Runtime/ref/System.Runtime.cs @@ -7803,35 +7803,29 @@ public partial interface IAsyncEnumerator : System.IAsyncDisposable T Current { get; } System.Threading.Tasks.ValueTask MoveNextAsync(); } - public partial interface ICollection : System.Collections.Generic.IEnumerable, System.Collections.IEnumerable, System.Collections.Generic.IReadOnlyCollection + public partial interface ICollection : System.Collections.Generic.IEnumerable, System.Collections.IEnumerable { - new int Count { get; } + int Count { get; } bool IsReadOnly { get; } void Add(T item); void Clear(); bool Contains(T item); void CopyTo(T[] array, int arrayIndex); bool Remove(T item); - int System.Collections.Generic.IReadOnlyCollection.Count => Count; } public partial interface IComparer { int Compare(T? x, T? y); } - public partial interface IDictionary : System.Collections.Generic.ICollection>, System.Collections.Generic.IEnumerable>, System.Collections.IEnumerable, System.Collections.Generic.IReadOnlyDictionary, System.Collections.Generic.IReadOnlyCollection> + public partial interface IDictionary : System.Collections.Generic.ICollection>, System.Collections.Generic.IEnumerable>, System.Collections.IEnumerable { - new TValue this[TKey key] { get; set; } - new System.Collections.Generic.ICollection Keys { get; } - new System.Collections.Generic.ICollection Values { get; } + TValue this[TKey key] { get; set; } + System.Collections.Generic.ICollection Keys { get; } + System.Collections.Generic.ICollection Values { get; } void Add(TKey key, TValue value); - new bool ContainsKey(TKey key); + bool ContainsKey(TKey key); bool Remove(TKey key); - new bool TryGetValue(TKey key, [System.Diagnostics.CodeAnalysis.MaybeNullWhenAttribute(false)] out TValue value); - TValue System.Collections.Generic.IReadOnlyDictionary.this[TKey key] => this[key]; - System.Collections.Generic.IEnumerable System.Collections.Generic.IReadOnlyDictionary.Keys => Keys; - System.Collections.Generic.IEnumerable System.Collections.Generic.IReadOnlyDictionary.Values => Values; - bool System.Collections.Generic.IReadOnlyDictionary.ContainsKey(TKey key) => ContainsKey(key); - bool System.Collections.Generic.IReadOnlyDictionary.TryGetValue(TKey key, [System.Diagnostics.CodeAnalysis.MaybeNullWhenAttribute(false)] out TValue value) => TryGetValue(key, out value); + bool TryGetValue(TKey key, [System.Diagnostics.CodeAnalysis.MaybeNullWhenAttribute(false)] out TValue value); } public partial interface IEnumerable : System.Collections.IEnumerable { @@ -7846,13 +7840,12 @@ public partial interface IEqualityComparer bool Equals(T? x, T? y); int GetHashCode([System.Diagnostics.CodeAnalysis.DisallowNullAttribute] T obj); } - public partial interface IList : System.Collections.Generic.ICollection, System.Collections.Generic.IEnumerable, System.Collections.IEnumerable, System.Collections.Generic.IReadOnlyList, System.Collections.Generic.IReadOnlyCollection + public partial interface IList : System.Collections.Generic.ICollection, System.Collections.Generic.IEnumerable, System.Collections.IEnumerable { - new T this[int index] { get; set; } + T this[int index] { get; set; } int IndexOf(T item); void Insert(int index, T item); void RemoveAt(int index); - T System.Collections.Generic.IReadOnlyList.this[int index] => this[index]; } public partial interface IReadOnlyCollection : System.Collections.Generic.IEnumerable, System.Collections.IEnumerable { @@ -7880,27 +7873,19 @@ public partial interface IReadOnlySet : System.Collections.Generic.IEnumerabl bool Overlaps(System.Collections.Generic.IEnumerable other); bool SetEquals(System.Collections.Generic.IEnumerable other); } - public partial interface ISet : System.Collections.Generic.ICollection, System.Collections.Generic.IEnumerable, System.Collections.IEnumerable, System.Collections.Generic.IReadOnlySet, System.Collections.Generic.IReadOnlyCollection + public partial interface ISet : System.Collections.Generic.ICollection, System.Collections.Generic.IEnumerable, System.Collections.IEnumerable { new bool Add(T item); void ExceptWith(System.Collections.Generic.IEnumerable other); void IntersectWith(System.Collections.Generic.IEnumerable other); - new bool IsProperSubsetOf(System.Collections.Generic.IEnumerable other); - new bool IsProperSupersetOf(System.Collections.Generic.IEnumerable other); - new bool IsSubsetOf(System.Collections.Generic.IEnumerable other); - new bool IsSupersetOf(System.Collections.Generic.IEnumerable other); - new bool Overlaps(System.Collections.Generic.IEnumerable other); - new bool SetEquals(System.Collections.Generic.IEnumerable other); + bool IsProperSubsetOf(System.Collections.Generic.IEnumerable other); + bool IsProperSupersetOf(System.Collections.Generic.IEnumerable other); + bool IsSubsetOf(System.Collections.Generic.IEnumerable other); + bool IsSupersetOf(System.Collections.Generic.IEnumerable other); + bool Overlaps(System.Collections.Generic.IEnumerable other); + bool SetEquals(System.Collections.Generic.IEnumerable other); void SymmetricExceptWith(System.Collections.Generic.IEnumerable other); void UnionWith(System.Collections.Generic.IEnumerable other); - new bool Contains(T item) => ((ICollection)this).Contains(item); - bool System.Collections.Generic.IReadOnlySet.Contains(T item) => ((ICollection)this).Contains(item); - bool System.Collections.Generic.IReadOnlySet.IsProperSubsetOf(System.Collections.Generic.IEnumerable other) => IsProperSubsetOf(other); - bool System.Collections.Generic.IReadOnlySet.IsProperSupersetOf(System.Collections.Generic.IEnumerable other) => IsProperSupersetOf(other); - bool System.Collections.Generic.IReadOnlySet.IsSubsetOf(System.Collections.Generic.IEnumerable other) => IsSubsetOf(other); - bool System.Collections.Generic.IReadOnlySet.IsSupersetOf(System.Collections.Generic.IEnumerable other) => IsSupersetOf(other); - bool System.Collections.Generic.IReadOnlySet.Overlaps(System.Collections.Generic.IEnumerable other) => Overlaps(other); - bool System.Collections.Generic.IReadOnlySet.SetEquals(System.Collections.Generic.IEnumerable other) => SetEquals(other); } public partial class KeyNotFoundException : System.SystemException { diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Nodes/JsonObject.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Nodes/JsonObject.cs index 021a4ac75b3c72..24f8653053af76 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Nodes/JsonObject.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Nodes/JsonObject.cs @@ -35,12 +35,7 @@ public JsonObject(IEnumerable> properties, JsonN { bool isCaseInsensitive = IsCaseInsensitive(options); - JsonPropertyDictionary dictionary = -#if NET9_0_OR_GREATER // ICollection : IReadOnlyCollection on .NET 9+ - properties is IReadOnlyCollection> propertiesCollection -#else - properties is ICollection> propertiesCollection -#endif + JsonPropertyDictionary dictionary = properties is ICollection> propertiesCollection ? new(isCaseInsensitive, propertiesCollection.Count) : new(isCaseInsensitive); From 6313ff8cee86c27aedade4d576f9e56c810cd345 Mon Sep 17 00:00:00 2001 From: Rich Lander Date: Sun, 28 Apr 2024 07:54:10 -0700 Subject: [PATCH 123/161] Update build to `net9.0` images (#101630) * Update build to `net9.0` images * Update docs/workflow/building/coreclr/linux-instructions.md Co-authored-by: Adeel Mujahid <3840695+am11@users.noreply.github.com> * Revert x86 build change --------- Co-authored-by: Sven Boemer Co-authored-by: Adeel Mujahid <3840695+am11@users.noreply.github.com> --- .../building/coreclr/linux-instructions.md | 17 +++++++++-------- .../templates/pipeline-with-resources.yml | 10 +++++----- 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/docs/workflow/building/coreclr/linux-instructions.md b/docs/workflow/building/coreclr/linux-instructions.md index 8e7457ff521850..518208141e49f6 100644 --- a/docs/workflow/building/coreclr/linux-instructions.md +++ b/docs/workflow/building/coreclr/linux-instructions.md @@ -59,14 +59,15 @@ docker pull mcr.microsoft.com/dotnet-buildtools/prereqs:cbl-mariner-2.0-cross-ar All official builds are cross-builds with a rootfs for the target OS, and will use the clang version available on the container. | Host OS | Target OS | Target Arch | Image location | crossrootfs location | -| --------------------- | ------------ | --------------- | -------------------------------------------------------------------------------- | -------------------- | -| CBL-mariner 2.0 (x64) | Alpine 3.13 | x64 | `mcr.microsoft.com/dotnet-buildtools/prereqs:cbl-mariner-2.0-cross-amd64-alpine` | `/crossrootfs/x64` | -| CBL-mariner 2.0 (x64) | Ubuntu 16.04 | x64 | `mcr.microsoft.com/dotnet-buildtools/prereqs:cbl-mariner-2.0-cross-amd64` | `/crossrootfs/x64` | -| CBL-mariner 2.0 (x64) | Alpine | arm32 (armhf) | `mcr.microsoft.com/dotnet-buildtools/prereqs:cbl-mariner-2.0-cross-arm-alpine` | `/crossrootfs/arm` | -| CBL-mariner 2.0 (x64) | Ubuntu 16.04 | arm32 (armhf) | `mcr.microsoft.com/dotnet-buildtools/prereqs:cbl-mariner-2.0-cross-arm` | `/crossrootfs/arm` | -| CBL-mariner 2.0 (x64) | Alpine | arm64 (arm64v8) | `mcr.microsoft.com/dotnet-buildtools/prereqs:cbl-mariner-2.0-cross-arm64-alpine` | `/crossrootfs/arm64` | -| CBL-mariner 2.0 (x64) | Ubuntu 16.04 | arm64 (arm64v8) | `mcr.microsoft.com/dotnet-buildtools/prereqs:cbl-mariner-2.0-cross-arm64` | `/crossrootfs/arm64` | -| Ubuntu 18.04 (x64) | FreeBSD | x64 | `mcr.microsoft.com/dotnet-buildtools/prereqs:ubuntu-18.04-cross-freebsd-12` | `/crossrootfs/x64` | +| --------------------- | ------------ | --------------- | -------------------------------------------------------------------------------------- | -------------------- | +| Azure Linux (x64) | Alpine 3.13 | x64 | `mcr.microsoft.com/dotnet-buildtools/prereqs:azurelinux-3.0-cross-amd64-alpine-net9.0` | `/crossrootfs/x64` | +| Azure Linux (x64) | Ubuntu 16.04 | x64 | `mcr.microsoft.com/dotnet-buildtools/prereqs:azurelinux-3.0-cross-amd64-net9.0` | `/crossrootfs/x64` | +| Azure Linux (x64) | Alpine | arm32 (armhf) | `mcr.microsoft.com/dotnet-buildtools/prereqs:azurelinux-3.0-cross-arm-alpine-net9.0` | `/crossrootfs/arm` | +| Azure Linux (x64) | Ubuntu 16.04 | arm32 (armhf) | `mcr.microsoft.com/dotnet-buildtools/prereqs:azurelinux-3.0-cross-arm-net9.0` | `/crossrootfs/arm` | +| Azure Linux (x64) | Alpine | arm64 (arm64v8) | `mcr.microsoft.com/dotnet-buildtools/prereqs:azurelinux-3.0-cross-arm64-alpine-net9.0` | `/crossrootfs/arm64` | +| Azure Linux (x64) | Ubuntu 16.04 | arm64 (arm64v8) | `mcr.microsoft.com/dotnet-buildtools/prereqs:azurelinux-3.0-cross-arm64-net9.0` | `/crossrootfs/arm64` | +| Azure Linux (x64) | Ubuntu 16.04 | x86 | `mcr.microsoft.com/dotnet-buildtools/prereqs:azurelinux-3.0-cross-x86-net8.0` | `/crossrootfs/x86` | +| CBL-mariner 2.0 (x64) | FreeBSD 13 | x64 | `mcr.microsoft.com/dotnet-buildtools/prereqs:cbl-mariner-2.0-cross-amd64-freebsd-13` | `/crossrootfs/x64` | These Docker images are built using the Dockerfiles maintained in the [dotnet-buildtools-prereqs-docker repo](https://github.com/dotnet/dotnet-buildtools-prereqs-docker). diff --git a/eng/pipelines/common/templates/pipeline-with-resources.yml b/eng/pipelines/common/templates/pipeline-with-resources.yml index 3c9fc538c4845b..aa7fc3acb1f06d 100644 --- a/eng/pipelines/common/templates/pipeline-with-resources.yml +++ b/eng/pipelines/common/templates/pipeline-with-resources.yml @@ -17,7 +17,7 @@ extends: containers: linux_arm: - image: mcr.microsoft.com/dotnet-buildtools/prereqs:azurelinux-3.0-cross-arm-net8.0 + image: mcr.microsoft.com/dotnet-buildtools/prereqs:azurelinux-3.0-cross-arm-net9.0 env: ROOTFS_DIR: /crossrootfs/arm @@ -33,17 +33,17 @@ extends: ROOTFS_DIR: /crossrootfs/arm64 linux_musl_x64: - image: mcr.microsoft.com/dotnet-buildtools/prereqs:azurelinux-3.0-cross-amd64-alpine-net8.0 + image: mcr.microsoft.com/dotnet-buildtools/prereqs:azurelinux-3.0-cross-amd64-alpine-net9.0 env: ROOTFS_DIR: /crossrootfs/x64 linux_musl_arm: - image: mcr.microsoft.com/dotnet-buildtools/prereqs:azurelinux-3.0-cross-arm-alpine-net8.0 + image: mcr.microsoft.com/dotnet-buildtools/prereqs:azurelinux-3.0-cross-arm-alpine-net9.0 env: ROOTFS_DIR: /crossrootfs/arm linux_musl_arm64: - image: mcr.microsoft.com/dotnet-buildtools/prereqs:azurelinux-3.0-cross-arm64-alpine-net8.0 + image: mcr.microsoft.com/dotnet-buildtools/prereqs:azurelinux-3.0-cross-arm64-alpine-net9.0 env: ROOTFS_DIR: /crossrootfs/arm64 @@ -56,7 +56,7 @@ extends: image: mcr.microsoft.com/dotnet-buildtools/prereqs:cbl-mariner-2.0-android-docker linux_x64: - image: mcr.microsoft.com/dotnet-buildtools/prereqs:azurelinux-3.0-cross-amd64-net8.0 + image: mcr.microsoft.com/dotnet-buildtools/prereqs:azurelinux-3.0-cross-amd64-net9.0 env: ROOTFS_DIR: /crossrootfs/x64 From c3e5ce97a29317d3dab98d09c310daf11a2260c7 Mon Sep 17 00:00:00 2001 From: Adeel Mujahid <3840695+am11@users.noreply.github.com> Date: Sun, 28 Apr 2024 22:08:05 +0300 Subject: [PATCH 124/161] Fix x86 build with clang-18 (#101650) * Fix x86 build with clang-18 * Suppress Wsync-alignment * Update x86 pipeline to use clang-18 --- eng/pipelines/common/templates/pipeline-with-resources.yml | 2 +- src/coreclr/CMakeLists.txt | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/eng/pipelines/common/templates/pipeline-with-resources.yml b/eng/pipelines/common/templates/pipeline-with-resources.yml index aa7fc3acb1f06d..62f8434f8335c0 100644 --- a/eng/pipelines/common/templates/pipeline-with-resources.yml +++ b/eng/pipelines/common/templates/pipeline-with-resources.yml @@ -61,7 +61,7 @@ extends: ROOTFS_DIR: /crossrootfs/x64 linux_x86: - image: mcr.microsoft.com/dotnet-buildtools/prereqs:azurelinux-3.0-cross-x86-net8.0 + image: mcr.microsoft.com/dotnet-buildtools/prereqs:azurelinux-3.0-cross-x86-net9.0 env: ROOTFS_DIR: /crossrootfs/x86 diff --git a/src/coreclr/CMakeLists.txt b/src/coreclr/CMakeLists.txt index aaf4005aa7394b..7ed0d509212cc4 100644 --- a/src/coreclr/CMakeLists.txt +++ b/src/coreclr/CMakeLists.txt @@ -206,6 +206,7 @@ if(CLR_CMAKE_HOST_UNIX) # warnings and errors to be suppressed. # Suppress these warnings here to avoid breaking the build. add_compile_options($<$:-Wno-null-arithmetic>) + add_compile_options($<$:-Wno-sync-alignment>) add_compile_options($<$:-Wno-conversion-null>) add_compile_options($<$:-Wno-pointer-arith>) From 95ed37a5dfaa75ca9ee8ec0b109a583e3ed753b1 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Sun, 28 Apr 2024 21:02:54 -0700 Subject: [PATCH 125/161] [main] Update dependencies from dotnet/roslyn (#101330) * Update dependencies from https://github.com/dotnet/roslyn build 20240419.13 Microsoft.SourceBuild.Intermediate.roslyn , Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.11.0-1.24219.1 -> To Version 4.11.0-1.24219.13 * Update dependencies from https://github.com/dotnet/roslyn build 20240420.2 Microsoft.SourceBuild.Intermediate.roslyn , Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.11.0-1.24219.1 -> To Version 4.11.0-1.24220.2 * Update dependencies from https://github.com/dotnet/roslyn build 20240421.2 Microsoft.SourceBuild.Intermediate.roslyn , Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.11.0-1.24219.1 -> To Version 4.11.0-1.24221.2 * Update dependencies from https://github.com/dotnet/roslyn build 20240423.2 Microsoft.SourceBuild.Intermediate.roslyn , Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.11.0-1.24219.1 -> To Version 4.11.0-1.24223.2 * Update dependencies from https://github.com/dotnet/roslyn build 20240423.15 Microsoft.SourceBuild.Intermediate.roslyn , Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.11.0-1.24219.1 -> To Version 4.11.0-1.24223.15 * Update dependencies from https://github.com/dotnet/roslyn build 20240424.9 Microsoft.SourceBuild.Intermediate.roslyn , Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.11.0-1.24219.1 -> To Version 4.11.0-1.24224.9 * Update dependencies from https://github.com/dotnet/roslyn build 20240425.10 Microsoft.SourceBuild.Intermediate.roslyn , Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.11.0-1.24219.1 -> To Version 4.11.0-1.24225.10 * Update dependencies from https://github.com/dotnet/roslyn build 20240426.4 Microsoft.SourceBuild.Intermediate.roslyn , Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.11.0-1.24219.1 -> To Version 4.11.0-1.24226.4 * Update dependencies from https://github.com/dotnet/roslyn build 20240428.1 Microsoft.SourceBuild.Intermediate.roslyn , Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.11.0-1.24219.1 -> To Version 4.11.0-1.24228.1 --------- Co-authored-by: dotnet-maestro[bot] Co-authored-by: Larry Ewing --- eng/Version.Details.xml | 16 ++++++++-------- eng/Versions.props | 6 +++--- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 9bcdac9884a810..029ab74db176f4 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -360,17 +360,17 @@ https://github.com/dotnet/runtime-assets 6e78861f1f307cd9f0e64a45b1d7884fa4470930 - + https://github.com/dotnet/roslyn - 3027ed4a9186a6924722a1597c8d31a59d411f7c + 7a96b1530744f6637ad6bb6bf5b8dfa33ea15b81 - + https://github.com/dotnet/roslyn - 3027ed4a9186a6924722a1597c8d31a59d411f7c + 7a96b1530744f6637ad6bb6bf5b8dfa33ea15b81 - + https://github.com/dotnet/roslyn - 3027ed4a9186a6924722a1597c8d31a59d411f7c + 7a96b1530744f6637ad6bb6bf5b8dfa33ea15b81 https://github.com/dotnet/roslyn-analyzers @@ -381,9 +381,9 @@ b07c100bfc66013a8444172d00cfa04c9ceb5a97 - + https://github.com/dotnet/roslyn - 3027ed4a9186a6924722a1597c8d31a59d411f7c + 7a96b1530744f6637ad6bb6bf5b8dfa33ea15b81 diff --git a/eng/Versions.props b/eng/Versions.props index 0ff857849146a1..25e794136a7ce1 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -42,9 +42,9 @@ Any tools that contribute to the design-time experience should use the MicrosoftCodeAnalysisVersion_LatestVS property above to ensure they do not break the local dev experience. --> - 4.11.0-1.24219.1 - 4.11.0-1.24219.1 - 4.11.0-1.24219.1 + 4.11.0-1.24228.1 + 4.11.0-1.24228.1 + 4.11.0-1.24228.1 diff --git a/eng/Versions.props b/eng/Versions.props index 25e794136a7ce1..223c05b2560787 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -34,8 +34,8 @@ - 3.11.0-beta1.24216.2 - 9.0.0-preview.24216.2 + 3.11.0-beta1.24225.1 + 9.0.0-preview.24225.1 - + https://github.com/dotnet/runtime - 56610095196ac12a397b1acd00835db4d86849b9 + b8fe1d0ccb60926d6e7ef5d42e2398c178c9ee5c - + https://github.com/dotnet/runtime - 56610095196ac12a397b1acd00835db4d86849b9 + b8fe1d0ccb60926d6e7ef5d42e2398c178c9ee5c - + https://github.com/dotnet/runtime - 56610095196ac12a397b1acd00835db4d86849b9 + b8fe1d0ccb60926d6e7ef5d42e2398c178c9ee5c - + https://github.com/dotnet/runtime - 56610095196ac12a397b1acd00835db4d86849b9 + b8fe1d0ccb60926d6e7ef5d42e2398c178c9ee5c https://github.com/dotnet/xharness diff --git a/eng/Versions.props b/eng/Versions.props index 223c05b2560787..168e86e4e81b2e 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -104,10 +104,10 @@ 6.0.0-preview.1.102 - 9.0.0-preview.4.24219.3 + 9.0.0-preview.4.24227.6 6.0.0 - 9.0.0-preview.4.24219.3 + 9.0.0-preview.4.24227.6 6.0.0 1.1.1 @@ -119,19 +119,19 @@ 8.0.0 5.0.0 4.5.5 - 9.0.0-preview.4.24219.3 - 9.0.0-preview.4.24219.3 + 9.0.0-preview.4.24227.6 + 9.0.0-preview.4.24227.6 6.0.0 5.0.0 5.0.0 5.0.0 7.0.0 - 9.0.0-preview.4.24219.3 + 9.0.0-preview.4.24227.6 6.0.0 7.0.0 4.5.4 4.5.0 - 9.0.0-preview.4.24219.3 + 9.0.0-preview.4.24227.6 8.0.0 8.0.0 @@ -210,7 +210,7 @@ 0.11.4-alpha.24222.1 - 9.0.0-preview.4.24219.3 + 9.0.0-preview.4.24227.6 9.0.0-preview.5.24223.2 diff --git a/src/coreclr/tools/Common/TypeSystem/Common/Utilities/CustomAttributeTypeNameParser.cs b/src/coreclr/tools/Common/TypeSystem/Common/Utilities/CustomAttributeTypeNameParser.cs index 72779375f4697a..33a86023ced277 100644 --- a/src/coreclr/tools/Common/TypeSystem/Common/Utilities/CustomAttributeTypeNameParser.cs +++ b/src/coreclr/tools/Common/TypeSystem/Common/Utilities/CustomAttributeTypeNameParser.cs @@ -29,6 +29,8 @@ namespace System.Reflection { internal partial struct TypeNameParser { + private static readonly TypeNameParseOptions s_typeNameParseOptions = new() { MaxNodes = int.MaxValue }; + private ModuleDesc _module; private bool _throwIfNotFound; private Func _canonResolver; @@ -36,7 +38,7 @@ internal partial struct TypeNameParser public static TypeDesc ResolveType(ModuleDesc module, string name, bool throwIfNotFound, Func canonResolver) { - if (!TypeName.TryParse(name.AsSpan(), out TypeName parsed)) + if (!TypeName.TryParse(name.AsSpan(), out TypeName parsed, s_typeNameParseOptions)) { ThrowHelper.ThrowTypeLoadException(name, module); } diff --git a/src/coreclr/tools/ILVerification/ILVerification.projitems b/src/coreclr/tools/ILVerification/ILVerification.projitems index 3b2c30ddef1f18..c0f3644b1ab343 100644 --- a/src/coreclr/tools/ILVerification/ILVerification.projitems +++ b/src/coreclr/tools/ILVerification/ILVerification.projitems @@ -66,30 +66,6 @@ Utilities\CustomAttributeTypeNameParser.cs - - Utilities\HexConverter.cs - - - Utilities\AssemblyNameFormatter.cs - - - Utilities\AssemblyNameParser.cs - - - Utilities\Metadata\AssemblyNameInfo.cs - - - Utilities\TypeName.cs - - - Utilities\TypeNameParserOptions.cs - - - Utilities\TypeNameParser.cs - - - Utilities\TypeNameParserHelpers.cs - System\Diagnostics\CodeAnalysis\UnconditionalSuppressMessageAttribute.cs diff --git a/src/coreclr/tools/ILVerify/ILVerify.csproj b/src/coreclr/tools/ILVerify/ILVerify.csproj index e1915c65d6f2dd..804f32ddc7bc38 100644 --- a/src/coreclr/tools/ILVerify/ILVerify.csproj +++ b/src/coreclr/tools/ILVerify/ILVerify.csproj @@ -17,6 +17,7 @@ + diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/TypeNameParser.Dataflow.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/TypeNameParser.Dataflow.cs index 5b0cfdb12b4445..278b6c4735afcc 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/TypeNameParser.Dataflow.cs +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/TypeNameParser.Dataflow.cs @@ -9,6 +9,8 @@ namespace System.Reflection { internal partial struct TypeNameParser { + private static readonly TypeNameParseOptions s_typeNameParseOptions = new() { MaxNodes = int.MaxValue }; + private TypeSystemContext _context; private ModuleDesc _callingModule; private List _referencedModules; @@ -17,7 +19,7 @@ internal partial struct TypeNameParser public static TypeDesc ResolveType(string name, ModuleDesc callingModule, TypeSystemContext context, List referencedModules, out bool typeWasNotFoundInAssemblyNorBaseLibrary) { - if (!TypeName.TryParse(name, out TypeName parsed)) + if (!TypeName.TryParse(name, out TypeName parsed, s_typeNameParseOptions)) { typeWasNotFoundInAssemblyNorBaseLibrary = false; return null; diff --git a/src/coreclr/tools/aot/ILCompiler.TypeSystem/ILCompiler.TypeSystem.csproj b/src/coreclr/tools/aot/ILCompiler.TypeSystem/ILCompiler.TypeSystem.csproj index 23afa3780b1abc..1a5db3b44445da 100644 --- a/src/coreclr/tools/aot/ILCompiler.TypeSystem/ILCompiler.TypeSystem.csproj +++ b/src/coreclr/tools/aot/ILCompiler.TypeSystem/ILCompiler.TypeSystem.csproj @@ -198,39 +198,12 @@ Utilities\CustomAttributeTypeNameParser.cs - - Utilities\HexConverter.cs - - - Utilities\AssemblyNameFormatter.cs - - - Utilities\AssemblyNameParser.cs - - - Utilities\AssemblyNameInfo.cs - - - Utilities\TypeName.cs - - - Utilities\TypeNameParser.cs - - - Utilities\TypeNameParserHelpers.cs - - - Utilities\TypeNameParserOptions.cs - Utilities\CustomAttributeTypeNameParser.Helpers Utilities\ValueStringBuilder.cs - - Utilities\ValueStringBuilder.AppendSpanFormattable.cs - Utilities\GCPointerMap.Algorithm.cs @@ -741,6 +714,10 @@ + + + + runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/src/libraries/Common/src/System/Reflection/Metadata/AssemblyNameInfo.cs b/src/libraries/Common/src/System/Reflection/Metadata/AssemblyNameInfo.cs index ee586e3b57a8c0..cb4de9467f660b 100644 --- a/src/libraries/Common/src/System/Reflection/Metadata/AssemblyNameInfo.cs +++ b/src/libraries/Common/src/System/Reflection/Metadata/AssemblyNameInfo.cs @@ -21,10 +21,10 @@ namespace System.Reflection.Metadata /// It's a more lightweight, immutable version of that does not pre-allocate instances. /// [DebuggerDisplay("{FullName}")] -#if SYSTEM_PRIVATE_CORELIB - internal -#else +#if SYSTEM_REFLECTION_METADATA public +#else + internal #endif sealed class AssemblyNameInfo { @@ -182,11 +182,7 @@ public AssemblyName ToAssemblyName() public static AssemblyNameInfo Parse(ReadOnlySpan assemblyName) => TryParse(assemblyName, out AssemblyNameInfo? result) ? result! -#if SYSTEM_REFLECTION_METADATA || SYSTEM_PRIVATE_CORELIB : throw new ArgumentException(SR.InvalidAssemblyName, nameof(assemblyName)); -#else // tools that reference this file as a link - : throw new ArgumentException("The given assembly name was invalid.", nameof(assemblyName)); -#endif /// /// Tries to parse a span of characters into an assembly name. diff --git a/src/libraries/Common/src/System/Reflection/Metadata/TypeName.cs b/src/libraries/Common/src/System/Reflection/Metadata/TypeName.cs index 2fac2f8ffd74db..1464f0248280b2 100644 --- a/src/libraries/Common/src/System/Reflection/Metadata/TypeName.cs +++ b/src/libraries/Common/src/System/Reflection/Metadata/TypeName.cs @@ -16,10 +16,10 @@ namespace System.Reflection.Metadata { [DebuggerDisplay("{AssemblyQualifiedName}")] -#if SYSTEM_PRIVATE_CORELIB - internal -#else +#if SYSTEM_REFLECTION_METADATA public +#else + internal #endif sealed class TypeName { diff --git a/src/libraries/Common/src/System/Reflection/Metadata/TypeNameParser.cs b/src/libraries/Common/src/System/Reflection/Metadata/TypeNameParser.cs index 7c75f3ee844d6d..dcba442054a5d6 100644 --- a/src/libraries/Common/src/System/Reflection/Metadata/TypeNameParser.cs +++ b/src/libraries/Common/src/System/Reflection/Metadata/TypeNameParser.cs @@ -17,7 +17,8 @@ namespace System.Reflection.Metadata [DebuggerDisplay("{_inputString}")] internal ref struct TypeNameParser { - private static readonly TypeNameParseOptions _defaults = new(); + private static readonly TypeNameParseOptions s_defaults = new(); + private readonly bool _throwOnError; private readonly TypeNameParseOptions _parseOptions; private ReadOnlySpan _inputString; @@ -26,7 +27,7 @@ private TypeNameParser(ReadOnlySpan name, bool throwOnError, TypeNameParse { _inputString = name; _throwOnError = throwOnError; - _parseOptions = options ?? _defaults; + _parseOptions = options ?? s_defaults; } internal static TypeName? Parse(ReadOnlySpan typeName, bool throwOnError, TypeNameParseOptions? options = default) @@ -50,7 +51,7 @@ private TypeNameParser(ReadOnlySpan name, bool throwOnError, TypeNameParse { if (throwOnError) { - if (recursiveDepth >= parser._parseOptions.MaxNodes) + if (parser._parseOptions.IsMaxDepthExceeded(recursiveDepth)) { ThrowInvalidOperation_MaxNodesExceeded(parser._parseOptions.MaxNodes); } @@ -249,7 +250,7 @@ private bool TryParseAssemblyName(ref AssemblyNameInfo? assemblyName) private bool TryDive(ref int depth) { - if (depth >= _parseOptions.MaxNodes) + if (_parseOptions.IsMaxDepthExceeded(depth)) { return false; } diff --git a/src/libraries/Common/src/System/Reflection/Metadata/TypeNameParserHelpers.cs b/src/libraries/Common/src/System/Reflection/Metadata/TypeNameParserHelpers.cs index 3783f56c73d4b7..1cdc5e230ad96a 100644 --- a/src/libraries/Common/src/System/Reflection/Metadata/TypeNameParserHelpers.cs +++ b/src/libraries/Common/src/System/Reflection/Metadata/TypeNameParserHelpers.cs @@ -331,53 +331,64 @@ internal static bool TryStripFirstCharAndTrailingSpaces(ref ReadOnlySpan s } [DoesNotReturn] - internal static void ThrowInvalidOperation_MaxNodesExceeded(int limit) => throw -#if SYSTEM_REFLECTION_METADATA - new InvalidOperationException(SR.Format(SR.InvalidOperation_MaxNodesExceeded, limit)); -#else // corelib and tools that reference this file as a link - new InvalidOperationException(); -#endif + internal static void ThrowArgumentException_InvalidTypeName(int errorIndex) + { + throw new ArgumentException(SR.Argument_InvalidTypeName, $"typeName@{errorIndex}"); + } [DoesNotReturn] - internal static void ThrowArgumentException_InvalidTypeName(int errorIndex) => throw -#if SYSTEM_PRIVATE_CORELIB - new ArgumentException(SR.Arg_ArgumentException, $"typeName@{errorIndex}"); -#elif SYSTEM_REFLECTION_METADATA - new ArgumentException(SR.Argument_InvalidTypeName, $"typeName@{errorIndex}"); -#else // tools that reference this file as a link - new ArgumentException(); + internal static void ThrowInvalidOperation_MaxNodesExceeded(int limit) + { +#if SYSTEM_REFLECTION_METADATA + throw new InvalidOperationException(SR.Format(SR.InvalidOperation_MaxNodesExceeded, limit)); +#else + Debug.Fail("Expected to be unreachable"); + throw new InvalidOperationException(); #endif + } [DoesNotReturn] - internal static void ThrowInvalidOperation_NotGenericType() => throw -#if SYSTEM_REFLECTION_METADATA || SYSTEM_PRIVATE_CORELIB - new InvalidOperationException(SR.InvalidOperation_NotGenericType); -#else // tools that reference this file as a link - new InvalidOperationException(); + internal static void ThrowInvalidOperation_NotGenericType() + { +#if SYSTEM_REFLECTION_METADATA + throw new InvalidOperationException(SR.InvalidOperation_NotGenericType); +#else + Debug.Fail("Expected to be unreachable"); + throw new InvalidOperationException(); #endif + } [DoesNotReturn] - internal static void ThrowInvalidOperation_NotNestedType() => throw + internal static void ThrowInvalidOperation_NotNestedType() + { #if SYSTEM_REFLECTION_METADATA - new InvalidOperationException(SR.InvalidOperation_NotNestedType); -#else // corelib and tools that reference this file as a link - new InvalidOperationException(); + throw new InvalidOperationException(SR.InvalidOperation_NotNestedType); +#else + Debug.Fail("Expected to be unreachable"); + throw new InvalidOperationException(); #endif + } [DoesNotReturn] - internal static void ThrowInvalidOperation_NoElement() => throw + internal static void ThrowInvalidOperation_NoElement() + { #if SYSTEM_REFLECTION_METADATA - new InvalidOperationException(SR.InvalidOperation_NoElement); -#else // corelib and tools that reference this file as a link - new InvalidOperationException(); + throw new InvalidOperationException(SR.InvalidOperation_NoElement); +#else + Debug.Fail("Expected to be unreachable"); + throw new InvalidOperationException(); #endif + } [DoesNotReturn] - internal static void ThrowInvalidOperation_HasToBeArrayClass() => throw -#if SYSTEM_REFLECTION_METADATA || SYSTEM_PRIVATE_CORELIB - new InvalidOperationException(SR.Argument_HasToBeArrayClass); -#else // tools that reference this file as a link - new InvalidOperationException(); + internal static void ThrowInvalidOperation_HasToBeArrayClass() + { +#if SYSTEM_REFLECTION_METADATA + throw new InvalidOperationException(SR.Argument_HasToBeArrayClass); +#else + Debug.Fail("Expected to be unreachable"); + throw new InvalidOperationException(); #endif + } } } diff --git a/src/libraries/Common/src/System/Reflection/Metadata/TypeNameParserOptions.cs b/src/libraries/Common/src/System/Reflection/Metadata/TypeNameParserOptions.cs index 66350c9a44cac7..551876e73147c9 100644 --- a/src/libraries/Common/src/System/Reflection/Metadata/TypeNameParserOptions.cs +++ b/src/libraries/Common/src/System/Reflection/Metadata/TypeNameParserOptions.cs @@ -3,19 +3,9 @@ namespace System.Reflection.Metadata { -#if SYSTEM_PRIVATE_CORELIB - internal -#else - public -#endif - sealed class TypeNameParseOptions + public sealed class TypeNameParseOptions { - private int _maxNodes = -#if SYSTEM_PRIVATE_CORELIB - int.MaxValue; // CoreLib has never introduced any limits -#else - 20; -#endif + private int _maxNodes = 20; /// /// Limits the maximum value of node count that parser can handle. @@ -37,5 +27,7 @@ public int MaxNodes _maxNodes = value; } } + + internal bool IsMaxDepthExceeded(int depth) => depth >= _maxNodes; } } diff --git a/src/libraries/Common/src/System/Reflection/TypeNameParser.Helpers.cs b/src/libraries/Common/src/System/Reflection/TypeNameParser.Helpers.cs index bcb2125d3f4ea3..84ef2137fb095b 100644 --- a/src/libraries/Common/src/System/Reflection/TypeNameParser.Helpers.cs +++ b/src/libraries/Common/src/System/Reflection/TypeNameParser.Helpers.cs @@ -8,6 +8,28 @@ #nullable enable +#if SYSTEM_PRIVATE_CORELIB +namespace System.Reflection.Metadata +{ + internal struct TypeNameParseOptions + { + public TypeNameParseOptions() { } +#pragma warning disable CA1822 // Mark members as static + // CoreLib does not enforce any limits + public bool IsMaxDepthExceeded(int _) => false; + public int MaxNodes + { + get + { + Debug.Fail("Expected to be unreachable"); + return 0; + } + } +#pragma warning restore CA1822 + } +} +#endif + namespace System.Reflection { internal partial struct TypeNameParser diff --git a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems index fccffa63fa159e..f1b61a1ea67c4b 100644 --- a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems +++ b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems @@ -1424,6 +1424,9 @@ Common\System\LocalAppContextSwitches.Common.cs + + Common\System\HexConverter.cs + Common\System\HResults.cs @@ -1493,9 +1496,6 @@ Common\System\Reflection\Metadata\TypeNameParserHelpers.cs - - Common\System\Reflection\Metadata\TypeNameParserOptions.cs - Common\System\Runtime\Versioning\NonVersionableAttribute.cs @@ -1599,11 +1599,6 @@ - - - Common\System\HexConverter.cs - - Common\Interop\Windows\Advapi32\Interop.EncryptDecrypt.cs From f88ab88f4ce02569f84922cda802317e69682d8a Mon Sep 17 00:00:00 2001 From: Qiao Pengcheng Date: Mon, 29 Apr 2024 16:40:51 +0800 Subject: [PATCH 129/161] fixed the split error for LoongArch64. (#101656) * fixed the split error for LoongArch64. * amend code for CRs. * amend the splitting's judge independent of the `var->lvIsSplit` which will be delete in future. --- src/coreclr/jit/abi.cpp | 4 +++ src/coreclr/jit/codegencommon.cpp | 55 ++++++++++++++++++++----------- 2 files changed, 40 insertions(+), 19 deletions(-) diff --git a/src/coreclr/jit/abi.cpp b/src/coreclr/jit/abi.cpp index 7a594f77f39121..7fa39d04644342 100644 --- a/src/coreclr/jit/abi.cpp +++ b/src/coreclr/jit/abi.cpp @@ -259,13 +259,17 @@ bool ABIPassingInformation::HasExactlyOneStackSegment() const bool ABIPassingInformation::IsSplitAcrossRegistersAndStack() const { if (NumSegments < 2) + { return false; + } bool isFirstInReg = Segments[0].IsPassedInRegister(); for (unsigned i = 1; i < NumSegments; i++) { if (isFirstInReg != Segments[i].IsPassedInRegister()) + { return true; + } } return false; } diff --git a/src/coreclr/jit/codegencommon.cpp b/src/coreclr/jit/codegencommon.cpp index c3608402d27ec2..301b10b1de0717 100644 --- a/src/coreclr/jit/codegencommon.cpp +++ b/src/coreclr/jit/codegencommon.cpp @@ -4119,7 +4119,7 @@ void CodeGen::genEnregisterOSRArgsAndLocals() } } -#if defined(SWIFT_SUPPORT) || defined(TARGET_RISCV64) +#if defined(SWIFT_SUPPORT) || defined(TARGET_RISCV64) || defined(TARGET_LOONGARCH64) //----------------------------------------------------------------------------- // genHomeSwiftStructParameters: Move the incoming segment to the local stack frame. // @@ -4159,8 +4159,16 @@ void CodeGen::genHomeStackSegment(unsigned lclNum, } emitAttr size = emitTypeSize(loadType); - int loadOffset = - -(isFramePointerUsed() ? genCallerSPtoFPdelta() : genCallerSPtoInitialSPdelta()) + (int)seg.GetStackOffset(); + int loadOffset = (int)seg.GetStackOffset(); + if (isFramePointerUsed()) + { + loadOffset -= genCallerSPtoFPdelta(); + } + else + { + loadOffset -= genCallerSPtoInitialSPdelta(); + } + #ifdef TARGET_XARCH GetEmitter()->emitIns_R_AR(ins_Load(loadType), size, initReg, genFramePointerReg(), loadOffset); #else @@ -4171,7 +4179,7 @@ void CodeGen::genHomeStackSegment(unsigned lclNum, if (initRegStillZeroed) *initRegStillZeroed = false; } -#endif // defined(SWIFT_SUPPORT) || defined(TARGET_RISCV64) +#endif // defined(SWIFT_SUPPORT) || defined(TARGET_RISCV64) || defined(TARGET_LOONGARCH64) #ifdef SWIFT_SUPPORT @@ -4248,32 +4256,41 @@ void CodeGen::genHomeSwiftStructParameters(bool handleStack) // void CodeGen::genHomeStackPartOfSplitParameter(regNumber initReg, bool* initRegStillZeroed) { -#ifdef TARGET_RISCV64 +#if defined(TARGET_RISCV64) || defined(TARGET_LOONGARCH64) unsigned lclNum = 0; for (; lclNum < compiler->info.compArgsCount; lclNum++) { LclVarDsc* var = compiler->lvaGetDesc(lclNum); - if (!var->lvIsSplit || !var->lvOnFrame) + if (!var->lvOnFrame || !varTypeIsStruct(var)) + { continue; + } - JITDUMP("Homing stack part of split parameter V%02u\n", lclNum); - - assert(varTypeIsStruct(var)); - assert(!compiler->lvaIsImplicitByRefLocal(lclNum)); const ABIPassingInformation& abiInfo = compiler->lvaGetParameterABIInfo(lclNum); - assert(abiInfo.NumSegments == 2); - assert(abiInfo.Segments[0].GetRegister() == REG_ARG_LAST); - const ABIPassingSegment& seg = abiInfo.Segments[1]; + if (abiInfo.IsSplitAcrossRegistersAndStack()) + { + assert(var->lvIsSplit); + JITDUMP("Homing stack part of split parameter V%02u\n", lclNum); - genHomeStackSegment(lclNum, seg, initReg, initRegStillZeroed); + assert(abiInfo.NumSegments == 2); + assert(abiInfo.Segments[0].GetRegister() == REG_ARG_LAST); + assert(abiInfo.Segments[1].GetStackOffset() == 0); + const ABIPassingSegment& seg = abiInfo.Segments[1]; - for (lclNum += 1; lclNum < compiler->info.compArgsCount; lclNum++) - { - assert(!compiler->lvaGetDesc(lclNum)->lvIsSplit); // There should be only one split parameter + genHomeStackSegment(lclNum, seg, initReg, initRegStillZeroed); + +#ifdef DEBUG + for (lclNum += 1; lclNum < compiler->info.compArgsCount; lclNum++) + { + const ABIPassingInformation& abiInfo2 = compiler->lvaGetParameterABIInfo(lclNum); + // There should be only one split parameter + assert(!abiInfo2.IsSplitAcrossRegistersAndStack()); + } +#endif + break; } - break; } -#endif +#endif // TARGET_RISCV64 || TARGET_LOONGARCH64 } /*----------------------------------------------------------------------------- From 9b4c5c6ad69dc6cc4fbbc584d63d4f836766efdc Mon Sep 17 00:00:00 2001 From: Eric StJohn Date: Mon, 29 Apr 2024 08:46:53 -0700 Subject: [PATCH 130/161] Prefer most derived member in Configuration Binder source generator (#101316) * Prefer most derived member in Configuration Binder source generator * Skip overridden properties in config source generator - include only definitions --- .../ConfigurationBindingGenerator.Parser.cs | 6 ++ .../ConfigurationBinderTests.TestClasses.cs | 59 ++++++++++++++++++ .../tests/Common/ConfigurationBinderTests.cs | 62 +++++++++++++++++++ 3 files changed, 127 insertions(+) diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/ConfigurationBindingGenerator.Parser.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/ConfigurationBindingGenerator.Parser.cs index a569be384367eb..cb39cd788cfd7d 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/ConfigurationBindingGenerator.Parser.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/ConfigurationBindingGenerator.Parser.cs @@ -660,6 +660,12 @@ private ObjectSpec CreateObjectSpec(TypeParseInfo typeParseInfo) if (member is IPropertySymbol { IsIndexer: false, IsImplicitlyDeclared: false } property && !IsUnsupportedType(property.Type)) { string propertyName = property.Name; + + if (property.IsOverride || properties?.ContainsKey(propertyName) is true) + { + continue; + } + TypeRef propertyTypeRef = EnqueueTransitiveType(typeParseInfo, property.Type, DiagnosticDescriptors.PropertyNotSupported, propertyName); AttributeData? attributeData = property.GetAttributes().FirstOrDefault(a => SymbolEqualityComparer.Default.Equals(a.AttributeClass, _typeSymbols.ConfigurationKeyNameAttribute)); diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/Common/ConfigurationBinderTests.TestClasses.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/Common/ConfigurationBinderTests.TestClasses.cs index 9aad9566463aff..02f3a74f317b1a 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/Common/ConfigurationBinderTests.TestClasses.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/Common/ConfigurationBinderTests.TestClasses.cs @@ -930,5 +930,64 @@ public class SimplePoco public string B { get; set; } } + public class BaseForHiddenMembers + { + public string A { get; set; } + public string B { get; set; } + public TestSettingsEnum E {get; set;} + + public virtual string C { get => CBase; set => CBase = value; } + + public string CBase; + + public virtual string D { get; } + + public virtual string F { get => FBase; set => FBase = value; } + public string FBase; + + + public virtual int X { get => XBase; set => XBase = value; } + public int XBase; + } + + public enum TestSettingsEnum2 + { + // Note - the reflection binder will try to bind to every member + Option1 = TestSettingsEnum.Option1, + Option2 = TestSettingsEnum.Option2, + } + + public class IntermediateDerivedClass : BaseForHiddenMembers + { + public new virtual string D { get => DBase; set => DBase = value; } + public string DBase; + + public override string F { get => "IF"; } + + } + + public class DerivedClassWithHiddenMembers : IntermediateDerivedClass + { + public new string A { get; } = "ADerived"; + public new int B { get; set; } + public new TestSettingsEnum2 E + { + get => (TestSettingsEnum2)base.E; + set => base.E = (TestSettingsEnum)value; + } + + // only override get + public override string C { get => "DC"; } + + // override new only get + public override string D { get => "DD"; } + + // two overrides of only get + public override string F { get => "DF"; } + + // override only set + public override int X { set => base.X = value + 1; } + } + } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/Common/ConfigurationBinderTests.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/Common/ConfigurationBinderTests.cs index 7b0a8ca7e7e385..95585b76239237 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/Common/ConfigurationBinderTests.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/Common/ConfigurationBinderTests.cs @@ -2471,5 +2471,67 @@ public MockConfigurationRoot(IList providers) : base(pro IConfigurationSection IConfiguration.GetSection(string key) => this[key] is null ? null : new ConfigurationSection(this, key); } + + [Fact] + public void CanBindToClassWithNewProperties() + { + /// the source generator will bind to the most derived property only. + /// the reflection binder will bind the same data to all properties (including hidden). + + var config = TestHelpers.GetConfigurationFromJsonString(""" + { + "A": "AVal", + "B": "5", + "C": "CVal", + "D": "DVal", + "E": "Option2", + "F": "FVal", + "X": "52" + } + """); + var obj = new DerivedClassWithHiddenMembers(); + + config.Bind(obj); + + BaseForHiddenMembers baseObj = obj; + IntermediateDerivedClass intermediateObj = obj; + + Assert.Equal("ADerived", obj.A); +#if BUILDING_SOURCE_GENERATOR_TESTS + // source generator will not set hidden property + Assert.Null(baseObj.A); +#else + // reflection binder will set hidden property + Assert.Equal("AVal", baseObj.A); +#endif + + Assert.Equal(5, obj.B); +#if BUILDING_SOURCE_GENERATOR_TESTS + // source generator will not set hidden property + Assert.Null(baseObj.B); +#else + // reflection binder will set hidden property + Assert.Equal("5", baseObj.B); +#endif + + Assert.Equal(TestSettingsEnum2.Option2, obj.E); + Assert.Equal(TestSettingsEnum.Option2, baseObj.E); + + Assert.Equal("DC", obj.C); + // The setter should still be called, even when only getter is overridden. + Assert.Equal("CVal", obj.CBase); + + // can hide a readonly property with r/w property + Assert.Null(baseObj.D); + Assert.Equal("DD", obj.D); + // The setter should still be called, even when only getter is overridden. + Assert.Equal("DVal", obj.DBase); + + Assert.Equal("DF", obj.F); + Assert.Equal("FVal", obj.FBase); + + Assert.Equal(53, obj.X); + Assert.Equal(53, obj.XBase); + } } } From 92ca5f3227ada3f1620cd9b0ea631491303e4148 Mon Sep 17 00:00:00 2001 From: Keith Dahlby Date: Mon, 29 Apr 2024 10:49:01 -0500 Subject: [PATCH 131/161] Annotate `config.GetValue()` with `[NotNullIfNotNull]` (#101336) * Annotate GetValue() with [NotNullIfNotNull] * Avoid duplicate NullableAttributes.cs * Annotate generated GetValue() with [NotNullIfNotNull] --- src/libraries/Directory.Build.targets | 1 + .../ConfigurationBindingGenerator.Emitter.cs | 2 ++ .../ConfigurationBindingGenerator.Parser.cs | 1 + .../gen/Emitter/ConfigurationBinder.cs | 10 ++++++++ .../gen/Parser/KnownTypeSymbols.cs | 4 +++ .../gen/Specs/SourceGenerationSpec.cs | 1 + ...crosoft.Extensions.Configuration.Binder.cs | 2 ++ .../src/ConfigurationBinder.cs | 2 ++ .../tests/Common/ConfigurationBinderTests.cs | 25 ++++++++++++++----- .../GetValue.generated.txt | 2 ++ .../GetValue_T_Key_DefaultValue.generated.txt | 1 + ...alue_TypeOf_Key_DefaultValue.generated.txt | 1 + ...ation.Binder.SourceGeneration.Tests.csproj | 3 +++ 13 files changed, 49 insertions(+), 6 deletions(-) diff --git a/src/libraries/Directory.Build.targets b/src/libraries/Directory.Build.targets index e3d599b2d8276a..5a3fff449e7bba 100644 --- a/src/libraries/Directory.Build.targets +++ b/src/libraries/Directory.Build.targets @@ -170,6 +170,7 @@ diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/ConfigurationBindingGenerator.Emitter.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/ConfigurationBindingGenerator.Emitter.cs index d8c5a8925b46b2..1dceb31a0cc8aa 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/ConfigurationBindingGenerator.Emitter.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/ConfigurationBindingGenerator.Emitter.cs @@ -15,6 +15,7 @@ private sealed partial class Emitter private readonly TypeIndex _typeIndex; private readonly bool _emitEnumParseMethod; private readonly bool _emitGenericParseEnum; + private readonly bool _emitNotNullIfNotNull; private readonly bool _emitThrowIfNullMethod; private readonly SourceWriter _writer = new(); @@ -26,6 +27,7 @@ public Emitter(SourceGenerationSpec sourceGenSpec) _typeIndex = new TypeIndex(sourceGenSpec.ConfigTypes); _emitEnumParseMethod = sourceGenSpec.EmitEnumParseMethod; _emitGenericParseEnum = sourceGenSpec.EmitGenericParseEnum; + _emitNotNullIfNotNull = sourceGenSpec.EmitNotNullIfNotNull; _emitThrowIfNullMethod = sourceGenSpec.EmitThrowIfNullMethod; } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/ConfigurationBindingGenerator.Parser.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/ConfigurationBindingGenerator.Parser.cs index cb39cd788cfd7d..3d6e2b6503101a 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/ConfigurationBindingGenerator.Parser.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/ConfigurationBindingGenerator.Parser.cs @@ -57,6 +57,7 @@ internal sealed partial class Parser(CompilationData compilationData) ConfigTypes = _createdTypeSpecs.Values.OrderBy(s => s.TypeRef.FullyQualifiedName).ToImmutableEquatableArray(), EmitEnumParseMethod = _emitEnumParseMethod, EmitGenericParseEnum = _emitGenericParseEnum, + EmitNotNullIfNotNull = _typeSymbols.NotNullIfNotNullAttribute is not null, EmitThrowIfNullMethod = IsThrowIfNullMethodToBeEmitted() }; } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Emitter/ConfigurationBinder.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Emitter/ConfigurationBinder.cs index c6f23779ec93d4..f49cabc8bfc0c5 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Emitter/ConfigurationBinder.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Emitter/ConfigurationBinder.cs @@ -73,6 +73,7 @@ private void EmitGetValueMethods() if (ShouldEmitMethods(MethodsToGen.ConfigBinder_GetValue_T_key_defaultValue)) { EmitStartDefinition_Get_Or_GetValue_Overload(MethodsToGen.ConfigBinder_GetValue_T_key_defaultValue, documentation); + EmitNotNullIfNotNull(Identifier.defaultValue); _writer.WriteLine($"public static T? {Identifier.GetValue}(this {Identifier.IConfiguration} {Identifier.configuration}, string {Identifier.key}, T {Identifier.defaultValue}) => " + $"(T?)({expressionForGetValueCore}({Identifier.configuration}, typeof(T), {Identifier.key}) ?? {Identifier.defaultValue});"); } @@ -87,11 +88,20 @@ private void EmitGetValueMethods() if (ShouldEmitMethods(MethodsToGen.ConfigBinder_GetValue_TypeOf_key_defaultValue)) { EmitStartDefinition_Get_Or_GetValue_Overload(MethodsToGen.ConfigBinder_GetValue_TypeOf_key_defaultValue, documentation); + EmitNotNullIfNotNull(Identifier.defaultValue); _writer.WriteLine($"public static object? {Identifier.GetValue}(this {Identifier.IConfiguration} {Identifier.configuration}, Type {Identifier.type}, string {Identifier.key}, object? {Identifier.defaultValue}) => " + $"{expressionForGetValueCore}({Identifier.configuration}, {Identifier.type}, {Identifier.key}) ?? {Identifier.defaultValue};"); } } + private void EmitNotNullIfNotNull(string parameterName) + { + if (_emitNotNullIfNotNull) + { + _writer.WriteLine($"[return: global::System.Diagnostics.CodeAnalysis.NotNullIfNotNull(nameof({parameterName}))]"); + } + } + private void EmitBindMethods_ConfigurationBinder() { if (!ShouldEmitMethods(MethodsToGen.ConfigBinder_Bind)) diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Parser/KnownTypeSymbols.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Parser/KnownTypeSymbols.cs index 89ff70db196b04..2f084ec7bdfce9 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Parser/KnownTypeSymbols.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Parser/KnownTypeSymbols.cs @@ -64,6 +64,7 @@ internal sealed class KnownTypeSymbols public INamedTypeSymbol? MemberInfo { get; } public INamedTypeSymbol? ParameterInfo { get; } public INamedTypeSymbol? Delegate { get; } + public INamedTypeSymbol? NotNullIfNotNullAttribute { get; } public KnownTypeSymbols(CSharpCompilation compilation) { @@ -132,6 +133,9 @@ public KnownTypeSymbols(CSharpCompilation compilation) IntPtr = Compilation.GetSpecialType(SpecialType.System_IntPtr); UIntPtr = Compilation.GetSpecialType(SpecialType.System_UIntPtr); Delegate = Compilation.GetSpecialType(SpecialType.System_Delegate); + + // Only generate nullable attributes if available + NotNullIfNotNullAttribute = compilation.GetBestTypeByMetadataName("System.Diagnostics.CodeAnalysis.NotNullIfNotNullAttribute"); } } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Specs/SourceGenerationSpec.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Specs/SourceGenerationSpec.cs index c4fc5a6079ad99..e435ffa0cd0b23 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Specs/SourceGenerationSpec.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Specs/SourceGenerationSpec.cs @@ -12,6 +12,7 @@ public sealed record SourceGenerationSpec public required ImmutableEquatableArray ConfigTypes { get; init; } public required bool EmitEnumParseMethod { get; set; } public required bool EmitGenericParseEnum { get; set; } + public required bool EmitNotNullIfNotNull { get; set; } public required bool EmitThrowIfNullMethod { get; set; } } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/ref/Microsoft.Extensions.Configuration.Binder.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/ref/Microsoft.Extensions.Configuration.Binder.cs index 0f28d4f2fb9af8..c0ee592ed6b879 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/ref/Microsoft.Extensions.Configuration.Binder.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/ref/Microsoft.Extensions.Configuration.Binder.cs @@ -32,10 +32,12 @@ public static void Bind(this Microsoft.Extensions.Configuration.IConfiguration c [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("In case the type is non-primitive, the trimmer cannot statically analyze the object's type so its members may be trimmed.")] public static object? GetValue(this Microsoft.Extensions.Configuration.IConfiguration configuration, [System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembersAttribute(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.All)] System.Type type, string key) { throw null; } [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("In case the type is non-primitive, the trimmer cannot statically analyze the object's type so its members may be trimmed.")] + [return: System.Diagnostics.CodeAnalysis.NotNullIfNotNull(nameof(defaultValue))] public static object? GetValue(this Microsoft.Extensions.Configuration.IConfiguration configuration, [System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembersAttribute(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.All)] System.Type type, string key, object? defaultValue) { throw null; } [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("In case the type is non-primitive, the trimmer cannot statically analyze the object's type so its members may be trimmed.")] public static T? GetValue<[System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembersAttribute(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.All)] T>(this Microsoft.Extensions.Configuration.IConfiguration configuration, string key) { throw null; } [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("In case the type is non-primitive, the trimmer cannot statically analyze the object's type so its members may be trimmed.")] + [return: System.Diagnostics.CodeAnalysis.NotNullIfNotNull(nameof(defaultValue))] public static T? GetValue<[System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembersAttribute(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.All)] T>(this Microsoft.Extensions.Configuration.IConfiguration configuration, string key, T defaultValue) { throw null; } [System.Diagnostics.CodeAnalysis.RequiresDynamicCodeAttribute("Binding strongly typed objects to configuration values requires generating dynamic code at runtime, for example instantiating generic types.")] [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("In case the type is non-primitive, the trimmer cannot statically analyze the object's type so its members may be trimmed.")] diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/src/ConfigurationBinder.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/src/ConfigurationBinder.cs index c6783555ca4757..658653c28c0fe1 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/src/ConfigurationBinder.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/src/ConfigurationBinder.cs @@ -167,6 +167,7 @@ public static void Bind(this IConfiguration configuration, object? instance, Act /// The default value to use if no value is found. /// The converted value. [RequiresUnreferencedCode(TrimmingWarningMessage)] + [return: NotNullIfNotNull(nameof(defaultValue))] public static T? GetValue<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] T>(this IConfiguration configuration, string key, T defaultValue) { return (T?)GetValue(configuration, typeof(T), key, defaultValue); @@ -198,6 +199,7 @@ public static void Bind(this IConfiguration configuration, object? instance, Act /// The default value to use if no value is found. /// The converted value. [RequiresUnreferencedCode(TrimmingWarningMessage)] + [return: NotNullIfNotNull(nameof(defaultValue))] public static object? GetValue( this IConfiguration configuration, [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/Common/ConfigurationBinderTests.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/Common/ConfigurationBinderTests.cs index 95585b76239237..22691e75714263 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/Common/ConfigurationBinderTests.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/Common/ConfigurationBinderTests.cs @@ -326,11 +326,15 @@ public void CanBindToObjectProperty() [Fact] public void GetNullValue() { - var dic = new Dictionary + #nullable enable + #pragma warning disable IDE0004 // Cast is redundant + + var dic = new Dictionary { {"Integer", null}, {"Boolean", null}, {"Nested:Integer", null}, + {"String", null}, {"Object", null } }; var configurationBuilder = new ConfigurationBuilder(); @@ -341,13 +345,16 @@ public void GetNullValue() Assert.False(config.GetValue("Boolean")); Assert.Equal(0, config.GetValue("Integer")); Assert.Equal(0, config.GetValue("Nested:Integer")); + Assert.Null(config.GetValue("String")); Assert.Null(config.GetValue("Object")); // Generic overloads with default value. - Assert.True(config.GetValue("Boolean", true)); - Assert.Equal(1, config.GetValue("Integer", 1)); - Assert.Equal(1, config.GetValue("Nested:Integer", 1)); - Assert.Equal(new NestedConfig(""), config.GetValue("Object", new NestedConfig(""))); + Assert.True((bool)config.GetValue("Boolean", true)); + Assert.Equal(1, (int)config.GetValue("Integer", 1)); + Assert.Equal(1, (int)config.GetValue("Nested:Integer", 1)); + // [NotNullIfNotNull] avoids CS8600: Converting possible null value to non-nullable type. + Assert.Equal("s", (string)config.GetValue("String", "s")); + Assert.Equal(new NestedConfig(""), (NestedConfig)config.GetValue("Object", new NestedConfig(""))); // Type overloads. Assert.Null(config.GetValue(typeof(bool), "Boolean")); @@ -356,16 +363,22 @@ public void GetNullValue() Assert.Null(config.GetValue(typeof(ComplexOptions), "Object")); // Type overloads with default value. + // [NotNullIfNotNull] avoids CS8605: Unboxing a possibly null value. Assert.True((bool)config.GetValue(typeof(bool), "Boolean", true)); Assert.Equal(1, (int)config.GetValue(typeof(int), "Integer", 1)); Assert.Equal(1, (int)config.GetValue(typeof(int), "Nested:Integer", 1)); - Assert.Equal(new NestedConfig(""), config.GetValue("Object", new NestedConfig(""))); + // [NotNullIfNotNull] avoids CS8600: Converting possible null value to non-nullable type. + Assert.Equal("s", (string)config.GetValue(typeof(string), "String", "s")); + Assert.Equal(new NestedConfig(""), (NestedConfig)config.GetValue("Object", new NestedConfig(""))); // GetSection tests. Assert.False(config.GetSection("Boolean").Get()); Assert.Equal(0, config.GetSection("Integer").Get()); Assert.Equal(0, config.GetSection("Nested:Integer").Get()); Assert.Null(config.GetSection("Object").Get()); + + #pragma warning restore IDE0004 + #nullable restore } [Fact] diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/ConfigurationBinder/GetValue.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/ConfigurationBinder/GetValue.generated.txt index 67df05b508e896..72edaaf8c6fba6 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/ConfigurationBinder/GetValue.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/ConfigurationBinder/GetValue.generated.txt @@ -39,6 +39,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration /// Extracts the value with the specified key and converts it to the specified type. [InterceptsLocation(@"src-0.cs", 16, 24)] + [return: global::System.Diagnostics.CodeAnalysis.NotNullIfNotNull(nameof(defaultValue))] public static T? GetValue(this IConfiguration configuration, string key, T defaultValue) => (T?)(BindingExtensions.GetValueCore(configuration, typeof(T), key) ?? defaultValue); /// Extracts the value with the specified key and converts it to the specified type. @@ -47,6 +48,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration /// Extracts the value with the specified key and converts it to the specified type. [InterceptsLocation(@"src-0.cs", 17, 24)] + [return: global::System.Diagnostics.CodeAnalysis.NotNullIfNotNull(nameof(defaultValue))] public static object? GetValue(this IConfiguration configuration, Type type, string key, object? defaultValue) => BindingExtensions.GetValueCore(configuration, type, key) ?? defaultValue; #endregion IConfiguration extensions. diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/ConfigurationBinder/GetValue_T_Key_DefaultValue.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/ConfigurationBinder/GetValue_T_Key_DefaultValue.generated.txt index b546b86ea1b9b6..c383398924de61 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/ConfigurationBinder/GetValue_T_Key_DefaultValue.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/ConfigurationBinder/GetValue_T_Key_DefaultValue.generated.txt @@ -35,6 +35,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration #region IConfiguration extensions. /// Extracts the value with the specified key and converts it to the specified type. [InterceptsLocation(@"src-0.cs", 12, 20)] + [return: global::System.Diagnostics.CodeAnalysis.NotNullIfNotNull(nameof(defaultValue))] public static T? GetValue(this IConfiguration configuration, string key, T defaultValue) => (T?)(BindingExtensions.GetValueCore(configuration, typeof(T), key) ?? defaultValue); #endregion IConfiguration extensions. diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/ConfigurationBinder/GetValue_TypeOf_Key_DefaultValue.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/ConfigurationBinder/GetValue_TypeOf_Key_DefaultValue.generated.txt index 772160a53bdd55..8371cd0b05ca1f 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/ConfigurationBinder/GetValue_TypeOf_Key_DefaultValue.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/ConfigurationBinder/GetValue_TypeOf_Key_DefaultValue.generated.txt @@ -35,6 +35,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration #region IConfiguration extensions. /// Extracts the value with the specified key and converts it to the specified type. [InterceptsLocation(@"src-0.cs", 11, 20)] + [return: global::System.Diagnostics.CodeAnalysis.NotNullIfNotNull(nameof(defaultValue))] public static object? GetValue(this IConfiguration configuration, Type type, string key, object? defaultValue) => BindingExtensions.GetValueCore(configuration, type, key) ?? defaultValue; #endregion IConfiguration extensions. diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Microsoft.Extensions.Configuration.Binder.SourceGeneration.Tests.csproj b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Microsoft.Extensions.Configuration.Binder.SourceGeneration.Tests.csproj index eccbe7d759b411..c19f91354cba5a 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Microsoft.Extensions.Configuration.Binder.SourceGeneration.Tests.csproj +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Microsoft.Extensions.Configuration.Binder.SourceGeneration.Tests.csproj @@ -8,6 +8,9 @@ $(NoWarn);SYSLIB1103,SYSLIB1104 $(InterceptorsPreviewNamespaces);Microsoft.Extensions.Configuration.Binder.SourceGeneration true + + + true From 62e7396d7db73609ed5a2baf65e38668b981aff4 Mon Sep 17 00:00:00 2001 From: Jackson Schuster <36744439+jtschuster@users.noreply.github.com> Date: Mon, 29 Apr 2024 09:48:46 -0700 Subject: [PATCH 132/161] ILLink: give info message on duplicate members only when within a single descriptors file (#101574) In the trimmer we rely on the order of marking to determine if a descriptors file has a duplicate member. As we transition to the dependency analysis framework, the marking order changes, and this exposed scenarios where a descriptors file is found after some items have already been marked. This caused unnecessary IL2025 warnings (Duplicate preserve in descriptor file) to be reported. Instead of using the global marking state, we will keep a per-descriptor-file set of which members are preserved and only report duplicates within that set. --- .../linker/Linker.Steps/DescriptorMarker.cs | 27 +++++++++++++------ .../src/linker/Linker/MessageContainer.cs | 5 ++++ .../LinkXml/LinkXmlErrorCases.cs | 14 +++++++--- 3 files changed, 34 insertions(+), 12 deletions(-) diff --git a/src/tools/illink/src/linker/Linker.Steps/DescriptorMarker.cs b/src/tools/illink/src/linker/Linker.Steps/DescriptorMarker.cs index a527ca2e0df60b..f07200ab47e4b8 100644 --- a/src/tools/illink/src/linker/Linker.Steps/DescriptorMarker.cs +++ b/src/tools/illink/src/linker/Linker.Steps/DescriptorMarker.cs @@ -2,6 +2,7 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. using System; +using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Text; @@ -23,14 +24,24 @@ public class DescriptorMarker : ProcessLinkerXmlBase static readonly string[] _accessorsAll = new string[] { "all" }; static readonly char[] _accessorsSep = new char[] { ';' }; + protected readonly HashSet _preservedMembers; + public DescriptorMarker (LinkContext context, Stream documentStream, string xmlDocumentLocation) : base (context, documentStream, xmlDocumentLocation) { + _preservedMembers = new (); } public DescriptorMarker (LinkContext context, Stream documentStream, EmbeddedResource resource, AssemblyDefinition resourceAssembly, string xmlDocumentLocation = "") : base (context, documentStream, resource, resourceAssembly, xmlDocumentLocation) { + _preservedMembers = new (); + } + + protected void LogDuplicatePreserve(string memberName, XPathNavigator duplicatePosition) + { + var origin = GetMessageOriginForPosition (duplicatePosition); + _context.LogMessage (MessageContainer.CreateInfoMessage (origin, $"Duplicate preserve of '{memberName}'")); } public void Mark () @@ -147,16 +158,16 @@ protected static TypePreserve GetTypePreserve (XPathNavigator nav) protected override void ProcessField (TypeDefinition type, FieldDefinition field, XPathNavigator nav) { - if (_context.Annotations.IsMarked (field)) - LogWarning (nav, DiagnosticId.XmlDuplicatePreserveMember, field.FullName); + if (!_preservedMembers.Add (field)) + LogDuplicatePreserve (field.FullName, nav); _context.Annotations.Mark (field, new DependencyInfo (DependencyKind.XmlDescriptor, _xmlDocumentLocation), GetMessageOriginForPosition (nav)); } protected override void ProcessMethod (TypeDefinition type, MethodDefinition method, XPathNavigator nav, object? customData) { - if (_context.Annotations.IsMarked (method)) - LogWarning (nav, DiagnosticId.XmlDuplicatePreserveMember, method.GetDisplayName ()); + if (!_preservedMembers.Add (method)) + LogDuplicatePreserve (method.GetDisplayName (), nav); _context.Annotations.MarkIndirectlyCalledMethod (method); _context.Annotations.SetAction (method, MethodAction.Parse); @@ -212,8 +223,8 @@ public static string GetMethodSignature (MethodDefinition meth, bool includeGene protected override void ProcessEvent (TypeDefinition type, EventDefinition @event, XPathNavigator nav, object? customData) { - if (_context.Annotations.IsMarked (@event)) - LogWarning (nav, DiagnosticId.XmlDuplicatePreserveMember, @event.FullName); + if (!_preservedMembers.Add (@event)) + LogDuplicatePreserve(@event.FullName, nav); ProcessMethod (type, @event.AddMethod, nav, customData); ProcessMethod (type, @event.RemoveMethod, nav, customData); @@ -224,8 +235,8 @@ protected override void ProcessProperty (TypeDefinition type, PropertyDefinition { string[] accessors = fromSignature ? GetAccessors (nav) : _accessorsAll; - if (_context.Annotations.IsMarked (property)) - LogWarning (nav, DiagnosticId.XmlDuplicatePreserveMember, property.FullName); + if (!_preservedMembers.Add (property)) + LogDuplicatePreserve(property.FullName, nav); if (Array.IndexOf (accessors, "all") >= 0) { ProcessMethodIfNotNull (type, property.GetMethod, nav, customData); diff --git a/src/tools/illink/src/linker/Linker/MessageContainer.cs b/src/tools/illink/src/linker/Linker/MessageContainer.cs index eb1fe94a53cfdf..0de844bd6e8002 100644 --- a/src/tools/illink/src/linker/Linker/MessageContainer.cs +++ b/src/tools/illink/src/linker/Linker/MessageContainer.cs @@ -253,6 +253,11 @@ public static MessageContainer CreateInfoMessage (string text) return new MessageContainer (MessageCategory.Info, text, null); } + internal static MessageContainer CreateInfoMessage (MessageOrigin origin, string text) + { + return new MessageContainer (MessageCategory.Info, text, null, "", origin); + } + /// /// Create a diagnostics message. /// diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/LinkXml/LinkXmlErrorCases.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/LinkXml/LinkXmlErrorCases.cs index 467831cbb69fcd..e9021db105d4e8 100644 --- a/src/tools/illink/test/Mono.Linker.Tests.Cases/LinkXml/LinkXmlErrorCases.cs +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/LinkXml/LinkXmlErrorCases.cs @@ -6,6 +6,7 @@ namespace Mono.Linker.Tests.Cases.LinkXml { [SetupLinkerDescriptorFile ("LinkXmlErrorCases.xml")] [SetupLinkerArgument ("--skip-unresolved", "true")] + [SetupLinkerArgument ("--verbose")] [ExpectedWarning ("IL2001", "TypeWithNoFields", FileName = "LinkXmlErrorCases.xml", SourceLine = 3, SourceColumn = 6)] [ExpectedWarning ("IL2002", "TypeWithNoMethods", FileName = "LinkXmlErrorCases.xml", SourceLine = 4, SourceColumn = 6)] @@ -17,10 +18,15 @@ namespace Mono.Linker.Tests.Cases.LinkXml [ExpectedWarning ("IL2017", "NonExistentProperty", "TypeWithNoProperties", FileName = "LinkXmlErrorCases.xml", SourceLine = 21, SourceColumn = 8)] [ExpectedWarning ("IL2018", "SetOnlyProperty", "TypeWithProperties", FileName = "LinkXmlErrorCases.xml", SourceLine = 25, SourceColumn = 8)] [ExpectedWarning ("IL2019", "GetOnlyProperty", "TypeWithProperties", FileName = "LinkXmlErrorCases.xml", SourceLine = 26, SourceColumn = 8)] - [ExpectedWarning ("IL2025", "Method", Tool.Trimmer, "", FileName = "LinkXmlErrorCases.xml", SourceLine = 39, SourceColumn = 8)] - [ExpectedWarning ("IL2025", "Event", Tool.Trimmer, "", FileName = "LinkXmlErrorCases.xml", SourceLine = 40, SourceColumn = 8)] - [ExpectedWarning ("IL2025", "Field", Tool.Trimmer, "", FileName = "LinkXmlErrorCases.xml", SourceLine = 41, SourceColumn = 8)] - [ExpectedWarning ("IL2025", "Property", Tool.Trimmer, "", FileName = "LinkXmlErrorCases.xml", SourceLine = 42, SourceColumn = 8)] + [LogContains ("Duplicate preserve of 'System.Int32 Mono.Linker.Tests.Cases.LinkXml.LinkXmlErrorCases/TypeWithEverything::Field'", ProducedBy = Tool.Trimmer)] + [LogContains ("Duplicate preserve of 'Mono.Linker.Tests.Cases.LinkXml.LinkXmlErrorCases.TypeWithEverything.TypeWithEverything()'", ProducedBy = Tool.Trimmer)] + [LogContains ("Duplicate preserve of 'Mono.Linker.Tests.Cases.LinkXml.LinkXmlErrorCases.TypeWithEverything.Method()'", ProducedBy = Tool.Trimmer)] + [LogContains ("Duplicate preserve of 'System.EventHandler Mono.Linker.Tests.Cases.LinkXml.LinkXmlErrorCases/TypeWithEverything::Event'", ProducedBy = Tool.Trimmer)] + [LogContains ("Duplicate preserve of 'Mono.Linker.Tests.Cases.LinkXml.LinkXmlErrorCases.TypeWithEverything.Event.add'", ProducedBy = Tool.Trimmer)] + [LogContains ("Duplicate preserve of 'Mono.Linker.Tests.Cases.LinkXml.LinkXmlErrorCases.TypeWithEverything.Event.remove'", ProducedBy = Tool.Trimmer)] + [LogContains ("Duplicate preserve of 'System.Int32 Mono.Linker.Tests.Cases.LinkXml.LinkXmlErrorCases/TypeWithEverything::Property()'", ProducedBy = Tool.Trimmer)] + [LogContains ("Duplicate preserve of 'Mono.Linker.Tests.Cases.LinkXml.LinkXmlErrorCases.TypeWithEverything.Property.get'", ProducedBy = Tool.Trimmer)] + [LogContains ("Duplicate preserve of 'Mono.Linker.Tests.Cases.LinkXml.LinkXmlErrorCases.TypeWithEverything.Property.set'", ProducedBy = Tool.Trimmer)] // NativeAOT doesn't support wildcard * and will skip usages of it, including if they would warn // https://github.com/dotnet/runtime/issues/80466 [ExpectedWarning ("IL2100", Tool.Trimmer, "", FileName = "LinkXmlErrorCases.xml", SourceLine = 50, SourceColumn = 4)] From 2d4dae9ce9e3a172fcc84e0e01a5756cb0b44bbc Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Mon, 29 Apr 2024 12:07:44 -0500 Subject: [PATCH 133/161] [main] Update dependencies from dotnet/runtime, dotnet/sdk (#101682) * Update dependencies from https://github.com/dotnet/runtime build 20240429.1 Microsoft.DotNet.ILCompiler , Microsoft.NET.Sdk.IL , Microsoft.NETCore.App.Runtime.win-x64 , Microsoft.NETCore.ILAsm , runtime.native.System.IO.Ports , System.Reflection.Metadata , System.Reflection.MetadataLoadContext , System.Text.Json , Microsoft.SourceBuild.Intermediate.runtime.linux-x64 From Version 9.0.0-preview.4.24227.6 -> To Version 9.0.0-preview.4.24229.1 * Update dependencies from https://github.com/dotnet/sdk build 20240427.1 Microsoft.SourceBuild.Intermediate.sdk , Microsoft.DotNet.ApiCompat.Task From Version 9.0.100-preview.4.24221.4 -> To Version 9.0.100-preview.5.24227.1 --------- Co-authored-by: dotnet-maestro[bot] --- eng/Version.Details.xml | 44 ++++++++++++++++++++--------------------- eng/Versions.props | 16 +++++++-------- global.json | 2 +- 3 files changed, 31 insertions(+), 31 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 7626973e31e9dc..021a0b220d86d3 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -282,43 +282,43 @@ https://github.com/dotnet/llvm-project 26f8c30340764cfa7fa9090dc01a36c222bf09c1 - + https://github.com/dotnet/runtime - b8fe1d0ccb60926d6e7ef5d42e2398c178c9ee5c + 7745b5ec3db34cd358b26710c0ec32db8b0b23f7 - + https://github.com/dotnet/runtime - b8fe1d0ccb60926d6e7ef5d42e2398c178c9ee5c + 7745b5ec3db34cd358b26710c0ec32db8b0b23f7 - + https://github.com/dotnet/runtime - b8fe1d0ccb60926d6e7ef5d42e2398c178c9ee5c + 7745b5ec3db34cd358b26710c0ec32db8b0b23f7 - + https://github.com/dotnet/runtime - b8fe1d0ccb60926d6e7ef5d42e2398c178c9ee5c + 7745b5ec3db34cd358b26710c0ec32db8b0b23f7 - + https://github.com/dotnet/runtime - b8fe1d0ccb60926d6e7ef5d42e2398c178c9ee5c + 7745b5ec3db34cd358b26710c0ec32db8b0b23f7 - + https://github.com/dotnet/runtime - b8fe1d0ccb60926d6e7ef5d42e2398c178c9ee5c + 7745b5ec3db34cd358b26710c0ec32db8b0b23f7 - + https://github.com/dotnet/runtime - b8fe1d0ccb60926d6e7ef5d42e2398c178c9ee5c + 7745b5ec3db34cd358b26710c0ec32db8b0b23f7 - + https://github.com/dotnet/runtime - b8fe1d0ccb60926d6e7ef5d42e2398c178c9ee5c + 7745b5ec3db34cd358b26710c0ec32db8b0b23f7 - + https://github.com/dotnet/runtime - b8fe1d0ccb60926d6e7ef5d42e2398c178c9ee5c + 7745b5ec3db34cd358b26710c0ec32db8b0b23f7 https://github.com/dotnet/xharness @@ -386,14 +386,14 @@ 7a96b1530744f6637ad6bb6bf5b8dfa33ea15b81 - + https://github.com/dotnet/sdk - 1529907f03b73e097a6e4f33fd3c5aea2246f021 + 0f7644da23265f1be382b28ff56f5505b0329334 - + https://github.com/dotnet/sdk - 1529907f03b73e097a6e4f33fd3c5aea2246f021 + 0f7644da23265f1be382b28ff56f5505b0329334 diff --git a/eng/Versions.props b/eng/Versions.props index 168e86e4e81b2e..d9720d96516e56 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -81,7 +81,7 @@ 0.2.0 - 9.0.100-preview.4.24221.4 + 9.0.100-preview.5.24227.1 9.0.0-beta.24226.3 9.0.0-beta.24226.3 @@ -104,10 +104,10 @@ 6.0.0-preview.1.102 - 9.0.0-preview.4.24227.6 + 9.0.0-preview.4.24229.1 6.0.0 - 9.0.0-preview.4.24227.6 + 9.0.0-preview.4.24229.1 6.0.0 1.1.1 @@ -119,19 +119,19 @@ 8.0.0 5.0.0 4.5.5 - 9.0.0-preview.4.24227.6 - 9.0.0-preview.4.24227.6 + 9.0.0-preview.4.24229.1 + 9.0.0-preview.4.24229.1 6.0.0 5.0.0 5.0.0 5.0.0 7.0.0 - 9.0.0-preview.4.24227.6 + 9.0.0-preview.4.24229.1 6.0.0 7.0.0 4.5.4 4.5.0 - 9.0.0-preview.4.24227.6 + 9.0.0-preview.4.24229.1 8.0.0 8.0.0 @@ -210,7 +210,7 @@ 0.11.4-alpha.24222.1 - 9.0.0-preview.4.24227.6 + 9.0.0-preview.4.24229.1 9.0.0-preview.5.24223.2 diff --git a/global.json b/global.json index 2ea13b55221eef..8cafaf799ea2c5 100644 --- a/global.json +++ b/global.json @@ -13,6 +13,6 @@ "Microsoft.DotNet.SharedFramework.Sdk": "9.0.0-beta.24226.3", "Microsoft.Build.NoTargets": "3.7.0", "Microsoft.Build.Traversal": "3.4.0", - "Microsoft.NET.Sdk.IL": "9.0.0-preview.4.24219.3" + "Microsoft.NET.Sdk.IL": "9.0.0-preview.4.24229.1" } } From 2f1c518d8bb905f2f4d71c72edc6115255a679a1 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Mon, 29 Apr 2024 12:15:32 -0500 Subject: [PATCH 134/161] Update dependencies from https://github.com/dotnet/roslyn build 20240428.2 (#101679) Microsoft.SourceBuild.Intermediate.roslyn , Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.11.0-1.24228.1 -> To Version 4.11.0-1.24228.2 Co-authored-by: dotnet-maestro[bot] --- eng/Version.Details.xml | 16 ++++++++-------- eng/Versions.props | 6 +++--- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 021a0b220d86d3..76279d16eb0303 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -360,17 +360,17 @@ https://github.com/dotnet/runtime-assets 6e78861f1f307cd9f0e64a45b1d7884fa4470930 - + https://github.com/dotnet/roslyn - 7a96b1530744f6637ad6bb6bf5b8dfa33ea15b81 + 75995e26b4c6f9a30ace7bcb65c0b4e42c0b397c - + https://github.com/dotnet/roslyn - 7a96b1530744f6637ad6bb6bf5b8dfa33ea15b81 + 75995e26b4c6f9a30ace7bcb65c0b4e42c0b397c - + https://github.com/dotnet/roslyn - 7a96b1530744f6637ad6bb6bf5b8dfa33ea15b81 + 75995e26b4c6f9a30ace7bcb65c0b4e42c0b397c https://github.com/dotnet/roslyn-analyzers @@ -381,9 +381,9 @@ 8dccccec1ce3bd2fb532ec77d7e092ab9d684db7 - + https://github.com/dotnet/roslyn - 7a96b1530744f6637ad6bb6bf5b8dfa33ea15b81 + 75995e26b4c6f9a30ace7bcb65c0b4e42c0b397c diff --git a/eng/Versions.props b/eng/Versions.props index d9720d96516e56..b7f74da3d8e4a2 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -42,9 +42,9 @@ Any tools that contribute to the design-time experience should use the MicrosoftCodeAnalysisVersion_LatestVS property above to ensure they do not break the local dev experience. --> - 4.11.0-1.24228.1 - 4.11.0-1.24228.1 - 4.11.0-1.24228.1 + 4.11.0-1.24228.2 + 4.11.0-1.24228.2 + 4.11.0-1.24228.2 diff --git a/eng/Versions.props b/eng/Versions.props index b7f74da3d8e4a2..241d20a5801b05 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -153,12 +153,12 @@ 9.0.0-beta.24222.1 9.0.0-beta.24222.1 - 1.0.0-prerelease.24219.3 - 1.0.0-prerelease.24219.3 - 1.0.0-prerelease.24219.3 - 1.0.0-prerelease.24219.3 - 1.0.0-prerelease.24219.3 - 1.0.0-prerelease.24219.3 + 1.0.0-prerelease.24223.3 + 1.0.0-prerelease.24223.3 + 1.0.0-prerelease.24223.3 + 1.0.0-prerelease.24223.3 + 1.0.0-prerelease.24223.3 + 1.0.0-prerelease.24223.3 2.0.0 17.8.0-beta1.23475.2 From b88785f22d6a6d0618ebb63490b4a87e3b61c9f6 Mon Sep 17 00:00:00 2001 From: Kevin Jones Date: Mon, 29 Apr 2024 13:43:21 -0400 Subject: [PATCH 136/161] Ignore line endings when comparing AsnXml generated content --- .../Security/Cryptography/Asn1/AsnXml.targets | 39 +++++++++++++------ 1 file changed, 28 insertions(+), 11 deletions(-) diff --git a/src/libraries/Common/src/System/Security/Cryptography/Asn1/AsnXml.targets b/src/libraries/Common/src/System/Security/Cryptography/Asn1/AsnXml.targets index 940c73ca57237c..eb285cc2cfc279 100644 --- a/src/libraries/Common/src/System/Security/Cryptography/Asn1/AsnXml.targets +++ b/src/libraries/Common/src/System/Security/Cryptography/Asn1/AsnXml.targets @@ -1,9 +1,6 @@ - <_AsnXmlDiffCmd>%24%28command -v diff%29 -q -a - <_AsnXmlDiffCmd Condition="$([MSBuild]::IsOsPlatform('windows')) == 'true'">$(SystemRoot)\System32\fc.exe /a - <_AsnXmlDiffCmd Condition="$([MSBuild]::IsOsPlatform('osx')) == 'true'">diff @@ -11,6 +8,27 @@ + + + + + + + + + + + + + + + - - - + + + - + From 73a428dd05b92ac727e5831340bb13e18afa39ba Mon Sep 17 00:00:00 2001 From: Stephen Toub Date: Mon, 29 Apr 2024 13:55:03 -0400 Subject: [PATCH 137/161] Fix handling of case-sensitive set loops in RegexPrefixAnalyzer.FindPrefixes (#101608) * Fix handling of case-sensitive set loops in RegexPrefixAnalyzer.FindPrefixes For an expression like `[Aa]{2}`, we were generating the strings "AA" and "aa" but not "Aa" or "aA". This code isn't exercised yet, as we're currently only using FindPrefixes for case-insensitive, but I'm trying to enable it for case-sensitive as well, and hit this. I'm not adding new tests here as plenty of existing tests catch it once it's enabled. * Also exit early as soon as we can detect too many possible prefixes --- .../RegularExpressions/RegexPrefixAnalyzer.cs | 43 +++++++++++++------ .../FunctionalTests/Regex.Match.Tests.cs | 11 ++--- 2 files changed, 35 insertions(+), 19 deletions(-) diff --git a/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexPrefixAnalyzer.cs b/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexPrefixAnalyzer.cs index b46af7b1b9d066..556a187203f035 100644 --- a/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexPrefixAnalyzer.cs +++ b/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexPrefixAnalyzer.cs @@ -59,9 +59,11 @@ static bool FindPrefixesCore(RegexNode node, List results, bool i // If we're too deep to analyze further, we can't trust what we've already computed, so stop iterating. // Also bail if any of our results is already hitting the threshold, or if this node is RTL, which is // not worth the complexity of handling. + // Or if we've already discovered more than the allowed number of prefixes. if (!StackHelper.TryEnsureSufficientExecutionStack() || !results.TrueForAll(sb => sb.Length < MaxPrefixLength) || - (node.Options & RegexOptions.RightToLeft) != 0) + (node.Options & RegexOptions.RightToLeft) != 0 || + results.Count > MaxPrefixes) { return false; } @@ -162,23 +164,30 @@ static bool FindPrefixesCore(RegexNode node, List results, bool i int reps = node.Kind is RegexNodeKind.Set ? 1 : Math.Min(node.M, MaxPrefixLength); if (!ignoreCase) { - int existingCount = results.Count; - - // Duplicate all of the existing strings for all of the new suffixes, other than the first. - foreach (char suffix in setChars.Slice(1, charCount - 1)) + for (int rep = 0; rep < reps; rep++) { - for (int existing = 0; existing < existingCount; existing++) + int existingCount = results.Count; + if (existingCount * charCount > MaxPrefixes) { - StringBuilder newSb = new StringBuilder().Append(results[existing]); - newSb.Append(suffix, reps); - results.Add(newSb); + return false; } - } - // Then append the first suffix to all of the existing strings. - for (int existing = 0; existing < existingCount; existing++) - { - results[existing].Append(setChars[0], reps); + // Duplicate all of the existing strings for all of the new suffixes, other than the first. + foreach (char suffix in setChars.Slice(1, charCount - 1)) + { + for (int existing = 0; existing < existingCount; existing++) + { + StringBuilder newSb = new StringBuilder().Append(results[existing]); + newSb.Append(suffix); + results.Add(newSb); + } + } + + // Then append the first suffix to all of the existing strings. + for (int existing = 0; existing < existingCount; existing++) + { + results[existing].Append(setChars[0]); + } } } else @@ -248,6 +257,12 @@ static bool FindPrefixesCore(RegexNode node, List results, bool i { _ = FindPrefixesCore(node.Child(i), alternateBranchResults, ignoreCase); + // If we now have too many results, bail. + if ((allBranchResults?.Count ?? 0) + alternateBranchResults.Count > MaxPrefixes) + { + return false; + } + Debug.Assert(alternateBranchResults.Count > 0); foreach (StringBuilder sb in alternateBranchResults) { diff --git a/src/libraries/System.Text.RegularExpressions/tests/FunctionalTests/Regex.Match.Tests.cs b/src/libraries/System.Text.RegularExpressions/tests/FunctionalTests/Regex.Match.Tests.cs index d58290174c222f..9d3679be60b938 100644 --- a/src/libraries/System.Text.RegularExpressions/tests/FunctionalTests/Regex.Match.Tests.cs +++ b/src/libraries/System.Text.RegularExpressions/tests/FunctionalTests/Regex.Match.Tests.cs @@ -1172,6 +1172,7 @@ public async Task Match_VaryingLengthStrings_Huge(RegexEngine engine) public static IEnumerable Match_DeepNesting_MemberData() { + foreach (RegexOptions options in new[] { RegexOptions.None, RegexOptions.IgnoreCase }) foreach (RegexEngine engine in RegexHelpers.AvailableEngines) { if (RegexHelpers.IsNonBacktracking(engine)) @@ -1180,15 +1181,15 @@ public static IEnumerable Match_DeepNesting_MemberData() continue; } - yield return new object[] { engine, 1 }; - yield return new object[] { engine, 10 }; - yield return new object[] { engine, 100 }; + yield return new object[] { engine, options, 1 }; + yield return new object[] { engine, options, 10 }; + yield return new object[] { engine, options, 100 }; } } [Theory] [MemberData(nameof(Match_DeepNesting_MemberData))] - public async Task Match_DeepNesting(RegexEngine engine, int count) + public async Task Match_DeepNesting(RegexEngine engine, RegexOptions options, int count) { const string Start = @"((?>abc|(?:def[ghi]", End = @")))"; const string Match = "defg"; @@ -1196,7 +1197,7 @@ public async Task Match_DeepNesting(RegexEngine engine, int count) string pattern = string.Concat(Enumerable.Repeat(Start, count)) + string.Concat(Enumerable.Repeat(End, count)); string input = string.Concat(Enumerable.Repeat(Match, count)); - Regex r = await RegexHelpers.GetRegexAsync(engine, pattern); + Regex r = await RegexHelpers.GetRegexAsync(engine, pattern, options); Match m = r.Match(input); Assert.True(m.Success); From 703105241219a31ba4c74d43d3c51559cdfdcdf1 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Mon, 29 Apr 2024 11:11:10 -0700 Subject: [PATCH 138/161] Arm64/Sve: Implement divide/multiply/subtract Math APIs (#101578) * Add Divide/Multiply/Subtract * Add hwintrinsic support for Divide,Multiply and Subtract * remove space * Add test cases * trim space * handle the scenario for 2 operands predicated-only instruction * Remove *DIVR and *SUBR from comments * fix jit format * fix merge conflict --- src/coreclr/jit/hwintrinsiccodegenarm64.cpp | 27 +- src/coreclr/jit/hwintrinsiclistarm64sve.h | 3 + .../Arm/Sve.PlatformNotSupported.cs | 293 ++++++++++++++++++ .../src/System/Runtime/Intrinsics/Arm/Sve.cs | 292 +++++++++++++++++ .../ref/System.Runtime.Intrinsics.cs | 23 +- .../GenerateHWIntrinsicTests_Arm.cs | 27 ++ 6 files changed, 660 insertions(+), 5 deletions(-) diff --git a/src/coreclr/jit/hwintrinsiccodegenarm64.cpp b/src/coreclr/jit/hwintrinsiccodegenarm64.cpp index c38afb87a83340..aadd8fcf28e000 100644 --- a/src/coreclr/jit/hwintrinsiccodegenarm64.cpp +++ b/src/coreclr/jit/hwintrinsiccodegenarm64.cpp @@ -511,11 +511,30 @@ void CodeGen::genHWIntrinsic(GenTreeHWIntrinsic* node) if (falseReg != embMaskOp1Reg) { - // None of targetReg, embMaskOp1Reg and falseReg are same. In such case, use the - // "unpredicated" version of the instruction and then use "sel" to select the active lanes. + // At the point, targetReg != embMaskOp1Reg != falseReg + if (HWIntrinsicInfo::IsOptionalEmbeddedMaskedOperation(intrinEmbMask.id)) + { + // If the embedded instruction supports optional mask operation, use the "unpredicated" + // version of the instruction, followed by "sel" to select the active lanes. + GetEmitter()->emitIns_R_R_R(insEmbMask, emitSize, targetReg, embMaskOp1Reg, + embMaskOp2Reg, opt, INS_SCALABLE_OPTS_UNPREDICATED); + } + else + { + // If the instruction just has "predicated" version, then move the "embMaskOp1Reg" + // into targetReg. Next, do the predicated operation on the targetReg and last, + // use "sel" to select the active lanes based on mask, and set inactive lanes + // to falseReg. + + assert(targetReg != embMaskOp2Reg); + assert(HWIntrinsicInfo::IsEmbeddedMaskedOperation(intrinEmbMask.id)); + + GetEmitter()->emitIns_R_R(INS_sve_movprfx, EA_SCALABLE, targetReg, embMaskOp1Reg); + + GetEmitter()->emitIns_R_R_R(insEmbMask, emitSize, targetReg, maskReg, embMaskOp2Reg, + opt); + } - GetEmitter()->emitIns_R_R_R(insEmbMask, emitSize, targetReg, embMaskOp1Reg, embMaskOp2Reg, - opt, INS_SCALABLE_OPTS_UNPREDICATED); GetEmitter()->emitIns_R_R_R_R(INS_sve_sel, emitSize, targetReg, maskReg, targetReg, falseReg, opt, INS_SCALABLE_OPTS_UNPREDICATED); break; diff --git a/src/coreclr/jit/hwintrinsiclistarm64sve.h b/src/coreclr/jit/hwintrinsiclistarm64sve.h index ef9740e4556523..cbd5ea6eb4983e 100644 --- a/src/coreclr/jit/hwintrinsiclistarm64sve.h +++ b/src/coreclr/jit/hwintrinsiclistarm64sve.h @@ -42,6 +42,7 @@ HARDWARE_INTRINSIC(Sve, CreateWhileLessThanOrEqualMask16Bit, HARDWARE_INTRINSIC(Sve, CreateWhileLessThanOrEqualMask32Bit, -1, 2, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sve_whilele, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SIMD, HW_Flag_Scalable|HW_Flag_SpecialCodeGen|HW_Flag_ReturnsPerElementMask) HARDWARE_INTRINSIC(Sve, CreateWhileLessThanOrEqualMask64Bit, -1, 2, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sve_whilele, INS_invalid, INS_invalid}, HW_Category_SIMD, HW_Flag_Scalable|HW_Flag_SpecialCodeGen|HW_Flag_ReturnsPerElementMask) HARDWARE_INTRINSIC(Sve, CreateWhileLessThanOrEqualMask8Bit, -1, 2, false, {INS_invalid, INS_sve_whilele, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SIMD, HW_Flag_Scalable|HW_Flag_SpecialCodeGen|HW_Flag_ReturnsPerElementMask) +HARDWARE_INTRINSIC(Sve, Divide, -1, 2, true, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sve_sdiv, INS_sve_udiv, INS_sve_sdiv, INS_sve_udiv, INS_sve_fdiv, INS_sve_fdiv}, HW_Category_SIMD, HW_Flag_Scalable|HW_Flag_EmbeddedMaskedOperation|HW_Flag_HasRMWSemantics|HW_Flag_LowMaskedOperation) HARDWARE_INTRINSIC(Sve, LoadVector, -1, 2, true, {INS_sve_ld1b, INS_sve_ld1b, INS_sve_ld1h, INS_sve_ld1h, INS_sve_ld1w, INS_sve_ld1w, INS_sve_ld1d, INS_sve_ld1d, INS_sve_ld1w, INS_sve_ld1d}, HW_Category_MemoryLoad, HW_Flag_Scalable|HW_Flag_ExplicitMaskedOperation|HW_Flag_LowMaskedOperation) HARDWARE_INTRINSIC(Sve, LoadVectorByteZeroExtendToInt16, -1, 2, false, {INS_invalid, INS_invalid, INS_sve_ld1b, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_MemoryLoad, HW_Flag_Scalable|HW_Flag_ExplicitMaskedOperation|HW_Flag_LowMaskedOperation) HARDWARE_INTRINSIC(Sve, LoadVectorByteZeroExtendToInt32, -1, 2, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sve_ld1b, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_MemoryLoad, HW_Flag_Scalable|HW_Flag_ExplicitMaskedOperation|HW_Flag_LowMaskedOperation) @@ -67,6 +68,8 @@ HARDWARE_INTRINSIC(Sve, LoadVectorUInt16ZeroExtendToUInt32, HARDWARE_INTRINSIC(Sve, LoadVectorUInt16ZeroExtendToUInt64, -1, 2, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sve_ld1h, INS_invalid, INS_invalid}, HW_Category_MemoryLoad, HW_Flag_Scalable|HW_Flag_ExplicitMaskedOperation|HW_Flag_LowMaskedOperation) HARDWARE_INTRINSIC(Sve, LoadVectorUInt32ZeroExtendToInt64, -1, 2, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sve_ld1w, INS_invalid, INS_invalid, INS_invalid}, HW_Category_MemoryLoad, HW_Flag_Scalable|HW_Flag_ExplicitMaskedOperation|HW_Flag_LowMaskedOperation) HARDWARE_INTRINSIC(Sve, LoadVectorUInt32ZeroExtendToUInt64, -1, 2, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sve_ld1w, INS_invalid, INS_invalid}, HW_Category_MemoryLoad, HW_Flag_Scalable|HW_Flag_ExplicitMaskedOperation|HW_Flag_LowMaskedOperation) +HARDWARE_INTRINSIC(Sve, Multiply, -1, 2, true, {INS_sve_mul, INS_sve_mul, INS_sve_mul, INS_sve_mul, INS_sve_mul, INS_sve_mul, INS_sve_mul, INS_sve_mul, INS_sve_fmul, INS_sve_fmul}, HW_Category_SIMD, HW_Flag_Scalable|HW_Flag_EmbeddedMaskedOperation|HW_Flag_HasRMWSemantics) +HARDWARE_INTRINSIC(Sve, Subtract, -1, 2, true, {INS_sve_sub, INS_sve_sub, INS_sve_sub, INS_sve_sub, INS_sve_sub, INS_sve_sub, INS_sve_sub, INS_sve_sub, INS_sve_fsub, INS_sve_fsub}, HW_Category_SIMD, HW_Flag_Scalable|HW_Flag_EmbeddedMaskedOperation|HW_Flag_HasRMWSemantics) HARDWARE_INTRINSIC(Sve, UnzipEven, -1, 2, true, {INS_sve_uzp1, INS_sve_uzp1, INS_sve_uzp1, INS_sve_uzp1, INS_sve_uzp1, INS_sve_uzp1, INS_sve_uzp1, INS_sve_uzp1, INS_sve_uzp1, INS_sve_uzp1}, HW_Category_SIMD, HW_Flag_Scalable|HW_Flag_SpecialCodeGen) HARDWARE_INTRINSIC(Sve, UnzipOdd, -1, 2, true, {INS_sve_uzp2, INS_sve_uzp2, INS_sve_uzp2, INS_sve_uzp2, INS_sve_uzp2, INS_sve_uzp2, INS_sve_uzp2, INS_sve_uzp2, INS_sve_uzp2, INS_sve_uzp2}, HW_Category_SIMD, HW_Flag_Scalable|HW_Flag_SpecialCodeGen) diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Arm/Sve.PlatformNotSupported.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Arm/Sve.PlatformNotSupported.cs index 3b992e440ef6b5..84583b46874563 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Arm/Sve.PlatformNotSupported.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Arm/Sve.PlatformNotSupported.cs @@ -552,6 +552,32 @@ internal Arm64() { } public static unsafe Vector CreateWhileLessThanOrEqualMask8Bit(ulong left, ulong right) { throw new PlatformNotSupportedException(); } + /// Divide : Divide + + /// + /// svfloat32_t svdiv[_f32]_m(svbool_t pg, svfloat32_t op1, svfloat32_t op2) + /// FDIV Ztied1.S, Pg/M, Ztied1.S, Zop2.S + /// MOVPRFX Zresult, Zop1; FDIV Zresult.S, Pg/M, Zresult.S, Zop2.S + /// svfloat32_t svdiv[_f32]_x(svbool_t pg, svfloat32_t op1, svfloat32_t op2) + /// FDIV Ztied1.S, Pg/M, Ztied1.S, Zop2.S + /// MOVPRFX Zresult, Zop1; FDIV Zresult.S, Pg/M, Zresult.S, Zop2.S + /// svfloat32_t svdiv[_f32]_z(svbool_t pg, svfloat32_t op1, svfloat32_t op2) + /// MOVPRFX Zresult.S, Pg/Z, Zop1.S; FDIV Zresult.S, Pg/M, Zresult.S, Zop2.S + /// + public static unsafe Vector Divide(Vector left, Vector right) { throw new PlatformNotSupportedException(); } + + /// + /// svfloat64_t svdiv[_f64]_m(svbool_t pg, svfloat64_t op1, svfloat64_t op2) + /// FDIV Ztied1.D, Pg/M, Ztied1.D, Zop2.D + /// MOVPRFX Zresult, Zop1; FDIV Zresult.D, Pg/M, Zresult.D, Zop2.D + /// svfloat64_t svdiv[_f64]_x(svbool_t pg, svfloat64_t op1, svfloat64_t op2) + /// FDIV Ztied1.D, Pg/M, Ztied1.D, Zop2.D + /// MOVPRFX Zresult, Zop1; FDIV Zresult.D, Pg/M, Zresult.D, Zop2.D + /// svfloat64_t svdiv[_f64]_z(svbool_t pg, svfloat64_t op1, svfloat64_t op2) + /// MOVPRFX Zresult.D, Pg/Z, Zop1.D; FDIV Zresult.D, Pg/M, Zresult.D, Zop2.D + /// + public static unsafe Vector Divide(Vector left, Vector right) { throw new PlatformNotSupportedException(); } + /// LoadVector : Unextended load /// @@ -840,6 +866,273 @@ internal Arm64() { } /// public static unsafe Vector LoadVectorUInt32ZeroExtendToUInt64(Vector mask, uint* address) { throw new PlatformNotSupportedException(); } + /// Multiply : Multiply + + /// + /// svint8_t svmul[_s8]_m(svbool_t pg, svint8_t op1, svint8_t op2) + /// MUL Ztied1.B, Pg/M, Ztied1.B, Zop2.B + /// MOVPRFX Zresult, Zop1; MUL Zresult.B, Pg/M, Zresult.B, Zop2.B + /// svint8_t svmul[_s8]_x(svbool_t pg, svint8_t op1, svint8_t op2) + /// MUL Ztied1.B, Pg/M, Ztied1.B, Zop2.B + /// MUL Ztied2.B, Pg/M, Ztied2.B, Zop1.B + /// MOVPRFX Zresult, Zop1; MUL Zresult.B, Pg/M, Zresult.B, Zop2.B + /// svint8_t svmul[_s8]_z(svbool_t pg, svint8_t op1, svint8_t op2) + /// MOVPRFX Zresult.B, Pg/Z, Zop1.B; MUL Zresult.B, Pg/M, Zresult.B, Zop2.B + /// MOVPRFX Zresult.B, Pg/Z, Zop2.B; MUL Zresult.B, Pg/M, Zresult.B, Zop1.B + /// + public static unsafe Vector Multiply(Vector left, Vector right) { throw new PlatformNotSupportedException(); } + + /// + /// svint16_t svmul[_s16]_m(svbool_t pg, svint16_t op1, svint16_t op2) + /// MUL Ztied1.H, Pg/M, Ztied1.H, Zop2.H + /// MOVPRFX Zresult, Zop1; MUL Zresult.H, Pg/M, Zresult.H, Zop2.H + /// svint16_t svmul[_s16]_x(svbool_t pg, svint16_t op1, svint16_t op2) + /// MUL Ztied1.H, Pg/M, Ztied1.H, Zop2.H + /// MUL Ztied2.H, Pg/M, Ztied2.H, Zop1.H + /// MOVPRFX Zresult, Zop1; MUL Zresult.H, Pg/M, Zresult.H, Zop2.H + /// svint16_t svmul[_s16]_z(svbool_t pg, svint16_t op1, svint16_t op2) + /// MOVPRFX Zresult.H, Pg/Z, Zop1.H; MUL Zresult.H, Pg/M, Zresult.H, Zop2.H + /// MOVPRFX Zresult.H, Pg/Z, Zop2.H; MUL Zresult.H, Pg/M, Zresult.H, Zop1.H + /// + public static unsafe Vector Multiply(Vector left, Vector right) { throw new PlatformNotSupportedException(); } + + /// + /// svint32_t svmul[_s32]_m(svbool_t pg, svint32_t op1, svint32_t op2) + /// MUL Ztied1.S, Pg/M, Ztied1.S, Zop2.S + /// MOVPRFX Zresult, Zop1; MUL Zresult.S, Pg/M, Zresult.S, Zop2.S + /// svint32_t svmul[_s32]_x(svbool_t pg, svint32_t op1, svint32_t op2) + /// MUL Ztied1.S, Pg/M, Ztied1.S, Zop2.S + /// MUL Ztied2.S, Pg/M, Ztied2.S, Zop1.S + /// MOVPRFX Zresult, Zop1; MUL Zresult.S, Pg/M, Zresult.S, Zop2.S + /// svint32_t svmul[_s32]_z(svbool_t pg, svint32_t op1, svint32_t op2) + /// MOVPRFX Zresult.S, Pg/Z, Zop1.S; MUL Zresult.S, Pg/M, Zresult.S, Zop2.S + /// MOVPRFX Zresult.S, Pg/Z, Zop2.S; MUL Zresult.S, Pg/M, Zresult.S, Zop1.S + /// + public static unsafe Vector Multiply(Vector left, Vector right) { throw new PlatformNotSupportedException(); } + + /// + /// svint64_t svmul[_s64]_m(svbool_t pg, svint64_t op1, svint64_t op2) + /// MUL Ztied1.D, Pg/M, Ztied1.D, Zop2.D + /// MOVPRFX Zresult, Zop1; MUL Zresult.D, Pg/M, Zresult.D, Zop2.D + /// svint64_t svmul[_s64]_x(svbool_t pg, svint64_t op1, svint64_t op2) + /// MUL Ztied1.D, Pg/M, Ztied1.D, Zop2.D + /// MUL Ztied2.D, Pg/M, Ztied2.D, Zop1.D + /// MOVPRFX Zresult, Zop1; MUL Zresult.D, Pg/M, Zresult.D, Zop2.D + /// svint64_t svmul[_s64]_z(svbool_t pg, svint64_t op1, svint64_t op2) + /// MOVPRFX Zresult.D, Pg/Z, Zop1.D; MUL Zresult.D, Pg/M, Zresult.D, Zop2.D + /// MOVPRFX Zresult.D, Pg/Z, Zop2.D; MUL Zresult.D, Pg/M, Zresult.D, Zop1.D + /// + public static unsafe Vector Multiply(Vector left, Vector right) { throw new PlatformNotSupportedException(); } + + /// + /// svuint8_t svmul[_u8]_m(svbool_t pg, svuint8_t op1, svuint8_t op2) + /// MUL Ztied1.B, Pg/M, Ztied1.B, Zop2.B + /// MOVPRFX Zresult, Zop1; MUL Zresult.B, Pg/M, Zresult.B, Zop2.B + /// svuint8_t svmul[_u8]_x(svbool_t pg, svuint8_t op1, svuint8_t op2) + /// MUL Ztied1.B, Pg/M, Ztied1.B, Zop2.B + /// MUL Ztied2.B, Pg/M, Ztied2.B, Zop1.B + /// MOVPRFX Zresult, Zop1; MUL Zresult.B, Pg/M, Zresult.B, Zop2.B + /// svuint8_t svmul[_u8]_z(svbool_t pg, svuint8_t op1, svuint8_t op2) + /// MOVPRFX Zresult.B, Pg/Z, Zop1.B; MUL Zresult.B, Pg/M, Zresult.B, Zop2.B + /// MOVPRFX Zresult.B, Pg/Z, Zop2.B; MUL Zresult.B, Pg/M, Zresult.B, Zop1.B + /// + public static unsafe Vector Multiply(Vector left, Vector right) { throw new PlatformNotSupportedException(); } + + /// + /// svuint16_t svmul[_u16]_m(svbool_t pg, svuint16_t op1, svuint16_t op2) + /// MUL Ztied1.H, Pg/M, Ztied1.H, Zop2.H + /// MOVPRFX Zresult, Zop1; MUL Zresult.H, Pg/M, Zresult.H, Zop2.H + /// svuint16_t svmul[_u16]_x(svbool_t pg, svuint16_t op1, svuint16_t op2) + /// MUL Ztied1.H, Pg/M, Ztied1.H, Zop2.H + /// MUL Ztied2.H, Pg/M, Ztied2.H, Zop1.H + /// MOVPRFX Zresult, Zop1; MUL Zresult.H, Pg/M, Zresult.H, Zop2.H + /// svuint16_t svmul[_u16]_z(svbool_t pg, svuint16_t op1, svuint16_t op2) + /// MOVPRFX Zresult.H, Pg/Z, Zop1.H; MUL Zresult.H, Pg/M, Zresult.H, Zop2.H + /// MOVPRFX Zresult.H, Pg/Z, Zop2.H; MUL Zresult.H, Pg/M, Zresult.H, Zop1.H + /// + public static unsafe Vector Multiply(Vector left, Vector right) { throw new PlatformNotSupportedException(); } + + /// + /// svuint32_t svmul[_u32]_m(svbool_t pg, svuint32_t op1, svuint32_t op2) + /// MUL Ztied1.S, Pg/M, Ztied1.S, Zop2.S + /// MOVPRFX Zresult, Zop1; MUL Zresult.S, Pg/M, Zresult.S, Zop2.S + /// svuint32_t svmul[_u32]_x(svbool_t pg, svuint32_t op1, svuint32_t op2) + /// MUL Ztied1.S, Pg/M, Ztied1.S, Zop2.S + /// MUL Ztied2.S, Pg/M, Ztied2.S, Zop1.S + /// MOVPRFX Zresult, Zop1; MUL Zresult.S, Pg/M, Zresult.S, Zop2.S + /// svuint32_t svmul[_u32]_z(svbool_t pg, svuint32_t op1, svuint32_t op2) + /// MOVPRFX Zresult.S, Pg/Z, Zop1.S; MUL Zresult.S, Pg/M, Zresult.S, Zop2.S + /// MOVPRFX Zresult.S, Pg/Z, Zop2.S; MUL Zresult.S, Pg/M, Zresult.S, Zop1.S + /// + public static unsafe Vector Multiply(Vector left, Vector right) { throw new PlatformNotSupportedException(); } + + /// + /// svuint64_t svmul[_u64]_m(svbool_t pg, svuint64_t op1, svuint64_t op2) + /// MUL Ztied1.D, Pg/M, Ztied1.D, Zop2.D + /// MOVPRFX Zresult, Zop1; MUL Zresult.D, Pg/M, Zresult.D, Zop2.D + /// svuint64_t svmul[_u64]_x(svbool_t pg, svuint64_t op1, svuint64_t op2) + /// MUL Ztied1.D, Pg/M, Ztied1.D, Zop2.D + /// MUL Ztied2.D, Pg/M, Ztied2.D, Zop1.D + /// MOVPRFX Zresult, Zop1; MUL Zresult.D, Pg/M, Zresult.D, Zop2.D + /// svuint64_t svmul[_u64]_z(svbool_t pg, svuint64_t op1, svuint64_t op2) + /// MOVPRFX Zresult.D, Pg/Z, Zop1.D; MUL Zresult.D, Pg/M, Zresult.D, Zop2.D + /// MOVPRFX Zresult.D, Pg/Z, Zop2.D; MUL Zresult.D, Pg/M, Zresult.D, Zop1.D + /// + public static unsafe Vector Multiply(Vector left, Vector right) { throw new PlatformNotSupportedException(); } + + /// + /// svfloat32_t svmul[_f32]_m(svbool_t pg, svfloat32_t op1, svfloat32_t op2) + /// FMUL Ztied1.S, Pg/M, Ztied1.S, Zop2.S + /// MOVPRFX Zresult, Zop1; FMUL Zresult.S, Pg/M, Zresult.S, Zop2.S + /// svfloat32_t svmul[_f32]_x(svbool_t pg, svfloat32_t op1, svfloat32_t op2) + /// FMUL Ztied1.S, Pg/M, Ztied1.S, Zop2.S + /// FMUL Ztied2.S, Pg/M, Ztied2.S, Zop1.S + /// FMUL Zresult.S, Zop1.S, Zop2.S + /// MOVPRFX Zresult, Zop1; FMUL Zresult.S, Pg/M, Zresult.S, Zop2.S + /// svfloat32_t svmul[_f32]_z(svbool_t pg, svfloat32_t op1, svfloat32_t op2) + /// MOVPRFX Zresult.S, Pg/Z, Zop1.S; FMUL Zresult.S, Pg/M, Zresult.S, Zop2.S + /// MOVPRFX Zresult.S, Pg/Z, Zop2.S; FMUL Zresult.S, Pg/M, Zresult.S, Zop1.S + /// + public static unsafe Vector Multiply(Vector left, Vector right) { throw new PlatformNotSupportedException(); } + + /// + /// svfloat64_t svmul[_f64]_m(svbool_t pg, svfloat64_t op1, svfloat64_t op2) + /// FMUL Ztied1.D, Pg/M, Ztied1.D, Zop2.D + /// MOVPRFX Zresult, Zop1; FMUL Zresult.D, Pg/M, Zresult.D, Zop2.D + /// svfloat64_t svmul[_f64]_x(svbool_t pg, svfloat64_t op1, svfloat64_t op2) + /// FMUL Ztied1.D, Pg/M, Ztied1.D, Zop2.D + /// FMUL Ztied2.D, Pg/M, Ztied2.D, Zop1.D + /// FMUL Zresult.D, Zop1.D, Zop2.D + /// MOVPRFX Zresult, Zop1; FMUL Zresult.D, Pg/M, Zresult.D, Zop2.D + /// svfloat64_t svmul[_f64]_z(svbool_t pg, svfloat64_t op1, svfloat64_t op2) + /// MOVPRFX Zresult.D, Pg/Z, Zop1.D; FMUL Zresult.D, Pg/M, Zresult.D, Zop2.D + /// MOVPRFX Zresult.D, Pg/Z, Zop2.D; FMUL Zresult.D, Pg/M, Zresult.D, Zop1.D + /// + public static unsafe Vector Multiply(Vector left, Vector right) { throw new PlatformNotSupportedException(); } + + /// Subtract : Subtract + + /// + /// svint8_t svsub[_s8]_m(svbool_t pg, svint8_t op1, svint8_t op2) + /// SUB Ztied1.B, Pg/M, Ztied1.B, Zop2.B + /// MOVPRFX Zresult, Zop1; SUB Zresult.B, Pg/M, Zresult.B, Zop2.B + /// svint8_t svsub[_s8]_x(svbool_t pg, svint8_t op1, svint8_t op2) + /// SUB Ztied1.B, Pg/M, Ztied1.B, Zop2.B + /// SUB Zresult.B, Zop1.B, Zop2.B + /// svint8_t svsub[_s8]_z(svbool_t pg, svint8_t op1, svint8_t op2) + /// MOVPRFX Zresult.B, Pg/Z, Zop1.B; SUB Zresult.B, Pg/M, Zresult.B, Zop2.B + /// + public static unsafe Vector Subtract(Vector left, Vector right) { throw new PlatformNotSupportedException(); } + + /// + /// svint16_t svsub[_s16]_m(svbool_t pg, svint16_t op1, svint16_t op2) + /// SUB Ztied1.H, Pg/M, Ztied1.H, Zop2.H + /// MOVPRFX Zresult, Zop1; SUB Zresult.H, Pg/M, Zresult.H, Zop2.H + /// svint16_t svsub[_s16]_x(svbool_t pg, svint16_t op1, svint16_t op2) + /// SUB Ztied1.H, Pg/M, Ztied1.H, Zop2.H + /// SUB Zresult.H, Zop1.H, Zop2.H + /// svint16_t svsub[_s16]_z(svbool_t pg, svint16_t op1, svint16_t op2) + /// MOVPRFX Zresult.H, Pg/Z, Zop1.H; SUB Zresult.H, Pg/M, Zresult.H, Zop2.H + /// + public static unsafe Vector Subtract(Vector left, Vector right) { throw new PlatformNotSupportedException(); } + + /// + /// svint32_t svsub[_s32]_m(svbool_t pg, svint32_t op1, svint32_t op2) + /// SUB Ztied1.S, Pg/M, Ztied1.S, Zop2.S + /// MOVPRFX Zresult, Zop1; SUB Zresult.S, Pg/M, Zresult.S, Zop2.S + /// svint32_t svsub[_s32]_x(svbool_t pg, svint32_t op1, svint32_t op2) + /// SUB Ztied1.S, Pg/M, Ztied1.S, Zop2.S + /// SUB Zresult.S, Zop1.S, Zop2.S + /// svint32_t svsub[_s32]_z(svbool_t pg, svint32_t op1, svint32_t op2) + /// MOVPRFX Zresult.S, Pg/Z, Zop1.S; SUB Zresult.S, Pg/M, Zresult.S, Zop2.S + /// + public static unsafe Vector Subtract(Vector left, Vector right) { throw new PlatformNotSupportedException(); } + + /// + /// svint64_t svsub[_s64]_m(svbool_t pg, svint64_t op1, svint64_t op2) + /// SUB Ztied1.D, Pg/M, Ztied1.D, Zop2.D + /// MOVPRFX Zresult, Zop1; SUB Zresult.D, Pg/M, Zresult.D, Zop2.D + /// svint64_t svsub[_s64]_x(svbool_t pg, svint64_t op1, svint64_t op2) + /// SUB Ztied1.D, Pg/M, Ztied1.D, Zop2.D + /// SUB Zresult.D, Zop1.D, Zop2.D + /// svint64_t svsub[_s64]_z(svbool_t pg, svint64_t op1, svint64_t op2) + /// MOVPRFX Zresult.D, Pg/Z, Zop1.D; SUB Zresult.D, Pg/M, Zresult.D, Zop2.D + /// + public static unsafe Vector Subtract(Vector left, Vector right) { throw new PlatformNotSupportedException(); } + + /// + /// svuint8_t svsub[_u8]_m(svbool_t pg, svuint8_t op1, svuint8_t op2) + /// SUB Ztied1.B, Pg/M, Ztied1.B, Zop2.B + /// MOVPRFX Zresult, Zop1; SUB Zresult.B, Pg/M, Zresult.B, Zop2.B + /// svuint8_t svsub[_u8]_x(svbool_t pg, svuint8_t op1, svuint8_t op2) + /// SUB Ztied1.B, Pg/M, Ztied1.B, Zop2.B + /// SUB Zresult.B, Zop1.B, Zop2.B + /// svuint8_t svsub[_u8]_z(svbool_t pg, svuint8_t op1, svuint8_t op2) + /// MOVPRFX Zresult.B, Pg/Z, Zop1.B; SUB Zresult.B, Pg/M, Zresult.B, Zop2.B + /// + public static unsafe Vector Subtract(Vector left, Vector right) { throw new PlatformNotSupportedException(); } + + /// + /// svuint16_t svsub[_u16]_m(svbool_t pg, svuint16_t op1, svuint16_t op2) + /// SUB Ztied1.H, Pg/M, Ztied1.H, Zop2.H + /// MOVPRFX Zresult, Zop1; SUB Zresult.H, Pg/M, Zresult.H, Zop2.H + /// svuint16_t svsub[_u16]_x(svbool_t pg, svuint16_t op1, svuint16_t op2) + /// SUB Ztied1.H, Pg/M, Ztied1.H, Zop2.H + /// SUB Zresult.H, Zop1.H, Zop2.H + /// svuint16_t svsub[_u16]_z(svbool_t pg, svuint16_t op1, svuint16_t op2) + /// MOVPRFX Zresult.H, Pg/Z, Zop1.H; SUB Zresult.H, Pg/M, Zresult.H, Zop2.H + /// + public static unsafe Vector Subtract(Vector left, Vector right) { throw new PlatformNotSupportedException(); } + + /// + /// svuint32_t svsub[_u32]_m(svbool_t pg, svuint32_t op1, svuint32_t op2) + /// SUB Ztied1.S, Pg/M, Ztied1.S, Zop2.S + /// MOVPRFX Zresult, Zop1; SUB Zresult.S, Pg/M, Zresult.S, Zop2.S + /// svuint32_t svsub[_u32]_x(svbool_t pg, svuint32_t op1, svuint32_t op2) + /// SUB Ztied1.S, Pg/M, Ztied1.S, Zop2.S + /// SUB Zresult.S, Zop1.S, Zop2.S + /// svuint32_t svsub[_u32]_z(svbool_t pg, svuint32_t op1, svuint32_t op2) + /// MOVPRFX Zresult.S, Pg/Z, Zop1.S; SUB Zresult.S, Pg/M, Zresult.S, Zop2.S + /// + public static unsafe Vector Subtract(Vector left, Vector right) { throw new PlatformNotSupportedException(); } + + /// + /// svuint64_t svsub[_u64]_m(svbool_t pg, svuint64_t op1, svuint64_t op2) + /// SUB Ztied1.D, Pg/M, Ztied1.D, Zop2.D + /// MOVPRFX Zresult, Zop1; SUB Zresult.D, Pg/M, Zresult.D, Zop2.D + /// svuint64_t svsub[_u64]_x(svbool_t pg, svuint64_t op1, svuint64_t op2) + /// SUB Ztied1.D, Pg/M, Ztied1.D, Zop2.D + /// SUB Zresult.D, Zop1.D, Zop2.D + /// svuint64_t svsub[_u64]_z(svbool_t pg, svuint64_t op1, svuint64_t op2) + /// MOVPRFX Zresult.D, Pg/Z, Zop1.D; SUB Zresult.D, Pg/M, Zresult.D, Zop2.D + /// + public static unsafe Vector Subtract(Vector left, Vector right) { throw new PlatformNotSupportedException(); } + + /// + /// svfloat32_t svsub[_f32]_m(svbool_t pg, svfloat32_t op1, svfloat32_t op2) + /// FSUB Ztied1.S, Pg/M, Ztied1.S, Zop2.S + /// MOVPRFX Zresult, Zop1; FSUB Zresult.S, Pg/M, Zresult.S, Zop2.S + /// svfloat32_t svsub[_f32]_x(svbool_t pg, svfloat32_t op1, svfloat32_t op2) + /// FSUB Ztied1.S, Pg/M, Ztied1.S, Zop2.S + /// FSUB Zresult.S, Zop1.S, Zop2.S + /// MOVPRFX Zresult, Zop1; FSUB Zresult.S, Pg/M, Zresult.S, Zop2.S + /// svfloat32_t svsub[_f32]_z(svbool_t pg, svfloat32_t op1, svfloat32_t op2) + /// MOVPRFX Zresult.S, Pg/Z, Zop1.S; FSUB Zresult.S, Pg/M, Zresult.S, Zop2.S + /// + public static unsafe Vector Subtract(Vector left, Vector right) { throw new PlatformNotSupportedException(); } + + /// + /// svfloat64_t svsub[_f64]_m(svbool_t pg, svfloat64_t op1, svfloat64_t op2) + /// FSUB Ztied1.D, Pg/M, Ztied1.D, Zop2.D + /// MOVPRFX Zresult, Zop1; FSUB Zresult.D, Pg/M, Zresult.D, Zop2.D + /// svfloat64_t svsub[_f64]_x(svbool_t pg, svfloat64_t op1, svfloat64_t op2) + /// FSUB Ztied1.D, Pg/M, Ztied1.D, Zop2.D + /// FSUB Zresult.D, Zop1.D, Zop2.D + /// MOVPRFX Zresult, Zop1; FSUB Zresult.D, Pg/M, Zresult.D, Zop2.D + /// svfloat64_t svsub[_f64]_z(svbool_t pg, svfloat64_t op1, svfloat64_t op2) + /// MOVPRFX Zresult.D, Pg/Z, Zop1.D; FSUB Zresult.D, Pg/M, Zresult.D, Zop2.D + /// + public static unsafe Vector Subtract(Vector left, Vector right) { throw new PlatformNotSupportedException(); } /// UnzipEven : Concatenate even elements from two inputs diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Arm/Sve.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Arm/Sve.cs index 0f4f57dad8e9bc..e823e36e4db2a9 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Arm/Sve.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Arm/Sve.cs @@ -608,6 +608,32 @@ internal Arm64() { } public static unsafe Vector CreateWhileLessThanOrEqualMask8Bit(ulong left, ulong right) => CreateWhileLessThanOrEqualMask8Bit(left, right); + /// Divide : Divide + + /// + /// svfloat32_t svdiv[_f32]_m(svbool_t pg, svfloat32_t op1, svfloat32_t op2) + /// FDIV Ztied1.S, Pg/M, Ztied1.S, Zop2.S + /// MOVPRFX Zresult, Zop1; FDIV Zresult.S, Pg/M, Zresult.S, Zop2.S + /// svfloat32_t svdiv[_f32]_x(svbool_t pg, svfloat32_t op1, svfloat32_t op2) + /// FDIV Ztied1.S, Pg/M, Ztied1.S, Zop2.S + /// MOVPRFX Zresult, Zop1; FDIV Zresult.S, Pg/M, Zresult.S, Zop2.S + /// svfloat32_t svdiv[_f32]_z(svbool_t pg, svfloat32_t op1, svfloat32_t op2) + /// MOVPRFX Zresult.S, Pg/Z, Zop1.S; FDIV Zresult.S, Pg/M, Zresult.S, Zop2.S + /// + public static unsafe Vector Divide(Vector left, Vector right) => Divide(left, right); + + /// + /// svfloat64_t svdiv[_f64]_m(svbool_t pg, svfloat64_t op1, svfloat64_t op2) + /// FDIV Ztied1.D, Pg/M, Ztied1.D, Zop2.D + /// MOVPRFX Zresult, Zop1; FDIV Zresult.D, Pg/M, Zresult.D, Zop2.D + /// svfloat64_t svdiv[_f64]_x(svbool_t pg, svfloat64_t op1, svfloat64_t op2) + /// FDIV Ztied1.D, Pg/M, Ztied1.D, Zop2.D + /// MOVPRFX Zresult, Zop1; FDIV Zresult.D, Pg/M, Zresult.D, Zop2.D + /// svfloat64_t svdiv[_f64]_z(svbool_t pg, svfloat64_t op1, svfloat64_t op2) + /// MOVPRFX Zresult.D, Pg/Z, Zop1.D; FDIV Zresult.D, Pg/M, Zresult.D, Zop2.D + /// + public static unsafe Vector Divide(Vector left, Vector right) => Divide(left, right); + /// LoadVector : Unextended load /// @@ -897,6 +923,272 @@ internal Arm64() { } public static unsafe Vector LoadVectorUInt32ZeroExtendToUInt64(Vector mask, uint* address) => LoadVectorUInt32ZeroExtendToUInt64(mask, address); + /// + /// svint8_t svmul[_s8]_m(svbool_t pg, svint8_t op1, svint8_t op2) + /// MUL Ztied1.B, Pg/M, Ztied1.B, Zop2.B + /// MOVPRFX Zresult, Zop1; MUL Zresult.B, Pg/M, Zresult.B, Zop2.B + /// svint8_t svmul[_s8]_x(svbool_t pg, svint8_t op1, svint8_t op2) + /// MUL Ztied1.B, Pg/M, Ztied1.B, Zop2.B + /// MUL Ztied2.B, Pg/M, Ztied2.B, Zop1.B + /// MOVPRFX Zresult, Zop1; MUL Zresult.B, Pg/M, Zresult.B, Zop2.B + /// svint8_t svmul[_s8]_z(svbool_t pg, svint8_t op1, svint8_t op2) + /// MOVPRFX Zresult.B, Pg/Z, Zop1.B; MUL Zresult.B, Pg/M, Zresult.B, Zop2.B + /// MOVPRFX Zresult.B, Pg/Z, Zop2.B; MUL Zresult.B, Pg/M, Zresult.B, Zop1.B + /// + public static unsafe Vector Multiply(Vector left, Vector right) => Multiply(left, right); + + /// + /// svint16_t svmul[_s16]_m(svbool_t pg, svint16_t op1, svint16_t op2) + /// MUL Ztied1.H, Pg/M, Ztied1.H, Zop2.H + /// MOVPRFX Zresult, Zop1; MUL Zresult.H, Pg/M, Zresult.H, Zop2.H + /// svint16_t svmul[_s16]_x(svbool_t pg, svint16_t op1, svint16_t op2) + /// MUL Ztied1.H, Pg/M, Ztied1.H, Zop2.H + /// MUL Ztied2.H, Pg/M, Ztied2.H, Zop1.H + /// MOVPRFX Zresult, Zop1; MUL Zresult.H, Pg/M, Zresult.H, Zop2.H + /// svint16_t svmul[_s16]_z(svbool_t pg, svint16_t op1, svint16_t op2) + /// MOVPRFX Zresult.H, Pg/Z, Zop1.H; MUL Zresult.H, Pg/M, Zresult.H, Zop2.H + /// MOVPRFX Zresult.H, Pg/Z, Zop2.H; MUL Zresult.H, Pg/M, Zresult.H, Zop1.H + /// + public static unsafe Vector Multiply(Vector left, Vector right) => Multiply(left, right); + + /// + /// svint32_t svmul[_s32]_m(svbool_t pg, svint32_t op1, svint32_t op2) + /// MUL Ztied1.S, Pg/M, Ztied1.S, Zop2.S + /// MOVPRFX Zresult, Zop1; MUL Zresult.S, Pg/M, Zresult.S, Zop2.S + /// svint32_t svmul[_s32]_x(svbool_t pg, svint32_t op1, svint32_t op2) + /// MUL Ztied1.S, Pg/M, Ztied1.S, Zop2.S + /// MUL Ztied2.S, Pg/M, Ztied2.S, Zop1.S + /// MOVPRFX Zresult, Zop1; MUL Zresult.S, Pg/M, Zresult.S, Zop2.S + /// svint32_t svmul[_s32]_z(svbool_t pg, svint32_t op1, svint32_t op2) + /// MOVPRFX Zresult.S, Pg/Z, Zop1.S; MUL Zresult.S, Pg/M, Zresult.S, Zop2.S + /// MOVPRFX Zresult.S, Pg/Z, Zop2.S; MUL Zresult.S, Pg/M, Zresult.S, Zop1.S + /// + public static unsafe Vector Multiply(Vector left, Vector right) => Multiply(left, right); + + /// + /// svint64_t svmul[_s64]_m(svbool_t pg, svint64_t op1, svint64_t op2) + /// MUL Ztied1.D, Pg/M, Ztied1.D, Zop2.D + /// MOVPRFX Zresult, Zop1; MUL Zresult.D, Pg/M, Zresult.D, Zop2.D + /// svint64_t svmul[_s64]_x(svbool_t pg, svint64_t op1, svint64_t op2) + /// MUL Ztied1.D, Pg/M, Ztied1.D, Zop2.D + /// MUL Ztied2.D, Pg/M, Ztied2.D, Zop1.D + /// MOVPRFX Zresult, Zop1; MUL Zresult.D, Pg/M, Zresult.D, Zop2.D + /// svint64_t svmul[_s64]_z(svbool_t pg, svint64_t op1, svint64_t op2) + /// MOVPRFX Zresult.D, Pg/Z, Zop1.D; MUL Zresult.D, Pg/M, Zresult.D, Zop2.D + /// MOVPRFX Zresult.D, Pg/Z, Zop2.D; MUL Zresult.D, Pg/M, Zresult.D, Zop1.D + /// + public static unsafe Vector Multiply(Vector left, Vector right) => Multiply(left, right); + + /// + /// svuint8_t svmul[_u8]_m(svbool_t pg, svuint8_t op1, svuint8_t op2) + /// MUL Ztied1.B, Pg/M, Ztied1.B, Zop2.B + /// MOVPRFX Zresult, Zop1; MUL Zresult.B, Pg/M, Zresult.B, Zop2.B + /// svuint8_t svmul[_u8]_x(svbool_t pg, svuint8_t op1, svuint8_t op2) + /// MUL Ztied1.B, Pg/M, Ztied1.B, Zop2.B + /// MUL Ztied2.B, Pg/M, Ztied2.B, Zop1.B + /// MOVPRFX Zresult, Zop1; MUL Zresult.B, Pg/M, Zresult.B, Zop2.B + /// svuint8_t svmul[_u8]_z(svbool_t pg, svuint8_t op1, svuint8_t op2) + /// MOVPRFX Zresult.B, Pg/Z, Zop1.B; MUL Zresult.B, Pg/M, Zresult.B, Zop2.B + /// MOVPRFX Zresult.B, Pg/Z, Zop2.B; MUL Zresult.B, Pg/M, Zresult.B, Zop1.B + /// + public static unsafe Vector Multiply(Vector left, Vector right) => Multiply(left, right); + + /// + /// svuint16_t svmul[_u16]_m(svbool_t pg, svuint16_t op1, svuint16_t op2) + /// MUL Ztied1.H, Pg/M, Ztied1.H, Zop2.H + /// MOVPRFX Zresult, Zop1; MUL Zresult.H, Pg/M, Zresult.H, Zop2.H + /// svuint16_t svmul[_u16]_x(svbool_t pg, svuint16_t op1, svuint16_t op2) + /// MUL Ztied1.H, Pg/M, Ztied1.H, Zop2.H + /// MUL Ztied2.H, Pg/M, Ztied2.H, Zop1.H + /// MOVPRFX Zresult, Zop1; MUL Zresult.H, Pg/M, Zresult.H, Zop2.H + /// svuint16_t svmul[_u16]_z(svbool_t pg, svuint16_t op1, svuint16_t op2) + /// MOVPRFX Zresult.H, Pg/Z, Zop1.H; MUL Zresult.H, Pg/M, Zresult.H, Zop2.H + /// MOVPRFX Zresult.H, Pg/Z, Zop2.H; MUL Zresult.H, Pg/M, Zresult.H, Zop1.H + /// + public static unsafe Vector Multiply(Vector left, Vector right) => Multiply(left, right); + + /// + /// svuint32_t svmul[_u32]_m(svbool_t pg, svuint32_t op1, svuint32_t op2) + /// MUL Ztied1.S, Pg/M, Ztied1.S, Zop2.S + /// MOVPRFX Zresult, Zop1; MUL Zresult.S, Pg/M, Zresult.S, Zop2.S + /// svuint32_t svmul[_u32]_x(svbool_t pg, svuint32_t op1, svuint32_t op2) + /// MUL Ztied1.S, Pg/M, Ztied1.S, Zop2.S + /// MUL Ztied2.S, Pg/M, Ztied2.S, Zop1.S + /// MOVPRFX Zresult, Zop1; MUL Zresult.S, Pg/M, Zresult.S, Zop2.S + /// svuint32_t svmul[_u32]_z(svbool_t pg, svuint32_t op1, svuint32_t op2) + /// MOVPRFX Zresult.S, Pg/Z, Zop1.S; MUL Zresult.S, Pg/M, Zresult.S, Zop2.S + /// MOVPRFX Zresult.S, Pg/Z, Zop2.S; MUL Zresult.S, Pg/M, Zresult.S, Zop1.S + /// + public static unsafe Vector Multiply(Vector left, Vector right) => Multiply(left, right); + + /// + /// svuint64_t svmul[_u64]_m(svbool_t pg, svuint64_t op1, svuint64_t op2) + /// MUL Ztied1.D, Pg/M, Ztied1.D, Zop2.D + /// MOVPRFX Zresult, Zop1; MUL Zresult.D, Pg/M, Zresult.D, Zop2.D + /// svuint64_t svmul[_u64]_x(svbool_t pg, svuint64_t op1, svuint64_t op2) + /// MUL Ztied1.D, Pg/M, Ztied1.D, Zop2.D + /// MUL Ztied2.D, Pg/M, Ztied2.D, Zop1.D + /// MOVPRFX Zresult, Zop1; MUL Zresult.D, Pg/M, Zresult.D, Zop2.D + /// svuint64_t svmul[_u64]_z(svbool_t pg, svuint64_t op1, svuint64_t op2) + /// MOVPRFX Zresult.D, Pg/Z, Zop1.D; MUL Zresult.D, Pg/M, Zresult.D, Zop2.D + /// MOVPRFX Zresult.D, Pg/Z, Zop2.D; MUL Zresult.D, Pg/M, Zresult.D, Zop1.D + /// + public static unsafe Vector Multiply(Vector left, Vector right) => Multiply(left, right); + + /// + /// svfloat32_t svmul[_f32]_m(svbool_t pg, svfloat32_t op1, svfloat32_t op2) + /// FMUL Ztied1.S, Pg/M, Ztied1.S, Zop2.S + /// MOVPRFX Zresult, Zop1; FMUL Zresult.S, Pg/M, Zresult.S, Zop2.S + /// svfloat32_t svmul[_f32]_x(svbool_t pg, svfloat32_t op1, svfloat32_t op2) + /// FMUL Ztied1.S, Pg/M, Ztied1.S, Zop2.S + /// FMUL Ztied2.S, Pg/M, Ztied2.S, Zop1.S + /// FMUL Zresult.S, Zop1.S, Zop2.S + /// MOVPRFX Zresult, Zop1; FMUL Zresult.S, Pg/M, Zresult.S, Zop2.S + /// svfloat32_t svmul[_f32]_z(svbool_t pg, svfloat32_t op1, svfloat32_t op2) + /// MOVPRFX Zresult.S, Pg/Z, Zop1.S; FMUL Zresult.S, Pg/M, Zresult.S, Zop2.S + /// MOVPRFX Zresult.S, Pg/Z, Zop2.S; FMUL Zresult.S, Pg/M, Zresult.S, Zop1.S + /// + public static unsafe Vector Multiply(Vector left, Vector right) => Multiply(left, right); + + /// + /// svfloat64_t svmul[_f64]_m(svbool_t pg, svfloat64_t op1, svfloat64_t op2) + /// FMUL Ztied1.D, Pg/M, Ztied1.D, Zop2.D + /// MOVPRFX Zresult, Zop1; FMUL Zresult.D, Pg/M, Zresult.D, Zop2.D + /// svfloat64_t svmul[_f64]_x(svbool_t pg, svfloat64_t op1, svfloat64_t op2) + /// FMUL Ztied1.D, Pg/M, Ztied1.D, Zop2.D + /// FMUL Ztied2.D, Pg/M, Ztied2.D, Zop1.D + /// FMUL Zresult.D, Zop1.D, Zop2.D + /// MOVPRFX Zresult, Zop1; FMUL Zresult.D, Pg/M, Zresult.D, Zop2.D + /// svfloat64_t svmul[_f64]_z(svbool_t pg, svfloat64_t op1, svfloat64_t op2) + /// MOVPRFX Zresult.D, Pg/Z, Zop1.D; FMUL Zresult.D, Pg/M, Zresult.D, Zop2.D + /// MOVPRFX Zresult.D, Pg/Z, Zop2.D; FMUL Zresult.D, Pg/M, Zresult.D, Zop1.D + /// + public static unsafe Vector Multiply(Vector left, Vector right) => Multiply(left, right); + + /// Subtract : Subtract + + /// + /// svint8_t svsub[_s8]_m(svbool_t pg, svint8_t op1, svint8_t op2) + /// SUB Ztied1.B, Pg/M, Ztied1.B, Zop2.B + /// MOVPRFX Zresult, Zop1; SUB Zresult.B, Pg/M, Zresult.B, Zop2.B + /// svint8_t svsub[_s8]_x(svbool_t pg, svint8_t op1, svint8_t op2) + /// SUB Ztied1.B, Pg/M, Ztied1.B, Zop2.B + /// SUB Zresult.B, Zop1.B, Zop2.B + /// svint8_t svsub[_s8]_z(svbool_t pg, svint8_t op1, svint8_t op2) + /// MOVPRFX Zresult.B, Pg/Z, Zop1.B; SUB Zresult.B, Pg/M, Zresult.B, Zop2.B + /// + public static unsafe Vector Subtract(Vector left, Vector right) => Subtract(left, right); + + /// + /// svint16_t svsub[_s16]_m(svbool_t pg, svint16_t op1, svint16_t op2) + /// SUB Ztied1.H, Pg/M, Ztied1.H, Zop2.H + /// MOVPRFX Zresult, Zop1; SUB Zresult.H, Pg/M, Zresult.H, Zop2.H + /// svint16_t svsub[_s16]_x(svbool_t pg, svint16_t op1, svint16_t op2) + /// SUB Ztied1.H, Pg/M, Ztied1.H, Zop2.H + /// SUB Zresult.H, Zop1.H, Zop2.H + /// svint16_t svsub[_s16]_z(svbool_t pg, svint16_t op1, svint16_t op2) + /// MOVPRFX Zresult.H, Pg/Z, Zop1.H; SUB Zresult.H, Pg/M, Zresult.H, Zop2.H + /// + public static unsafe Vector Subtract(Vector left, Vector right) => Subtract(left, right); + + /// + /// svint32_t svsub[_s32]_m(svbool_t pg, svint32_t op1, svint32_t op2) + /// SUB Ztied1.S, Pg/M, Ztied1.S, Zop2.S + /// MOVPRFX Zresult, Zop1; SUB Zresult.S, Pg/M, Zresult.S, Zop2.S + /// svint32_t svsub[_s32]_x(svbool_t pg, svint32_t op1, svint32_t op2) + /// SUB Ztied1.S, Pg/M, Ztied1.S, Zop2.S + /// SUB Zresult.S, Zop1.S, Zop2.S + /// svint32_t svsub[_s32]_z(svbool_t pg, svint32_t op1, svint32_t op2) + /// MOVPRFX Zresult.S, Pg/Z, Zop1.S; SUB Zresult.S, Pg/M, Zresult.S, Zop2.S + /// + public static unsafe Vector Subtract(Vector left, Vector right) => Subtract(left, right); + + /// + /// svint64_t svsub[_s64]_m(svbool_t pg, svint64_t op1, svint64_t op2) + /// SUB Ztied1.D, Pg/M, Ztied1.D, Zop2.D + /// MOVPRFX Zresult, Zop1; SUB Zresult.D, Pg/M, Zresult.D, Zop2.D + /// svint64_t svsub[_s64]_x(svbool_t pg, svint64_t op1, svint64_t op2) + /// SUB Ztied1.D, Pg/M, Ztied1.D, Zop2.D + /// SUB Zresult.D, Zop1.D, Zop2.D + /// svint64_t svsub[_s64]_z(svbool_t pg, svint64_t op1, svint64_t op2) + /// MOVPRFX Zresult.D, Pg/Z, Zop1.D; SUB Zresult.D, Pg/M, Zresult.D, Zop2.D + /// + public static unsafe Vector Subtract(Vector left, Vector right) => Subtract(left, right); + + /// + /// svuint8_t svsub[_u8]_m(svbool_t pg, svuint8_t op1, svuint8_t op2) + /// SUB Ztied1.B, Pg/M, Ztied1.B, Zop2.B + /// MOVPRFX Zresult, Zop1; SUB Zresult.B, Pg/M, Zresult.B, Zop2.B + /// svuint8_t svsub[_u8]_x(svbool_t pg, svuint8_t op1, svuint8_t op2) + /// SUB Ztied1.B, Pg/M, Ztied1.B, Zop2.B + /// SUB Zresult.B, Zop1.B, Zop2.B + /// svuint8_t svsub[_u8]_z(svbool_t pg, svuint8_t op1, svuint8_t op2) + /// MOVPRFX Zresult.B, Pg/Z, Zop1.B; SUB Zresult.B, Pg/M, Zresult.B, Zop2.B + /// + public static unsafe Vector Subtract(Vector left, Vector right) => Subtract(left, right); + + /// + /// svuint16_t svsub[_u16]_m(svbool_t pg, svuint16_t op1, svuint16_t op2) + /// SUB Ztied1.H, Pg/M, Ztied1.H, Zop2.H + /// MOVPRFX Zresult, Zop1; SUB Zresult.H, Pg/M, Zresult.H, Zop2.H + /// svuint16_t svsub[_u16]_x(svbool_t pg, svuint16_t op1, svuint16_t op2) + /// SUB Ztied1.H, Pg/M, Ztied1.H, Zop2.H + /// SUB Zresult.H, Zop1.H, Zop2.H + /// svuint16_t svsub[_u16]_z(svbool_t pg, svuint16_t op1, svuint16_t op2) + /// MOVPRFX Zresult.H, Pg/Z, Zop1.H; SUB Zresult.H, Pg/M, Zresult.H, Zop2.H + /// + public static unsafe Vector Subtract(Vector left, Vector right) => Subtract(left, right); + + /// + /// svuint32_t svsub[_u32]_m(svbool_t pg, svuint32_t op1, svuint32_t op2) + /// SUB Ztied1.S, Pg/M, Ztied1.S, Zop2.S + /// MOVPRFX Zresult, Zop1; SUB Zresult.S, Pg/M, Zresult.S, Zop2.S + /// svuint32_t svsub[_u32]_x(svbool_t pg, svuint32_t op1, svuint32_t op2) + /// SUB Ztied1.S, Pg/M, Ztied1.S, Zop2.S + /// SUB Zresult.S, Zop1.S, Zop2.S + /// svuint32_t svsub[_u32]_z(svbool_t pg, svuint32_t op1, svuint32_t op2) + /// MOVPRFX Zresult.S, Pg/Z, Zop1.S; SUB Zresult.S, Pg/M, Zresult.S, Zop2.S + /// + public static unsafe Vector Subtract(Vector left, Vector right) => Subtract(left, right); + + /// + /// svuint64_t svsub[_u64]_m(svbool_t pg, svuint64_t op1, svuint64_t op2) + /// SUB Ztied1.D, Pg/M, Ztied1.D, Zop2.D + /// MOVPRFX Zresult, Zop1; SUB Zresult.D, Pg/M, Zresult.D, Zop2.D + /// svuint64_t svsub[_u64]_x(svbool_t pg, svuint64_t op1, svuint64_t op2) + /// SUB Ztied1.D, Pg/M, Ztied1.D, Zop2.D + /// SUB Zresult.D, Zop1.D, Zop2.D + /// svuint64_t svsub[_u64]_z(svbool_t pg, svuint64_t op1, svuint64_t op2) + /// MOVPRFX Zresult.D, Pg/Z, Zop1.D; SUB Zresult.D, Pg/M, Zresult.D, Zop2.D + /// + public static unsafe Vector Subtract(Vector left, Vector right) => Subtract(left, right); + + /// + /// svfloat32_t svsub[_f32]_m(svbool_t pg, svfloat32_t op1, svfloat32_t op2) + /// FSUB Ztied1.S, Pg/M, Ztied1.S, Zop2.S + /// MOVPRFX Zresult, Zop1; FSUB Zresult.S, Pg/M, Zresult.S, Zop2.S + /// svfloat32_t svsub[_f32]_x(svbool_t pg, svfloat32_t op1, svfloat32_t op2) + /// FSUB Ztied1.S, Pg/M, Ztied1.S, Zop2.S + /// FSUB Zresult.S, Zop1.S, Zop2.S + /// MOVPRFX Zresult, Zop1; FSUB Zresult.S, Pg/M, Zresult.S, Zop2.S + /// svfloat32_t svsub[_f32]_z(svbool_t pg, svfloat32_t op1, svfloat32_t op2) + /// MOVPRFX Zresult.S, Pg/Z, Zop1.S; FSUB Zresult.S, Pg/M, Zresult.S, Zop2.S + /// + public static unsafe Vector Subtract(Vector left, Vector right) => Subtract(left, right); + + /// + /// svfloat64_t svsub[_f64]_m(svbool_t pg, svfloat64_t op1, svfloat64_t op2) + /// FSUB Ztied1.D, Pg/M, Ztied1.D, Zop2.D + /// MOVPRFX Zresult, Zop1; FSUB Zresult.D, Pg/M, Zresult.D, Zop2.D + /// svfloat64_t svsub[_f64]_x(svbool_t pg, svfloat64_t op1, svfloat64_t op2) + /// FSUB Ztied1.D, Pg/M, Ztied1.D, Zop2.D + /// FSUB Zresult.D, Zop1.D, Zop2.D + /// MOVPRFX Zresult, Zop1; FSUB Zresult.D, Pg/M, Zresult.D, Zop2.D + /// svfloat64_t svsub[_f64]_z(svbool_t pg, svfloat64_t op1, svfloat64_t op2) + /// MOVPRFX Zresult.D, Pg/Z, Zop1.D; FSUB Zresult.D, Pg/M, Zresult.D, Zop2.D + /// + public static unsafe Vector Subtract(Vector left, Vector right) => Subtract(left, right); + /// UnzipEven : Concatenate even elements from two inputs /// diff --git a/src/libraries/System.Runtime.Intrinsics/ref/System.Runtime.Intrinsics.cs b/src/libraries/System.Runtime.Intrinsics/ref/System.Runtime.Intrinsics.cs index 881100ff95976c..f67349e325b27e 100644 --- a/src/libraries/System.Runtime.Intrinsics/ref/System.Runtime.Intrinsics.cs +++ b/src/libraries/System.Runtime.Intrinsics/ref/System.Runtime.Intrinsics.cs @@ -4243,6 +4243,8 @@ internal Arm64() { } public static System.Numerics.Vector CreateWhileLessThanOrEqualMask8Bit(long left, long right) { throw null; } public static System.Numerics.Vector CreateWhileLessThanOrEqualMask8Bit(uint left, uint right) { throw null; } public static System.Numerics.Vector CreateWhileLessThanOrEqualMask8Bit(ulong left, ulong right) { throw null; } + public static System.Numerics.Vector Divide(System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } + public static System.Numerics.Vector Divide(System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } public static unsafe System.Numerics.Vector LoadVector(System.Numerics.Vector mask, sbyte* address) { throw null; } public static unsafe System.Numerics.Vector LoadVector(System.Numerics.Vector mask, short* address) { throw null; } public static unsafe System.Numerics.Vector LoadVector(System.Numerics.Vector mask, int* address) { throw null; } @@ -4277,7 +4279,26 @@ internal Arm64() { } public static unsafe System.Numerics.Vector LoadVectorUInt16ZeroExtendToUInt64(System.Numerics.Vector mask, ushort* address) { throw null; } public static unsafe System.Numerics.Vector LoadVectorUInt32ZeroExtendToInt64(System.Numerics.Vector mask, uint* address) { throw null; } public static unsafe System.Numerics.Vector LoadVectorUInt32ZeroExtendToUInt64(System.Numerics.Vector mask, uint* address) { throw null; } - + public static System.Numerics.Vector Subtract(System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } + public static System.Numerics.Vector Subtract(System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } + public static System.Numerics.Vector Subtract(System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } + public static System.Numerics.Vector Subtract(System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } + public static System.Numerics.Vector Subtract(System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } + public static System.Numerics.Vector Subtract(System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } + public static System.Numerics.Vector Subtract(System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } + public static System.Numerics.Vector Subtract(System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } + public static System.Numerics.Vector Subtract(System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } + public static System.Numerics.Vector Subtract(System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } + public static System.Numerics.Vector Multiply(System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } + public static System.Numerics.Vector Multiply(System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } + public static System.Numerics.Vector Multiply(System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } + public static System.Numerics.Vector Multiply(System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } + public static System.Numerics.Vector Multiply(System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } + public static System.Numerics.Vector Multiply(System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } + public static System.Numerics.Vector Multiply(System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } + public static System.Numerics.Vector Multiply(System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } + public static System.Numerics.Vector Multiply(System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } + public static System.Numerics.Vector Multiply(System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } public static System.Numerics.Vector UnzipEven(System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } public static System.Numerics.Vector UnzipEven(System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } public static System.Numerics.Vector UnzipEven(System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } diff --git a/src/tests/Common/GenerateHWIntrinsicTests/GenerateHWIntrinsicTests_Arm.cs b/src/tests/Common/GenerateHWIntrinsicTests/GenerateHWIntrinsicTests_Arm.cs index db964d4793e1bb..9ef86027848352 100644 --- a/src/tests/Common/GenerateHWIntrinsicTests/GenerateHWIntrinsicTests_Arm.cs +++ b/src/tests/Common/GenerateHWIntrinsicTests/GenerateHWIntrinsicTests_Arm.cs @@ -2909,6 +2909,9 @@ ("SveVecBinOpTest.template", new Dictionary { ["TestName"] = "Sve_Add_uint", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "Add", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "Helpers.Add(left[i], right[i]) != result[i]", ["GetIterResult"] = "Helpers.Add(left[i], right[i])"}), ("SveVecBinOpTest.template", new Dictionary { ["TestName"] = "Sve_Add_ulong", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "Add", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt64", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "UInt64", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt64()", ["ValidateIterResult"] = "Helpers.Add(left[i], right[i]) != result[i]", ["GetIterResult"] = "Helpers.Add(left[i], right[i])"}), + ("SveVecBinOpTest.template", new Dictionary { ["TestName"] = "Sve_Divide_float", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "Divide", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "Helpers.Divide(left[i], right[i]) != result[i]", ["GetIterResult"] = "Helpers.Divide(left[i], right[i])"}), + ("SveVecBinOpTest.template", new Dictionary { ["TestName"] = "Sve_Divide_double", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "Divide", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "Double", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["ValidateIterResult"] = "Helpers.Divide(left[i], right[i]) != result[i]", ["GetIterResult"] = "Helpers.Divide(left[i], right[i])"}), + ("SveConditionalSelect.template", new Dictionary { ["TestName"] = "Sve_ConditionalSelect_float", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "ConditionalSelect", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "Single", ["Op3VectorType"] = "Vector", ["Op3BaseType"] = "Single", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp3"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "(firstOp[i] != 0 ? (result[i] != secondOp[i]) : (result[i] != thirdOp[i]))",}), ("SveConditionalSelect.template", new Dictionary { ["TestName"] = "Sve_ConditionalSelect_double", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "ConditionalSelect", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "Double", ["Op3VectorType"] = "Vector", ["Op3BaseType"] = "Double", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp3"] = "TestLibrary.Generator.GetDouble()", ["ValidateIterResult"] = "(firstOp[i] != 0 ? (result[i] != secondOp[i]) : (result[i] != thirdOp[i]))",}), ("SveConditionalSelect.template", new Dictionary { ["TestName"] = "Sve_ConditionalSelect_sbyte", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "ConditionalSelect", ["RetVectorType"] = "Vector", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "SByte", ["Op3VectorType"] = "Vector", ["Op3BaseType"] = "SByte", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp3"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "(firstOp[i] != 0 ? (result[i] != secondOp[i]) : (result[i] != thirdOp[i]))",}), @@ -2993,6 +2996,29 @@ ("SveLoadMaskedUnOpTest.template", new Dictionary { ["TestName"] = "SveLoadVectorUInt16ZeroExtendToUInt64", ["Isa"] = "Sve", ["Method"] = "LoadVectorUInt16ZeroExtendToUInt64", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt64", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "8", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), ("SveLoadMaskedUnOpTest.template", new Dictionary { ["TestName"] = "SveLoadVectorUInt32ZeroExtendToInt64", ["Isa"] = "Sve", ["Method"] = "LoadVectorUInt32ZeroExtendToInt64", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Int64", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "8", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), ("SveLoadMaskedUnOpTest.template", new Dictionary { ["TestName"] = "SveLoadVectorUInt32ZeroExtendToUInt64", ["Isa"] = "Sve", ["Method"] = "LoadVectorUInt32ZeroExtendToUInt64", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt64", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "8", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), + + ("SveVecBinOpTest.template", new Dictionary { ["TestName"] = "Sve_Multiply_float", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "Multiply", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "Helpers.Multiply(left[i], right[i]) != result[i]", ["GetIterResult"] = "Helpers.Multiply(left[i], right[i])"}), + ("SveVecBinOpTest.template", new Dictionary { ["TestName"] = "Sve_Multiply_double", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "Multiply", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "Double", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["ValidateIterResult"] = "Helpers.Multiply(left[i], right[i]) != result[i]", ["GetIterResult"] = "Helpers.Multiply(left[i], right[i])"}), + ("SveVecBinOpTest.template", new Dictionary { ["TestName"] = "Sve_Multiply_sbyte", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "Multiply", ["RetVectorType"] = "Vector", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "(sbyte)TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.Multiply(left[i], right[i]) != result[i]", ["GetIterResult"] = "Helpers.Multiply(left[i], right[i])"}), + ("SveVecBinOpTest.template", new Dictionary { ["TestName"] = "Sve_Multiply_short", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "Multiply", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "(short)TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.Multiply(left[i], right[i]) != result[i]", ["GetIterResult"] = "Helpers.Multiply(left[i], right[i])"}), + ("SveVecBinOpTest.template", new Dictionary { ["TestName"] = "Sve_Multiply_int", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "Multiply", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.Multiply(left[i], right[i]) != result[i]", ["GetIterResult"] = "Helpers.Multiply(left[i], right[i])"}), + ("SveVecBinOpTest.template", new Dictionary { ["TestName"] = "Sve_Multiply_long", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "Multiply", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Int64", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "Int64", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt64()", ["ValidateIterResult"] = "Helpers.Multiply(left[i], right[i]) != result[i]", ["GetIterResult"] = "Helpers.Multiply(left[i], right[i])"}), + ("SveVecBinOpTest.template", new Dictionary { ["TestName"] = "Sve_Multiply_byte", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "Multiply", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "(byte)TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "Helpers.Multiply(left[i], right[i]) != result[i]", ["GetIterResult"] = "Helpers.Multiply(left[i], right[i])"}), + ("SveVecBinOpTest.template", new Dictionary { ["TestName"] = "Sve_Multiply_ushort", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "Multiply", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "Helpers.Multiply(left[i], right[i]) != result[i]", ["GetIterResult"] = "Helpers.Multiply(left[i], right[i])"}), + ("SveVecBinOpTest.template", new Dictionary { ["TestName"] = "Sve_Multiply_uint", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "Multiply", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "Helpers.Multiply(left[i], right[i]) != result[i]", ["GetIterResult"] = "Helpers.Multiply(left[i], right[i])"}), + ("SveVecBinOpTest.template", new Dictionary { ["TestName"] = "Sve_Multiply_ulong", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "Multiply", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt64", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "UInt64", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt64()", ["ValidateIterResult"] = "Helpers.Multiply(left[i], right[i]) != result[i]", ["GetIterResult"] = "Helpers.Multiply(left[i], right[i])"}), + + ("SveVecBinOpTest.template", new Dictionary { ["TestName"] = "Sve_Subtract_float", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "Subtract", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "Helpers.Subtract(left[i], right[i]) != result[i]", ["GetIterResult"] = "Helpers.Subtract(left[i], right[i])"}), + ("SveVecBinOpTest.template", new Dictionary { ["TestName"] = "Sve_Subtract_double", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "Subtract", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "Double", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["ValidateIterResult"] = "Helpers.Subtract(left[i], right[i]) != result[i]", ["GetIterResult"] = "Helpers.Subtract(left[i], right[i])"}), + ("SveVecBinOpTest.template", new Dictionary { ["TestName"] = "Sve_Subtract_sbyte", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "Subtract", ["RetVectorType"] = "Vector", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "(sbyte)TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.Subtract(left[i], right[i]) != result[i]", ["GetIterResult"] = "Helpers.Subtract(left[i], right[i])"}), + ("SveVecBinOpTest.template", new Dictionary { ["TestName"] = "Sve_Subtract_short", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "Subtract", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "(short)TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.Subtract(left[i], right[i]) != result[i]", ["GetIterResult"] = "Helpers.Subtract(left[i], right[i])"}), + ("SveVecBinOpTest.template", new Dictionary { ["TestName"] = "Sve_Subtract_int", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "Subtract", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.Subtract(left[i], right[i]) != result[i]", ["GetIterResult"] = "Helpers.Subtract(left[i], right[i])"}), + ("SveVecBinOpTest.template", new Dictionary { ["TestName"] = "Sve_Subtract_long", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "Subtract", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Int64", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "Int64", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt64()", ["ValidateIterResult"] = "Helpers.Subtract(left[i], right[i]) != result[i]", ["GetIterResult"] = "Helpers.Subtract(left[i], right[i])"}), + ("SveVecBinOpTest.template", new Dictionary { ["TestName"] = "Sve_Subtract_byte", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "Subtract", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "(byte)TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "Helpers.Subtract(left[i], right[i]) != result[i]", ["GetIterResult"] = "Helpers.Subtract(left[i], right[i])"}), + ("SveVecBinOpTest.template", new Dictionary { ["TestName"] = "Sve_Subtract_ushort", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "Subtract", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "Helpers.Subtract(left[i], right[i]) != result[i]", ["GetIterResult"] = "Helpers.Subtract(left[i], right[i])"}), + ("SveVecBinOpTest.template", new Dictionary { ["TestName"] = "Sve_Subtract_uint", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "Subtract", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "Helpers.Subtract(left[i], right[i]) != result[i]", ["GetIterResult"] = "Helpers.Subtract(left[i], right[i])"}), + ("SveVecBinOpTest.template", new Dictionary { ["TestName"] = "Sve_Subtract_ulong", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "Subtract", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt64", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "UInt64", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt64()", ["ValidateIterResult"] = "Helpers.Subtract(left[i], right[i]) != result[i]", ["GetIterResult"] = "Helpers.Subtract(left[i], right[i])"}), + ("SveVecPairBinOpTest.template", new Dictionary { ["TestName"] = "SveUnzipEven_float", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "UnzipEven", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateEntry"] = "result[index] != left[i] || result[index + half] != right[i]"}), ("SveVecPairBinOpTest.template", new Dictionary { ["TestName"] = "SveUnzipEven_double", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "UnzipEven", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "Double", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["ValidateEntry"] = "result[index] != left[i] || result[index + half] != right[i]"}), ("SveVecPairBinOpTest.template", new Dictionary { ["TestName"] = "SveUnzipEven_sbyte", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "UnzipEven", ["RetVectorType"] = "Vector", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateEntry"] = "result[index] != left[i] || result[index + half] != right[i]"}), @@ -3013,6 +3039,7 @@ ("SveVecPairBinOpTest.template", new Dictionary { ["TestName"] = "SveUnzipOdd_ushort", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "UnzipOdd", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["ValidateEntry"] = "result[index] != left[i + 1] || result[index + half] != right[i + 1]"}), ("SveVecPairBinOpTest.template", new Dictionary { ["TestName"] = "SveUnzipOdd_uint", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "UnzipOdd", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["ValidateEntry"] = "result[index] != left[i + 1] || result[index + half] != right[i + 1]"}), ("SveVecPairBinOpTest.template", new Dictionary { ["TestName"] = "SveUnzipOdd_ulong", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "UnzipOdd", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt64", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "UInt64", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt64()", ["ValidateEntry"] = "result[index] != left[i + 1] || result[index + half] != right[i + 1]"}), + ("SveVecPairBinOpTest.template", new Dictionary { ["TestName"] = "SveZipHigh_float", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "ZipHigh", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateEntry"] = "result[i] != left[index + half] || result[i + 1] != right[index + half]"}), ("SveVecPairBinOpTest.template", new Dictionary { ["TestName"] = "SveZipHigh_double", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "ZipHigh", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "Double", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["ValidateEntry"] = "result[i] != left[index + half] || result[i + 1] != right[index + half]"}), ("SveVecPairBinOpTest.template", new Dictionary { ["TestName"] = "SveZipHigh_sbyte", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "ZipHigh", ["RetVectorType"] = "Vector", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateEntry"] = "result[i] != left[index + half] || result[i + 1] != right[index + half]"}), From 42f4c3096aa81da74aa27c63862611400639b8c4 Mon Sep 17 00:00:00 2001 From: Jakob Botsch Nielsen Date: Mon, 29 Apr 2024 20:22:21 +0200 Subject: [PATCH 139/161] JIT: Move internal reserved registers to a side table (#101647) This gets rid of `GenTree::gtRsvdRegs` by moving internal registers to a side table. We generally use internal registers very rarely, so making the lookup more costly seems worth the trade off (especially to make it easier to expand `regMaskTP` to 16 bytes). There was one exception where we used internal registers a lot, which was `GT_CALL` for R2R codegen on arm64/arm32. For those nodes we always allocate an internal register to load the target into (the target is obtained by loading the R2R indirection cell that is passed in an argument register). For arm64 it was simple to avoid this internal register: we can simply use LR always, since that register is going to be overwritten by the call anyway. This results in -2% TP for crossgen2 arm64 just from avoiding building this extra interval. This is also the cause of the asm diffs. For arm32 the same strategy doesn't work as well because loading into LR is a 4 byte instruction while loading into other registers is a 2 byte instruction. So for arm32 we still use an internal register and take the small throughput hit. This change reduces JIT memory usage by ~1.5%. The throughput cost (when discounting some spurious inlining decision changes) seems to be around 0.1%. --- src/coreclr/jit/codegenarm.cpp | 24 ++--- src/coreclr/jit/codegenarm64.cpp | 45 ++++---- src/coreclr/jit/codegenarmarch.cpp | 82 ++++++++------- src/coreclr/jit/codegencommon.cpp | 107 ++++++++++++++++++++ src/coreclr/jit/codegeninterface.h | 22 +++- src/coreclr/jit/codegenlinear.cpp | 2 +- src/coreclr/jit/codegenloongarch64.cpp | 38 +++---- src/coreclr/jit/codegenriscv64.cpp | 76 +++++++------- src/coreclr/jit/codegenxarch.cpp | 66 ++++++------ src/coreclr/jit/emitarm.cpp | 18 ++-- src/coreclr/jit/emitarm64.cpp | 8 +- src/coreclr/jit/emitloongarch64.cpp | 6 +- src/coreclr/jit/emitriscv64.cpp | 14 +-- src/coreclr/jit/emitxarch.cpp | 2 +- src/coreclr/jit/gentree.cpp | 76 ++------------ src/coreclr/jit/gentree.h | 6 -- src/coreclr/jit/hwintrinsiccodegenarm64.cpp | 6 +- src/coreclr/jit/hwintrinsiccodegenxarch.cpp | 44 ++++---- src/coreclr/jit/jithashtable.h | 50 +++++++-- src/coreclr/jit/lsra.cpp | 4 +- src/coreclr/jit/lsraarmarch.cpp | 20 ++-- src/coreclr/jit/lsrabuild.cpp | 4 - src/coreclr/jit/simdcodegenxarch.cpp | 6 +- 23 files changed, 416 insertions(+), 310 deletions(-) diff --git a/src/coreclr/jit/codegenarm.cpp b/src/coreclr/jit/codegenarm.cpp index 2c010f116a2657..dea8b19fbee94f 100644 --- a/src/coreclr/jit/codegenarm.cpp +++ b/src/coreclr/jit/codegenarm.cpp @@ -280,7 +280,7 @@ void CodeGen::genSetRegToConst(regNumber targetReg, var_types targetType, GenTre if (targetType == TYP_FLOAT) { // Get a temp integer register - regNumber tmpReg = tree->GetSingleTempReg(); + regNumber tmpReg = internalRegisters.GetSingle(tree); float f = forceCastToFloat(constValue); instGen_Set_Reg_To_Imm(EA_4BYTE, tmpReg, *((int*)(&f))); @@ -293,8 +293,8 @@ void CodeGen::genSetRegToConst(regNumber targetReg, var_types targetType, GenTre unsigned* cv = (unsigned*)&constValue; // Get two temp integer registers - regNumber tmpReg1 = tree->ExtractTempReg(); - regNumber tmpReg2 = tree->GetSingleTempReg(); + regNumber tmpReg1 = internalRegisters.Extract(tree); + regNumber tmpReg2 = internalRegisters.GetSingle(tree); instGen_Set_Reg_To_Imm(EA_4BYTE, tmpReg1, cv[0]); instGen_Set_Reg_To_Imm(EA_4BYTE, tmpReg2, cv[1]); @@ -431,9 +431,9 @@ void CodeGen::genLclHeap(GenTree* tree) } // Setup the regTmp, if there is one. - if (tree->AvailableTempRegCount() > 0) + if (internalRegisters.Count(tree) > 0) { - regTmp = tree->ExtractTempReg(); + regTmp = internalRegisters.Extract(tree); } // If we have an outgoing arg area then we must adjust the SP by popping off the @@ -833,7 +833,7 @@ void CodeGen::genCodeForCpObj(GenTreeBlk* cpObjNode) gcInfo.gcMarkRegPtrVal(REG_WRITE_BARRIER_DST_BYREF, dstAddr->TypeGet()); // Temp register used to perform the sequence of loads and stores. - regNumber tmpReg = cpObjNode->ExtractTempReg(); + regNumber tmpReg = internalRegisters.Extract(cpObjNode); assert(genIsValidIntReg(tmpReg)); if (cpObjNode->IsVolatile()) @@ -1026,18 +1026,18 @@ void CodeGen::genCodeForStoreLclFld(GenTreeLclFld* tree) { // Arm supports unaligned access only for integer types, // convert the storing floating data into 1 or 2 integer registers and write them as int. - regNumber addr = tree->ExtractTempReg(); + regNumber addr = internalRegisters.Extract(tree); emit->emitIns_R_S(INS_lea, EA_PTRSIZE, addr, varNum, offset); if (targetType == TYP_FLOAT) { - regNumber floatAsInt = tree->GetSingleTempReg(); + regNumber floatAsInt = internalRegisters.GetSingle(tree); emit->emitIns_Mov(INS_vmov_f2i, EA_4BYTE, floatAsInt, dataReg, /* canSkip */ false); emit->emitIns_R_R(INS_str, EA_4BYTE, floatAsInt, addr); } else { - regNumber halfdoubleAsInt1 = tree->ExtractTempReg(); - regNumber halfdoubleAsInt2 = tree->GetSingleTempReg(); + regNumber halfdoubleAsInt1 = internalRegisters.Extract(tree); + regNumber halfdoubleAsInt2 = internalRegisters.GetSingle(tree); emit->emitIns_R_R_R(INS_vmov_d2i, EA_8BYTE, halfdoubleAsInt1, halfdoubleAsInt2, dataReg); emit->emitIns_R_R_I(INS_str, EA_4BYTE, halfdoubleAsInt1, addr, 0); emit->emitIns_R_R_I(INS_str, EA_4BYTE, halfdoubleAsInt1, addr, 4); @@ -1209,7 +1209,7 @@ void CodeGen::genCkfinite(GenTree* treeNode) emitter* emit = GetEmitter(); var_types targetType = treeNode->TypeGet(); - regNumber intReg = treeNode->GetSingleTempReg(); + regNumber intReg = internalRegisters.GetSingle(treeNode); regNumber fpReg = genConsumeReg(treeNode->AsOp()->gtOp1); regNumber targetReg = treeNode->GetRegNum(); @@ -1592,7 +1592,7 @@ void CodeGen::genFloatToIntCast(GenTree* treeNode) genConsumeOperands(treeNode->AsOp()); - regNumber tmpReg = treeNode->GetSingleTempReg(); + regNumber tmpReg = internalRegisters.GetSingle(treeNode); assert(insVcvt != INS_invalid); GetEmitter()->emitIns_R_R(insVcvt, dstSize, tmpReg, op1->GetRegNum()); diff --git a/src/coreclr/jit/codegenarm64.cpp b/src/coreclr/jit/codegenarm64.cpp index 8695545cc934a3..dc79220dcd0b87 100644 --- a/src/coreclr/jit/codegenarm64.cpp +++ b/src/coreclr/jit/codegenarm64.cpp @@ -2372,7 +2372,7 @@ void CodeGen::genSetRegToConst(regNumber targetReg, var_types targetType, GenTre else { // Get a temp integer register to compute long address. - regNumber addrReg = tree->GetSingleTempReg(); + regNumber addrReg = internalRegisters.GetSingle(tree); // We must load the FP constant from the constant pool // Emit a data section constant for the float or double constant. @@ -2407,7 +2407,7 @@ void CodeGen::genSetRegToConst(regNumber targetReg, var_types targetType, GenTre else { // Get a temp integer register to compute long address. - regNumber addrReg = tree->GetSingleTempReg(); + regNumber addrReg = internalRegisters.GetSingle(tree); simd8_t constValue; memcpy(&constValue, &vecCon->gtSimdVal, sizeof(simd8_t)); @@ -2431,7 +2431,7 @@ void CodeGen::genSetRegToConst(regNumber targetReg, var_types targetType, GenTre else { // Get a temp integer register to compute long address. - regNumber addrReg = tree->GetSingleTempReg(); + regNumber addrReg = internalRegisters.GetSingle(tree); simd16_t constValue = {}; memcpy(&constValue, &vecCon->gtSimdVal, sizeof(simd12_t)); @@ -2455,7 +2455,7 @@ void CodeGen::genSetRegToConst(regNumber targetReg, var_types targetType, GenTre else { // Get a temp integer register to compute long address. - regNumber addrReg = tree->GetSingleTempReg(); + regNumber addrReg = internalRegisters.GetSingle(tree); simd16_t constValue; memcpy(&constValue, &vecCon->gtSimdVal, sizeof(simd16_t)); @@ -3132,12 +3132,12 @@ void CodeGen::genLclHeap(GenTree* tree) // since we don't need any internal registers. if (compiler->info.compInitMem) { - assert(tree->AvailableTempRegCount() == 0); + assert(internalRegisters.Count(tree) == 0); regCnt = targetReg; } else { - regCnt = tree->ExtractTempReg(); + regCnt = internalRegisters.Extract(tree); inst_Mov(size->TypeGet(), regCnt, targetReg, /* canSkip */ true); } @@ -3254,12 +3254,12 @@ void CodeGen::genLclHeap(GenTree* tree) assert(regCnt == REG_NA); if (compiler->info.compInitMem) { - assert(tree->AvailableTempRegCount() == 0); + assert(internalRegisters.Count(tree) == 0); regCnt = targetReg; } else { - regCnt = tree->ExtractTempReg(); + regCnt = internalRegisters.Extract(tree); } instGen_Set_Reg_To_Imm(((unsigned int)amount == amount) ? EA_4BYTE : EA_8BYTE, regCnt, amount); } @@ -3323,7 +3323,7 @@ void CodeGen::genLclHeap(GenTree* tree) // // Setup the regTmp - regNumber regTmp = tree->GetSingleTempReg(); + regNumber regTmp = internalRegisters.GetSingle(tree); BasicBlock* loop = genCreateTempLabel(); BasicBlock* done = genCreateTempLabel(); @@ -3668,7 +3668,7 @@ void CodeGen::genCodeForCpObj(GenTreeBlk* cpObjNode) unsigned slots = layout->GetSlotCount(); // Temp register(s) used to perform the sequence of loads and stores. - regNumber tmpReg = cpObjNode->ExtractTempReg(RBM_ALLINT); + regNumber tmpReg = internalRegisters.Extract(cpObjNode, RBM_ALLINT); regNumber tmpReg2 = REG_NA; assert(genIsValidIntReg(tmpReg)); @@ -3677,7 +3677,7 @@ void CodeGen::genCodeForCpObj(GenTreeBlk* cpObjNode) if (slots > 1) { - tmpReg2 = cpObjNode->ExtractTempReg(RBM_ALLINT); + tmpReg2 = internalRegisters.Extract(cpObjNode, RBM_ALLINT); assert(tmpReg2 != tmpReg); assert(genIsValidIntReg(tmpReg2)); assert(tmpReg2 != REG_WRITE_BARRIER_DST_BYREF); @@ -3730,8 +3730,8 @@ void CodeGen::genCodeForCpObj(GenTreeBlk* cpObjNode) regNumber tmpSimdReg2 = REG_NA; if ((slots >= 4) && compiler->IsBaselineSimdIsaSupported()) { - tmpSimdReg1 = cpObjNode->ExtractTempReg(RBM_ALLFLOAT); - tmpSimdReg2 = cpObjNode->ExtractTempReg(RBM_ALLFLOAT); + tmpSimdReg1 = internalRegisters.Extract(cpObjNode, RBM_ALLFLOAT); + tmpSimdReg2 = internalRegisters.Extract(cpObjNode, RBM_ALLFLOAT); } unsigned i = 0; @@ -3810,7 +3810,7 @@ void CodeGen::genTableBasedSwitch(GenTree* treeNode) regNumber idxReg = treeNode->AsOp()->gtOp1->GetRegNum(); regNumber baseReg = treeNode->AsOp()->gtOp2->GetRegNum(); - regNumber tmpReg = treeNode->GetSingleTempReg(); + regNumber tmpReg = internalRegisters.GetSingle(treeNode); // load the ip-relative offset (which is relative to start of fgFirstBB) GetEmitter()->emitIns_R_R_R(INS_ldr, EA_4BYTE, baseReg, baseReg, idxReg, INS_OPTS_LSL); @@ -3869,7 +3869,7 @@ void CodeGen::genLockedInstructions(GenTreeOp* treeNode) case GT_XAND: { // Grab a temp reg to perform `MVN` for dataReg first. - regNumber tempReg = treeNode->GetSingleTempReg(); + regNumber tempReg = internalRegisters.GetSingle(treeNode); GetEmitter()->emitIns_R_R(INS_mvn, dataSize, tempReg, dataReg); GetEmitter()->emitIns_R_R_R(INS_ldclral, dataSize, tempReg, (targetReg == REG_NA) ? REG_ZR : targetReg, addrReg); @@ -3902,9 +3902,10 @@ void CodeGen::genLockedInstructions(GenTreeOp* treeNode) // These are imported normally if Atomics aren't supported. assert(!treeNode->OperIs(GT_XORR, GT_XAND)); - regNumber exResultReg = treeNode->ExtractTempReg(RBM_ALLINT); - regNumber storeDataReg = (treeNode->OperGet() == GT_XCHG) ? dataReg : treeNode->ExtractTempReg(RBM_ALLINT); - regNumber loadReg = (targetReg != REG_NA) ? targetReg : storeDataReg; + regNumber exResultReg = internalRegisters.Extract(treeNode, RBM_ALLINT); + regNumber storeDataReg = + (treeNode->OperGet() == GT_XCHG) ? dataReg : internalRegisters.Extract(treeNode, RBM_ALLINT); + regNumber loadReg = (targetReg != REG_NA) ? targetReg : storeDataReg; // Check allocator assumptions // @@ -4055,7 +4056,7 @@ void CodeGen::genCodeForCmpXchg(GenTreeCmpXchg* treeNode) } else { - regNumber exResultReg = treeNode->ExtractTempReg(RBM_ALLINT); + regNumber exResultReg = internalRegisters.Extract(treeNode, RBM_ALLINT); // Check allocator assumptions // @@ -4600,7 +4601,7 @@ void CodeGen::genCkfinite(GenTree* treeNode) emitter* emit = GetEmitter(); // Extract exponent into a register. - regNumber intReg = treeNode->GetSingleTempReg(); + regNumber intReg = internalRegisters.GetSingle(treeNode); regNumber fpReg = genConsumeReg(op1); inst_Mov(targetType, intReg, fpReg, /* canSkip */ false, emitActualTypeSize(treeNode)); @@ -5351,7 +5352,7 @@ void CodeGen::genStoreIndTypeSimd12(GenTreeStoreInd* treeNode) regNumber dataReg = genConsumeReg(data); // Need an additional integer register to extract upper 4 bytes from data. - regNumber tmpReg = treeNode->GetSingleTempReg(); + regNumber tmpReg = internalRegisters.GetSingle(treeNode); // 8-byte write GetEmitter()->emitIns_R_R(INS_str, EA_8BYTE, dataReg, addrReg); @@ -5386,7 +5387,7 @@ void CodeGen::genLoadIndTypeSimd12(GenTreeIndir* treeNode) regNumber addrReg = genConsumeReg(addr); // Need an additional int register to read upper 4 bytes, which is different from targetReg - regNumber tmpReg = treeNode->GetSingleTempReg(); + regNumber tmpReg = internalRegisters.GetSingle(treeNode); // 8-byte read GetEmitter()->emitIns_R_R(INS_ldr, EA_8BYTE, tgtReg, addrReg); diff --git a/src/coreclr/jit/codegenarmarch.cpp b/src/coreclr/jit/codegenarmarch.cpp index d015332a76d8b7..90447292dbe837 100644 --- a/src/coreclr/jit/codegenarmarch.cpp +++ b/src/coreclr/jit/codegenarmarch.cpp @@ -910,9 +910,9 @@ void CodeGen::genPutArgStk(GenTreePutArgStk* treeNode) // in ARM64/ARM // Setup loReg (and hiReg) from the internal registers that we reserved in lower. // - regNumber loReg = treeNode->ExtractTempReg(); + regNumber loReg = internalRegisters.Extract(treeNode); #ifdef TARGET_ARM64 - regNumber hiReg = treeNode->GetSingleTempReg(); + regNumber hiReg = internalRegisters.GetSingle(treeNode); #endif // TARGET_ARM64 GenTreeLclVarCommon* srcLclNode = nullptr; @@ -1268,7 +1268,7 @@ void CodeGen::genPutArgSplit(GenTreePutArgSplit* treeNode) regNumber allocatedValueReg = REG_NA; if (treeNode->gtNumRegs == 1) { - allocatedValueReg = treeNode->ExtractTempReg(); + allocatedValueReg = internalRegisters.Extract(treeNode); } // Pick a register to store intermediate values in for the to-stack @@ -1640,19 +1640,19 @@ void CodeGen::genCodeForLclFld(GenTreeLclFld* tree) { // Arm supports unaligned access only for integer types, // load the floating data as 1 or 2 integer registers and convert them to float. - regNumber addr = tree->ExtractTempReg(); + regNumber addr = internalRegisters.Extract(tree); emit->emitIns_R_S(INS_lea, EA_PTRSIZE, addr, varNum, offs); if (targetType == TYP_FLOAT) { - regNumber floatAsInt = tree->GetSingleTempReg(); + regNumber floatAsInt = internalRegisters.GetSingle(tree); emit->emitIns_R_R(INS_ldr, EA_4BYTE, floatAsInt, addr); emit->emitIns_Mov(INS_vmov_i2f, EA_4BYTE, targetReg, floatAsInt, /* canSkip */ false); } else { - regNumber halfdoubleAsInt1 = tree->ExtractTempReg(); - regNumber halfdoubleAsInt2 = tree->GetSingleTempReg(); + regNumber halfdoubleAsInt1 = internalRegisters.Extract(tree); + regNumber halfdoubleAsInt2 = internalRegisters.GetSingle(tree); emit->emitIns_R_R_I(INS_ldr, EA_4BYTE, halfdoubleAsInt1, addr, 0); emit->emitIns_R_R_I(INS_ldr, EA_4BYTE, halfdoubleAsInt2, addr, 4); emit->emitIns_R_R_R(INS_vmov_i2d, EA_8BYTE, targetReg, halfdoubleAsInt1, halfdoubleAsInt2); @@ -1694,7 +1694,7 @@ void CodeGen::genCodeForIndexAddr(GenTreeIndexAddr* node) // The index is never contained, even if it is a constant. assert(index->isUsedFromReg()); - const regNumber tmpReg = node->ExtractTempReg(); + const regNumber tmpReg = internalRegisters.Extract(node); regNumber indexReg = index->GetRegNum(); @@ -1742,7 +1742,7 @@ void CodeGen::genCodeForIndexAddr(GenTreeIndexAddr* node) #ifdef TARGET_ARM64 if (!index->TypeIs(TYP_I_IMPL)) { - const regNumber tmpReg2 = node->ExtractTempReg(); + const regNumber tmpReg2 = internalRegisters.Extract(node); GetEmitter()->emitIns_Mov(INS_mov, EA_4BYTE, tmpReg2, indexReg, /* canSkip */ false); indexReg = tmpReg2; } @@ -2662,7 +2662,7 @@ void CodeGen::genCodeForInitBlkUnroll(GenTreeBlk* node) const int dstOffsetAdjustment = helper.GetDstOffset() - dstRegAddrAlignment; dstRegAddrAlignment = 0; - const regNumber tempReg = node->ExtractTempReg(RBM_ALLINT); + const regNumber tempReg = internalRegisters.Extract(node, RBM_ALLINT); genInstrWithConstant(INS_add, EA_PTRSIZE, tempReg, dstReg, dstOffsetAdjustment, tempReg); dstReg = tempReg; @@ -2684,7 +2684,7 @@ void CodeGen::genCodeForInitBlkUnroll(GenTreeBlk* node) if (shouldUse16ByteWideInstrs) { - const regNumber simdReg = node->GetSingleTempReg(RBM_ALLFLOAT); + const regNumber simdReg = internalRegisters.GetSingle(node, RBM_ALLFLOAT); const int initValue = (src->AsIntCon()->IconValue() & 0xFF); emit->emitIns_R_I(INS_movi, EA_16BYTE, simdReg, initValue, INS_OPTS_16B); @@ -2967,23 +2967,23 @@ void CodeGen::genCodeForCpBlkUnroll(GenTreeBlk* node) if ((srcOffsetAdjustment != 0) && (dstOffsetAdjustment != 0)) { - const regNumber tempReg1 = node->ExtractTempReg(RBM_ALLINT); + const regNumber tempReg1 = internalRegisters.Extract(node, RBM_ALLINT); genInstrWithConstant(INS_add, EA_PTRSIZE, tempReg1, srcReg, srcOffsetAdjustment, tempReg1); srcReg = tempReg1; - const regNumber tempReg2 = node->ExtractTempReg(RBM_ALLINT); + const regNumber tempReg2 = internalRegisters.Extract(node, RBM_ALLINT); genInstrWithConstant(INS_add, EA_PTRSIZE, tempReg2, dstReg, dstOffsetAdjustment, tempReg2); dstReg = tempReg2; } else if (srcOffsetAdjustment != 0) { - const regNumber tempReg = node->ExtractTempReg(RBM_ALLINT); + const regNumber tempReg = internalRegisters.Extract(node, RBM_ALLINT); genInstrWithConstant(INS_add, EA_PTRSIZE, tempReg, srcReg, srcOffsetAdjustment, tempReg); srcReg = tempReg; } else if (dstOffsetAdjustment != 0) { - const regNumber tempReg = node->ExtractTempReg(RBM_ALLINT); + const regNumber tempReg = internalRegisters.Extract(node, RBM_ALLINT); genInstrWithConstant(INS_add, EA_PTRSIZE, tempReg, dstReg, dstOffsetAdjustment, tempReg); dstReg = tempReg; } @@ -2991,16 +2991,16 @@ void CodeGen::genCodeForCpBlkUnroll(GenTreeBlk* node) regNumber intReg1 = REG_NA; regNumber intReg2 = REG_NA; - const unsigned intRegCount = node->AvailableTempRegCount(RBM_ALLINT); + const unsigned intRegCount = internalRegisters.Count(node, RBM_ALLINT); if (intRegCount >= 2) { - intReg1 = node->ExtractTempReg(RBM_ALLINT); - intReg2 = node->ExtractTempReg(RBM_ALLINT); + intReg1 = internalRegisters.Extract(node, RBM_ALLINT); + intReg2 = internalRegisters.Extract(node, RBM_ALLINT); } else if (intRegCount == 1) { - intReg1 = node->GetSingleTempReg(RBM_ALLINT); + intReg1 = internalRegisters.GetSingle(node, RBM_ALLINT); intReg2 = rsGetRsvdReg(); } else @@ -3010,8 +3010,8 @@ void CodeGen::genCodeForCpBlkUnroll(GenTreeBlk* node) if (shouldUse16ByteWideInstrs) { - const regNumber simdReg1 = node->ExtractTempReg(RBM_ALLFLOAT); - const regNumber simdReg2 = node->GetSingleTempReg(RBM_ALLFLOAT); + const regNumber simdReg1 = internalRegisters.Extract(node, RBM_ALLFLOAT); + const regNumber simdReg2 = internalRegisters.GetSingle(node, RBM_ALLFLOAT); helper.Unroll(FP_REGSIZE_BYTES, intReg1, simdReg1, simdReg2, srcReg, dstReg, GetEmitter()); } @@ -3022,7 +3022,7 @@ void CodeGen::genCodeForCpBlkUnroll(GenTreeBlk* node) #endif // TARGET_ARM64 #ifdef TARGET_ARM - const regNumber tempReg = node->ExtractTempReg(RBM_ALLINT); + const regNumber tempReg = internalRegisters.Extract(node, RBM_ALLINT); for (unsigned regSize = REGSIZE_BYTES; size > 0; size -= regSize, srcOffset += regSize, dstOffset += regSize) { @@ -3147,13 +3147,13 @@ void CodeGen::genCodeForMemmove(GenTreeBlk* tree) if (size >= simdSize) { // Number of SIMD regs needed to save the whole src to regs. - const unsigned numberOfSimdRegs = tree->AvailableTempRegCount(RBM_ALLFLOAT); + const unsigned numberOfSimdRegs = internalRegisters.Count(tree, RBM_ALLFLOAT); // Pop all temp regs to a local array, currently, this impl is limited with LSRA's MaxInternalCount regNumber tempRegs[LinearScan::MaxInternalCount] = {}; for (unsigned i = 0; i < numberOfSimdRegs; i++) { - tempRegs[i] = tree->ExtractTempReg(RBM_ALLFLOAT); + tempRegs[i] = internalRegisters.Extract(tree, RBM_ALLFLOAT); } auto emitSimdLoadStore = [&](bool load) { @@ -3190,15 +3190,15 @@ void CodeGen::genCodeForMemmove(GenTreeBlk* tree) const unsigned loadStoreSize = 1 << BitOperations::Log2(size); if (loadStoreSize == size) { - const regNumber tmpReg = tree->GetSingleTempReg(RBM_ALLINT); + const regNumber tmpReg = internalRegisters.GetSingle(tree, RBM_ALLINT); emitLoadStore(/* load */ true, loadStoreSize, tmpReg, 0); emitLoadStore(/* load */ false, loadStoreSize, tmpReg, 0); } else { - assert(tree->AvailableTempRegCount() == 2); - const regNumber tmpReg1 = tree->ExtractTempReg(RBM_ALLINT); - const regNumber tmpReg2 = tree->ExtractTempReg(RBM_ALLINT); + assert(internalRegisters.Count(tree) == 2); + const regNumber tmpReg1 = internalRegisters.Extract(tree, RBM_ALLINT); + const regNumber tmpReg2 = internalRegisters.Extract(tree, RBM_ALLINT); emitLoadStore(/* load */ true, loadStoreSize, tmpReg1, 0); emitLoadStore(/* load */ true, loadStoreSize, tmpReg2, size - loadStoreSize); emitLoadStore(/* load */ false, loadStoreSize, tmpReg1, 0); @@ -3258,7 +3258,7 @@ void CodeGen::genCodeForInitBlkLoop(GenTreeBlk* initBlkNode) // Extend liveness of dstReg in case if it gets killed by the store. gcInfo.gcMarkRegPtrVal(dstReg, dstNode->TypeGet()); - const regNumber offsetReg = initBlkNode->GetSingleTempReg(); + const regNumber offsetReg = internalRegisters.GetSingle(initBlkNode); instGen_Set_Reg_To_Imm(EA_PTRSIZE, offsetReg, size - TARGET_POINTER_SIZE); BasicBlock* loop = genCreateTempLabel(); @@ -3342,7 +3342,7 @@ void CodeGen::genCall(GenTreeCall* call) const regNumber regThis = genGetThisArgReg(call); #if defined(TARGET_ARM) - const regNumber tmpReg = call->ExtractTempReg(); + const regNumber tmpReg = internalRegisters.Extract(call); GetEmitter()->emitIns_R_R_I(INS_ldr, EA_4BYTE, tmpReg, regThis, 0); #elif defined(TARGET_ARM64) GetEmitter()->emitIns_R_R_I(INS_ldr, EA_4BYTE, REG_ZR, regThis, 0); @@ -3368,7 +3368,7 @@ void CodeGen::genCall(GenTreeCall* call) (call->IsVirtualStubRelativeIndir() && (call->gtEntryPoint.accessType == IAT_VALUE))); assert(call->gtControlExpr == nullptr); - regNumber tmpReg = call->GetSingleTempReg(); + regNumber tmpReg = internalRegisters.GetSingle(call); // Register where we save call address in should not be overridden by epilog. assert((genRegMask(tmpReg) & (RBM_INT_CALLEE_TRASH & ~RBM_LR)) == genRegMask(tmpReg)); @@ -3376,7 +3376,7 @@ void CodeGen::genCall(GenTreeCall* call) call->IsVirtualStubRelativeIndir() ? compiler->virtualStubParamInfo->GetReg() : REG_R2R_INDIRECT_PARAM; GetEmitter()->emitIns_R_R(ins_Load(TYP_I_IMPL), emitActualTypeSize(TYP_I_IMPL), tmpReg, callAddrReg); // We will use this again when emitting the jump in genCallInstruction in the epilog - call->gtRsvdRegs |= genRegMask(tmpReg); + internalRegisters.Add(call, genRegMask(tmpReg)); } #endif @@ -3666,15 +3666,25 @@ void CodeGen::genCallInstruction(GenTreeCall* call) if (callThroughIndirReg != REG_NA) { assert(call->IsR2ROrVirtualStubRelativeIndir()); - regNumber targetAddrReg = call->GetSingleTempReg(); + regNumber targetAddrReg; // For fast tailcalls we have already loaded the call target when processing the call node. if (!call->IsFastTailCall()) { +#ifdef TARGET_ARM + // For arm32 we've allocated an internal register to load the target into. + // Loading into lr takes 4 bytes (instead of potentially 2 with another register). + targetAddrReg = internalRegisters.GetSingle(call); +#else + // For arm64 we just use lr and skip the internal register. + targetAddrReg = REG_LR; +#endif + GetEmitter()->emitIns_R_R(ins_Load(TYP_I_IMPL), emitActualTypeSize(TYP_I_IMPL), targetAddrReg, callThroughIndirReg); } else { + targetAddrReg = internalRegisters.GetSingle(call); // Register where we save call address in should not be overridden by epilog. assert((genRegMask(targetAddrReg) & (RBM_INT_CALLEE_TRASH & ~RBM_LR)) == genRegMask(targetAddrReg)); } @@ -3731,7 +3741,7 @@ void CodeGen::genCallInstruction(GenTreeCall* call) #ifdef TARGET_ARM if (!validImmForBL((ssize_t)addr)) { - regNumber tmpReg = call->GetSingleTempReg(); + regNumber tmpReg = internalRegisters.GetSingle(call); instGen_Set_Reg_To_Imm(EA_HANDLE_CNS_RELOC, tmpReg, (ssize_t)addr); // clang-format off genEmitCall(emitter::EC_INDIR_R, @@ -4721,7 +4731,7 @@ void CodeGen::genLeaInstruction(GenTreeAddrMode* lea) if (offset != 0) { - regNumber tmpReg = lea->GetSingleTempReg(); + regNumber tmpReg = internalRegisters.GetSingle(lea); // When generating fully interruptible code we have to use the "large offset" sequence // when calculating a EA_BYREF as we can't report a byref that points outside of the object @@ -4803,7 +4813,7 @@ void CodeGen::genLeaInstruction(GenTreeAddrMode* lea) else { // We require a tmpReg to hold the offset - regNumber tmpReg = lea->GetSingleTempReg(); + regNumber tmpReg = internalRegisters.GetSingle(lea); // First load tmpReg with the large offset constant instGen_Set_Reg_To_Imm(EA_PTRSIZE, tmpReg, offset); diff --git a/src/coreclr/jit/codegencommon.cpp b/src/coreclr/jit/codegencommon.cpp index 301b10b1de0717..6ec296a1391bb5 100644 --- a/src/coreclr/jit/codegencommon.cpp +++ b/src/coreclr/jit/codegencommon.cpp @@ -62,10 +62,117 @@ CodeGenInterface* getCodeGenerator(Compiler* comp) return new (comp, CMK_Codegen) CodeGen(comp); } +NodeInternalRegisters::NodeInternalRegisters(Compiler* comp) + : m_table(comp->getAllocator(CMK_LSRA)) +{ +} + +//------------------------------------------------------------------------ +// Add: Add internal allocated registers for the specified node. +// +// Parameters: +// tree - IR node to add internal allocated registers to +// regs - Registers to add +// +void NodeInternalRegisters::Add(GenTree* tree, regMaskTP regs) +{ + assert(regs != RBM_NONE); + + regMaskTP* result = m_table.LookupPointerOrAdd(tree, RBM_NONE); + *result |= regs; +} + +//------------------------------------------------------------------------ +// Extract: Find the lowest number temporary register from the gtRsvdRegs set +// that is also in the optional given mask (typically, RBM_ALLINT or +// RBM_ALLFLOAT), and return it. Remove this register from the temporary +// register set, so it won't be returned again. +// +// Parameters: +// tree - IR node whose internal registers to extract +// mask - Mask of allowed registers that can be returned +// +// Returns: +// Register number. +// +regNumber NodeInternalRegisters::Extract(GenTree* tree, regMaskTP mask) +{ + regMaskTP* regs = m_table.LookupPointer(tree); + assert(regs != nullptr); + + regMaskTP availableSet = *regs & mask; + assert(availableSet != RBM_NONE); + + regNumber result = genFirstRegNumFromMask(availableSet); + *regs ^= genRegMask(result); + + return result; +} + +//------------------------------------------------------------------------ +// GetSingleTempReg: There is expected to be exactly one available temporary register +// in the given mask in the internal register set. Get that register. No future calls to get +// a temporary register are expected. Removes the register from the set, but only in +// DEBUG to avoid doing unnecessary work in non-DEBUG builds. +// +// Parameters: +// tree - IR node whose internal registers to extract +// mask - Mask of allowed registers that can be returned +// +// Returns: +// Register number. +// +regNumber NodeInternalRegisters::GetSingle(GenTree* tree, regMaskTP mask) +{ + regMaskTP* regs = m_table.LookupPointer(tree); + assert(regs != nullptr); + + regMaskTP availableSet = *regs & mask; + assert(genExactlyOneBit(availableSet)); + + regNumber result = genFirstRegNumFromMask(availableSet); + INDEBUG(*regs &= ~genRegMask(result)); + + return result; +} + +//------------------------------------------------------------------------ +// GetAll: Get all internal registers for the specified IR node. +// +// Parameters: +// tree - IR node whose internal registers to query +// +// Returns: +// Mask of registers. +// +regMaskTP NodeInternalRegisters::GetAll(GenTree* tree) +{ + regMaskTP regs; + return m_table.Lookup(tree, ®s) ? regs : RBM_NONE; +} + +//------------------------------------------------------------------------ +// Count: return the number of available temporary registers in the (optional) +// given set (typically, RBM_ALLINT or RBM_ALLFLOAT). +// +// Parameters: +// tree - IR node whose internal registers to query +// mask - Mask of registers to count +// +// Returns: +// Count of nodes +// +unsigned NodeInternalRegisters::Count(GenTree* tree, regMaskTP mask) +{ + regMaskTP regs; + return m_table.Lookup(tree, ®s) ? genCountBits(regs & mask) : 0; +} + // CodeGen constructor CodeGenInterface::CodeGenInterface(Compiler* theCompiler) : gcInfo(theCompiler) , regSet(theCompiler, gcInfo) + , internalRegisters(theCompiler) , compiler(theCompiler) , treeLifeUpdater(nullptr) { diff --git a/src/coreclr/jit/codegeninterface.h b/src/coreclr/jit/codegeninterface.h index ef87ccca858702..608c72c22d48d0 100644 --- a/src/coreclr/jit/codegeninterface.h +++ b/src/coreclr/jit/codegeninterface.h @@ -46,6 +46,21 @@ struct RegState CodeGenInterface* getCodeGenerator(Compiler* comp); +class NodeInternalRegisters +{ + typedef JitHashTable, regMaskTP> NodeInternalRegistersTable; + NodeInternalRegistersTable m_table; + +public: + NodeInternalRegisters(Compiler* comp); + + void Add(GenTree* tree, regMaskTP reg); + regNumber Extract(GenTree* tree, regMaskTP mask = static_cast(-1)); + regNumber GetSingle(GenTree* tree, regMaskTP mask = static_cast(-1)); + regMaskTP GetAll(GenTree* tree); + unsigned Count(GenTree* tree, regMaskTP mask = static_cast(-1)); +}; + class CodeGenInterface { friend class emitter; @@ -122,9 +137,10 @@ class CodeGenInterface GCInfo gcInfo; - RegSet regSet; - RegState intRegState; - RegState floatRegState; + RegSet regSet; + RegState intRegState; + RegState floatRegState; + NodeInternalRegisters internalRegisters; protected: Compiler* compiler; diff --git a/src/coreclr/jit/codegenlinear.cpp b/src/coreclr/jit/codegenlinear.cpp index d099fe192fc38a..786f40c2f4ca7d 100644 --- a/src/coreclr/jit/codegenlinear.cpp +++ b/src/coreclr/jit/codegenlinear.cpp @@ -1905,7 +1905,7 @@ void CodeGen::genSetBlockSize(GenTreeBlk* blkNode, regNumber sizeReg) { if (sizeReg != REG_NA) { - assert((blkNode->gtRsvdRegs & genRegMask(sizeReg)) != 0); + assert((internalRegisters.GetAll(blkNode) & genRegMask(sizeReg)) != 0); // This can go via helper which takes the size as a native uint. instGen_Set_Reg_To_Imm(EA_PTRSIZE, sizeReg, blkNode->Size()); } diff --git a/src/coreclr/jit/codegenloongarch64.cpp b/src/coreclr/jit/codegenloongarch64.cpp index 1bd29a432ce170..6fceb11807ed33 100644 --- a/src/coreclr/jit/codegenloongarch64.cpp +++ b/src/coreclr/jit/codegenloongarch64.cpp @@ -1513,7 +1513,7 @@ void CodeGen::genSetRegToConst(regNumber targetReg, var_types targetType, GenTre else { // Get a temp integer register to compute long address. - // regNumber addrReg = tree->GetSingleTempReg(); + // regNumber addrReg = internalRegisters.GetSingle(tree); // We must load the FP constant from the constant pool // Emit a data section constant for the float or double constant. @@ -1962,12 +1962,12 @@ void CodeGen::genLclHeap(GenTree* tree) // since we don't need any internal registers. if (compiler->info.compInitMem) { - assert(tree->AvailableTempRegCount() == 0); + assert(internalRegisters.Count(tree) == 0); regCnt = targetReg; } else { - regCnt = tree->ExtractTempReg(); + regCnt = internalRegisters.Extract(tree); if (regCnt != targetReg) { emit->emitIns_R_R_I(INS_ori, easz, regCnt, targetReg, 0); @@ -2064,12 +2064,12 @@ void CodeGen::genLclHeap(GenTree* tree) assert(regCnt == REG_NA); if (compiler->info.compInitMem) { - assert(tree->AvailableTempRegCount() == 0); + assert(internalRegisters.Count(tree) == 0); regCnt = targetReg; } else { - regCnt = tree->ExtractTempReg(); + regCnt = internalRegisters.Extract(tree); } instGen_Set_Reg_To_Imm(((unsigned int)amount == amount) ? EA_4BYTE : EA_8BYTE, regCnt, amount); } @@ -2134,7 +2134,7 @@ void CodeGen::genLclHeap(GenTree* tree) // // Setup the regTmp - regNumber regTmp = tree->GetSingleTempReg(); + regNumber regTmp = internalRegisters.GetSingle(tree); assert(regCnt != REG_R21); emit->emitIns_R_R_R(INS_sltu, EA_PTRSIZE, REG_R21, REG_SPBASE, regCnt); @@ -2585,7 +2585,7 @@ void CodeGen::genCodeForCpObj(GenTreeBlk* cpObjNode) unsigned slots = layout->GetSlotCount(); // Temp register(s) used to perform the sequence of loads and stores. - regNumber tmpReg = cpObjNode->ExtractTempReg(); + regNumber tmpReg = internalRegisters.Extract(cpObjNode); regNumber tmpReg2 = REG_NA; assert(genIsValidIntReg(tmpReg)); @@ -2594,7 +2594,7 @@ void CodeGen::genCodeForCpObj(GenTreeBlk* cpObjNode) if (slots > 1) { - tmpReg2 = cpObjNode->GetSingleTempReg(); + tmpReg2 = internalRegisters.GetSingle(cpObjNode); assert(tmpReg2 != tmpReg); assert(genIsValidIntReg(tmpReg2)); assert(tmpReg2 != REG_WRITE_BARRIER_DST_BYREF); @@ -2729,7 +2729,7 @@ void CodeGen::genTableBasedSwitch(GenTree* treeNode) regNumber idxReg = treeNode->AsOp()->gtOp1->GetRegNum(); regNumber baseReg = treeNode->AsOp()->gtOp2->GetRegNum(); - regNumber tmpReg = treeNode->GetSingleTempReg(); + regNumber tmpReg = internalRegisters.GetSingle(treeNode); // load the ip-relative offset (which is relative to start of fgFirstBB) GetEmitter()->emitIns_R_R_I(INS_slli_d, EA_8BYTE, REG_R21, idxReg, 2); @@ -3591,7 +3591,7 @@ void CodeGen::genCkfinite(GenTree* treeNode) emitAttr attr = emitActualTypeSize(treeNode); // Extract exponent into a register. - regNumber intReg = treeNode->GetSingleTempReg(); + regNumber intReg = internalRegisters.GetSingle(treeNode); regNumber fpReg = genConsumeReg(op1); emit->emitIns_R_R(attr == EA_8BYTE ? INS_movfr2gr_d : INS_movfr2gr_s, attr, intReg, fpReg); @@ -5101,7 +5101,7 @@ void CodeGen::genPutArgStk(GenTreePutArgStk* treeNode) // Setup loReg from the internal registers that we reserved in lower. // - regNumber loReg = treeNode->ExtractTempReg(); + regNumber loReg = internalRegisters.Extract(treeNode); regNumber addrReg = REG_NA; GenTreeLclVarCommon* varNode = nullptr; @@ -5382,7 +5382,7 @@ void CodeGen::genPutArgSplit(GenTreePutArgSplit* treeNode) assert(source->OperGet() == GT_BLK); assert(varTypeIsStruct(targetType)); - regNumber baseReg = treeNode->ExtractTempReg(); + regNumber baseReg = internalRegisters.Extract(treeNode); regNumber addrReg = REG_NA; GenTreeLclVarCommon* varNode = nullptr; @@ -6019,7 +6019,7 @@ void CodeGen::genCodeForCpBlkUnroll(GenTreeBlk* cpBlkNode) assert(srcOffset < INT32_MAX - static_cast(size)); assert(dstOffset < INT32_MAX - static_cast(size)); - regNumber tempReg = cpBlkNode->ExtractTempReg(RBM_ALLINT); + regNumber tempReg = internalRegisters.Extract(cpBlkNode, RBM_ALLINT); if (size >= 2 * REGSIZE_BYTES) { @@ -6148,7 +6148,7 @@ void CodeGen::genCodeForInitBlkLoop(GenTreeBlk* initBlkNode) // Extend liveness of dstReg in case if it gets killed by the store. gcInfo.gcMarkRegPtrVal(dstReg, dstNode->TypeGet()); - const regNumber offsetReg = initBlkNode->GetSingleTempReg(); + const regNumber offsetReg = internalRegisters.GetSingle(initBlkNode); instGen_Set_Reg_To_Imm(EA_PTRSIZE, offsetReg, size - TARGET_POINTER_SIZE); // loop begin: @@ -6247,7 +6247,7 @@ void CodeGen::genCall(GenTreeCall* call) (call->IsVirtualStubRelativeIndir() && (call->gtEntryPoint.accessType == IAT_VALUE))); assert(call->gtControlExpr == nullptr); - regNumber tmpReg = call->GetSingleTempReg(); + regNumber tmpReg = internalRegisters.GetSingle(call); // Register where we save call address in should not be overridden by epilog. assert((genRegMask(tmpReg) & (RBM_INT_CALLEE_TRASH & ~RBM_RA)) == genRegMask(tmpReg)); @@ -6255,7 +6255,7 @@ void CodeGen::genCall(GenTreeCall* call) call->IsVirtualStubRelativeIndir() ? compiler->virtualStubParamInfo->GetReg() : REG_R2R_INDIRECT_PARAM; GetEmitter()->emitIns_R_R_I(ins_Load(TYP_I_IMPL), emitActualTypeSize(TYP_I_IMPL), tmpReg, callAddrReg, 0); // We will use this again when emitting the jump in genCallInstruction in the epilog - call->gtRsvdRegs |= genRegMask(tmpReg); + internalRegisters.Add(call, genRegMask(tmpReg)); } #endif @@ -6473,7 +6473,7 @@ void CodeGen::genCallInstruction(GenTreeCall* call) if (callThroughIndirReg != REG_NA) { assert(call->IsR2ROrVirtualStubRelativeIndir()); - regNumber targetAddrReg = call->GetSingleTempReg(); + regNumber targetAddrReg = internalRegisters.GetSingle(call); // For fast tailcalls we have already loaded the call target when processing the call node. if (!call->IsFastTailCall()) { @@ -7131,7 +7131,7 @@ void CodeGen::genLeaInstruction(GenTreeAddrMode* lea) } else { - regNumber tmpReg = lea->GetSingleTempReg(); + regNumber tmpReg = internalRegisters.GetSingle(lea); noway_assert(tmpReg != index->GetRegNum()); noway_assert(tmpReg != memBase->GetRegNum()); @@ -7168,7 +7168,7 @@ void CodeGen::genLeaInstruction(GenTreeAddrMode* lea) else { // We require a tmpReg to hold the offset - regNumber tmpReg = lea->GetSingleTempReg(); + regNumber tmpReg = internalRegisters.GetSingle(lea); // First load tmpReg with the large offset constant emit->emitIns_I_la(EA_PTRSIZE, tmpReg, offset); diff --git a/src/coreclr/jit/codegenriscv64.cpp b/src/coreclr/jit/codegenriscv64.cpp index 0fa8bdb5874f40..84a2663dcbcce5 100644 --- a/src/coreclr/jit/codegenriscv64.cpp +++ b/src/coreclr/jit/codegenriscv64.cpp @@ -1536,7 +1536,7 @@ void CodeGen::genSetRegToConst(regNumber targetReg, var_types targetType, GenTre else { // Get a temp integer register to compute long address. - // regNumber addrReg = tree->GetSingleTempReg(); + // regNumber addrReg = internalRegisters.GetSingle(tree); // We must load the FP constant from the constant pool // Emit a data section constant for the float or double constant. @@ -1616,7 +1616,7 @@ void CodeGen::genCodeForMulHi(GenTreeOp* treeNode) assert(EA_SIZE(attr) == EA_4BYTE); if (isUnsigned) { - regNumber tempReg = treeNode->GetSingleTempReg(); + regNumber tempReg = internalRegisters.GetSingle(treeNode); emit->emitIns_R_R_I(INS_slli, EA_8BYTE, tempReg, op1->GetRegNum(), 32); emit->emitIns_R_R_I(INS_slli, EA_8BYTE, targetReg, op2->GetRegNum(), 32); emit->emitIns_R_R_R(INS_mulhu, EA_8BYTE, targetReg, tempReg, targetReg); @@ -1982,7 +1982,7 @@ void CodeGen::genLclHeap(GenTree* tree) } else { - regCnt = tree->ExtractTempReg(); + regCnt = internalRegisters.Extract(tree); if (regCnt != targetReg) { emit->emitIns_R_R_I(INS_ori, easz, regCnt, targetReg, 0); @@ -2012,7 +2012,7 @@ void CodeGen::genLclHeap(GenTree* tree) unsigned outgoingArgSpaceAligned = roundUp(compiler->lvaOutgoingArgSpaceSize, STACK_ALIGN); // assert((compiler->lvaOutgoingArgSpaceSize % STACK_ALIGN) == 0); // This must be true for the stack to remain // // aligned - tempReg = tree->ExtractTempReg(); + tempReg = internalRegisters.Extract(tree); genInstrWithConstant(INS_addi, EA_PTRSIZE, REG_SPBASE, REG_SPBASE, outgoingArgSpaceAligned, tempReg); stackAdjustment += outgoingArgSpaceAligned; } @@ -2067,7 +2067,7 @@ void CodeGen::genLclHeap(GenTree* tree) else { if (tempReg == REG_NA) - tempReg = tree->ExtractTempReg(); + tempReg = internalRegisters.Extract(tree); emit->emitLoadImmediate(EA_PTRSIZE, tempReg, amount); emit->emitIns_R_R_R(INS_sub, EA_PTRSIZE, REG_SPBASE, REG_SPBASE, tempReg); } @@ -2085,7 +2085,7 @@ void CodeGen::genLclHeap(GenTree* tree) } else { - regCnt = tree->ExtractTempReg(); + regCnt = internalRegisters.Extract(tree); } instGen_Set_Reg_To_Imm(((unsigned int)amount == amount) ? EA_4BYTE : EA_8BYTE, regCnt, amount); } @@ -2152,9 +2152,9 @@ void CodeGen::genLclHeap(GenTree* tree) // if (tempReg == REG_NA) - tempReg = tree->ExtractTempReg(); + tempReg = internalRegisters.Extract(tree); - regNumber rPageSize = tree->GetSingleTempReg(); + regNumber rPageSize = internalRegisters.GetSingle(tree); assert(regCnt != tempReg); emit->emitIns_R_R_R(INS_sltu, EA_PTRSIZE, tempReg, REG_SPBASE, regCnt); @@ -2359,7 +2359,7 @@ void CodeGen::genCodeForDivMod(GenTreeOp* tree) ssize_t intConst = (int)(divisorOp->AsIntCon()->gtIconVal); if (!emitter::isGeneralRegister(divisorReg)) { - tempReg = tree->GetSingleTempReg(); + tempReg = internalRegisters.GetSingle(tree); divisorReg = tempReg; } emit->emitLoadImmediate(EA_PTRSIZE, divisorReg, intConst); @@ -2382,7 +2382,7 @@ void CodeGen::genCodeForDivMod(GenTreeOp* tree) if ((exceptions & ExceptionSetFlags::ArithmeticException) != ExceptionSetFlags::None) { if (tempReg == REG_NA) - tempReg = tree->GetSingleTempReg(); + tempReg = internalRegisters.GetSingle(tree); // Check if the divisor is not -1 branch to 'sdivLabel' emit->emitIns_R_R_I(INS_addi, EA_PTRSIZE, tempReg, REG_ZERO, -1); @@ -2608,7 +2608,7 @@ void CodeGen::genCodeForCpObj(GenTreeBlk* cpObjNode) unsigned slots = layout->GetSlotCount(); // Temp register(s) used to perform the sequence of loads and stores. - regNumber tmpReg = cpObjNode->ExtractTempReg(); + regNumber tmpReg = internalRegisters.Extract(cpObjNode); regNumber tmpReg2 = REG_NA; assert(genIsValidIntReg(tmpReg)); @@ -2617,7 +2617,7 @@ void CodeGen::genCodeForCpObj(GenTreeBlk* cpObjNode) if (slots > 1) { - tmpReg2 = cpObjNode->GetSingleTempReg(); + tmpReg2 = internalRegisters.GetSingle(cpObjNode); assert(tmpReg2 != tmpReg); assert(genIsValidIntReg(tmpReg2)); assert(tmpReg2 != REG_WRITE_BARRIER_DST_BYREF); @@ -2752,7 +2752,7 @@ void CodeGen::genTableBasedSwitch(GenTree* treeNode) regNumber idxReg = treeNode->AsOp()->gtOp1->GetRegNum(); regNumber baseReg = treeNode->AsOp()->gtOp2->GetRegNum(); - regNumber tmpReg = treeNode->GetSingleTempReg(); + regNumber tmpReg = internalRegisters.GetSingle(treeNode); // load the ip-relative offset (which is relative to start of fgFirstBB) GetEmitter()->emitIns_R_R_I(INS_slli, EA_8BYTE, tmpReg, idxReg, 2); @@ -2852,7 +2852,7 @@ void CodeGen::genCodeForCmpXchg(GenTreeCmpXchg* treeNode) regNumber loc = locOp->GetRegNum(); regNumber val = valOp->GetRegNum(); regNumber comparand = comparandOp->GetRegNum(); - regNumber storeErr = treeNode->ExtractTempReg(RBM_ALLINT); + regNumber storeErr = internalRegisters.Extract(treeNode, RBM_ALLINT); // Register allocator should have extended the lifetimes of all input and internal registers // They should all be different @@ -3559,7 +3559,7 @@ void CodeGen::genFloatToIntCast(GenTree* treeNode) genConsumeOperands(treeNode->AsOp()); - regNumber tmpReg = treeNode->GetSingleTempReg(); + regNumber tmpReg = internalRegisters.GetSingle(treeNode); assert(tmpReg != treeNode->GetRegNum()); assert(tmpReg != op1->GetRegNum()); @@ -3606,7 +3606,7 @@ void CodeGen::genCkfinite(GenTree* treeNode) emitAttr attr = emitActualTypeSize(treeNode); // Extract exponent into a register. - regNumber intReg = treeNode->GetSingleTempReg(); + regNumber intReg = internalRegisters.GetSingle(treeNode); regNumber fpReg = genConsumeReg(op1); emit->emitIns_R_R(attr == EA_4BYTE ? INS_fclass_s : INS_fclass_d, attr, intReg, fpReg); @@ -3671,7 +3671,7 @@ void CodeGen::genCodeForCompare(GenTreeOp* tree) } else if (tree->OperIs(GT_EQ)) { - regNumber tempReg = tree->GetSingleTempReg(); + regNumber tempReg = internalRegisters.GetSingle(tree); skipLabel = genCreateTempLabel(); emit->emitIns_R_R(cmpSize == EA_4BYTE ? INS_fclass_s : INS_fclass_d, cmpSize, targetReg, regOp1); emit->emitIns_R_R(cmpSize == EA_4BYTE ? INS_fclass_s : INS_fclass_d, cmpSize, tempReg, regOp2); @@ -3716,7 +3716,7 @@ void CodeGen::genCodeForCompare(GenTreeOp* tree) } else if (tree->OperIs(GT_NE)) { - regNumber tempReg = tree->GetSingleTempReg(); + regNumber tempReg = internalRegisters.GetSingle(tree); emit->emitIns_R_R(cmpSize == EA_4BYTE ? INS_fclass_s : INS_fclass_d, cmpSize, targetReg, regOp1); emit->emitIns_R_R(cmpSize == EA_4BYTE ? INS_fclass_s : INS_fclass_d, cmpSize, tempReg, regOp2); emit->emitIns_R_R_R(INS_or, EA_8BYTE, tempReg, targetReg, tempReg); @@ -3755,7 +3755,7 @@ void CodeGen::genCodeForCompare(GenTreeOp* tree) { imm = static_cast(imm); - regNumber tmpRegOp1 = tree->GetSingleTempReg(); + regNumber tmpRegOp1 = internalRegisters.GetSingle(tree); assert(regOp1 != tmpRegOp1); emit->emitIns_R_R_I(INS_slli, EA_8BYTE, tmpRegOp1, regOp1, 32); @@ -3884,7 +3884,7 @@ void CodeGen::genCodeForCompare(GenTreeOp* tree) if (cmpSize == EA_4BYTE) { regNumber tmpRegOp1 = REG_RA; - regNumber tmpRegOp2 = tree->GetSingleTempReg(); + regNumber tmpRegOp2 = internalRegisters.GetSingle(tree); assert(regOp1 != tmpRegOp2); assert(regOp2 != tmpRegOp2); @@ -5280,7 +5280,7 @@ void CodeGen::genPutArgStk(GenTreePutArgStk* treeNode) // Setup loReg from the internal registers that we reserved in lower. // - regNumber loReg = treeNode->ExtractTempReg(); + regNumber loReg = internalRegisters.Extract(treeNode); GenTreeLclVarCommon* srcLclNode = nullptr; regNumber addrReg = REG_NA; @@ -5523,7 +5523,7 @@ void CodeGen::genPutArgSplit(GenTreePutArgSplit* treeNode) regNumber allocatedValueReg = REG_NA; if (treeNode->gtNumRegs == 1) { - allocatedValueReg = treeNode->ExtractTempReg(); + allocatedValueReg = internalRegisters.Extract(treeNode); } // Pick a register to store intermediate values in for the to-stack @@ -5670,13 +5670,13 @@ void CodeGen::genRangeCheck(GenTree* oper) if (genActualType(length) == TYP_INT) { - regNumber tempReg = oper->ExtractTempReg(); + regNumber tempReg = internalRegisters.Extract(oper); GetEmitter()->emitIns_R_R_I(INS_addiw, EA_4BYTE, tempReg, lengthReg, 0); // sign-extend lengthReg = tempReg; } if (genActualType(index) == TYP_INT) { - regNumber tempReg = oper->GetSingleTempReg(); + regNumber tempReg = internalRegisters.GetSingle(oper); GetEmitter()->emitIns_R_R_I(INS_addiw, EA_4BYTE, tempReg, indexReg, 0); // sign-extend indexReg = tempReg; } @@ -5759,7 +5759,7 @@ void CodeGen::genCodeForShift(GenTree* tree) if (tree->OperIs(GT_ROR, GT_ROL)) { - regNumber tempReg = tree->GetSingleTempReg(); + regNumber tempReg = internalRegisters.GetSingle(tree); unsigned immWidth = emitter::getBitWidth(size); // For RISCV64, immWidth will be set to 32 or 64 if (!shiftBy->IsCnsIntOrI()) { @@ -5949,7 +5949,7 @@ void CodeGen::genCodeForIndexAddr(GenTreeIndexAddr* node) // The index is never contained, even if it is a constant. assert(index->isUsedFromReg()); - regNumber tempReg = node->GetSingleTempReg(); + regNumber tempReg = internalRegisters.GetSingle(node); // Generate the bounds check if necessary. if (node->IsBoundsChecked()) @@ -6156,7 +6156,7 @@ void CodeGen::genCodeForCpBlkUnroll(GenTreeBlk* cpBlkNode) assert(srcOffset < INT32_MAX - static_cast(size)); assert(dstOffset < INT32_MAX - static_cast(size)); - regNumber tempReg = cpBlkNode->ExtractTempReg(RBM_ALLINT); + regNumber tempReg = internalRegisters.Extract(cpBlkNode, RBM_ALLINT); if (size >= 2 * REGSIZE_BYTES) { @@ -6285,7 +6285,7 @@ void CodeGen::genCodeForInitBlkLoop(GenTreeBlk* initBlkNode) // Extend liveness of dstReg in case if it gets killed by the store. gcInfo.gcMarkRegPtrVal(dstReg, dstNode->TypeGet()); - const regNumber tempReg = initBlkNode->GetSingleTempReg(); + const regNumber tempReg = internalRegisters.GetSingle(initBlkNode); instGen_Set_Reg_To_Imm(EA_PTRSIZE, tempReg, size - TARGET_POINTER_SIZE); // tempReg = dstReg + tempReg (a new interior pointer, but in a nongc region) @@ -6391,7 +6391,7 @@ void CodeGen::genCall(GenTreeCall* call) (call->IsVirtualStubRelativeIndir() && (call->gtEntryPoint.accessType == IAT_VALUE))); assert(call->gtControlExpr == nullptr); - regNumber tmpReg = call->GetSingleTempReg(); + regNumber tmpReg = internalRegisters.GetSingle(call); // Register where we save call address in should not be overridden by epilog. assert((genRegMask(tmpReg) & (RBM_INT_CALLEE_TRASH & ~RBM_RA)) == genRegMask(tmpReg)); @@ -6399,7 +6399,7 @@ void CodeGen::genCall(GenTreeCall* call) call->IsVirtualStubRelativeIndir() ? compiler->virtualStubParamInfo->GetReg() : REG_R2R_INDIRECT_PARAM; GetEmitter()->emitIns_R_R_I(ins_Load(TYP_I_IMPL), emitActualTypeSize(TYP_I_IMPL), tmpReg, callAddrReg, 0); // We will use this again when emitting the jump in genCallInstruction in the epilog - call->gtRsvdRegs |= genRegMask(tmpReg); + internalRegisters.Add(call, genRegMask(tmpReg)); } #endif @@ -6617,7 +6617,7 @@ void CodeGen::genCallInstruction(GenTreeCall* call) if (callThroughIndirReg != REG_NA) { assert(call->IsR2ROrVirtualStubRelativeIndir()); - regNumber targetAddrReg = call->GetSingleTempReg(); + regNumber targetAddrReg = internalRegisters.GetSingle(call); // For fast tailcalls we have already loaded the call target when processing the call node. if (!call->IsFastTailCall()) { @@ -6885,7 +6885,7 @@ void CodeGen::genIntCastOverflowCheck(GenTreeCast* cast, const GenIntCastDesc& d case GenIntCastDesc::CHECK_UINT_RANGE: { - regNumber tempReg = cast->GetSingleTempReg(); + regNumber tempReg = internalRegisters.GetSingle(cast); // We need to check if the value is not greater than 0xFFFFFFFF // if the upper 32 bits are zero. ssize_t imm = -1; @@ -6899,7 +6899,7 @@ void CodeGen::genIntCastOverflowCheck(GenTreeCast* cast, const GenIntCastDesc& d case GenIntCastDesc::CHECK_POSITIVE_INT_RANGE: { - regNumber tempReg = cast->GetSingleTempReg(); + regNumber tempReg = internalRegisters.GetSingle(cast); // We need to check if the value is not greater than 0x7FFFFFFF // if the upper 33 bits are zero. // instGen_Set_Reg_To_Imm(EA_8BYTE, tempReg, 0xFFFFFFFF80000000LL); @@ -6915,7 +6915,7 @@ void CodeGen::genIntCastOverflowCheck(GenTreeCast* cast, const GenIntCastDesc& d case GenIntCastDesc::CHECK_INT_RANGE: { - const regNumber tempReg = cast->GetSingleTempReg(); + const regNumber tempReg = internalRegisters.GetSingle(cast); assert(tempReg != reg); GetEmitter()->emitLoadImmediate(EA_8BYTE, tempReg, INT32_MAX); genJumpToThrowHlpBlk_la(SCK_OVERFLOW, INS_blt, tempReg, nullptr, reg); @@ -6930,7 +6930,7 @@ void CodeGen::genIntCastOverflowCheck(GenTreeCast* cast, const GenIntCastDesc& d assert(desc.CheckKind() == GenIntCastDesc::CHECK_SMALL_INT_RANGE); const int castMaxValue = desc.CheckSmallIntMax(); const int castMinValue = desc.CheckSmallIntMin(); - const regNumber tempReg = cast->GetSingleTempReg(); + const regNumber tempReg = internalRegisters.GetSingle(cast); instruction ins; if (castMaxValue > 2047) @@ -7229,7 +7229,7 @@ void CodeGen::genLeaInstruction(GenTreeAddrMode* lea) assert(isPow2(lea->gtScale)); BitScanForward(&scale, lea->gtScale); assert(scale <= 4); - regNumber scaleTempReg = scale ? lea->ExtractTempReg() : REG_NA; + regNumber scaleTempReg = scale ? internalRegisters.Extract(lea) : REG_NA; if (offset == 0) { @@ -7250,7 +7250,7 @@ void CodeGen::genLeaInstruction(GenTreeAddrMode* lea) } else { - regNumber tmpReg = lea->GetSingleTempReg(); + regNumber tmpReg = internalRegisters.GetSingle(lea); noway_assert(tmpReg != index->GetRegNum()); noway_assert(tmpReg != memBase->GetRegNum()); @@ -7287,7 +7287,7 @@ void CodeGen::genLeaInstruction(GenTreeAddrMode* lea) else { // We require a tmpReg to hold the offset - regNumber tmpReg = lea->GetSingleTempReg(); + regNumber tmpReg = internalRegisters.GetSingle(lea); // First load tmpReg with the large offset constant emit->emitLoadImmediate(EA_PTRSIZE, tmpReg, offset); diff --git a/src/coreclr/jit/codegenxarch.cpp b/src/coreclr/jit/codegenxarch.cpp index 4901ee9e3aa086..a2a17e735c9038 100644 --- a/src/coreclr/jit/codegenxarch.cpp +++ b/src/coreclr/jit/codegenxarch.cpp @@ -914,7 +914,7 @@ void CodeGen::genCodeForLongUMod(GenTreeOp* node) // xor edx, edx // div divisor->GetRegNum() // mov eax, temp - const regNumber tempReg = node->GetSingleTempReg(); + const regNumber tempReg = internalRegisters.GetSingle(node); inst_Mov(TYP_INT, tempReg, REG_EAX, /* canSkip */ false); inst_Mov(TYP_INT, REG_EAX, REG_EDX, /* canSkip */ false); instGen_Set_Reg_To_Zero(EA_PTRSIZE, REG_EDX); @@ -1761,7 +1761,7 @@ void CodeGen::genCodeForReturnTrap(GenTreeOp* tree) inst_JMP(EJ_je, skipLabel); // emit the call to the EE-helper that stops for GC (or other reasons) - regNumber tmpReg = tree->GetSingleTempReg(RBM_ALLINT); + regNumber tmpReg = internalRegisters.GetSingle(tree, RBM_ALLINT); assert(genIsValidIntReg(tmpReg)); genEmitHelperCall(CORINFO_HELP_STOP_FOR_GC, 0, EA_UNKNOWN, tmpReg); @@ -2334,7 +2334,7 @@ void CodeGen::genMultiRegStoreToSIMDLocal(GenTreeLclVar* lclNode) } else { - regNumber tempXmm = lclNode->GetSingleTempReg(); + regNumber tempXmm = internalRegisters.GetSingle(lclNode); assert(tempXmm != targetReg); inst_Mov(TYP_FLOAT, tempXmm, reg1, /* canSkip */ false); GetEmitter()->emitIns_SIMD_R_R_R(INS_punpckldq, size, targetReg, targetReg, tempXmm); @@ -2675,7 +2675,7 @@ void CodeGen::genCodeForMemmove(GenTreeBlk* tree) if ((size >= simdSize) && (simdSize > 0)) { // Number of SIMD regs needed to save the whole src to regs. - unsigned numberOfSimdRegs = tree->AvailableTempRegCount(RBM_ALLFLOAT); + unsigned numberOfSimdRegs = internalRegisters.Count(tree, RBM_ALLFLOAT); // Lowering takes care to only introduce this node such that we will always have enough // temporary SIMD registers to fully load the source and avoid any potential issues with overlap. @@ -2685,7 +2685,7 @@ void CodeGen::genCodeForMemmove(GenTreeBlk* tree) regNumber tempRegs[LinearScan::MaxInternalCount] = {}; for (unsigned i = 0; i < numberOfSimdRegs; i++) { - tempRegs[i] = tree->ExtractTempReg(RBM_ALLFLOAT); + tempRegs[i] = internalRegisters.Extract(tree, RBM_ALLFLOAT); } auto emitSimdLoadStore = [&](bool load) { @@ -2770,15 +2770,15 @@ void CodeGen::genCodeForMemmove(GenTreeBlk* tree) unsigned loadStoreSize = 1 << BitOperations::Log2(size); if (loadStoreSize == size) { - regNumber tmpReg = tree->GetSingleTempReg(RBM_ALLINT); + regNumber tmpReg = internalRegisters.GetSingle(tree, RBM_ALLINT); emitScalarLoadStore(/* load */ true, loadStoreSize, tmpReg, 0); emitScalarLoadStore(/* load */ false, loadStoreSize, tmpReg, 0); } else { - assert(tree->AvailableTempRegCount() == 2); - regNumber tmpReg1 = tree->ExtractTempReg(RBM_ALLINT); - regNumber tmpReg2 = tree->ExtractTempReg(RBM_ALLINT); + assert(internalRegisters.Count(tree) == 2); + regNumber tmpReg1 = internalRegisters.Extract(tree, RBM_ALLINT); + regNumber tmpReg2 = internalRegisters.Extract(tree, RBM_ALLINT); emitScalarLoadStore(/* load */ true, loadStoreSize, tmpReg1, 0); emitScalarLoadStore(/* load */ true, loadStoreSize, tmpReg2, size - loadStoreSize); emitScalarLoadStore(/* load */ false, loadStoreSize, tmpReg1, 0); @@ -2855,12 +2855,12 @@ void CodeGen::genLclHeap(GenTree* tree) // since we don't need any internal registers. if (compiler->info.compInitMem) { - assert(tree->AvailableTempRegCount() == 0); + assert(internalRegisters.Count(tree) == 0); regCnt = targetReg; } else { - regCnt = tree->GetSingleTempReg(); + regCnt = internalRegisters.GetSingle(tree); // Above, we put the size in targetReg. Now, copy it to our new temp register if necessary. inst_Mov(size->TypeGet(), regCnt, targetReg, /* canSkip */ true); @@ -2954,7 +2954,7 @@ void CodeGen::genLclHeap(GenTree* tree) // via BLK explicitly, so just bump the stack pointer. if ((amount >= compiler->eeGetPageSize()) || (TARGET_POINTER_SIZE == 4)) { - regCnt = tree->GetSingleTempReg(); + regCnt = internalRegisters.GetSingle(tree); instGen_Set_Reg_To_Imm(EA_PTRSIZE, regCnt, -(ssize_t)amount); genStackPointerDynamicAdjustmentWithProbe(regCnt); // lastTouchDelta is dynamic, and can be up to a page. So if we have outgoing arg space, @@ -2971,7 +2971,7 @@ void CodeGen::genLclHeap(GenTree* tree) } // We should not have any temp registers at this point. - assert(tree->AvailableTempRegCount() == 0); + assert(internalRegisters.Count(tree) == 0); if (compiler->info.compInitMem) { @@ -3234,7 +3234,7 @@ void CodeGen::genCodeForInitBlkUnroll(GenTreeBlk* node) #ifdef FEATURE_SIMD if (willUseSimdMov) { - regNumber srcXmmReg = node->GetSingleTempReg(RBM_ALLFLOAT); + regNumber srcXmmReg = internalRegisters.GetSingle(node, RBM_ALLFLOAT); unsigned regSize = compiler->roundDownSIMDSize(size); var_types loadType = compiler->getSIMDTypeForSize(regSize); simd_t vecCon; @@ -3392,7 +3392,7 @@ void CodeGen::genCodeForInitBlkLoop(GenTreeBlk* initBlkNode) // Extend liveness of dstReg in case if it gets killed by the store. gcInfo.gcMarkRegPtrVal(dstReg, dstNode->TypeGet()); - const regNumber offsetReg = initBlkNode->GetSingleTempReg(); + const regNumber offsetReg = internalRegisters.GetSingle(initBlkNode); instGen_Set_Reg_To_Imm(EA_PTRSIZE, offsetReg, size - TARGET_POINTER_SIZE); BasicBlock* loop = genCreateTempLabel(); @@ -3531,7 +3531,7 @@ void CodeGen::genCodeForCpBlkUnroll(GenTreeBlk* node) if ((size >= regSize) && (regSize > 0)) { - regNumber tempReg = node->GetSingleTempReg(RBM_ALLFLOAT); + regNumber tempReg = internalRegisters.GetSingle(node, RBM_ALLFLOAT); instruction simdMov = simdUnalignedMovIns(); @@ -3593,7 +3593,7 @@ void CodeGen::genCodeForCpBlkUnroll(GenTreeBlk* node) // Fill the remainder with normal loads/stores if (size > 0) { - regNumber tempReg = node->GetSingleTempReg(RBM_ALLINT); + regNumber tempReg = internalRegisters.GetSingle(node, RBM_ALLINT); #ifdef TARGET_AMD64 unsigned regSize = REGSIZE_BYTES; @@ -3878,11 +3878,11 @@ void CodeGen::genStructPutArgUnroll(GenTreePutArgStk* putArgNode) if (loadSize >= XMM_REGSIZE_BYTES) #endif { - xmmTmpReg = putArgNode->GetSingleTempReg(RBM_ALLFLOAT); + xmmTmpReg = internalRegisters.GetSingle(putArgNode, RBM_ALLFLOAT); } if ((loadSize % XMM_REGSIZE_BYTES) != 0) { - intTmpReg = putArgNode->GetSingleTempReg(RBM_ALLINT); + intTmpReg = internalRegisters.GetSingle(putArgNode, RBM_ALLINT); } #ifdef TARGET_X86 @@ -3934,7 +3934,7 @@ void CodeGen::genStructPutArgRepMovs(GenTreePutArgStk* putArgNode) // Make sure we got the arguments of the cpblk operation in the right registers, and that // 'src' is contained as expected. - assert(putArgNode->gtRsvdRegs == (RBM_RDI | RBM_RCX | RBM_RSI)); + assert(internalRegisters.GetAll(putArgNode) == (RBM_RDI | RBM_RCX | RBM_RSI)); assert(src->isContained()); genConsumePutStructArgStk(putArgNode, REG_RDI, REG_RSI, REG_RCX); @@ -4219,7 +4219,7 @@ void CodeGen::genCodeForCpObj(GenTreeBlk* cpObjNode) { // If the destination of the CpObj is on the stack, make sure we allocated // RCX to emit the movsp (alias for movsd or movsq for 32 and 64 bits respectively). - assert((cpObjNode->gtRsvdRegs & RBM_RCX) != 0); + assert((internalRegisters.GetAll(cpObjNode) & RBM_RCX) != 0); GetEmitter()->emitIns_R_I(INS_mov, EA_4BYTE, REG_RCX, slots); instGen(INS_r_movsp); @@ -4269,7 +4269,7 @@ void CodeGen::genCodeForCpObj(GenTreeBlk* cpObjNode) { // Otherwise, we can save code-size and improve CQ by emitting // rep movsp (alias for movsd/movsq for x86/x64) - assert((cpObjNode->gtRsvdRegs & RBM_RCX) != 0); + assert((internalRegisters.GetAll(cpObjNode) & RBM_RCX) != 0); GetEmitter()->emitIns_R_I(INS_mov, EA_4BYTE, REG_RCX, nonGcSlotCount); instGen(INS_r_movsp); @@ -4300,7 +4300,7 @@ void CodeGen::genTableBasedSwitch(GenTree* treeNode) regNumber idxReg = treeNode->AsOp()->gtOp1->GetRegNum(); regNumber baseReg = treeNode->AsOp()->gtOp2->GetRegNum(); - regNumber tmpReg = treeNode->GetSingleTempReg(); + regNumber tmpReg = internalRegisters.GetSingle(treeNode); // load the ip-relative offset (which is relative to start of fgFirstBB) GetEmitter()->emitIns_R_ARX(INS_mov, EA_4BYTE, baseReg, baseReg, idxReg, 4, 0); @@ -4427,7 +4427,7 @@ void CodeGen::genLockedInstructions(GenTreeOp* node) // Extend liveness of addr gcInfo.gcMarkRegPtrVal(addr->GetRegNum(), addr->TypeGet()); - const regNumber tmpReg = node->GetSingleTempReg(); + const regNumber tmpReg = internalRegisters.GetSingle(node); GetEmitter()->emitIns_R_AR(INS_mov, size, REG_RAX, addr->GetRegNum(), 0); BasicBlock* loop = genCreateTempLabel(); genDefineTempLabel(loop); @@ -5306,7 +5306,7 @@ void CodeGen::genCodeForIndexAddr(GenTreeIndexAddr* node) regNumber tmpReg = REG_NA; #ifdef TARGET_64BIT - tmpReg = node->GetSingleTempReg(); + tmpReg = internalRegisters.GetSingle(node); #endif // Generate the bounds check if necessary. @@ -5356,7 +5356,7 @@ void CodeGen::genCodeForIndexAddr(GenTreeIndexAddr* node) // The VM doesn't allow such large array elements but let's be sure. noway_assert(scale <= INT32_MAX); #else // !TARGET_64BIT - tmpReg = node->GetSingleTempReg(); + tmpReg = internalRegisters.GetSingle(node); #endif // !TARGET_64BIT GetEmitter()->emitIns_R_I(emitter::inst3opImulForReg(tmpReg), EA_PTRSIZE, indexReg, @@ -7239,7 +7239,7 @@ void CodeGen::genIntCastOverflowCheck(GenTreeCast* cast, const GenIntCastDesc& d // We need to check if the value is not greater than 0xFFFFFFFF but this value // cannot be encoded in an immediate operand. Use a right shift to test if the // upper 32 bits are zero. This requires a temporary register. - const regNumber tempReg = cast->GetSingleTempReg(); + const regNumber tempReg = internalRegisters.GetSingle(cast); assert(tempReg != reg); GetEmitter()->emitIns_Mov(INS_mov, EA_8BYTE, tempReg, reg, /* canSkip */ false); GetEmitter()->emitIns_R_I(INS_shr_N, EA_8BYTE, tempReg, 32); @@ -7255,7 +7255,7 @@ void CodeGen::genIntCastOverflowCheck(GenTreeCast* cast, const GenIntCastDesc& d case GenIntCastDesc::CHECK_INT_RANGE: { // Emit "if ((long)(int)x != x) goto OVERFLOW" - const regNumber regTmp = cast->GetSingleTempReg(); + const regNumber regTmp = internalRegisters.GetSingle(cast); GetEmitter()->emitIns_Mov(INS_movsxd, EA_8BYTE, regTmp, reg, true); GetEmitter()->emitIns_R_R(INS_cmp, EA_8BYTE, reg, regTmp); genJumpToThrowHlpBlk(EJ_jne, SCK_OVERFLOW); @@ -7666,7 +7666,7 @@ void CodeGen::genCkfinite(GenTree* treeNode) regNumber targetReg = treeNode->GetRegNum(); // Extract exponent into a register. - regNumber tmpReg = treeNode->GetSingleTempReg(); + regNumber tmpReg = internalRegisters.GetSingle(treeNode); genConsumeReg(op1); @@ -8357,17 +8357,17 @@ void CodeGen::genPutArgStkFieldList(GenTreePutArgStk* putArgStk) unsigned prevFieldOffset = currentOffset; regNumber intTmpReg = REG_NA; regNumber simdTmpReg = REG_NA; - if (putArgStk->AvailableTempRegCount() != 0) + if (internalRegisters.Count(putArgStk) != 0) { - regMaskTP rsvdRegs = putArgStk->gtRsvdRegs; + regMaskTP rsvdRegs = internalRegisters.GetAll(putArgStk); if ((rsvdRegs & RBM_ALLINT) != 0) { - intTmpReg = putArgStk->GetSingleTempReg(RBM_ALLINT); + intTmpReg = internalRegisters.GetSingle(putArgStk, RBM_ALLINT); assert(genIsValidIntReg(intTmpReg)); } if ((rsvdRegs & RBM_ALLFLOAT) != 0) { - simdTmpReg = putArgStk->GetSingleTempReg(RBM_ALLFLOAT); + simdTmpReg = internalRegisters.GetSingle(putArgStk, RBM_ALLFLOAT); assert(genIsValidFloatReg(simdTmpReg)); } assert(genCountBits(rsvdRegs) == (unsigned)((intTmpReg == REG_NA) ? 0 : 1) + ((simdTmpReg == REG_NA) ? 0 : 1)); diff --git a/src/coreclr/jit/emitarm.cpp b/src/coreclr/jit/emitarm.cpp index 81331547b4a924..65a6e098b2976a 100644 --- a/src/coreclr/jit/emitarm.cpp +++ b/src/coreclr/jit/emitarm.cpp @@ -7869,15 +7869,15 @@ void emitter::emitInsLoadStoreOp(instruction ins, emitAttr attr, regNumber dataR var_types type = indir->AsStoreInd()->Data()->TypeGet(); if (type == TYP_FLOAT) { - regNumber tmpReg = indir->GetSingleTempReg(); + regNumber tmpReg = codeGen->internalRegisters.GetSingle(indir); emitIns_Mov(INS_vmov_f2i, EA_4BYTE, tmpReg, dataReg, /* canSkip */ false); emitInsLoadStoreOp(INS_str, EA_4BYTE, tmpReg, indir, 0); return; } else if (type == TYP_DOUBLE) { - regNumber tmpReg1 = indir->ExtractTempReg(); - regNumber tmpReg2 = indir->GetSingleTempReg(); + regNumber tmpReg1 = codeGen->internalRegisters.Extract(indir); + regNumber tmpReg2 = codeGen->internalRegisters.GetSingle(indir); emitIns_R_R_R(INS_vmov_d2i, EA_8BYTE, tmpReg1, tmpReg2, dataReg); emitInsLoadStoreOp(INS_str, EA_4BYTE, tmpReg1, indir, 0); emitInsLoadStoreOp(INS_str, EA_4BYTE, tmpReg2, indir, 4); @@ -7889,15 +7889,15 @@ void emitter::emitInsLoadStoreOp(instruction ins, emitAttr attr, regNumber dataR var_types type = indir->TypeGet(); if (type == TYP_FLOAT) { - regNumber tmpReg = indir->GetSingleTempReg(); + regNumber tmpReg = codeGen->internalRegisters.GetSingle(indir); emitInsLoadStoreOp(INS_ldr, EA_4BYTE, tmpReg, indir, 0); emitIns_Mov(INS_vmov_i2f, EA_4BYTE, dataReg, tmpReg, /* canSkip */ false); return; } else if (type == TYP_DOUBLE) { - regNumber tmpReg1 = indir->ExtractTempReg(); - regNumber tmpReg2 = indir->GetSingleTempReg(); + regNumber tmpReg1 = codeGen->internalRegisters.Extract(indir); + regNumber tmpReg2 = codeGen->internalRegisters.GetSingle(indir); emitInsLoadStoreOp(INS_ldr, EA_4BYTE, tmpReg1, indir, 0); emitInsLoadStoreOp(INS_ldr, EA_4BYTE, tmpReg2, indir, 4); emitIns_R_R_R(INS_vmov_i2d, EA_8BYTE, dataReg, tmpReg1, tmpReg2); @@ -7940,7 +7940,7 @@ void emitter::emitInsLoadStoreOp(instruction ins, emitAttr attr, regNumber dataR if (offset != 0) { - regNumber tmpReg = indir->GetSingleTempReg(); + regNumber tmpReg = codeGen->internalRegisters.GetSingle(indir); // If the LEA produces a GCREF or BYREF, we need to be careful to mark any temp register // computed with the base register as a BYREF. @@ -8023,7 +8023,7 @@ void emitter::emitInsLoadStoreOp(instruction ins, emitAttr attr, regNumber dataR else { // We require a tmpReg to hold the offset - regNumber tmpReg = indir->GetSingleTempReg(); + regNumber tmpReg = codeGen->internalRegisters.GetSingle(indir); // First load/store tmpReg with the large offset constant codeGen->instGen_Set_Reg_To_Imm(EA_PTRSIZE, tmpReg, offset); @@ -8175,7 +8175,7 @@ regNumber emitter::emitInsTernary(instruction ins, emitAttr attr, GenTree* dst, { if (isMulOverflow) { - regNumber extraReg = dst->GetSingleTempReg(); + regNumber extraReg = codeGen->internalRegisters.GetSingle(dst); assert(extraReg != dst->GetRegNum()); if ((dst->gtFlags & GTF_UNSIGNED) != 0) diff --git a/src/coreclr/jit/emitarm64.cpp b/src/coreclr/jit/emitarm64.cpp index 181b9706e41611..3c988633e798b9 100644 --- a/src/coreclr/jit/emitarm64.cpp +++ b/src/coreclr/jit/emitarm64.cpp @@ -14243,7 +14243,7 @@ void emitter::emitInsLoadStoreOp(instruction ins, emitAttr attr, regNumber dataR if (offset != 0) { - regNumber tmpReg = indir->GetSingleTempReg(); + regNumber tmpReg = codeGen->internalRegisters.GetSingle(indir); emitAttr addType = varTypeIsGC(memBase) ? EA_BYREF : EA_PTRSIZE; @@ -14350,7 +14350,7 @@ void emitter::emitInsLoadStoreOp(instruction ins, emitAttr attr, regNumber dataR else { // We require a tmpReg to hold the offset - regNumber tmpReg = indir->GetSingleTempReg(); + regNumber tmpReg = codeGen->internalRegisters.GetSingle(indir); // First load/store tmpReg with the large offset constant codeGen->instGen_Set_Reg_To_Imm(EA_PTRSIZE, tmpReg, offset); @@ -14490,7 +14490,7 @@ regNumber emitter::emitInsTernary(instruction ins, emitAttr attr, GenTree* dst, { if (isMulOverflow) { - regNumber extraReg = dst->GetSingleTempReg(); + regNumber extraReg = codeGen->internalRegisters.GetSingle(dst); assert(extraReg != dst->GetRegNum()); if ((dst->gtFlags & GTF_UNSIGNED) != 0) @@ -16996,7 +16996,7 @@ void emitter::emitStoreSimd12ToLclOffset(unsigned varNum, unsigned offset, regNu emitIns_S_R(INS_str, EA_8BYTE, dataReg, varNum, offset); // Extract upper 4-bytes from data - regNumber tmpReg = tmpRegProvider->GetSingleTempReg(); + regNumber tmpReg = codeGen->internalRegisters.GetSingle(tmpRegProvider); emitIns_R_R_I(INS_mov, EA_4BYTE, tmpReg, dataReg, 2); // 4-byte write diff --git a/src/coreclr/jit/emitloongarch64.cpp b/src/coreclr/jit/emitloongarch64.cpp index 63d4e9a975b9b1..43281e536e8b31 100644 --- a/src/coreclr/jit/emitloongarch64.cpp +++ b/src/coreclr/jit/emitloongarch64.cpp @@ -4586,7 +4586,7 @@ void emitter::emitInsLoadStoreOp(instruction ins, emitAttr attr, regNumber dataR if (offset != 0) { - regNumber tmpReg = indir->GetSingleTempReg(); + regNumber tmpReg = codeGen->internalRegisters.GetSingle(indir); if (isValidSimm12(offset)) { @@ -4727,7 +4727,7 @@ void emitter::emitInsLoadStoreOp(instruction ins, emitAttr attr, regNumber dataR else { // We require a tmpReg to hold the offset - regNumber tmpReg = indir->GetSingleTempReg(); + regNumber tmpReg = codeGen->internalRegisters.GetSingle(indir); // First load/store tmpReg with the large offset constant emitIns_I_la(EA_PTRSIZE, tmpReg, offset); @@ -5058,7 +5058,7 @@ regNumber emitter::emitInsTernary(instruction ins, emitAttr attr, GenTree* dst, if ((dst->gtFlags & GTF_UNSIGNED) == 0) { - saveOperReg2 = dst->GetSingleTempReg(); + saveOperReg2 = codeGen->internalRegisters.GetSingle(dst); assert((saveOperReg2 != REG_RA) && (saveOperReg2 != REG_R21)); assert(REG_RA != regOp1); assert(saveOperReg2 != regOp2); diff --git a/src/coreclr/jit/emitriscv64.cpp b/src/coreclr/jit/emitriscv64.cpp index d78fc0e9d5b29b..932c9a1125b016 100644 --- a/src/coreclr/jit/emitriscv64.cpp +++ b/src/coreclr/jit/emitriscv64.cpp @@ -4463,7 +4463,7 @@ void emitter::emitInsLoadStoreOp(instruction ins, emitAttr attr, regNumber dataR if (offset != 0) { - regNumber tmpReg = indir->GetSingleTempReg(); + regNumber tmpReg = codeGen->internalRegisters.GetSingle(indir); if (isValidSimm12(offset)) { @@ -4496,7 +4496,7 @@ void emitter::emitInsLoadStoreOp(instruction ins, emitAttr attr, regNumber dataR noway_assert(emitInsIsLoad(ins) || (tmpReg != dataReg)); noway_assert(tmpReg != index->GetRegNum()); - regNumber scaleReg = indir->GetSingleTempReg(); + regNumber scaleReg = codeGen->internalRegisters.GetSingle(indir); // Then load/store dataReg from/to [tmpReg + index*scale] emitIns_R_R_I(INS_slli, addType, scaleReg, index->GetRegNum(), lsl); emitIns_R_R_R(INS_add, addType, tmpReg, tmpReg, scaleReg); @@ -4605,7 +4605,7 @@ void emitter::emitInsLoadStoreOp(instruction ins, emitAttr attr, regNumber dataR else { // We require a tmpReg to hold the offset - regNumber tmpReg = indir->GetSingleTempReg(); + regNumber tmpReg = codeGen->internalRegisters.GetSingle(indir); // First load/store tmpReg with the large offset constant emitLoadImmediate(EA_PTRSIZE, tmpReg, offset); @@ -4771,7 +4771,7 @@ regNumber emitter::emitInsTernary(instruction ins, emitAttr attr, GenTree* dst, assert(ins == INS_addi || ins == INS_addiw || ins == INS_andi || ins == INS_ori || ins == INS_xori); - regNumber tempReg = needCheckOv ? dst->ExtractTempReg() : REG_NA; + regNumber tempReg = needCheckOv ? codeGen->internalRegisters.Extract(dst) : REG_NA; if (needCheckOv) { @@ -4823,7 +4823,7 @@ regNumber emitter::emitInsTernary(instruction ins, emitAttr attr, GenTree* dst, } else { - regNumber tempReg = needCheckOv ? dst->ExtractTempReg() : REG_NA; + regNumber tempReg = needCheckOv ? codeGen->internalRegisters.Extract(dst) : REG_NA; switch (dst->OperGet()) { @@ -4897,7 +4897,7 @@ regNumber emitter::emitInsTernary(instruction ins, emitAttr attr, GenTree* dst, } else { - regNumber tempReg2 = dst->ExtractTempReg(); + regNumber tempReg2 = codeGen->internalRegisters.Extract(dst); assert(tempReg2 != dstReg); assert(tempReg2 != src1Reg); assert(tempReg2 != src2Reg); @@ -5003,7 +5003,7 @@ regNumber emitter::emitInsTernary(instruction ins, emitAttr attr, GenTree* dst, else { tempReg1 = REG_RA; - tempReg2 = dst->ExtractTempReg(); + tempReg2 = codeGen->internalRegisters.Extract(dst); assert(tempReg1 != tempReg2); assert(tempReg1 != saveOperReg1); assert(tempReg2 != saveOperReg2); diff --git a/src/coreclr/jit/emitxarch.cpp b/src/coreclr/jit/emitxarch.cpp index 6bf148cf2d8883..35cb3a986ee580 100644 --- a/src/coreclr/jit/emitxarch.cpp +++ b/src/coreclr/jit/emitxarch.cpp @@ -5641,7 +5641,7 @@ void emitter::emitStoreSimd12ToLclOffset(unsigned varNum, unsigned offset, regNu } else { - regNumber tmpReg = tmpRegProvider->GetSingleTempReg(); + regNumber tmpReg = codeGen->internalRegisters.GetSingle(tmpRegProvider); assert(isFloatReg(tmpReg)); // Extract upper 4 bytes from data diff --git a/src/coreclr/jit/gentree.cpp b/src/coreclr/jit/gentree.cpp index 8076662e183e44..d48fc45868ba22 100644 --- a/src/coreclr/jit/gentree.cpp +++ b/src/coreclr/jit/gentree.cpp @@ -9782,7 +9782,6 @@ GenTree* Compiler::gtCloneExpr(GenTree* tree) /* Make sure to copy back fields that may have been initialized */ copy->CopyRawCosts(tree); - copy->gtRsvdRegs = tree->gtRsvdRegs; copy->CopyReg(tree); return copy; } @@ -11644,7 +11643,7 @@ void Compiler::gtDispNode(GenTree* tree, IndentStack* indentStack, _In_ _In_opt_ if (verbose && 0) { printf(" RR="); - dspRegMask(tree->gtRsvdRegs); + dspRegMask(JitTls::GetCompiler()->codeGen->internalRegisters.GetAll(tree)); printf("\n"); } } @@ -27720,75 +27719,14 @@ regMaskTP ReturnTypeDesc::GetABIReturnRegs(CorInfoCallConvExtension callConv) co } //------------------------------------------------------------------------ -// The following functions manage the gtRsvdRegs set of temporary registers -// created by LSRA during code generation. - -//------------------------------------------------------------------------ -// AvailableTempRegCount: return the number of available temporary registers in the (optional) given set -// (typically, RBM_ALLINT or RBM_ALLFLOAT). -// -// Arguments: -// mask - (optional) Check for available temporary registers only in this set. -// -// Return Value: -// Count of available temporary registers in given set. -// -unsigned GenTree::AvailableTempRegCount(regMaskTP mask /* = (regMaskTP)-1 */) const -{ - return genCountBits(gtRsvdRegs & mask); -} - -//------------------------------------------------------------------------ -// GetSingleTempReg: There is expected to be exactly one available temporary register -// in the given mask in the gtRsvdRegs set. Get that register. No future calls to get -// a temporary register are expected. Removes the register from the set, but only in -// DEBUG to avoid doing unnecessary work in non-DEBUG builds. +// GetNum: Get the SSA number for a given field. // -// Arguments: -// mask - (optional) Get an available temporary register only in this set. -// -// Return Value: -// Available temporary register in given mask. -// -regNumber GenTree::GetSingleTempReg(regMaskTP mask /* = (regMaskTP)-1 */) -{ - regMaskTP availableSet = gtRsvdRegs & mask; - assert(genCountBits(availableSet) == 1); - regNumber tempReg = genRegNumFromMask(availableSet); - INDEBUG(gtRsvdRegs &= ~availableSet;) // Remove the register from the set, so it can't be used again. - return tempReg; -} - -//------------------------------------------------------------------------ -// ExtractTempReg: Find the lowest number temporary register from the gtRsvdRegs set -// that is also in the optional given mask (typically, RBM_ALLINT or RBM_ALLFLOAT), -// and return it. Remove this register from the temporary register set, so it won't -// be returned again. -// -// Arguments: -// mask - (optional) Extract an available temporary register only in this set. -// -// Return Value: -// Available temporary register in given mask. -// -regNumber GenTree::ExtractTempReg(regMaskTP mask /* = (regMaskTP)-1 */) -{ - regMaskTP availableSet = gtRsvdRegs & mask; - assert(genCountBits(availableSet) >= 1); - regNumber tempReg = genFirstRegNumFromMask(availableSet); - gtRsvdRegs ^= genRegMask(tempReg); - return tempReg; -} - -//------------------------------------------------------------------------ -// GetNum: Get the SSA number for a given field. -// -// Arguments: -// compiler - The Compiler instance -// index - The field index +// Arguments: +// compiler - The Compiler instance +// index - The field index // -// Return Value: -// The SSA number corresponding to the field at "index". +// Return Value: +// The SSA number corresponding to the field at "index". // unsigned SsaNumInfo::GetNum(Compiler* compiler, unsigned index) const { diff --git a/src/coreclr/jit/gentree.h b/src/coreclr/jit/gentree.h index 2f3a2a7b2f573b..7dbfef174994e6 100644 --- a/src/coreclr/jit/gentree.h +++ b/src/coreclr/jit/gentree.h @@ -956,12 +956,6 @@ struct GenTree ValueNumPair gtVNPair; - regMaskSmall gtRsvdRegs; // set of fixed trashed registers - - unsigned AvailableTempRegCount(regMaskTP mask = (regMaskTP)-1) const; - regNumber GetSingleTempReg(regMaskTP mask = (regMaskTP)-1); - regNumber ExtractTempReg(regMaskTP mask = (regMaskTP)-1); - void SetVNsFromNode(GenTree* tree) { gtVNPair = tree->gtVNPair; diff --git a/src/coreclr/jit/hwintrinsiccodegenarm64.cpp b/src/coreclr/jit/hwintrinsiccodegenarm64.cpp index aadd8fcf28e000..f58ca6c6e858d5 100644 --- a/src/coreclr/jit/hwintrinsiccodegenarm64.cpp +++ b/src/coreclr/jit/hwintrinsiccodegenarm64.cpp @@ -99,7 +99,7 @@ CodeGen::HWIntrinsicImmOpHelper::HWIntrinsicImmOpHelper(CodeGen* codeGen, GenTre // using the same approach as in hwintrinsicxarch.cpp - adding an additional indirection level in form of a // branch table. assert(!HWIntrinsicInfo::GeneratesMultipleIns(intrin->GetHWIntrinsicId())); - branchTargetReg = intrin->GetSingleTempReg(); + branchTargetReg = codeGen->internalRegisters.GetSingle(intrin); } endLabel = codeGen->genCreateTempLabel(); @@ -1206,7 +1206,7 @@ void CodeGen::genHWIntrinsic(GenTreeHWIntrinsic* node) if (intrin.op1->OperIsLocal()) { unsigned varNum = intrin.op1->AsLclVarCommon()->GetLclNum(); - baseReg = node->ExtractTempReg(); + baseReg = internalRegisters.Extract(node); // Load the address of varNum GetEmitter()->emitIns_R_S(INS_lea, EA_PTRSIZE, baseReg, varNum, 0); @@ -1226,7 +1226,7 @@ void CodeGen::genHWIntrinsic(GenTreeHWIntrinsic* node) unsigned simdInitTempVarNum = compiler->lvaSIMDInitTempVarNum; noway_assert(simdInitTempVarNum != BAD_VAR_NUM); - baseReg = node->ExtractTempReg(); + baseReg = internalRegisters.Extract(node); // Load the address of simdInitTempVarNum GetEmitter()->emitIns_R_S(INS_lea, EA_PTRSIZE, baseReg, simdInitTempVarNum, 0); diff --git a/src/coreclr/jit/hwintrinsiccodegenxarch.cpp b/src/coreclr/jit/hwintrinsiccodegenxarch.cpp index 79e6b497c368a9..a4b6748f3db531 100644 --- a/src/coreclr/jit/hwintrinsiccodegenxarch.cpp +++ b/src/coreclr/jit/hwintrinsiccodegenxarch.cpp @@ -323,8 +323,8 @@ void CodeGen::genHWIntrinsic(GenTreeHWIntrinsic* node) insOpts newInstOptions = AddEmbRoundingMode(instOptions, i); genHWIntrinsic_R_RM(node, ins, simdSize, targetReg, rmOp, newInstOptions); }; - regNumber baseReg = node->ExtractTempReg(); - regNumber offsReg = node->GetSingleTempReg(); + regNumber baseReg = internalRegisters.Extract(node); + regNumber offsReg = internalRegisters.GetSingle(node); genHWIntrinsicJumpTableFallback(intrinsicId, lastOp->GetRegNum(), baseReg, offsReg, emitSwCase); break; @@ -335,8 +335,8 @@ void CodeGen::genHWIntrinsic(GenTreeHWIntrinsic* node) insOpts newInstOptions = AddEmbRoundingMode(instOptions, i); genHWIntrinsic_R_R_RM(node, ins, simdSize, newInstOptions); }; - regNumber baseReg = node->ExtractTempReg(); - regNumber offsReg = node->GetSingleTempReg(); + regNumber baseReg = internalRegisters.Extract(node); + regNumber offsReg = internalRegisters.GetSingle(node); genHWIntrinsicJumpTableFallback(intrinsicId, lastOp->GetRegNum(), baseReg, offsReg, emitSwCase); break; @@ -524,8 +524,8 @@ void CodeGen::genHWIntrinsic(GenTreeHWIntrinsic* node) // Reflection. However, it // can also occur if the consumer calls it directly and just doesn't pass a // constant value. - regNumber baseReg = node->ExtractTempReg(); - regNumber offsReg = node->GetSingleTempReg(); + regNumber baseReg = internalRegisters.Extract(node); + regNumber offsReg = internalRegisters.GetSingle(node); genHWIntrinsicJumpTableFallback(intrinsicId, op2Reg, baseReg, offsReg, emitSwCase); } } @@ -574,8 +574,8 @@ void CodeGen::genHWIntrinsic(GenTreeHWIntrinsic* node) // We emit a fallback case for the scenario when the imm-op is not a constant. This should // normally happen when the intrinsic is called indirectly, such as via Reflection. However, it // can also occur if the consumer calls it directly and just doesn't pass a constant value. - regNumber baseReg = node->ExtractTempReg(); - regNumber offsReg = node->GetSingleTempReg(); + regNumber baseReg = internalRegisters.Extract(node); + regNumber offsReg = internalRegisters.GetSingle(node); genHWIntrinsicJumpTableFallback(intrinsicId, op3Reg, baseReg, offsReg, emitSwCase); } } @@ -670,8 +670,8 @@ void CodeGen::genHWIntrinsic(GenTreeHWIntrinsic* node) // We emit a fallback case for the scenario when the imm-op is not a constant. This should // normally happen when the intrinsic is called indirectly, such as via Reflection. However, it // can also occur if the consumer calls it directly and just doesn't pass a constant value. - regNumber baseReg = node->ExtractTempReg(); - regNumber offsReg = node->GetSingleTempReg(); + regNumber baseReg = internalRegisters.Extract(node); + regNumber offsReg = internalRegisters.GetSingle(node); genHWIntrinsicJumpTableFallback(intrinsicId, op4Reg, baseReg, offsReg, emitSwCase); } } @@ -1373,8 +1373,8 @@ void CodeGen::genNonTableDrivenHWIntrinsicsJumpTableFallback(GenTreeHWIntrinsic* insOpts newInstOptions = AddEmbRoundingMode(instOptions, i); genHWIntrinsic_R_RM(node, ins, attr, targetReg, rmOp, newInstOptions); }; - regNumber baseReg = node->ExtractTempReg(); - regNumber offsReg = node->GetSingleTempReg(); + regNumber baseReg = internalRegisters.Extract(node); + regNumber offsReg = internalRegisters.GetSingle(node); genHWIntrinsicJumpTableFallback(intrinsicId, lastOp->GetRegNum(), baseReg, offsReg, emitSwCase); break; } @@ -1394,8 +1394,8 @@ void CodeGen::genNonTableDrivenHWIntrinsicsJumpTableFallback(GenTreeHWIntrinsic* insOpts newInstOptions = AddEmbRoundingMode(instOptions, i); genHWIntrinsic_R_RM(node, ins, attr, targetReg, rmOp, newInstOptions); }; - regNumber baseReg = node->ExtractTempReg(); - regNumber offsReg = node->GetSingleTempReg(); + regNumber baseReg = internalRegisters.Extract(node); + regNumber offsReg = internalRegisters.GetSingle(node); genHWIntrinsicJumpTableFallback(intrinsicId, lastOp->GetRegNum(), baseReg, offsReg, emitSwCase); break; } @@ -1408,8 +1408,8 @@ void CodeGen::genNonTableDrivenHWIntrinsicsJumpTableFallback(GenTreeHWIntrinsic* insOpts newInstOptions = AddEmbRoundingMode(instOptions, i); genHWIntrinsic_R_R_RM(node, ins, EA_8BYTE, newInstOptions); }; - regNumber baseReg = node->ExtractTempReg(); - regNumber offsReg = node->GetSingleTempReg(); + regNumber baseReg = internalRegisters.Extract(node); + regNumber offsReg = internalRegisters.GetSingle(node); genHWIntrinsicJumpTableFallback(intrinsicId, lastOp->GetRegNum(), baseReg, offsReg, emitSwCase); break; } @@ -1440,8 +1440,8 @@ void CodeGen::genNonTableDrivenHWIntrinsicsJumpTableFallback(GenTreeHWIntrinsic* insOpts newInstOptions = AddEmbRoundingMode(instOptions, i); genHWIntrinsic_R_R_R_RM(ins, attr, targetReg, op1Reg, op2Reg, op3, newInstOptions); }; - regNumber baseReg = node->ExtractTempReg(); - regNumber offsReg = node->GetSingleTempReg(); + regNumber baseReg = internalRegisters.Extract(node); + regNumber offsReg = internalRegisters.GetSingle(node); genHWIntrinsicJumpTableFallback(intrinsicId, lastOp->GetRegNum(), baseReg, offsReg, emitSwCase); break; } @@ -2074,8 +2074,8 @@ void CodeGen::genSSE41Intrinsic(GenTreeHWIntrinsic* node) // We emit a fallback case for the scenario when the imm-op is not a constant. This should // normally happen when the intrinsic is called indirectly, such as via Reflection. However, it // can also occur if the consumer calls it directly and just doesn't pass a constant value. - regNumber baseReg = node->ExtractTempReg(); - regNumber offsReg = node->GetSingleTempReg(); + regNumber baseReg = internalRegisters.Extract(node); + regNumber offsReg = internalRegisters.GetSingle(node); genHWIntrinsicJumpTableFallback(intrinsicId, op2->GetRegNum(), baseReg, offsReg, emitSwCase); } break; @@ -2225,7 +2225,7 @@ void CodeGen::genAvxFamilyIntrinsic(GenTreeHWIntrinsic* node, insOpts instOption regNumber op2Reg = op2->GetRegNum(); regNumber addrBaseReg = REG_NA; regNumber addrIndexReg = REG_NA; - regNumber maskReg = node->ExtractTempReg(RBM_ALLFLOAT); + regNumber maskReg = internalRegisters.Extract(node, RBM_ALLFLOAT); if (numArgs == 5) { @@ -2902,7 +2902,7 @@ void CodeGen::genBMI1OrBMI2Intrinsic(GenTreeHWIntrinsic* node, insOpts instOptio assert(op3Reg != op1Reg); assert(op3Reg != targetReg); assert(op3Reg != REG_EDX); - lowReg = node->GetSingleTempReg(); + lowReg = internalRegisters.GetSingle(node); assert(op3Reg != lowReg); assert(lowReg != targetReg); } diff --git a/src/coreclr/jit/jithashtable.h b/src/coreclr/jit/jithashtable.h index f699c3eee19d24..7f9153b75864a7 100644 --- a/src/coreclr/jit/jithashtable.h +++ b/src/coreclr/jit/jithashtable.h @@ -233,7 +233,7 @@ class JitHashTable } //------------------------------------------------------------------------ - // Lookup: Get a pointer to the value associated to the specified key. + // LookupPointer: Get a pointer to the value associated to the specified key. // if any. // // Arguments: @@ -261,6 +261,48 @@ class JitHashTable } } + //------------------------------------------------------------------------ + // LookupPointerOrAdd: Get a pointer to the value associated to the specified key. + // If not present, add it with the specified default value and return a pointer to it. + // + // Arguments: + // k - the key + // defaultValue - Default value to add to the table if the key was not present + // + // Return Value: + // A pointer to the value associated with the specified key. + // + Value* LookupPointerOrAdd(Key k, Value defaultValue) + { + CheckGrowth(); + + assert(m_tableSizeInfo.prime != 0); + + unsigned index = GetIndexForKey(k); + + Node* n = m_table[index]; + while (n != nullptr) + { + if (KeyFuncs::Equals(k, n->m_key)) + { + return &n->m_val; + } + + n = n->m_next; + } + + n = new (m_alloc) Node(m_table[index], k, defaultValue); + m_table[index] = n; + m_tableCount++; + return &n->m_val; + } + + enum SetKind + { + None, + Overwrite + }; + //------------------------------------------------------------------------ // Set: Associate the specified value with the specified key. // @@ -279,12 +321,6 @@ class JitHashTable // If the key already exists and kind is Normal // this method will assert // - enum SetKind - { - None, - Overwrite - }; - bool Set(Key k, Value v, SetKind kind = None) { CheckGrowth(); diff --git a/src/coreclr/jit/lsra.cpp b/src/coreclr/jit/lsra.cpp index ebcb21fff18bc3..efd861348223dc 100644 --- a/src/coreclr/jit/lsra.cpp +++ b/src/coreclr/jit/lsra.cpp @@ -8106,7 +8106,7 @@ void LinearScan::resolveRegisters() assert(currentRefPosition->isIntervalRef()); if (currentRefPosition->getInterval()->isInternal) { - treeNode->gtRsvdRegs |= currentRefPosition->registerAssignment; + compiler->codeGen->internalRegisters.Add(treeNode, currentRefPosition->registerAssignment); } else { @@ -8918,7 +8918,7 @@ void LinearScan::handleOutgoingCriticalEdges(BasicBlock* block) GenTree* switchTable = LIR::AsRange(block).LastNode(); assert(switchTable != nullptr && switchTable->OperGet() == GT_SWITCH_TABLE); - consumedRegs = switchTable->gtRsvdRegs; + consumedRegs = compiler->codeGen->internalRegisters.GetAll(switchTable); GenTree* op1 = switchTable->gtGetOp1(); GenTree* op2 = switchTable->gtGetOp2(); noway_assert(op1 != nullptr && op2 != nullptr); diff --git a/src/coreclr/jit/lsraarmarch.cpp b/src/coreclr/jit/lsraarmarch.cpp index c2b8b74406584e..f88173e05e2092 100644 --- a/src/coreclr/jit/lsraarmarch.cpp +++ b/src/coreclr/jit/lsraarmarch.cpp @@ -181,16 +181,24 @@ int LinearScan::BuildCall(GenTreeCall* call) } else if (call->IsR2ROrVirtualStubRelativeIndir()) { - // For R2R and VSD we have stub address in REG_R2R_INDIRECT_PARAM - // and will load call address into the temp register from this register. - regMaskTP candidates = RBM_NONE; if (call->IsFastTailCall()) { - candidates = allRegs(TYP_INT) & RBM_INT_CALLEE_TRASH; + // For R2R and VSD we have stub address in REG_R2R_INDIRECT_PARAM + // and will load call address into the temp register from this register. + regMaskTP candidates = allRegs(TYP_INT) & RBM_INT_CALLEE_TRASH; assert(candidates != RBM_NONE); + buildInternalIntRegisterDefForNode(call, candidates); + } + else + { + // For arm64 we can use lr for non-tailcalls so we skip the + // internal register as a TP optimization. We could do the same for + // arm32, but loading into lr cannot be encoded in 2 bytes, so + // another register is usually better. +#ifdef TARGET_ARM + buildInternalIntRegisterDefForNode(call); +#endif } - - buildInternalIntRegisterDefForNode(call, candidates); } #ifdef TARGET_ARM else diff --git a/src/coreclr/jit/lsrabuild.cpp b/src/coreclr/jit/lsrabuild.cpp index 37fa4320cc6918..22cba5900a7ddd 100644 --- a/src/coreclr/jit/lsrabuild.cpp +++ b/src/coreclr/jit/lsrabuild.cpp @@ -1730,10 +1730,6 @@ int LinearScan::ComputeAvailableSrcCount(GenTree* node) // void LinearScan::buildRefPositionsForNode(GenTree* tree, LsraLocation currentLoc) { - // The set of internal temporary registers used by this node are stored in the - // gtRsvdRegs register mask. Clear it out. - tree->gtRsvdRegs = RBM_NONE; - #ifdef DEBUG if (VERBOSE) { diff --git a/src/coreclr/jit/simdcodegenxarch.cpp b/src/coreclr/jit/simdcodegenxarch.cpp index d0fb1bf0aef4e8..aff087062f58fe 100644 --- a/src/coreclr/jit/simdcodegenxarch.cpp +++ b/src/coreclr/jit/simdcodegenxarch.cpp @@ -96,7 +96,7 @@ void CodeGen::genStoreIndTypeSimd12(GenTreeStoreInd* treeNode) } else { - regNumber tmpReg = treeNode->GetSingleTempReg(); + regNumber tmpReg = internalRegisters.GetSingle(treeNode); // Extract upper 4 bytes from data emit->emitIns_R_R(INS_movhlps, EA_16BYTE, tmpReg, dataReg); @@ -295,7 +295,7 @@ void CodeGen::genEmitStoreLclTypeSimd12(GenTree* store, unsigned lclNum, unsigne } else { - regNumber tmpReg = store->GetSingleTempReg(); + regNumber tmpReg = internalRegisters.GetSingle(store); // Extract upper 4 bytes from data emit->emitIns_R_R(INS_movhlps, EA_16BYTE, tmpReg, dataReg); @@ -391,7 +391,7 @@ void CodeGen::genPutArgStkSimd12(GenTreePutArgStk* treeNode) regNumber dataReg = genConsumeReg(data); // Need an additional Xmm register to extract upper 4 bytes from data. - regNumber tmpReg = treeNode->GetSingleTempReg(); + regNumber tmpReg = internalRegisters.GetSingle(treeNode); genStoreSimd12ToStack(dataReg, tmpReg); } From 4170efe8fdc2dd06232b915076d1b77954632681 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 29 Apr 2024 11:27:58 -0700 Subject: [PATCH 140/161] Bump actions/github-script from 6 to 7 (#101588) Bumps [actions/github-script](https://github.com/actions/github-script) from 6 to 7. - [Release notes](https://github.com/actions/github-script/releases) - [Commits](https://github.com/actions/github-script/compare/v6...v7) --- updated-dependencies: - dependency-name: actions/github-script dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/bump-chrome-version.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/bump-chrome-version.yml b/.github/workflows/bump-chrome-version.yml index fc2f09cf3d01f7..e47563ca44a071 100644 --- a/.github/workflows/bump-chrome-version.yml +++ b/.github/workflows/bump-chrome-version.yml @@ -47,7 +47,7 @@ jobs: - name: Create PR if: steps.check_changes.outputs.has_changes == 'true' - uses: actions/github-script@v6 + uses: actions/github-script@v7 with: script: | const { CHROME_LINUX_VER, CHROME_WIN_VER } = process.env; From 4ac82c948aa21554545362c86120a53ee9dff2fb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 29 Apr 2024 12:21:12 -0700 Subject: [PATCH 141/161] Bump actions/upload-artifact from 1 to 4 (#101587) Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 1 to 4. - [Release notes](https://github.com/actions/upload-artifact/releases) - [Commits](https://github.com/actions/upload-artifact/compare/v1...v4) --- updated-dependencies: - dependency-name: actions/upload-artifact dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/aspnetcore-sync.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/aspnetcore-sync.yml b/.github/workflows/aspnetcore-sync.yml index 01aa3dfdabca60..12cc86c47b8983 100644 --- a/.github/workflows/aspnetcore-sync.yml +++ b/.github/workflows/aspnetcore-sync.yml @@ -42,7 +42,7 @@ jobs: mkdir ..\artifacts git status > ..\artifacts\status.txt git diff > ..\artifacts\diff.txt - - uses: actions/upload-artifact@v1 + - uses: actions/upload-artifact@v4 with: name: results path: artifacts From 261611930d6b436d7c4395450356b624d903d9bf Mon Sep 17 00:00:00 2001 From: Viktor Hofer Date: Mon, 29 Apr 2024 21:28:04 +0200 Subject: [PATCH 142/161] Replace usage of out-of-support TFM compiler directives (#101672) * Replace usage of out-of-support TFM compiler directives ... and directives for TFMs that we don't target anymore in main. Replaces the following directives with `NET` or `!NET`: - `#if NETCOREAPP2*` - `#if !NETCOREAPP2*` - `#if NETCOREAPP3*` - `#if !NETCOREAPP3*` - `#if NET5*` - `#if !NET5*` - `#if NET6*` - `#if !NET6*` - `#if NET7*` - `#if !NET7*` * Update EmitterTests.cs --- .../Utilities/LockFreeReaderHashtable.cs | 4 ++-- .../Common/src/Interop/Interop.Ldap.cs | 14 ++++++------ .../Common/src/Interop/Interop.Odbc.cs | 10 ++++----- .../CryptUI/Interop.CryptUIDlgCertificate.cs | 10 ++++----- .../Interop/Windows/Gdi32/Interop.AbortDoc.cs | 4 ++-- .../Gdi32/Interop.CreateCompatibleBitmap.cs | 4 ++-- .../Windows/Gdi32/Interop.CreateDIBSection.cs | 4 ++-- .../Interop/Windows/Gdi32/Interop.DEVMODE.cs | 2 +- .../Interop/Windows/Gdi32/Interop.EndDoc.cs | 4 ++-- .../Interop/Windows/Gdi32/Interop.EndPage.cs | 4 ++-- .../Windows/Gdi32/Interop.ExtEscape.cs | 6 ++--- .../Windows/Gdi32/Interop.GetDIBits.cs | 6 ++--- .../Windows/Gdi32/Interop.GetObject.cs | 8 +++---- .../Gdi32/Interop.GetPaletteEntries.cs | 4 ++-- .../Gdi32/Interop.IntersectClipRect.cs | 4 ++-- .../Interop/Windows/Gdi32/Interop.ResetDC.cs | 6 ++--- .../Interop/Windows/Gdi32/Interop.StartDoc.cs | 8 +++---- .../Windows/Gdi32/Interop.StartPage.cs | 4 ++-- .../Windows/Kernel32/Interop.SelectObject.cs | 6 ++--- .../Shell32/Interop.ExtractAssociatedIcon.cs | 4 ++-- .../Windows/User32/Interop.CopyImage.cs | 4 ++-- .../Interop.CreateIconFromResourceEx.cs | 2 +- .../Windows/User32/Interop.DestroyIcon.cs | 4 ++-- .../Windows/User32/Interop.DrawIconEx.cs | 8 +++---- .../Windows/User32/Interop.GetIconInfo.cs | 4 ++-- .../User32/Interop.GetSystemMetrics.cs | 2 +- .../Windows/User32/Interop.LoadIcon.cs | 4 ++-- .../Windows/WinHttp/Interop.winhttp.cs | 6 ++--- .../Windows/WinHttp/Interop.winhttp_types.cs | 6 ++--- .../WinMm/Interop.waveOutGetDevCaps.cs | 6 ++--- .../Winspool/Interop.DocumentProperties.cs | 12 +++++----- .../Windows/Winspool/Interop.EnumPrinters.cs | 2 +- .../src/System/CodeDom/CodeTypeReference.cs | 4 ++-- .../CodeDom/CodeTypeReferenceCollection.cs | 4 ++-- .../Data/Common/DbConnectionOptions.Common.cs | 4 ++-- .../src/System/IO/TempFileCollection.cs | 2 +- .../Common/src/System/IO/Win32Marshal.cs | 2 +- .../Cryptography/Asn1/AttributeAsn.manual.cs | 2 +- .../Asn1/X509ExtensionAsn.manual.cs | 2 +- .../Cryptography/CryptoThrowHelper.Windows.cs | 6 ++--- ...0108HmacCounterKdfImplementationManaged.cs | 3 --- .../Threading/Tasks/TaskToAsyncResult.cs | 6 ++--- .../Common/src/System/ThrowHelper.cs | 12 +++++----- .../TestUtilities/System/AssertExtensions.cs | 10 ++++----- .../System/WindowsIdentityFixture.cs | 6 ++--- .../tests/TestUtilities/TestEventListener.cs | 2 +- .../src/IMemoryCache.cs | 2 +- .../MemoryCacheGetCurrentStatisticsTests.cs | 2 +- .../src/PhysicalFilesWatcher.cs | 2 +- .../src/WindowsServiceHelpers.cs | 2 +- .../src/HostBuilder.cs | 5 ----- .../ref/Microsoft.Extensions.Http.cs | 6 ++--- .../DefaultSocketsHttpHandlerBuilder.cs | 2 +- .../HttpClientBuilderExtensions.cs | 2 +- .../ISocketsHttpHandlerBuilder.cs | 2 +- .../SocketsHttpHandlerBuilderExtensions.cs | 2 +- .../src/Logging/HttpClientLoggerHandler.cs | 2 +- .../src/Logging/LoggingHttpMessageHandler.cs | 4 ++-- .../Logging/LoggingScopeHttpMessageHandler.cs | 4 ++-- .../Logging/HttpClientLoggerTest.cs | 6 ++--- .../Logging/LoggingUriOutputTests.cs | 2 +- .../SocketsHttpHandlerConfigurationTest.cs | 2 +- .../TestMessageHandler.cs | 2 +- .../SourceGenerationTests/EmitterTests.cs | 6 ++--- .../Generated/OptionsValidationTests.cs | 2 +- .../SourceGenerationTests/Generated/Utils.cs | 4 ++-- .../TestClasses/Models.cs | 2 +- .../System/Collections/Frozen/Constants.cs | 8 +------ .../Collections/Frozen/FrozenHashTable.cs | 2 +- .../System/Collections/Frozen/FrozenSet.cs | 2 +- .../Collections/Frozen/String/KeyAnalyzer.cs | 2 +- .../Frozen/String/LengthBuckets.cs | 4 ++-- .../Immutable/ImmutableArray_1.Builder.cs | 6 ++--- .../src/System/Polyfills.cs | 8 +++---- .../tests/Frozen/FrozenSetTests.cs | 2 +- .../ImplicitMachineConfigHost.cs | 2 +- .../src/DbConnectionOptions.cs | 4 ++-- .../src/System/Diagnostics/Activity.cs | 4 ++-- .../Diagnostics/Metrics/CounterAggregator.cs | 2 +- .../Diagnostics/Reader/UnsafeNativeMethods.cs | 10 ++++----- .../System/Formats/Asn1/AsnDecoder.Integer.cs | 2 +- .../System/Formats/Asn1/AsnWriter.Integer.cs | 2 +- .../System/Formats/Asn1/SetOfValueComparer.cs | 2 +- .../src/System/IO/Hashing/Crc32.cs | 4 ++-- .../src/System/IO/Hashing/Crc64.cs | 2 +- .../src/System/IO/Hashing/XxHash128.cs | 8 +++---- .../src/System/IO/Hashing/XxHash3.cs | 4 ++-- .../src/System/IO/Hashing/XxHashShared.cs | 22 +++++++++---------- .../tests/NonCryptoHashTestDriver.cs | 2 +- .../System.IO.Hashing/tests/XxHash128Tests.cs | 6 ++--- .../InternalRelationshipCollection.cs | 2 +- .../Packaging/PackUriHelper.PackUriScheme.cs | 2 +- .../tests/PipeReaderCopyToAsyncTests.cs | 2 +- .../src/System/IO/Ports/SerialPort.cs | 2 +- .../Internal/Utilities/StreamExtensions.cs | 2 +- .../Reflection/TypeLoading/General/Helpers.cs | 2 +- .../Reflection/TypeLoading/Types/RoType.cs | 2 +- .../tests/src/Tests/Type/TypeTests.cs | 2 +- .../src/Internal/Cryptography/PkcsHelpers.cs | 2 +- .../System/Security/Cryptography/Xml/Utils.cs | 2 +- .../Cryptography/Xml/XmlResolverHelper.cs | 4 ++-- .../src/System/ServiceModel/XmlBuffer.cs | 2 +- .../src/Internal/Synthesis/AudioBase.cs | 2 +- .../src/Internal/Synthesis/EngineSite.cs | 2 +- .../System/Text/CodePagesEncodingProvider.cs | 2 +- .../System.Text.Json/Common/JsonHelpers.cs | 2 +- .../ref/System.Text.Json.netcoreapp.cs | 2 +- .../Json/Document/JsonDocument.MetadataDb.cs | 2 +- .../src/System/Text/Json/JsonConstants.cs | 2 +- .../Reader/Utf8JsonReader.MultiSegment.cs | 2 +- .../DefaultJsonTypeInfoResolver.Converters.cs | 2 +- .../JsonMetadataServices.Converters.cs | 2 +- .../Metadata/JsonPropertyInfo.cs | 2 +- ...CollectionTests.Dictionary.NonStringKey.cs | 2 +- .../tests/Common/TestClasses/TestClasses.cs | 2 +- .../Text/RegularExpressions/RegexCharClass.cs | 6 ++--- .../Text/RegularExpressions/RegexWriter.cs | 2 +- .../src/System/Threading/StackHelper.cs | 2 +- .../FunctionalTests/Regex.Match.Tests.cs | 14 ++++++------ .../FunctionalTests/Regex.Tests.Common.cs | 4 ++-- .../tests/FunctionalTests/RegexRunnerTests.cs | 2 +- .../src/Base/DataflowBlock.cs | 2 +- .../src/Internal/Common.cs | 2 +- .../src/System/Media/SoundPlayer.cs | 2 +- .../X509Certificates/X509Certificate2UI.cs | 4 ++-- .../WebcilConverter.cs | 4 ++-- .../WebcilWasmWrapper.cs | 8 +++---- .../DiagnosticsServerRouterFactory.cs | 2 +- 128 files changed, 253 insertions(+), 267 deletions(-) diff --git a/src/coreclr/tools/Common/TypeSystem/Common/Utilities/LockFreeReaderHashtable.cs b/src/coreclr/tools/Common/TypeSystem/Common/Utilities/LockFreeReaderHashtable.cs index 613ec30fa01d2e..1b772684dc1c13 100644 --- a/src/coreclr/tools/Common/TypeSystem/Common/Utilities/LockFreeReaderHashtable.cs +++ b/src/coreclr/tools/Common/TypeSystem/Common/Utilities/LockFreeReaderHashtable.cs @@ -367,7 +367,7 @@ public TValue AddOrGetExisting(TValue value) private TValue AddOrGetExistingInner(TValue value, out bool addedValue) { -#if NET5_0_OR_GREATER +#if NET ArgumentNullException.ThrowIfNull(value); #else if (value == null) @@ -596,7 +596,7 @@ public bool Contains(TKey key) /// Value from the hashtable if found, otherwise null. public TValue GetValueIfExists(TValue value) { -#if NET5_0_OR_GREATER +#if NET ArgumentNullException.ThrowIfNull(value); #else if (value == null) diff --git a/src/libraries/Common/src/Interop/Interop.Ldap.cs b/src/libraries/Common/src/Interop/Interop.Ldap.cs index 7fb63a1d3c5e20..4020dd0fe89bbb 100644 --- a/src/libraries/Common/src/Interop/Interop.Ldap.cs +++ b/src/libraries/Common/src/Interop/Interop.Ldap.cs @@ -4,7 +4,7 @@ using System.Diagnostics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -#if NET7_0_OR_GREATER +#if NET using System.Runtime.InteropServices.Marshalling; #endif using System.Security.Authentication; @@ -31,7 +31,7 @@ internal readonly struct Luid public int HighPart => _highPart; } -#if NET7_0_OR_GREATER +#if NET [NativeMarshalling(typeof(Marshaller))] #endif [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] @@ -49,7 +49,7 @@ internal struct SEC_WINNT_AUTH_IDENTITY_EX public string packageList; public int packageListLength; -#if NET7_0_OR_GREATER +#if NET [CustomMarshaller(typeof(SEC_WINNT_AUTH_IDENTITY_EX), MarshalMode.ManagedToUnmanagedIn, typeof(Marshaller))] internal static class Marshaller { @@ -176,7 +176,7 @@ internal struct LDAP_TIMEVAL public int tv_usec; } -#if NET7_0_OR_GREATER +#if NET [NativeMarshalling(typeof(PinningMarshaller))] #endif [StructLayout(LayoutKind.Sequential)] @@ -185,7 +185,7 @@ internal sealed class BerVal public int bv_len; public IntPtr bv_val = IntPtr.Zero; -#if NET7_0_OR_GREATER +#if NET [CustomMarshaller(typeof(BerVal), MarshalMode.ManagedToUnmanagedIn, typeof(PinningMarshaller))] internal static unsafe class PinningMarshaller { @@ -207,7 +207,7 @@ internal sealed class LdapControl public LdapControl() { } } -#if NET7_0_OR_GREATER +#if NET [NativeMarshalling(typeof(Marshaller))] #endif [StructLayout(LayoutKind.Sequential)] @@ -217,7 +217,7 @@ internal struct LdapReferralCallback public QUERYFORCONNECTIONInternal query; public NOTIFYOFNEWCONNECTIONInternal notify; public DEREFERENCECONNECTIONInternal dereference; -#if NET7_0_OR_GREATER +#if NET public static readonly unsafe int Size = sizeof(Marshaller.MarshalValue.Native); [CustomMarshaller(typeof(LdapReferralCallback), MarshalMode.ManagedToUnmanagedIn, typeof(MarshalValue))] diff --git a/src/libraries/Common/src/Interop/Interop.Odbc.cs b/src/libraries/Common/src/Interop/Interop.Odbc.cs index 250ef4371298b3..3e751856262025 100644 --- a/src/libraries/Common/src/Interop/Interop.Odbc.cs +++ b/src/libraries/Common/src/Interop/Interop.Odbc.cs @@ -5,7 +5,7 @@ using System.Data.Odbc; using System.Runtime.ConstrainedExecution; using System.Runtime.InteropServices; -#if NET7_0_OR_GREATER +#if NET using System.Runtime.InteropServices.Marshalling; #endif using System.Runtime.Versioning; @@ -38,7 +38,7 @@ internal static partial ODBC32.SQLRETURN SQLAllocHandle( /*SQLUSMALLINT*/ushort ColumnNumber, /*SQLSMALLINT*/ODBC32.SQL_C TargetType, /*SQLPOINTER*/ -#if NET7_0_OR_GREATER +#if NET [MarshalUsing(typeof(HandleRefMarshaller))] #endif HandleRef TargetValue, @@ -64,13 +64,13 @@ internal static partial ODBC32.SQLRETURN SQLBindCol( /*SQLULEN*/IntPtr cbColDef, /*SQLSMALLINT*/IntPtr ibScale, /*SQLPOINTER*/ -#if NET7_0_OR_GREATER +#if NET [MarshalUsing(typeof(HandleRefMarshaller))] #endif HandleRef rgbValue, /*SQLLEN*/IntPtr BufferLength, /*SQLLEN* */ -#if NET7_0_OR_GREATER +#if NET [MarshalUsing(typeof(HandleRefMarshaller))] #endif HandleRef StrLen_or_Ind); @@ -326,7 +326,7 @@ internal static partial ODBC32.SQLRETURN SQLSetConnectAttrW( /*SQLSMALLINT*/short ColumnNumber, /*SQLSMALLINT*/ODBC32.SQL_DESC FieldIdentifier, /*SQLPOINTER*/ -#if NET7_0_OR_GREATER +#if NET [MarshalUsing(typeof(HandleRefMarshaller))] #endif HandleRef CharacterAttribute, diff --git a/src/libraries/Common/src/Interop/Windows/CryptUI/Interop.CryptUIDlgCertificate.cs b/src/libraries/Common/src/Interop/Windows/CryptUI/Interop.CryptUIDlgCertificate.cs index e58a0b497dc412..97b5d4bba72617 100644 --- a/src/libraries/Common/src/Interop/Windows/CryptUI/Interop.CryptUIDlgCertificate.cs +++ b/src/libraries/Common/src/Interop/Windows/CryptUI/Interop.CryptUIDlgCertificate.cs @@ -4,7 +4,7 @@ using System; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -#if NET7_0_OR_GREATER +#if NET using System.Runtime.InteropServices.Marshalling; #endif using Microsoft.Win32.SafeHandles; @@ -13,7 +13,7 @@ internal static partial class Interop { internal static partial class CryptUI { -#if NET7_0_OR_GREATER +#if NET [NativeMarshalling(typeof(Marshaller))] #else [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] @@ -39,7 +39,7 @@ internal struct CRYPTUI_VIEWCERTIFICATE_STRUCTW internal IntPtr rgPropSheetPages; internal uint nStartPage; -#if NET7_0_OR_GREATER +#if NET [CustomMarshaller(typeof(CRYPTUI_VIEWCERTIFICATE_STRUCTW), MarshalMode.Default, typeof(Marshaller))] public static class Marshaller { @@ -127,7 +127,7 @@ public CRYPTUI_VIEWCERTIFICATE_STRUCTW ToManaged() #endif } -#if NET7_0_OR_GREATER +#if NET [NativeMarshalling(typeof(Marshaller))] #else [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] @@ -151,7 +151,7 @@ internal struct CRYPTUI_SELECTCERTIFICATE_STRUCTW internal IntPtr rgPropSheetPages; internal IntPtr hSelectedCertStore; -#if NET7_0_OR_GREATER +#if NET [CustomMarshaller(typeof(CRYPTUI_SELECTCERTIFICATE_STRUCTW), MarshalMode.Default, typeof(Marshaller))] public static class Marshaller { diff --git a/src/libraries/Common/src/Interop/Windows/Gdi32/Interop.AbortDoc.cs b/src/libraries/Common/src/Interop/Windows/Gdi32/Interop.AbortDoc.cs index cca83bef74b6a4..0326ead026c334 100644 --- a/src/libraries/Common/src/Interop/Windows/Gdi32/Interop.AbortDoc.cs +++ b/src/libraries/Common/src/Interop/Windows/Gdi32/Interop.AbortDoc.cs @@ -2,7 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Runtime.InteropServices; -#if NET7_0_OR_GREATER +#if NET using System.Runtime.InteropServices.Marshalling; #endif @@ -12,7 +12,7 @@ internal static partial class Gdi32 { [LibraryImport(Libraries.Gdi32, SetLastError = true)] internal static partial int AbortDoc( -#if NET7_0_OR_GREATER +#if NET [MarshalUsing(typeof(HandleRefMarshaller))] #endif HandleRef hDC); diff --git a/src/libraries/Common/src/Interop/Windows/Gdi32/Interop.CreateCompatibleBitmap.cs b/src/libraries/Common/src/Interop/Windows/Gdi32/Interop.CreateCompatibleBitmap.cs index e051d8f8d70055..fdfc84cddf583c 100644 --- a/src/libraries/Common/src/Interop/Windows/Gdi32/Interop.CreateCompatibleBitmap.cs +++ b/src/libraries/Common/src/Interop/Windows/Gdi32/Interop.CreateCompatibleBitmap.cs @@ -3,7 +3,7 @@ using System; using System.Runtime.InteropServices; -#if NET7_0_OR_GREATER +#if NET using System.Runtime.InteropServices.Marshalling; #endif @@ -13,7 +13,7 @@ internal static partial class Gdi32 { [LibraryImport(Libraries.Gdi32, SetLastError = true)] internal static partial IntPtr CreateCompatibleBitmap( -#if NET7_0_OR_GREATER +#if NET [MarshalUsing(typeof(HandleRefMarshaller))] #endif HandleRef hDC, int width, int height); diff --git a/src/libraries/Common/src/Interop/Windows/Gdi32/Interop.CreateDIBSection.cs b/src/libraries/Common/src/Interop/Windows/Gdi32/Interop.CreateDIBSection.cs index ca024801b4287e..2654d0e653ad19 100644 --- a/src/libraries/Common/src/Interop/Windows/Gdi32/Interop.CreateDIBSection.cs +++ b/src/libraries/Common/src/Interop/Windows/Gdi32/Interop.CreateDIBSection.cs @@ -3,7 +3,7 @@ using System; using System.Runtime.InteropServices; -#if NET7_0_OR_GREATER +#if NET using System.Runtime.InteropServices.Marshalling; #endif @@ -13,7 +13,7 @@ internal static partial class Gdi32 { [LibraryImport(Libraries.Gdi32, SetLastError = true)] internal static partial IntPtr CreateDIBSection( -#if NET7_0_OR_GREATER +#if NET [MarshalUsing(typeof(HandleRefMarshaller))] #endif HandleRef hdc, ref BITMAPINFO_FLAT bmi, int iUsage, ref IntPtr ppvBits, IntPtr hSection, int dwOffset); diff --git a/src/libraries/Common/src/Interop/Windows/Gdi32/Interop.DEVMODE.cs b/src/libraries/Common/src/Interop/Windows/Gdi32/Interop.DEVMODE.cs index aa26afa85665fb..bb0fa59f771279 100644 --- a/src/libraries/Common/src/Interop/Windows/Gdi32/Interop.DEVMODE.cs +++ b/src/libraries/Common/src/Interop/Windows/Gdi32/Interop.DEVMODE.cs @@ -3,7 +3,7 @@ using System; using System.Runtime.InteropServices; -#if NET7_0_OR_GREATER +#if NET using System.Runtime.InteropServices.Marshalling; #endif diff --git a/src/libraries/Common/src/Interop/Windows/Gdi32/Interop.EndDoc.cs b/src/libraries/Common/src/Interop/Windows/Gdi32/Interop.EndDoc.cs index b65d8106b34392..2bd8ad72416341 100644 --- a/src/libraries/Common/src/Interop/Windows/Gdi32/Interop.EndDoc.cs +++ b/src/libraries/Common/src/Interop/Windows/Gdi32/Interop.EndDoc.cs @@ -2,7 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Runtime.InteropServices; -#if NET7_0_OR_GREATER +#if NET using System.Runtime.InteropServices.Marshalling; #endif @@ -12,7 +12,7 @@ internal static partial class Gdi32 { [LibraryImport(Libraries.Gdi32, SetLastError = true)] internal static partial int EndDoc( -#if NET7_0_OR_GREATER +#if NET [MarshalUsing(typeof(HandleRefMarshaller))] #endif HandleRef hDC); diff --git a/src/libraries/Common/src/Interop/Windows/Gdi32/Interop.EndPage.cs b/src/libraries/Common/src/Interop/Windows/Gdi32/Interop.EndPage.cs index f09232b01fbacc..0349c5044ba194 100644 --- a/src/libraries/Common/src/Interop/Windows/Gdi32/Interop.EndPage.cs +++ b/src/libraries/Common/src/Interop/Windows/Gdi32/Interop.EndPage.cs @@ -2,7 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Runtime.InteropServices; -#if NET7_0_OR_GREATER +#if NET using System.Runtime.InteropServices.Marshalling; #endif @@ -12,7 +12,7 @@ internal static partial class Gdi32 { [LibraryImport(Libraries.Gdi32, SetLastError = true)] internal static partial int EndPage( -#if NET7_0_OR_GREATER +#if NET [MarshalUsing(typeof(HandleRefMarshaller))] #endif HandleRef hDC); diff --git a/src/libraries/Common/src/Interop/Windows/Gdi32/Interop.ExtEscape.cs b/src/libraries/Common/src/Interop/Windows/Gdi32/Interop.ExtEscape.cs index 449ba1b934b333..6ade151f8b0660 100644 --- a/src/libraries/Common/src/Interop/Windows/Gdi32/Interop.ExtEscape.cs +++ b/src/libraries/Common/src/Interop/Windows/Gdi32/Interop.ExtEscape.cs @@ -2,7 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Runtime.InteropServices; -#if NET7_0_OR_GREATER +#if NET using System.Runtime.InteropServices.Marshalling; #endif @@ -16,14 +16,14 @@ internal static partial class Gdi32 [LibraryImport(Libraries.Gdi32, SetLastError = true)] internal static partial int ExtEscape( -#if NET7_0_OR_GREATER +#if NET [MarshalUsing(typeof(HandleRefMarshaller))] #endif HandleRef hDC, int nEscape, int cbInput, ref int inData, int cbOutput, out int outData); [LibraryImport(Libraries.Gdi32, SetLastError = true)] internal static partial int ExtEscape( -#if NET7_0_OR_GREATER +#if NET [MarshalUsing(typeof(HandleRefMarshaller))] #endif HandleRef hDC, int nEscape, int cbInput, byte[] inData, int cbOutput, out int outData); diff --git a/src/libraries/Common/src/Interop/Windows/Gdi32/Interop.GetDIBits.cs b/src/libraries/Common/src/Interop/Windows/Gdi32/Interop.GetDIBits.cs index 03cbc74a846d5f..11900ac16602ca 100644 --- a/src/libraries/Common/src/Interop/Windows/Gdi32/Interop.GetDIBits.cs +++ b/src/libraries/Common/src/Interop/Windows/Gdi32/Interop.GetDIBits.cs @@ -3,7 +3,7 @@ using System; using System.Runtime.InteropServices; -#if NET7_0_OR_GREATER +#if NET using System.Runtime.InteropServices.Marshalling; #endif @@ -13,11 +13,11 @@ internal static partial class Gdi32 { [LibraryImport(Libraries.Gdi32)] internal static partial int GetDIBits( -#if NET7_0_OR_GREATER +#if NET [MarshalUsing(typeof(HandleRefMarshaller))] #endif HandleRef hdc, -#if NET7_0_OR_GREATER +#if NET [MarshalUsing(typeof(HandleRefMarshaller))] #endif HandleRef hbm, int arg1, int arg2, IntPtr arg3, ref BITMAPINFO_FLAT bmi, int arg5); diff --git a/src/libraries/Common/src/Interop/Windows/Gdi32/Interop.GetObject.cs b/src/libraries/Common/src/Interop/Windows/Gdi32/Interop.GetObject.cs index 83fcfa6f9d2359..afb88d5bd14a54 100644 --- a/src/libraries/Common/src/Interop/Windows/Gdi32/Interop.GetObject.cs +++ b/src/libraries/Common/src/Interop/Windows/Gdi32/Interop.GetObject.cs @@ -3,7 +3,7 @@ using System; using System.Runtime.InteropServices; -#if NET7_0_OR_GREATER +#if NET using System.Runtime.InteropServices.Marshalling; #endif @@ -13,20 +13,20 @@ internal static partial class Gdi32 { [LibraryImport(Libraries.Gdi32, EntryPoint = "GetObjectW", SetLastError = true)] internal static partial int GetObject( -#if NET7_0_OR_GREATER +#if NET [MarshalUsing(typeof(HandleRefMarshaller))] #endif HandleRef hObject, int nSize, ref BITMAP bm); [LibraryImport(Libraries.Gdi32, EntryPoint = "GetObjectW", SetLastError = true, StringMarshalling = StringMarshalling.Utf16)] internal static partial int GetObject( -#if NET7_0_OR_GREATER +#if NET [MarshalUsing(typeof(HandleRefMarshaller))] #endif HandleRef hObject, int nSize, ref Interop.User32.LOGFONT lf); internal static unsafe int GetObject( -#if NET7_0_OR_GREATER +#if NET [MarshalUsing(typeof(HandleRefMarshaller))] #endif HandleRef hObject, ref Interop.User32.LOGFONT lp) diff --git a/src/libraries/Common/src/Interop/Windows/Gdi32/Interop.GetPaletteEntries.cs b/src/libraries/Common/src/Interop/Windows/Gdi32/Interop.GetPaletteEntries.cs index 4f2f2ed8035918..ab2ad0b6ea33bc 100644 --- a/src/libraries/Common/src/Interop/Windows/Gdi32/Interop.GetPaletteEntries.cs +++ b/src/libraries/Common/src/Interop/Windows/Gdi32/Interop.GetPaletteEntries.cs @@ -2,7 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Runtime.InteropServices; -#if NET7_0_OR_GREATER +#if NET using System.Runtime.InteropServices.Marshalling; #endif @@ -12,7 +12,7 @@ internal static partial class Gdi32 { [LibraryImport(Libraries.Gdi32)] internal static partial uint GetPaletteEntries( -#if NET7_0_OR_GREATER +#if NET [MarshalUsing(typeof(HandleRefMarshaller))] #endif HandleRef hpal, int iStartIndex, int nEntries, byte[] lppe); diff --git a/src/libraries/Common/src/Interop/Windows/Gdi32/Interop.IntersectClipRect.cs b/src/libraries/Common/src/Interop/Windows/Gdi32/Interop.IntersectClipRect.cs index a82d6c5514ed2f..0084bcd6265270 100644 --- a/src/libraries/Common/src/Interop/Windows/Gdi32/Interop.IntersectClipRect.cs +++ b/src/libraries/Common/src/Interop/Windows/Gdi32/Interop.IntersectClipRect.cs @@ -3,7 +3,7 @@ using System; using System.Runtime.InteropServices; -#if NET7_0_OR_GREATER +#if NET using System.Runtime.InteropServices.Marshalling; #endif @@ -13,7 +13,7 @@ internal static partial class Gdi32 { [LibraryImport(Libraries.Gdi32, SetLastError = true)] internal static partial int IntersectClipRect( -#if NET7_0_OR_GREATER +#if NET [MarshalUsing(typeof(HandleRefMarshaller))] #endif HandleRef hDC, int x1, int y1, int x2, int y2); diff --git a/src/libraries/Common/src/Interop/Windows/Gdi32/Interop.ResetDC.cs b/src/libraries/Common/src/Interop/Windows/Gdi32/Interop.ResetDC.cs index 3737f3f46699b1..e26750aa2895f9 100644 --- a/src/libraries/Common/src/Interop/Windows/Gdi32/Interop.ResetDC.cs +++ b/src/libraries/Common/src/Interop/Windows/Gdi32/Interop.ResetDC.cs @@ -3,7 +3,7 @@ using System; using System.Runtime.InteropServices; -#if NET7_0_OR_GREATER +#if NET using System.Runtime.InteropServices.Marshalling; #endif @@ -13,11 +13,11 @@ internal static partial class Gdi32 { [LibraryImport(Libraries.Gdi32, EntryPoint = "ResetDCW", SetLastError = true)] internal static partial IntPtr /*HDC*/ ResetDC( -#if NET7_0_OR_GREATER +#if NET [MarshalUsing(typeof(HandleRefMarshaller))] #endif HandleRef hDC, -#if NET7_0_OR_GREATER +#if NET [MarshalUsing(typeof(HandleRefMarshaller))] #endif HandleRef /*DEVMODE*/ lpDevMode); diff --git a/src/libraries/Common/src/Interop/Windows/Gdi32/Interop.StartDoc.cs b/src/libraries/Common/src/Interop/Windows/Gdi32/Interop.StartDoc.cs index c62da1844b8e6e..8199ff3f217ff3 100644 --- a/src/libraries/Common/src/Interop/Windows/Gdi32/Interop.StartDoc.cs +++ b/src/libraries/Common/src/Interop/Windows/Gdi32/Interop.StartDoc.cs @@ -3,7 +3,7 @@ using System; using System.Runtime.InteropServices; -#if NET7_0_OR_GREATER +#if NET using System.Runtime.InteropServices.Marshalling; #endif @@ -13,12 +13,12 @@ internal static partial class Gdi32 { [LibraryImport(Libraries.Gdi32, EntryPoint = "StartDocW", SetLastError = true)] internal static partial int StartDoc( -#if NET7_0_OR_GREATER +#if NET [MarshalUsing(typeof(HandleRefMarshaller))] #endif HandleRef hDC, in DOCINFO lpDocInfo); -#if NET7_0_OR_GREATER +#if NET [NativeMarshalling(typeof(Marshaller))] #endif [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] @@ -32,7 +32,7 @@ internal struct DOCINFO public DOCINFO() { } -#if NET7_0_OR_GREATER +#if NET [CustomMarshaller(typeof(DOCINFO), MarshalMode.ManagedToUnmanagedIn, typeof(Marshaller))] public static class Marshaller { diff --git a/src/libraries/Common/src/Interop/Windows/Gdi32/Interop.StartPage.cs b/src/libraries/Common/src/Interop/Windows/Gdi32/Interop.StartPage.cs index 00ecc844d7e8a3..549151d43337dd 100644 --- a/src/libraries/Common/src/Interop/Windows/Gdi32/Interop.StartPage.cs +++ b/src/libraries/Common/src/Interop/Windows/Gdi32/Interop.StartPage.cs @@ -2,7 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Runtime.InteropServices; -#if NET7_0_OR_GREATER +#if NET using System.Runtime.InteropServices.Marshalling; #endif @@ -12,7 +12,7 @@ internal static partial class Gdi32 { [LibraryImport(Libraries.Gdi32, SetLastError = true)] internal static partial int StartPage( -#if NET7_0_OR_GREATER +#if NET [MarshalUsing(typeof(HandleRefMarshaller))] #endif HandleRef hDC); diff --git a/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.SelectObject.cs b/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.SelectObject.cs index efcc90a00fb256..da8fb34e900af0 100644 --- a/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.SelectObject.cs +++ b/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.SelectObject.cs @@ -3,7 +3,7 @@ using System; using System.Runtime.InteropServices; -#if NET7_0_OR_GREATER +#if NET using System.Runtime.InteropServices.Marshalling; #endif @@ -13,11 +13,11 @@ internal static partial class Kernel32 { [LibraryImport(Libraries.Gdi32, SetLastError = true)] internal static partial IntPtr SelectObject( -#if NET7_0_OR_GREATER +#if NET [MarshalUsing(typeof(HandleRefMarshaller))] #endif HandleRef hdc, -#if NET7_0_OR_GREATER +#if NET [MarshalUsing(typeof(HandleRefMarshaller))] #endif HandleRef obj); diff --git a/src/libraries/Common/src/Interop/Windows/Shell32/Interop.ExtractAssociatedIcon.cs b/src/libraries/Common/src/Interop/Windows/Shell32/Interop.ExtractAssociatedIcon.cs index 6162795d061e19..d71fc5b7a0835a 100644 --- a/src/libraries/Common/src/Interop/Windows/Shell32/Interop.ExtractAssociatedIcon.cs +++ b/src/libraries/Common/src/Interop/Windows/Shell32/Interop.ExtractAssociatedIcon.cs @@ -3,7 +3,7 @@ using System; using System.Runtime.InteropServices; -#if NET7_0_OR_GREATER +#if NET using System.Runtime.InteropServices.Marshalling; #endif @@ -13,7 +13,7 @@ internal static partial class Shell32 { [LibraryImport(Libraries.Shell32, EntryPoint = "ExtractAssociatedIconW")] internal static unsafe partial IntPtr ExtractAssociatedIcon( -#if NET7_0_OR_GREATER +#if NET [MarshalUsing(typeof(HandleRefMarshaller))] #endif HandleRef hInst, char* iconPath, ref int index); diff --git a/src/libraries/Common/src/Interop/Windows/User32/Interop.CopyImage.cs b/src/libraries/Common/src/Interop/Windows/User32/Interop.CopyImage.cs index 4211c156c36552..b971b37309311e 100644 --- a/src/libraries/Common/src/Interop/Windows/User32/Interop.CopyImage.cs +++ b/src/libraries/Common/src/Interop/Windows/User32/Interop.CopyImage.cs @@ -3,7 +3,7 @@ using System; using System.Runtime.InteropServices; -#if NET7_0_OR_GREATER +#if NET using System.Runtime.InteropServices.Marshalling; #endif @@ -13,7 +13,7 @@ internal static partial class User32 { [LibraryImport(Libraries.User32, SetLastError = true)] internal static partial IntPtr CopyImage( -#if NET7_0_OR_GREATER +#if NET [MarshalUsing(typeof(HandleRefMarshaller))] #endif HandleRef hImage, int uType, int cxDesired, int cyDesired, int fuFlags); diff --git a/src/libraries/Common/src/Interop/Windows/User32/Interop.CreateIconFromResourceEx.cs b/src/libraries/Common/src/Interop/Windows/User32/Interop.CreateIconFromResourceEx.cs index a295619f2ac4a3..9c11ee7eba900b 100644 --- a/src/libraries/Common/src/Interop/Windows/User32/Interop.CreateIconFromResourceEx.cs +++ b/src/libraries/Common/src/Interop/Windows/User32/Interop.CreateIconFromResourceEx.cs @@ -3,7 +3,7 @@ using System; using System.Runtime.InteropServices; -#if NET7_0_OR_GREATER +#if NET using System.Runtime.InteropServices.Marshalling; #endif diff --git a/src/libraries/Common/src/Interop/Windows/User32/Interop.DestroyIcon.cs b/src/libraries/Common/src/Interop/Windows/User32/Interop.DestroyIcon.cs index 1528c6ae181eb3..782dbcec0e7f4c 100644 --- a/src/libraries/Common/src/Interop/Windows/User32/Interop.DestroyIcon.cs +++ b/src/libraries/Common/src/Interop/Windows/User32/Interop.DestroyIcon.cs @@ -3,7 +3,7 @@ using System; using System.Runtime.InteropServices; -#if NET7_0_OR_GREATER +#if NET using System.Runtime.InteropServices.Marshalling; #endif @@ -14,7 +14,7 @@ internal static partial class User32 [LibraryImport(Libraries.User32, SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] internal static partial bool DestroyIcon( -#if NET7_0_OR_GREATER +#if NET [MarshalUsing(typeof(HandleRefMarshaller))] #endif HandleRef hIcon); diff --git a/src/libraries/Common/src/Interop/Windows/User32/Interop.DrawIconEx.cs b/src/libraries/Common/src/Interop/Windows/User32/Interop.DrawIconEx.cs index 6ac69016bde602..9c0a0bfee89ea3 100644 --- a/src/libraries/Common/src/Interop/Windows/User32/Interop.DrawIconEx.cs +++ b/src/libraries/Common/src/Interop/Windows/User32/Interop.DrawIconEx.cs @@ -3,7 +3,7 @@ using System; using System.Runtime.InteropServices; -#if NET7_0_OR_GREATER +#if NET using System.Runtime.InteropServices.Marshalling; #endif @@ -14,15 +14,15 @@ internal static partial class User32 [LibraryImport(Libraries.User32, SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] internal static partial bool DrawIconEx( -#if NET7_0_OR_GREATER +#if NET [MarshalUsing(typeof(HandleRefMarshaller))] #endif HandleRef hDC, int x, int y, -#if NET7_0_OR_GREATER +#if NET [MarshalUsing(typeof(HandleRefMarshaller))] #endif HandleRef hIcon, int width, int height, int iStepIfAniCursor, -#if NET7_0_OR_GREATER +#if NET [MarshalUsing(typeof(HandleRefMarshaller))] #endif HandleRef hBrushFlickerFree, int diFlags); diff --git a/src/libraries/Common/src/Interop/Windows/User32/Interop.GetIconInfo.cs b/src/libraries/Common/src/Interop/Windows/User32/Interop.GetIconInfo.cs index e97f54e2e8f6ee..faa505574e6b8c 100644 --- a/src/libraries/Common/src/Interop/Windows/User32/Interop.GetIconInfo.cs +++ b/src/libraries/Common/src/Interop/Windows/User32/Interop.GetIconInfo.cs @@ -3,7 +3,7 @@ using System; using System.Runtime.InteropServices; -#if NET7_0_OR_GREATER +#if NET using System.Runtime.InteropServices.Marshalling; #endif @@ -14,7 +14,7 @@ internal static partial class User32 [LibraryImport(Libraries.User32, SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] internal static partial bool GetIconInfo( -#if NET7_0_OR_GREATER +#if NET [MarshalUsing(typeof(HandleRefMarshaller))] #endif HandleRef hIcon, ref ICONINFO info); diff --git a/src/libraries/Common/src/Interop/Windows/User32/Interop.GetSystemMetrics.cs b/src/libraries/Common/src/Interop/Windows/User32/Interop.GetSystemMetrics.cs index 761e69a4a2c829..4232c4348719e9 100644 --- a/src/libraries/Common/src/Interop/Windows/User32/Interop.GetSystemMetrics.cs +++ b/src/libraries/Common/src/Interop/Windows/User32/Interop.GetSystemMetrics.cs @@ -3,7 +3,7 @@ using System; using System.Runtime.InteropServices; -#if NET7_0_OR_GREATER +#if NET using System.Runtime.InteropServices.Marshalling; #endif diff --git a/src/libraries/Common/src/Interop/Windows/User32/Interop.LoadIcon.cs b/src/libraries/Common/src/Interop/Windows/User32/Interop.LoadIcon.cs index f391366d89b125..378129442bf185 100644 --- a/src/libraries/Common/src/Interop/Windows/User32/Interop.LoadIcon.cs +++ b/src/libraries/Common/src/Interop/Windows/User32/Interop.LoadIcon.cs @@ -3,7 +3,7 @@ using System; using System.Runtime.InteropServices; -#if NET7_0_OR_GREATER +#if NET using System.Runtime.InteropServices.Marshalling; #endif @@ -13,7 +13,7 @@ internal static partial class User32 { [LibraryImport(Libraries.User32, EntryPoint = "LoadIconW", SetLastError = true)] internal static partial IntPtr LoadIcon( -#if NET7_0_OR_GREATER +#if NET [MarshalUsing(typeof(HandleRefMarshaller))] #endif HandleRef hInst, IntPtr iconId); diff --git a/src/libraries/Common/src/Interop/Windows/WinHttp/Interop.winhttp.cs b/src/libraries/Common/src/Interop/Windows/WinHttp/Interop.winhttp.cs index 7e1010013c35d5..69457b97300730 100644 --- a/src/libraries/Common/src/Interop/Windows/WinHttp/Interop.winhttp.cs +++ b/src/libraries/Common/src/Interop/Windows/WinHttp/Interop.winhttp.cs @@ -3,7 +3,7 @@ using System; using System.Runtime.InteropServices; -#if NET7_0_OR_GREATER +#if NET using System.Runtime.InteropServices.Marshalling; #endif using System.Text; @@ -45,7 +45,7 @@ public static partial SafeWinHttpHandle WinHttpOpenRequest( [return: MarshalAs(UnmanagedType.Bool)] public static partial bool WinHttpAddRequestHeaders( SafeWinHttpHandle requestHandle, -#if NET7_0_OR_GREATER +#if NET [MarshalUsing(typeof(SimpleStringBufferMarshaller))] StringBuilder headers, #else #pragma warning disable CA1838 // Uses pooled StringBuilder @@ -55,7 +55,7 @@ public static partial bool WinHttpAddRequestHeaders( uint headersLength, uint modifiers); -#if NET7_0_OR_GREATER +#if NET [CustomMarshaller(typeof(StringBuilder), MarshalMode.ManagedToUnmanagedIn, typeof(SimpleStringBufferMarshaller))] private static unsafe class SimpleStringBufferMarshaller { diff --git a/src/libraries/Common/src/Interop/Windows/WinHttp/Interop.winhttp_types.cs b/src/libraries/Common/src/Interop/Windows/WinHttp/Interop.winhttp_types.cs index 1cbdfa79d5962a..e76fa9b67e5bcb 100644 --- a/src/libraries/Common/src/Interop/Windows/WinHttp/Interop.winhttp_types.cs +++ b/src/libraries/Common/src/Interop/Windows/WinHttp/Interop.winhttp_types.cs @@ -3,7 +3,7 @@ using System; using System.Runtime.InteropServices; -#if NET7_0_OR_GREATER +#if NET using System.Runtime.InteropServices.Marshalling; #endif using System.Text; @@ -247,7 +247,7 @@ public delegate void WINHTTP_STATUS_CALLBACK( IntPtr statusInformation, uint statusInformationLength); -#if NET7_0_OR_GREATER +#if NET [NativeMarshalling(typeof(Marshaller))] #endif [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] @@ -261,7 +261,7 @@ public struct WINHTTP_AUTOPROXY_OPTIONS public uint Reserved2; [MarshalAs(UnmanagedType.Bool)] public bool AutoLoginIfChallenged; -#if NET7_0_OR_GREATER +#if NET [CustomMarshaller(typeof(WINHTTP_AUTOPROXY_OPTIONS), MarshalMode.Default, typeof(Marshaller))] public static class Marshaller { diff --git a/src/libraries/Common/src/Interop/Windows/WinMm/Interop.waveOutGetDevCaps.cs b/src/libraries/Common/src/Interop/Windows/WinMm/Interop.waveOutGetDevCaps.cs index a9ebcba2950c55..954101a9c3cbee 100644 --- a/src/libraries/Common/src/Interop/Windows/WinMm/Interop.waveOutGetDevCaps.cs +++ b/src/libraries/Common/src/Interop/Windows/WinMm/Interop.waveOutGetDevCaps.cs @@ -3,7 +3,7 @@ using System; using System.Runtime.InteropServices; -#if NET7_0_OR_GREATER +#if NET using System.Runtime.InteropServices.Marshalling; #endif @@ -12,7 +12,7 @@ internal static partial class Interop internal static partial class WinMM { #pragma warning disable CA1823 // unused fields -#if NET7_0_OR_GREATER +#if NET [NativeMarshalling(typeof(Marshaller))] #endif internal struct WAVEOUTCAPS @@ -27,7 +27,7 @@ internal struct WAVEOUTCAPS private ushort wChannels; private ushort wReserved1; private ushort dwSupport; -#if NET7_0_OR_GREATER +#if NET [CustomMarshaller(typeof(WAVEOUTCAPS), MarshalMode.Default, typeof(Marshaller))] public static class Marshaller { diff --git a/src/libraries/Common/src/Interop/Windows/Winspool/Interop.DocumentProperties.cs b/src/libraries/Common/src/Interop/Windows/Winspool/Interop.DocumentProperties.cs index bf54cfb1b5b90c..8e7b6ce0c9d763 100644 --- a/src/libraries/Common/src/Interop/Windows/Winspool/Interop.DocumentProperties.cs +++ b/src/libraries/Common/src/Interop/Windows/Winspool/Interop.DocumentProperties.cs @@ -3,7 +3,7 @@ using System; using System.Runtime.InteropServices; -#if NET7_0_OR_GREATER +#if NET using System.Runtime.InteropServices.Marshalling; #endif @@ -13,26 +13,26 @@ internal static partial class Winspool { [LibraryImport(Libraries.Winspool, EntryPoint = "DocumentPropertiesW", SetLastError = true, StringMarshalling = StringMarshalling.Utf16)] internal static partial int DocumentProperties( -#if NET7_0_OR_GREATER +#if NET [MarshalUsing(typeof(HandleRefMarshaller))] #endif HandleRef hwnd, -#if NET7_0_OR_GREATER +#if NET [MarshalUsing(typeof(HandleRefMarshaller))] #endif HandleRef hPrinter, string pDeviceName, IntPtr /*DEVMODE*/ pDevModeOutput, -#if NET7_0_OR_GREATER +#if NET [MarshalUsing(typeof(HandleRefMarshaller))] #endif HandleRef /*DEVMODE*/ pDevModeInput, int fMode); [LibraryImport(Libraries.Winspool, EntryPoint = "DocumentPropertiesW", SetLastError = true, StringMarshalling = StringMarshalling.Utf16)] internal static partial int DocumentProperties( -#if NET7_0_OR_GREATER +#if NET [MarshalUsing(typeof(HandleRefMarshaller))] #endif HandleRef hwnd, -#if NET7_0_OR_GREATER +#if NET [MarshalUsing(typeof(HandleRefMarshaller))] #endif HandleRef hPrinter, string pDeviceName, IntPtr /*DEVMODE*/ pDevModeOutput, IntPtr /*DEVMODE*/ pDevModeInput, int fMode); diff --git a/src/libraries/Common/src/Interop/Windows/Winspool/Interop.EnumPrinters.cs b/src/libraries/Common/src/Interop/Windows/Winspool/Interop.EnumPrinters.cs index ca967e11d16d86..baeed522bb0c82 100644 --- a/src/libraries/Common/src/Interop/Windows/Winspool/Interop.EnumPrinters.cs +++ b/src/libraries/Common/src/Interop/Windows/Winspool/Interop.EnumPrinters.cs @@ -3,7 +3,7 @@ using System; using System.Runtime.InteropServices; -#if NET7_0_OR_GREATER +#if NET using System.Runtime.InteropServices.Marshalling; #endif diff --git a/src/libraries/Common/src/System/CodeDom/CodeTypeReference.cs b/src/libraries/Common/src/System/CodeDom/CodeTypeReference.cs index 615d6017e37e37..cb75ff887f6871 100644 --- a/src/libraries/Common/src/System/CodeDom/CodeTypeReference.cs +++ b/src/libraries/Common/src/System/CodeDom/CodeTypeReference.cs @@ -42,7 +42,7 @@ public CodeTypeReference() public CodeTypeReference(Type type) { -#if NET5_0_OR_GREATER +#if NET ArgumentNullException.ThrowIfNull(type); #else if (type is null) @@ -271,7 +271,7 @@ private void Initialize(string? typeName, CodeTypeReferenceOptions options) } // Now see if we have some arity. baseType could be null if this is an array type. -#if NET5_0_OR_GREATER +#if NET if (_baseType != null && _baseType.Contains('`')) // string.Contains(char) is .NetCore2.1+ specific #else if (_baseType != null && _baseType.IndexOf('`') != -1) // string.Contains(char) is .NetCore2.1+ specific diff --git a/src/libraries/Common/src/System/CodeDom/CodeTypeReferenceCollection.cs b/src/libraries/Common/src/System/CodeDom/CodeTypeReferenceCollection.cs index 21b2ae857366ac..55119bc720664b 100644 --- a/src/libraries/Common/src/System/CodeDom/CodeTypeReferenceCollection.cs +++ b/src/libraries/Common/src/System/CodeDom/CodeTypeReferenceCollection.cs @@ -41,7 +41,7 @@ public CodeTypeReference this[int index] public void AddRange(CodeTypeReference[] value) { -#if NET5_0_OR_GREATER +#if NET ArgumentNullException.ThrowIfNull(value); #else if (value is null) @@ -58,7 +58,7 @@ public void AddRange(CodeTypeReference[] value) public void AddRange(CodeTypeReferenceCollection value) { -#if NET5_0_OR_GREATER +#if NET ArgumentNullException.ThrowIfNull(value); #else if (value is null) diff --git a/src/libraries/Common/src/System/Data/Common/DbConnectionOptions.Common.cs b/src/libraries/Common/src/System/Data/Common/DbConnectionOptions.Common.cs index 936c81c094e45d..da3b254f99eb25 100644 --- a/src/libraries/Common/src/System/Data/Common/DbConnectionOptions.Common.cs +++ b/src/libraries/Common/src/System/Data/Common/DbConnectionOptions.Common.cs @@ -50,7 +50,7 @@ internal partial class DbConnectionOptions private static readonly Regex s_connectionStringRegex = CreateConnectionStringRegex(); private static readonly Regex s_connectionStringRegexOdbc = CreateConnectionStringRegexOdbc(); -#if NET7_0_OR_GREATER +#if NET [GeneratedRegex(ConnectionStringPattern, RegexOptions.ExplicitCapture)] private static partial Regex CreateConnectionStringRegex(); @@ -67,7 +67,7 @@ internal partial class DbConnectionOptions private static readonly Regex s_connectionStringQuoteValueRegex = CreateConnectionStringQuoteValueRegex(); // generally do not quote the value if it matches the pattern private static readonly Regex s_connectionStringQuoteOdbcValueRegex = CreateConnectionStringQuoteOdbcValueRegex(); // do not quote odbc value if it matches this pattern -#if NET7_0_OR_GREATER +#if NET [GeneratedRegex("^(?![;\\s])[^\\p{Cc}]+(? public static IAsyncResult Begin(Task task, AsyncCallback? callback, object? state) { -#if NET6_0_OR_GREATER +#if NET ArgumentNullException.ThrowIfNull(task); #else if (task is null) @@ -68,7 +68,7 @@ public static TResult End(IAsyncResult asyncResult) => /// was not produced by a call to . public static Task Unwrap(IAsyncResult asyncResult) { -#if NET6_0_OR_GREATER +#if NET ArgumentNullException.ThrowIfNull(asyncResult); #else if (asyncResult is null) @@ -97,7 +97,7 @@ public static Task Unwrap(IAsyncResult asyncResult) /// public static Task Unwrap(IAsyncResult asyncResult) { -#if NET6_0_OR_GREATER +#if NET ArgumentNullException.ThrowIfNull(asyncResult); #else if (asyncResult is null) diff --git a/src/libraries/Common/src/System/ThrowHelper.cs b/src/libraries/Common/src/System/ThrowHelper.cs index 4257c05891e32c..098b8321492764 100644 --- a/src/libraries/Common/src/System/ThrowHelper.cs +++ b/src/libraries/Common/src/System/ThrowHelper.cs @@ -15,7 +15,7 @@ internal static partial class ThrowHelper /// The reference type argument to validate as non-null. /// The name of the parameter with which corresponds. internal static void ThrowIfNull( -#if NETCOREAPP3_0_OR_GREATER +#if NET [NotNull] #endif object? argument, @@ -27,7 +27,7 @@ internal static void ThrowIfNull( } } -#if NETCOREAPP3_0_OR_GREATER +#if NET [DoesNotReturn] #endif private static void Throw(string? paramName) => throw new ArgumentNullException(paramName); @@ -40,17 +40,17 @@ internal static void ThrowIfNull( /// The name of the parameter being checked. /// The original value of . [MethodImpl(MethodImplOptions.AggressiveInlining)] -#if NETCOREAPP3_0_OR_GREATER +#if NET [return: NotNull] #endif public static string IfNullOrWhitespace( -#if NETCOREAPP3_0_OR_GREATER +#if NET [NotNull] #endif string? argument, [CallerArgumentExpression(nameof(argument))] string paramName = "") { -#if !NETCOREAPP3_1_OR_GREATER +#if !NET if (argument == null) { throw new ArgumentNullException(paramName); @@ -74,7 +74,7 @@ public static string IfNullOrWhitespace( } } -#if !NETCOREAPP3_0_OR_GREATER +#if !NET namespace System.Runtime.CompilerServices { [AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)] diff --git a/src/libraries/Common/tests/TestUtilities/System/AssertExtensions.cs b/src/libraries/Common/tests/TestUtilities/System/AssertExtensions.cs index 232c05afb8d271..0d658dae016cc7 100644 --- a/src/libraries/Common/tests/TestUtilities/System/AssertExtensions.cs +++ b/src/libraries/Common/tests/TestUtilities/System/AssertExtensions.cs @@ -5,7 +5,7 @@ using System.Linq; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -#if NET6_0_OR_GREATER +#if NET using System.Runtime.Intrinsics; #endif using System.Threading; @@ -710,7 +710,7 @@ static unsafe bool IsPositiveZero(double value) return (*(ulong*)(&value)) == 0x0000000000000000; } -#if NET6_0_OR_GREATER +#if NET static unsafe bool IsNegativeZero(Half value) { return (*(ushort*)(&value)) == 0x8000; @@ -780,7 +780,7 @@ static string ToStringPadded(double value) } } -#if NET6_0_OR_GREATER +#if NET static string ToStringPadded(Half value) { if (Half.IsNaN(value)) @@ -1036,7 +1036,7 @@ public static void Equal(float expected, float actual, float variance) } } -#if NET6_0_OR_GREATER +#if NET /// Verifies that two values are equal, within the . /// The expected value /// The value to be compared against @@ -1196,7 +1196,7 @@ static unsafe int SingleToInt32Bits(float value) throw EqualException.ForMismatchedValues(ToStringPadded(expected), ToStringPadded(actual)); } -#if NET6_0_OR_GREATER +#if NET /// Verifies that two values's binary representations are identical. /// The expected value /// The value to be compared against diff --git a/src/libraries/Common/tests/TestUtilities/System/WindowsIdentityFixture.cs b/src/libraries/Common/tests/TestUtilities/System/WindowsIdentityFixture.cs index b4d9be2a52744d..2817d305e6d0a1 100644 --- a/src/libraries/Common/tests/TestUtilities/System/WindowsIdentityFixture.cs +++ b/src/libraries/Common/tests/TestUtilities/System/WindowsIdentityFixture.cs @@ -6,7 +6,7 @@ using System.Linq; using System.Net; using System.Runtime.InteropServices; -#if NET7_0_OR_GREATER +#if NET using System.Runtime.InteropServices.Marshalling; #endif using System.Security.Cryptography; @@ -127,7 +127,7 @@ private void CreateUser() [LibraryImport("netapi32.dll")] internal static partial uint NetUserDel([MarshalAs(UnmanagedType.LPWStr)] string servername, [MarshalAs(UnmanagedType.LPWStr)] string username); -#if NET7_0_OR_GREATER +#if NET [NativeMarshalling(typeof(USER_INFO_1.Marshaller))] #endif [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] @@ -142,7 +142,7 @@ internal struct USER_INFO_1 public uint usri1_flags; public string usri1_script_path; -#if NET7_0_OR_GREATER +#if NET [CustomMarshaller(typeof(USER_INFO_1), MarshalMode.Default, typeof(Marshaller))] public static class Marshaller { diff --git a/src/libraries/Common/tests/TestUtilities/TestEventListener.cs b/src/libraries/Common/tests/TestUtilities/TestEventListener.cs index 3c33bdb633e36b..8cb70ee3cbd8c9 100644 --- a/src/libraries/Common/tests/TestUtilities/TestEventListener.cs +++ b/src/libraries/Common/tests/TestUtilities/TestEventListener.cs @@ -99,7 +99,7 @@ protected override void OnEventSourceCreated(EventSource eventSource) protected override void OnEventWritten(EventWrittenEventArgs eventData) { StringBuilder sb = new StringBuilder(). -#if NETCOREAPP2_2_OR_GREATER || NETSTANDARD2_1_OR_GREATER +#if NET || NETSTANDARD2_1_OR_GREATER Append($"{eventData.TimeStamp:HH:mm:ss.fffffff}[{eventData.EventName}] "); #else Append($"[{eventData.EventName}] "); diff --git a/src/libraries/Microsoft.Extensions.Caching.Abstractions/src/IMemoryCache.cs b/src/libraries/Microsoft.Extensions.Caching.Abstractions/src/IMemoryCache.cs index ccce249b23d958..8388a9f0433eb1 100644 --- a/src/libraries/Microsoft.Extensions.Caching.Abstractions/src/IMemoryCache.cs +++ b/src/libraries/Microsoft.Extensions.Caching.Abstractions/src/IMemoryCache.cs @@ -31,7 +31,7 @@ public interface IMemoryCache : IDisposable /// An object identifying the entry. void Remove(object key); -#if NET6_0_OR_GREATER +#if NET /// /// Gets a snapshot of the cache statistics if available. /// diff --git a/src/libraries/Microsoft.Extensions.Caching.Memory/tests/MemoryCacheGetCurrentStatisticsTests.cs b/src/libraries/Microsoft.Extensions.Caching.Memory/tests/MemoryCacheGetCurrentStatisticsTests.cs index cee6245f3e9c6b..576b7e103aebae 100644 --- a/src/libraries/Microsoft.Extensions.Caching.Memory/tests/MemoryCacheGetCurrentStatisticsTests.cs +++ b/src/libraries/Microsoft.Extensions.Caching.Memory/tests/MemoryCacheGetCurrentStatisticsTests.cs @@ -106,7 +106,7 @@ public void GetCurrentStatistics_UpdateAfterExistingItemExpired_CurrentEstimated } } -#if NET6_0_OR_GREATER +#if NET [Fact] public void GetCurrentStatistics_DIMReturnsNull() { diff --git a/src/libraries/Microsoft.Extensions.FileProviders.Physical/src/PhysicalFilesWatcher.cs b/src/libraries/Microsoft.Extensions.FileProviders.Physical/src/PhysicalFilesWatcher.cs index db0a767573a1e8..eaa53fec71ede1 100644 --- a/src/libraries/Microsoft.Extensions.FileProviders.Physical/src/PhysicalFilesWatcher.cs +++ b/src/libraries/Microsoft.Extensions.FileProviders.Physical/src/PhysicalFilesWatcher.cs @@ -160,7 +160,7 @@ private IChangeToken GetOrAddChangeToken(string pattern) } IChangeToken changeToken; -#if NET5_0_OR_GREATER +#if NET bool isWildCard = pattern.Contains('*'); #else bool isWildCard = pattern.IndexOf('*') != -1; diff --git a/src/libraries/Microsoft.Extensions.Hosting.WindowsServices/src/WindowsServiceHelpers.cs b/src/libraries/Microsoft.Extensions.Hosting.WindowsServices/src/WindowsServiceHelpers.cs index 9de601ddebe7d5..05eed40ff6df48 100644 --- a/src/libraries/Microsoft.Extensions.Hosting.WindowsServices/src/WindowsServiceHelpers.cs +++ b/src/libraries/Microsoft.Extensions.Hosting.WindowsServices/src/WindowsServiceHelpers.cs @@ -28,7 +28,7 @@ private static bool GetIsWindowsService() if ( #if NETFRAMEWORK Environment.OSVersion.Platform != PlatformID.Win32NT -#elif NET5_0_OR_GREATER +#elif NET !OperatingSystem.IsWindows() #else !RuntimeInformation.IsOSPlatform(OSPlatform.Windows) diff --git a/src/libraries/Microsoft.Extensions.Hosting/src/HostBuilder.cs b/src/libraries/Microsoft.Extensions.Hosting/src/HostBuilder.cs index 7a965e0efc85f5..4a9806a2fcd787 100644 --- a/src/libraries/Microsoft.Extensions.Hosting/src/HostBuilder.cs +++ b/src/libraries/Microsoft.Extensions.Hosting/src/HostBuilder.cs @@ -190,11 +190,6 @@ internal static DiagnosticListener LogHostBuilding(HostApplicationBuilder hostAp return diagnosticListener; } -// Remove when https://github.com/dotnet/runtime/pull/78532 is merged and consumed by the used SDK. -#if NET7_0 - [UnconditionalSuppressMessage("AOT", "IL3050:RequiresDynamicCode", - Justification = "DiagnosticSource is used here to pass objects in-memory to code using HostFactoryResolver. This won't require creating new generic types.")] -#endif [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:UnrecognizedReflectionPattern", Justification = "The values being passed into Write are being consumed by the application already.")] private static void Write<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties)] T>( diff --git a/src/libraries/Microsoft.Extensions.Http/ref/Microsoft.Extensions.Http.cs b/src/libraries/Microsoft.Extensions.Http/ref/Microsoft.Extensions.Http.cs index 51891e8ebcf754..8c791124208828 100644 --- a/src/libraries/Microsoft.Extensions.Http/ref/Microsoft.Extensions.Http.cs +++ b/src/libraries/Microsoft.Extensions.Http/ref/Microsoft.Extensions.Http.cs @@ -28,7 +28,7 @@ public static partial class HttpClientBuilderExtensions public static Microsoft.Extensions.DependencyInjection.IHttpClientBuilder RedactLoggedHeaders(this Microsoft.Extensions.DependencyInjection.IHttpClientBuilder builder, System.Func shouldRedactHeaderValue) { throw null; } public static Microsoft.Extensions.DependencyInjection.IHttpClientBuilder RemoveAllLoggers(this Microsoft.Extensions.DependencyInjection.IHttpClientBuilder builder) { throw null; } public static Microsoft.Extensions.DependencyInjection.IHttpClientBuilder SetHandlerLifetime(this Microsoft.Extensions.DependencyInjection.IHttpClientBuilder builder, System.TimeSpan handlerLifetime) { throw null; } -#if NET5_0_OR_GREATER +#if NET [System.Runtime.Versioning.UnsupportedOSPlatformAttribute("browser")] public static Microsoft.Extensions.DependencyInjection.IHttpClientBuilder UseSocketsHttpHandler(this Microsoft.Extensions.DependencyInjection.IHttpClientBuilder builder, System.Action? configureHandler = null) { throw null; } [System.Runtime.Versioning.UnsupportedOSPlatformAttribute("browser")] @@ -64,14 +64,14 @@ public partial interface IHttpClientBuilder string Name { get; } Microsoft.Extensions.DependencyInjection.IServiceCollection Services { get; } } -#if NET5_0_OR_GREATER +#if NET public partial interface ISocketsHttpHandlerBuilder { string Name { get; } Microsoft.Extensions.DependencyInjection.IServiceCollection Services { get; } } #endif -#if NET5_0_OR_GREATER +#if NET public static partial class SocketsHttpHandlerBuilderExtensions { [System.Runtime.Versioning.UnsupportedOSPlatformAttribute("browser")] diff --git a/src/libraries/Microsoft.Extensions.Http/src/DependencyInjection/DefaultSocketsHttpHandlerBuilder.cs b/src/libraries/Microsoft.Extensions.Http/src/DependencyInjection/DefaultSocketsHttpHandlerBuilder.cs index 57b905c0f3e6e0..61986cedfbe1a3 100644 --- a/src/libraries/Microsoft.Extensions.Http/src/DependencyInjection/DefaultSocketsHttpHandlerBuilder.cs +++ b/src/libraries/Microsoft.Extensions.Http/src/DependencyInjection/DefaultSocketsHttpHandlerBuilder.cs @@ -1,7 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -#if NET5_0_OR_GREATER +#if NET namespace Microsoft.Extensions.DependencyInjection { internal sealed class DefaultSocketsHttpHandlerBuilder : ISocketsHttpHandlerBuilder diff --git a/src/libraries/Microsoft.Extensions.Http/src/DependencyInjection/HttpClientBuilderExtensions.cs b/src/libraries/Microsoft.Extensions.Http/src/DependencyInjection/HttpClientBuilderExtensions.cs index a9adb32fc5d84c..758a989be3a8b2 100644 --- a/src/libraries/Microsoft.Extensions.Http/src/DependencyInjection/HttpClientBuilderExtensions.cs +++ b/src/libraries/Microsoft.Extensions.Http/src/DependencyInjection/HttpClientBuilderExtensions.cs @@ -265,7 +265,7 @@ public static IHttpClientBuilder ConfigureHttpMessageHandlerBuilder(this IHttpCl return builder; } -#if NET5_0_OR_GREATER +#if NET /// /// Adds or updates as a primary handler for a named . If provided, /// also adds a delegate that will be used to configure the primary . diff --git a/src/libraries/Microsoft.Extensions.Http/src/DependencyInjection/ISocketsHttpHandlerBuilder.cs b/src/libraries/Microsoft.Extensions.Http/src/DependencyInjection/ISocketsHttpHandlerBuilder.cs index d7509e009c9c47..75333f8d747c71 100644 --- a/src/libraries/Microsoft.Extensions.Http/src/DependencyInjection/ISocketsHttpHandlerBuilder.cs +++ b/src/libraries/Microsoft.Extensions.Http/src/DependencyInjection/ISocketsHttpHandlerBuilder.cs @@ -1,7 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -#if NET5_0_OR_GREATER +#if NET namespace Microsoft.Extensions.DependencyInjection { /// diff --git a/src/libraries/Microsoft.Extensions.Http/src/DependencyInjection/SocketsHttpHandlerBuilderExtensions.cs b/src/libraries/Microsoft.Extensions.Http/src/DependencyInjection/SocketsHttpHandlerBuilderExtensions.cs index 0d56606b742bde..d3bb98c8a11620 100644 --- a/src/libraries/Microsoft.Extensions.Http/src/DependencyInjection/SocketsHttpHandlerBuilderExtensions.cs +++ b/src/libraries/Microsoft.Extensions.Http/src/DependencyInjection/SocketsHttpHandlerBuilderExtensions.cs @@ -1,7 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -#if NET5_0_OR_GREATER +#if NET using System; using System.Net; using System.Net.Http; diff --git a/src/libraries/Microsoft.Extensions.Http/src/Logging/HttpClientLoggerHandler.cs b/src/libraries/Microsoft.Extensions.Http/src/Logging/HttpClientLoggerHandler.cs index 087ec81fbb6cd9..a7aeebe8578f3e 100644 --- a/src/libraries/Microsoft.Extensions.Http/src/Logging/HttpClientLoggerHandler.cs +++ b/src/libraries/Microsoft.Extensions.Http/src/Logging/HttpClientLoggerHandler.cs @@ -61,7 +61,7 @@ protected override async Task SendAsync(HttpRequestMessage } } -#if NET5_0_OR_GREATER +#if NET protected override HttpResponseMessage Send(HttpRequestMessage request, CancellationToken cancellationToken) { ThrowHelper.ThrowIfNull(request); diff --git a/src/libraries/Microsoft.Extensions.Http/src/Logging/LoggingHttpMessageHandler.cs b/src/libraries/Microsoft.Extensions.Http/src/Logging/LoggingHttpMessageHandler.cs index 5056474e9ead2f..e592e7d236fbb4 100644 --- a/src/libraries/Microsoft.Extensions.Http/src/Logging/LoggingHttpMessageHandler.cs +++ b/src/libraries/Microsoft.Extensions.Http/src/Logging/LoggingHttpMessageHandler.cs @@ -62,7 +62,7 @@ async Task Core(HttpRequestMessage request, bool useAsync, var stopwatch = ValueStopwatch.StartNew(); HttpResponseMessage response = useAsync ? await base.SendAsync(request, cancellationToken).ConfigureAwait(false) -#if NET5_0_OR_GREATER +#if NET : base.Send(request, cancellationToken); #else : throw new NotImplementedException("Unreachable code"); @@ -78,7 +78,7 @@ async Task Core(HttpRequestMessage request, bool useAsync, protected override Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) => SendCoreAsync(request, useAsync: true, cancellationToken); -#if NET5_0_OR_GREATER +#if NET /// /// Logs the request to and response from the sent . protected override HttpResponseMessage Send(HttpRequestMessage request, CancellationToken cancellationToken) diff --git a/src/libraries/Microsoft.Extensions.Http/src/Logging/LoggingScopeHttpMessageHandler.cs b/src/libraries/Microsoft.Extensions.Http/src/Logging/LoggingScopeHttpMessageHandler.cs index e170acbfe83c80..1894a005f84a68 100644 --- a/src/libraries/Microsoft.Extensions.Http/src/Logging/LoggingScopeHttpMessageHandler.cs +++ b/src/libraries/Microsoft.Extensions.Http/src/Logging/LoggingScopeHttpMessageHandler.cs @@ -63,7 +63,7 @@ async Task Core(HttpRequestMessage request, bool useAsync, Log.RequestPipelineStart(_logger, request, shouldRedactHeaderValue); HttpResponseMessage response = useAsync ? await base.SendAsync(request, cancellationToken).ConfigureAwait(false) -#if NET5_0_OR_GREATER +#if NET : base.Send(request, cancellationToken); #else : throw new NotImplementedException("Unreachable code"); @@ -80,7 +80,7 @@ async Task Core(HttpRequestMessage request, bool useAsync, protected override Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) => SendCoreAsync(request, useAsync: true, cancellationToken); -#if NET5_0_OR_GREATER +#if NET /// /// Logs the request to and response from the sent . protected override HttpResponseMessage Send(HttpRequestMessage request, CancellationToken cancellationToken) diff --git a/src/libraries/Microsoft.Extensions.Http/tests/Microsoft.Extensions.Http.Tests/Logging/HttpClientLoggerTest.cs b/src/libraries/Microsoft.Extensions.Http/tests/Microsoft.Extensions.Http.Tests/Logging/HttpClientLoggerTest.cs index 6fb8e2dd8f7a98..039ba46b186251 100644 --- a/src/libraries/Microsoft.Extensions.Http/tests/Microsoft.Extensions.Http.Tests/Logging/HttpClientLoggerTest.cs +++ b/src/libraries/Microsoft.Extensions.Http/tests/Microsoft.Extensions.Http.Tests/Logging/HttpClientLoggerTest.cs @@ -156,7 +156,7 @@ private void AssertCounters(TestCountingLogger testLogger, int requestCount, boo } } -#if NET5_0_OR_GREATER +#if NET [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsNetCore))] [InlineData(false, false)] [InlineData(false, true)] @@ -588,7 +588,7 @@ private async Task SendAsyncCore(HttpRequestMessage request } else { -#if NET5_0_OR_GREATER +#if NET return base.Send(request, cancellationToken); #else throw new NotImplementedException("unreachable"); @@ -609,7 +609,7 @@ private async Task SendAsyncCore(HttpRequestMessage request protected override Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) => SendAsyncCore(request, async: true, cancellationToken); -#if NET5_0_OR_GREATER +#if NET protected override HttpResponseMessage Send(HttpRequestMessage request, CancellationToken cancellationToken) => SendAsyncCore(request, async: false, cancellationToken).GetAwaiter().GetResult(); #endif diff --git a/src/libraries/Microsoft.Extensions.Http/tests/Microsoft.Extensions.Http.Tests/Logging/LoggingUriOutputTests.cs b/src/libraries/Microsoft.Extensions.Http/tests/Microsoft.Extensions.Http.Tests/Logging/LoggingUriOutputTests.cs index 8f6ca7a8c4e285..bdd204f709df39 100644 --- a/src/libraries/Microsoft.Extensions.Http/tests/Microsoft.Extensions.Http.Tests/Logging/LoggingUriOutputTests.cs +++ b/src/libraries/Microsoft.Extensions.Http/tests/Microsoft.Extensions.Http.Tests/Logging/LoggingUriOutputTests.cs @@ -91,7 +91,7 @@ public async Task LoggingScopeHttpMessageHandler_LogsAbsoluteUri() Assert.Equal("HTTP GET http://api.example.com/search?term=Western%20Australia", message.Scope.ToString()); } -#if NET5_0_OR_GREATER +#if NET [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNetCore))] public void LoggingHttpMessageHandler_LogsAbsoluteUri_Sync() { diff --git a/src/libraries/Microsoft.Extensions.Http/tests/Microsoft.Extensions.Http.Tests/SocketsHttpHandlerConfigurationTest.cs b/src/libraries/Microsoft.Extensions.Http/tests/Microsoft.Extensions.Http.Tests/SocketsHttpHandlerConfigurationTest.cs index 4473917ff728f0..059557a0784a70 100644 --- a/src/libraries/Microsoft.Extensions.Http/tests/Microsoft.Extensions.Http.Tests/SocketsHttpHandlerConfigurationTest.cs +++ b/src/libraries/Microsoft.Extensions.Http/tests/Microsoft.Extensions.Http.Tests/SocketsHttpHandlerConfigurationTest.cs @@ -1,7 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -#if NET5_0_OR_GREATER +#if NET using System; using System.Collections.Generic; using System.Net; diff --git a/src/libraries/Microsoft.Extensions.Http/tests/Microsoft.Extensions.Http.Tests/TestMessageHandler.cs b/src/libraries/Microsoft.Extensions.Http/tests/Microsoft.Extensions.Http.Tests/TestMessageHandler.cs index 5cbb8eb168f302..6bf2050cbd15c5 100644 --- a/src/libraries/Microsoft.Extensions.Http/tests/Microsoft.Extensions.Http.Tests/TestMessageHandler.cs +++ b/src/libraries/Microsoft.Extensions.Http/tests/Microsoft.Extensions.Http.Tests/TestMessageHandler.cs @@ -26,7 +26,7 @@ protected override Task SendAsync(HttpRequestMessage reques return Task.FromResult(response); } -#if NET5_0_OR_GREATER +#if NET protected override HttpResponseMessage Send(HttpRequestMessage request, CancellationToken cancellationToken) => _responseFactory(request); #endif } diff --git a/src/libraries/Microsoft.Extensions.Options/tests/SourceGenerationTests/EmitterTests.cs b/src/libraries/Microsoft.Extensions.Options/tests/SourceGenerationTests/EmitterTests.cs index af91cab872c88f..1f54faf77d7fef 100644 --- a/src/libraries/Microsoft.Extensions.Options/tests/SourceGenerationTests/EmitterTests.cs +++ b/src/libraries/Microsoft.Extensions.Options/tests/SourceGenerationTests/EmitterTests.cs @@ -24,8 +24,8 @@ public async Task TestEmitter() #pragma warning disable RS1035 // To allow using the File IO APIs inside the analyzer test foreach (var file in Directory.GetFiles("TestClasses")) { -#if NETCOREAPP3_1_OR_GREATER - sources.Add("#define NETCOREAPP3_1_OR_GREATER\n" + File.ReadAllText(file)); +#if NET + sources.Add("#define NET\n" + File.ReadAllText(file)); #else sources.Add(File.ReadAllText(file)); #endif @@ -46,7 +46,7 @@ public async Task TestEmitter() Assert.Empty(d); _ = Assert.Single(r); -#if NETCOREAPP3_1_OR_GREATER +#if NET string baseline = File.ReadAllText(@"Baselines/NetCoreApp/Validators.g.cs"); #else string baseline = File.ReadAllText(@"Baselines/NetFX/Validators.g.cs"); diff --git a/src/libraries/Microsoft.Extensions.Options/tests/SourceGenerationTests/Generated/OptionsValidationTests.cs b/src/libraries/Microsoft.Extensions.Options/tests/SourceGenerationTests/Generated/OptionsValidationTests.cs index 4f9770ce7a17ca..01519b780eba1e 100644 --- a/src/libraries/Microsoft.Extensions.Options/tests/SourceGenerationTests/Generated/OptionsValidationTests.cs +++ b/src/libraries/Microsoft.Extensions.Options/tests/SourceGenerationTests/Generated/OptionsValidationTests.cs @@ -186,7 +186,7 @@ public void RangeAttributeModelDoubleInvalid() [Fact] public void RangeAttributeModelDateValid() { -#if NETCOREAPP3_1_OR_GREATER +#if NET // Setting non-invariant culture to check that // attribute's "ParseLimitsInInvariantCulture" property // was set up correctly in the validator: diff --git a/src/libraries/Microsoft.Extensions.Options/tests/SourceGenerationTests/Generated/Utils.cs b/src/libraries/Microsoft.Extensions.Options/tests/SourceGenerationTests/Generated/Utils.cs index 7412374f18a56f..eb6bf661490995 100644 --- a/src/libraries/Microsoft.Extensions.Options/tests/SourceGenerationTests/Generated/Utils.cs +++ b/src/libraries/Microsoft.Extensions.Options/tests/SourceGenerationTests/Generated/Utils.cs @@ -1,7 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -#if NETCOREAPP3_1_OR_GREATER +#if NET using System.Linq; #endif using Microsoft.Extensions.Options; @@ -15,7 +15,7 @@ public static void VerifyValidateOptionsResult(ValidateOptionsResult vr, int exp { Assert.NotNull(vr); -#if NETCOREAPP3_1_OR_GREATER +#if NET var failures = vr.Failures!.ToArray(); #else var failures = vr.FailureMessage!.Split(';'); diff --git a/src/libraries/Microsoft.Extensions.Options/tests/SourceGenerationTests/TestClasses/Models.cs b/src/libraries/Microsoft.Extensions.Options/tests/SourceGenerationTests/TestClasses/Models.cs index c245ebd783bdcf..bc76114ab62944 100644 --- a/src/libraries/Microsoft.Extensions.Options/tests/SourceGenerationTests/TestClasses/Models.cs +++ b/src/libraries/Microsoft.Extensions.Options/tests/SourceGenerationTests/TestClasses/Models.cs @@ -76,7 +76,7 @@ public class RangeAttributeModelDouble public class RangeAttributeModelDate { -#if NETCOREAPP3_1_OR_GREATER +#if NET [Range(typeof(DateTime), "1/2/2004", "3/4/2004", ParseLimitsInInvariantCulture = true)] #else [Range(typeof(DateTime), "1/2/2004", "3/4/2004")] diff --git a/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/Constants.cs b/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/Constants.cs index 5371a0354aeac6..ed797f8fae7bba 100644 --- a/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/Constants.cs +++ b/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/Constants.cs @@ -61,19 +61,13 @@ public static bool IsKnownComparable() => typeof(T) == typeof(DateTime) || typeof(T) == typeof(DateTimeOffset) || typeof(T) == typeof(Guid) || -#if NETCOREAPP3_0_OR_GREATER +#if NET typeof(T) == typeof(Rune) || -#endif -#if NET5_0_OR_GREATER typeof(T) == typeof(Half) || typeof(T) == typeof(nint) || typeof(T) == typeof(nuint) || -#endif -#if NET6_0_OR_GREATER typeof(T) == typeof(DateOnly) || typeof(T) == typeof(TimeOnly) || -#endif -#if NET7_0_OR_GREATER typeof(T) == typeof(Int128) || typeof(T) == typeof(UInt128) || #endif diff --git a/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/FrozenHashTable.cs b/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/FrozenHashTable.cs index afb4785147391f..2bda7b2c76e70a 100644 --- a/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/FrozenHashTable.cs +++ b/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/FrozenHashTable.cs @@ -159,7 +159,7 @@ private static int CalcNumBuckets(ReadOnlySpan hashCodes, bool hashCodesAre if (!hashCodesAreUnique) { codes = -#if NETCOREAPP2_0_OR_GREATER +#if NET new HashSet(hashCodes.Length); #else new HashSet(); diff --git a/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/FrozenSet.cs b/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/FrozenSet.cs index 50bbdeb18aad64..79acea67bd100c 100644 --- a/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/FrozenSet.cs +++ b/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/FrozenSet.cs @@ -202,7 +202,7 @@ private static FrozenSet CreateFromSet(HashSet source) [DebuggerTypeProxy(typeof(ImmutableEnumerableDebuggerProxy<>))] [DebuggerDisplay("Count = {Count}")] public abstract class FrozenSet : ISet, -#if NET5_0_OR_GREATER +#if NET IReadOnlySet, #endif IReadOnlyCollection, ICollection diff --git a/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/KeyAnalyzer.cs b/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/KeyAnalyzer.cs index 208cf88c6ea62d..0793b3d12f7315 100644 --- a/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/KeyAnalyzer.cs +++ b/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/KeyAnalyzer.cs @@ -64,7 +64,7 @@ private static bool TryUseSubstring(ReadOnlySpan uniqueStrings, bool all new JustifiedCaseInsensitiveSubstringComparer(); HashSet set = new HashSet( -#if NET6_0_OR_GREATER +#if NET uniqueStrings.Length, #endif comparer); diff --git a/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/LengthBuckets.cs b/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/LengthBuckets.cs index 97659c5479365c..626b21a8bf1212 100644 --- a/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/LengthBuckets.cs +++ b/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/String/LengthBuckets.cs @@ -28,7 +28,7 @@ internal static class LengthBuckets } int arraySize = spread * MaxPerLength; -#if NET6_0_OR_GREATER +#if NET if (arraySize > Array.MaxLength) #else if (arraySize > 0X7FFFFFC7) @@ -87,7 +87,7 @@ internal static class LengthBuckets return null; } -#if NET6_0_OR_GREATER +#if NET // We don't need an array with every value initialized to zero if we are just about to overwrite every value anyway. int[] copy = GC.AllocateUninitializedArray(arraySize); Array.Copy(buckets, copy, arraySize); diff --git a/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableArray_1.Builder.cs b/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableArray_1.Builder.cs index 060492a40bd06e..459a3889d30af8 100644 --- a/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableArray_1.Builder.cs +++ b/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableArray_1.Builder.cs @@ -589,7 +589,7 @@ public void RemoveRange(int index, int length) if (index + length < this._count) { -#if NET6_0_OR_GREATER +#if NET if (RuntimeHelpers.IsReferenceOrContainsReferences()) { Array.Clear(_elements, index, length); // Clear the elements so that the gc can reclaim the references. @@ -919,7 +919,7 @@ public int LastIndexOf(T item, int startIndex, int count, IEqualityComparer? /// public void Reverse() { -#if NETCOREAPP2_0_OR_GREATER || NETSTANDARD2_1_OR_GREATER +#if NET || NETSTANDARD2_1_OR_GREATER Array.Reverse(_elements, 0, _count); #else // The non-generic Array.Reverse is not used because it does not perform @@ -963,7 +963,7 @@ public void Sort(Comparison comparison) if (Count > 1) { -#if NET6_0_OR_GREATER +#if NET // MemoryExtensions.Sort is not available in .NET Framework / Standard 2.0. // But the overload with a Comparison argument doesn't allocate. _elements.AsSpan(0, _count).Sort(comparison); diff --git a/src/libraries/System.Collections.Immutable/src/System/Polyfills.cs b/src/libraries/System.Collections.Immutable/src/System/Polyfills.cs index 77f304f46fdcd8..eeb82f0960ccc4 100644 --- a/src/libraries/System.Collections.Immutable/src/System/Polyfills.cs +++ b/src/libraries/System.Collections.Immutable/src/System/Polyfills.cs @@ -6,7 +6,7 @@ namespace System.Collections.Generic { -#if !NETCOREAPP2_0_OR_GREATER +#if !NET internal static class KeyValuePairExtensions { [EditorBrowsable(EditorBrowsableState.Never)] @@ -18,7 +18,7 @@ public static void Deconstruct(this KeyValuePair sou } #endif -#if !NET5_0_OR_GREATER +#if !NET internal interface IReadOnlySet : IReadOnlyCollection { bool Contains(T item); @@ -34,7 +34,7 @@ internal interface IReadOnlySet : IReadOnlyCollection namespace System.Numerics { -#if !NETCOREAPP3_0_OR_GREATER +#if !NET internal static class BitOperations { [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -45,7 +45,7 @@ internal static class BitOperations namespace System.Runtime.CompilerServices { -#if !NETCOREAPP3_0_OR_GREATER +#if !NET [AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)] internal sealed class CallerArgumentExpressionAttribute : Attribute { diff --git a/src/libraries/System.Collections.Immutable/tests/Frozen/FrozenSetTests.cs b/src/libraries/System.Collections.Immutable/tests/Frozen/FrozenSetTests.cs index 2558f9bedcd895..717efc31e45bb3 100644 --- a/src/libraries/System.Collections.Immutable/tests/Frozen/FrozenSetTests.cs +++ b/src/libraries/System.Collections.Immutable/tests/Frozen/FrozenSetTests.cs @@ -297,7 +297,7 @@ private sealed class InvertingComparer : IEqualityComparer private sealed class EmptySet : ISet -#if NET5_0_OR_GREATER +#if NET , IReadOnlySet #endif { diff --git a/src/libraries/System.Configuration.ConfigurationManager/src/System/Configuration/ImplicitMachineConfigHost.cs b/src/libraries/System.Configuration.ConfigurationManager/src/System/Configuration/ImplicitMachineConfigHost.cs index 32403a8950c2c2..195b3ca5ff4a38 100644 --- a/src/libraries/System.Configuration.ConfigurationManager/src/System/Configuration/ImplicitMachineConfigHost.cs +++ b/src/libraries/System.Configuration.ConfigurationManager/src/System/Configuration/ImplicitMachineConfigHost.cs @@ -81,7 +81,7 @@ public override Stream OpenStreamForRead(string streamName)
" + -#if NET7_0_OR_GREATER +#if NET @"
" + #endif @"
diff --git a/src/libraries/System.Data.OleDb/src/DbConnectionOptions.cs b/src/libraries/System.Data.OleDb/src/DbConnectionOptions.cs index 0bb5bde47ea416..81b4ecdc5b7175 100644 --- a/src/libraries/System.Data.OleDb/src/DbConnectionOptions.cs +++ b/src/libraries/System.Data.OleDb/src/DbConnectionOptions.cs @@ -59,7 +59,7 @@ internal partial class DbConnectionOptions private static readonly Regex ConnectionStringRegex = CreateConnectionStringRegex(); private static readonly Regex ConnectionStringRegexOdbc = CreateConnectionStringRegexOdbc(); -#if NET7_0_OR_GREATER +#if NET [GeneratedRegex(ConnectionStringPattern, RegexOptions.ExplicitCapture)] private static partial Regex CreateConnectionStringRegex(); @@ -76,7 +76,7 @@ internal partial class DbConnectionOptions private static readonly Regex ConnectionStringQuoteValueRegex = CreateConnectionStringQuoteValueRegex(); // generally do not quote the value if it matches the pattern private static readonly Regex ConnectionStringQuoteOdbcValueRegex = CreateConnectionStringQuoteOdbcValueRegex(); // do not quote odbc value if it matches this pattern -#if NET7_0_OR_GREATER +#if NET [GeneratedRegex("^(?![;\\s])[^\\p{Cc}]+(? flagsChars = stackalloc char[2]; HexConverter.ToCharsBuffer((byte)((~ActivityTraceFlagsIsSet) & _w3CIdFlags), flagsChars, 0, HexConverter.Casing.Lower); string id = -#if NET6_0_OR_GREATER +#if NET string.Create(null, stackalloc char[128], $"00-{_traceId}-{_spanId}-{flagsChars}"); #else "00-" + _traceId + "-" + _spanId + "-" + flagsChars.ToString(); @@ -258,7 +258,7 @@ public string? ParentId Span flagsChars = stackalloc char[2]; HexConverter.ToCharsBuffer((byte)((~ActivityTraceFlagsIsSet) & _parentTraceFlags), flagsChars, 0, HexConverter.Casing.Lower); string parentId = -#if NET6_0_OR_GREATER +#if NET string.Create(null, stackalloc char[128], $"00-{_traceId}-{_parentSpanId}-{flagsChars}"); #else "00-" + _traceId + "-" + _parentSpanId + "-" + flagsChars.ToString(); diff --git a/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/CounterAggregator.cs b/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/CounterAggregator.cs index b9e3c8d35bca70..4577c16b9b988e 100644 --- a/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/CounterAggregator.cs +++ b/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/CounterAggregator.cs @@ -33,7 +33,7 @@ public override void Update(double value) // Get the delta best associated with the current thread, preferring to use core ID rather than // thread ID to reduce contention. ref PaddedDouble delta = ref deltas[ -#if NETCOREAPP2_1_OR_GREATER +#if NET Thread.GetCurrentProcessorId() #else Environment.CurrentManagedThreadId diff --git a/src/libraries/System.Diagnostics.EventLog/src/System/Diagnostics/Reader/UnsafeNativeMethods.cs b/src/libraries/System.Diagnostics.EventLog/src/System/Diagnostics/Reader/UnsafeNativeMethods.cs index e5cdb63f7ba76c..a8f8fd63369693 100644 --- a/src/libraries/System.Diagnostics.EventLog/src/System/Diagnostics/Reader/UnsafeNativeMethods.cs +++ b/src/libraries/System.Diagnostics.EventLog/src/System/Diagnostics/Reader/UnsafeNativeMethods.cs @@ -5,7 +5,7 @@ using System; using System.Diagnostics.Eventing.Reader; using System.Runtime.InteropServices; -#if NET7_0_OR_GREATER +#if NET using System.Runtime.InteropServices.Marshalling; #endif using System.Security; @@ -341,7 +341,7 @@ internal enum EvtLoginClass EvtRpcLogin = 1 } -#if NET7_0_OR_GREATER +#if NET [NativeMarshalling(typeof(Marshaller))] #endif [StructLayout(LayoutKind.Sequential)] @@ -355,7 +355,7 @@ internal struct EvtRpcLogin public string Domain; public CoTaskMemUnicodeSafeHandle Password; public int Flags; -#if NET7_0_OR_GREATER +#if NET [CustomMarshaller(typeof(EvtRpcLogin), MarshalMode.ManagedToUnmanagedRef, typeof(ValueMarshaller))] public static class Marshaller { @@ -695,7 +695,7 @@ internal static partial bool EvtRender( out int buffUsed, out int propCount); -#if NET7_0_OR_GREATER +#if NET [NativeMarshalling(typeof(Marshaller))] #endif [StructLayout(LayoutKind.Explicit, CharSet = CharSet.Unicode)] @@ -708,7 +708,7 @@ internal struct EvtStringVariant [FieldOffset(12)] public uint Type; -#if NET7_0_OR_GREATER +#if NET [CustomMarshaller(typeof(EvtStringVariant), MarshalMode.Default, typeof(Marshaller))] public static class Marshaller { diff --git a/src/libraries/System.Formats.Asn1/src/System/Formats/Asn1/AsnDecoder.Integer.cs b/src/libraries/System.Formats.Asn1/src/System/Formats/Asn1/AsnDecoder.Integer.cs index 102b05b82fb368..35372824d35e20 100644 --- a/src/libraries/System.Formats.Asn1/src/System/Formats/Asn1/AsnDecoder.Integer.cs +++ b/src/libraries/System.Formats.Asn1/src/System/Formats/Asn1/AsnDecoder.Integer.cs @@ -104,7 +104,7 @@ public static BigInteger ReadInteger( { ReadOnlySpan contents = ReadIntegerBytes(source, ruleSet, out int consumed, expectedTag); -#if NETCOREAPP2_1_OR_GREATER +#if NET BigInteger value = new BigInteger(contents, isBigEndian: true); #else byte[] tmp = CryptoPool.Rent(contents.Length); diff --git a/src/libraries/System.Formats.Asn1/src/System/Formats/Asn1/AsnWriter.Integer.cs b/src/libraries/System.Formats.Asn1/src/System/Formats/Asn1/AsnWriter.Integer.cs index 389196c0acd261..b1720b5106b2cd 100644 --- a/src/libraries/System.Formats.Asn1/src/System/Formats/Asn1/AsnWriter.Integer.cs +++ b/src/libraries/System.Formats.Asn1/src/System/Formats/Asn1/AsnWriter.Integer.cs @@ -281,7 +281,7 @@ private void WriteIntegerCore(Asn1Tag tag, BigInteger value) Debug.Assert(!tag.IsConstructed); WriteTag(tag); -#if NETCOREAPP2_1_OR_GREATER +#if NET WriteLength(value.GetByteCount()); // WriteLength ensures the content-space value.TryWriteBytes(_buffer.AsSpan(_offset), out int bytesWritten, isBigEndian: true); diff --git a/src/libraries/System.Formats.Asn1/src/System/Formats/Asn1/SetOfValueComparer.cs b/src/libraries/System.Formats.Asn1/src/System/Formats/Asn1/SetOfValueComparer.cs index 44b6c3030957e8..d766b5008c324c 100644 --- a/src/libraries/System.Formats.Asn1/src/System/Formats/Asn1/SetOfValueComparer.cs +++ b/src/libraries/System.Formats.Asn1/src/System/Formats/Asn1/SetOfValueComparer.cs @@ -17,7 +17,7 @@ internal static int Compare(ReadOnlySpan x, ReadOnlySpan y) int min = Math.Min(x.Length, y.Length); int diff; -#if NET7_0_OR_GREATER +#if NET int diffIndex = x.CommonPrefixLength(y); if (diffIndex != min) diff --git a/src/libraries/System.IO.Hashing/src/System/IO/Hashing/Crc32.cs b/src/libraries/System.IO.Hashing/src/System/IO/Hashing/Crc32.cs index 3a844a60637b07..260bf0bdadb374 100644 --- a/src/libraries/System.IO.Hashing/src/System/IO/Hashing/Crc32.cs +++ b/src/libraries/System.IO.Hashing/src/System/IO/Hashing/Crc32.cs @@ -169,7 +169,7 @@ public static uint HashToUInt32(ReadOnlySpan source) => private static uint Update(uint crc, ReadOnlySpan source) { -#if NET7_0_OR_GREATER +#if NET if (CanBeVectorized(source)) { return UpdateVectorized(crc, source); @@ -181,7 +181,7 @@ private static uint Update(uint crc, ReadOnlySpan source) private static uint UpdateScalar(uint crc, ReadOnlySpan source) { -#if NET6_0_OR_GREATER +#if NET // Use ARM intrinsics for CRC if available. This is used for the trailing bytes on the vectorized path // and is the primary method if the vectorized path is unavailable. if (System.Runtime.Intrinsics.Arm.Crc32.Arm64.IsSupported) diff --git a/src/libraries/System.IO.Hashing/src/System/IO/Hashing/Crc64.cs b/src/libraries/System.IO.Hashing/src/System/IO/Hashing/Crc64.cs index e9993a7503e787..89b81c657c518c 100644 --- a/src/libraries/System.IO.Hashing/src/System/IO/Hashing/Crc64.cs +++ b/src/libraries/System.IO.Hashing/src/System/IO/Hashing/Crc64.cs @@ -167,7 +167,7 @@ public static ulong HashToUInt64(ReadOnlySpan source) => private static ulong Update(ulong crc, ReadOnlySpan source) { -#if NET7_0_OR_GREATER +#if NET if (CanBeVectorized(source)) { return UpdateVectorized(crc, source); diff --git a/src/libraries/System.IO.Hashing/src/System/IO/Hashing/XxHash128.cs b/src/libraries/System.IO.Hashing/src/System/IO/Hashing/XxHash128.cs index fdfd24a60ab1f4..e1181cb73f914d 100644 --- a/src/libraries/System.IO.Hashing/src/System/IO/Hashing/XxHash128.cs +++ b/src/libraries/System.IO.Hashing/src/System/IO/Hashing/XxHash128.cs @@ -17,7 +17,7 @@ namespace System.IO.Hashing /// For methods that persist the computed numerical hash value as bytes, /// the value is written in the Big Endian byte order. /// -#if NET5_0_OR_GREATER +#if NET [SkipLocalsInit] #endif public sealed unsafe class XxHash128 : NonCryptographicHashAlgorithm @@ -51,7 +51,7 @@ public XxHash128(long seed) : base(HashLengthInBytes) /// is null. public static byte[] Hash(byte[] source, long seed) { -#if NET6_0_OR_GREATER +#if NET ArgumentNullException.ThrowIfNull(source); #else if (source is null) @@ -110,7 +110,7 @@ public static bool TryHash(ReadOnlySpan source, Span destination, ou return false; } -#if NET7_0_OR_GREATER +#if NET /// Computes the XXH128 hash of the provided data. /// The data to hash. /// The seed value for this hash computation. The default is zero. @@ -197,7 +197,7 @@ private Hash128 GetCurrentHashAsHash128() return current; } -#if NET7_0_OR_GREATER +#if NET /// Gets the current computed hash value without modifying accumulated state. /// The hash value for the data already provided. [CLSCompliant(false)] diff --git a/src/libraries/System.IO.Hashing/src/System/IO/Hashing/XxHash3.cs b/src/libraries/System.IO.Hashing/src/System/IO/Hashing/XxHash3.cs index 702409b949d451..affdfe78d6a850 100644 --- a/src/libraries/System.IO.Hashing/src/System/IO/Hashing/XxHash3.cs +++ b/src/libraries/System.IO.Hashing/src/System/IO/Hashing/XxHash3.cs @@ -16,7 +16,7 @@ namespace System.IO.Hashing /// For methods that persist the computed numerical hash value as bytes, /// the value is written in the Big Endian byte order. /// -#if NET5_0_OR_GREATER +#if NET [SkipLocalsInit] #endif public sealed unsafe class XxHash3 : NonCryptographicHashAlgorithm @@ -50,7 +50,7 @@ public XxHash3(long seed) : base(HashLengthInBytes) /// is null. public static byte[] Hash(byte[] source, long seed) { -#if NET6_0_OR_GREATER +#if NET ArgumentNullException.ThrowIfNull(source); #else if (source is null) diff --git a/src/libraries/System.IO.Hashing/src/System/IO/Hashing/XxHashShared.cs b/src/libraries/System.IO.Hashing/src/System/IO/Hashing/XxHashShared.cs index bfdf1963ac3b02..cafa80dbbf112e 100644 --- a/src/libraries/System.IO.Hashing/src/System/IO/Hashing/XxHashShared.cs +++ b/src/libraries/System.IO.Hashing/src/System/IO/Hashing/XxHashShared.cs @@ -6,7 +6,7 @@ using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -#if NET7_0_OR_GREATER +#if NET using System.Runtime.Intrinsics; using System.Runtime.Intrinsics.Arm; using System.Runtime.Intrinsics.X86; @@ -15,7 +15,7 @@ namespace System.IO.Hashing { /// Shared implementation of the XXH3 hash algorithm for 64-bit in and version. -#if NET5_0_OR_GREATER +#if NET [SkipLocalsInit] #endif internal static unsafe class XxHashShared @@ -333,7 +333,7 @@ public static void CopyAccumulators(ref State state, ulong* accumulators) { fixed (ulong* stateAccumulators = state.Accumulators) { -#if NET7_0_OR_GREATER +#if NET if (Vector256.IsHardwareAccelerated) { Vector256.Store(Vector256.Load(stateAccumulators), accumulators); @@ -390,7 +390,7 @@ public static void DigestLong(ref State state, ulong* accumulators, byte* secret [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void InitializeAccumulators(ulong* accumulators) { -#if NET7_0_OR_GREATER +#if NET if (Vector256.IsHardwareAccelerated) { Vector256.Store(Vector256.Create(Prime32_3, Prime64_1, Prime64_2, Prime64_3), accumulators); @@ -452,7 +452,7 @@ public static ulong Avalanche(ulong hash) [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ulong Multiply64To128(ulong left, ulong right, out ulong lower) { -#if NET5_0_OR_GREATER +#if NET return Math.BigMul(left, right, out lower); #else ulong lowerLow = Multiply32To64((uint)left, (uint)right); @@ -479,7 +479,7 @@ public static void DeriveSecretFromSeed(byte* destinationSecret, ulong seed) { fixed (byte* defaultSecret = &MemoryMarshal.GetReference(DefaultSecret)) { -#if NET7_0_OR_GREATER +#if NET if (Vector256.IsHardwareAccelerated && BitConverter.IsLittleEndian) { Vector256 seedVec = Vector256.Create(seed, 0u - seed, seed, 0u - seed); @@ -515,7 +515,7 @@ private static void Accumulate(ulong* accumulators, byte* source, byte* secret, byte* secretForAccumulate = secret; byte* secretForScramble = secret + (SecretLengthBytes - StripeLengthBytes); -#if NET7_0_OR_GREATER +#if NET if (Vector256.IsHardwareAccelerated && BitConverter.IsLittleEndian) { Vector256 acc1 = Vector256.Load(accumulators); @@ -620,7 +620,7 @@ public static void Accumulate512(ulong* accumulators, byte* source, byte* secret [MethodImpl(MethodImplOptions.AggressiveInlining)] private static void Accumulate512Inlined(ulong* accumulators, byte* source, byte* secret) { -#if NET7_0_OR_GREATER +#if NET if (Vector256.IsHardwareAccelerated && BitConverter.IsLittleEndian) { for (int i = 0; i < AccumulatorCount / Vector256.Count; i++) @@ -659,7 +659,7 @@ private static void Accumulate512Inlined(ulong* accumulators, byte* source, byte } } -#if NET7_0_OR_GREATER +#if NET [MethodImpl(MethodImplOptions.AggressiveInlining)] private static Vector256 Accumulate256(Vector256 accVec, byte* source, Vector256 secret) { @@ -714,7 +714,7 @@ private static Vector128 MultiplyWideningLower(Vector128 source) private static void ScrambleAccumulators(ulong* accumulators, byte* secret) { -#if NET7_0_OR_GREATER +#if NET if (Vector256.IsHardwareAccelerated && BitConverter.IsLittleEndian) { for (int i = 0; i < AccumulatorCount / Vector256.Count; i++) @@ -752,7 +752,7 @@ private static void ScrambleAccumulators(ulong* accumulators, byte* secret) } } -#if NET7_0_OR_GREATER +#if NET [MethodImpl(MethodImplOptions.AggressiveInlining)] private static Vector256 ScrambleAccumulator256(Vector256 accVec, Vector256 secret) { diff --git a/src/libraries/System.IO.Hashing/tests/NonCryptoHashTestDriver.cs b/src/libraries/System.IO.Hashing/tests/NonCryptoHashTestDriver.cs index f2d8e411533ec7..fe17c4c14eab87 100644 --- a/src/libraries/System.IO.Hashing/tests/NonCryptoHashTestDriver.cs +++ b/src/libraries/System.IO.Hashing/tests/NonCryptoHashTestDriver.cs @@ -420,7 +420,7 @@ public LargeTestCase(string name, byte data, long repeatCount, string outputHex) public IEnumerable> EnumerateDataChunks() { -#if NET5_0_OR_GREATER +#if NET byte[] chunk = GC.AllocateUninitializedArray(1024 * 1024); #else byte[] chunk = new byte[1024 * 1024]; diff --git a/src/libraries/System.IO.Hashing/tests/XxHash128Tests.cs b/src/libraries/System.IO.Hashing/tests/XxHash128Tests.cs index 8d32a6f06c1d2d..3ba2044d069505 100644 --- a/src/libraries/System.IO.Hashing/tests/XxHash128Tests.cs +++ b/src/libraries/System.IO.Hashing/tests/XxHash128Tests.cs @@ -41,7 +41,7 @@ public void Hash_OneShot_Expected() Assert.Equal(expectedHash128, ReadHashBigEndian(XxHash128.Hash(input, test.Seed))); Assert.Equal(expectedHash128, ReadHashBigEndian(XxHash128.Hash((ReadOnlySpan)input, test.Seed))); -#if NET7_0_OR_GREATER +#if NET // Validate `XxHash128.HashToUInt128` Assert.Equal(new UInt128(test.HashHigh, test.HashLow), XxHash128.HashToUInt128(input, test.Seed)); #endif @@ -110,7 +110,7 @@ public void Hash_Streaming_Expected() // Validate that the hash we get from doing a one-shot of all the data up to this point // matches the incremental hash for the data appended until now. -#if NET7_0_OR_GREATER +#if NET Assert.Equal(XxHash128.HashToUInt128(asciiBytes.AsSpan(0, processed), test.Seed), hash.GetCurrentHashAsUInt128()); #endif Assert.True(hash.TryGetCurrentHash(destination, out int bytesWritten)); @@ -120,7 +120,7 @@ public void Hash_Streaming_Expected() } // Validate the final hash code. -#if NET7_0_OR_GREATER +#if NET Assert.Equal(new UInt128(test.HashHigh, test.HashLow), hash.GetCurrentHashAsUInt128()); #endif Array.Clear(destination, 0, destination.Length); diff --git a/src/libraries/System.IO.Packaging/src/System/IO/Packaging/InternalRelationshipCollection.cs b/src/libraries/System.IO.Packaging/src/System/IO/Packaging/InternalRelationshipCollection.cs index b2ace96c807391..d76b0972d017ce 100644 --- a/src/libraries/System.IO.Packaging/src/System/IO/Packaging/InternalRelationshipCollection.cs +++ b/src/libraries/System.IO.Packaging/src/System/IO/Packaging/InternalRelationshipCollection.cs @@ -320,7 +320,7 @@ private void ProcessRelationshipAttributes(XmlCompatibilityReader reader) { try { -#if NET6_0_OR_GREATER +#if NET relationshipTargetMode = Enum.Parse(targetModeAttributeValue, ignoreCase: false); #else relationshipTargetMode = (TargetMode)(Enum.Parse(typeof(TargetMode), targetModeAttributeValue, ignoreCase: false)); diff --git a/src/libraries/System.IO.Packaging/src/System/IO/Packaging/PackUriHelper.PackUriScheme.cs b/src/libraries/System.IO.Packaging/src/System/IO/Packaging/PackUriHelper.PackUriScheme.cs index 2707afbf4b5391..8bf3d1e5a0e8b5 100644 --- a/src/libraries/System.IO.Packaging/src/System/IO/Packaging/PackUriHelper.PackUriScheme.cs +++ b/src/libraries/System.IO.Packaging/src/System/IO/Packaging/PackUriHelper.PackUriScheme.cs @@ -285,7 +285,7 @@ private static string EscapeSpecialCharacters(string path) // This is currently enforced by the order of characters in the s_specialCharacterChars array foreach (char c in s_specialCharacterChars) { -#if NET5_0_OR_GREATER +#if NET if (path.Contains(c)) #else if (path.IndexOf(c) != -1) diff --git a/src/libraries/System.IO.Pipelines/tests/PipeReaderCopyToAsyncTests.cs b/src/libraries/System.IO.Pipelines/tests/PipeReaderCopyToAsyncTests.cs index 21228b2a1bf726..3c524de5122365 100644 --- a/src/libraries/System.IO.Pipelines/tests/PipeReaderCopyToAsyncTests.cs +++ b/src/libraries/System.IO.Pipelines/tests/PipeReaderCopyToAsyncTests.cs @@ -349,7 +349,7 @@ public override void Write(byte[] buffer, int offset, int count) Check(count); base.Write(buffer, offset, count); } -#if NETCOREAPP3_0_OR_GREATER +#if NET public override void Write(ReadOnlySpan buffer) { Check(buffer.Length); diff --git a/src/libraries/System.IO.Ports/src/System/IO/Ports/SerialPort.cs b/src/libraries/System.IO.Ports/src/System/IO/Ports/SerialPort.cs index 752163fd2bd379..426eb77d637d5b 100644 --- a/src/libraries/System.IO.Ports/src/System/IO/Ports/SerialPort.cs +++ b/src/libraries/System.IO.Ports/src/System/IO/Ports/SerialPort.cs @@ -963,7 +963,7 @@ public string ReadExisting() Buffer.BlockCopy(_inBuffer, _readPos, bytesReceived, 0, CachedBytesToRead); } -#if NET7_0_OR_GREATER +#if NET _internalSerialStream.ReadExactly(bytesReceived, CachedBytesToRead, bytesReceived.Length - CachedBytesToRead); // get everything #else int readCount = bytesReceived.Length - CachedBytesToRead; diff --git a/src/libraries/System.Reflection.Metadata/src/System/Reflection/Internal/Utilities/StreamExtensions.cs b/src/libraries/System.Reflection.Metadata/src/System/Reflection/Internal/Utilities/StreamExtensions.cs index bb52925254c277..2bda7989a9bb9b 100644 --- a/src/libraries/System.Reflection.Metadata/src/System/Reflection/Internal/Utilities/StreamExtensions.cs +++ b/src/libraries/System.Reflection.Metadata/src/System/Reflection/Internal/Utilities/StreamExtensions.cs @@ -78,7 +78,7 @@ internal static int TryReadAll(this Stream stream, byte[] buffer, int offset, in #if NETCOREAPP internal static int TryReadAll(this Stream stream, Span buffer) -#if NET7_0_OR_GREATER +#if NET => stream.ReadAtLeast(buffer, buffer.Length, throwOnEndOfStream: false); #else { diff --git a/src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/General/Helpers.cs b/src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/General/Helpers.cs index d172f20f1cb066..cc8e5f3ce1ad23 100644 --- a/src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/General/Helpers.cs +++ b/src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/General/Helpers.cs @@ -134,7 +134,7 @@ public static bool NeedsEscapingInTypeName(this char c) public static string UnescapeTypeNameIdentifier(this string identifier) { -#if NET5_0_OR_GREATER +#if NET if (identifier.Contains('\\')) #else if (identifier.IndexOf('\\') != -1) diff --git a/src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/Types/RoType.cs b/src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/Types/RoType.cs index 50ab6b7f307a08..1a5369f2f638d1 100644 --- a/src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/Types/RoType.cs +++ b/src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/Types/RoType.cs @@ -331,7 +331,7 @@ public sealed override Type MakeArrayType(int rank) private volatile RoType? _lazyUnderlyingEnumType; public sealed override Array GetEnumValues() => throw new InvalidOperationException(SR.Arg_InvalidOperation_Reflection); -#if NET7_0_OR_GREATER +#if NET [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2085:UnrecognizedReflectionPattern", Justification = "Enum Types are not trimmed.")] public override Array GetEnumValuesAsUnderlyingType() diff --git a/src/libraries/System.Reflection.MetadataLoadContext/tests/src/Tests/Type/TypeTests.cs b/src/libraries/System.Reflection.MetadataLoadContext/tests/src/Tests/Type/TypeTests.cs index 03611db20825a4..c476213963544a 100644 --- a/src/libraries/System.Reflection.MetadataLoadContext/tests/src/Tests/Type/TypeTests.cs +++ b/src/libraries/System.Reflection.MetadataLoadContext/tests/src/Tests/Type/TypeTests.cs @@ -365,7 +365,7 @@ public static IEnumerable GetEnumUnderlyingTypeData } } -#if NET7_0_OR_GREATER +#if NET [Fact] public static void GetEnumValuesAsUnderlyingType() { diff --git a/src/libraries/System.Security.Cryptography.Pkcs/src/Internal/Cryptography/PkcsHelpers.cs b/src/libraries/System.Security.Cryptography.Pkcs/src/Internal/Cryptography/PkcsHelpers.cs index 6351a376c0bc72..b26ff355f378e8 100644 --- a/src/libraries/System.Security.Cryptography.Pkcs/src/Internal/Cryptography/PkcsHelpers.cs +++ b/src/libraries/System.Security.Cryptography.Pkcs/src/Internal/Cryptography/PkcsHelpers.cs @@ -364,7 +364,7 @@ public static string ToSerialString(this byte[] serialBytes) return ToUpperHexString(serialBytes); } -#if NET5_0_OR_GREATER +#if NET private static string ToUpperHexString(ReadOnlySpan ba) { return Convert.ToHexString(ba); diff --git a/src/libraries/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/Utils.cs b/src/libraries/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/Utils.cs index ffffeefa5bac37..de7bc2b9b77b7e 100644 --- a/src/libraries/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/Utils.cs +++ b/src/libraries/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/Utils.cs @@ -720,7 +720,7 @@ internal static X509Certificate2Collection BuildBagOfCerts(KeyInfoX509Data keyIn return collection; } -#if NET5_0_OR_GREATER +#if NET internal static string EncodeHexString(byte[] sArray) { return Convert.ToHexString(sArray); diff --git a/src/libraries/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/XmlResolverHelper.cs b/src/libraries/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/XmlResolverHelper.cs index 3070ffa8e1d233..948f883b80a2eb 100644 --- a/src/libraries/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/XmlResolverHelper.cs +++ b/src/libraries/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/XmlResolverHelper.cs @@ -11,14 +11,14 @@ internal static class XmlResolverHelper { internal static XmlResolver GetThrowingResolver() { -#if NET7_0_OR_GREATER +#if NET return XmlResolver.ThrowingResolver; #else return XmlThrowingResolver.s_singleton; #endif } -#if !NET7_0_OR_GREATER +#if !NET // An XmlResolver that forbids all external entity resolution. // (Copied from XmlResolver.ThrowingResolver.cs.) private sealed class XmlThrowingResolver : XmlResolver diff --git a/src/libraries/System.ServiceModel.Syndication/src/System/ServiceModel/XmlBuffer.cs b/src/libraries/System.ServiceModel.Syndication/src/System/ServiceModel/XmlBuffer.cs index 17f3cfa2e1e7ad..4c31f32bf505a2 100644 --- a/src/libraries/System.ServiceModel.Syndication/src/System/ServiceModel/XmlBuffer.cs +++ b/src/libraries/System.ServiceModel.Syndication/src/System/ServiceModel/XmlBuffer.cs @@ -87,7 +87,7 @@ public void Close() _buffer = new byte[_stream.Length]; _stream.Position = 0; -#if NET7_0_OR_GREATER +#if NET _stream.ReadExactly(_buffer); #else int totalRead = 0; diff --git a/src/libraries/System.Speech/src/Internal/Synthesis/AudioBase.cs b/src/libraries/System.Speech/src/Internal/Synthesis/AudioBase.cs index 782cd59fb6c34c..c8ecfa78483570 100644 --- a/src/libraries/System.Speech/src/Internal/Synthesis/AudioBase.cs +++ b/src/libraries/System.Speech/src/Internal/Synthesis/AudioBase.cs @@ -122,7 +122,7 @@ internal void PlayWaveFile(AudioData audio) { byte[] data = new byte[(int)audio._stream.Length]; -#if NET7_0_OR_GREATER +#if NET audio._stream.ReadExactly(data); #else int totalRead = 0; diff --git a/src/libraries/System.Speech/src/Internal/Synthesis/EngineSite.cs b/src/libraries/System.Speech/src/Internal/Synthesis/EngineSite.cs index a658f37ca6180b..c6caca4d9c25bf 100644 --- a/src/libraries/System.Speech/src/Internal/Synthesis/EngineSite.cs +++ b/src/libraries/System.Speech/src/Internal/Synthesis/EngineSite.cs @@ -175,7 +175,7 @@ public Stream LoadResource(Uri uri, string mediaType) MemoryStream memStream = new(cLen); byte[] ab = new byte[cLen]; -#if NET7_0_OR_GREATER +#if NET stream.ReadExactly(ab); #else int totalRead = 0; diff --git a/src/libraries/System.Text.Encoding.CodePages/src/System/Text/CodePagesEncodingProvider.cs b/src/libraries/System.Text.Encoding.CodePages/src/System/Text/CodePagesEncodingProvider.cs index c984dbf460d8a4..58bb679c7712ae 100644 --- a/src/libraries/System.Text.Encoding.CodePages/src/System/Text/CodePagesEncodingProvider.cs +++ b/src/libraries/System.Text.Encoding.CodePages/src/System/Text/CodePagesEncodingProvider.cs @@ -197,7 +197,7 @@ public static EncodingProvider Instance internal static unsafe ref T GetNonNullPinnableReference(T[] array) where T : struct { return ref -#if NET5_0_OR_GREATER +#if NET MemoryMarshal.GetArrayDataReference(array); #else array.Length != 0 ? ref array[0] : ref Unsafe.AsRef((void*)1); diff --git a/src/libraries/System.Text.Json/Common/JsonHelpers.cs b/src/libraries/System.Text.Json/Common/JsonHelpers.cs index 5711afa8370689..afa3afb4dc2ce4 100644 --- a/src/libraries/System.Text.Json/Common/JsonHelpers.cs +++ b/src/libraries/System.Text.Json/Common/JsonHelpers.cs @@ -55,7 +55,7 @@ internal static bool RequiresSpecialNumberHandlingOnWrite(JsonNumberHandling? ha internal static void StableSortByKey(this List items, Func keySelector) where TKey : unmanaged, IComparable { -#if NET6_0_OR_GREATER +#if NET Span span = CollectionsMarshal.AsSpan(items); // Tuples implement lexical ordering OOTB which can be used to encode stable sorting diff --git a/src/libraries/System.Text.Json/ref/System.Text.Json.netcoreapp.cs b/src/libraries/System.Text.Json/ref/System.Text.Json.netcoreapp.cs index 847da900ad35d8..bbf2e3846a6bcd 100644 --- a/src/libraries/System.Text.Json/ref/System.Text.Json.netcoreapp.cs +++ b/src/libraries/System.Text.Json/ref/System.Text.Json.netcoreapp.cs @@ -12,7 +12,7 @@ public static partial class JsonMetadataServices public static System.Text.Json.Serialization.JsonConverter HalfConverter { get { throw null; } } public static System.Text.Json.Serialization.JsonConverter TimeOnlyConverter { get { throw null; } } -#if NET7_0_OR_GREATER +#if NET public static System.Text.Json.Serialization.JsonConverter Int128Converter { get { throw null; } } [System.CLSCompliantAttribute(false)] public static System.Text.Json.Serialization.JsonConverter UInt128Converter { get { throw null; } } diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Document/JsonDocument.MetadataDb.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Document/JsonDocument.MetadataDb.cs index afdbf4bd0b9b26..a53df982c12eb4 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Document/JsonDocument.MetadataDb.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Document/JsonDocument.MetadataDb.cs @@ -240,7 +240,7 @@ private void Enlarge() // Note: Array.MaxLength exists only on .NET 6 or greater, // so for the other versions value is hardcoded const int MaxArrayLength = 0x7FFFFFC7; -#if NET6_0_OR_GREATER +#if NET Debug.Assert(MaxArrayLength == Array.MaxLength); #endif diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/JsonConstants.cs b/src/libraries/System.Text.Json/src/System/Text/Json/JsonConstants.cs index 7fe47499c1aa85..c2dbc58e131a0c 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/JsonConstants.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/JsonConstants.cs @@ -65,7 +65,7 @@ internal static partial class JsonConstants // When transcoding from UTF8 -> UTF16, the byte count threshold where we rent from the array pool before performing a normal alloc. public const long ArrayPoolMaxSizeBeforeUsingNormalAlloc = -#if NET6_0_OR_GREATER +#if NET 1024 * 1024 * 1024; // ArrayPool limit increased in .NET 6 #else 1024 * 1024; diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Reader/Utf8JsonReader.MultiSegment.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Reader/Utf8JsonReader.MultiSegment.cs index 8635031292e32c..22d3cc1c497d81 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Reader/Utf8JsonReader.MultiSegment.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Reader/Utf8JsonReader.MultiSegment.cs @@ -633,7 +633,7 @@ private static int FindMismatch(ReadOnlySpan span, ReadOnlySpan lite int indexOfFirstMismatch; -#if NET7_0_OR_GREATER +#if NET indexOfFirstMismatch = span.CommonPrefixLength(literal); #else int minLength = Math.Min(span.Length, literal.Length); diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Metadata/DefaultJsonTypeInfoResolver.Converters.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Metadata/DefaultJsonTypeInfoResolver.Converters.cs index 117e3ba3d63a97..b5bb76c77b0652 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Metadata/DefaultJsonTypeInfoResolver.Converters.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Metadata/DefaultJsonTypeInfoResolver.Converters.cs @@ -74,7 +74,7 @@ private static Dictionary GetDefaultSimpleConverters() Add(JsonMetadataServices.UInt16Converter); Add(JsonMetadataServices.UInt32Converter); Add(JsonMetadataServices.UInt64Converter); -#if NET7_0_OR_GREATER +#if NET Add(JsonMetadataServices.Int128Converter); Add(JsonMetadataServices.UInt128Converter); #endif diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Metadata/JsonMetadataServices.Converters.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Metadata/JsonMetadataServices.Converters.cs index 83a24191b8fe25..1cf87d0c940e7a 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Metadata/JsonMetadataServices.Converters.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Metadata/JsonMetadataServices.Converters.cs @@ -108,7 +108,7 @@ public static partial class JsonMetadataServices public static JsonConverter Int64Converter => s_int64Converter ??= new Int64Converter(); private static JsonConverter? s_int64Converter; -#if NET7_0_OR_GREATER +#if NET /// /// Returns a instance that converts values. /// diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Metadata/JsonPropertyInfo.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Metadata/JsonPropertyInfo.cs index 959490b53f19fc..e70cd8848868af 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Metadata/JsonPropertyInfo.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Metadata/JsonPropertyInfo.cs @@ -626,7 +626,7 @@ private bool NumberHandingIsApplicable() #if NETCOREAPP potentialNumberType == typeof(Half) || #endif -#if NET7_0_OR_GREATER +#if NET potentialNumberType == typeof(Int128) || potentialNumberType == typeof(UInt128) || #endif diff --git a/src/libraries/System.Text.Json/tests/Common/CollectionTests/CollectionTests.Dictionary.NonStringKey.cs b/src/libraries/System.Text.Json/tests/Common/CollectionTests/CollectionTests.Dictionary.NonStringKey.cs index dfaff9130fa78a..ce8ac3d254d3ac 100644 --- a/src/libraries/System.Text.Json/tests/Common/CollectionTests/CollectionTests.Dictionary.NonStringKey.cs +++ b/src/libraries/System.Text.Json/tests/Common/CollectionTests/CollectionTests.Dictionary.NonStringKey.cs @@ -46,7 +46,7 @@ public static IEnumerable GetTestDictionaries() yield return WrapArgs(DateTime.MaxValue, 1, expectedJson: $@"{{""{DateTime.MaxValue:O}"":1}}"); yield return WrapArgs(DateTimeOffset.MaxValue, 1, expectedJson: $@"{{""{DateTimeOffset.MaxValue:O}"":1}}"); yield return WrapArgs(TimeSpan.MaxValue, 1, expectedJson: $@"{{""{TimeSpan.MaxValue}"":1}}"); -#if NET6_0_OR_GREATER +#if NET yield return WrapArgs(DateOnly.MaxValue, 1, expectedJson: $@"{{""{DateOnly.MaxValue:O}"":1}}"); yield return WrapArgs(TimeOnly.MaxValue, 1, expectedJson: $@"{{""{TimeOnly.MaxValue:O}"":1}}"); #endif diff --git a/src/libraries/System.Text.Json/tests/Common/TestClasses/TestClasses.cs b/src/libraries/System.Text.Json/tests/Common/TestClasses/TestClasses.cs index 9f8af715fdb8e4..92c12b1dfc44c9 100644 --- a/src/libraries/System.Text.Json/tests/Common/TestClasses/TestClasses.cs +++ b/src/libraries/System.Text.Json/tests/Common/TestClasses/TestClasses.cs @@ -1907,7 +1907,7 @@ public override void WriteAsPropertyName(Utf8JsonWriter writer, int value, JsonS public static class ReflectionExtensions { -#if NET6_0_OR_GREATER +#if NET [return: System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembers(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicConstructors)] public static Type WithConstructors( [System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembers(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicConstructors)] diff --git a/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexCharClass.cs b/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexCharClass.cs index 5666498347e468..3c24bdc78ad06f 100644 --- a/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexCharClass.cs +++ b/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexCharClass.cs @@ -563,7 +563,7 @@ public static string ConvertOldStringsToClass(string set, string category) } return -#if NETCOREAPP2_1_OR_GREATER +#if NET string #else StringExtensions @@ -1304,7 +1304,7 @@ static bool InitializeValue(char ch, string set, ref uint[]? asciiLazyCache) } uint[]? cache = asciiLazyCache ?? Interlocked.CompareExchange(ref asciiLazyCache, new uint[CacheArrayLength], null) ?? asciiLazyCache; -#if NET5_0_OR_GREATER +#if NET Interlocked #else InterlockedExtensions @@ -1594,7 +1594,7 @@ internal static unsafe string CharsToStringClass(ReadOnlySpan chars) #pragma warning disable CS8500 // takes address of managed type ReadOnlySpan tmpChars = chars; // avoid address exposing the span and impacting the other code in the method that uses it return -#if NETCOREAPP2_1_OR_GREATER +#if NET string #else StringExtensions diff --git a/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexWriter.cs b/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexWriter.cs index 5284c09339bd7b..4d779d4f48f127 100644 --- a/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexWriter.cs +++ b/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexWriter.cs @@ -177,7 +177,7 @@ private void Emit(RegexOpcode op, int opd1, int opd2) ///
private int StringCode(string str) { -#if NET6_0_OR_GREATER +#if NET ref int i = ref CollectionsMarshal.GetValueRefOrAddDefault(_stringTable, str, out bool exists); if (!exists) { diff --git a/src/libraries/System.Text.RegularExpressions/src/System/Threading/StackHelper.cs b/src/libraries/System.Text.RegularExpressions/src/System/Threading/StackHelper.cs index c338c2bb73e95c..ded50c662ea4a4 100644 --- a/src/libraries/System.Text.RegularExpressions/src/System/Threading/StackHelper.cs +++ b/src/libraries/System.Text.RegularExpressions/src/System/Threading/StackHelper.cs @@ -12,7 +12,7 @@ internal static class StackHelper /// Tries to ensure there is sufficient stack to execute the average .NET function. public static bool TryEnsureSufficientExecutionStack() { -#if NETCOREAPP2_0_OR_GREATER +#if NET return RuntimeHelpers.TryEnsureSufficientExecutionStack(); #else try diff --git a/src/libraries/System.Text.RegularExpressions/tests/FunctionalTests/Regex.Match.Tests.cs b/src/libraries/System.Text.RegularExpressions/tests/FunctionalTests/Regex.Match.Tests.cs index 9d3679be60b938..234b416a9b46de 100644 --- a/src/libraries/System.Text.RegularExpressions/tests/FunctionalTests/Regex.Match.Tests.cs +++ b/src/libraries/System.Text.RegularExpressions/tests/FunctionalTests/Regex.Match.Tests.cs @@ -1327,7 +1327,7 @@ public void Match_InstanceMethods_DefaultTimeout_Throws(RegexEngine engine) }, ((int)engine).ToString(CultureInfo.InvariantCulture)).Dispose(); } -#if NET7_0_OR_GREATER +#if NET [ConditionalFact(typeof(RemoteExecutor), nameof(RemoteExecutor.IsSupported))] public void Match_InstanceMethods_DefaultTimeout_SourceGenerated_Throws() { @@ -1885,7 +1885,7 @@ public async Task Match_StartatDiffersFromBeginning(RegexEngine engine, string p Regex r = await RegexHelpers.GetRegexAsync(engine, pattern, options); Assert.Equal(expectedSuccessStartAt, r.IsMatch(input, startat)); -#if NET7_0_OR_GREATER +#if NET Assert.Equal(expectedSuccessStartAt, r.IsMatch(input.AsSpan(), startat)); #endif @@ -2069,7 +2069,7 @@ public async Task TestCharIsLowerCultureEdgeCasesAroundTurkishCharacters(RegexEn Regex r1 = await RegexHelpers.GetRegexAsync(engine, "[\u012F-\u0130]", RegexOptions.IgnoreCase); Regex r2 = await RegexHelpers.GetRegexAsync(engine, "[\u012F\u0130]", RegexOptions.IgnoreCase); Assert.Equal(r1.IsMatch("\u0130"), r2.IsMatch("\u0130")); -#if NET7_0_OR_GREATER +#if NET Assert.Equal(r1.IsMatch("\u0130".AsSpan()), r2.IsMatch("\u0130".AsSpan())); #endif @@ -2491,14 +2491,14 @@ private static void VerifyIsMatchThrows(Regex? r, string input, TimeSpan time if (r == null) { Assert.Throws(() => timeout == Regex.InfiniteMatchTimeout ? Regex.IsMatch(input, pattern, options) : Regex.IsMatch(input, pattern, options, timeout)); -#if NET7_0_OR_GREATER +#if NET Assert.Throws(() => timeout == Regex.InfiniteMatchTimeout ? Regex.IsMatch(input.AsSpan(), pattern, options) : Regex.IsMatch(input.AsSpan(), pattern, options, timeout)); #endif } else { Assert.Throws(() => r.IsMatch(input)); -#if NET7_0_OR_GREATER +#if NET Assert.Throws(() => r.IsMatch(input.AsSpan())); #endif } @@ -2513,7 +2513,7 @@ private static void VerifyIsMatch(Regex? r, string input, bool expected, TimeSpa { Assert.Equal(expected, Regex.IsMatch(input, pattern)); } -#if NET7_0_OR_GREATER +#if NET Assert.Equal(expected, timeout == Regex.InfiniteMatchTimeout ? Regex.IsMatch(input.AsSpan(), pattern, options) : Regex.IsMatch(input.AsSpan(), pattern, options, timeout)); if (options == RegexOptions.None) { @@ -2524,7 +2524,7 @@ private static void VerifyIsMatch(Regex? r, string input, bool expected, TimeSpa else { Assert.Equal(expected, r.IsMatch(input)); -#if NET7_0_OR_GREATER +#if NET Assert.Equal(expected, r.IsMatch(input.AsSpan())); #endif } diff --git a/src/libraries/System.Text.RegularExpressions/tests/FunctionalTests/Regex.Tests.Common.cs b/src/libraries/System.Text.RegularExpressions/tests/FunctionalTests/Regex.Tests.Common.cs index 4d4f2252839ae5..b0a9b6549492bc 100644 --- a/src/libraries/System.Text.RegularExpressions/tests/FunctionalTests/Regex.Tests.Common.cs +++ b/src/libraries/System.Text.RegularExpressions/tests/FunctionalTests/Regex.Tests.Common.cs @@ -187,7 +187,7 @@ public static async Task GetRegexesAsync(RegexEngine engine, params (st /// Set the AppContext variable REGEX_NONBACKTRACKING_MAX_AUTOMATA_SIZE to the given max value. Only used with Nonbacktracking engine. public static void SetSafeSizeThreshold(int maxSize) { -#if NET7_0_OR_GREATER +#if NET AppContext.SetData("REGEX_NONBACKTRACKING_MAX_AUTOMATA_SIZE", maxSize); #endif } @@ -195,7 +195,7 @@ public static void SetSafeSizeThreshold(int maxSize) /// Remove the AppContext variable REGEX_NONBACKTRACKING_MAX_AUTOMATA_SIZE value. Only used with Nonbacktracking engine. public static void RestoreSafeSizeThresholdToDefault() { -#if NET7_0_OR_GREATER +#if NET AppContext.SetData("REGEX_NONBACKTRACKING_MAX_AUTOMATA_SIZE", null); #endif } diff --git a/src/libraries/System.Text.RegularExpressions/tests/FunctionalTests/RegexRunnerTests.cs b/src/libraries/System.Text.RegularExpressions/tests/FunctionalTests/RegexRunnerTests.cs index d4cd665e5b1af9..0f5799687011cd 100644 --- a/src/libraries/System.Text.RegularExpressions/tests/FunctionalTests/RegexRunnerTests.cs +++ b/src/libraries/System.Text.RegularExpressions/tests/FunctionalTests/RegexRunnerTests.cs @@ -50,7 +50,7 @@ public async Task EnsureRunmatchValueIsNulledAfterIsMatch(RegexEngine engine) MethodInfo getTextMethod = typeof(Match).GetMethod("get_Text", BindingFlags.Instance | BindingFlags.NonPublic); Assert.Null(getTextMethod.Invoke(runmatch, [])); Assert.Equal(string.Empty, runmatch.Value); -#if NET7_0_OR_GREATER +#if NET Assert.True(runmatch.ValueSpan == ReadOnlySpan.Empty); #endif } diff --git a/src/libraries/System.Threading.Tasks.Dataflow/src/Base/DataflowBlock.cs b/src/libraries/System.Threading.Tasks.Dataflow/src/Base/DataflowBlock.cs index 63cdedf4b466a6..c91cff3b5423ab 100644 --- a/src/libraries/System.Threading.Tasks.Dataflow/src/Base/DataflowBlock.cs +++ b/src/libraries/System.Threading.Tasks.Dataflow/src/Base/DataflowBlock.cs @@ -1470,7 +1470,7 @@ public static Task OutputAvailableAsync( { // When cancellation is requested, unlink the target from the source and cancel the target. target._ctr = cancellationToken.Register( -#if NET6_0_OR_GREATER +#if NET OutputAvailableAsyncTarget.CancelAndUnlink, #else static state => OutputAvailableAsyncTarget.CancelAndUnlink(state, default), diff --git a/src/libraries/System.Threading.Tasks.Dataflow/src/Internal/Common.cs b/src/libraries/System.Threading.Tasks.Dataflow/src/Internal/Common.cs index 7bfd3ecf35d952..c04ee9556003d4 100644 --- a/src/libraries/System.Threading.Tasks.Dataflow/src/Internal/Common.cs +++ b/src/libraries/System.Threading.Tasks.Dataflow/src/Internal/Common.cs @@ -190,7 +190,7 @@ internal static void WireCancellationToComplete( // data, and we also want to dispose of that registration when we complete so that we don't // leak into a long-living cancellation token. CancellationTokenRegistration reg = cancellationToken.Register( -#if NET6_0_OR_GREATER +#if NET completeAction, completeState #else state => diff --git a/src/libraries/System.Windows.Extensions/src/System/Media/SoundPlayer.cs b/src/libraries/System.Windows.Extensions/src/System/Media/SoundPlayer.cs index d77919070c24df..e57dff3e55ce2a 100644 --- a/src/libraries/System.Windows.Extensions/src/System/Media/SoundPlayer.cs +++ b/src/libraries/System.Windows.Extensions/src/System/Media/SoundPlayer.cs @@ -314,7 +314,7 @@ private void LoadStream(bool loadSync) int streamLen = (int)_stream.Length; _currentPos = 0; _streamData = new byte[streamLen]; -#if NET7_0_OR_GREATER +#if NET _stream.ReadExactly(_streamData); #else int totalRead = 0; diff --git a/src/libraries/System.Windows.Extensions/src/System/Security/Cryptography/X509Certificates/X509Certificate2UI.cs b/src/libraries/System.Windows.Extensions/src/System/Security/Cryptography/X509Certificates/X509Certificate2UI.cs index b19e217322f07e..dfdb4660ea4991 100644 --- a/src/libraries/System.Windows.Extensions/src/System/Security/Cryptography/X509Certificates/X509Certificate2UI.cs +++ b/src/libraries/System.Windows.Extensions/src/System/Security/Cryptography/X509Certificates/X509Certificate2UI.cs @@ -53,7 +53,7 @@ private static unsafe void DisplayX509Certificate(X509Certificate2 certificate, // Initialize view structure. Interop.CryptUI.CRYPTUI_VIEWCERTIFICATE_STRUCTW ViewInfo = default; -#if NET7_0_OR_GREATER +#if NET ViewInfo.dwSize = (uint)sizeof(Interop.CryptUI.CRYPTUI_VIEWCERTIFICATE_STRUCTW.Marshaller.Native); #else ViewInfo.dwSize = (uint)Marshal.SizeOf(); @@ -122,7 +122,7 @@ private static unsafe SafeCertStoreHandle SelectFromStore(SafeCertStoreHandle sa Interop.CryptUI.CRYPTUI_SELECTCERTIFICATE_STRUCTW csc = default; // Older versions of CRYPTUI do not check the size correctly, // so always force it to the oldest version of the structure. -#if NET7_0_OR_GREATER +#if NET // Declare a local for Native to enable us to get the managed byte offset // without having a null check cause a failure. Interop.CryptUI.CRYPTUI_SELECTCERTIFICATE_STRUCTW.Marshaller.Native native; diff --git a/src/tasks/Microsoft.NET.WebAssembly.Webcil/WebcilConverter.cs b/src/tasks/Microsoft.NET.WebAssembly.Webcil/WebcilConverter.cs index 13c34bde4b8ea1..0a0495f72fef4e 100644 --- a/src/tasks/Microsoft.NET.WebAssembly.Webcil/WebcilConverter.cs +++ b/src/tasks/Microsoft.NET.WebAssembly.Webcil/WebcilConverter.cs @@ -213,7 +213,7 @@ private static void WriteSectionHeader(Stream s, WebcilSectionHeader sectionHead WriteStructure(s, sectionHeader); } -#if NETCOREAPP2_1_OR_GREATER +#if NET private static void WriteStructure(Stream s, T structure) where T : unmanaged { @@ -256,7 +256,7 @@ private static void CopySections(Stream outStream, FileStream inputStream, Immut } } -#if NETCOREAPP2_1_OR_GREATER +#if NET private static void ReadExactly(FileStream s, Span buffer) { s.ReadExactly(buffer); diff --git a/src/tasks/Microsoft.NET.WebAssembly.Webcil/WebcilWasmWrapper.cs b/src/tasks/Microsoft.NET.WebAssembly.Webcil/WebcilWasmWrapper.cs index 3f8560446306fb..f47a1247474784 100644 --- a/src/tasks/Microsoft.NET.WebAssembly.Webcil/WebcilWasmWrapper.cs +++ b/src/tasks/Microsoft.NET.WebAssembly.Webcil/WebcilWasmWrapper.cs @@ -63,7 +63,7 @@ public void WriteWasmWrappedWebcil(Stream outputStream) // // extracted by wasm-reader -s wrapper.wasm private static -#if NET7_0_OR_GREATER +#if NET ReadOnlyMemory #else byte[] @@ -80,7 +80,7 @@ private static // // extracted by wasm-reader -s wrapper.wasm private static -#if NET7_0_OR_GREATER +#if NET ReadOnlyMemory #else byte[] @@ -91,7 +91,7 @@ private static private static void WriteWasmHeader(Stream outputStream) { -#if NET7_0_OR_GREATER +#if NET outputStream.Write(s_wasmWrapperPrefix.Span); #else outputStream.Write(s_wasmWrapperPrefix, 0, s_wasmWrapperPrefix.Length); @@ -100,7 +100,7 @@ private static void WriteWasmHeader(Stream outputStream) private static void WriteWasmSuffix(Stream outputStream) { -#if NET7_0_OR_GREATER +#if NET outputStream.Write(s_wasmWrapperSuffix.Span); #else outputStream.Write(s_wasmWrapperSuffix, 0, s_wasmWrapperSuffix.Length); diff --git a/src/tests/tracing/eventpipe/common/Microsoft.Diagnostics.NETCore.Client/DiagnosticsServerRouter/DiagnosticsServerRouterFactory.cs b/src/tests/tracing/eventpipe/common/Microsoft.Diagnostics.NETCore.Client/DiagnosticsServerRouter/DiagnosticsServerRouterFactory.cs index 30ccdc1a48f4be..41726e9286791b 100644 --- a/src/tests/tracing/eventpipe/common/Microsoft.Diagnostics.NETCore.Client/DiagnosticsServerRouter/DiagnosticsServerRouterFactory.cs +++ b/src/tests/tracing/eventpipe/common/Microsoft.Diagnostics.NETCore.Client/DiagnosticsServerRouter/DiagnosticsServerRouterFactory.cs @@ -136,7 +136,7 @@ protected async Task IsStreamConnectedAsync(Stream stream, CancellationToken tok protected bool IsCompletedSuccessfully(Task t) { -#if NETCOREAPP2_0_OR_GREATER +#if NET return t.IsCompletedSuccessfully; #else return t.IsCompleted && !t.IsCanceled && !t.IsFaulted; From 3f47add997451b6b0e5689008f1915653ed41002 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 29 Apr 2024 12:30:30 -0700 Subject: [PATCH 143/161] Bump dotnet/actions-create-pull-request from 3 to 4 (#101586) Bumps [dotnet/actions-create-pull-request](https://github.com/dotnet/actions-create-pull-request) from 3 to 4. - [Commits](https://github.com/dotnet/actions-create-pull-request/compare/v3...v4) --- updated-dependencies: - dependency-name: dotnet/actions-create-pull-request dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/aspnetcore-sync.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/aspnetcore-sync.yml b/.github/workflows/aspnetcore-sync.yml index 12cc86c47b8983..e80fb301fa4cbe 100644 --- a/.github/workflows/aspnetcore-sync.yml +++ b/.github/workflows/aspnetcore-sync.yml @@ -57,7 +57,7 @@ jobs: - name: Send PR if: steps.check.outputs.changed == 'true' # https://github.com/marketplace/actions/create-pull-request - uses: dotnet/actions-create-pull-request@v3 + uses: dotnet/actions-create-pull-request@v4 with: token: ${{ secrets.GITHUB_TOKEN }} path: .\runtime From 6cd329b25315c5f21e86dac74f6cbe6d0deb6b0e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 29 Apr 2024 13:02:06 -0700 Subject: [PATCH 144/161] Bump actions/checkout v4 and set dependabot to only bump its major versions (#101585) * Bump actions/checkout from 2.0.0 to 4.1.4 Bumps [actions/checkout](https://github.com/actions/checkout) from 2.0.0 to 4.1.4. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/v2...v4.1.4) --- updated-dependencies: - dependency-name: actions/checkout dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] * Set dependabot to bump github-actions to major versions; use checkout v4 * Ignore patch and minor updates to actions/checkout --------- Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Jeff Handley --- .github/dependabot.yml | 3 +++ .github/workflows/aspnetcore-sync.yml | 4 ++-- .github/workflows/bump-chrome-version.yml | 2 +- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 9a538c12cfa42d..806f7fad67b045 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -7,3 +7,6 @@ updates: open-pull-requests-limit: 5 labels: - area-codeflow + ignore: + - dependency-name: "actions/checkout" + update-types: ["version-update:semver-patch","version-update:semver-minor"] diff --git a/.github/workflows/aspnetcore-sync.yml b/.github/workflows/aspnetcore-sync.yml index e80fb301fa4cbe..582f371cf9ab49 100644 --- a/.github/workflows/aspnetcore-sync.yml +++ b/.github/workflows/aspnetcore-sync.yml @@ -16,14 +16,14 @@ jobs: runs-on: windows-latest steps: - name: Checkout aspnetcore - uses: actions/checkout@v2.0.0 + uses: actions/checkout@v4 with: # Test this script using changes in a fork repository: 'dotnet/aspnetcore' path: aspnetcore ref: main - name: Checkout runtime - uses: actions/checkout@v2.0.0 + uses: actions/checkout@v4 with: # Test this script using changes in a fork repository: 'dotnet/runtime' diff --git a/.github/workflows/bump-chrome-version.yml b/.github/workflows/bump-chrome-version.yml index e47563ca44a071..e1d1e89658ca02 100644 --- a/.github/workflows/bump-chrome-version.yml +++ b/.github/workflows/bump-chrome-version.yml @@ -16,7 +16,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Setup Branch run: | git config user.name github-actions[bot] From 33a68d0cef067034df5cbac89415568e5fda63ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Strehovsk=C3=BD?= Date: Tue, 30 Apr 2024 06:34:57 +0900 Subject: [PATCH 145/161] Reduce generic specialized code in console formatters (#101474) Move code that doesn't need to be generic to a non-generic method. Reduces the size of the Stage 2 goldilocks app by 1.4% since these methods are rather large (especially the `JsonConsoleFormatter` one) and we have many specializations. --- .../src/JsonConsoleFormatter.cs | 28 +++++++++++-------- .../src/SimpleConsoleFormatter.cs | 18 ++++++------ .../src/SystemdConsoleFormatter.cs | 13 ++++++--- 3 files changed, 36 insertions(+), 23 deletions(-) diff --git a/src/libraries/Microsoft.Extensions.Logging.Console/src/JsonConsoleFormatter.cs b/src/libraries/Microsoft.Extensions.Logging.Console/src/JsonConsoleFormatter.cs index 122556bbbe460c..b3ff45e33d9ed1 100644 --- a/src/libraries/Microsoft.Extensions.Logging.Console/src/JsonConsoleFormatter.cs +++ b/src/libraries/Microsoft.Extensions.Logging.Console/src/JsonConsoleFormatter.cs @@ -32,10 +32,16 @@ public override void Write(in LogEntry logEntry, IExternalScopeP { return; } - LogLevel logLevel = logEntry.LogLevel; - string category = logEntry.Category; - int eventId = logEntry.EventId.Id; - Exception? exception = logEntry.Exception; + + // We extract most of the work into a non-generic method to save code size. If this was left in the generic + // method, we'd get generic specialization for all TState parameters, but that's unnecessary. + WriteInternal(scopeProvider, textWriter, message, logEntry.LogLevel, logEntry.Category, logEntry.EventId.Id, logEntry.Exception, + logEntry.State != null, logEntry.State?.ToString(), logEntry.State as IReadOnlyCollection>); + } + + private void WriteInternal(IExternalScopeProvider? scopeProvider, TextWriter textWriter, string message, LogLevel logLevel, + string category, int eventId, Exception? exception, bool hasState, string? stateMessage, IReadOnlyCollection>? stateProperties) + { const int DefaultBufferSize = 1024; using (var output = new PooledByteBufferWriter(DefaultBufferSize)) { @@ -48,9 +54,9 @@ public override void Write(in LogEntry logEntry, IExternalScopeP DateTimeOffset dateTimeOffset = FormatterOptions.UseUtcTimestamp ? DateTimeOffset.UtcNow : DateTimeOffset.Now; writer.WriteString("Timestamp", dateTimeOffset.ToString(timestampFormat)); } - writer.WriteNumber(nameof(logEntry.EventId), eventId); - writer.WriteString(nameof(logEntry.LogLevel), GetLogLevelString(logLevel)); - writer.WriteString(nameof(logEntry.Category), category); + writer.WriteNumber(nameof(LogEntry.EventId), eventId); + writer.WriteString(nameof(LogEntry.LogLevel), GetLogLevelString(logLevel)); + writer.WriteString(nameof(LogEntry.Category), category); writer.WriteString("Message", message); if (exception != null) @@ -58,11 +64,11 @@ public override void Write(in LogEntry logEntry, IExternalScopeP writer.WriteString(nameof(Exception), exception.ToString()); } - if (logEntry.State != null) + if (hasState) { - writer.WriteStartObject(nameof(logEntry.State)); - writer.WriteString("Message", logEntry.State.ToString()); - if (logEntry.State is IReadOnlyCollection> stateProperties) + writer.WriteStartObject(nameof(LogEntry.State)); + writer.WriteString("Message", stateMessage); + if (stateProperties != null) { foreach (KeyValuePair item in stateProperties) { diff --git a/src/libraries/Microsoft.Extensions.Logging.Console/src/SimpleConsoleFormatter.cs b/src/libraries/Microsoft.Extensions.Logging.Console/src/SimpleConsoleFormatter.cs index 308c831dd2ea81..6aba8cb172ac8b 100644 --- a/src/libraries/Microsoft.Extensions.Logging.Console/src/SimpleConsoleFormatter.cs +++ b/src/libraries/Microsoft.Extensions.Logging.Console/src/SimpleConsoleFormatter.cs @@ -51,7 +51,15 @@ public override void Write(in LogEntry logEntry, IExternalScopeP { return; } - LogLevel logLevel = logEntry.LogLevel; + + // We extract most of the work into a non-generic method to save code size. If this was left in the generic + // method, we'd get generic specialization for all TState parameters, but that's unnecessary. + WriteInternal(scopeProvider, textWriter, message, logEntry.LogLevel, logEntry.EventId.Id, logEntry.Exception, logEntry.Category); + } + + private void WriteInternal(IExternalScopeProvider? scopeProvider, TextWriter textWriter, string message, LogLevel logLevel, + int eventId, Exception? exception, string category) + { ConsoleColors logLevelColors = GetLogLevelConsoleColors(logLevel); string logLevelString = GetLogLevelString(logLevel); @@ -70,14 +78,8 @@ public override void Write(in LogEntry logEntry, IExternalScopeP { textWriter.WriteColoredMessage(logLevelString, logLevelColors.Background, logLevelColors.Foreground); } - CreateDefaultLogMessage(textWriter, logEntry, message, scopeProvider); - } - private void CreateDefaultLogMessage(TextWriter textWriter, in LogEntry logEntry, string message, IExternalScopeProvider? scopeProvider) - { bool singleLine = FormatterOptions.SingleLine; - int eventId = logEntry.EventId.Id; - Exception? exception = logEntry.Exception; // Example: // info: ConsoleApp.Program[10] @@ -85,7 +87,7 @@ private void CreateDefaultLogMessage(TextWriter textWriter, in LogEntry< // category and event id textWriter.Write(LoglevelPadding); - textWriter.Write(logEntry.Category); + textWriter.Write(category); textWriter.Write('['); #if NETCOREAPP diff --git a/src/libraries/Microsoft.Extensions.Logging.Console/src/SystemdConsoleFormatter.cs b/src/libraries/Microsoft.Extensions.Logging.Console/src/SystemdConsoleFormatter.cs index 5c0626307db195..2d306fee1d0a4b 100644 --- a/src/libraries/Microsoft.Extensions.Logging.Console/src/SystemdConsoleFormatter.cs +++ b/src/libraries/Microsoft.Extensions.Logging.Console/src/SystemdConsoleFormatter.cs @@ -41,10 +41,15 @@ public override void Write(in LogEntry logEntry, IExternalScopeP { return; } - LogLevel logLevel = logEntry.LogLevel; - string category = logEntry.Category; - int eventId = logEntry.EventId.Id; - Exception? exception = logEntry.Exception; + + // We extract most of the work into a non-generic method to save code size. If this was left in the generic + // method, we'd get generic specialization for all TState parameters, but that's unnecessary. + WriteInternal(scopeProvider, textWriter, message, logEntry.LogLevel, logEntry.Category, logEntry.EventId.Id, logEntry.Exception); + } + + private void WriteInternal(IExternalScopeProvider? scopeProvider, TextWriter textWriter, string message, LogLevel logLevel, string category, + int eventId, Exception? exception) + { // systemd reads messages from standard out line-by-line in a 'message' format. // newline characters are treated as message delimiters, so we must replace them. // Messages longer than the journal LineMax setting (default: 48KB) are cropped. From aab8803eac4111a711b6eb65242ee8a5b14fa411 Mon Sep 17 00:00:00 2001 From: Stephen Toub Date: Mon, 29 Apr 2024 18:16:40 -0400 Subject: [PATCH 146/161] Disable TensorPrimitives vectorization of Log, Cbrt, Pow, and RootN (#101690) We had a test bug that was hiding cases where one of the expected / actual was NaN and the other wasn't. --- .../Numerics/Tensors/netcore/TensorPrimitives.Cbrt.cs | 2 +- .../Numerics/Tensors/netcore/TensorPrimitives.Log.cs | 2 +- .../Numerics/Tensors/netcore/TensorPrimitives.Pow.cs | 2 +- .../Numerics/Tensors/netcore/TensorPrimitives.RootN.cs | 2 +- src/libraries/System.Numerics.Tensors/tests/Helpers.cs | 10 ++++++++++ 5 files changed, 14 insertions(+), 4 deletions(-) diff --git a/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.Cbrt.cs b/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.Cbrt.cs index 1bc8b85696c121..3336411a098966 100644 --- a/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.Cbrt.cs +++ b/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.Cbrt.cs @@ -26,7 +26,7 @@ public static void Cbrt(ReadOnlySpan x, Span destination) private readonly struct CbrtOperator : IUnaryOperator where T : IRootFunctions { - public static bool Vectorizable => typeof(T) == typeof(float) || typeof(T) == typeof(double); + public static bool Vectorizable => false; // typeof(T) == typeof(float) || typeof(T) == typeof(double); // TODO: https://github.com/dotnet/runtime/issues/100535 public static T Invoke(T x) => T.Cbrt(x); diff --git a/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.Log.cs b/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.Log.cs index 74d17f036d9404..d3d2f3e9a705d3 100644 --- a/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.Log.cs +++ b/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.Log.cs @@ -161,7 +161,7 @@ public static Vector512 Invoke(Vector512 x) private readonly struct LogBaseOperator : IBinaryOperator where T : ILogarithmicFunctions { - public static bool Vectorizable => LogOperator.Vectorizable; + public static bool Vectorizable => false; //LogOperator.Vectorizable; // TODO: https://github.com/dotnet/runtime/issues/100535 public static T Invoke(T x, T y) => T.Log(x, y); public static Vector128 Invoke(Vector128 x, Vector128 y) => LogOperator.Invoke(x) / LogOperator.Invoke(y); public static Vector256 Invoke(Vector256 x, Vector256 y) => LogOperator.Invoke(x) / LogOperator.Invoke(y); diff --git a/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.Pow.cs b/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.Pow.cs index 72d35ed5be779f..263235e4a5c2e3 100644 --- a/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.Pow.cs +++ b/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.Pow.cs @@ -59,7 +59,7 @@ public static void Pow(T x, ReadOnlySpan y, Span destination) private readonly struct PowOperator : IBinaryOperator where T : IPowerFunctions { - public static bool Vectorizable => typeof(T) == typeof(float) || typeof(T) == typeof(double); + public static bool Vectorizable => false; // typeof(T) == typeof(float) || typeof(T) == typeof(double); // TODO: https://github.com/dotnet/runtime/issues/100535 public static T Invoke(T x, T y) => T.Pow(x, y); diff --git a/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.RootN.cs b/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.RootN.cs index e7c394892950a9..5a732f76936000 100644 --- a/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.RootN.cs +++ b/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.RootN.cs @@ -28,7 +28,7 @@ private readonly struct RootNOperator(int n) : IStatefulUnaryOperator wher { private readonly int _n = n; - public static bool Vectorizable => typeof(T) == typeof(float) || typeof(T) == typeof(double); + public static bool Vectorizable => false; // typeof(T) == typeof(float) || typeof(T) == typeof(double); // TODO: https://github.com/dotnet/runtime/issues/100535 public T Invoke(T x) => T.RootN(x, _n); diff --git a/src/libraries/System.Numerics.Tensors/tests/Helpers.cs b/src/libraries/System.Numerics.Tensors/tests/Helpers.cs index 729cacda351695..1cc399d0a5a52c 100644 --- a/src/libraries/System.Numerics.Tensors/tests/Helpers.cs +++ b/src/libraries/System.Numerics.Tensors/tests/Helpers.cs @@ -28,6 +28,11 @@ private static class DefaultTolerance where T : unmanaged, INumber public static bool IsEqualWithTolerance(T expected, T actual, T? tolerance = null) where T : unmanaged, INumber { + if (T.IsNaN(expected) != T.IsNaN(actual)) + { + return false; + } + tolerance = tolerance ?? DefaultTolerance.Value; T diff = T.Abs(expected - actual); return !(diff > tolerance && diff > T.Max(T.Abs(expected), T.Abs(actual)) * tolerance); @@ -35,6 +40,11 @@ public static bool IsEqualWithTolerance(T expected, T actual, T? tolerance = #else public static bool IsEqualWithTolerance(float expected, float actual, float? tolerance = null) { + if (float.IsNaN(expected) != float.IsNaN(actual)) + { + return false; + } + tolerance ??= DefaultFloatTolerance; float diff = MathF.Abs(expected - actual); return !(diff > tolerance && diff > MathF.Max(MathF.Abs(expected), MathF.Abs(actual)) * tolerance); From f9207e6c85bb6aebd9e7af7504fd3db28b32d058 Mon Sep 17 00:00:00 2001 From: Adeel Mujahid <3840695+am11@users.noreply.github.com> Date: Tue, 30 Apr 2024 04:02:07 +0300 Subject: [PATCH 147/161] Remove distros versions calculation (#100580) --- eng/common/native/init-distro-rid.sh | 18 +----------------- eng/pipelines/runtime.yml | 2 +- 2 files changed, 2 insertions(+), 18 deletions(-) diff --git a/eng/common/native/init-distro-rid.sh b/eng/common/native/init-distro-rid.sh index 228be0b1598629..83ea7aab0e081c 100644 --- a/eng/common/native/init-distro-rid.sh +++ b/eng/common/native/init-distro-rid.sh @@ -20,10 +20,6 @@ getNonPortableDistroRid() # shellcheck disable=SC1091 if [ -e "${rootfsDir}/etc/os-release" ]; then . "${rootfsDir}/etc/os-release" - if [ "${ID}" = "rhel" ] || [ "${ID}" = "rocky" ] || [ "${ID}" = "alpine" ] || [ "${ID}" = "ol" ]; then - VERSION_ID="${VERSION_ID%.*}" # Remove the last version digit for these distros - fi - if echo "${VERSION_ID:-}" | grep -qE '^([[:digit:]]|\.)+$'; then nonPortableRid="${ID}.${VERSION_ID}-${targetArch}" else @@ -48,19 +44,7 @@ getNonPortableDistroRid() nonPortableRid="android.$__android_sdk_version-${targetArch}" elif [ "$targetOs" = "illumos" ]; then __uname_version=$(uname -v) - case "$__uname_version" in - omnios-*) - __omnios_major_version=$(echo "$__uname_version" | cut -c9-10) - nonPortableRid="omnios.$__omnios_major_version-${targetArch}" - ;; - joyent_*) - __smartos_major_version=$(echo "$__uname_version" | cut -c9-10) - nonPortableRid="smartos.$__smartos_major_version-${targetArch}" - ;; - *) - nonPortableRid="illumos-${targetArch}" - ;; - esac + nonPortableRid="illumos-${targetArch}" elif [ "$targetOs" = "solaris" ]; then __uname_version=$(uname -v) __solaris_major_version=$(echo "$__uname_version" | cut -d'.' -f1) diff --git a/eng/pipelines/runtime.yml b/eng/pipelines/runtime.yml index 32f99429ffd692..dbf8e0a7fcc1e4 100644 --- a/eng/pipelines/runtime.yml +++ b/eng/pipelines/runtime.yml @@ -498,7 +498,7 @@ extends: jobParameters: testScope: innerloop nameSuffix: CoreCLR_NonPortable - buildArgs: -s clr.native+clr.tools+clr.corelib+clr.nativecorelib+clr.aot+clr.packages -c $(_BuildConfig) /p:PortableBuild=false + buildArgs: -s clr.native+clr.tools+clr.corelib+clr.nativecorelib+clr.aot+clr.packages --outputrid tizen.9.0.0-armel -c $(_BuildConfig) /p:PortableBuild=false timeoutInMinutes: 120 condition: >- or( From 55c904024601c133f8ad081bc704c3c1fc5c7c9b Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Mon, 29 Apr 2024 20:05:01 -0700 Subject: [PATCH 148/161] Arm64/Sve: Add SignExtend* and ZeroExtend* math APIs (#101702) * Add [Sign|Zero]Extend[8|16|32] APIs: * Add API to instruction mapping * eliminate extra movprfx for AllBitsSetMask * Add test cases --- src/coreclr/jit/hwintrinsiccodegenarm64.cpp | 3 +- src/coreclr/jit/hwintrinsiclistarm64sve.h | 7 +- .../Arm/Sve.PlatformNotSupported.cs | 158 +++++++++++++++++ .../src/System/Runtime/Intrinsics/Arm/Sve.cs | 160 ++++++++++++++++++ .../ref/System.Runtime.Intrinsics.cs | 17 ++ .../GenerateHWIntrinsicTests_Arm.cs | 28 ++- .../HardwareIntrinsics/Arm/Shared/Helpers.cs | 23 +++ 7 files changed, 386 insertions(+), 10 deletions(-) diff --git a/src/coreclr/jit/hwintrinsiccodegenarm64.cpp b/src/coreclr/jit/hwintrinsiccodegenarm64.cpp index f58ca6c6e858d5..1f7f2865631c10 100644 --- a/src/coreclr/jit/hwintrinsiccodegenarm64.cpp +++ b/src/coreclr/jit/hwintrinsiccodegenarm64.cpp @@ -448,14 +448,13 @@ void CodeGen::genHWIntrinsic(GenTreeHWIntrinsic* node) if (intrin.op3->isContained()) { assert(intrin.op3->IsVectorZero()); - if (intrin.op1->isContained()) + if (intrin.op1->isContained() || intrin.op1->IsMaskAllBitsSet()) { // We already skip importing ConditionalSelect if op1 == trueAll, however // if we still see it here, it is because we wrapped the predicated instruction // inside ConditionalSelect. // As such, no need to move the `falseReg` to `targetReg` // because the predicated instruction will eventually set it. - assert(intrin.op1->IsMaskAllBitsSet()); } else { diff --git a/src/coreclr/jit/hwintrinsiclistarm64sve.h b/src/coreclr/jit/hwintrinsiclistarm64sve.h index cbd5ea6eb4983e..b4d0c1319a2276 100644 --- a/src/coreclr/jit/hwintrinsiclistarm64sve.h +++ b/src/coreclr/jit/hwintrinsiclistarm64sve.h @@ -69,10 +69,15 @@ HARDWARE_INTRINSIC(Sve, LoadVectorUInt16ZeroExtendToUInt64, HARDWARE_INTRINSIC(Sve, LoadVectorUInt32ZeroExtendToInt64, -1, 2, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sve_ld1w, INS_invalid, INS_invalid, INS_invalid}, HW_Category_MemoryLoad, HW_Flag_Scalable|HW_Flag_ExplicitMaskedOperation|HW_Flag_LowMaskedOperation) HARDWARE_INTRINSIC(Sve, LoadVectorUInt32ZeroExtendToUInt64, -1, 2, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sve_ld1w, INS_invalid, INS_invalid}, HW_Category_MemoryLoad, HW_Flag_Scalable|HW_Flag_ExplicitMaskedOperation|HW_Flag_LowMaskedOperation) HARDWARE_INTRINSIC(Sve, Multiply, -1, 2, true, {INS_sve_mul, INS_sve_mul, INS_sve_mul, INS_sve_mul, INS_sve_mul, INS_sve_mul, INS_sve_mul, INS_sve_mul, INS_sve_fmul, INS_sve_fmul}, HW_Category_SIMD, HW_Flag_Scalable|HW_Flag_EmbeddedMaskedOperation|HW_Flag_HasRMWSemantics) +HARDWARE_INTRINSIC(Sve, SignExtend16, -1, -1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sve_sxth, INS_invalid, INS_sve_sxth, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SIMD, HW_Flag_Scalable|HW_Flag_EmbeddedMaskedOperation|HW_Flag_LowMaskedOperation) +HARDWARE_INTRINSIC(Sve, SignExtend32, -1, -1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sve_sxtw, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SIMD, HW_Flag_Scalable|HW_Flag_EmbeddedMaskedOperation|HW_Flag_LowMaskedOperation) +HARDWARE_INTRINSIC(Sve, SignExtend8, -1, -1, false, {INS_invalid, INS_invalid, INS_sve_sxtb, INS_invalid, INS_sve_sxtb, INS_invalid, INS_sve_sxtb, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SIMD, HW_Flag_Scalable|HW_Flag_EmbeddedMaskedOperation|HW_Flag_LowMaskedOperation) HARDWARE_INTRINSIC(Sve, Subtract, -1, 2, true, {INS_sve_sub, INS_sve_sub, INS_sve_sub, INS_sve_sub, INS_sve_sub, INS_sve_sub, INS_sve_sub, INS_sve_sub, INS_sve_fsub, INS_sve_fsub}, HW_Category_SIMD, HW_Flag_Scalable|HW_Flag_EmbeddedMaskedOperation|HW_Flag_HasRMWSemantics) - HARDWARE_INTRINSIC(Sve, UnzipEven, -1, 2, true, {INS_sve_uzp1, INS_sve_uzp1, INS_sve_uzp1, INS_sve_uzp1, INS_sve_uzp1, INS_sve_uzp1, INS_sve_uzp1, INS_sve_uzp1, INS_sve_uzp1, INS_sve_uzp1}, HW_Category_SIMD, HW_Flag_Scalable|HW_Flag_SpecialCodeGen) HARDWARE_INTRINSIC(Sve, UnzipOdd, -1, 2, true, {INS_sve_uzp2, INS_sve_uzp2, INS_sve_uzp2, INS_sve_uzp2, INS_sve_uzp2, INS_sve_uzp2, INS_sve_uzp2, INS_sve_uzp2, INS_sve_uzp2, INS_sve_uzp2}, HW_Category_SIMD, HW_Flag_Scalable|HW_Flag_SpecialCodeGen) +HARDWARE_INTRINSIC(Sve, ZeroExtend16, -1, -1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sve_uxth, INS_invalid, INS_sve_uxth, INS_invalid, INS_invalid}, HW_Category_SIMD, HW_Flag_Scalable|HW_Flag_EmbeddedMaskedOperation|HW_Flag_LowMaskedOperation) +HARDWARE_INTRINSIC(Sve, ZeroExtend32, -1, -1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sve_uxtw, INS_invalid, INS_invalid}, HW_Category_SIMD, HW_Flag_Scalable|HW_Flag_EmbeddedMaskedOperation|HW_Flag_LowMaskedOperation) +HARDWARE_INTRINSIC(Sve, ZeroExtend8, -1, -1, false, {INS_invalid, INS_invalid, INS_invalid, INS_sve_uxtb, INS_invalid, INS_sve_uxtb, INS_invalid, INS_sve_uxtb, INS_invalid, INS_invalid}, HW_Category_SIMD, HW_Flag_Scalable|HW_Flag_EmbeddedMaskedOperation|HW_Flag_LowMaskedOperation) HARDWARE_INTRINSIC(Sve, ZipHigh, -1, 2, true, {INS_sve_zip2, INS_sve_zip2, INS_sve_zip2, INS_sve_zip2, INS_sve_zip2, INS_sve_zip2, INS_sve_zip2, INS_sve_zip2, INS_sve_zip2, INS_sve_zip2}, HW_Category_SIMD, HW_Flag_Scalable|HW_Flag_SpecialCodeGen) HARDWARE_INTRINSIC(Sve, ZipLow, -1, 2, true, {INS_sve_zip1, INS_sve_zip1, INS_sve_zip1, INS_sve_zip1, INS_sve_zip1, INS_sve_zip1, INS_sve_zip1, INS_sve_zip1, INS_sve_zip1, INS_sve_zip1}, HW_Category_SIMD, HW_Flag_Scalable|HW_Flag_SpecialCodeGen) diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Arm/Sve.PlatformNotSupported.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Arm/Sve.PlatformNotSupported.cs index 84583b46874563..afbaa6e8969c52 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Arm/Sve.PlatformNotSupported.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Arm/Sve.PlatformNotSupported.cs @@ -1010,6 +1010,86 @@ internal Arm64() { } /// public static unsafe Vector Multiply(Vector left, Vector right) { throw new PlatformNotSupportedException(); } + /// SignExtend16 : Sign-extend the low 16 bits + + /// + /// svint32_t svexth[_s32]_m(svint32_t inactive, svbool_t pg, svint32_t op) + /// SXTH Ztied.S, Pg/M, Zop.S + /// MOVPRFX Zresult, Zinactive; SXTH Zresult.S, Pg/M, Zop.S + /// svint32_t svexth[_s32]_x(svbool_t pg, svint32_t op) + /// SXTH Ztied.S, Pg/M, Ztied.S + /// MOVPRFX Zresult, Zop; SXTH Zresult.S, Pg/M, Zop.S + /// svint32_t svexth[_s32]_z(svbool_t pg, svint32_t op) + /// MOVPRFX Zresult.S, Pg/Z, Zop.S; SXTH Zresult.S, Pg/M, Zop.S + /// + public static unsafe Vector SignExtend16(Vector value) { throw new PlatformNotSupportedException(); } + + /// + /// svint64_t svexth[_s64]_m(svint64_t inactive, svbool_t pg, svint64_t op) + /// SXTH Ztied.D, Pg/M, Zop.D + /// MOVPRFX Zresult, Zinactive; SXTH Zresult.D, Pg/M, Zop.D + /// svint64_t svexth[_s64]_x(svbool_t pg, svint64_t op) + /// SXTH Ztied.D, Pg/M, Ztied.D + /// MOVPRFX Zresult, Zop; SXTH Zresult.D, Pg/M, Zop.D + /// svint64_t svexth[_s64]_z(svbool_t pg, svint64_t op) + /// MOVPRFX Zresult.D, Pg/Z, Zop.D; SXTH Zresult.D, Pg/M, Zop.D + /// + public static unsafe Vector SignExtend16(Vector value) { throw new PlatformNotSupportedException(); } + + + /// SignExtend32 : Sign-extend the low 32 bits + + /// + /// svint64_t svextw[_s64]_m(svint64_t inactive, svbool_t pg, svint64_t op) + /// SXTW Ztied.D, Pg/M, Zop.D + /// MOVPRFX Zresult, Zinactive; SXTW Zresult.D, Pg/M, Zop.D + /// svint64_t svextw[_s64]_x(svbool_t pg, svint64_t op) + /// SXTW Ztied.D, Pg/M, Ztied.D + /// MOVPRFX Zresult, Zop; SXTW Zresult.D, Pg/M, Zop.D + /// svint64_t svextw[_s64]_z(svbool_t pg, svint64_t op) + /// MOVPRFX Zresult.D, Pg/Z, Zop.D; SXTW Zresult.D, Pg/M, Zop.D + /// + public static unsafe Vector SignExtend32(Vector value) { throw new PlatformNotSupportedException(); } + + + /// SignExtend8 : Sign-extend the low 8 bits + + /// + /// svint16_t svextb[_s16]_m(svint16_t inactive, svbool_t pg, svint16_t op) + /// SXTB Ztied.H, Pg/M, Zop.H + /// MOVPRFX Zresult, Zinactive; SXTB Zresult.H, Pg/M, Zop.H + /// svint16_t svextb[_s16]_x(svbool_t pg, svint16_t op) + /// SXTB Ztied.H, Pg/M, Ztied.H + /// MOVPRFX Zresult, Zop; SXTB Zresult.H, Pg/M, Zop.H + /// svint16_t svextb[_s16]_z(svbool_t pg, svint16_t op) + /// MOVPRFX Zresult.H, Pg/Z, Zop.H; SXTB Zresult.H, Pg/M, Zop.H + /// + public static unsafe Vector SignExtend8(Vector value) { throw new PlatformNotSupportedException(); } + + /// + /// svint32_t svextb[_s32]_m(svint32_t inactive, svbool_t pg, svint32_t op) + /// SXTB Ztied.S, Pg/M, Zop.S + /// MOVPRFX Zresult, Zinactive; SXTB Zresult.S, Pg/M, Zop.S + /// svint32_t svextb[_s32]_x(svbool_t pg, svint32_t op) + /// SXTB Ztied.S, Pg/M, Ztied.S + /// MOVPRFX Zresult, Zop; SXTB Zresult.S, Pg/M, Zop.S + /// svint32_t svextb[_s32]_z(svbool_t pg, svint32_t op) + /// MOVPRFX Zresult.S, Pg/Z, Zop.S; SXTB Zresult.S, Pg/M, Zop.S + /// + public static unsafe Vector SignExtend8(Vector value) { throw new PlatformNotSupportedException(); } + + /// + /// svint64_t svextb[_s64]_m(svint64_t inactive, svbool_t pg, svint64_t op) + /// SXTB Ztied.D, Pg/M, Zop.D + /// MOVPRFX Zresult, Zinactive; SXTB Zresult.D, Pg/M, Zop.D + /// svint64_t svextb[_s64]_x(svbool_t pg, svint64_t op) + /// SXTB Ztied.D, Pg/M, Ztied.D + /// MOVPRFX Zresult, Zop; SXTB Zresult.D, Pg/M, Zop.D + /// svint64_t svextb[_s64]_z(svbool_t pg, svint64_t op) + /// MOVPRFX Zresult.D, Pg/Z, Zop.D; SXTB Zresult.D, Pg/M, Zop.D + /// + public static unsafe Vector SignExtend8(Vector value) { throw new PlatformNotSupportedException(); } + /// Subtract : Subtract /// @@ -1248,6 +1328,84 @@ internal Arm64() { } /// public static unsafe Vector UnzipOdd(Vector left, Vector right) { throw new PlatformNotSupportedException(); } + /// ZeroExtend16 : Zero-extend the low 16 bits + + /// + /// svuint32_t svexth[_u32]_m(svuint32_t inactive, svbool_t pg, svuint32_t op) + /// UXTH Ztied.S, Pg/M, Zop.S + /// MOVPRFX Zresult, Zinactive; UXTH Zresult.S, Pg/M, Zop.S + /// svuint32_t svexth[_u32]_x(svbool_t pg, svuint32_t op) + /// UXTH Ztied.S, Pg/M, Ztied.S + /// AND Ztied.S, Ztied.S, #65535 + /// svuint32_t svexth[_u32]_z(svbool_t pg, svuint32_t op) + /// MOVPRFX Zresult.S, Pg/Z, Zop.S; UXTH Zresult.S, Pg/M, Zop.S + /// + public static unsafe Vector ZeroExtend16(Vector value) { throw new PlatformNotSupportedException(); } + + /// + /// svuint64_t svexth[_u64]_m(svuint64_t inactive, svbool_t pg, svuint64_t op) + /// UXTH Ztied.D, Pg/M, Zop.D + /// MOVPRFX Zresult, Zinactive; UXTH Zresult.D, Pg/M, Zop.D + /// svuint64_t svexth[_u64]_x(svbool_t pg, svuint64_t op) + /// UXTH Ztied.D, Pg/M, Ztied.D + /// AND Ztied.D, Ztied.D, #65535 + /// svuint64_t svexth[_u64]_z(svbool_t pg, svuint64_t op) + /// MOVPRFX Zresult.D, Pg/Z, Zop.D; UXTH Zresult.D, Pg/M, Zop.D + /// + public static unsafe Vector ZeroExtend16(Vector value) { throw new PlatformNotSupportedException(); } + + + /// ZeroExtend32 : Zero-extend the low 32 bits + + /// + /// svuint64_t svextw[_u64]_m(svuint64_t inactive, svbool_t pg, svuint64_t op) + /// UXTW Ztied.D, Pg/M, Zop.D + /// MOVPRFX Zresult, Zinactive; UXTW Zresult.D, Pg/M, Zop.D + /// svuint64_t svextw[_u64]_x(svbool_t pg, svuint64_t op) + /// UXTW Ztied.D, Pg/M, Ztied.D + /// AND Ztied.D, Ztied.D, #4294967295 + /// svuint64_t svextw[_u64]_z(svbool_t pg, svuint64_t op) + /// MOVPRFX Zresult.D, Pg/Z, Zop.D; UXTW Zresult.D, Pg/M, Zop.D + /// + public static unsafe Vector ZeroExtend32(Vector value) { throw new PlatformNotSupportedException(); } + + /// ZeroExtend8 : Zero-extend the low 8 bits + + /// + /// svuint16_t svextb[_u16]_m(svuint16_t inactive, svbool_t pg, svuint16_t op) + /// UXTB Ztied.H, Pg/M, Zop.H + /// MOVPRFX Zresult, Zinactive; UXTB Zresult.H, Pg/M, Zop.H + /// svuint16_t svextb[_u16]_x(svbool_t pg, svuint16_t op) + /// UXTB Ztied.H, Pg/M, Ztied.H + /// AND Ztied.H, Ztied.H, #255 + /// svuint16_t svextb[_u16]_z(svbool_t pg, svuint16_t op) + /// MOVPRFX Zresult.H, Pg/Z, Zop.H; UXTB Zresult.H, Pg/M, Zop.H + /// + public static unsafe Vector ZeroExtend8(Vector value) { throw new PlatformNotSupportedException(); } + + /// + /// svuint32_t svextb[_u32]_m(svuint32_t inactive, svbool_t pg, svuint32_t op) + /// UXTB Ztied.S, Pg/M, Zop.S + /// MOVPRFX Zresult, Zinactive; UXTB Zresult.S, Pg/M, Zop.S + /// svuint32_t svextb[_u32]_x(svbool_t pg, svuint32_t op) + /// UXTB Ztied.S, Pg/M, Ztied.S + /// AND Ztied.S, Ztied.S, #255 + /// svuint32_t svextb[_u32]_z(svbool_t pg, svuint32_t op) + /// MOVPRFX Zresult.S, Pg/Z, Zop.S; UXTB Zresult.S, Pg/M, Zop.S + /// + public static unsafe Vector ZeroExtend8(Vector value) { throw new PlatformNotSupportedException(); } + + /// + /// svuint64_t svextb[_u64]_m(svuint64_t inactive, svbool_t pg, svuint64_t op) + /// UXTB Ztied.D, Pg/M, Zop.D + /// MOVPRFX Zresult, Zinactive; UXTB Zresult.D, Pg/M, Zop.D + /// svuint64_t svextb[_u64]_x(svbool_t pg, svuint64_t op) + /// UXTB Ztied.D, Pg/M, Ztied.D + /// AND Ztied.D, Ztied.D, #255 + /// svuint64_t svextb[_u64]_z(svbool_t pg, svuint64_t op) + /// MOVPRFX Zresult.D, Pg/Z, Zop.D; UXTB Zresult.D, Pg/M, Zop.D + /// + public static unsafe Vector ZeroExtend8(Vector value) { throw new PlatformNotSupportedException(); } /// ZipHigh : Interleave elements from high halves of two inputs diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Arm/Sve.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Arm/Sve.cs index e823e36e4db2a9..7c2c8a0a4e78e6 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Arm/Sve.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Arm/Sve.cs @@ -1065,6 +1065,85 @@ internal Arm64() { } /// public static unsafe Vector Multiply(Vector left, Vector right) => Multiply(left, right); + /// SignExtend16 : Sign-extend the low 16 bits + + /// + /// svint32_t svexth[_s32]_m(svint32_t inactive, svbool_t pg, svint32_t op) + /// SXTH Ztied.S, Pg/M, Zop.S + /// MOVPRFX Zresult, Zinactive; SXTH Zresult.S, Pg/M, Zop.S + /// svint32_t svexth[_s32]_x(svbool_t pg, svint32_t op) + /// SXTH Ztied.S, Pg/M, Ztied.S + /// MOVPRFX Zresult, Zop; SXTH Zresult.S, Pg/M, Zop.S + /// svint32_t svexth[_s32]_z(svbool_t pg, svint32_t op) + /// MOVPRFX Zresult.S, Pg/Z, Zop.S; SXTH Zresult.S, Pg/M, Zop.S + /// + public static unsafe Vector SignExtend16(Vector value) => SignExtend16(value); + + /// + /// svint64_t svexth[_s64]_m(svint64_t inactive, svbool_t pg, svint64_t op) + /// SXTH Ztied.D, Pg/M, Zop.D + /// MOVPRFX Zresult, Zinactive; SXTH Zresult.D, Pg/M, Zop.D + /// svint64_t svexth[_s64]_x(svbool_t pg, svint64_t op) + /// SXTH Ztied.D, Pg/M, Ztied.D + /// MOVPRFX Zresult, Zop; SXTH Zresult.D, Pg/M, Zop.D + /// svint64_t svexth[_s64]_z(svbool_t pg, svint64_t op) + /// MOVPRFX Zresult.D, Pg/Z, Zop.D; SXTH Zresult.D, Pg/M, Zop.D + /// + public static unsafe Vector SignExtend16(Vector value) => SignExtend16(value); + + /// SignExtend32 : Sign-extend the low 32 bits + + /// + /// svint64_t svextw[_s64]_m(svint64_t inactive, svbool_t pg, svint64_t op) + /// SXTW Ztied.D, Pg/M, Zop.D + /// MOVPRFX Zresult, Zinactive; SXTW Zresult.D, Pg/M, Zop.D + /// svint64_t svextw[_s64]_x(svbool_t pg, svint64_t op) + /// SXTW Ztied.D, Pg/M, Ztied.D + /// MOVPRFX Zresult, Zop; SXTW Zresult.D, Pg/M, Zop.D + /// svint64_t svextw[_s64]_z(svbool_t pg, svint64_t op) + /// MOVPRFX Zresult.D, Pg/Z, Zop.D; SXTW Zresult.D, Pg/M, Zop.D + /// + public static unsafe Vector SignExtend32(Vector value) => SignExtend32(value); + + + /// SignExtend8 : Sign-extend the low 8 bits + + /// + /// svint16_t svextb[_s16]_m(svint16_t inactive, svbool_t pg, svint16_t op) + /// SXTB Ztied.H, Pg/M, Zop.H + /// MOVPRFX Zresult, Zinactive; SXTB Zresult.H, Pg/M, Zop.H + /// svint16_t svextb[_s16]_x(svbool_t pg, svint16_t op) + /// SXTB Ztied.H, Pg/M, Ztied.H + /// MOVPRFX Zresult, Zop; SXTB Zresult.H, Pg/M, Zop.H + /// svint16_t svextb[_s16]_z(svbool_t pg, svint16_t op) + /// MOVPRFX Zresult.H, Pg/Z, Zop.H; SXTB Zresult.H, Pg/M, Zop.H + /// + public static unsafe Vector SignExtend8(Vector value) => SignExtend8(value); + + /// + /// svint32_t svextb[_s32]_m(svint32_t inactive, svbool_t pg, svint32_t op) + /// SXTB Ztied.S, Pg/M, Zop.S + /// MOVPRFX Zresult, Zinactive; SXTB Zresult.S, Pg/M, Zop.S + /// svint32_t svextb[_s32]_x(svbool_t pg, svint32_t op) + /// SXTB Ztied.S, Pg/M, Ztied.S + /// MOVPRFX Zresult, Zop; SXTB Zresult.S, Pg/M, Zop.S + /// svint32_t svextb[_s32]_z(svbool_t pg, svint32_t op) + /// MOVPRFX Zresult.S, Pg/Z, Zop.S; SXTB Zresult.S, Pg/M, Zop.S + /// + public static unsafe Vector SignExtend8(Vector value) => SignExtend8(value); + + /// + /// svint64_t svextb[_s64]_m(svint64_t inactive, svbool_t pg, svint64_t op) + /// SXTB Ztied.D, Pg/M, Zop.D + /// MOVPRFX Zresult, Zinactive; SXTB Zresult.D, Pg/M, Zop.D + /// svint64_t svextb[_s64]_x(svbool_t pg, svint64_t op) + /// SXTB Ztied.D, Pg/M, Ztied.D + /// MOVPRFX Zresult, Zop; SXTB Zresult.D, Pg/M, Zop.D + /// svint64_t svextb[_s64]_z(svbool_t pg, svint64_t op) + /// MOVPRFX Zresult.D, Pg/Z, Zop.D; SXTB Zresult.D, Pg/M, Zop.D + /// + public static unsafe Vector SignExtend8(Vector value) => SignExtend8(value); + /// Subtract : Subtract /// @@ -1329,6 +1408,87 @@ internal Arm64() { } /// UZP2 Presult.D, Pop1.D, Pop2.D /// public static unsafe Vector UnzipOdd(Vector left, Vector right) => UnzipOdd(left, right); + + /// ZeroExtend16 : Zero-extend the low 16 bits + + /// + /// svuint32_t svexth[_u32]_m(svuint32_t inactive, svbool_t pg, svuint32_t op) + /// UXTH Ztied.S, Pg/M, Zop.S + /// MOVPRFX Zresult, Zinactive; UXTH Zresult.S, Pg/M, Zop.S + /// svuint32_t svexth[_u32]_x(svbool_t pg, svuint32_t op) + /// UXTH Ztied.S, Pg/M, Ztied.S + /// AND Ztied.S, Ztied.S, #65535 + /// svuint32_t svexth[_u32]_z(svbool_t pg, svuint32_t op) + /// MOVPRFX Zresult.S, Pg/Z, Zop.S; UXTH Zresult.S, Pg/M, Zop.S + /// + public static unsafe Vector ZeroExtend16(Vector value) => ZeroExtend16(value); + + /// + /// svuint64_t svexth[_u64]_m(svuint64_t inactive, svbool_t pg, svuint64_t op) + /// UXTH Ztied.D, Pg/M, Zop.D + /// MOVPRFX Zresult, Zinactive; UXTH Zresult.D, Pg/M, Zop.D + /// svuint64_t svexth[_u64]_x(svbool_t pg, svuint64_t op) + /// UXTH Ztied.D, Pg/M, Ztied.D + /// AND Ztied.D, Ztied.D, #65535 + /// svuint64_t svexth[_u64]_z(svbool_t pg, svuint64_t op) + /// MOVPRFX Zresult.D, Pg/Z, Zop.D; UXTH Zresult.D, Pg/M, Zop.D + /// + public static unsafe Vector ZeroExtend16(Vector value) => ZeroExtend16(value); + + + /// ZeroExtend32 : Zero-extend the low 32 bits + + /// + /// svuint64_t svextw[_u64]_m(svuint64_t inactive, svbool_t pg, svuint64_t op) + /// UXTW Ztied.D, Pg/M, Zop.D + /// MOVPRFX Zresult, Zinactive; UXTW Zresult.D, Pg/M, Zop.D + /// svuint64_t svextw[_u64]_x(svbool_t pg, svuint64_t op) + /// UXTW Ztied.D, Pg/M, Ztied.D + /// AND Ztied.D, Ztied.D, #4294967295 + /// svuint64_t svextw[_u64]_z(svbool_t pg, svuint64_t op) + /// MOVPRFX Zresult.D, Pg/Z, Zop.D; UXTW Zresult.D, Pg/M, Zop.D + /// + public static unsafe Vector ZeroExtend32(Vector value) => ZeroExtend32(value); + + + /// ZeroExtend8 : Zero-extend the low 8 bits + + /// + /// svuint16_t svextb[_u16]_m(svuint16_t inactive, svbool_t pg, svuint16_t op) + /// UXTB Ztied.H, Pg/M, Zop.H + /// MOVPRFX Zresult, Zinactive; UXTB Zresult.H, Pg/M, Zop.H + /// svuint16_t svextb[_u16]_x(svbool_t pg, svuint16_t op) + /// UXTB Ztied.H, Pg/M, Ztied.H + /// AND Ztied.H, Ztied.H, #255 + /// svuint16_t svextb[_u16]_z(svbool_t pg, svuint16_t op) + /// MOVPRFX Zresult.H, Pg/Z, Zop.H; UXTB Zresult.H, Pg/M, Zop.H + /// + public static unsafe Vector ZeroExtend8(Vector value) => ZeroExtend8(value); + + /// + /// svuint32_t svextb[_u32]_m(svuint32_t inactive, svbool_t pg, svuint32_t op) + /// UXTB Ztied.S, Pg/M, Zop.S + /// MOVPRFX Zresult, Zinactive; UXTB Zresult.S, Pg/M, Zop.S + /// svuint32_t svextb[_u32]_x(svbool_t pg, svuint32_t op) + /// UXTB Ztied.S, Pg/M, Ztied.S + /// AND Ztied.S, Ztied.S, #255 + /// svuint32_t svextb[_u32]_z(svbool_t pg, svuint32_t op) + /// MOVPRFX Zresult.S, Pg/Z, Zop.S; UXTB Zresult.S, Pg/M, Zop.S + /// + public static unsafe Vector ZeroExtend8(Vector value) => ZeroExtend8(value); + + /// + /// svuint64_t svextb[_u64]_m(svuint64_t inactive, svbool_t pg, svuint64_t op) + /// UXTB Ztied.D, Pg/M, Zop.D + /// MOVPRFX Zresult, Zinactive; UXTB Zresult.D, Pg/M, Zop.D + /// svuint64_t svextb[_u64]_x(svbool_t pg, svuint64_t op) + /// UXTB Ztied.D, Pg/M, Ztied.D + /// AND Ztied.D, Ztied.D, #255 + /// svuint64_t svextb[_u64]_z(svbool_t pg, svuint64_t op) + /// MOVPRFX Zresult.D, Pg/Z, Zop.D; UXTB Zresult.D, Pg/M, Zop.D + /// + public static unsafe Vector ZeroExtend8(Vector value) => ZeroExtend8(value); + /// ZipHigh : Interleave elements from high halves of two inputs /// diff --git a/src/libraries/System.Runtime.Intrinsics/ref/System.Runtime.Intrinsics.cs b/src/libraries/System.Runtime.Intrinsics/ref/System.Runtime.Intrinsics.cs index f67349e325b27e..88839fee87dcad 100644 --- a/src/libraries/System.Runtime.Intrinsics/ref/System.Runtime.Intrinsics.cs +++ b/src/libraries/System.Runtime.Intrinsics/ref/System.Runtime.Intrinsics.cs @@ -4279,6 +4279,14 @@ internal Arm64() { } public static unsafe System.Numerics.Vector LoadVectorUInt16ZeroExtendToUInt64(System.Numerics.Vector mask, ushort* address) { throw null; } public static unsafe System.Numerics.Vector LoadVectorUInt32ZeroExtendToInt64(System.Numerics.Vector mask, uint* address) { throw null; } public static unsafe System.Numerics.Vector LoadVectorUInt32ZeroExtendToUInt64(System.Numerics.Vector mask, uint* address) { throw null; } + + public static System.Numerics.Vector SignExtend16(System.Numerics.Vector value) { throw null; } + public static System.Numerics.Vector SignExtend16(System.Numerics.Vector value) { throw null; } + public static System.Numerics.Vector SignExtend32(System.Numerics.Vector value) { throw null; } + public static System.Numerics.Vector SignExtend8(System.Numerics.Vector value) { throw null; } + public static System.Numerics.Vector SignExtend8(System.Numerics.Vector value) { throw null; } + public static System.Numerics.Vector SignExtend8(System.Numerics.Vector value) { throw null; } + public static System.Numerics.Vector Subtract(System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } public static System.Numerics.Vector Subtract(System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } public static System.Numerics.Vector Subtract(System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } @@ -4289,6 +4297,7 @@ internal Arm64() { } public static System.Numerics.Vector Subtract(System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } public static System.Numerics.Vector Subtract(System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } public static System.Numerics.Vector Subtract(System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } + public static System.Numerics.Vector Multiply(System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } public static System.Numerics.Vector Multiply(System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } public static System.Numerics.Vector Multiply(System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } @@ -4299,6 +4308,7 @@ internal Arm64() { } public static System.Numerics.Vector Multiply(System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } public static System.Numerics.Vector Multiply(System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } public static System.Numerics.Vector Multiply(System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } + public static System.Numerics.Vector UnzipEven(System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } public static System.Numerics.Vector UnzipEven(System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } public static System.Numerics.Vector UnzipEven(System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } @@ -4321,6 +4331,13 @@ internal Arm64() { } public static System.Numerics.Vector UnzipOdd(System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } public static System.Numerics.Vector UnzipOdd(System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } + public static System.Numerics.Vector ZeroExtend16(System.Numerics.Vector value) { throw null; } + public static System.Numerics.Vector ZeroExtend16(System.Numerics.Vector value) { throw null; } + public static System.Numerics.Vector ZeroExtend32(System.Numerics.Vector value) { throw null; } + public static System.Numerics.Vector ZeroExtend8(System.Numerics.Vector value) { throw null; } + public static System.Numerics.Vector ZeroExtend8(System.Numerics.Vector value) { throw null; } + public static System.Numerics.Vector ZeroExtend8(System.Numerics.Vector value) { throw null; } + public static System.Numerics.Vector ZipHigh(System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } public static System.Numerics.Vector ZipHigh(System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } public static System.Numerics.Vector ZipHigh(System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } diff --git a/src/tests/Common/GenerateHWIntrinsicTests/GenerateHWIntrinsicTests_Arm.cs b/src/tests/Common/GenerateHWIntrinsicTests/GenerateHWIntrinsicTests_Arm.cs index 9ef86027848352..589217ca968e4a 100644 --- a/src/tests/Common/GenerateHWIntrinsicTests/GenerateHWIntrinsicTests_Arm.cs +++ b/src/tests/Common/GenerateHWIntrinsicTests/GenerateHWIntrinsicTests_Arm.cs @@ -2972,12 +2972,6 @@ ("SveLoadMaskedUnOpTest.template", new Dictionary { ["TestName"] = "SveLoadVector_uint", ["Isa"] = "Sve", ["Method"] = "LoadVector", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt32", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "64", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), ("SveLoadMaskedUnOpTest.template", new Dictionary { ["TestName"] = "SveLoadVector_ulong", ["Isa"] = "Sve", ["Method"] = "LoadVector", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt64", ["Op2BaseType"] = "UInt64", ["LargestVectorSize"] = "64", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt64()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), - ("SveLoadMaskedUnOpTest.template", new Dictionary { ["TestName"] = "SveLoadVectorByteZeroExtendToInt16", ["Isa"] = "Sve", ["Method"] = "LoadVectorByteZeroExtendToInt16", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Int16", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "8", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), - ("SveLoadMaskedUnOpTest.template", new Dictionary { ["TestName"] = "SveLoadVectorByteZeroExtendToInt32", ["Isa"] = "Sve", ["Method"] = "LoadVectorByteZeroExtendToInt32", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Int32", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "8", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), - ("SveLoadMaskedUnOpTest.template", new Dictionary { ["TestName"] = "SveLoadVectorByteZeroExtendToInt64", ["Isa"] = "Sve", ["Method"] = "LoadVectorByteZeroExtendToInt64", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Int64", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "8", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), - ("SveLoadMaskedUnOpTest.template", new Dictionary { ["TestName"] = "SveLoadVectorByteZeroExtendToUInt16", ["Isa"] = "Sve", ["Method"] = "LoadVectorByteZeroExtendToUInt16", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt16", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "8", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), - ("SveLoadMaskedUnOpTest.template", new Dictionary { ["TestName"] = "SveLoadVectorByteZeroExtendToUInt32", ["Isa"] = "Sve", ["Method"] = "LoadVectorByteZeroExtendToUInt32", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt32", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "8", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), - ("SveLoadMaskedUnOpTest.template", new Dictionary { ["TestName"] = "SveLoadVectorByteZeroExtendToUInt64", ["Isa"] = "Sve", ["Method"] = "LoadVectorByteZeroExtendToUInt64", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt64", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "8", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), ("SveLoadMaskedUnOpTest.template", new Dictionary { ["TestName"] = "SveLoadVectorInt16SignExtendToInt32", ["Isa"] = "Sve", ["Method"] = "LoadVectorInt16SignExtendToInt32", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Int32", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "8", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), ("SveLoadMaskedUnOpTest.template", new Dictionary { ["TestName"] = "SveLoadVectorInt16SignExtendToInt64", ["Isa"] = "Sve", ["Method"] = "LoadVectorInt16SignExtendToInt64", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Int64", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "8", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), ("SveLoadMaskedUnOpTest.template", new Dictionary { ["TestName"] = "SveLoadVectorInt16SignExtendToUInt32", ["Isa"] = "Sve", ["Method"] = "LoadVectorInt16SignExtendToUInt32", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt32", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "8", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), @@ -2990,6 +2984,12 @@ ("SveLoadMaskedUnOpTest.template", new Dictionary { ["TestName"] = "SveLoadVectorSByteSignExtendToUInt16", ["Isa"] = "Sve", ["Method"] = "LoadVectorSByteSignExtendToUInt16", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt16", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "8", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), ("SveLoadMaskedUnOpTest.template", new Dictionary { ["TestName"] = "SveLoadVectorSByteSignExtendToUInt32", ["Isa"] = "Sve", ["Method"] = "LoadVectorSByteSignExtendToUInt32", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt32", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "8", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), ("SveLoadMaskedUnOpTest.template", new Dictionary { ["TestName"] = "SveLoadVectorSByteSignExtendToUInt64", ["Isa"] = "Sve", ["Method"] = "LoadVectorSByteSignExtendToUInt64", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt64", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "8", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "(ulong)firstOp[i] != result[i]"}), + ("SveLoadMaskedUnOpTest.template", new Dictionary { ["TestName"] = "SveLoadVectorByteZeroExtendToInt16", ["Isa"] = "Sve", ["Method"] = "LoadVectorByteZeroExtendToInt16", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Int16", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "8", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), + ("SveLoadMaskedUnOpTest.template", new Dictionary { ["TestName"] = "SveLoadVectorByteZeroExtendToInt32", ["Isa"] = "Sve", ["Method"] = "LoadVectorByteZeroExtendToInt32", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Int32", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "8", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), + ("SveLoadMaskedUnOpTest.template", new Dictionary { ["TestName"] = "SveLoadVectorByteZeroExtendToInt64", ["Isa"] = "Sve", ["Method"] = "LoadVectorByteZeroExtendToInt64", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Int64", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "8", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), + ("SveLoadMaskedUnOpTest.template", new Dictionary { ["TestName"] = "SveLoadVectorByteZeroExtendToUInt16", ["Isa"] = "Sve", ["Method"] = "LoadVectorByteZeroExtendToUInt16", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt16", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "8", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), + ("SveLoadMaskedUnOpTest.template", new Dictionary { ["TestName"] = "SveLoadVectorByteZeroExtendToUInt32", ["Isa"] = "Sve", ["Method"] = "LoadVectorByteZeroExtendToUInt32", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt32", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "8", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), + ("SveLoadMaskedUnOpTest.template", new Dictionary { ["TestName"] = "SveLoadVectorByteZeroExtendToUInt64", ["Isa"] = "Sve", ["Method"] = "LoadVectorByteZeroExtendToUInt64", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt64", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "8", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), ("SveLoadMaskedUnOpTest.template", new Dictionary { ["TestName"] = "SveLoadVectorUInt16ZeroExtendToInt32", ["Isa"] = "Sve", ["Method"] = "LoadVectorUInt16ZeroExtendToInt32", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Int32", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "8", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), ("SveLoadMaskedUnOpTest.template", new Dictionary { ["TestName"] = "SveLoadVectorUInt16ZeroExtendToInt64", ["Isa"] = "Sve", ["Method"] = "LoadVectorUInt16ZeroExtendToInt64", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Int64", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "8", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), ("SveLoadMaskedUnOpTest.template", new Dictionary { ["TestName"] = "SveLoadVectorUInt16ZeroExtendToUInt32", ["Isa"] = "Sve", ["Method"] = "LoadVectorUInt16ZeroExtendToUInt32", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt32", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "8", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), @@ -3008,6 +3008,13 @@ ("SveVecBinOpTest.template", new Dictionary { ["TestName"] = "Sve_Multiply_uint", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "Multiply", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "Helpers.Multiply(left[i], right[i]) != result[i]", ["GetIterResult"] = "Helpers.Multiply(left[i], right[i])"}), ("SveVecBinOpTest.template", new Dictionary { ["TestName"] = "Sve_Multiply_ulong", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "Multiply", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt64", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "UInt64", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt64()", ["ValidateIterResult"] = "Helpers.Multiply(left[i], right[i]) != result[i]", ["GetIterResult"] = "Helpers.Multiply(left[i], right[i])"}), + ("SveSimpleVecOpTest.template", new Dictionary { ["TestName"] = "Sve_SignExtend16_int", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "SignExtend16", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Int32", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "result[i] != Helpers.SignExtend(firstOp[i], 16, false)", ["GetIterResult"] = "Helpers.SignExtend(leftOp[i], 16, false)"}), + ("SveSimpleVecOpTest.template", new Dictionary { ["TestName"] = "Sve_SignExtend16_long", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "SignExtend16", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Int64", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["ValidateIterResult"] = "result[i] != Helpers.SignExtend(firstOp[i], 16, false)", ["GetIterResult"] = "Helpers.SignExtend(leftOp[i], 16, false)"}), + ("SveSimpleVecOpTest.template", new Dictionary { ["TestName"] = "Sve_SignExtend32_long", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "SignExtend32", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Int64", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["ValidateIterResult"] = "result[i] != Helpers.SignExtend(firstOp[i], 32, false)", ["GetIterResult"] = "Helpers.SignExtend(leftOp[i], 32, false)"}), + ("SveSimpleVecOpTest.template", new Dictionary { ["TestName"] = "Sve_SignExtend8_short", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "SignExtend8", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Int16", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "result[i] != Helpers.SignExtend(firstOp[i], 8, false)", ["GetIterResult"] = "Helpers.SignExtend(leftOp[i], 8, false)"}), + ("SveSimpleVecOpTest.template", new Dictionary { ["TestName"] = "Sve_SignExtend8_int", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "SignExtend8", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Int32", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "result[i] != Helpers.SignExtend(firstOp[i], 8, false)", ["GetIterResult"] = "Helpers.SignExtend(leftOp[i], 8, false)"}), + ("SveSimpleVecOpTest.template", new Dictionary { ["TestName"] = "Sve_SignExtend8_long", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "SignExtend8", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Int64", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["ValidateIterResult"] = "result[i] != Helpers.SignExtend(firstOp[i], 8, false)", ["GetIterResult"] = "Helpers.SignExtend(leftOp[i], 8, false)"}), + ("SveVecBinOpTest.template", new Dictionary { ["TestName"] = "Sve_Subtract_float", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "Subtract", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "Helpers.Subtract(left[i], right[i]) != result[i]", ["GetIterResult"] = "Helpers.Subtract(left[i], right[i])"}), ("SveVecBinOpTest.template", new Dictionary { ["TestName"] = "Sve_Subtract_double", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "Subtract", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "Double", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["ValidateIterResult"] = "Helpers.Subtract(left[i], right[i]) != result[i]", ["GetIterResult"] = "Helpers.Subtract(left[i], right[i])"}), ("SveVecBinOpTest.template", new Dictionary { ["TestName"] = "Sve_Subtract_sbyte", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "Subtract", ["RetVectorType"] = "Vector", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "(sbyte)TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.Subtract(left[i], right[i]) != result[i]", ["GetIterResult"] = "Helpers.Subtract(left[i], right[i])"}), @@ -3039,7 +3046,14 @@ ("SveVecPairBinOpTest.template", new Dictionary { ["TestName"] = "SveUnzipOdd_ushort", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "UnzipOdd", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["ValidateEntry"] = "result[index] != left[i + 1] || result[index + half] != right[i + 1]"}), ("SveVecPairBinOpTest.template", new Dictionary { ["TestName"] = "SveUnzipOdd_uint", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "UnzipOdd", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["ValidateEntry"] = "result[index] != left[i + 1] || result[index + half] != right[i + 1]"}), ("SveVecPairBinOpTest.template", new Dictionary { ["TestName"] = "SveUnzipOdd_ulong", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "UnzipOdd", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt64", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "UInt64", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt64()", ["ValidateEntry"] = "result[index] != left[i + 1] || result[index + half] != right[i + 1]"}), - + + ("SveSimpleVecOpTest.template", new Dictionary { ["TestName"] = "Sve_ZeroExtend16_uint", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "ZeroExtend16", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "result[i] != Helpers.SignExtend(firstOp[i], 16, true)", ["GetIterResult"] = "Helpers.SignExtend(leftOp[i], 16, true)"}), + ("SveSimpleVecOpTest.template", new Dictionary { ["TestName"] = "Sve_ZeroExtend16_ulong", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "ZeroExtend16", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt64", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "(TestLibrary.Generator.GetUInt64() & 0x3FFFFFFFFFFFFFFF)", ["ValidateIterResult"] = "result[i] != Helpers.SignExtend(firstOp[i], 16, true)", ["GetIterResult"] = "Helpers.SignExtend(leftOp[i], 16, true)"}), + ("SveSimpleVecOpTest.template", new Dictionary { ["TestName"] = "Sve_ZeroExtend32_ulong", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "ZeroExtend32", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt64", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "(TestLibrary.Generator.GetUInt64() & 0x3FFFFFFFFFFFFFFF)", ["ValidateIterResult"] = "result[i] != Helpers.SignExtend(firstOp[i], 32, true)", ["GetIterResult"] = "Helpers.SignExtend(leftOp[i], 32, true)"}), + ("SveSimpleVecOpTest.template", new Dictionary { ["TestName"] = "Sve_ZeroExtend8_ushort", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "ZeroExtend8", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "result[i] != Helpers.SignExtend(firstOp[i], 8, true)", ["GetIterResult"] = "Helpers.SignExtend(leftOp[i], 8, true)"}), + ("SveSimpleVecOpTest.template", new Dictionary { ["TestName"] = "Sve_ZeroExtend8_uint", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "ZeroExtend8", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "result[i] != Helpers.SignExtend(firstOp[i], 8, true)", ["GetIterResult"] = "Helpers.SignExtend(leftOp[i], 8, true)"}), + ("SveSimpleVecOpTest.template", new Dictionary { ["TestName"] = "Sve_ZeroExtend8_ulong", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "ZeroExtend8", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt64", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "(TestLibrary.Generator.GetUInt64() & 0x3FFFFFFFFFFFFFFF)", ["ValidateIterResult"] = "result[i] != Helpers.SignExtend(firstOp[i], 8, true)", ["GetIterResult"] = "Helpers.SignExtend(leftOp[i], 8, true)"}), + ("SveVecPairBinOpTest.template", new Dictionary { ["TestName"] = "SveZipHigh_float", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "ZipHigh", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateEntry"] = "result[i] != left[index + half] || result[i + 1] != right[index + half]"}), ("SveVecPairBinOpTest.template", new Dictionary { ["TestName"] = "SveZipHigh_double", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "ZipHigh", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "Double", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["ValidateEntry"] = "result[i] != left[index + half] || result[i + 1] != right[index + half]"}), ("SveVecPairBinOpTest.template", new Dictionary { ["TestName"] = "SveZipHigh_sbyte", ["Isa"] = "Sve", ["LoadIsa"] = "Sve", ["Method"] = "ZipHigh", ["RetVectorType"] = "Vector", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateEntry"] = "result[i] != left[index + half] || result[i + 1] != right[index + half]"}), diff --git a/src/tests/JIT/HardwareIntrinsics/Arm/Shared/Helpers.cs b/src/tests/JIT/HardwareIntrinsics/Arm/Shared/Helpers.cs index 4b44b29337573a..6e96c9fc080a5a 100644 --- a/src/tests/JIT/HardwareIntrinsics/Arm/Shared/Helpers.cs +++ b/src/tests/JIT/HardwareIntrinsics/Arm/Shared/Helpers.cs @@ -1701,6 +1701,29 @@ private static int HighNarrowing(long op1, bool round) public static long MultiplyWideningUpperAndSubtract(long[] op1, int[] op2, int[] op3, int i) => MultiplyWideningAndSubtract(op1[i], op2[i + op2.Length / 2], op3[i + op3.Length / 2]); + public static T SignExtend(T n, int numBits, bool zeroExtend) where T : struct, IComparable, IConvertible + { + // Get the underlying integer value + dynamic value = Convert.ChangeType(n, typeof(long)); + + // Mask to extract the lowest numBits + long mask = (1L << numBits) - 1; + long lowestBits = value & mask; + + // Sign extension for signed integers + long signBitMask = 1L << (numBits - 1); + if (!zeroExtend && ((lowestBits & signBitMask) != 0)) + { + // If sign bit is set, it's a negative number + return (T)Convert.ChangeType(-((~lowestBits & mask) + 1), typeof(T)); + } + else + { + // If sign bit is not set, it's a positive number + return (T)Convert.ChangeType(lowestBits, typeof(T)); + } + } + public static int SubtractHighNarrowing(long op1, long op2) => HighNarrowing((long)(op1 - op2), round: false); public static long SubtractHighNarrowingUpper(int[] op1, long[] op2, long[] op3, int i) => i < op1.Length ? op1[i] : SubtractHighNarrowing(op2[i - op1.Length], op3[i - op1.Length]); From 333fb71d54bd84256e740aa08f8b836d4cd71d98 Mon Sep 17 00:00:00 2001 From: AtariDreams Date: Tue, 30 Apr 2024 00:29:04 -0400 Subject: [PATCH 149/161] Optimize flips between 1 and 0 (#100491) We can solve this with a bit flip rather than + 1 mod 2. --- src/coreclr/jit/compiler.cpp | 2 +- src/coreclr/jit/emitxarch.cpp | 8 ++++---- src/coreclr/vm/gc_unwind_x86.inl | 5 +---- 3 files changed, 6 insertions(+), 9 deletions(-) diff --git a/src/coreclr/jit/compiler.cpp b/src/coreclr/jit/compiler.cpp index 60f306307b90cd..f15820a7dc5746 100644 --- a/src/coreclr/jit/compiler.cpp +++ b/src/coreclr/jit/compiler.cpp @@ -2193,7 +2193,7 @@ const char* Compiler::compRegVarName(regNumber reg, bool displayVar, bool isFloa // consecutive calls before printing static int index = 0; // for circular index into the name array - index = (index + 1) % 2; // circular reuse of index + index ^= 1; // circular reuse of index sprintf_s(nameVarReg[index], NAME_VAR_REG_BUFFER_LEN, "%s'%s'", getRegName(reg), VarNameToStr(varName)); return nameVarReg[index]; diff --git a/src/coreclr/jit/emitxarch.cpp b/src/coreclr/jit/emitxarch.cpp index 35cb3a986ee580..6fe7f00dddc359 100644 --- a/src/coreclr/jit/emitxarch.cpp +++ b/src/coreclr/jit/emitxarch.cpp @@ -10102,7 +10102,7 @@ const char* emitter::emitRegName(regNumber reg, emitAttr attr, bool varName) con suffix = 'd'; goto APPEND_SUFFIX; } - rbc = (rbc + 1) % 2; + rbc ^= 1; rb[rbc][0] = 'e'; rb[rbc][1] = rn[1]; rb[rbc][2] = rn[2]; @@ -10133,7 +10133,7 @@ const char* emitter::emitRegName(regNumber reg, emitAttr attr, bool varName) con { suffix = 'b'; APPEND_SUFFIX: - rbc = (rbc + 1) % 2; + rbc ^= 1; rb[rbc][0] = rn[0]; rb[rbc][1] = rn[1]; if (rn[2]) @@ -10151,7 +10151,7 @@ const char* emitter::emitRegName(regNumber reg, emitAttr attr, bool varName) con } else { - rbc = (rbc + 1) % 2; + rbc ^= 1; rb[rbc][0] = rn[1]; if (reg < 4) { @@ -10168,7 +10168,7 @@ const char* emitter::emitRegName(regNumber reg, emitAttr attr, bool varName) con #endif // TARGET_AMD64 #if defined(TARGET_X86) - rbc = (rbc + 1) % 2; + rbc ^= 1; rb[rbc][0] = rn[1]; rb[rbc][1] = 'l'; strcpy_s(&rb[rbc][2], sizeof(rb[0]) - 2, rn + 3); diff --git a/src/coreclr/vm/gc_unwind_x86.inl b/src/coreclr/vm/gc_unwind_x86.inl index 017f8f8f803a9e..33604336d28c52 100644 --- a/src/coreclr/vm/gc_unwind_x86.inl +++ b/src/coreclr/vm/gc_unwind_x86.inl @@ -1670,10 +1670,7 @@ unsigned scanArgRegTableI(PTR_CBYTE table, { thisPtrReg = REGI_NA; } - if (iptrRegs & regMask) - { - iptrRegs &= ~regMask; - } + iptrRegs &= ~regMask; } iptr = isThis = false; continue; From fcc2408188269837221ff73f169de161aa47acac Mon Sep 17 00:00:00 2001 From: Rich Lander Date: Mon, 29 Apr 2024 22:18:15 -0700 Subject: [PATCH 150/161] Update build instructions table (#101706) --- docs/workflow/building/coreclr/linux-instructions.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/workflow/building/coreclr/linux-instructions.md b/docs/workflow/building/coreclr/linux-instructions.md index 518208141e49f6..3acec5e95ad9a9 100644 --- a/docs/workflow/building/coreclr/linux-instructions.md +++ b/docs/workflow/building/coreclr/linux-instructions.md @@ -66,7 +66,7 @@ All official builds are cross-builds with a rootfs for the target OS, and will u | Azure Linux (x64) | Ubuntu 16.04 | arm32 (armhf) | `mcr.microsoft.com/dotnet-buildtools/prereqs:azurelinux-3.0-cross-arm-net9.0` | `/crossrootfs/arm` | | Azure Linux (x64) | Alpine | arm64 (arm64v8) | `mcr.microsoft.com/dotnet-buildtools/prereqs:azurelinux-3.0-cross-arm64-alpine-net9.0` | `/crossrootfs/arm64` | | Azure Linux (x64) | Ubuntu 16.04 | arm64 (arm64v8) | `mcr.microsoft.com/dotnet-buildtools/prereqs:azurelinux-3.0-cross-arm64-net9.0` | `/crossrootfs/arm64` | -| Azure Linux (x64) | Ubuntu 16.04 | x86 | `mcr.microsoft.com/dotnet-buildtools/prereqs:azurelinux-3.0-cross-x86-net8.0` | `/crossrootfs/x86` | +| Azure Linux (x64) | Ubuntu 16.04 | x86 | `mcr.microsoft.com/dotnet-buildtools/prereqs:azurelinux-3.0-cross-x86-net9.0` | `/crossrootfs/x86` | | CBL-mariner 2.0 (x64) | FreeBSD 13 | x64 | `mcr.microsoft.com/dotnet-buildtools/prereqs:cbl-mariner-2.0-cross-amd64-freebsd-13` | `/crossrootfs/x64` | These Docker images are built using the Dockerfiles maintained in the [dotnet-buildtools-prereqs-docker repo](https://github.com/dotnet/dotnet-buildtools-prereqs-docker). From fc09b220e1c6f48ab755f9f259b8441c58c0880c Mon Sep 17 00:00:00 2001 From: Matous Kozak <55735845+matouskozak@users.noreply.github.com> Date: Tue, 30 Apr 2024 10:48:33 +0200 Subject: [PATCH 151/161] [mono] Force Mono to respect explicit struct size when LayoutKind.Sequential is used (#101529) * respect explicit size with sequential layout * test for sequential layout with explicit size --- src/mono/mono/metadata/class-init.c | 2 +- src/mono/mono/metadata/marshal.c | 7 +- .../MarshalUnalignedStructArray.cs | 75 +++++++++++++++++++ 3 files changed, 81 insertions(+), 3 deletions(-) create mode 100644 src/tests/Interop/ArrayMarshalling/UnalignedStructArray/MarshalUnalignedStructArray.cs diff --git a/src/mono/mono/metadata/class-init.c b/src/mono/mono/metadata/class-init.c index 13cf1fa612b359..8608dc30bfc63a 100644 --- a/src/mono/mono/metadata/class-init.c +++ b/src/mono/mono/metadata/class-init.c @@ -2331,7 +2331,7 @@ mono_class_layout_fields (MonoClass *klass, int base_instance_size, int packing_ instance_size = MAX (real_size, instance_size); - if (instance_size & (min_align - 1)) { + if (instance_size & (min_align - 1) && !explicit_size) { instance_size += min_align - 1; instance_size &= ~(min_align - 1); } diff --git a/src/mono/mono/metadata/marshal.c b/src/mono/mono/metadata/marshal.c index 09fddd573c0fdb..aad740a31d90e5 100644 --- a/src/mono/mono/metadata/marshal.c +++ b/src/mono/mono/metadata/marshal.c @@ -5749,7 +5749,7 @@ MonoMarshalType * mono_marshal_load_type_info (MonoClass* klass) { int j, count = 0; - guint32 native_size = 0, min_align = 1, packing; + guint32 native_size = 0, min_align = 1, packing, explicit_size = 0; MonoMarshalType *info; MonoClassField* field; gpointer iter; @@ -5793,7 +5793,7 @@ mono_marshal_load_type_info (MonoClass* klass) info->num_fields = count; /* Try to find a size for this type in metadata */ - mono_metadata_packing_from_typedef (m_class_get_image (klass), m_class_get_type_token (klass), NULL, &native_size); + explicit_size = mono_metadata_packing_from_typedef (m_class_get_image (klass), m_class_get_type_token (klass), NULL, &native_size); if (m_class_get_parent (klass)) { int parent_size = mono_class_native_size (m_class_get_parent (klass), NULL); @@ -5879,6 +5879,9 @@ mono_marshal_load_type_info (MonoClass* klass) align_size = FALSE; else min_align = MIN (min_align, packing); + } else if (layout == TYPE_ATTRIBUTE_SEQUENTIAL_LAYOUT) { + if (explicit_size && native_size == info->native_size) + align_size = FALSE; } } diff --git a/src/tests/Interop/ArrayMarshalling/UnalignedStructArray/MarshalUnalignedStructArray.cs b/src/tests/Interop/ArrayMarshalling/UnalignedStructArray/MarshalUnalignedStructArray.cs new file mode 100644 index 00000000000000..266a5dbf28d83b --- /dev/null +++ b/src/tests/Interop/ArrayMarshalling/UnalignedStructArray/MarshalUnalignedStructArray.cs @@ -0,0 +1,75 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +using System; +using System.Runtime.InteropServices; +using TestLibrary; +using Xunit; + +public static unsafe class MarshalUnalignedStructArrayTest +{ + [Fact] + public static void TestEntryPoint() + { + /* + * This test validates that the size and offsets of InnerStruct and OuterStruct are as expected. + * It also demonstrates accessing unaligned data in an array. + */ + // Validate that both InnerStruct and OuterStruct have the correct size + Assert.Equal(12, sizeof(InnerStruct)); + Assert.Equal(24, sizeof(OuterStruct)); + + // Validate that the fields of InnerStruct are at the expected offsets + Assert.Equal(0, Marshal.OffsetOf("F0").ToInt32()); + Assert.Equal(8, Marshal.OffsetOf("F1").ToInt32()); + + // Validate that the fields of OuterStruct are at the expected offsets + Assert.Equal(0, Marshal.OffsetOf("F0").ToInt32()); + Assert.Equal(8, Marshal.OffsetOf("F1").ToInt32()); + Assert.Equal(20, Marshal.OffsetOf("F2").ToInt32()); + + // Validate that we are able to access unaligned in an array + InnerStruct[] arrStructs = new InnerStruct[] + { + new InnerStruct(1, 2), + new InnerStruct(3, 4), + new InnerStruct(5, 6), + }; + + fixed (InnerStruct* pStruct = &arrStructs[0]) + { + byte* ptr = (byte*)pStruct; + ptr += 12; + Assert.Equal(3, *(long*)ptr); + Assert.Equal(4, *(int*)(ptr + 8)); + } + + } +} + +[StructLayout(LayoutKind.Sequential, Size = 12)] +struct InnerStruct +{ + public long F0; + public uint F1; + + public InnerStruct(long f0, uint f1) + { + F0 = f0; + F1 = f1; + } +} + +[StructLayout(LayoutKind.Sequential, Size = 24)] +struct OuterStruct +{ + public sbyte F0; + public InnerStruct F1; + public uint F2; + + public OuterStruct(sbyte f0, InnerStruct f1, uint f2) + { + F0 = f0; + F1 = f1; + F2 = f2; + } +} From d7a6ffa857ee8bee4732604c0cb7e9008f0df90c Mon Sep 17 00:00:00 2001 From: Jakob Botsch Nielsen Date: Tue, 30 Apr 2024 10:48:47 +0200 Subject: [PATCH 152/161] SPMI: Replay recorded allocPgoInstrumentationBySchema HRESULT (#101696) Current SPMI collection has a recorded allocPgoInstrumentationBySchema call that failed (EE returned 0x80004001). SPMI fails to replay that correctly. Fix #101685 --- .../tools/superpmi/superpmi-shared/methodcontext.cpp | 9 ++++++--- .../tools/superpmi/superpmi-shared/methodcontext.h | 2 +- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp index 4219aca7ca118b..25e3b1c7744150 100644 --- a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp @@ -5640,10 +5640,11 @@ HRESULT MethodContext::repAllocPgoInstrumentationBySchema( UINT32 countSchemaItems, BYTE** pInstrumentationData) { - if (repAllocPgoInstrumentationBySchemaRecorded(ftnHnd, pSchema, countSchemaItems, pInstrumentationData)) + HRESULT result; + if (repAllocPgoInstrumentationBySchemaRecorded(ftnHnd, pSchema, countSchemaItems, pInstrumentationData, &result)) { // Matching case: return same layout as recorded EE. - return S_OK; + return result; } // Do our own layout. @@ -5676,7 +5677,8 @@ bool MethodContext::repAllocPgoInstrumentationBySchemaRecorded( CORINFO_METHOD_HANDLE ftnHnd, ICorJitInfo::PgoInstrumentationSchema* pSchema, UINT32 countSchemaItems, - BYTE** pInstrumentationData) + BYTE** pInstrumentationData, + HRESULT* result) { if (AllocPgoInstrumentationBySchema == nullptr) return false; @@ -5716,6 +5718,7 @@ bool MethodContext::repAllocPgoInstrumentationBySchemaRecorded( // We assume JIT does not write or read from this buffer, only generate // code that uses it. *pInstrumentationData = (BYTE*)value.instrumentationDataAddress; + *result = value.result; return true; } diff --git a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h index 2af344894e97d8..2c85988aa32e8e 100644 --- a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h +++ b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h @@ -709,7 +709,7 @@ class MethodContext void recAllocPgoInstrumentationBySchema(CORINFO_METHOD_HANDLE ftnHnd, ICorJitInfo::PgoInstrumentationSchema* pSchema, UINT32 countSchemaItems, BYTE** pInstrumentationData, HRESULT result); void dmpAllocPgoInstrumentationBySchema(DWORDLONG key, const Agnostic_AllocPgoInstrumentationBySchema& value); HRESULT repAllocPgoInstrumentationBySchema(CORINFO_METHOD_HANDLE ftnHnd, ICorJitInfo::PgoInstrumentationSchema* pSchema, UINT32 countSchemaItems, BYTE** pInstrumentationData); - bool repAllocPgoInstrumentationBySchemaRecorded(CORINFO_METHOD_HANDLE ftnHnd, ICorJitInfo::PgoInstrumentationSchema* pSchema, UINT32 countSchemaItems, BYTE** pInstrumentationData); + bool repAllocPgoInstrumentationBySchemaRecorded(CORINFO_METHOD_HANDLE ftnHnd, ICorJitInfo::PgoInstrumentationSchema* pSchema, UINT32 countSchemaItems, BYTE** pInstrumentationData, HRESULT* result); void recGetPgoInstrumentationResults(CORINFO_METHOD_HANDLE ftnHnd, ICorJitInfo::PgoInstrumentationSchema** pSchema, UINT32* pCountSchemaItems, BYTE** pInstrumentationData, ICorJitInfo::PgoSource* pPgoSource, bool* pDynamicPgo, HRESULT result); void dmpGetPgoInstrumentationResults(DWORDLONG key, const Agnostic_GetPgoInstrumentationResults& value); From 3fac575b7308febd8a1bbd34c2382eede1096b03 Mon Sep 17 00:00:00 2001 From: Radek Zikmund <32671551+rzikm@users.noreply.github.com> Date: Tue, 30 Apr 2024 12:14:05 +0200 Subject: [PATCH 153/161] Refresh cached credentials after PreAuthenticate fails (#101053) * Support refreshing credentials in pre-auth cache * Fix minor bug in CredentialCache * Add unit test * Fix tests * Fix tests attempt 2 * Merge two lock statements. * Fix build --- .../src/System/Net/CredentialCacheKey.cs | 133 ++++++++++++++++++ .../src/System.Net.Http.csproj | 3 + .../AuthenticationHelper.cs | 36 +++-- .../ConnectionPool/HttpConnectionPool.cs | 6 +- .../PreAuthCredentialCache.cs | 61 ++++++++ .../HttpClientHandlerTest.BasicAuth.cs | 114 +++++++++++++++ .../System.Net.Http.Functional.Tests.csproj | 1 + .../src/System.Net.Primitives.csproj | 2 + .../src/System/Net/CredentialCache.cs | 126 +---------------- .../FunctionalTests/CredentialCacheTest.cs | 11 ++ 10 files changed, 363 insertions(+), 130 deletions(-) create mode 100644 src/libraries/Common/src/System/Net/CredentialCacheKey.cs create mode 100644 src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/PreAuthCredentialCache.cs create mode 100644 src/libraries/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.BasicAuth.cs diff --git a/src/libraries/Common/src/System/Net/CredentialCacheKey.cs b/src/libraries/Common/src/System/Net/CredentialCacheKey.cs new file mode 100644 index 00000000000000..0d59c101493157 --- /dev/null +++ b/src/libraries/Common/src/System/Net/CredentialCacheKey.cs @@ -0,0 +1,133 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Collections; +using System.Collections.Generic; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.Globalization; + +namespace System.Net +{ + internal sealed class CredentialCacheKey : IEquatable + { + public readonly Uri UriPrefix; + public readonly int UriPrefixLength = -1; + public readonly string AuthenticationType; + + internal CredentialCacheKey(Uri uriPrefix, string authenticationType) + { + Debug.Assert(uriPrefix != null); + Debug.Assert(authenticationType != null); + + UriPrefix = uriPrefix; + UriPrefixLength = UriPrefix.AbsolutePath.LastIndexOf('/'); + AuthenticationType = authenticationType; + } + + internal bool Match(Uri uri, string authenticationType) + { + if (uri == null || authenticationType == null) + { + return false; + } + + // If the protocols don't match, this credential is not applicable for the given Uri. + if (!string.Equals(authenticationType, AuthenticationType, StringComparison.OrdinalIgnoreCase)) + { + return false; + } + + if (NetEventSource.Log.IsEnabled()) NetEventSource.Info(this, $"Match({UriPrefix} & {uri})"); + + return IsPrefix(uri, UriPrefix); + } + + // IsPrefix (Uri) + // + // Determines whether is a prefix of this URI. A prefix + // match is defined as: + // + // scheme match + // + host match + // + port match, if any + // + path is a prefix of path, if any + // + // Returns: + // True if is a prefix of this URI + private static bool IsPrefix(Uri uri, Uri prefixUri) + { + Debug.Assert(uri != null); + Debug.Assert(prefixUri != null); + + if (prefixUri.Scheme != uri.Scheme || prefixUri.Host != uri.Host || prefixUri.Port != uri.Port) + { + return false; + } + + int prefixLen = prefixUri.AbsolutePath.LastIndexOf('/'); + if (prefixLen > uri.AbsolutePath.LastIndexOf('/')) + { + return false; + } + + return string.Compare(uri.AbsolutePath, 0, prefixUri.AbsolutePath, 0, prefixLen, StringComparison.OrdinalIgnoreCase) == 0; + } + + public override int GetHashCode() => + StringComparer.OrdinalIgnoreCase.GetHashCode(AuthenticationType) ^ + UriPrefix.GetHashCode(); + + public bool Equals([NotNullWhen(true)] CredentialCacheKey? other) + { + if (other == null) + { + return false; + } + + bool equals = + string.Equals(AuthenticationType, other.AuthenticationType, StringComparison.OrdinalIgnoreCase) && + UriPrefix.Equals(other.UriPrefix); + + if (NetEventSource.Log.IsEnabled()) NetEventSource.Info(this, $"Equals({this},{other}) returns {equals}"); + + return equals; + } + + public override bool Equals([NotNullWhen(true)] object? obj) => Equals(obj as CredentialCacheKey); + + public override string ToString() => + string.Create(CultureInfo.InvariantCulture, $"[{UriPrefixLength}]:{UriPrefix}:{AuthenticationType}"); + } + + internal static class CredentialCacheHelper + { + public static bool TryGetCredential(Dictionary cache, Uri uriPrefix, string authType, [NotNullWhen(true)] out Uri? mostSpecificMatchUri, [NotNullWhen(true)] out NetworkCredential? mostSpecificMatch) + { + int longestMatchPrefix = -1; + mostSpecificMatch = null; + mostSpecificMatchUri = null; + + // Enumerate through every credential in the cache + foreach ((CredentialCacheKey key, NetworkCredential value) in cache) + { + // Determine if this credential is applicable to the current Uri/AuthType + if (key.Match(uriPrefix, authType)) + { + int prefixLen = key.UriPrefixLength; + + // Check if the match is better than the current-most-specific match + if (prefixLen > longestMatchPrefix) + { + // Yes: update the information about currently preferred match + longestMatchPrefix = prefixLen; + mostSpecificMatch = value; + mostSpecificMatchUri = key.UriPrefix; + } + } + } + + return mostSpecificMatch != null; + } + } +} diff --git a/src/libraries/System.Net.Http/src/System.Net.Http.csproj b/src/libraries/System.Net.Http/src/System.Net.Http.csproj index 7db63948a28513..e4ffec94743f35 100644 --- a/src/libraries/System.Net.Http/src/System.Net.Http.csproj +++ b/src/libraries/System.Net.Http/src/System.Net.Http.csproj @@ -164,6 +164,8 @@ Link="Common\System\Text\ValueStringBuilder.AppendSpanFormattable.cs" /> + @@ -216,6 +218,7 @@ + diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/AuthenticationHelper.cs b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/AuthenticationHelper.cs index 639e0367ba5aa7..69f01907167c7e 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/AuthenticationHelper.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/AuthenticationHelper.cs @@ -215,11 +215,12 @@ private static async ValueTask SendWithAuthAsync(HttpReques // If preauth is enabled and this isn't proxy auth, try to get a basic credential from the // preauth credentials cache, and if successful, set an auth header for it onto the request. // Currently we only support preauth for Basic. - bool performedBasicPreauth = false; + NetworkCredential? preAuthCredential = null; + Uri? preAuthCredentialUri = null; if (preAuthenticate) { Debug.Assert(pool.PreAuthCredentials != null); - NetworkCredential? credential; + (Uri uriPrefix, NetworkCredential credential)? preAuthCredentialPair; lock (pool.PreAuthCredentials) { // Just look for basic credentials. If in the future we support preauth @@ -227,13 +228,13 @@ private static async ValueTask SendWithAuthAsync(HttpReques Debug.Assert(pool.PreAuthCredentials.GetCredential(authUri, NegotiateScheme) == null); Debug.Assert(pool.PreAuthCredentials.GetCredential(authUri, NtlmScheme) == null); Debug.Assert(pool.PreAuthCredentials.GetCredential(authUri, DigestScheme) == null); - credential = pool.PreAuthCredentials.GetCredential(authUri, BasicScheme); + preAuthCredentialPair = pool.PreAuthCredentials.GetCredential(authUri, BasicScheme); } - if (credential != null) + if (preAuthCredentialPair != null) { - SetBasicAuthToken(request, credential, isProxyAuth); - performedBasicPreauth = true; + (preAuthCredentialUri, preAuthCredential) = preAuthCredentialPair.Value; + SetBasicAuthToken(request, preAuthCredential, isProxyAuth); } } @@ -265,13 +266,21 @@ await TrySetDigestAuthToken(request, challenge.Credential, digestResponse, isPro break; case AuthenticationType.Basic: - if (performedBasicPreauth) + if (preAuthCredential != null) { if (NetEventSource.Log.IsEnabled()) { NetEventSource.AuthenticationError(authUri, $"Pre-authentication with {(isProxyAuth ? "proxy" : "server")} failed."); } - break; + + if (challenge.Credential == preAuthCredential) + { + // Pre auth failed, and user supplied credentials are still same, we can stop there. + break; + } + + // Pre-auth credentials have changed, continue with the new ones. + // The old ones will be removed below. } response.Dispose(); @@ -293,6 +302,17 @@ await TrySetDigestAuthToken(request, challenge.Credential, digestResponse, isPro default: lock (pool.PreAuthCredentials!) { + // remove previously cached (failing) creds + if (preAuthCredentialUri != null) + { + if (NetEventSource.Log.IsEnabled()) + { + NetEventSource.Info(pool.PreAuthCredentials, $"Removing Basic credential from cache, uri={preAuthCredentialUri}, username={preAuthCredential!.UserName}"); + } + + pool.PreAuthCredentials.Remove(preAuthCredentialUri, BasicScheme); + } + try { if (NetEventSource.Log.IsEnabled()) diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectionPool/HttpConnectionPool.cs b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectionPool/HttpConnectionPool.cs index 1cff8e9ad39516..0d9f3a2a1b9537 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectionPool/HttpConnectionPool.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectionPool/HttpConnectionPool.cs @@ -59,7 +59,7 @@ internal sealed partial class HttpConnectionPool : IDisposable private SslClientAuthenticationOptions? _sslOptionsHttp3; private readonly SslClientAuthenticationOptions? _sslOptionsProxy; - private readonly CredentialCache? _preAuthCredentials; + private readonly PreAuthCredentialCache? _preAuthCredentials; /// Whether the pool has been used since the last time a cleanup occurred. private bool _usedSinceLastCleanup = true; @@ -237,7 +237,7 @@ public HttpConnectionPool(HttpConnectionPoolManager poolManager, HttpConnectionK // Set up for PreAuthenticate. Access to this cache is guarded by a lock on the cache itself. if (_poolManager.Settings._preAuthenticate) { - _preAuthCredentials = new CredentialCache(); + _preAuthCredentials = new PreAuthCredentialCache(); } _http11RequestQueue = new RequestQueue(); @@ -296,7 +296,7 @@ private static SslClientAuthenticationOptions ConstructSslOptions(HttpConnection public bool IsSecure => _kind == HttpConnectionKind.Https || _kind == HttpConnectionKind.SslProxyTunnel || _kind == HttpConnectionKind.SslSocksTunnel; public Uri? ProxyUri => _proxyUri; public ICredentials? ProxyCredentials => _poolManager.ProxyCredentials; - public CredentialCache? PreAuthCredentials => _preAuthCredentials; + public PreAuthCredentialCache? PreAuthCredentials => _preAuthCredentials; public bool IsDefaultPort => OriginAuthority.Port == (IsSecure ? DefaultHttpsPort : DefaultHttpPort); private bool DoProxyAuth => (_kind == HttpConnectionKind.Proxy || _kind == HttpConnectionKind.ProxyConnect); diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/PreAuthCredentialCache.cs b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/PreAuthCredentialCache.cs new file mode 100644 index 00000000000000..1f4dcc54fb0c2c --- /dev/null +++ b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/PreAuthCredentialCache.cs @@ -0,0 +1,61 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Collections; +using System.Collections.Generic; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.Globalization; + +namespace System.Net.Http +{ + internal sealed class PreAuthCredentialCache + { + private Dictionary? _cache; + + public void Add(Uri uriPrefix, string authType, NetworkCredential cred) + { + Debug.Assert(uriPrefix != null); + Debug.Assert(authType != null); + + var key = new CredentialCacheKey(uriPrefix, authType); + + if (NetEventSource.Log.IsEnabled()) NetEventSource.Info(this, $"Adding key:[{key}], cred:[{cred.Domain}],[{cred.UserName}]"); + + _cache ??= new Dictionary(); + _cache.Add(key, cred); + } + + public void Remove(Uri uriPrefix, string authType) + { + Debug.Assert(uriPrefix != null); + Debug.Assert(authType != null); + + if (_cache == null) + { + return; + } + + var key = new CredentialCacheKey(uriPrefix, authType); + if (NetEventSource.Log.IsEnabled()) NetEventSource.Info(this, $"Removing key:[{key}]"); + _cache.Remove(key); + } + + public (Uri uriPrefix, NetworkCredential credential)? GetCredential(Uri uriPrefix, string authType) + { + Debug.Assert(uriPrefix != null); + Debug.Assert(authType != null); + + if (_cache == null) + { + return null; + } + + CredentialCacheHelper.TryGetCredential(_cache, uriPrefix, authType, out Uri? mostSpecificMatchUri, out NetworkCredential? mostSpecificMatch); + + if (NetEventSource.Log.IsEnabled()) NetEventSource.Info(this, $"Returning {(mostSpecificMatch == null ? "null" : "(" + mostSpecificMatch.UserName + ":" + mostSpecificMatch.Domain + ")")}"); + + return mostSpecificMatch == null ? null : (mostSpecificMatchUri!, mostSpecificMatch!); + } + } +} diff --git a/src/libraries/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.BasicAuth.cs b/src/libraries/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.BasicAuth.cs new file mode 100644 index 00000000000000..a6ac590fb6adcf --- /dev/null +++ b/src/libraries/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.BasicAuth.cs @@ -0,0 +1,114 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Linq; +using System.Net.Test.Common; +using System.Text; +using System.Threading.Tasks; + +using Microsoft.DotNet.XUnitExtensions; +using Xunit; +using Xunit.Abstractions; + +namespace System.Net.Http.Functional.Tests +{ + [ConditionalClass(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))] + public class HttpClientHandlerTest_BasicAuth : HttpClientHandlerTestBase + { + public HttpClientHandlerTest_BasicAuth(ITestOutputHelper output) : base(output) + { + } + + protected override Version UseVersion => HttpVersion.Version20; + + [Fact] + public async Task RefreshesPreAuthCredentialsOnChange() + { + CredentialPlugin credentialPlugin = new CredentialPlugin(); + + using Http2LoopbackServer server = Http2LoopbackServer.CreateServer(); + server.AllowMultipleConnections = true; + + HttpClientHandler handler = CreateHttpClientHandler(); + handler.PreAuthenticate = true; + handler.Credentials = credentialPlugin; + using HttpClient client = CreateHttpClient(handler); + + Task sendTask = client.GetAsync(server.Address); + + async Task GetAuth(GenericLoopbackConnection connection) + { + HttpRequestData data = await connection.ReadRequestDataAsync(); + HttpHeaderData? header = data.Headers.FirstOrDefault(h => string.Equals(h.Name, "Authorization", StringComparison.OrdinalIgnoreCase)); + + if (header == null) + { + return ""; + } + + return Encoding.UTF8.GetString(Convert.FromBase64String(header.Value.Value.Replace("Basic", "", StringComparison.OrdinalIgnoreCase))); + } + + await server.HandleRequestAsync(HttpStatusCode.Unauthorized, headers: new[] { new HttpHeaderData("WWW-Authenticate", "Basic realm=\"test\"") }); + await server.AcceptConnectionAsync(async conn => + { + Assert.Equal("username:password", await GetAuth(conn)); + await conn.SendResponseAsync(HttpStatusCode.OK); + }).WaitAsync(TimeSpan.FromSeconds(30)); + + HttpResponseMessage response = await sendTask; + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + + // change password and try again + credentialPlugin.ChangePassword(); + sendTask = client.GetAsync(server.Address); + + // first one reuses the cached credentials -> 401 + await server.AcceptConnectionAsync(async conn => + { + Assert.Equal("username:password", await GetAuth(conn)); + await conn.SendResponseAsync(HttpStatusCode.Unauthorized, headers: new[] { new HttpHeaderData("WWW-Authenticate", "Basic realm=\"test\"") }); + }).WaitAsync(TimeSpan.FromSeconds(30)); + + // client should try again with correct credentials + await server.AcceptConnectionAsync(async conn => + { + Assert.Equal("username:password1", await GetAuth(conn)); + await conn.SendResponseAsync(HttpStatusCode.OK); + }).WaitAsync(TimeSpan.FromSeconds(30)); + + response = await sendTask; + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + } + } + + internal class CredentialPlugin : ICredentials + { + public CredentialPlugin() + { + UserName = "username"; + counter = 0; + Password = "password"; + } + + private int counter; + public string UserName { get; private set; } + public string Password { get; private set; } + + public void ChangePassword() + { + counter++; + Password = "password" + counter; + } + + NetworkCredential? ICredentials.GetCredential(Uri uri, string authType) + { + if (authType == "Basic") + { + return new NetworkCredential(UserName, Password); + } + + return null; + } + } +} diff --git a/src/libraries/System.Net.Http/tests/FunctionalTests/System.Net.Http.Functional.Tests.csproj b/src/libraries/System.Net.Http/tests/FunctionalTests/System.Net.Http.Functional.Tests.csproj index fd09f7db0b2282..0256d1d53a4517 100644 --- a/src/libraries/System.Net.Http/tests/FunctionalTests/System.Net.Http.Functional.Tests.csproj +++ b/src/libraries/System.Net.Http/tests/FunctionalTests/System.Net.Http.Functional.Tests.csproj @@ -245,6 +245,7 @@ + diff --git a/src/libraries/System.Net.Primitives/src/System.Net.Primitives.csproj b/src/libraries/System.Net.Primitives/src/System.Net.Primitives.csproj index a659207964a3e8..e71aaa8222e300 100644 --- a/src/libraries/System.Net.Primitives/src/System.Net.Primitives.csproj +++ b/src/libraries/System.Net.Primitives/src/System.Net.Primitives.csproj @@ -82,6 +82,8 @@ Link="Common\System\Text\StringBuilderCache.cs" /> + diff --git a/src/libraries/System.Net.Primitives/src/System/Net/CredentialCache.cs b/src/libraries/System.Net.Primitives/src/System/Net/CredentialCache.cs index 8cb88371227919..8e46d4ab6c529d 100644 --- a/src/libraries/System.Net.Primitives/src/System/Net/CredentialCache.cs +++ b/src/libraries/System.Net.Primitives/src/System/Net/CredentialCache.cs @@ -13,7 +13,7 @@ namespace System.Net // name-password pairs and associates these with host/realm. public class CredentialCache : ICredentials, ICredentialsByHost, IEnumerable { - private Dictionary? _cache; + private Dictionary? _cache; private Dictionary? _cacheForHosts; private int _version; @@ -37,11 +37,11 @@ public void Add(Uri uriPrefix, string authType, NetworkCredential cred) ++_version; - var key = new CredentialKey(uriPrefix, authType); + var key = new CredentialCacheKey(uriPrefix, authType); if (NetEventSource.Log.IsEnabled()) NetEventSource.Info(this, $"Adding key:[{key}], cred:[{cred.Domain}],[{cred.UserName}]"); - _cache ??= new Dictionary(); + _cache ??= new Dictionary(); _cache.Add(key, cred); } @@ -88,7 +88,7 @@ public void Remove(Uri? uriPrefix, string? authType) ++_version; - var key = new CredentialKey(uriPrefix, authType); + var key = new CredentialCacheKey(uriPrefix, authType); if (NetEventSource.Log.IsEnabled()) NetEventSource.Info(this, $"Removing key:[{key}]"); @@ -135,28 +135,7 @@ public void Remove(string? host, int port, string? authenticationType) return null; } - int longestMatchPrefix = -1; - NetworkCredential? mostSpecificMatch = null; - - // Enumerate through every credential in the cache - foreach (KeyValuePair pair in _cache) - { - CredentialKey key = pair.Key; - - // Determine if this credential is applicable to the current Uri/AuthType - if (key.Match(uriPrefix, authType)) - { - int prefixLen = key.UriPrefixLength; - - // Check if the match is better than the current-most-specific match - if (prefixLen > longestMatchPrefix) - { - // Yes: update the information about currently preferred match - longestMatchPrefix = prefixLen; - mostSpecificMatch = pair.Value; - } - } - } + CredentialCacheHelper.TryGetCredential(_cache, uriPrefix, authType, out _ /*uri*/, out NetworkCredential? mostSpecificMatch); if (NetEventSource.Log.IsEnabled()) NetEventSource.Info(this, $"Returning {(mostSpecificMatch == null ? "null" : "(" + mostSpecificMatch.UserName + ":" + mostSpecificMatch.Domain + ")")}"); @@ -201,7 +180,7 @@ internal static CredentialEnumerator Create(CredentialCache cache) { return cache._cacheForHosts != null ? new DoubleTableCredentialEnumerator(cache) : - new SingleTableCredentialEnumerator(cache, cache._cache); + new SingleTableCredentialEnumerator(cache, cache._cache); } else { @@ -286,7 +265,7 @@ public override void Reset() } } - private sealed class DoubleTableCredentialEnumerator : SingleTableCredentialEnumerator + private sealed class DoubleTableCredentialEnumerator : SingleTableCredentialEnumerator { private Dictionary.ValueCollection.Enumerator _enumerator; // mutable struct field deliberately not readonly. private bool _onThisEnumerator; @@ -406,95 +385,4 @@ public override bool Equals([NotNullWhen(true)] object? obj) => public override string ToString() => string.Create(CultureInfo.InvariantCulture, $"{Host}:{Port}:{AuthenticationType}"); } - - internal sealed class CredentialKey : IEquatable - { - public readonly Uri UriPrefix; - public readonly int UriPrefixLength = -1; - public readonly string AuthenticationType; - - internal CredentialKey(Uri uriPrefix, string authenticationType) - { - Debug.Assert(uriPrefix != null); - Debug.Assert(authenticationType != null); - - UriPrefix = uriPrefix; - UriPrefixLength = UriPrefix.ToString().Length; - AuthenticationType = authenticationType; - } - - internal bool Match(Uri uri, string authenticationType) - { - if (uri == null || authenticationType == null) - { - return false; - } - - // If the protocols don't match, this credential is not applicable for the given Uri. - if (!string.Equals(authenticationType, AuthenticationType, StringComparison.OrdinalIgnoreCase)) - { - return false; - } - - if (NetEventSource.Log.IsEnabled()) NetEventSource.Info(this, $"Match({UriPrefix} & {uri})"); - - return IsPrefix(uri, UriPrefix); - } - - // IsPrefix (Uri) - // - // Determines whether is a prefix of this URI. A prefix - // match is defined as: - // - // scheme match - // + host match - // + port match, if any - // + path is a prefix of path, if any - // - // Returns: - // True if is a prefix of this URI - private static bool IsPrefix(Uri uri, Uri prefixUri) - { - Debug.Assert(uri != null); - Debug.Assert(prefixUri != null); - - if (prefixUri.Scheme != uri.Scheme || prefixUri.Host != uri.Host || prefixUri.Port != uri.Port) - { - return false; - } - - int prefixLen = prefixUri.AbsolutePath.LastIndexOf('/'); - if (prefixLen > uri.AbsolutePath.LastIndexOf('/')) - { - return false; - } - - return string.Compare(uri.AbsolutePath, 0, prefixUri.AbsolutePath, 0, prefixLen, StringComparison.OrdinalIgnoreCase) == 0; - } - - public override int GetHashCode() => - StringComparer.OrdinalIgnoreCase.GetHashCode(AuthenticationType) ^ - UriPrefix.GetHashCode(); - - public bool Equals([NotNullWhen(true)] CredentialKey? other) - { - if (other == null) - { - return false; - } - - bool equals = - string.Equals(AuthenticationType, other.AuthenticationType, StringComparison.OrdinalIgnoreCase) && - UriPrefix.Equals(other.UriPrefix); - - if (NetEventSource.Log.IsEnabled()) NetEventSource.Info(this, $"Equals({this},{other}) returns {equals}"); - - return equals; - } - - public override bool Equals([NotNullWhen(true)] object? obj) => Equals(obj as CredentialKey); - - public override string ToString() => - string.Create(CultureInfo.InvariantCulture, $"[{UriPrefixLength}]:{UriPrefix}:{AuthenticationType}"); - } } diff --git a/src/libraries/System.Net.Primitives/tests/FunctionalTests/CredentialCacheTest.cs b/src/libraries/System.Net.Primitives/tests/FunctionalTests/CredentialCacheTest.cs index a67967b36811c7..6895fabba4f1b9 100644 --- a/src/libraries/System.Net.Primitives/tests/FunctionalTests/CredentialCacheTest.cs +++ b/src/libraries/System.Net.Primitives/tests/FunctionalTests/CredentialCacheTest.cs @@ -272,6 +272,17 @@ public static void GetCredential_SimilarUriAuthenticationType_GetLongestUriPrefi Assert.Equal(nc, credential2); } + [Fact] + public static void GetCredential_LongerUriButShorterMatch() + { + CredentialCache cc = new CredentialCache(); + cc.Add(new Uri("http://microsoft:80/common/unique/something"), authenticationType1, credential2); + cc.Add(new Uri("http://microsoft:80/common/veryloooooongprefix"), authenticationType1, credential1); + + NetworkCredential nc = cc.GetCredential(new Uri("http://microsoft:80/common/unique/a"), authenticationType1); + Assert.Equal(nc, credential2); + } + [Fact] public static void GetCredential_UriAuthenticationType_Invalid() { From 2ad47cd52ebe57c1b4c2e28f95cc4eed6fcb354d Mon Sep 17 00:00:00 2001 From: Ilona Tomkowicz <32700855+ilonatommy@users.noreply.github.com> Date: Tue, 30 Apr 2024 12:57:18 +0200 Subject: [PATCH 154/161] [wasm] Switch off `HybridGlobalization` lane on v8 on CI (#101671) * Stop testing on v8. * Try to block by scenario, * Limit scenarios. This reverts commit 38f64f7a8619b427f1b5c617db5dead7d8f194ee. --- .../extra-platforms/runtime-extra-platforms-wasm.yml | 2 -- ...ystem.Globalization.Calendars.Hybrid.WASM.Tests.csproj | 8 ++++++++ .../Hybrid/System.Globalization.Hybrid.WASM.Tests.csproj | 8 ++++++++ 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/eng/pipelines/extra-platforms/runtime-extra-platforms-wasm.yml b/eng/pipelines/extra-platforms/runtime-extra-platforms-wasm.yml index d31cad685995d2..a5c6cb414227d8 100644 --- a/eng/pipelines/extra-platforms/runtime-extra-platforms-wasm.yml +++ b/eng/pipelines/extra-platforms/runtime-extra-platforms-wasm.yml @@ -197,7 +197,6 @@ jobs: isWasmOnlyBuild: ${{ parameters.isWasmOnlyBuild }} alwaysRun: true scenarios: - - WasmTestOnV8 - WasmTestOnChrome - WasmTestOnFirefox - WasmTestOnNodeJS @@ -215,7 +214,6 @@ jobs: isWasmOnlyBuild: ${{ parameters.isWasmOnlyBuild }} alwaysRun: true scenarios: - - WasmTestOnV8 - WasmTestOnChrome - WasmTestOnNodeJS diff --git a/src/libraries/System.Runtime/tests/System.Globalization.Calendars.Tests/Hybrid/System.Globalization.Calendars.Hybrid.WASM.Tests.csproj b/src/libraries/System.Runtime/tests/System.Globalization.Calendars.Tests/Hybrid/System.Globalization.Calendars.Hybrid.WASM.Tests.csproj index 5b898363764087..7e10ef4ac1dd59 100644 --- a/src/libraries/System.Runtime/tests/System.Globalization.Calendars.Tests/Hybrid/System.Globalization.Calendars.Hybrid.WASM.Tests.csproj +++ b/src/libraries/System.Runtime/tests/System.Globalization.Calendars.Tests/Hybrid/System.Globalization.Calendars.Hybrid.WASM.Tests.csproj @@ -4,6 +4,14 @@ true true true + + + + WasmTestOnChrome + $(TestArchiveRoot)browserornodejs/ + $(TestArchiveTestsRoot)$(OSPlatformConfig)/ + $(DefineConstants);TARGET_BROWSER + true diff --git a/src/libraries/System.Runtime/tests/System.Globalization.Tests/Hybrid/System.Globalization.Hybrid.WASM.Tests.csproj b/src/libraries/System.Runtime/tests/System.Globalization.Tests/Hybrid/System.Globalization.Hybrid.WASM.Tests.csproj index a39604c1cfaccd..fdc037e655558d 100644 --- a/src/libraries/System.Runtime/tests/System.Globalization.Tests/Hybrid/System.Globalization.Hybrid.WASM.Tests.csproj +++ b/src/libraries/System.Runtime/tests/System.Globalization.Tests/Hybrid/System.Globalization.Hybrid.WASM.Tests.csproj @@ -6,6 +6,14 @@ true true + + + WasmTestOnChrome + $(TestArchiveRoot)browserornodejs/ + $(TestArchiveTestsRoot)$(OSPlatformConfig)/ + $(DefineConstants);TARGET_BROWSER + true + From 80aa46441244c7a05f7b2bbbbb0d4812f76b488a Mon Sep 17 00:00:00 2001 From: Jan Kotas Date: Tue, 30 Apr 2024 06:26:56 -0700 Subject: [PATCH 155/161] Backport assorted changes from runtimelab (#101655) * Backport assorted changes from runtimelab - Official build template - FEATURE_HIJACK define - Misc other cleanup * Delete unused DATA_ALIGNMENT definition --- eng/native/configureplatform.cmake | 1 - eng/pipelines/common/xplat-setup.yml | 1 - eng/pipelines/runtimelab-official.yml | 78 +++++++++ eng/pipelines/runtimelab.yml | 149 ++++++------------ src/coreclr/nativeaot/Runtime/CMakeLists.txt | 14 +- src/coreclr/nativeaot/Runtime/CommonMacros.h | 27 ---- .../nativeaot/Runtime/GCMemoryHelpers.inl | 2 + src/coreclr/nativeaot/Runtime/PalRedhawk.h | 2 + src/coreclr/nativeaot/Runtime/portable.cpp | 22 --- src/coreclr/nativeaot/Runtime/thread.cpp | 30 ++-- src/coreclr/nativeaot/Runtime/thread.h | 20 ++- src/coreclr/nativeaot/Runtime/threadstore.cpp | 4 + .../nativeaot/Runtime/unix/PalRedhawkUnix.cpp | 7 +- 13 files changed, 178 insertions(+), 179 deletions(-) create mode 100644 eng/pipelines/runtimelab-official.yml diff --git a/eng/native/configureplatform.cmake b/eng/native/configureplatform.cmake index c7c378ab0e41b3..20851f8617423d 100644 --- a/eng/native/configureplatform.cmake +++ b/eng/native/configureplatform.cmake @@ -429,7 +429,6 @@ endif(CLR_CMAKE_TARGET_OS STREQUAL haiku) if(CLR_CMAKE_TARGET_OS STREQUAL emscripten) set(CLR_CMAKE_TARGET_UNIX 1) - set(CLR_CMAKE_TARGET_LINUX 1) set(CLR_CMAKE_TARGET_BROWSER 1) endif(CLR_CMAKE_TARGET_OS STREQUAL emscripten) diff --git a/eng/pipelines/common/xplat-setup.yml b/eng/pipelines/common/xplat-setup.yml index 743f6a42531bcc..f50a2db9e81ec5 100644 --- a/eng/pipelines/common/xplat-setup.yml +++ b/eng/pipelines/common/xplat-setup.yml @@ -188,7 +188,6 @@ jobs: name: $(DncEngPublicBuildPool) demands: ImageOverride -equals windows.vs2022.amd64.open - ${{ if eq(parameters.helixQueuesTemplate, '') }}: # macOS hosted pool machines are slower so we need to give a greater timeout than the 60 mins default. ${{ if and(eq(parameters.jobParameters.timeoutInMinutes, ''), in(parameters.osGroup, 'osx', 'maccatalyst', 'ios', 'tvos')) }}: diff --git a/eng/pipelines/runtimelab-official.yml b/eng/pipelines/runtimelab-official.yml new file mode 100644 index 00000000000000..84a8bd69258d5c --- /dev/null +++ b/eng/pipelines/runtimelab-official.yml @@ -0,0 +1,78 @@ +trigger: + batch: true + branches: + include: + - feature/* + paths: + include: + - '*' + exclude: + - '**.md' + - eng/Version.Details.xml + - .devcontainer/* + - .github/* + - docs/* + - LICENSE.TXT + - PATENTS.TXT + - THIRD-PARTY-NOTICES.TXT + +variables: +- template: /eng/pipelines/common/variables.yml + parameters: + templatePath: 'templates-official' + +- ${{ if and(ne(variables['System.TeamProject'], 'public'), ne(variables['Build.Reason'], 'PullRequest')) }}: + - name: TeamName + value: dotnet-core +extends: + template: /eng/pipelines/common/templates/pipeline-with-resources.yml@self + parameters: + isOfficialBuild: true + stages: + - stage: Build + jobs: + # + # Build the whole product with Release CoreCLR + # + - template: /eng/pipelines/common/platform-matrix.yml + parameters: + jobTemplate: /eng/pipelines/common/global-build-job.yml + helixQueuesTemplate: /eng/pipelines/libraries/helix-queues-setup.yml + buildConfig: release + platforms: + - linux_x64 + - windows_x64 + jobParameters: + templatePath: 'templates-official' + isOfficialBuild: true + timeoutInMinutes: 180 + buildArgs: -s clr+libs+hosts+packs -c $(_BuildConfig) + postBuildSteps: + # Upload the results. + - template: /eng/pipelines/common/upload-intermediate-artifacts-step.yml + parameters: + name: $(osGroup)$(osSubgroup)_$(archType) + + # + # Build libraries AllConfigurations for packages + # + - template: /eng/pipelines/common/platform-matrix.yml + parameters: + jobTemplate: /eng/pipelines/common/global-build-job.yml + buildConfig: Release + platforms: + - windows_x64 + jobParameters: + templatePath: 'templates-official' + buildArgs: -s tools+libs -allConfigurations -c $(_BuildConfig) /p:TestAssemblies=false /p:TestPackages=true + nameSuffix: Libraries_AllConfigurations + isOfficialBuild: true + postBuildSteps: + - template: /eng/pipelines/common/upload-intermediate-artifacts-step.yml + parameters: + name: Libraries_AllConfigurations + timeoutInMinutes: 95 + + - template: /eng/pipelines/official/stages/publish.yml + parameters: + isOfficialBuild: true diff --git a/eng/pipelines/runtimelab.yml b/eng/pipelines/runtimelab.yml index 0fe01fd2816f73..7e0aaeab207216 100644 --- a/eng/pipelines/runtimelab.yml +++ b/eng/pipelines/runtimelab.yml @@ -49,103 +49,56 @@ extends: stages: - stage: Build jobs: - - ${{ if ne(variables.isOfficialBuild, true) }}: - # - # Build the whole product with Checked CoreCLR and run runtime tests - # - - template: /eng/pipelines/common/platform-matrix.yml - parameters: - jobTemplate: /eng/pipelines/common/global-build-job.yml - helixQueuesTemplate: /eng/pipelines/coreclr/templates/helix-queues-setup.yml - buildConfig: checked - platforms: - - linux_x64 - - windows_x64 - jobParameters: - timeoutInMinutes: 200 - buildArgs: -s clr+libs+hosts+packs -c debug -rc $(_BuildConfig) - postBuildSteps: - - template: /eng/pipelines/common/templates/runtimes/build-runtime-tests-and-send-to-helix.yml - parameters: - creator: dotnet-bot - testRunNamePrefixSuffix: CoreCLR_$(_BuildConfig) + # + # Build the whole product with Checked CoreCLR and run runtime tests + # + - template: /eng/pipelines/common/platform-matrix.yml + parameters: + jobTemplate: /eng/pipelines/common/global-build-job.yml + helixQueuesTemplate: /eng/pipelines/coreclr/templates/helix-queues-setup.yml + buildConfig: checked + platforms: + - linux_x64 + - windows_x64 + jobParameters: + timeoutInMinutes: 200 + buildArgs: -s clr+libs+hosts+packs -c debug -rc $(_BuildConfig) + postBuildSteps: + - template: /eng/pipelines/common/templates/runtimes/build-runtime-tests-and-send-to-helix.yml + parameters: + creator: dotnet-bot + testRunNamePrefixSuffix: CoreCLR_$(_BuildConfig) - # - # Build the whole product with Release CoreCLR and run libraries tests - # - - template: /eng/pipelines/common/platform-matrix.yml - parameters: - jobTemplate: /eng/pipelines/common/global-build-job.yml - helixQueuesTemplate: /eng/pipelines/libraries/helix-queues-setup.yml - buildConfig: release - platforms: - - linux_x64 - - windows_x64 - jobParameters: - timeoutInMinutes: 180 - buildArgs: -s clr+libs+libs.tests+hosts+packs -c $(_BuildConfig) /p:ArchiveTests=true - postBuildSteps: - - template: /eng/pipelines/libraries/helix.yml - parameters: - creator: dotnet-bot - testRunNamePrefixSuffix: Libraries_$(_BuildConfig) + # + # Build the whole product with Release CoreCLR and run libraries tests + # + - template: /eng/pipelines/common/platform-matrix.yml + parameters: + jobTemplate: /eng/pipelines/common/global-build-job.yml + helixQueuesTemplate: /eng/pipelines/libraries/helix-queues-setup.yml + buildConfig: release + platforms: + - linux_x64 + - windows_x64 + jobParameters: + timeoutInMinutes: 180 + buildArgs: -s clr+libs+libs.tests+hosts+packs -c $(_BuildConfig) /p:ArchiveTests=true + postBuildSteps: + - template: /eng/pipelines/libraries/helix.yml + parameters: + creator: dotnet-bot + testRunNamePrefixSuffix: Libraries_$(_BuildConfig) - # - # Build and test libraries AllConfigurations - # - - template: /eng/pipelines/common/platform-matrix.yml - parameters: - jobTemplate: /eng/pipelines/common/global-build-job.yml - buildConfig: ${{ variables.debugOnPrReleaseOnRolling }} - platforms: - - windows_x64 - jobParameters: - buildArgs: -test -s tools+libs+libs.tests -allConfigurations -c $(_BuildConfig) /p:TestAssemblies=false /p:TestPackages=true - nameSuffix: Libraries_AllConfigurations - timeoutInMinutes: 150 - - - ${{ else }}: - # - # Build the whole product with Release CoreCLR - # - - template: /eng/pipelines/common/platform-matrix.yml - parameters: - jobTemplate: /eng/pipelines/common/global-build-job.yml - helixQueuesTemplate: /eng/pipelines/libraries/helix-queues-setup.yml - buildConfig: release - platforms: - - linux_x64 - - windows_x64 - jobParameters: - isOfficialBuild: true - timeoutInMinutes: 180 - buildArgs: -s clr+libs+hosts+packs -c $(_BuildConfig) - postBuildSteps: - # Upload the results. - - template: /eng/pipelines/common/upload-intermediate-artifacts-step.yml - parameters: - name: $(osGroup)$(osSubgroup)_$(archType) - - # - # Build libraries AllConfigurations for packages - # - - template: /eng/pipelines/common/platform-matrix.yml - parameters: - jobTemplate: /eng/pipelines/common/global-build-job.yml - buildConfig: Release - platforms: - - windows_x64 - jobParameters: - buildArgs: -s tools+libs -allConfigurations -c $(_BuildConfig) /p:TestAssemblies=false /p:TestPackages=true - nameSuffix: Libraries_AllConfigurations - isOfficialBuild: true - postBuildSteps: - - template: /eng/pipelines/common/upload-intermediate-artifacts-step.yml - parameters: - name: Libraries_AllConfigurations - timeoutInMinutes: 95 - - - ${{ if eq(variables.isOfficialBuild, true) }}: - - template: /eng/pipelines/official/stages/publish.yml - parameters: - isOfficialBuild: true \ No newline at end of file + # + # Build and test libraries AllConfigurations + # + - template: /eng/pipelines/common/platform-matrix.yml + parameters: + jobTemplate: /eng/pipelines/common/global-build-job.yml + buildConfig: ${{ variables.debugOnPrReleaseOnRolling }} + platforms: + - windows_x64 + jobParameters: + buildArgs: -test -s tools+libs+libs.tests -allConfigurations -c $(_BuildConfig) /p:TestAssemblies=false /p:TestPackages=true + nameSuffix: Libraries_AllConfigurations + timeoutInMinutes: 150 diff --git a/src/coreclr/nativeaot/Runtime/CMakeLists.txt b/src/coreclr/nativeaot/Runtime/CMakeLists.txt index f070214054f7f9..4a10690b15af4f 100644 --- a/src/coreclr/nativeaot/Runtime/CMakeLists.txt +++ b/src/coreclr/nativeaot/Runtime/CMakeLists.txt @@ -231,15 +231,19 @@ if(FEATURE_EVENT_TRACE) add_definitions(-DFEATURE_EVENT_TRACE) endif() +if (NOT CLR_CMAKE_TARGET_ARCH_WASM) + add_definitions(-DFEATURE_HIJACK) +endif() + add_definitions(-DFEATURE_BASICFREEZE) add_definitions(-DFEATURE_CONSERVATIVE_GC) if(CLR_CMAKE_TARGET_ARCH_AMD64 OR CLR_CMAKE_TARGET_ARCH_ARM64) add_definitions(-DFEATURE_USE_SOFTWARE_WRITE_WATCH_FOR_GC_HEAP) add_definitions(-DFEATURE_MANUALLY_MANAGED_CARD_BUNDLES) -endif(CLR_CMAKE_TARGET_ARCH_AMD64 OR CLR_CMAKE_TARGET_ARCH_ARM64) -if(CLR_CMAKE_TARGET_ARCH_ARM) +endif() +if(CLR_CMAKE_TARGET_ARCH_ARM OR CLR_CMAKE_TARGET_ARCH_WASM) add_definitions(-DFEATURE_64BIT_ALIGNMENT) -endif(CLR_CMAKE_TARGET_ARCH_ARM) +endif() add_definitions(-DFEATURE_CUSTOM_IMPORTS) add_definitions(-DFEATURE_DYNAMIC_CODE) @@ -250,7 +254,7 @@ add_definitions(-DNATIVEAOT) add_definitions(-DFEATURE_CACHED_INTERFACE_DISPATCH) if(CLR_CMAKE_TARGET_ARCH_I386 OR CLR_CMAKE_TARGET_ARCH_ARM) add_definitions(-DINTERFACE_DISPATCH_CACHE_HAS_CELL_BACKPOINTER) -endif(CLR_CMAKE_TARGET_ARCH_I386 OR CLR_CMAKE_TARGET_ARCH_ARM) +endif() add_definitions(-D_LIB) # there is a problem with undefined symbols when this is set @@ -267,7 +271,7 @@ if(CLR_CMAKE_TARGET_WIN32) add_compile_options($<$:/safeseh>) endif() else() - if(NOT CLR_CMAKE_TARGET_APPLE) + if(NOT CLR_CMAKE_TARGET_APPLE AND NOT CLR_CMAKE_TARGET_ARCH_WASM) add_definitions(-DFEATURE_READONLY_GS_COOKIE) endif() include(unix/configure.cmake) diff --git a/src/coreclr/nativeaot/Runtime/CommonMacros.h b/src/coreclr/nativeaot/Runtime/CommonMacros.h index a2b4183fb1ecd5..4b74de2360e616 100644 --- a/src/coreclr/nativeaot/Runtime/CommonMacros.h +++ b/src/coreclr/nativeaot/Runtime/CommonMacros.h @@ -125,35 +125,8 @@ inline bool IS_ALIGNED(T* val, uintptr_t alignment); #ifndef __GCENV_BASE_INCLUDED__ -#if defined(HOST_WASM) -#define OS_PAGE_SIZE 0x4 -#else #define OS_PAGE_SIZE PalOsPageSize() -#endif - -#if defined(HOST_AMD64) - -#define DATA_ALIGNMENT 8 - -#elif defined(HOST_X86) - -#define DATA_ALIGNMENT 4 - -#elif defined(HOST_ARM) -#define DATA_ALIGNMENT 4 - -#elif defined(HOST_ARM64) - -#define DATA_ALIGNMENT 8 - -#elif defined(HOST_WASM) - -#define DATA_ALIGNMENT 4 - -#else -#error Unsupported target architecture -#endif #endif // __GCENV_BASE_INCLUDED__ #if defined(TARGET_ARM) diff --git a/src/coreclr/nativeaot/Runtime/GCMemoryHelpers.inl b/src/coreclr/nativeaot/Runtime/GCMemoryHelpers.inl index bb4c64aed3cf48..cb4adbfc6a275f 100644 --- a/src/coreclr/nativeaot/Runtime/GCMemoryHelpers.inl +++ b/src/coreclr/nativeaot/Runtime/GCMemoryHelpers.inl @@ -172,6 +172,8 @@ static const uint32_t INVALIDGCVALUE = 0xcccccccd; FORCEINLINE void InlineWriteBarrier(void * dst, void * ref) { + ASSERT(((uint8_t*)dst >= g_lowest_address) && ((uint8_t*)dst < g_highest_address)) + if (((uint8_t*)ref >= g_ephemeral_low) && ((uint8_t*)ref < g_ephemeral_high)) { // volatile is used here to prevent fetch of g_card_table from being reordered diff --git a/src/coreclr/nativeaot/Runtime/PalRedhawk.h b/src/coreclr/nativeaot/Runtime/PalRedhawk.h index e44c87a6046e09..9257324bd1589b 100644 --- a/src/coreclr/nativeaot/Runtime/PalRedhawk.h +++ b/src/coreclr/nativeaot/Runtime/PalRedhawk.h @@ -688,9 +688,11 @@ REDHAWK_PALIMPORT bool REDHAWK_PALAPI PalStartBackgroundGCThread(_In_ Background REDHAWK_PALIMPORT bool REDHAWK_PALAPI PalStartFinalizerThread(_In_ BackgroundCallback callback, _In_opt_ void* pCallbackContext); REDHAWK_PALIMPORT bool REDHAWK_PALAPI PalStartEventPipeHelperThread(_In_ BackgroundCallback callback, _In_opt_ void* pCallbackContext); +#ifdef FEATURE_HIJACK typedef void (*PalHijackCallback)(_In_ NATIVE_CONTEXT* pThreadContext, _In_opt_ void* pThreadToHijack); REDHAWK_PALIMPORT void REDHAWK_PALAPI PalHijack(HANDLE hThread, _In_opt_ void* pThreadToHijack); REDHAWK_PALIMPORT UInt32_BOOL REDHAWK_PALAPI PalRegisterHijackCallback(_In_ PalHijackCallback callback); +#endif REDHAWK_PALIMPORT UInt32_BOOL REDHAWK_PALAPI PalAllocateThunksFromTemplate(_In_ HANDLE hTemplateModule, uint32_t templateRva, size_t templateSize, _Outptr_result_bytebuffer_(templateSize) void** newThunksOut); REDHAWK_PALIMPORT UInt32_BOOL REDHAWK_PALAPI PalFreeThunksFromTemplate(_In_ void *pBaseAddress, size_t templateSize); diff --git a/src/coreclr/nativeaot/Runtime/portable.cpp b/src/coreclr/nativeaot/Runtime/portable.cpp index bcd99d051198d8..318a10fd20a526 100644 --- a/src/coreclr/nativeaot/Runtime/portable.cpp +++ b/src/coreclr/nativeaot/Runtime/portable.cpp @@ -332,28 +332,6 @@ void * ReturnFromUniversalTransition; EXTERN_C void * ReturnFromUniversalTransition_DebugStepTailCall; void * ReturnFromUniversalTransition_DebugStepTailCall; -#endif // USE_PORTABLE_HELPERS - -#if defined(USE_PORTABLE_HELPERS) -// -// Return address hijacking -// -FCIMPL0(void, RhpGcStressHijack) -{ - ASSERT_UNCONDITIONALLY("NYI"); -} -FCIMPLEND - -FCIMPL0(void, RhpGcProbeHijack) -{ - ASSERT_UNCONDITIONALLY("NYI"); -} -FCIMPLEND - -#endif // defined(USE_PORTABLE_HELPERS) || defined(TARGET_UNIX) - -#if defined(USE_PORTABLE_HELPERS) - #if !defined (HOST_ARM64) FCIMPL2(void, RhpAssignRef, Object ** dst, Object * ref) { diff --git a/src/coreclr/nativeaot/Runtime/thread.cpp b/src/coreclr/nativeaot/Runtime/thread.cpp index 41fa9e53949459..1ae78d37d56fc4 100644 --- a/src/coreclr/nativeaot/Runtime/thread.cpp +++ b/src/coreclr/nativeaot/Runtime/thread.cpp @@ -578,7 +578,8 @@ void Thread::GcScanRootsWorker(ScanFunc * pfnEnumCallback, ScanContext * pvCallb #ifndef DACCESS_COMPILE -EXTERN_C void FASTCALL RhpSuspendRedirected(); +#ifdef FEATURE_HIJACK + EXTERN_C void FASTCALL RhpGcProbeHijack(); EXTERN_C void FASTCALL RhpGcStressHijack(); @@ -815,6 +816,7 @@ void Thread::HijackReturnAddressWorker(StackFrameIterator* frameIterator, Hijack GetPalThreadIdForLogging(), frameIterator->GetRegisterSet()->GetIP()); } } +#endif // FEATURE_HIJACK NATIVE_CONTEXT* Thread::GetInterruptedContext() { @@ -834,6 +836,16 @@ NATIVE_CONTEXT* Thread::EnsureRedirectionContext() return m_interruptedContext; } +EXTERN_C NOINLINE void FASTCALL RhpSuspendRedirected() +{ + Thread* pThread = ThreadStore::GetCurrentThread(); + pThread->WaitForGC(INTERRUPTED_THREAD_MARKER); + + // restore execution at interrupted location + PalRestoreContext(pThread->GetInterruptedContext()); + UNREACHABLE(); +} + bool Thread::Redirect() { ASSERT(!IsDoNotTriggerGcSet()); @@ -861,6 +873,7 @@ bool Thread::Redirect() } #endif //FEATURE_SUSPEND_REDIRECTION +#ifdef FEATURE_HIJACK bool Thread::InlineSuspend(NATIVE_CONTEXT* interruptedContext) { ASSERT(!IsDoNotTriggerGcSet()); @@ -948,6 +961,7 @@ void* Thread::GetHijackedReturnAddress() ASSERT(ThreadStore::GetCurrentThread() == this); return m_pvHijackedReturnAddress; } +#endif // FEATURE_HIJACK void Thread::SetState(ThreadStateFlags flags) { @@ -1021,20 +1035,6 @@ EXTERN_C NOINLINE void FASTCALL RhpGcPoll2(PInvokeTransitionFrame* pFrame) RhpWaitForGC2(pFrame); } -#ifdef FEATURE_SUSPEND_REDIRECTION - -EXTERN_C NOINLINE void FASTCALL RhpSuspendRedirected() -{ - Thread* pThread = ThreadStore::GetCurrentThread(); - pThread->WaitForGC(INTERRUPTED_THREAD_MARKER); - - // restore execution at interrupted location - PalRestoreContext(pThread->GetInterruptedContext()); - UNREACHABLE(); -} - -#endif //FEATURE_SUSPEND_REDIRECTION - void Thread::PushExInfo(ExInfo * pExInfo) { ValidateExInfoStack(); diff --git a/src/coreclr/nativeaot/Runtime/thread.h b/src/coreclr/nativeaot/Runtime/thread.h index 161fea12281688..3c8073faa2ac70 100644 --- a/src/coreclr/nativeaot/Runtime/thread.h +++ b/src/coreclr/nativeaot/Runtime/thread.h @@ -92,9 +92,11 @@ struct ThreadBuffer PInvokeTransitionFrame* m_pCachedTransitionFrame; PTR_Thread m_pNext; // used by ThreadStore's SList HANDLE m_hPalThread; // WARNING: this may legitimately be INVALID_HANDLE_VALUE +#ifdef FEATURE_HIJACK void ** m_ppvHijackedReturnAddressLocation; void * m_pvHijackedReturnAddress; uintptr_t m_uHijackedReturnValueFlags; +#endif // FEATURE_HIJACK PTR_ExInfo m_pExInfoStackHead; Object* m_threadAbortException; // ThreadAbortException instance -set only during thread abort #ifdef TARGET_X86 @@ -168,7 +170,7 @@ class Thread : private ThreadBuffer void ClearState(ThreadStateFlags flags); bool IsStateSet(ThreadStateFlags flags); - +#ifdef FEATURE_HIJACK static void HijackCallback(NATIVE_CONTEXT* pThreadContext, void* pThreadToHijack); // @@ -181,6 +183,11 @@ class Thread : private ThreadBuffer void HijackReturnAddress(NATIVE_CONTEXT* pSuspendCtx, HijackFunc* pfnHijackFunction); void HijackReturnAddressWorker(StackFrameIterator* frameIterator, HijackFunc* pfnHijackFunction); bool InlineSuspend(NATIVE_CONTEXT* interruptedContext); + void CrossThreadUnhijack(); + void UnhijackWorker(); +#else // FEATURE_HIJACK + void CrossThreadUnhijack() { } +#endif // FEATURE_HIJACK #ifdef FEATURE_SUSPEND_REDIRECTION bool Redirect(); @@ -188,8 +195,6 @@ class Thread : private ThreadBuffer bool CacheTransitionFrameForSuspend(); void ResetCachedTransitionFrame(); - void CrossThreadUnhijack(); - void UnhijackWorker(); void EnsureRuntimeInitialized(); // @@ -222,10 +227,17 @@ class Thread : private ThreadBuffer void GcScanRoots(ScanFunc* pfnEnumCallback, ScanContext * pvCallbackData); +#ifdef FEATURE_HIJACK void Hijack(); void Unhijack(); bool IsHijacked(); void* GetHijackedReturnAddress(); + static bool IsHijackTarget(void * address); +#else // FEATURE_HIJACK + void Unhijack() { } + bool IsHijacked() { return false; } + static bool IsHijackTarget(void * address) { return false; } +#endif // FEATURE_HIJACK #ifdef FEATURE_GC_STRESS static void HijackForGcStress(PAL_LIMITED_CONTEXT * pSuspendCtx); @@ -262,8 +274,6 @@ class Thread : private ThreadBuffer PInvokeTransitionFrame* GetTransitionFrameForStackTrace(); void * GetCurrentThreadPInvokeReturnAddress(); - static bool IsHijackTarget(void * address); - // // The set of operations used to support unmanaged code running in cooperative mode // diff --git a/src/coreclr/nativeaot/Runtime/threadstore.cpp b/src/coreclr/nativeaot/Runtime/threadstore.cpp index d94ef850a1c9bb..63bb947e2baa9b 100644 --- a/src/coreclr/nativeaot/Runtime/threadstore.cpp +++ b/src/coreclr/nativeaot/Runtime/threadstore.cpp @@ -85,8 +85,10 @@ ThreadStore * ThreadStore::Create(RuntimeInstance * pRuntimeInstance) if (NULL == pNewThreadStore) return NULL; +#ifdef FEATURE_HIJACK if (!PalRegisterHijackCallback(Thread::HijackCallback)) return NULL; +#endif pNewThreadStore->m_pRuntimeInstance = pRuntimeInstance; @@ -281,10 +283,12 @@ void ThreadStore::SuspendAllThreads(bool waitForGCEvent) if (!pTargetThread->CacheTransitionFrameForSuspend()) { remaining++; +#ifdef FEATURE_HIJACK if (!observeOnly) { pTargetThread->Hijack(); } +#endif // FEATURE_HIJACK } } END_FOREACH_THREAD diff --git a/src/coreclr/nativeaot/Runtime/unix/PalRedhawkUnix.cpp b/src/coreclr/nativeaot/Runtime/unix/PalRedhawkUnix.cpp index 5cac500ca85a87..79a9476e3b7641 100644 --- a/src/coreclr/nativeaot/Runtime/unix/PalRedhawkUnix.cpp +++ b/src/coreclr/nativeaot/Runtime/unix/PalRedhawkUnix.cpp @@ -705,12 +705,7 @@ REDHAWK_PALEXPORT bool REDHAWK_PALAPI PalStartBackgroundGCThread(_In_ Background REDHAWK_PALEXPORT bool REDHAWK_PALAPI PalStartFinalizerThread(_In_ BackgroundCallback callback, _In_opt_ void* pCallbackContext) { -#ifdef HOST_WASM - // WASMTODO: No threads so we can't start the finalizer thread - return true; -#else // HOST_WASM return PalStartBackgroundWork(callback, pCallbackContext, UInt32_TRUE); -#endif // HOST_WASM } REDHAWK_PALEXPORT bool REDHAWK_PALAPI PalStartEventPipeHelperThread(_In_ BackgroundCallback callback, _In_opt_ void* pCallbackContext) @@ -989,6 +984,7 @@ extern "C" uint16_t RtlCaptureStackBackTrace(uint32_t arg1, uint32_t arg2, void* return 0; } +#ifdef FEATURE_HIJACK static PalHijackCallback g_pHijackCallback; static struct sigaction g_previousActivationHandler; @@ -1076,6 +1072,7 @@ REDHAWK_PALEXPORT void REDHAWK_PALAPI PalHijack(HANDLE hThread, _In_opt_ void* p abort(); } } +#endif // FEATURE_HIJACK extern "C" uint32_t WaitForSingleObjectEx(HANDLE handle, uint32_t milliseconds, UInt32_BOOL alertable) { From bb61fb53fe77c6871c3dd3660254d7f55a743ffe Mon Sep 17 00:00:00 2001 From: Omair Majid Date: Tue, 30 Apr 2024 09:36:05 -0400 Subject: [PATCH 156/161] With system brotli, do not use versioned symbols (#101576) The system version of libbrotli has symbols without the `V1.0` version. Support linking against that by removing the steps to use the versioned exports file. Without this fix, the build only works with bfd linker (I am not sure how). When lld is used, the build errors out: ld.lld : error : version script assignment of 'V1.0' to symbol 'BrotliDecoderCreateInstance' failed: symbol not defined [runtime/src/native/libs/build-native.proj] ld.lld : error : version script assignment of 'V1.0' to symbol 'BrotliDecoderDecompress' failed: symbol not defined [runtime/src/native/libs/build-native.proj] ld.lld : error : version script assignment of 'V1.0' to symbol 'BrotliDecoderDecompressStream' failed: symbol not defined [runtime/src/native/libs/build-native.proj] ld.lld : error : version script assignment of 'V1.0' to symbol 'BrotliDecoderDestroyInstance' failed: symbol not defined [runtime/src/native/libs/build-native.proj] ld.lld : error : version script assignment of 'V1.0' to symbol 'BrotliDecoderIsFinished' failed: symbol not defined [runtime/src/native/libs/build-native.proj] ld.lld : error : version script assignment of 'V1.0' to symbol 'BrotliEncoderCompress' failed: symbol not defined [runtime/src/native/libs/build-native.proj] ld.lld : error : version script assignment of 'V1.0' to symbol 'BrotliEncoderCompressStream' failed: symbol not defined [runtime/src/native/libs/build-native.proj] ld.lld : error : version script assignment of 'V1.0' to symbol 'BrotliEncoderCreateInstance' failed: symbol not defined [runtime/src/native/libs/build-native.proj] ld.lld : error : version script assignment of 'V1.0' to symbol 'BrotliEncoderDestroyInstance' failed: symbol not defined [runtime/src/native/libs/build-native.proj] ld.lld : error : version script assignment of 'V1.0' to symbol 'BrotliEncoderHasMoreOutput' failed: symbol not defined [runtime/src/native/libs/build-native.proj] ld.lld : error : version script assignment of 'V1.0' to symbol 'BrotliEncoderSetParameter' failed: symbol not defined [runtime/src/native/libs/build-native.proj] clang-18 : error : linker command failed with exit code 1 (use -v to see invocation) [runtime/src/native/libs/build-native.proj] --- .../CMakeLists.txt | 20 +++++++++---------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/src/native/libs/System.IO.Compression.Native/CMakeLists.txt b/src/native/libs/System.IO.Compression.Native/CMakeLists.txt index 0a05e96eb494ba..089363cf5554ec 100644 --- a/src/native/libs/System.IO.Compression.Native/CMakeLists.txt +++ b/src/native/libs/System.IO.Compression.Native/CMakeLists.txt @@ -66,7 +66,7 @@ if (CLR_CMAKE_TARGET_UNIX OR CLR_CMAKE_TARGET_BROWSER OR CLR_CMAKE_TARGET_WASI) ${NATIVE_LIBS_EXTRA} ) - if (NOT CLR_CMAKE_TARGET_MACCATALYST AND NOT CLR_CMAKE_TARGET_IOS AND NOT CLR_CMAKE_TARGET_TVOS AND NOT CLR_CMAKE_TARGET_ANDROID) + if (NOT CLR_CMAKE_TARGET_MACCATALYST AND NOT CLR_CMAKE_TARGET_IOS AND NOT CLR_CMAKE_TARGET_TVOS AND NOT CLR_CMAKE_TARGET_ANDROID AND NOT CLR_CMAKE_USE_SYSTEM_BROTLI) set(DEF_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/System.IO.Compression.Native_unixexports.src) set(EXPORTS_FILE ${CMAKE_CURRENT_BINARY_DIR}/System.IO.Compression.Native.exports) generate_exports_file(${DEF_SOURCES} ${EXPORTS_FILE}) @@ -78,16 +78,14 @@ if (CLR_CMAKE_TARGET_UNIX OR CLR_CMAKE_TARGET_BROWSER OR CLR_CMAKE_TARGET_WASI) set_property(TARGET System.IO.Compression.Native APPEND_STRING PROPERTY LINK_FLAGS ${EXPORTS_LINKER_OPTION}) set_property(TARGET System.IO.Compression.Native APPEND_STRING PROPERTY LINK_DEPENDS ${EXPORTS_FILE}) - if (NOT CLR_CMAKE_USE_SYSTEM_BROTLI) - add_custom_command(TARGET System.IO.Compression.Native POST_BUILD - COMMENT "Verifying System.IO.Compression.Native entry points against entrypoints.c " - COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/../verify-entrypoints.sh - $ - ${CMAKE_CURRENT_SOURCE_DIR}/entrypoints.c - ${CMAKE_NM} - VERBATIM - ) - endif () + add_custom_command(TARGET System.IO.Compression.Native POST_BUILD + COMMENT "Verifying System.IO.Compression.Native entry points against entrypoints.c " + COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/../verify-entrypoints.sh + $ + ${CMAKE_CURRENT_SOURCE_DIR}/entrypoints.c + ${CMAKE_NM} + VERBATIM + ) endif () install_with_stripped_symbols (System.IO.Compression.Native PROGRAMS .) From 82830499e172ff553be11f4e85386c6bf077a397 Mon Sep 17 00:00:00 2001 From: Sanjam Panda <36253777+saitama951@users.noreply.github.com> Date: Tue, 30 Apr 2024 19:20:24 +0530 Subject: [PATCH 157/161] fix stack local offset size for passing argument (#101103) --- src/mono/mono/mini/mini-s390x.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mono/mono/mini/mini-s390x.c b/src/mono/mono/mini/mini-s390x.c index c87ec5573bc5e4..c084bdfb1be76e 100644 --- a/src/mono/mono/mini/mini-s390x.c +++ b/src/mono/mono/mini/mini-s390x.c @@ -1580,7 +1580,7 @@ mono_arch_allocate_vars (MonoCompile *cfg) inst->inst_offset = offset + (8 - size); } } - offset += MAX(size, 8); + offset += 8; } curinst++; } From 9fa12355097e1ac17ac44445649a381323e9c35f Mon Sep 17 00:00:00 2001 From: Qiao Pengcheng Date: Tue, 30 Apr 2024 23:26:13 +0800 Subject: [PATCH 158/161] [LoongArch64] clear float type when passed by integer reg. (#101713) --- src/coreclr/jit/targetloongarch64.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/coreclr/jit/targetloongarch64.cpp b/src/coreclr/jit/targetloongarch64.cpp index 6d63951c8ea205..9292f0e0e67a8f 100644 --- a/src/coreclr/jit/targetloongarch64.cpp +++ b/src/coreclr/jit/targetloongarch64.cpp @@ -161,6 +161,7 @@ ABIPassingInformation LoongArch64Classifier::Classify(Compiler* comp, canPassArgInRegisters = m_floatRegs.Count() > 0; if (!canPassArgInRegisters) { + type = TYP_I_IMPL; m_floatRegs.Clear(); canPassArgInRegisters = m_intRegs.Count() > 0; } From 017593d90781d797df8b2241f6d1f83c236c442b Mon Sep 17 00:00:00 2001 From: Jakob Botsch Nielsen Date: Tue, 30 Apr 2024 18:29:30 +0200 Subject: [PATCH 159/161] JIT: Avoid relying on bbNum to find lexical loop boundaries (#101714) Switch `FlowGraphNaturalLoop::GetLexicallyTopMostBlock` and `FlowGraphNaturalLoop::GetLexicallyBottomMostBlock` to more robust implementations that scan the basic block list forwards (and backwards) to find the boundary blocks. Fix #101695 --- src/coreclr/jit/flowgraph.cpp | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/src/coreclr/jit/flowgraph.cpp b/src/coreclr/jit/flowgraph.cpp index 8b73d10aa8dc1d..2a185d9e47b1d1 100644 --- a/src/coreclr/jit/flowgraph.cpp +++ b/src/coreclr/jit/flowgraph.cpp @@ -5555,7 +5555,7 @@ bool FlowGraphNaturalLoop::InitBlockEntersLoopOnTrue(BasicBlock* initBlock) // the loop. // // Returns: -// Block with highest bbNum. +// First block in block order contained in the loop. // // Remarks: // Mostly exists as a quirk while transitioning from the old loop @@ -5563,12 +5563,13 @@ bool FlowGraphNaturalLoop::InitBlockEntersLoopOnTrue(BasicBlock* initBlock) // BasicBlock* FlowGraphNaturalLoop::GetLexicallyTopMostBlock() { - BasicBlock* top = m_header; - VisitLoopBlocks([&top](BasicBlock* loopBlock) { - if (loopBlock->bbNum < top->bbNum) - top = loopBlock; - return BasicBlockVisit::Continue; - }); + BasicBlock* top = m_dfsTree->GetCompiler()->fgFirstBB; + + while (!ContainsBlock(top)) + { + top = top->Next(); + assert(top != nullptr); + } return top; } @@ -5578,7 +5579,7 @@ BasicBlock* FlowGraphNaturalLoop::GetLexicallyTopMostBlock() // within the loop. // // Returns: -// Block with highest bbNum. +// Last block in block order contained in the loop. // // Remarks: // Mostly exists as a quirk while transitioning from the old loop @@ -5586,12 +5587,13 @@ BasicBlock* FlowGraphNaturalLoop::GetLexicallyTopMostBlock() // BasicBlock* FlowGraphNaturalLoop::GetLexicallyBottomMostBlock() { - BasicBlock* bottom = m_header; - VisitLoopBlocks([&bottom](BasicBlock* loopBlock) { - if (loopBlock->bbNum > bottom->bbNum) - bottom = loopBlock; - return BasicBlockVisit::Continue; - }); + BasicBlock* bottom = m_dfsTree->GetCompiler()->fgLastBB; + + while (!ContainsBlock(bottom)) + { + bottom = bottom->Prev(); + assert(bottom != nullptr); + } return bottom; } From 30b3721b36ecaac4abb43c847940313d26f2edf7 Mon Sep 17 00:00:00 2001 From: Sven Boemer Date: Tue, 30 Apr 2024 15:38:49 -0700 Subject: [PATCH 160/161] Preserve static type info for return value of ctor (#101212) Instead of tracking the return value as "TopValue" or "unknown", this models the constructor as returning a value with a static type when called with newobj, letting us undo the workaround from https://github.com/dotnet/runtime/pull/101031. --- .../Common/Compiler/Dataflow/MethodProxy.cs | 2 + .../Compiler/Dataflow/FlowAnnotations.cs | 8 ++-- .../Compiler/Dataflow/HandleCallAction.cs | 11 ++--- .../Compiler/Dataflow/MethodReturnValue.cs | 6 ++- .../Dataflow/ReflectionMethodBodyScanner.cs | 5 ++- .../TrimAnalysis/FlowAnnotations.cs | 8 ++-- .../TrimAnalysis/HandleCallAction.cs | 5 ++- .../TrimAnalysis/MethodProxy.cs | 2 + .../TrimAnalysis/MethodReturnValue.cs | 10 +++-- .../TrimAnalysis/TrimAnalysisVisitor.cs | 4 +- .../TrimAnalysis/FlowAnnotations.cs | 4 +- .../TrimAnalysis/HandleCallAction.cs | 24 +++++----- .../TypeSystemProxy/MethodProxy.cs | 1 + .../linker/Linker.Dataflow/FlowAnnotations.cs | 8 ++-- .../Linker.Dataflow/HandleCallAction.cs | 5 ++- .../src/linker/Linker.Dataflow/MethodProxy.cs | 2 + .../Linker.Dataflow/MethodReturnValue.cs | 11 ++++- .../ReflectionMethodBodyScanner.cs | 5 ++- .../DataFlowTests.cs | 6 +++ .../DataFlow/IReflectDataflow.cs | 3 ++ .../DataFlow/MethodReturnParameterDataFlow.cs | 8 ++-- .../DataFlow/MethodThisDataFlow.cs | 2 +- .../DataFlow/ObjectGetTypeDataflow.cs | 44 +++++++++++++++++++ 23 files changed, 129 insertions(+), 55 deletions(-) create mode 100644 src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/ObjectGetTypeDataflow.cs diff --git a/src/coreclr/tools/Common/Compiler/Dataflow/MethodProxy.cs b/src/coreclr/tools/Common/Compiler/Dataflow/MethodProxy.cs index 3e282dfc76dcf9..cfb4bb12902958 100644 --- a/src/coreclr/tools/Common/Compiler/Dataflow/MethodProxy.cs +++ b/src/coreclr/tools/Common/Compiler/Dataflow/MethodProxy.cs @@ -66,6 +66,8 @@ internal partial ImmutableArray GetGenericParameters() return builder.ToImmutableArray(); } + internal partial bool IsConstructor() => Method.IsConstructor; + internal partial bool IsStatic() => Method.Signature.IsStatic; internal partial bool HasImplicitThis() => !Method.Signature.IsStatic; diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/FlowAnnotations.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/FlowAnnotations.cs index 730330a31a9bc6..fd8094bc702831 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/FlowAnnotations.cs +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/FlowAnnotations.cs @@ -951,12 +951,12 @@ internal partial bool MethodRequiresDataFlowAnalysis(MethodProxy method) => RequiresDataflowAnalysisDueToSignature(method.Method); #pragma warning disable CA1822 // Other partial implementations are not in the ilc project - internal partial MethodReturnValue GetMethodReturnValue(MethodProxy method, DynamicallyAccessedMemberTypes dynamicallyAccessedMemberTypes) + internal partial MethodReturnValue GetMethodReturnValue(MethodProxy method, bool isNewObj, DynamicallyAccessedMemberTypes dynamicallyAccessedMemberTypes) #pragma warning restore CA1822 // Mark members as static - => new MethodReturnValue(method.Method, dynamicallyAccessedMemberTypes); + => new MethodReturnValue(method.Method, isNewObj, dynamicallyAccessedMemberTypes); - internal partial MethodReturnValue GetMethodReturnValue(MethodProxy method) - => GetMethodReturnValue(method, GetReturnParameterAnnotation(method.Method)); + internal partial MethodReturnValue GetMethodReturnValue(MethodProxy method, bool isNewObj) + => GetMethodReturnValue(method, isNewObj, GetReturnParameterAnnotation(method.Method)); internal partial GenericParameterValue GetGenericParameterValue(GenericParameterProxy genericParameter) => new GenericParameterValue(genericParameter.GenericParameter, GetGenericParameterAnnotation(genericParameter.GenericParameter)); diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/HandleCallAction.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/HandleCallAction.cs index c637185d15b539..7207efb6d03f59 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/HandleCallAction.cs +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/HandleCallAction.cs @@ -39,6 +39,7 @@ public HandleCallAction( { _reflectionMarker = reflectionMarker; _operation = operation; + _isNewObj = operation == ILOpcode.newobj; _diagnosticContext = diagnosticContext; _callingMethod = callingMethod; _annotations = annotations; @@ -337,12 +338,6 @@ private partial bool TryHandleIntrinsic ( if (Intrinsics.GetIntrinsicIdForMethod(_callingMethod) == IntrinsicId.RuntimeReflectionExtensions_GetMethodInfo) break; - if (param.IsEmpty()) - { - // The static value is unknown and the below `foreach` won't execute - _reflectionMarker.Dependencies.Add(_reflectionMarker.Factory.ReflectedDelegate(null), "Delegate.Method access on unknown delegate type"); - } - foreach (var valueNode in param.AsEnumerable()) { TypeDesc? staticType = (valueNode as IValueWithStaticType)?.StaticType?.Type; @@ -390,7 +385,7 @@ private partial bool TryHandleIntrinsic ( if (staticType is null || (!staticType.IsDefType && !staticType.IsArray)) { // We don't know anything about the type GetType was called on. Track this as a usual "result of a method call without any annotations" - AddReturnValue(_reflectionMarker.Annotations.GetMethodReturnValue(calledMethod)); + AddReturnValue(_reflectionMarker.Annotations.GetMethodReturnValue(calledMethod, _isNewObj)); } else if (staticType.IsSealed() || staticType.IsTypeOf("System", "Delegate")) { @@ -425,7 +420,7 @@ private partial bool TryHandleIntrinsic ( // Return a value which is "unknown type" with annotation. For now we'll use the return value node // for the method, which means we're loosing the information about which staticType this // started with. For now we don't need it, but we can add it later on. - AddReturnValue(_reflectionMarker.Annotations.GetMethodReturnValue(calledMethod, annotation)); + AddReturnValue(_reflectionMarker.Annotations.GetMethodReturnValue(calledMethod, _isNewObj, annotation)); } } } diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/MethodReturnValue.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/MethodReturnValue.cs index 7bb244d8d2bf07..7b90ffe6404599 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/MethodReturnValue.cs +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/MethodReturnValue.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Collections.Generic; +using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using ILCompiler.Dataflow; using ILLink.Shared.DataFlow; @@ -16,9 +17,10 @@ namespace ILLink.Shared.TrimAnalysis /// internal partial record MethodReturnValue { - public MethodReturnValue(MethodDesc method, DynamicallyAccessedMemberTypes dynamicallyAccessedMemberTypes) + public MethodReturnValue(MethodDesc method, bool isNewObj, DynamicallyAccessedMemberTypes dynamicallyAccessedMemberTypes) { - StaticType = method.Signature.ReturnType; + Debug.Assert(!isNewObj || method.IsConstructor, "isNewObj can only be true for constructors"); + StaticType = isNewObj ? method.OwningType : method.Signature.ReturnType; Method = method; DynamicallyAccessedMemberTypes = dynamicallyAccessedMemberTypes; } diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReflectionMethodBodyScanner.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReflectionMethodBodyScanner.cs index 3d9cfd1daa7c81..6a00b2df965762 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReflectionMethodBodyScanner.cs +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReflectionMethodBodyScanner.cs @@ -118,7 +118,7 @@ protected override void Scan(MethodIL methodBody, ref InterproceduralState inter if (!methodBody.OwningMethod.Signature.ReturnType.IsVoid) { var method = methodBody.OwningMethod; - var methodReturnValue = _annotations.GetMethodReturnValue(method); + var methodReturnValue = _annotations.GetMethodReturnValue(method, isNewObj: false); if (methodReturnValue.DynamicallyAccessedMemberTypes != 0) HandleAssignmentPattern(_origin, ReturnValue, methodReturnValue, method.GetDisplayName()); } @@ -315,7 +315,8 @@ public static MultiValue HandleCall( var callingMethodDefinition = callingMethodBody.OwningMethod; Debug.Assert(callingMethodDefinition == diagnosticContext.Origin.MemberDefinition); - var annotatedMethodReturnValue = reflectionMarker.Annotations.GetMethodReturnValue(calledMethod); + bool isNewObj = operation == ILOpcode.newobj; + var annotatedMethodReturnValue = reflectionMarker.Annotations.GetMethodReturnValue(calledMethod, isNewObj); Debug.Assert( RequiresReflectionMethodBodyScannerForCallSite(reflectionMarker.Annotations, calledMethod) || annotatedMethodReturnValue.DynamicallyAccessedMemberTypes == DynamicallyAccessedMemberTypes.None); diff --git a/src/tools/illink/src/ILLink.RoslynAnalyzer/TrimAnalysis/FlowAnnotations.cs b/src/tools/illink/src/ILLink.RoslynAnalyzer/TrimAnalysis/FlowAnnotations.cs index db0eb0af579ede..2fa967fdc9405d 100644 --- a/src/tools/illink/src/ILLink.RoslynAnalyzer/TrimAnalysis/FlowAnnotations.cs +++ b/src/tools/illink/src/ILLink.RoslynAnalyzer/TrimAnalysis/FlowAnnotations.cs @@ -103,11 +103,11 @@ public static DynamicallyAccessedMemberTypes GetTypeAnnotation(ITypeSymbol type) internal partial bool MethodRequiresDataFlowAnalysis (MethodProxy method) => RequiresDataFlowAnalysis (method.Method); - internal partial MethodReturnValue GetMethodReturnValue (MethodProxy method, DynamicallyAccessedMemberTypes dynamicallyAccessedMemberTypes) - => new MethodReturnValue (method.Method, dynamicallyAccessedMemberTypes); + internal partial MethodReturnValue GetMethodReturnValue (MethodProxy method, bool isNewObj, DynamicallyAccessedMemberTypes dynamicallyAccessedMemberTypes) + => new MethodReturnValue (method.Method, isNewObj, dynamicallyAccessedMemberTypes); - internal partial MethodReturnValue GetMethodReturnValue (MethodProxy method) - => GetMethodReturnValue (method, GetMethodReturnValueAnnotation (method.Method)); + internal partial MethodReturnValue GetMethodReturnValue (MethodProxy method, bool isNewObj) + => GetMethodReturnValue (method, isNewObj, GetMethodReturnValueAnnotation (method.Method)); internal partial GenericParameterValue GetGenericParameterValue (GenericParameterProxy genericParameter) => new GenericParameterValue (genericParameter.TypeParameterSymbol); diff --git a/src/tools/illink/src/ILLink.RoslynAnalyzer/TrimAnalysis/HandleCallAction.cs b/src/tools/illink/src/ILLink.RoslynAnalyzer/TrimAnalysis/HandleCallAction.cs index 9212cdc298fefb..d41ccee2388a58 100644 --- a/src/tools/illink/src/ILLink.RoslynAnalyzer/TrimAnalysis/HandleCallAction.cs +++ b/src/tools/illink/src/ILLink.RoslynAnalyzer/TrimAnalysis/HandleCallAction.cs @@ -33,6 +33,7 @@ public HandleCallAction ( { _owningSymbol = owningSymbol; _operation = operation; + _isNewObj = operation.Kind == OperationKind.ObjectCreation; _diagnosticContext = diagnosticContext; _annotations = FlowAnnotations.Instance; _reflectionAccessAnalyzer = default; @@ -86,7 +87,7 @@ private partial bool TryHandleIntrinsic ( if (staticType is null) { // We don't know anything about the type GetType was called on. Track this as a usual "result of a method call without any annotations" - AddReturnValue (FlowAnnotations.Instance.GetMethodReturnValue (calledMethod)); + AddReturnValue (FlowAnnotations.Instance.GetMethodReturnValue (calledMethod, _isNewObj)); } else if (staticType.IsSealed || staticType.IsTypeOf ("System", "Delegate") || staticType.TypeKind == TypeKind.Array) { // We can treat this one the same as if it was a typeof() expression @@ -106,7 +107,7 @@ private partial bool TryHandleIntrinsic ( AddReturnValue (new SystemTypeValue (new (staticType))); } else { var annotation = FlowAnnotations.GetTypeAnnotation (staticType); - AddReturnValue (FlowAnnotations.Instance.GetMethodReturnValue (calledMethod, annotation)); + AddReturnValue (FlowAnnotations.Instance.GetMethodReturnValue (calledMethod, _isNewObj, annotation)); } } break; diff --git a/src/tools/illink/src/ILLink.RoslynAnalyzer/TrimAnalysis/MethodProxy.cs b/src/tools/illink/src/ILLink.RoslynAnalyzer/TrimAnalysis/MethodProxy.cs index 5001e5836eaccb..0b274879440f51 100644 --- a/src/tools/illink/src/ILLink.RoslynAnalyzer/TrimAnalysis/MethodProxy.cs +++ b/src/tools/illink/src/ILLink.RoslynAnalyzer/TrimAnalysis/MethodProxy.cs @@ -46,6 +46,8 @@ internal partial ImmutableArray GetGenericParameters () return builder.ToImmutableArray (); } + internal partial bool IsConstructor () => Method.IsConstructor (); + internal partial bool IsStatic () => Method.IsStatic; internal partial bool HasImplicitThis () => Method.HasImplicitThis (); diff --git a/src/tools/illink/src/ILLink.RoslynAnalyzer/TrimAnalysis/MethodReturnValue.cs b/src/tools/illink/src/ILLink.RoslynAnalyzer/TrimAnalysis/MethodReturnValue.cs index 6a84896e577a86..d11181ad96d250 100644 --- a/src/tools/illink/src/ILLink.RoslynAnalyzer/TrimAnalysis/MethodReturnValue.cs +++ b/src/tools/illink/src/ILLink.RoslynAnalyzer/TrimAnalysis/MethodReturnValue.cs @@ -2,6 +2,7 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. using System.Collections.Generic; +using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using ILLink.RoslynAnalyzer; using ILLink.Shared.DataFlow; @@ -11,16 +12,17 @@ namespace ILLink.Shared.TrimAnalysis { internal partial record MethodReturnValue { - public MethodReturnValue (IMethodSymbol methodSymbol) - : this (methodSymbol, FlowAnnotations.GetMethodReturnValueAnnotation (methodSymbol)) + public MethodReturnValue (IMethodSymbol methodSymbol, bool isNewObj) + : this (methodSymbol, isNewObj, FlowAnnotations.GetMethodReturnValueAnnotation (methodSymbol)) { } - public MethodReturnValue (IMethodSymbol methodSymbol, DynamicallyAccessedMemberTypes dynamicallyAccessedMemberTypes) + public MethodReturnValue (IMethodSymbol methodSymbol, bool isNewObj, DynamicallyAccessedMemberTypes dynamicallyAccessedMemberTypes) { + Debug.Assert (!isNewObj || methodSymbol.MethodKind == MethodKind.Constructor, "isNewObj can only be true for constructors"); MethodSymbol = methodSymbol; DynamicallyAccessedMemberTypes = dynamicallyAccessedMemberTypes; - StaticType = new (methodSymbol.ReturnType); + StaticType = new (isNewObj ? methodSymbol.ContainingType : methodSymbol.ReturnType); } public readonly IMethodSymbol MethodSymbol; diff --git a/src/tools/illink/src/ILLink.RoslynAnalyzer/TrimAnalysis/TrimAnalysisVisitor.cs b/src/tools/illink/src/ILLink.RoslynAnalyzer/TrimAnalysis/TrimAnalysisVisitor.cs index 4ff9333c55904b..c3aaa62d99ba97 100644 --- a/src/tools/illink/src/ILLink.RoslynAnalyzer/TrimAnalysis/TrimAnalysisVisitor.cs +++ b/src/tools/illink/src/ILLink.RoslynAnalyzer/TrimAnalysis/TrimAnalysisVisitor.cs @@ -116,7 +116,7 @@ public override MultiValue VisitConversion (IConversionOperation operation, Stat var value = base.VisitConversion (operation, state); if (operation.OperatorMethod != null) - return operation.OperatorMethod.ReturnType.IsTypeInterestingForDataflow () ? new MethodReturnValue (operation.OperatorMethod) : value; + return operation.OperatorMethod.ReturnType.IsTypeInterestingForDataflow () ? new MethodReturnValue (operation.OperatorMethod, isNewObj: false) : value; // TODO - is it possible to have annotation on the operator method parameters? // if so, will these be checked here? @@ -341,7 +341,7 @@ public override void HandleReturnValue (MultiValue returnValue, IOperation opera return; if (method.ReturnType.IsTypeInterestingForDataflow ()) { - var returnParameter = new MethodReturnValue (method); + var returnParameter = new MethodReturnValue (method, isNewObj: false); TrimAnalysisPatterns.Add ( new TrimAnalysisAssignmentPattern (returnValue, returnParameter, operation, OwningSymbol, featureContext), diff --git a/src/tools/illink/src/ILLink.Shared/TrimAnalysis/FlowAnnotations.cs b/src/tools/illink/src/ILLink.Shared/TrimAnalysis/FlowAnnotations.cs index 7ca5df5a6b8fe4..4ef9a9ce61a41f 100644 --- a/src/tools/illink/src/ILLink.Shared/TrimAnalysis/FlowAnnotations.cs +++ b/src/tools/illink/src/ILLink.Shared/TrimAnalysis/FlowAnnotations.cs @@ -19,9 +19,9 @@ partial class FlowAnnotations { internal partial bool MethodRequiresDataFlowAnalysis (MethodProxy method); - internal partial MethodReturnValue GetMethodReturnValue (MethodProxy method, DynamicallyAccessedMemberTypes dynamicallyAccessedMemberTypes); + internal partial MethodReturnValue GetMethodReturnValue (MethodProxy method, bool isNewObj, DynamicallyAccessedMemberTypes dynamicallyAccessedMemberTypes); - internal partial MethodReturnValue GetMethodReturnValue (MethodProxy method); + internal partial MethodReturnValue GetMethodReturnValue (MethodProxy method, bool isNewObj); internal partial GenericParameterValue GetGenericParameterValue (GenericParameterProxy genericParameter); diff --git a/src/tools/illink/src/ILLink.Shared/TrimAnalysis/HandleCallAction.cs b/src/tools/illink/src/ILLink.Shared/TrimAnalysis/HandleCallAction.cs index 1ba45a7668bff0..ff2a393928deaf 100644 --- a/src/tools/illink/src/ILLink.Shared/TrimAnalysis/HandleCallAction.cs +++ b/src/tools/illink/src/ILLink.Shared/TrimAnalysis/HandleCallAction.cs @@ -26,6 +26,7 @@ internal partial struct HandleCallAction private readonly DiagnosticContext _diagnosticContext; private readonly FlowAnnotations _annotations; private readonly RequireDynamicallyAccessedMembersAction _requireDynamicallyAccessedMembersAction; + private readonly bool _isNewObj; public bool Invoke (MethodProxy calledMethod, MultiValue instanceValue, IReadOnlyList argumentValues, IntrinsicId intrinsicId, out MultiValue methodReturnValue) { @@ -37,11 +38,12 @@ public bool Invoke (MethodProxy calledMethod, MultiValue instanceValue, IReadOnl // As a convenience, if the code above didn't set the return value (and the method has a return value), // we will set it to be an unknown value with the return type of the method. - var annotatedMethodReturnValue = _annotations.GetMethodReturnValue (calledMethod); + var annotatedMethodReturnValue = _annotations.GetMethodReturnValue (calledMethod, _isNewObj); bool returnsVoid = calledMethod.ReturnsVoid (); - methodReturnValue = maybeMethodReturnValue ?? (returnsVoid ? - MultiValueLattice.Top : - annotatedMethodReturnValue); + methodReturnValue = maybeMethodReturnValue ?? + ((returnsVoid && !_isNewObj) + ? MultiValueLattice.Top + : annotatedMethodReturnValue); // Validate that the return value has the correct annotations as per the method return value annotations if (annotatedMethodReturnValue.DynamicallyAccessedMemberTypes != 0) { @@ -80,7 +82,7 @@ bool TryHandleSharedIntrinsic ( MultiValue? returnValue = methodReturnValue = null; bool requiresDataFlowAnalysis = _annotations.MethodRequiresDataFlowAnalysis (calledMethod); - var annotatedMethodReturnValue = _annotations.GetMethodReturnValue (calledMethod); + var annotatedMethodReturnValue = _annotations.GetMethodReturnValue (calledMethod, _isNewObj); Debug.Assert (requiresDataFlowAnalysis || annotatedMethodReturnValue.DynamicallyAccessedMemberTypes == DynamicallyAccessedMemberTypes.None); switch (intrinsicId) { @@ -237,7 +239,7 @@ GenericParameterValue genericParam && valueWithDynamicallyAccessedMembers.DynamicallyAccessedMemberTypes == DynamicallyAccessedMemberTypes.All) returnMemberTypes = DynamicallyAccessedMemberTypes.All; - AddReturnValue (_annotations.GetMethodReturnValue (calledMethod, returnMemberTypes)); + AddReturnValue (_annotations.GetMethodReturnValue (calledMethod, _isNewObj, returnMemberTypes)); } } } @@ -544,7 +546,7 @@ GenericParameterValue genericParam // We only applied the annotation based on binding flags, so we will keep the necessary types // but we will not keep anything on them. So the return value has no known annotations on it - AddReturnValue (_annotations.GetMethodReturnValue (calledMethod, DynamicallyAccessedMemberTypes.None)); + AddReturnValue (_annotations.GetMethodReturnValue (calledMethod, _isNewObj, DynamicallyAccessedMemberTypes.None)); } } } else if (value is NullValue) { @@ -558,9 +560,9 @@ GenericParameterValue genericParam // since All applies recursively to all nested type (see MarkStep.MarkEntireType). // Otherwise we only mark the nested type itself, nothing on it, so the return value has no annotation on it. if (value is ValueWithDynamicallyAccessedMembers { DynamicallyAccessedMemberTypes: DynamicallyAccessedMemberTypes.All }) - AddReturnValue (_annotations.GetMethodReturnValue (calledMethod, DynamicallyAccessedMemberTypes.All)); + AddReturnValue (_annotations.GetMethodReturnValue (calledMethod, _isNewObj, DynamicallyAccessedMemberTypes.All)); else - AddReturnValue (_annotations.GetMethodReturnValue (calledMethod, DynamicallyAccessedMemberTypes.None)); + AddReturnValue (_annotations.GetMethodReturnValue (calledMethod, _isNewObj, DynamicallyAccessedMemberTypes.None)); } } } @@ -832,7 +834,7 @@ GenericParameterValue genericParam } else if (typeNameValue is ValueWithDynamicallyAccessedMembers valueWithDynamicallyAccessedMembers && valueWithDynamicallyAccessedMembers.DynamicallyAccessedMemberTypes != 0) { // Propagate the annotation from the type name to the return value. Annotation on a string value will be fulfilled whenever a value is assigned to the string with annotation. // So while we don't know which type it is, we can guarantee that it will fulfill the annotation. - AddReturnValue (_annotations.GetMethodReturnValue (calledMethod, valueWithDynamicallyAccessedMembers.DynamicallyAccessedMemberTypes)); + AddReturnValue (_annotations.GetMethodReturnValue (calledMethod, _isNewObj, valueWithDynamicallyAccessedMembers.DynamicallyAccessedMemberTypes)); } else { _diagnosticContext.AddDiagnostic (DiagnosticId.UnrecognizedTypeNameInTypeGetType, calledMethod.GetDisplayName ()); AddReturnValue (MultiValueLattice.Top); @@ -956,7 +958,7 @@ GenericParameterValue genericParam propagatedMemberTypes |= DynamicallyAccessedMemberTypes.Interfaces; } - AddReturnValue (_annotations.GetMethodReturnValue (calledMethod, propagatedMemberTypes)); + AddReturnValue (_annotations.GetMethodReturnValue (calledMethod, _isNewObj, propagatedMemberTypes)); } else if (value is SystemTypeValue systemTypeValue) { if (TryGetBaseType (systemTypeValue.RepresentedType, out var baseType)) AddReturnValue (new SystemTypeValue (baseType.Value)); diff --git a/src/tools/illink/src/ILLink.Shared/TypeSystemProxy/MethodProxy.cs b/src/tools/illink/src/ILLink.Shared/TypeSystemProxy/MethodProxy.cs index 92ba44e630babf..008d1c1536ef77 100644 --- a/src/tools/illink/src/ILLink.Shared/TypeSystemProxy/MethodProxy.cs +++ b/src/tools/illink/src/ILLink.Shared/TypeSystemProxy/MethodProxy.cs @@ -56,6 +56,7 @@ internal bool HasParameterOfType (ParameterIndex parameterIndex, string fullType internal partial bool HasGenericParameters (); internal partial bool HasGenericParametersCount (int genericParameterCount); internal partial ImmutableArray GetGenericParameters (); + internal partial bool IsConstructor (); internal partial bool IsStatic (); internal partial bool HasImplicitThis (); internal partial bool ReturnsVoid (); diff --git a/src/tools/illink/src/linker/Linker.Dataflow/FlowAnnotations.cs b/src/tools/illink/src/linker/Linker.Dataflow/FlowAnnotations.cs index 0c257fa068d898..3b148cf3a1ac59 100644 --- a/src/tools/illink/src/linker/Linker.Dataflow/FlowAnnotations.cs +++ b/src/tools/illink/src/linker/Linker.Dataflow/FlowAnnotations.cs @@ -682,11 +682,11 @@ public FieldAnnotation (FieldDefinition field, DynamicallyAccessedMemberTypes an internal partial bool MethodRequiresDataFlowAnalysis (MethodProxy method) => RequiresDataFlowAnalysis (method.Method); - internal partial MethodReturnValue GetMethodReturnValue (MethodProxy method, DynamicallyAccessedMemberTypes dynamicallyAccessedMemberTypes) - => new MethodReturnValue (method.Method.ReturnType.ResolveToTypeDefinition (_context), method.Method, dynamicallyAccessedMemberTypes); + internal partial MethodReturnValue GetMethodReturnValue (MethodProxy method, bool isNewObj, DynamicallyAccessedMemberTypes dynamicallyAccessedMemberTypes) + => MethodReturnValue.Create (method.Method, isNewObj, dynamicallyAccessedMemberTypes, _context); - internal partial MethodReturnValue GetMethodReturnValue (MethodProxy method) - => GetMethodReturnValue (method, GetReturnParameterAnnotation (method.Method)); + internal partial MethodReturnValue GetMethodReturnValue (MethodProxy method, bool isNewObj) + => GetMethodReturnValue (method, isNewObj, GetReturnParameterAnnotation (method.Method)); internal partial GenericParameterValue GetGenericParameterValue (GenericParameterProxy genericParameter) => new GenericParameterValue (genericParameter.GenericParameter, GetGenericParameterAnnotation (genericParameter.GenericParameter)); diff --git a/src/tools/illink/src/linker/Linker.Dataflow/HandleCallAction.cs b/src/tools/illink/src/linker/Linker.Dataflow/HandleCallAction.cs index 6721ec63478fac..998d9a06fdaeb6 100644 --- a/src/tools/illink/src/linker/Linker.Dataflow/HandleCallAction.cs +++ b/src/tools/illink/src/linker/Linker.Dataflow/HandleCallAction.cs @@ -37,6 +37,7 @@ public HandleCallAction ( { _context = context; _operation = operation; + _isNewObj = operation.OpCode == OpCodes.Newobj; _markStep = markStep; _reflectionMarker = reflectionMarker; _diagnosticContext = diagnosticContext; @@ -122,7 +123,7 @@ private partial bool TryHandleIntrinsic ( TypeDefinition? staticType = (valueNode as IValueWithStaticType)?.StaticType?.Type; if (staticType is null) { // We don't know anything about the type GetType was called on. Track this as a usual result of a method call without any annotations - AddReturnValue (_context.Annotations.FlowAnnotations.GetMethodReturnValue (calledMethod)); + AddReturnValue (_context.Annotations.FlowAnnotations.GetMethodReturnValue (calledMethod, _isNewObj)); } else if (staticType.IsSealed || staticType.IsTypeOf ("System", "Delegate") || staticType.IsTypeOf ("System", "Array")) { // We can treat this one the same as if it was a typeof() expression @@ -151,7 +152,7 @@ private partial bool TryHandleIntrinsic ( // Return a value which is "unknown type" with annotation. For now we'll use the return value node // for the method, which means we're loosing the information about which staticType this // started with. For now we don't need it, but we can add it later on. - AddReturnValue (_context.Annotations.FlowAnnotations.GetMethodReturnValue (calledMethod, annotation)); + AddReturnValue (_context.Annotations.FlowAnnotations.GetMethodReturnValue (calledMethod, _isNewObj, annotation)); } } } diff --git a/src/tools/illink/src/linker/Linker.Dataflow/MethodProxy.cs b/src/tools/illink/src/linker/Linker.Dataflow/MethodProxy.cs index a4ca0634a81f8d..6e6fd7a1bf2159 100644 --- a/src/tools/illink/src/linker/Linker.Dataflow/MethodProxy.cs +++ b/src/tools/illink/src/linker/Linker.Dataflow/MethodProxy.cs @@ -59,6 +59,8 @@ internal partial ImmutableArray GetGenericParameters () return builder.ToImmutableArray (); } + internal partial bool IsConstructor () => Method.IsConstructor; + internal partial bool IsStatic () => Method.IsStatic; internal partial bool HasImplicitThis () => Method.HasImplicitThis (); diff --git a/src/tools/illink/src/linker/Linker.Dataflow/MethodReturnValue.cs b/src/tools/illink/src/linker/Linker.Dataflow/MethodReturnValue.cs index 9197a7bda6be10..bec6951b17e4d7 100644 --- a/src/tools/illink/src/linker/Linker.Dataflow/MethodReturnValue.cs +++ b/src/tools/illink/src/linker/Linker.Dataflow/MethodReturnValue.cs @@ -2,9 +2,11 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. using System.Collections.Generic; +using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using ILLink.Shared.DataFlow; using Mono.Cecil; +using Mono.Linker; using Mono.Linker.Dataflow; using TypeDefinition = Mono.Cecil.TypeDefinition; @@ -16,7 +18,14 @@ namespace ILLink.Shared.TrimAnalysis /// internal partial record MethodReturnValue { - public MethodReturnValue (TypeDefinition? staticType, MethodDefinition method, DynamicallyAccessedMemberTypes dynamicallyAccessedMemberTypes) + public static MethodReturnValue Create (MethodDefinition method, bool isNewObj, DynamicallyAccessedMemberTypes dynamicallyAccessedMemberTypes, LinkContext context) + { + Debug.Assert (!isNewObj || method.IsConstructor, "isNewObj can only be true for constructors"); + var staticType = isNewObj ? method.DeclaringType : method.ReturnType.ResolveToTypeDefinition (context); + return new MethodReturnValue (staticType, method, dynamicallyAccessedMemberTypes); + } + + private MethodReturnValue (TypeDefinition? staticType, MethodDefinition method, DynamicallyAccessedMemberTypes dynamicallyAccessedMemberTypes) { StaticType = staticType == null ? null : new (staticType); Method = method; diff --git a/src/tools/illink/src/linker/Linker.Dataflow/ReflectionMethodBodyScanner.cs b/src/tools/illink/src/linker/Linker.Dataflow/ReflectionMethodBodyScanner.cs index c33649404f6b14..3f5109bfeff9bd 100644 --- a/src/tools/illink/src/linker/Linker.Dataflow/ReflectionMethodBodyScanner.cs +++ b/src/tools/illink/src/linker/Linker.Dataflow/ReflectionMethodBodyScanner.cs @@ -75,7 +75,7 @@ protected override void Scan (MethodIL methodIL, ref InterproceduralState interp if (!methodIL.Method.ReturnsVoid ()) { var method = methodIL.Method; - var methodReturnValue = _annotations.GetMethodReturnValue (method); + var methodReturnValue = _annotations.GetMethodReturnValue (method, isNewObj: false); if (methodReturnValue.DynamicallyAccessedMemberTypes != 0) HandleAssignmentPattern (_origin, ReturnValue, methodReturnValue); } @@ -179,7 +179,8 @@ public static MultiValue HandleCall ( Debug.Assert (callingMethodDefinition != null); bool requiresDataFlowAnalysis = context.Annotations.FlowAnnotations.RequiresDataFlowAnalysis (calledMethodDefinition); - var annotatedMethodReturnValue = context.Annotations.FlowAnnotations.GetMethodReturnValue (calledMethodDefinition); + bool isNewObj = operation.OpCode.Code == Code.Newobj; + var annotatedMethodReturnValue = context.Annotations.FlowAnnotations.GetMethodReturnValue (calledMethodDefinition, isNewObj); Debug.Assert (requiresDataFlowAnalysis || annotatedMethodReturnValue.DynamicallyAccessedMemberTypes == DynamicallyAccessedMemberTypes.None); var handleCallAction = new HandleCallAction (context, operation, markStep, reflectionMarker, diagnosticContext, callingMethodDefinition, calledMethod); diff --git a/src/tools/illink/test/ILLink.RoslynAnalyzer.Tests/DataFlowTests.cs b/src/tools/illink/test/ILLink.RoslynAnalyzer.Tests/DataFlowTests.cs index c3ed28034906ad..3a95e6ea046cbd 100644 --- a/src/tools/illink/test/ILLink.RoslynAnalyzer.Tests/DataFlowTests.cs +++ b/src/tools/illink/test/ILLink.RoslynAnalyzer.Tests/DataFlowTests.cs @@ -313,6 +313,12 @@ public Task NullableAnnotations () return RunTest (); } + [Fact] + public Task ObjectGetTypeDataflow () + { + return RunTest (); + } + [Fact] public Task PropertyDataFlow () { diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/IReflectDataflow.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/IReflectDataflow.cs index ea14e8b4f2867f..db2bc09e13e59b 100644 --- a/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/IReflectDataflow.cs +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/IReflectDataflow.cs @@ -164,6 +164,9 @@ class TestType } [Kept] + // MyReflectOverType is not intrinsically understood by the analysis, so + // it doesn't satisfy the PublicFields | NonPublicFields requirement. + [ExpectedWarning ("IL2075")] public static void Test () { new MyReflectOverType (typeof (TestType)).GetFields (BindingFlags.Instance | BindingFlags.Public); diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/MethodReturnParameterDataFlow.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/MethodReturnParameterDataFlow.cs index 8f3adcbdaa0889..14c881bf2e4bdd 100644 --- a/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/MethodReturnParameterDataFlow.cs +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/MethodReturnParameterDataFlow.cs @@ -190,7 +190,7 @@ class AnnotationOnUnsupportedReturnType { class UnsupportedType { - [UnexpectedWarning ("IL2082", Tool.Analyzer, "")] // https://github.com/dotnet/runtime/issues/101211 + [UnexpectedWarning ("IL2082", Tool.Analyzer, "https://github.com/dotnet/runtime/issues/101211")] public UnsupportedType () { RequirePublicFields (this); } @@ -201,8 +201,7 @@ public UnsupportedType () { [ExpectedWarning ("IL2106")] // Linker and NativeAot should not produce IL2073 // They produce dataflow warnings despite the invalid annotations. - // https://github.com/dotnet/runtime/issues/101211 - [ExpectedWarning ("IL2073", Tool.Trimmer | Tool.NativeAot, "")] + [ExpectedWarning ("IL2073", Tool.Trimmer | Tool.NativeAot, "https://github.com/dotnet/runtime/issues/101211")] [return: DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] static UnsupportedType GetWithPublicMethods () { return GetUnsupportedTypeInstance (); @@ -215,12 +214,13 @@ static void RequirePublicFields ( { } - [ExpectedWarning ("IL2072", Tool.Analyzer, "")] // https://github.com/dotnet/runtime/issues/101211 + [ExpectedWarning ("IL2072", Tool.Analyzer, "https://github.com/dotnet/runtime/issues/101211")] static void TestMethodReturnValue () { var t = GetWithPublicMethods (); RequirePublicFields (t); } + [ExpectedWarning ("IL2072", Tool.Analyzer, "https://github.com/dotnet/runtime/issues/101211")] static void TestCtorReturnValue () { var t = new UnsupportedType (); RequirePublicFields (t); diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/MethodThisDataFlow.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/MethodThisDataFlow.cs index 50ae6925bdb4ef..c57d784bce24db 100644 --- a/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/MethodThisDataFlow.cs +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/MethodThisDataFlow.cs @@ -122,7 +122,7 @@ static void RequirePublicFields ( [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] UnsupportedType unsupportedTypeInstance) { } - [ExpectedWarning ("IL2075", nameof (UnsupportedType), nameof (UnsupportedType.GetMethod), Tool.Analyzer, "")] // BUG + [ExpectedWarning ("IL2075", nameof (UnsupportedType), nameof (UnsupportedType.GetMethod), Tool.Analyzer, "https://github.com/dotnet/runtime/issues/101211")] static void TestMethodThisParameter () { var t = GetUnsupportedTypeInstance (); t.GetMethod ("foo"); diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/ObjectGetTypeDataflow.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/ObjectGetTypeDataflow.cs new file mode 100644 index 00000000000000..e089abd68955b3 --- /dev/null +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/ObjectGetTypeDataflow.cs @@ -0,0 +1,44 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using Mono.Linker.Tests.Cases.Expectations.Assertions; +using Mono.Linker.Tests.Cases.Expectations.Helpers; + +namespace Mono.Linker.Tests.Cases.DataFlow +{ + [SkipKeptItemsValidation] + [ExpectedNoWarnings] + public class ObjectGetTypeDataflow + { + public static void Main () + { + SealedConstructorAsSource.Test (); + } + + class SealedConstructorAsSource + { + [KeptMember (".ctor()")] + public class Base + { + } + + [KeptMember (".ctor()")] + [KeptBaseType (typeof (Base))] + public sealed class Derived : Base + { + [KeptAttributeAttribute (typeof (RequiresUnreferencedCodeAttribute))] + [RequiresUnreferencedCode (nameof (Method))] + public void Method () { } + } + + [ExpectedWarning ("IL2026", nameof (Derived.Method))] + public static void Test () + { + new Derived ().GetType ().GetMethod ("Method"); + } + } + } +} From 7aefd27e8ab5011b082fca13717ef6e18050fe84 Mon Sep 17 00:00:00 2001 From: Jan Vorlicek Date: Wed, 1 May 2024 00:47:49 +0200 Subject: [PATCH 161/161] Fix nonvolatile context restoration (#101709) * Fix nonvolatile context restoration There is a possibility of a race between the ClrRestoreNonVolatileContext and an async signal handling (like the one we use for runtime suspension). If the signal kicks in after we've loaded Rsp, but before we jumped to the target address, the context we are loading the registers from could get overwritten by the signal handler stack. So the ClrRestoreNonVolatileContext would end up jumping into a wrong target address. The fix is to load the target address into a register before loading the Rsp and then jumping using the register. * Fix arm and x86 --- src/coreclr/pal/src/arch/arm/context2.S | 21 ++++++++++++--------- src/coreclr/pal/src/arch/i386/context2.S | 17 ++++++++++++----- src/coreclr/vm/amd64/Context.S | 3 ++- src/coreclr/vm/amd64/Context.asm | 3 ++- 4 files changed, 28 insertions(+), 16 deletions(-) diff --git a/src/coreclr/pal/src/arch/arm/context2.S b/src/coreclr/pal/src/arch/arm/context2.S index e292ca26fe2adc..bb41b0ff589b40 100644 --- a/src/coreclr/pal/src/arch/arm/context2.S +++ b/src/coreclr/pal/src/arch/arm/context2.S @@ -160,25 +160,28 @@ LOCAL_LABEL(Restore_CONTEXT_FLOATING_POINT): ldr R2, [r0, #(CONTEXT_Cpsr)] msr APSR, r2 - // Ideally, we would like to use `ldmia r0, {r0-r12, sp, lr, pc}` here, - // but clang 3.6 and later, as per ARM recommendation, disallows using - // Sp in the register list, and Pc and Lr simultaneously. - // So we are going to use the IPC register r12 to copy Sp, Lr and Pc - // which should be ok -- TODO: Is this really ok? + ldr r1, [r0, #(CONTEXT_Sp)] + ldr r2, [r0, #(CONTEXT_Pc)] + str r2, [r1, #-4] + ldr r2, [r0, #(CONTEXT_R12)] + str r2, [r1, #-8] add r12, r0, CONTEXT_R0 ldm r12, {r0-r11} - ldr sp, [r12, #(CONTEXT_Sp - (CONTEXT_R0))] ldr lr, [r12, #(CONTEXT_Lr - (CONTEXT_R0))] - ldr pc, [r12, #(CONTEXT_Pc - (CONTEXT_R0))] + ldr r12, [r12, #(CONTEXT_Sp - (CONTEXT_R0))] + sub r12, r12, #8 + mov sp, r12 + pop {r12, pc} LOCAL_LABEL(No_Restore_CONTEXT_INTEGER): ldr r2, [r0, #(CONTEXT_Cpsr)] msr APSR, r2 - ldr sp, [r0, #(CONTEXT_Sp)] ldr lr, [r0, #(CONTEXT_Lr)] - ldr pc, [r0, #(CONTEXT_Pc)] + ldr r2, [r0, #(CONTEXT_Pc)] + ldr sp, [r0, #(CONTEXT_Sp)] + bx r2 LOCAL_LABEL(No_Restore_CONTEXT_CONTROL): ldr r2, [r0, #(CONTEXT_ContextFlags)] diff --git a/src/coreclr/pal/src/arch/i386/context2.S b/src/coreclr/pal/src/arch/i386/context2.S index cf5b464c27d0ce..35768ea6232af2 100644 --- a/src/coreclr/pal/src/arch/i386/context2.S +++ b/src/coreclr/pal/src/arch/i386/context2.S @@ -115,11 +115,12 @@ LOCAL_LABEL(Done_Restore_CONTEXT_FLOATING_POINT): movdqu xmm7, [eax + CONTEXT_Xmm7] LOCAL_LABEL(Done_Restore_CONTEXT_EXTENDED_REGISTERS): - // Restore Stack - mov esp, [eax + CONTEXT_Esp] - // Create a minimal frame - push DWORD PTR [eax + CONTEXT_Eip] + mov ebx, [eax + CONTEXT_Esp] + mov ecx, [eax + CONTEXT_Eip] + mov edx, [eax + CONTEXT_Eax] + mov [ebx - 4], ecx + mov [ebx - 8], edx // Restore register(s) mov ebp, [eax + CONTEXT_Ebp] @@ -128,7 +129,13 @@ LOCAL_LABEL(Done_Restore_CONTEXT_EXTENDED_REGISTERS): mov edx, [eax + CONTEXT_Edx] mov ecx, [eax + CONTEXT_Ecx] mov ebx, [eax + CONTEXT_Ebx] - mov eax, [eax + CONTEXT_Eax] + + // Restore Stack + mov eax, [eax + CONTEXT_Esp] + sub eax, 8 + mov esp, eax + + pop eax // Resume ret diff --git a/src/coreclr/vm/amd64/Context.S b/src/coreclr/vm/amd64/Context.S index 0721c45f56727c..1eda47f0f9dc3f 100644 --- a/src/coreclr/vm/amd64/Context.S +++ b/src/coreclr/vm/amd64/Context.S @@ -51,8 +51,9 @@ NESTED_ENTRY ClrRestoreNonvolatileContextWorker, _TEXT, NoHandler // exception handling, iret and ret can't be used because their shadow stack enforcement would not allow that transition, // and using them would require writing to the shadow stack, which is not preferable. Instead, iret is partially // simulated. + mov rax, [r10 + OFFSETOF__CONTEXT__Rip] mov rsp, [r10 + OFFSETOF__CONTEXT__Rsp] - jmp qword ptr [r10 + OFFSETOF__CONTEXT__Rip] + jmp rax Done_Restore_CONTEXT_CONTROL: // The function was not asked to restore the control registers so we return back to the caller diff --git a/src/coreclr/vm/amd64/Context.asm b/src/coreclr/vm/amd64/Context.asm index a7165983cf4fa1..a2dbbda0b30991 100644 --- a/src/coreclr/vm/amd64/Context.asm +++ b/src/coreclr/vm/amd64/Context.asm @@ -63,8 +63,9 @@ NESTED_ENTRY ClrRestoreNonvolatileContextWorker, _TEXT mov eax, [r10 + OFFSETOF__CONTEXT__EFlags] push rax popfq + mov rax, [r10 + OFFSETOF__CONTEXT__Rip] mov rsp, [r10 + OFFSETOF__CONTEXT__Rsp] - jmp qword ptr [r10 + OFFSETOF__CONTEXT__Rip] + jmp rax Done_Restore_CONTEXT_CONTROL: ; The function was not asked to restore the control registers so we return back to the caller